Develop and Download Open Source Software

Browse Subversion Repository

Annotation of /branches/mty-makai/mty.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 192 - (hide annotations) (download) (as text)
Mon May 26 06:29:35 2008 UTC (15 years, 10 months ago) by notanpe
File MIME type: text/x-csrc
File size: 38802 byte(s)
シーズン 2 に向けて
1 chapuni 1 /***********************************************************************
2     *
3 chapuni 26 * file: mty.c
4 chapuni 1 *
5 chapuni 2 * まあ、待て屋。
6 chapuni 1 *
7     * $Id$
8     *
9     */
10    
11     #include <assert.h>
12     #include <ctype.h>
13 chapuni 24 #include <errno.h>
14 chapuni 9 #include <limits.h>
15 chapuni 24 #include <stdarg.h>
16 chapuni 20 #include <stddef.h>
17 chapuni 1 #include <stdio.h>
18     #include <stdlib.h>
19     #include <string.h>
20     #include <time.h>
21 notanpe 192 #include <sys/timeb.h>
22 notanpe 148 #include <sys/types.h>
23 chapuni 10
24     #if defined(WIN32)
25    
26     #include <windows.h>
27 notanpe 148 #include <process.h>
28 chapuni 10
29     #elif defined(__GNUC__)
30    
31     #include <sys/time.h>
32    
33     #endif
34    
35 chapuni 26 #include "config.h"
36 chapuni 39 #include "cp932.h"
37 chapuni 1 #include "crypt64.h"
38 chapuni 41 #include "desconst.h"
39 chapuni 46 #include "expr_parse.h"
40     #include "scoreboard.h"
41     #include "synth.h"
42 chapuni 74 #include "tr64.h"
43 chapuni 26 #include "translate.h"
44 notanpe 148 #include "util.h"
45 chapuni 99 #include "wdict.h"
46 chapuni 1
47 chapuni 39 #if USE_DT
48     #include "dt4.h"
49     #endif
50    
51 notanpe 192 /* CRYPT64 記述子 */
52     static
53     struct CRYPT64_DESC const *const crypt64_descs[] =
54     {
55     &crypt64_desc,
56     };
57    
58 chapuni 1 /* 鍵クラス */
59 chapuni 41 static
60 chapuni 1 struct
61     {
62 notanpe 148 unsigned short map[256];
63 chapuni 1 } kcls[8 + 8];
64    
65 chapuni 26 /* 拡張鍵クラス */
66 chapuni 1 #define KCLS_DT0 64
67     #define KCLS_DT1 128
68     #define KCLS_K2 256
69    
70     #if USE_DT
71     /* 鍵キメ用辞書インデクス */
72     struct DT *kd[8 + 8];
73    
74     /* 辞書インデクス */
75     struct DT *dtidx[0x100 + 1];
76     #endif
77    
78     /* 指定されたクラスと入っているキーから、classify を行う */
79     void
80 notanpe 148 key_make_map(uint8_t *key, int n)
81 chapuni 1 {
82     int i, j;
83     unsigned c = kcls[n].map[key[n]];
84    
85 chapuni 39 #if USE_DT
86 chapuni 1 if (3 <= n && n < 7 && kd[n - 3])
87     {
88     /* 辞書のケツの文字。後ろにナニヤラキャラクタが来る */
89     c = kd[n - 3]->c[0];
90     if ((0x81 <= c && c <= 0x9F)
91     || (0xE0 <= c && c <= 0xFC))
92     c = KCLS_K2;
93     else
94     c = (cp932[256 * key[n]]
95     | cp932[256 * (key[n] ^ 0x80)]);
96     #if DEBUG>=1
97     printf("*n=%d, key=%02X, cls=%04X\n",
98     n,
99     key[n],
100     c);
101     #endif
102     }
103     else if (2 <= n && n < 6 && kd[n - 2])
104     {
105     return;
106     }
107     else if (1 <= n && n < 5 && kd[n - 1])
108     {
109     return;
110     }
111     else if (1 <= n && n < 5 && !kd[n - 1]
112     //&& (c & KCLS_K2)
113     && (c & KCLS_DT1))
114     {
115     /* 漢字2文字を拾っていきまつ */
116     #if DEBUG>=1
117     printf("(%d)%02X %02X(%02X:%02X:%02X:%02X)\n",
118     n, key[n - 1], key[n],
119     cp932[(256 * key[n - 1] + key[n])],
120     cp932[(256 * key[n - 1] + key[n]) ^ 0x0080],
121     cp932[(256 * key[n - 1] + key[n]) ^ 0x8000],
122     cp932[(256 * key[n - 1] + key[n]) ^ 0x8080]);
123     #endif
124     if (n != 1 && n != 2
125     && (cp932[(256 * key[n - 1] + key[n]) ^ 0x0080] & KCLS_DT1))
126     key[n] ^= 0x80;
127     else if (n != 2 && n != 3
128     && (cp932[(256 * key[n - 1] + key[n]) ^ 0x8000] & KCLS_DT1))
129     key[n - 1] ^= 0x80;
130     else if (n > 3 && (cp932[(256 * key[n - 1] + key[n]) ^ 0x8080] & KCLS_DT1))
131     key[n - 1] ^= 0x80, key[n] ^= 0x80;
132     if (cp932[256 * key[n - 1] + key[n]] & KCLS_DT1)
133     {
134     for (kd[n - 1] = dtidx[key[n - 1]];
135     kd[n - 1]->c[1] != key[n];
136     kd[n - 1]++)
137     assert(kd[n - 1]->c[0] == key[n - 1]);
138     #if DEBUG>=1
139     printf("(%02X%02X:%02X%02X)%c%c%c%c\n",
140     kd[n - 1]->c[0],
141     kd[n - 1]->c[1],
142     kd[n - 1]->c[2],
143     kd[n - 1]->c[3],
144     kd[n - 1]->c[0],
145     kd[n - 1]->c[1],
146     kd[n - 1]->c[2],
147     kd[n - 1]->c[3]);
148     #endif
149     return;
150     }
151     }
152     else if (n < 4 && (c & KCLS_DT0) && kd[n] == NULL)
153     {
154     /* カタカナ埋め込みいきます */
155     assert(kd[n] == NULL);
156     #if DEBUG>=1
157     printf("n=%d, key=%02X\n", n, key[n]);
158     #endif
159     kd[n] = dtidx[key[n]];
160     if (!kd[n]
161     && !(n == 1 || n == 2)
162     && dtidx[key[n] ^ 0x80])
163     {
164     key[n] ^= 0x80;
165     kd[n] = dtidx[key[n]];
166     }
167     if (kd[n])
168     return;
169     }
170     else
171     {
172     kd[n] = NULL;
173     }
174 chapuni 39 #endif
175 chapuni 1
176     /* 最後の部分は class map を生成する必要ナシ */
177     if (n >= 6)
178     return;
179    
180     for (i = 0; i < 256; i++)
181     {
182 chapuni 25 unsigned bm = 0;
183 chapuni 1 #if 1
184     if (c & KCLS_K1)
185     {
186     if (cp932[256 * key[n] + i] & KCLS_K1)
187     bm |= KCLS_K2 | (cp932[256 * key[n] + i] & KCLS_DT1);
188     if (cp932[256 * (key[n] ^ 0x80) + i] & KCLS_K1)
189     bm |= KCLS_K2 | (cp932[256 * (key[n] ^ 0x80) + i] & KCLS_DT1);
190     #if 0
191     bm |= ((cp932[256 * key[n] + i] & KCLS_K1)
192     || (cp932[256 * (key[n] ^ 0x80) + i] & KCLS_K1)
193     ? KCLS_K2 : 0);
194     #endif
195     }
196     if (c & (KCLS_AN | KCLS_KA | KCLS_K2))
197     for (j = 0; j < 256; j++)
198     {
199     bm |= cp932[256 * i + j] & (KCLS_AN | KCLS_KA | KCLS_K1
200     | KCLS_DT0);
201     #if 0
202     if (j >= 127 && !(n == 0 || n == 1))
203     break;
204     #endif
205     }
206     kcls[n + 1].map[i] = bm;
207     #endif
208     if (i >= 128 && !(n == 0 || n == 1))
209     kcls[n + 1].map[i - 128] |= kcls[n + 1].map[i];
210     }
211    
212     if (n < 6)
213     kcls[n + 1].map[0x00] = kcls[n + 1].map[0x80] = 0;
214     if (n == 6)
215     kcls[7].map[0x00] |= KCLS_AN;
216     }
217    
218 chapuni 39 #if USE_DT
219 chapuni 1 unsigned
220     dt_get(int kdn,
221     int xn,
222     int n,
223     int ch)
224     {
225     int i;
226     #if DEBUG>=1
227     printf("*dt_get(%d)%c%c%c%c(%02X%02X:%02X%02X)->ch=%d",
228     n,
229     kd[kdn]->c[0], kd[kdn]->c[1], kd[kdn]->c[2], kd[kdn]->c[3],
230     kd[kdn]->c[0], kd[kdn]->c[1], kd[kdn]->c[2], kd[kdn]->c[3],
231     ch);
232     #endif
233     /* まずは数える */
234     for (i = 0;
235     kd[kdn][i].c[xn] == kd[kdn]->c[xn];
236     i++)
237     ;
238     assert(i > 0);
239     kd[kdn] += ch % i;
240     #if DEBUG>=1
241     printf("/%d\n dt_get: %c%c%c%c(%02X%02X:%02X%02X)->ch=%d\n",
242     i,
243     kd[kdn]->c[0], kd[kdn]->c[1], kd[kdn]->c[2], kd[kdn]->c[3],
244     kd[kdn]->c[0], kd[kdn]->c[1], kd[kdn]->c[2], kd[kdn]->c[3],
245     ch);
246     #endif
247     return kd[kdn]->c[n];
248     }
249 chapuni 39 #endif
250 chapuni 1
251     /* マップから文字を拾ってセット */
252     unsigned
253     key_set(int n, unsigned ch)
254     {
255     int cnt = 0, i;
256    
257 chapuni 39 #if USE_DT
258 chapuni 1 if (3 <= n && n < 7 && kd[n - 3])
259     {
260     return dt_get(n - 3, 2, 3, ch);
261     return kd[n - 3]->c[3];
262     }
263     else if (2 <= n && n < 6 && kd[n - 2])
264     {
265     return dt_get(n - 2, 1, 2, ch);
266     return kd[n - 2]->c[2];
267     }
268     else if (1 <= n && n < 5 && kd[n - 1])
269     {
270     return dt_get(n - 1, 0, 1, ch);
271     return kd[n - 1]->c[1];
272     }
273 chapuni 39 #endif
274 chapuni 1
275     #if DEBUG>=3
276     if (cnt == 0)
277     {
278     printf("n=%d, ch=%d, (n-1)=%02X\n", n, ch, key[n - 1]);
279     int j;
280     for (i = 0; i < 16; i++)
281     {
282     printf("map[0x%02X] =", 16 * i);
283     for (j = 0; j < 16; j++)
284     printf(" %03X", kcls[n].map[16 * i + j]);
285     printf("\n");
286     }
287     }
288     #endif
289     for (i = 0; i < 256; i++)
290     {
291     if (kcls[n].map[i])
292     {
293     if (ch-- == 0)
294     return i;
295     cnt++;
296     }
297     if (n != 1 && n != 2 && i >= 127)
298     break;
299     }
300     /* 見つからなかったのでもいっぺん */
301     assert(cnt > 0);
302     ch %= cnt;
303     for (i = 0; i < 256; i++)
304     if (kcls[n].map[i])
305     {
306     if (ch-- == 0)
307     return i;
308     }
309     assert(!"not matched");
310     return 0;
311     }
312    
313     /* bitwise key をセット */
314     static
315     void
316     key_set64(struct KEY *key64,
317     int n,
318     unsigned k,
319     unsigned vk,
320     unsigned sk)
321     {
322 chapuni 6 int i, j;
323 chapuni 1 if (!((vk | sk) & 0x7F))
324     return;
325    
326     for (i = 0; i < 7; i++)
327     {
328 chapuni 6 if (n == 7 && i < N_STRIDE) continue;
329 chapuni 1 if (sk & (1 << i))
330     {
331     /* セット */
332     int o = tr_pc1[n][6 - i] - 1;
333     if (o < 28)
334     {
335     assert(o >= 0);
336 chapuni 6 for (j = 0; j < N_ALU; j++)
337     key64->k[0][0][o].a[j]
338     = key64->k[0][1][o].a[j]
339     = -!!(k & (1 << i));
340 chapuni 1 }
341     else
342     {
343     assert(o >= 28);
344     assert(o < 56);
345 chapuni 6 for (j = 0; j < N_ALU; j++)
346     key64->k[1][0][o - 28].a[j]
347     = key64->k[1][1][o - 28].a[j]
348     = -!!(k & (1 << i));
349 chapuni 1 }
350     }
351     else if (vk & (1 << i))
352     {
353     /* 反転 */
354     int o = tr_pc1[n][6 - i] - 1;
355     if (o < 28)
356     {
357     assert(o >= 0);
358 chapuni 10 for (j = 0; j < N_ALU; j++)
359     key64->k[0][0][o].a[j]
360     = key64->k[0][1][o].a[j]
361     = ~key64->k[0][0][o].a[j];
362 chapuni 1 }
363     else
364     {
365     assert(o >= 28);
366     assert(o < 56);
367 chapuni 10 for (j = 0; j < N_ALU; j++)
368     key64->k[1][0][o - 28].a[j]
369     = key64->k[1][1][o - 28].a[j]
370     = ~key64->k[1][0][o - 28].a[j];
371 chapuni 1 }
372     }
373     }
374     }
375    
376     /* 指定されたクラスの開始値にリセット
377     直前の文字のクラスに縛られる */
378     int
379 notanpe 148 key_reset(uint8_t *key, int n)
380 chapuni 1 {
381     if (n >= 8)
382     return 1;
383     if (n == 7)
384     {
385     key[7] = 0;
386     return 1;
387     }
388    
389     /* 0-2 文字目はランダムに決める
390     3 文字目以降は初期値に */
391 notanpe 148 if (n >= KEY_SHUFFLE_POS)
392 chapuni 1 key[n] = key_set(n, 0);
393     else
394     key[n] = key_set(n, rand());
395    
396     #if DEBUG>=3
397     printf("key[%d]=%02X ncls=%04X\n", n, key[n], kcls[n].map[key[n]]);
398     #endif
399    
400     /* セットされた文字を元に、次キャラの文字クラスを決める */
401 notanpe 148 key_make_map(key, n);
402 chapuni 1
403 notanpe 148 return key_reset(key, n + 1);
404 chapuni 1 }
405    
406     /* 指定された鍵空間の中で、キーをひとつ進める
407     安全にインクリメントできた場合 true を返す */
408     static
409     int
410 notanpe 148 key_inc(uint8_t *key, int n)
411 chapuni 1 {
412     if (n >= 8)
413     return 0;
414     else if (n == 7)
415     {
416 chapuni 6 /* 最後のバイト */
417 notanpe 148 uint8_t o_k = (key[7] + (1 << N_STRIDE)) & 0x7F;
418     if (!o_k)
419     return 0; /* インクリメントできなかったときは次へ進めず待つ */
420    
421     /* 進める */
422     key[7] = o_k;
423     return 1;
424 chapuni 1 }
425 notanpe 148 else if (key_inc(key, n + 1)
426 chapuni 1 /*
427     && key_inc(n + 1)
428     && key_inc(n + 1)
429     && key_inc(n + 1)*/
430     )
431     return 1;
432    
433     /* Salt はインクリメントしない約束にする */
434     if (n == 1 || n == 2)
435     return 1;
436    
437     #if DEBUG>=3
438     printf("key_inc(n=%d,ck=%02X)\n", n, key[n]);
439     #endif
440    
441 chapuni 39 #if USE_DT
442 chapuni 1 /* 辞書語はインクリメントしていい約束にする */
443     if (3 <= n && n < 7 && kd[n - 3])
444     {
445     if ((key[n - 3] & 0x7F) == ((kd[n - 3] + 1)->c[0] & 0x7F)
446     && (key[n - 2] & 0x7F) == ((kd[n - 3] + 1)->c[1] & 0x7F)
447     && (key[n - 1] & 0x7F) == ((kd[n - 3] + 1)->c[2] & 0x7F))
448     {
449     memcpy(&key[n - 3], &(++kd[n - 3])->c[0], 4);
450     #if DEBUG>=2
451     printf(">dt_get:%c%c%c%c(%02X%02X:%02X%02X)\n",
452     kd[n - 3]->c[0], kd[n - 3]->c[1], kd[n - 3]->c[2], kd[n - 3]->c[3],
453     kd[n - 3]->c[0], kd[n - 3]->c[1], kd[n - 3]->c[2], kd[n - 3]->c[3]);
454     #endif
455     return 1;
456     }
457     else
458     {
459     return 0;
460     }
461     }
462     else if (2 <= n && n < 6 && kd[n - 2])
463     {
464     if ((key[n - 2] & 0x7F) == ((kd[n - 2] + 1)->c[0] & 0x7F)
465     && (key[n - 1] & 0x7F) == ((kd[n - 2] + 1)->c[1] & 0x7F))
466     {
467     memcpy(&key[n - 2], &(++kd[n - 2])->c[0], 4);
468     #if DEBUG>=2
469     printf(">dt_get:%c%c%c%c(%02X%02X:%02X%02X)\n",
470     kd[n - 2]->c[0], kd[n - 2]->c[1], kd[n - 2]->c[2], kd[n - 2]->c[3],
471     kd[n - 2]->c[0], kd[n - 2]->c[1], kd[n - 2]->c[2], kd[n - 2]->c[3]);
472     #endif
473     return 1;
474     }
475     else
476     {
477     return 0;
478     }
479     if (kd[n - 2]->c[0] == key[n - 2])
480     return 1;
481     else
482     return 0;
483     }
484     else if (1 <= n && n < 5 && kd[n - 1])
485     {
486     unsigned c2 = kd[n - 1]->c[0];
487     if ((0x81 <= c2 && c2 <= 0x9F)
488     || (0xE0 <= c2 && c2 <= 0xFC))
489     {
490     kd[n - 1] = NULL;
491     #if 0
492     if (!(n == 1 && n == 2))
493     key[n] &= 0x7F;
494     if (!(n == 2 && n == 3))
495     key[n - 1] &= 0x7F;
496     #endif
497     key_make_map(n - 1);
498     }
499     else if ((key[n - 1] & 0x7F) == ((kd[n - 1] + 1)->c[0] & 0x7F))
500     {
501     memcpy(&key[n - 1], &(++kd[n - 1])->c[0], 4);
502     #if DEBUG>=2
503     printf(">dt_get:%c%c%c%c(%02X%02X:%02X%02X)\n",
504     kd[n - 1]->c[0], kd[n - 1]->c[1], kd[n - 1]->c[2], kd[n - 1]->c[3],
505     kd[n - 1]->c[0], kd[n - 1]->c[1], kd[n - 1]->c[2], kd[n - 1]->c[3]);
506     #endif
507     return 1;
508     }
509     else
510     {
511     return 0;
512     }
513     #if 0
514     if (kd[n - 1]->c[0] == key[n - 1])
515     return 1;
516     else
517     return 0;
518     #endif
519     }
520     else if (n < 4 && kd[n])
521     {
522     if (0 && kd[n]->c[0] == key[n])
523     return 1;
524     kd[n] = NULL;
525     #if 0
526     if (!(n == 1 || n == 2))
527     key[n] &= 0x7F;
528     #endif
529     }
530 chapuni 39 #endif
531 chapuni 1
532     /* 実際に増やしてみる */
533     assert(n >= 3);
534     for (;;)
535     {
536     if (n <= 3
537     && !(key[n] & 0x80)
538     && kcls[n].map[key[n] ^ 0x80] & (KCLS_DT0))
539     {
540     /* 半角カタカナの1バイト目 */
541     key[n] ^= 0x80;
542     }
543     else
544     {
545     key[n] = (key[n] & 0x7F) + 1;
546     if (key[n] >= 0x80)
547 notanpe 148 {
548     key[n] = 0xFF; /* 次に突入させないため */
549     return 0;
550     }
551 chapuni 1 }
552    
553     if (kcls[n].map[key[n]])
554     {
555 notanpe 148 key_make_map(key, n);
556     key_reset(key, n + 1);
557 chapuni 1 return 1;
558     }
559     }
560     }
561    
562     /* 鍵を完全にリセットする
563     Saltもセットし直す */
564     static
565     void
566 notanpe 148 key_init(uint8_t *key)
567 chapuni 1 {
568     int i, j;
569    
570     #if USE_DT
571     /* 辞書を、インデクスを作りながらマップにはめこんで逝く
572     辞書はコード順昇順に並んでるものとする */
573     for (i = 0; i < dtcnt; i++)
574     {
575     unsigned c = dt[i].c[0];
576    
577     assert(dt[i].c[0]
578     && dt[i].c[1]
579     && dt[i].c[2]
580     && dt[i].c[3]);
581    
582     /* BSD 鯖でしにそうな文字は残念ながら除外 */
583     assert((dt[i].c[0] & 0x7F)
584     && (dt[i].c[1] & 0x7F)
585     && (dt[i].c[2] & 0x7F)
586     && (dt[i].c[3] & 0x7F));
587    
588     /* インデクス */
589     if (!dtidx[c])
590     dtidx[c] = &dt[i];
591    
592     if ((0x81 <= c && c <= 0x9F)
593     || (0xE0 <= c && c <= 0xFC))
594     {
595     /* 全角なので、2バイトきまった時点で立てる */
596     cp932[256 * c + dt[i].c[1]] |= KCLS_DT1;
597     }
598     else if (0xA1 <= c && c <= 0xDF)
599     {
600     /* 半角カナ */
601     for (j = 0; j < 256; j++)
602     cp932[256 * c + j] |= KCLS_DT0;
603     }
604     }
605     /* ケツ、ちうか番人 */
606     dtidx[0x100] = &dt[i];
607     #endif
608    
609     key[8] = 0;
610    
611     /* 初期マップを組む */
612     for (i = 0; i < 256; i++)
613     {
614     unsigned bm = 0;
615     kcls[0].map[i] = 0;
616     for (j = 0; j < 256; j++)
617     bm |= cp932[256 * i + j];
618     kcls[0].map[i] = bm & (KCLS_AN | KCLS_KA | KCLS_K1
619     | KCLS_DT0
620     );
621     if (i >= 128)
622     kcls[0].map[i - 128] |= kcls[0].map[i];
623     }
624    
625 notanpe 148 key_reset(key, 0);
626 chapuni 1 }
627    
628     /***************************************************************
629     *
630 chapuni 122 * 固定キーの生成
631     *
632     * 一見 Big Endian に非対応のように見えるだろうが
633     * 随所でに散らばっている kludge により
634     * ALU_T が 64 ビットである限り、これで問題なく動く。
635     *
636     */
637    
638     static
639     void
640     key_init_sk(struct KEY *key)
641     {
642     int i, j;
643     int o;
644     uint64_t m;
645    
646     for (i = 5, m = 0xFFFFFFFF00000000ULL;
647     i >= 0;
648     m ^= (m >> (1 << --i)))
649     {
650     o = tr_pc1[7][6 - i] - 1;
651 chapuni 123 #if DEBUG>=2
652 chapuni 122 printf("%d:%d->%2d: %08X%08X\n",
653     N_Q, i, o,
654     (unsigned)(m >> 32),
655     (unsigned)m);
656 chapuni 123 #endif
657 chapuni 122 for (j = 0; j < N_Q; j++)
658     if (o < 28)
659     key->k[0][0][o ].q[j] = key->k[0][1][o ].q[j] = m;
660     else
661     key->k[1][0][o - 28].q[j] = key->k[1][1][o - 28].q[j] = m;
662     }
663     #if N_STRIDE==7
664     /* bit 6 は Little Endian として扱う */
665     o = 0;
666     assert(tr_pc1[7][0] - 1 == o);
667     assert(N_Q == 2);
668     key->k[0][0][o].q[0] = key->k[0][1][o].q[0] = 0x0000000000000000ULL;
669     key->k[0][0][o].q[1] = key->k[0][1][o].q[1] = 0xFFFFFFFFFFFFFFFFULL;
670     #endif
671     }
672    
673     /***************************************************************
674     *
675 chapuni 1 * Salt のセット
676     * オペランドのオフセットを書き換えて回ってるので注意
677     *
678     */
679    
680     void
681 notanpe 148 set_salt(CODE_T *code,
682 notanpe 192 struct CRYPT64_DESC const *desc,
683 notanpe 148 uint8_t const *k)
684 chapuni 1 {
685     int i, j;
686    
687     for (i = 0; i < 2; i++)
688     {
689     unsigned s = k[1 + i] & 255;
690     if (s > 'z')
691     s = 0;
692     else if (s >= 'a')
693     s = s - 'a' + 2 + 10 + 26;
694     else if (s >= 'A')
695     s = s - 'A' + 2 + 10;
696     else if (s >= '.')
697     s = s - '.';
698     else
699     s = 0;
700    
701     #if DEBUG>=1
702     printf("Salt %d:%3o\n", i, s & 63);
703     #endif
704     for (j = 0; j < 6; j++)
705     {
706     #if DEBUG>=2
707 chapuni 6 //printf("Salt %d:%d %+3d:%+3d",
708     printf("Salt %d:%d %08lX:%08lX",
709 chapuni 1 i, j,
710 notanpe 192 LSALT(desc, code, 0, i, j, 0),
711     LSALT(desc, code, 0, i, j, 24));
712 chapuni 1 #endif
713     if (s & (1 << j))
714     {
715 notanpe 192 LSALT(desc, code, 0, i, j, 0) = sizeof(WS_T) * (((4 * i + j + 15) & 31) - 16);
716     LSALT(desc, code, 0, i, j, 24) = sizeof(WS_T) * (((4 * i + j - 1) & 31) - 16);
717 chapuni 1 }
718     else
719     {
720 notanpe 192 LSALT(desc, code, 0, i, j, 0) = sizeof(WS_T) * (((4 * i + j - 1) & 31) - 16);
721     LSALT(desc, code, 0, i, j, 24) = sizeof(WS_T) * (((4 * i + j + 15) & 31) - 16);
722 chapuni 1 }
723 notanpe 192 LSALT(desc, code, 0, i, j, 12) = sizeof(WS_T) * (((4 * i + j + 7) & 31) - 16);
724     LSALT(desc, code, 0, i, j, 36) = sizeof(WS_T) * (((4 * i + j + 23) & 31) - 16);
725 chapuni 1 #if DEBUG>=2
726 chapuni 6 //printf(" => %+3d:%+3d\n",
727     printf(" => %08lX:%08lX\n",
728 notanpe 192 LSALT(desc, code, 0, i, j, 0),
729     LSALT(desc, code, 0, i, j, 24));
730 chapuni 1 #endif
731     }
732     }
733     }
734    
735 notanpe 192 #define USEC_SEC 1000 /* 1秒 */
736    
737 chapuni 1 static
738 notanpe 192 uint64_t
739 notanpe 148 usec(void)
740 notanpe 119 {
741 notanpe 120 uint32_t sec, msec;
742    
743 notanpe 119 #if !defined(WIN32)
744     struct timeval tv;
745     gettimeofday(&tv, NULL);
746 notanpe 120 sec = tv.tv_sec;
747 notanpe 192 msec = tv.tv_usec / (1000000 / USEC_SEC);
748 notanpe 119 #else
749     struct timeb tm;
750     ftime(&tm);
751 notanpe 120 sec = tm.time;
752 notanpe 192 msec = tm.millitm / (1000 / USEC_SEC);
753 notanpe 119 #endif
754 notanpe 120
755 notanpe 192 return (uint64_t)USEC_SEC * sec + msec;
756 notanpe 119 }
757    
758     static
759 chapuni 24 int
760     log_printf(FILE *ofp, char const *fmt, ...)
761     {
762     int r;
763     va_list ap;
764     va_start(ap, fmt);
765     vfprintf(stdout, fmt, ap);
766     r = vfprintf(ofp, fmt, ap);
767     va_end(ap);
768     if (r > 0)
769     return r;
770     perror("log_printf");
771     exit(errno);
772     }
773    
774 chapuni 1 /***************************************************************
775     *
776 notanpe 192 * CPU capabilities を取得
777     * [XXX] あまりにも古いプロセッサのことは考えない。
778 chapuni 1 *
779 notanpe 192 * a[4] = {EAX,EBX,ECX,EDX}
780     *
781 chapuni 1 */
782    
783 notanpe 192 #if defined(__GNUC__)
784    
785     #define cpuid(n,a,b,c,d) \
786     asm("cpuid" \
787     : "=a"(a), "=b"(b), "=c"(c), "=d"(d) \
788     : "a"(n))
789    
790     #elif defined(WIN32)
791    
792     #define cpuid(n,a,b,c,d) \
793     do {int r[4]; __cpuid(r,n); \
794     (a) = r[0]; (b) = r[1]; (c) = r[2]; (d) = r[3];} while (0)
795    
796     #endif
797    
798     static
799     unsigned
800     cpuid_getfflags(void)
801 notanpe 148 {
802 notanpe 192 unsigned a, b, c, d;
803     cpuid(1, a, b, c, d);
804     return d;
805     }
806 chapuni 1
807 notanpe 148 static
808 notanpe 192 int
809     cpuid_issupported(void)
810     {
811     unsigned m = REQUIRED_CAPS;
812     return !((cpuid_getfflags() ^ m) & m);
813     }
814    
815     /***************************************************************
816     *
817     * バッチ処理用パケット
818     *
819     */
820    
821     static
822 notanpe 148 struct PACKET_CRYPT64 *
823     packet_create(int n, /* パケット数 */
824     int tn, /* 末尾要素にて必要なワーク数 */
825     uint8_t const *ini_key)
826     {
827     int i;
828     int siz;
829     void *p;
830 notanpe 192 intptr_t a = 128;
831 notanpe 148 struct PACKET_CRYPT64 *pkts;
832     assert(IS_POWER2(sizeof(struct PACKET_CRYPT64)));
833     assert(n >= 1);
834    
835 notanpe 192 siz = (a - 1
836 notanpe 148 + (n - 1) * sizeof(struct PACKET_CRYPT64)
837     + offsetof(struct PACKET_CRYPT64, param64.hit[tn]));
838     p = calloc(siz, 1);
839     /* バンダリあわせ */
840     pkts = (struct PACKET_CRYPT64 *)(((intptr_t)p
841 notanpe 192 + a - 1)
842     & -a);
843 notanpe 148 #if DEBUG>=1
844     fprintf(stderr,
845     "packet(n=%d,tn=%d) %d allocated; %p aligned to %p\n",
846     n, tn,
847     siz, p, pkts);
848     #endif
849    
850     /* 内部の初期化
851     コピーして回るのは、厳密には
852     最終要素のケツを破ってしまうことになるので
853     どうせ速度も要求されないしベタコード */
854     for (i = 0; i < n; i++)
855     {
856 notanpe 192 int j, k;
857 notanpe 148
858     /* t[16] は、内部演算で使用する、all 1 が入っている */
859     memset(&pkts[i].param64.t[T_INV], -1, sizeof(SLICE));
860    
861     /* 固定キーの生成 */
862     key_init_sk(&pkts[i].key64);
863    
864     /* キースケジュールをここに押し込めておく
865     従来は crypt64.S 内で完結するように引いていた */
866     for (j = 0; j < 28; j++)
867 notanpe 192 for (k = 0; k < N_ALU; k++)
868     pkts[i].key64.ks[j].a[k] = sizeof(WS_T) * ks_ls[j];
869 notanpe 148
870     /* 念のため、鍵をここで落ち着けておく(不要?) */
871     for (j = 0; j < 8; j++)
872     key_set64(&pkts[i].key64, j, pkts[i].uk.key[j] = ini_key[j], 0, 0x7F);
873     }
874    
875     return pkts;
876     }
877    
878     /***************************************************************
879     *
880     * thread
881     *
882     */
883    
884     #define NQ_CRYPT 64
885     #define NQ_CMP 32
886    
887     #if defined(__GNUC__)
888    
889     typedef int32_t ATOMWORD_T;
890    
891     #define LOCK_INC(p) \
892     asm volatile ("lock incl %0" \
893     : "=m"(*(p)) \
894     : /*nil*/ \
895     : "memory")
896    
897     #define LOCK_DEC(p) \
898     asm volatile ("lock decl %0" \
899     : "=m"(*(p)) \
900     : /*nil*/ \
901     : "memory")
902    
903     #define LOCK_CAS(pd,s,r) \
904     ({ ATOMWORD_T a; \
905     asm volatile ("lock cmpxchg %2,%1" \
906     : "=a"(a) \
907     : "m"(*(pd)), "r"(s), "0"(r) \
908     : "memory");a;})
909    
910     #define LOCK_CASP(pd,s,r) \
911     ({ void *a; \
912     asm volatile ("lock cmpxchg %2,%1" \
913     : "=a"(a) \
914     : "m"(*(pd)), "r"(s), "0"(r) \
915     : "memory");a;})
916    
917     #elif defined(WIN32)
918    
919     typedef LONG ATOMWORD_T;
920    
921     #define LOCK_INC(p) InterlockedIncrement((LONG *)(p))
922     #define LOCK_DEC(p) InterlockedDecrement((LONG *)(p))
923     #define LOCK_CAS(pd,s,r) InterlockedCompareExchange((LONG *)(pd), s, r)
924     #define LOCK_CASP(pd,s,r) InterlockedCompareExchangePointer((PVOID *)(pd), (PVOID)(s), (PVOID)r)
925    
926     #else
927     #error "configuration not implemented"
928     #endif
929    
930     #if defined(WIN32)
931    
932     typedef DWORD THREAD_TIMEOUT_T;
933    
934     #define THREAD_INFINITE INFINITE
935    
936     typedef HANDLE THREAD_TH_T;
937     typedef HANDLE THREAD_EV_T;
938    
939     #define thread_sleep(n) Sleep(n)
940     #define thread_create(th, proc, arg) {(th) = (HANDLE)_beginthread(proc, 8192, arg);}
941     #define thread_create_event(ev, f) {(ev) = CreateEvent(NULL, TRUE, f, NULL);}
942     #define thread_signal_event(ev) SetEvent(ev)
943     #define thread_clear_event(ev) ResetEvent(ev)
944     #define thread_get_tid() GetCurrentThread()
945     #define thread_set_priority(tid,n) SetThreadPriority(tid, n)
946     #define thread_set_affinity(tid,m) SetThreadAffinityMask(tid, (DWORD_PTR)1 << (m))
947    
948     static
949 chapuni 1 int
950 notanpe 148 thread_wait_event(THREAD_EV_T ev, DWORD tmo)
951     {
952     DWORD r = WaitForSingleObject(ev, tmo);
953     return (r < 0
954     ? r
955     : (r == WAIT_TIMEOUT
956     ? -1
957     : r));
958     }
959    
960 notanpe 192 #elif defined(_POSIX_SOURCE)
961 notanpe 148
962     #include <pthread.h>
963     #include <unistd.h>
964    
965     typedef int THREAD_TIMEOUT_T;
966    
967     #define THREAD_INFINITE INT_MAX
968    
969     #if defined(THREAD_PRIORITY_BELOW_NOROMAL) || defined(THREAD_PRIORITY_IDLE)
970     #error "unsupported implementation"
971     #endif
972    
973     #define THREAD_PRIORITY_NORMAL 14
974     #define THREAD_PRIORITY_BELOW_NORMAL 15
975     #define THREAD_PRIORITY_IDLE 16
976    
977     typedef pthread_t THREAD_TH_T;
978     typedef struct
979     {
980     pthread_mutex_t m;
981     pthread_cond_t c;
982     int volatile f;
983     } THREAD_EV_T;
984    
985     #define thread_sleep(n) (usleep(1000 * (n)) != EINVAL || sleep((n) / 1000))
986     #define thread_create(th, proc, arg) thread_create_p(&(th), proc, arg)
987     #define thread_create_event(ev, f) thread_create_event_p(&(ev), f)
988     #define thread_signal_event(ev) thread_set_event_p(&(ev), 1)
989     #define thread_clear_event(ev) thread_set_event_p(&(ev), 0)
990     #define thread_wait_event(ev,tmo) thread_wait_event_p(&(ev), tmo)
991    
992     static
993     void
994     thread_create_p(pthread_t *th, NORETURN (*proc)(void *), void *param)
995     {
996     pthread_create(th, NULL, (void *(*)(void *))proc, param);
997     }
998    
999     static
1000     void
1001     thread_create_event_p(THREAD_EV_T *ev, int f)
1002     {
1003     ev->f = f;
1004     pthread_cond_init(&ev->c, NULL);
1005     pthread_mutex_init(&ev->m, NULL);
1006     }
1007    
1008     static
1009     void
1010     thread_set_event_p(THREAD_EV_T *ev, int f)
1011     {
1012     pthread_mutex_lock(&ev->m);
1013     if (ev->f != f)
1014     {
1015     ev->f = f;
1016     pthread_cond_broadcast(&ev->c);
1017     }
1018     pthread_mutex_unlock(&ev->m);
1019     }
1020    
1021     static
1022     int
1023     thread_wait_event_p(THREAD_EV_T *ev, int a_tmo)
1024     {
1025     int timeout = a_tmo;
1026     struct timeval now;
1027     struct timespec tmo;
1028     int r;
1029    
1030     pthread_mutex_lock(&ev->m);
1031    
1032     /* 現在時刻からタイムアウト時刻を求める
1033     めんどくせー */
1034     gettimeofday(&now, NULL);
1035     tmo.tv_sec = now.tv_sec + (timeout / 1000);
1036     timeout %= 1000;
1037     timeout *= 1000;
1038     if (now.tv_usec >= 1000000 - timeout)
1039     {
1040     timeout -= 1000000;
1041     tmo.tv_sec++;
1042     }
1043     tmo.tv_nsec = 1000 * (now.tv_usec + timeout);
1044     r = 0;
1045     while (!ev->f)
1046     {
1047     r = pthread_cond_timedwait(&ev->c, &ev->m, &tmo);
1048     if (r == ETIMEDOUT
1049     && a_tmo < THREAD_INFINITE)
1050     break;
1051     }
1052    
1053     pthread_mutex_unlock(&ev->m);
1054    
1055     return (r == ETIMEDOUT
1056     ? (ETIMEDOUT < 0 ? ETIMEDOUT : -1)
1057     : 0);
1058     }
1059    
1060     #if defined(__linux__)
1061    
1062     /* デフォルトスケジューリングポリシーでは
1063     優先度設定したりアイドルスレッド起こしても
1064     おもしろくないので、そのへんは今後の研究課題。 */
1065    
1066     #include <linux/unistd.h>
1067     _syscall0(pid_t,gettid)
1068    
1069     #define thread_get_tid() gettid()
1070    
1071     static
1072     int thread_set_affinity(pid_t tid, int i)
1073     {
1074     cpu_set_t m;
1075     CPU_ZERO(&m);
1076     CPU_SET(i, &m);
1077     return sched_setaffinity(tid, sizeof(m), &m);
1078     }
1079    
1080     #else
1081    
1082     /* POSIX では、スレッド単位のスケジューリングに介入できない。 */
1083    
1084     #endif
1085    
1086     #else
1087     #error "configuration not supported"
1088     #endif
1089    
1090     struct THREAD_PARAM
1091     {
1092     /* 以下は共通情報のコピー */
1093     CODE_T *code;
1094 notanpe 192 THREAD_EV_T *p_ev_ks_activated;
1095 notanpe 148 ATOMWORD_T volatile *p_nidle; /* 待ちに入ったら増加 */
1096    
1097     /* 以下はスレッド固有 */
1098     #ifdef thread_set_priority
1099     THREAD_TH_T th;
1100     int pri;
1101     #endif
1102     };
1103    
1104     static
1105     volatile ATOMWORD_T wp_crypt, rp_crypt;
1106     static
1107     struct PACKET_CRYPT64 *volatile q_crypt[NQ_CRYPT];
1108    
1109     static
1110     volatile ATOMWORD_T wp_cmp, rp_cmp;
1111     static
1112     struct PACKET_CRYPT64 *volatile q_cmp[NQ_CMP];
1113    
1114     static
1115     uint64_t
1116     thread_avail(void)
1117     {
1118     #if !USE_MT
1119    
1120     return 0x1U;
1121    
1122     #elif defined(WIN32) /* Win32 API */
1123     DWORD_PTR mask, mask_s;
1124     if (!GetProcessAffinityMask(GetCurrentProcess(),
1125     &mask,
1126     &mask_s)
1127     || !mask
1128     || !mask_s)
1129     return 0x1U;
1130     #if DEBUG>=1
1131     fprintf(stderr,
1132     "m=%08X s=%08X\n",
1133     (unsigned)mask,
1134     (unsigned)mask_s);
1135     #endif
1136     if (popcnt64(mask_s) == 1)
1137     /* 何も言うまい */;
1138     else if (mask == mask_s)
1139     fprintf(stderr,
1140     "通常の%d倍とはよく言ったものです。\n",
1141     popcnt64(mask));
1142     else
1143     fprintf(stderr,
1144     "最高速力の%g倍の力でてきとうにがんばるよ。\n",
1145     (double)popcnt64(mask) / popcnt64(mask_s));
1146     return mask;
1147    
1148     #elif defined(__linux__) /* sched.h 拡張 */
1149    
1150     int i;
1151     uint64_t m = 0;
1152     cpu_set_t am;
1153     if (sched_getaffinity(getpid(), sizeof(am), &am) < 0)
1154     return 0x1U;
1155    
1156     for (i = 0; i < 64 && i < CPU_SETSIZE; i++)
1157     if (CPU_ISSET(i, &am))
1158     m |= 1ULL << i;
1159    
1160     return m;
1161     #else
1162    
1163     /* XXX プロセッサ数を調べ上げてください */
1164     return 0x01U;
1165    
1166     #endif
1167     }
1168    
1169     static
1170     NORETURN
1171     thread_crypt64(void *a_param)
1172     {
1173     struct THREAD_PARAM *param = a_param;
1174     CODE_T *code = param->code;
1175     struct PACKET_CRYPT64 *pkt;
1176     #ifdef thread_set_priority
1177     THREAD_TH_T th = thread_get_tid();
1178     thread_set_priority(th, param->pri);
1179     #endif
1180    
1181     for(;;)
1182     {
1183     ATOMWORD_T rp;
1184     ATOMWORD_T wp;
1185    
1186     /* キューから要求を取り出す */
1187     for (;;)
1188     {
1189     while ((rp = rp_crypt,
1190     WRAP(wp_crypt, NQ_CRYPT) == WRAP(rp, NQ_CRYPT)
1191     /*|| q_crypt[WRAP(rp, NQ_CRYPT)] == NULL*/))
1192     {
1193     THREAD_TIMEOUT_T tmo = (WRAP(wp_crypt, NQ_CRYPT) == WRAP(rp, NQ_CRYPT)
1194     ? THREAD_INFINITE
1195     : 1);
1196     int r;
1197    
1198 notanpe 192 /* 寝た */
1199 notanpe 148 if (tmo == THREAD_INFINITE)
1200     {
1201     LOCK_INC(param->p_nidle);
1202     }
1203    
1204     /* 要求待ち */
1205 notanpe 192 r = thread_wait_event(*param->p_ev_ks_activated, tmo);
1206 notanpe 148
1207     if (tmo == THREAD_INFINITE)
1208     {
1209     /* 起こされた */
1210     LOCK_DEC(param->p_nidle);
1211     }
1212     else if (r >= 0)
1213     {
1214     /* もうちょっと寝てみる */
1215     thread_sleep(tmo);
1216     }
1217    
1218     /* 自らの優先度を戻す
1219     (外からブーストされてるかも) */
1220     #ifdef thread_set_priority
1221     if (r >= 0)
1222     thread_set_priority(th, param->pri);
1223     #endif
1224     }
1225    
1226     if (LOCK_CAS(&rp_crypt, rp + 1, rp) != rp)
1227     continue;
1228     rp = WRAP(rp, NQ_CRYPT);
1229     break;
1230     }
1231    
1232     pkt = q_crypt[rp];
1233     assert(pkt != NULL);
1234     pkt = LOCK_CASP(&q_crypt[rp], NULL, pkt);
1235     assert(pkt != NULL);
1236    
1237     /* 実行してみる */
1238     CALL_CRYPT64(code, &pkt->key64, &pkt->param64);
1239    
1240     /* 結果をキューにたたき込む */
1241     for (;;)
1242     {
1243     while ((wp = wp_cmp,
1244     WRAP(rp_cmp - 1, NQ_CMP) == WRAP(wp, NQ_CMP))
1245     || q_cmp[WRAP(wp, NQ_CMP)] != NULL)
1246     {
1247     #if DEBUG>=1
1248     fprintf(stderr,
1249     "q_cmp stalled(%d,%d) %p\n",
1250     (unsigned)WRAP(wp, NQ_CMP),
1251     (unsigned)WRAP(rp_cmp - 1, NQ_CMP),
1252     q_cmp[WRAP(wp, NQ_CMP)]);
1253     #endif
1254     thread_sleep(1);
1255     }
1256    
1257     if (LOCK_CAS(&wp_cmp, wp + 1, wp) != wp)
1258     continue;
1259     wp = WRAP(wp, NQ_CMP);
1260     break;
1261     }
1262    
1263     pkt = LOCK_CASP(&q_cmp[wp], pkt, NULL);
1264     assert(pkt == NULL);
1265     }
1266     }
1267    
1268     /***************************************************************
1269     *
1270     * メインループとか
1271     *
1272     */
1273    
1274     int
1275 chapuni 1 main(int argc, char *argv[])
1276     {
1277 chapuni 74 int i;
1278 chapuni 1 int mincnt;
1279 chapuni 77 int nblk_hit, nblk_total;
1280 chapuni 84 int nap_hit, nap_total;
1281 notanpe 148 CODE_T *code = NULL;
1282     off_t code_cmp;
1283 chapuni 1 FILE *ofp;
1284 chapuni 46 FILE *sfp; /* scoreboard */
1285     struct ITREE *root_expr;
1286 notanpe 148 uint64_t proc_mask;
1287     int ks_activated;
1288 notanpe 192 static THREAD_EV_T event_ks_activated;
1289 notanpe 148 static ATOMWORD_T volatile nidle;
1290     struct THREAD_PARAM *threads = NULL;
1291     int nthreads;
1292     int npkts;
1293     struct PACKET_CRYPT64 *pkts, *pkt_hit;
1294     uint64_t pkts_vacant;
1295     int tn;
1296 chapuni 1 int cr;
1297    
1298 notanpe 148 /* 鍵文字列 */
1299     uint8_t key[8 + 8];
1300    
1301 chapuni 74 int xhash_loaded;
1302    
1303 notanpe 119 #define UPDATE_INTERVAL 8 /* 速度表示の間隔 秒 */
1304 notanpe 115 struct status {
1305 notanpe 192 uint64_t startTime; /* 開始時刻 ミリ秒 */
1306     uint64_t lastTime; /* 最後に表示した時刻 ミリ秒 */
1307     uint64_t loop; /* 総検索個数 */
1308     uint64_t lastloop; /* 最後に表示した時の loop */
1309 notanpe 115 } status;
1310 notanpe 192 uint64_t curTime;
1311     uint32_t upd_int = 0;
1312 notanpe 119 /*
1313 notanpe 120 平均速度 (trips/s) * UPDATE_INTERVAL が UINT32_MAX を超えると発狂する。
1314     UINT32_MAX = 4294967295, 平均速度 = 100Mtrips/s なら、
1315     4294967295 / (100 * 1000 * 1000) = 42.949 秒まで。(和良
1316 notanpe 119 LOOP_FACTOR が平均速度より十分小さければ、ほぼ指定間隔になる。
1317 notanpe 120 LOOP_FACTOR * UINT32_MAX + LOOP_FACOTR 個検索するとオーバーフローする。w
1318 notanpe 119 */
1319 chapuni 1
1320 notanpe 192 if (!cpuid_issupported())
1321 chapuni 1 {
1322 notanpe 192 fprintf(stderr, "この環境で走らせることが想定されていません。\n");
1323     exit(1);
1324 chapuni 1 }
1325    
1326 chapuni 10 assert((1 << N_STRIDE) == N_ALU * ALU_BITS);
1327    
1328 chapuni 46 /* タゲ読み込み */
1329     root_expr = expr_parse("target.txt");
1330 chapuni 2
1331 notanpe 148 /* コードを生成・展開
1332     起動予定スレッド数に応じて
1333     生成するコードを変える */
1334 chapuni 46 sfp = scoreboard_open();
1335 notanpe 192 fwrite(crypt64_descs[0]->pro, 1, crypt64_descs[0]->cmp_pro - crypt64_descs[0]->pro, sfp); /* prologue & コアループ */
1336 notanpe 148 proc_mask = thread_avail();
1337     if (proc_mask == 1U)
1338     {
1339     /* single */
1340     npkts = 1;
1341     pkts_vacant = 1;
1342     code_cmp = 0;
1343     }
1344     else
1345     {
1346     /* multi */
1347 notanpe 192 fwrite(crypt64_descs[0]->ep, 1, crypt64_descs[0]->ep_end - crypt64_descs[0]->ep, sfp); /* epilogue */
1348 chapuni 2
1349 notanpe 148 /* 比較器のみを生成(前半) */
1350     code_cmp = ftell(sfp);
1351     fseek(sfp, (-code_cmp) & 63, SEEK_CUR);
1352     code_cmp = ftell(sfp);
1353 notanpe 192 fwrite(crypt64_descs[0]->pro, 1, crypt64_descs[0]->crypt - crypt64_descs[0]->pro, sfp); /* prologue */
1354 notanpe 148 npkts = 64;
1355     pkts_vacant = (uint64_t)-1; /* (1 << 64) - 1 を計算したくない */
1356     }
1357    
1358     /* 比較部を生成 */
1359 notanpe 192 fwrite(crypt64_descs[0]->cmp_pro, 1, crypt64_descs[0]->cmp_ep - crypt64_descs[0]->cmp_pro, sfp); /* 比較器準備 */
1360 notanpe 148 tn = synth_synthesize(sfp, root_expr);
1361 notanpe 192 fwrite(crypt64_descs[0]->cmp_ep, 1, crypt64_descs[0]->ep_end - crypt64_descs[0]->cmp_ep, sfp); /* epilogue */
1362 notanpe 148
1363 chapuni 46 /* コードをメモリに貼り付ける */
1364     code = scoreboard_map(sfp);
1365 chapuni 1
1366     /* キーの初期化 */
1367 notanpe 192 srand(time(NULL));
1368 notanpe 148 key_init(key);
1369 notanpe 192 set_salt(code, crypt64_descs[0], key);
1370 chapuni 1
1371 notanpe 148 /* 演算パケットを作成 */
1372     pkts = packet_create(npkts, tn, key);
1373     pkt_hit = &pkts[npkts - 1];
1374    
1375     /* 働くおじさんを量産 */
1376     thread_create_event(event_ks_activated, 1);
1377     ks_activated = 1;
1378     nthreads = 0;
1379     if (code_cmp)
1380     {
1381     THREAD_TH_T h;
1382     int ots = -1;
1383     threads = calloc(2 * popcnt64(proc_mask), sizeof(*threads));
1384     for (i = 0; proc_mask; i++, proc_mask >>= 1)
1385     if (proc_mask & 1)
1386     {
1387     if (ots < 0)
1388     {
1389     /* 自分自身のスケジューリング
1390     こーゆー系のアプリは低めに設定するのが吉(かも) */
1391     #ifdef WIN32
1392     h = GetCurrentProcess();
1393     SetPriorityClass(h, BELOW_NORMAL_PRIORITY_CLASS);
1394 chapuni 1 #endif
1395 notanpe 148 #if defined(thread_set_priority)
1396     /* 心の隙間お埋めします */
1397     threads[nthreads].code = code;
1398 notanpe 192 threads[nthreads].p_ev_ks_activated = &event_ks_activated;
1399 notanpe 148 threads[nthreads].p_nidle = &nidle;
1400     threads[nthreads].pri = THREAD_PRIORITY_IDLE;
1401     thread_create(h, thread_crypt64, &threads[nthreads]);
1402     threads[nthreads].th = h;
1403     nthreads++;
1404     #endif
1405     if (!code_cmp)
1406     break;
1407 chapuni 1
1408 notanpe 148 /* 自分自身の残りの設定を、あとでやる */
1409     ots = i;
1410     }
1411     else
1412     {
1413     /* 他スレッドは、やや低めの優先度で。 */
1414     threads[nthreads].code = code;
1415 notanpe 192 threads[nthreads].p_ev_ks_activated = &event_ks_activated;
1416 notanpe 148 threads[nthreads].p_nidle = &nidle;
1417     #ifdef thread_set_priority
1418     threads[nthreads].pri = THREAD_PRIORITY_BELOW_NORMAL;
1419     #endif
1420     thread_create(h, thread_crypt64, &threads[nthreads]);
1421     #ifdef thread_set_priority
1422     threads[nthreads].th = h;
1423     #endif
1424     #ifdef thread_get_tid
1425     thread_set_affinity(h, i);
1426     #endif
1427     nthreads++;
1428     }
1429     }
1430     #ifdef thread_get_tid
1431     if (ots)
1432     thread_set_affinity(thread_get_tid(), ots);
1433     #endif
1434     }
1435    
1436 chapuni 24 if ((ofp = fopen("log.txt", "at")) == NULL)
1437     {
1438     perror("log.txt");
1439     return errno;
1440     }
1441 chapuni 1
1442 chapuni 24 setvbuf(ofp, NULL, _IONBF, BUFSIZ); /* XXX MSVCRT では _IOLBF が期待通りに動作しない */
1443    
1444 chapuni 1 mincnt = 0x7FFFFFFF;
1445 chapuni 77 nblk_hit = nblk_total = 0;
1446 chapuni 84 nap_hit = nap_total = 0;
1447 chapuni 1 cr = 0;
1448 notanpe 120 memset( &status, 0, sizeof( struct status ) );
1449 notanpe 119 status.startTime = status.lastTime = usec();
1450 chapuni 1 /* 探索ループだぞっと */
1451     for (;;)
1452     {
1453 notanpe 148 struct PACKET_CRYPT64 *pkt_c;
1454 chapuni 121 uint64_t cnt;
1455     int cnt1, cnt2;
1456 chapuni 1 int k, kk;
1457    
1458 notanpe 148 /* 比較器候補(may be NULL)
1459     先にキューから取り出す */
1460     pkt_c = q_cmp[WRAP(rp_cmp, NQ_CMP)];
1461 notanpe 192 if (pkt_c != NULL && WRAP(rp_cmp, NQ_CMP) != WRAP(wp_cmp, NQ_CMP))
1462 chapuni 1 {
1463 notanpe 148 pkt_c = LOCK_CASP(&q_cmp[WRAP(rp_cmp, NQ_CMP)], NULL, pkt_c);
1464     assert(pkt_c != NULL);
1465     LOCK_INC(&rp_cmp);
1466    
1467     /* パケットを vacant に回しておく */
1468     pkts_vacant |= 1ULL << (pkt_c - pkts);
1469 chapuni 1 }
1470    
1471 notanpe 148 /* Saltチェンジ待ち */
1472     if (!ks_activated)
1473     {
1474 notanpe 192 ATOMWORD_T rp;
1475    
1476     if (pkt_c == NULL)
1477     {
1478     if ((rp = rp_crypt,
1479     WRAP(rp, NQ_CRYPT) != WRAP(wp_crypt, NQ_CRYPT))
1480     && LOCK_CAS(&rp_crypt, rp + 1, rp) == rp)
1481     {
1482     /* !ks_activate 状態では、自らも要求キューをやっつけにいく */
1483     rp = WRAP(rp, NQ_CRYPT);
1484     pkt_c = q_crypt[rp];
1485     assert(pkt_c != NULL);
1486     pkt_c = LOCK_CASP(&q_crypt[rp], NULL, pkt_c);
1487     assert(pkt_c != NULL);
1488     assert(pkt_c != pkt_hit);
1489     CALL_CRYPT64(code,
1490     &pkt_c->key64,
1491     &pkt_c->param64);
1492    
1493     /* パケットを vacant に回しておく */
1494     pkts_vacant |= 1ULL << (pkt_c - pkts);
1495     }
1496     else
1497     {
1498     /* やはりすることがないのでまったりと過ごす */
1499     if (nidle != nthreads)
1500     thread_sleep(1);
1501     }
1502     }
1503    
1504 notanpe 148 if (nidle == nthreads)
1505     {
1506     assert(WRAP(rp_crypt, NQ_CRYPT) == WRAP(wp_crypt, NQ_CRYPT));
1507     /* Salt チェンジが可能 */
1508 notanpe 192 set_salt(code, crypt64_descs[0], key);
1509     if (nthreads)
1510 notanpe 148 thread_signal_event(event_ks_activated);
1511     ks_activated = 1;
1512     }
1513     }
1514    
1515     /* 鍵をキューにたたき込みまくる */
1516     if (!ks_activated)
1517     {
1518     /* 鍵を登録しない */
1519     ;
1520     }
1521     else for (i = npkts - 1; i >= 0; i--)
1522     if (pkts_vacant & (1ULL << i))
1523     {
1524     int j;
1525    
1526     if (i == npkts - 1)
1527     {
1528     /* 前段で、働くおじさんから
1529     結果をもらっていたら、何もしない */
1530     if (pkt_c != NULL)
1531     continue;
1532     }
1533     else
1534     {
1535     /* 前段で取り出したばかりの
1536     働くおじさんは、尊重する */
1537     if (&pkts[i] == pkt_c)
1538     continue;
1539    
1540     /* queue full の場合は見送る */
1541 notanpe 192 if (WRAP(wp_crypt, NQ_CRYPT) == WRAP(rp_crypt - 16, NQ_CRYPT) /* XXX 16 はてきとう */
1542 notanpe 148 || q_crypt[WRAP(wp_crypt, NQ_CRYPT)] != NULL)
1543     break;
1544     }
1545    
1546     /* 鍵のセット */
1547     for (j = 0; j < 8; j++)
1548     {
1549     key_set64(&pkts[i].key64, j, key[j], key[j] ^ pkts[i].uk.key[j], 0);
1550     pkts[i].uk.key[j] = key[j];
1551     }
1552    
1553     if (i == npkts - 1)
1554     {
1555     /* 次段で CRYPT64->CMP */
1556     assert(pkt_c == NULL);
1557     pkt_c = &pkts[i];
1558     assert(pkt_c == pkt_hit);
1559     }
1560     else
1561     {
1562     /* キューにたたき込む */
1563     while (LOCK_CASP(&q_crypt[WRAP(wp_crypt, NQ_CRYPT)], &pkts[i], NULL) != NULL)
1564     {
1565     /* 設計上はここに来ない */
1566     #if DEBUG>=1
1567     fprintf(stderr,
1568     "[XXX] q_crypt を汚してるのは誰だ? (rp=%3d, wp=%3d, v=%08X%08X)\n",
1569     (unsigned)WRAP(rp_crypt, NQ_CRYPT),
1570     (unsigned)WRAP(wp_crypt, NQ_CRYPT),
1571     (unsigned)(pkts_vacant >> 32),
1572     (unsigned)pkts_vacant);
1573     thread_sleep(1000);
1574     #endif
1575     thread_sleep(1);
1576     }
1577     LOCK_INC(&wp_crypt);
1578     pkts_vacant ^= 1ULL << i;
1579     assert(!(pkts_vacant & (1ULL << i))); /* 削れ */
1580     }
1581    
1582     /* 鍵増加はこんなところに移動! */
1583     assert(ks_activated);
1584     if (!key_inc(key, 6) && !key_inc(key, KEY_SHUFFLE_POS))
1585     {
1586     /* 鍵のシャッフル
1587     q_crypt が捌けるまで、set_salt() はできない */
1588     #if DEBUG>=1
1589     fprintf(stderr, "********************************SHUFFLE!\n");
1590     #endif
1591 notanpe 192 if (nthreads)
1592     thread_clear_event(event_ks_activated);
1593 notanpe 148 key_reset(key, 0);
1594    
1595     /* キューの鍵が捌けるまでアイドル状態に */
1596     ks_activated = 0;
1597    
1598     /* スレッドをブーストして回る */
1599     #ifdef thread_set_priority
1600     for (j = 0; j < nthreads; j++)
1601     {
1602     assert(threads != NULL);
1603     thread_set_priority(threads[j].th, THREAD_PRIORITY_NORMAL);
1604     }
1605     #endif
1606    
1607     /* ループ続行はもはや不要 */
1608     break;
1609     }
1610     }
1611    
1612     /* することがなくなっている場合 */
1613     if (pkt_c == NULL)
1614     {
1615     assert(!ks_activated);
1616     continue;
1617     }
1618    
1619 chapuni 14 /* 呼ぶ!
1620     LR 初期化は、サブモジュール内で行うべし
1621     FASTCALL に準じた呼び出しのため、
1622     ホントはいろいろレジスタが破壊されるハズ…なんだが。 */
1623 notanpe 148 if (pkt_c != pkt_hit)
1624     {
1625 notanpe 192 assert(code_cmp != 0);
1626 notanpe 148 cnt = CALL_CMP64(code + code_cmp,
1627     pkt_hit->param64.hit,
1628     pkt_c->param64.lr);
1629     }
1630     else
1631     {
1632     /* ようやく自スレッドで回せる */
1633     cnt = CALL_CRYPT64(code,
1634     &pkt_c->key64,
1635     &pkt_c->param64);
1636     if (code_cmp)
1637     cnt = CALL_CMP64(code + code_cmp,
1638     pkt_c->param64.hit,
1639     pkt_c->param64.lr);
1640     }
1641 chapuni 42
1642 chapuni 46 #if DEBUG>=1
1643 chapuni 121 cnt2 = (int32_t)(cnt >> 32);
1644     cnt1 = (int32_t)cnt;
1645     if (mincnt > cnt1 && cnt1 > 0)
1646 chapuni 1 {
1647 chapuni 121 mincnt = cnt1;
1648 chapuni 1 if (cr)
1649     fprintf(stderr, "\n");
1650     cr = 0;
1651 chapuni 121 fprintf(stderr, "cycle=%6d/%6d\n", cnt1, cnt2);
1652 chapuni 1 }
1653 chapuni 46 #endif
1654 chapuni 1
1655 notanpe 148 /* ヒットしたときの処理
1656     key および lr は pkt_c に
1657     合致判定は pkt_hit に入っているハズ */
1658 chapuni 74 xhash_loaded = 0;
1659 chapuni 6 for (kk = 0; kk < N_ALU; kk++)
1660 chapuni 1 {
1661 chapuni 6 ALU_T t;
1662 chapuni 84 if (!(kk & (N_ALU / N_Q - 1)))
1663 chapuni 77 nblk_total++, xhash_loaded = 0;
1664 chapuni 9
1665 notanpe 148 t = pkt_hit->param64.hit[HIT_ANY].a[kk];
1666 chapuni 1 if (!t)
1667     continue;
1668 chapuni 9
1669 chapuni 84 nap_total += ALU_BITS;
1670    
1671 chapuni 6 for (k = 0; k < ALU_BITS; k++)
1672 chapuni 1 {
1673 chapuni 74 static uint64_t xhash[64];
1674 chapuni 1 char hash[16];
1675 notanpe 148 uint8_t buf[32];
1676 notanpe 192 struct timeb tb;
1677     struct tm *plt;
1678 chapuni 9
1679     if (!(t & ((ALU_T)1 << k)))
1680 chapuni 1 continue;
1681 chapuni 9
1682 chapuni 84 nap_hit++;
1683    
1684 chapuni 74 /* 転置 */
1685     if (!xhash_loaded)
1686     {
1687 chapuni 77 nblk_hit++;
1688 notanpe 148 CALL_TR64(&pkt_c->param64.lr[0][0].q[kk / (N_ALU / N_Q)], xhash);
1689 chapuni 74 xhash_loaded = 1;
1690     }
1691    
1692     /* 辞書を調べる */
1693 notanpe 148 if (!((pkt_hit->param64.hit[HIT_BOOL].a[kk] & ((ALU_T)1 << k))
1694     || wdict_ishit(pkt_hit->param64.hit,
1695 chapuni 99 kk, k,
1696     xhash[(ALU_BITS * kk + k) & 0x3F])))
1697 chapuni 74 continue;
1698    
1699 notanpe 192 /* ヒット時刻; 魔改造とちょっと違う */
1700     ftime(&tb);
1701     plt = localtime(&tb.time);
1702    
1703 chapuni 1 for (i = 1; i < 11; i++)
1704     {
1705     unsigned c = 0;
1706 chapuni 74 c = (xhash[(ALU_BITS * kk + k) & 63] >> (6 * (i - 1))) & 0x3F; /* XXX */
1707     hash[i - 1] = C64[c];
1708 chapuni 1 }
1709     hash[10] = 0;
1710    
1711 notanpe 148 memcpy(buf, pkt_c->uk.key, 8);
1712 chapuni 1 buf[8] = buf[9] = 0;
1713 chapuni 10 buf[7] = (buf[7] & -(1 << N_STRIDE) & 0x7F) + ALU_BITS * kk + k;
1714 chapuni 1 if (translate(buf, 0, 1))
1715     {
1716     if (cr)
1717     fprintf(stderr, "\n");
1718     cr = 0;
1719 notanpe 148 #if DEBUG>=1
1720     fprintf(stderr, "%3d:", pkt_c - pkts);
1721     #endif
1722 chapuni 24 log_printf(ofp,
1723 notanpe 192 "◆%s #%s"
1724     "\t%04d/%02d/%02d %02d:%02d:%02d.%03d"
1725     "\t(%02X %02X %02X %02X %02X %02X %02X %02X/%02X)\n",
1726 chapuni 24 hash,
1727     buf,
1728 notanpe 192 plt->tm_year + 1900,
1729     plt->tm_mon + 1,
1730     plt->tm_mday,
1731     plt->tm_hour,
1732     plt->tm_min,
1733     plt->tm_sec,
1734     tb.millitm,
1735 chapuni 24 buf[0], buf[1], buf[2], buf[3],
1736     buf[4], buf[5], buf[6], buf[7],
1737 notanpe 192 buf[8]);
1738 chapuni 1 }
1739     else
1740     {
1741 notanpe 192 #if DEBUG>=1
1742 chapuni 1 if (cr)
1743     fprintf(stderr, "\n");
1744     cr = 0;
1745 notanpe 148 fprintf(stderr, "%3d:", pkt_c - pkts);
1746 chapuni 24 log_printf(ofp,
1747 notanpe 192 "◆%s (%02X %02X %02X %02X %02X %02X %02X %02X )\n",
1748 chapuni 24 hash,
1749     buf[0], buf[1], buf[2], buf[3],
1750 notanpe 192 buf[4], buf[5], buf[6], buf[7]);
1751     #endif
1752 chapuni 1 }
1753     }
1754     }
1755    
1756 notanpe 192 /* 速度計測 */
1757 notanpe 115 status.loop += N_ALU * ALU_BITS;
1758 notanpe 192 if (status.loop>= status.lastloop + upd_int
1759     && (curTime = usec()) != status.lastTime)
1760 chapuni 1 {
1761 notanpe 192 uint64_t diffTime;
1762 notanpe 120 int a, b, c;
1763 notanpe 119
1764 notanpe 192 /* 通算(単位 ktrips/sec) */
1765     diffTime = curTime - status.startTime;
1766     a = status.loop / ((1000 / USEC_SEC) * diffTime);
1767    
1768     /* 区間(単位 trips/sec) */
1769 notanpe 120 diffTime = curTime - status.lastTime;
1770 notanpe 192 b = USEC_SEC * (status.loop - status.lastloop) / diffTime;
1771    
1772     /* 予測 */
1773     c = UPDATE_INTERVAL * b;
1774    
1775     /* 立ち上がりなど、誤差があり upd_int が小さすぎたときは
1776     いきなり全補正せず 1 秒(==b)づつ収斂させる。 */
1777     upd_int = (upd_int + b < c
1778     ? upd_int + b
1779     : c);
1780    
1781 notanpe 120 status.lastTime = curTime;
1782     status.lastloop = status.loop;
1783 chapuni 77 #if DEBUG>=1
1784 notanpe 119 fprintf(stderr,
1785     "%5d/%5d(%3d%%)",
1786     nblk_hit, nblk_total, 100 * nblk_hit / nblk_total);
1787     nblk_hit = nblk_total = 0;
1788     if (nap_total)
1789     fprintf(stderr,
1790     " %5d/%5d(%3d%%)",
1791     nap_hit, nap_total, 100 * nap_hit / nap_total);
1792     else
1793     fprintf(stderr,
1794     " -----/-----(---%%)");
1795     nap_hit = nap_total = 0;
1796 chapuni 77 #endif
1797 notanpe 119 fprintf( stderr,
1798 notanpe 120 "%6dktrips/s [%6d.%03dktrips/s]\r",
1799     a, b / 1000, b % 1000 );
1800 notanpe 192 cr++;
1801 chapuni 1 }
1802     }
1803    
1804     return 0;
1805     }
1806    
1807 chapuni 2 /*
1808     * Local Variables:
1809     * tab-width: 4
1810     * End:
1811     *
1812     * EOF */

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Rev URL

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26