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