Develop and Download Open Source Software

Browse Subversion Repository

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 192 - (show 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 /***********************************************************************
2 *
3 * file: mty.c
4 *
5 * まあ、待て屋。
6 *
7 * $Id$
8 *
9 */
10
11 #include <assert.h>
12 #include <ctype.h>
13 #include <errno.h>
14 #include <limits.h>
15 #include <stdarg.h>
16 #include <stddef.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <time.h>
21 #include <sys/timeb.h>
22 #include <sys/types.h>
23
24 #if defined(WIN32)
25
26 #include <windows.h>
27 #include <process.h>
28
29 #elif defined(__GNUC__)
30
31 #include <sys/time.h>
32
33 #endif
34
35 #include "config.h"
36 #include "cp932.h"
37 #include "crypt64.h"
38 #include "desconst.h"
39 #include "expr_parse.h"
40 #include "scoreboard.h"
41 #include "synth.h"
42 #include "tr64.h"
43 #include "translate.h"
44 #include "util.h"
45 #include "wdict.h"
46
47 #if USE_DT
48 #include "dt4.h"
49 #endif
50
51 /* CRYPT64 記述子 */
52 static
53 struct CRYPT64_DESC const *const crypt64_descs[] =
54 {
55 &crypt64_desc,
56 };
57
58 /* 鍵クラス */
59 static
60 struct
61 {
62 unsigned short map[256];
63 } kcls[8 + 8];
64
65 /* 拡張鍵クラス */
66 #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 key_make_map(uint8_t *key, int n)
81 {
82 int i, j;
83 unsigned c = kcls[n].map[key[n]];
84
85 #if USE_DT
86 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 #endif
175
176 /* 最後の部分は class map を生成する必要ナシ */
177 if (n >= 6)
178 return;
179
180 for (i = 0; i < 256; i++)
181 {
182 unsigned bm = 0;
183 #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 #if USE_DT
219 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 #endif
250
251 /* マップから文字を拾ってセット */
252 unsigned
253 key_set(int n, unsigned ch)
254 {
255 int cnt = 0, i;
256
257 #if USE_DT
258 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 #endif
274
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 int i, j;
323 if (!((vk | sk) & 0x7F))
324 return;
325
326 for (i = 0; i < 7; i++)
327 {
328 if (n == 7 && i < N_STRIDE) continue;
329 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 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 }
341 else
342 {
343 assert(o >= 28);
344 assert(o < 56);
345 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 }
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 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 }
363 else
364 {
365 assert(o >= 28);
366 assert(o < 56);
367 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 }
372 }
373 }
374 }
375
376 /* 指定されたクラスの開始値にリセット
377 直前の文字のクラスに縛られる */
378 int
379 key_reset(uint8_t *key, int n)
380 {
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 if (n >= KEY_SHUFFLE_POS)
392 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 key_make_map(key, n);
402
403 return key_reset(key, n + 1);
404 }
405
406 /* 指定された鍵空間の中で、キーをひとつ進める
407 安全にインクリメントできた場合 true を返す */
408 static
409 int
410 key_inc(uint8_t *key, int n)
411 {
412 if (n >= 8)
413 return 0;
414 else if (n == 7)
415 {
416 /* 最後のバイト */
417 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 }
425 else if (key_inc(key, n + 1)
426 /*
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 #if USE_DT
442 /* 辞書語はインクリメントしていい約束にする */
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 #endif
531
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 {
548 key[n] = 0xFF; /* 次に突入させないため */
549 return 0;
550 }
551 }
552
553 if (kcls[n].map[key[n]])
554 {
555 key_make_map(key, n);
556 key_reset(key, n + 1);
557 return 1;
558 }
559 }
560 }
561
562 /* 鍵を完全にリセットする
563 Saltもセットし直す */
564 static
565 void
566 key_init(uint8_t *key)
567 {
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 key_reset(key, 0);
626 }
627
628 /***************************************************************
629 *
630 * 固定キーの生成
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 #if DEBUG>=2
652 printf("%d:%d->%2d: %08X%08X\n",
653 N_Q, i, o,
654 (unsigned)(m >> 32),
655 (unsigned)m);
656 #endif
657 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 * Salt のセット
676 * オペランドのオフセットを書き換えて回ってるので注意
677 *
678 */
679
680 void
681 set_salt(CODE_T *code,
682 struct CRYPT64_DESC const *desc,
683 uint8_t const *k)
684 {
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 //printf("Salt %d:%d %+3d:%+3d",
708 printf("Salt %d:%d %08lX:%08lX",
709 i, j,
710 LSALT(desc, code, 0, i, j, 0),
711 LSALT(desc, code, 0, i, j, 24));
712 #endif
713 if (s & (1 << j))
714 {
715 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 }
718 else
719 {
720 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 }
723 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 #if DEBUG>=2
726 //printf(" => %+3d:%+3d\n",
727 printf(" => %08lX:%08lX\n",
728 LSALT(desc, code, 0, i, j, 0),
729 LSALT(desc, code, 0, i, j, 24));
730 #endif
731 }
732 }
733 }
734
735 #define USEC_SEC 1000 /* 1秒 */
736
737 static
738 uint64_t
739 usec(void)
740 {
741 uint32_t sec, msec;
742
743 #if !defined(WIN32)
744 struct timeval tv;
745 gettimeofday(&tv, NULL);
746 sec = tv.tv_sec;
747 msec = tv.tv_usec / (1000000 / USEC_SEC);
748 #else
749 struct timeb tm;
750 ftime(&tm);
751 sec = tm.time;
752 msec = tm.millitm / (1000 / USEC_SEC);
753 #endif
754
755 return (uint64_t)USEC_SEC * sec + msec;
756 }
757
758 static
759 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 /***************************************************************
775 *
776 * CPU capabilities を取得
777 * [XXX] あまりにも古いプロセッサのことは考えない。
778 *
779 * a[4] = {EAX,EBX,ECX,EDX}
780 *
781 */
782
783 #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 {
802 unsigned a, b, c, d;
803 cpuid(1, a, b, c, d);
804 return d;
805 }
806
807 static
808 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 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 intptr_t a = 128;
831 struct PACKET_CRYPT64 *pkts;
832 assert(IS_POWER2(sizeof(struct PACKET_CRYPT64)));
833 assert(n >= 1);
834
835 siz = (a - 1
836 + (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 + a - 1)
842 & -a);
843 #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 int j, k;
857
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 for (k = 0; k < N_ALU; k++)
868 pkts[i].key64.ks[j].a[k] = sizeof(WS_T) * ks_ls[j];
869
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 int
950 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 #elif defined(_POSIX_SOURCE)
961
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 THREAD_EV_T *p_ev_ks_activated;
1095 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 /* 寝た */
1199 if (tmo == THREAD_INFINITE)
1200 {
1201 LOCK_INC(param->p_nidle);
1202 }
1203
1204 /* 要求待ち */
1205 r = thread_wait_event(*param->p_ev_ks_activated, tmo);
1206
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 main(int argc, char *argv[])
1276 {
1277 int i;
1278 int mincnt;
1279 int nblk_hit, nblk_total;
1280 int nap_hit, nap_total;
1281 CODE_T *code = NULL;
1282 off_t code_cmp;
1283 FILE *ofp;
1284 FILE *sfp; /* scoreboard */
1285 struct ITREE *root_expr;
1286 uint64_t proc_mask;
1287 int ks_activated;
1288 static THREAD_EV_T event_ks_activated;
1289 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 int cr;
1297
1298 /* 鍵文字列 */
1299 uint8_t key[8 + 8];
1300
1301 int xhash_loaded;
1302
1303 #define UPDATE_INTERVAL 8 /* 速度表示の間隔 秒 */
1304 struct status {
1305 uint64_t startTime; /* 開始時刻 ミリ秒 */
1306 uint64_t lastTime; /* 最後に表示した時刻 ミリ秒 */
1307 uint64_t loop; /* 総検索個数 */
1308 uint64_t lastloop; /* 最後に表示した時の loop */
1309 } status;
1310 uint64_t curTime;
1311 uint32_t upd_int = 0;
1312 /*
1313 平均速度 (trips/s) * UPDATE_INTERVAL が UINT32_MAX を超えると発狂する。
1314 UINT32_MAX = 4294967295, 平均速度 = 100Mtrips/s なら、
1315 4294967295 / (100 * 1000 * 1000) = 42.949 秒まで。(和良
1316 LOOP_FACTOR が平均速度より十分小さければ、ほぼ指定間隔になる。
1317 LOOP_FACTOR * UINT32_MAX + LOOP_FACOTR 個検索するとオーバーフローする。w
1318 */
1319
1320 if (!cpuid_issupported())
1321 {
1322 fprintf(stderr, "この環境で走らせることが想定されていません。\n");
1323 exit(1);
1324 }
1325
1326 assert((1 << N_STRIDE) == N_ALU * ALU_BITS);
1327
1328 /* タゲ読み込み */
1329 root_expr = expr_parse("target.txt");
1330
1331 /* コードを生成・展開
1332 起動予定スレッド数に応じて
1333 生成するコードを変える */
1334 sfp = scoreboard_open();
1335 fwrite(crypt64_descs[0]->pro, 1, crypt64_descs[0]->cmp_pro - crypt64_descs[0]->pro, sfp); /* prologue & コアループ */
1336 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 fwrite(crypt64_descs[0]->ep, 1, crypt64_descs[0]->ep_end - crypt64_descs[0]->ep, sfp); /* epilogue */
1348
1349 /* 比較器のみを生成(前半) */
1350 code_cmp = ftell(sfp);
1351 fseek(sfp, (-code_cmp) & 63, SEEK_CUR);
1352 code_cmp = ftell(sfp);
1353 fwrite(crypt64_descs[0]->pro, 1, crypt64_descs[0]->crypt - crypt64_descs[0]->pro, sfp); /* prologue */
1354 npkts = 64;
1355 pkts_vacant = (uint64_t)-1; /* (1 << 64) - 1 を計算したくない */
1356 }
1357
1358 /* 比較部を生成 */
1359 fwrite(crypt64_descs[0]->cmp_pro, 1, crypt64_descs[0]->cmp_ep - crypt64_descs[0]->cmp_pro, sfp); /* 比較器準備 */
1360 tn = synth_synthesize(sfp, root_expr);
1361 fwrite(crypt64_descs[0]->cmp_ep, 1, crypt64_descs[0]->ep_end - crypt64_descs[0]->cmp_ep, sfp); /* epilogue */
1362
1363 /* コードをメモリに貼り付ける */
1364 code = scoreboard_map(sfp);
1365
1366 /* キーの初期化 */
1367 srand(time(NULL));
1368 key_init(key);
1369 set_salt(code, crypt64_descs[0], key);
1370
1371 /* 演算パケットを作成 */
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 #endif
1395 #if defined(thread_set_priority)
1396 /* 心の隙間お埋めします */
1397 threads[nthreads].code = code;
1398 threads[nthreads].p_ev_ks_activated = &event_ks_activated;
1399 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
1408 /* 自分自身の残りの設定を、あとでやる */
1409 ots = i;
1410 }
1411 else
1412 {
1413 /* 他スレッドは、やや低めの優先度で。 */
1414 threads[nthreads].code = code;
1415 threads[nthreads].p_ev_ks_activated = &event_ks_activated;
1416 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 if ((ofp = fopen("log.txt", "at")) == NULL)
1437 {
1438 perror("log.txt");
1439 return errno;
1440 }
1441
1442 setvbuf(ofp, NULL, _IONBF, BUFSIZ); /* XXX MSVCRT では _IOLBF が期待通りに動作しない */
1443
1444 mincnt = 0x7FFFFFFF;
1445 nblk_hit = nblk_total = 0;
1446 nap_hit = nap_total = 0;
1447 cr = 0;
1448 memset( &status, 0, sizeof( struct status ) );
1449 status.startTime = status.lastTime = usec();
1450 /* 探索ループだぞっと */
1451 for (;;)
1452 {
1453 struct PACKET_CRYPT64 *pkt_c;
1454 uint64_t cnt;
1455 int cnt1, cnt2;
1456 int k, kk;
1457
1458 /* 比較器候補(may be NULL)
1459 先にキューから取り出す */
1460 pkt_c = q_cmp[WRAP(rp_cmp, NQ_CMP)];
1461 if (pkt_c != NULL && WRAP(rp_cmp, NQ_CMP) != WRAP(wp_cmp, NQ_CMP))
1462 {
1463 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 }
1470
1471 /* Saltチェンジ待ち */
1472 if (!ks_activated)
1473 {
1474 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 if (nidle == nthreads)
1505 {
1506 assert(WRAP(rp_crypt, NQ_CRYPT) == WRAP(wp_crypt, NQ_CRYPT));
1507 /* Salt チェンジが可能 */
1508 set_salt(code, crypt64_descs[0], key);
1509 if (nthreads)
1510 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 if (WRAP(wp_crypt, NQ_CRYPT) == WRAP(rp_crypt - 16, NQ_CRYPT) /* XXX 16 はてきとう */
1542 || 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 if (nthreads)
1592 thread_clear_event(event_ks_activated);
1593 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 /* 呼ぶ!
1620 LR 初期化は、サブモジュール内で行うべし
1621 FASTCALL に準じた呼び出しのため、
1622 ホントはいろいろレジスタが破壊されるハズ…なんだが。 */
1623 if (pkt_c != pkt_hit)
1624 {
1625 assert(code_cmp != 0);
1626 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
1642 #if DEBUG>=1
1643 cnt2 = (int32_t)(cnt >> 32);
1644 cnt1 = (int32_t)cnt;
1645 if (mincnt > cnt1 && cnt1 > 0)
1646 {
1647 mincnt = cnt1;
1648 if (cr)
1649 fprintf(stderr, "\n");
1650 cr = 0;
1651 fprintf(stderr, "cycle=%6d/%6d\n", cnt1, cnt2);
1652 }
1653 #endif
1654
1655 /* ヒットしたときの処理
1656 key および lr は pkt_c に
1657 合致判定は pkt_hit に入っているハズ */
1658 xhash_loaded = 0;
1659 for (kk = 0; kk < N_ALU; kk++)
1660 {
1661 ALU_T t;
1662 if (!(kk & (N_ALU / N_Q - 1)))
1663 nblk_total++, xhash_loaded = 0;
1664
1665 t = pkt_hit->param64.hit[HIT_ANY].a[kk];
1666 if (!t)
1667 continue;
1668
1669 nap_total += ALU_BITS;
1670
1671 for (k = 0; k < ALU_BITS; k++)
1672 {
1673 static uint64_t xhash[64];
1674 char hash[16];
1675 uint8_t buf[32];
1676 struct timeb tb;
1677 struct tm *plt;
1678
1679 if (!(t & ((ALU_T)1 << k)))
1680 continue;
1681
1682 nap_hit++;
1683
1684 /* 転置 */
1685 if (!xhash_loaded)
1686 {
1687 nblk_hit++;
1688 CALL_TR64(&pkt_c->param64.lr[0][0].q[kk / (N_ALU / N_Q)], xhash);
1689 xhash_loaded = 1;
1690 }
1691
1692 /* 辞書を調べる */
1693 if (!((pkt_hit->param64.hit[HIT_BOOL].a[kk] & ((ALU_T)1 << k))
1694 || wdict_ishit(pkt_hit->param64.hit,
1695 kk, k,
1696 xhash[(ALU_BITS * kk + k) & 0x3F])))
1697 continue;
1698
1699 /* ヒット時刻; 魔改造とちょっと違う */
1700 ftime(&tb);
1701 plt = localtime(&tb.time);
1702
1703 for (i = 1; i < 11; i++)
1704 {
1705 unsigned c = 0;
1706 c = (xhash[(ALU_BITS * kk + k) & 63] >> (6 * (i - 1))) & 0x3F; /* XXX */
1707 hash[i - 1] = C64[c];
1708 }
1709 hash[10] = 0;
1710
1711 memcpy(buf, pkt_c->uk.key, 8);
1712 buf[8] = buf[9] = 0;
1713 buf[7] = (buf[7] & -(1 << N_STRIDE) & 0x7F) + ALU_BITS * kk + k;
1714 if (translate(buf, 0, 1))
1715 {
1716 if (cr)
1717 fprintf(stderr, "\n");
1718 cr = 0;
1719 #if DEBUG>=1
1720 fprintf(stderr, "%3d:", pkt_c - pkts);
1721 #endif
1722 log_printf(ofp,
1723 "◆%s #%s"
1724 "\t%04d/%02d/%02d %02d:%02d:%02d.%03d"
1725 "\t(%02X %02X %02X %02X %02X %02X %02X %02X/%02X)\n",
1726 hash,
1727 buf,
1728 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 buf[0], buf[1], buf[2], buf[3],
1736 buf[4], buf[5], buf[6], buf[7],
1737 buf[8]);
1738 }
1739 else
1740 {
1741 #if DEBUG>=1
1742 if (cr)
1743 fprintf(stderr, "\n");
1744 cr = 0;
1745 fprintf(stderr, "%3d:", pkt_c - pkts);
1746 log_printf(ofp,
1747 "◆%s (%02X %02X %02X %02X %02X %02X %02X %02X )\n",
1748 hash,
1749 buf[0], buf[1], buf[2], buf[3],
1750 buf[4], buf[5], buf[6], buf[7]);
1751 #endif
1752 }
1753 }
1754 }
1755
1756 /* 速度計測 */
1757 status.loop += N_ALU * ALU_BITS;
1758 if (status.loop>= status.lastloop + upd_int
1759 && (curTime = usec()) != status.lastTime)
1760 {
1761 uint64_t diffTime;
1762 int a, b, c;
1763
1764 /* 通算(単位 ktrips/sec) */
1765 diffTime = curTime - status.startTime;
1766 a = status.loop / ((1000 / USEC_SEC) * diffTime);
1767
1768 /* 区間(単位 trips/sec) */
1769 diffTime = curTime - status.lastTime;
1770 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 status.lastTime = curTime;
1782 status.lastloop = status.loop;
1783 #if DEBUG>=1
1784 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 #endif
1797 fprintf( stderr,
1798 "%6dktrips/s [%6d.%03dktrips/s]\r",
1799 a, b / 1000, b % 1000 );
1800 cr++;
1801 }
1802 }
1803
1804 return 0;
1805 }
1806
1807 /*
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