progs/perftest.c: Use from Glibc syscall numbers.
[catacomb] / progs / rspit.c
1 /* -*-c-*-
2 *
3 * Spit out random numbers
4 *
5 * (c) 1999 Straylight/Edgeware
6 */
7
8 /*----- Licensing notice --------------------------------------------------*
9 *
10 * This file is part of Catacomb.
11 *
12 * Catacomb is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as
14 * published by the Free Software Foundation; either version 2 of the
15 * License, or (at your option) any later version.
16 *
17 * Catacomb is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with Catacomb; if not, write to the Free
24 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25 * MA 02111-1307, USA.
26 */
27
28 /*----- Header files ------------------------------------------------------*/
29
30 #define _FILE_OFFSET_BITS 64
31
32 #include "config.h"
33
34 #include <assert.h>
35 #include <errno.h>
36 #include <math.h>
37 #include <signal.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <time.h>
42
43 #ifndef PORTABLE
44 # include <unistd.h>
45 # include <sys/time.h>
46 #endif
47
48 #include <mLib/darray.h>
49 #include <mLib/dstr.h>
50 #include <mLib/macros.h>
51 #include <mLib/mdwopt.h>
52 #include <mLib/quis.h>
53 #include <mLib/report.h>
54 #include <mLib/sub.h>
55
56 #include "mp.h"
57 #include "mpint.h"
58 #include "mplimits.h"
59 #include "mptext.h"
60
61 #include "fipstest.h"
62 #include "grand.h"
63 #include "maurer.h"
64 #include "key.h"
65
66 #include "lcrand.h"
67 #include "fibrand.h"
68 #include "rand.h"
69 #include "noise.h"
70
71 #include "bbs.h"
72 #include "mprand.h"
73
74 #include "chacha.h"
75 #include "rc4.h"
76 #include "salsa20.h"
77 #include "salsa20-core.h"
78 #include "seal.h"
79 #include "sha3.h"
80
81 #include "des-ofb.h"
82 #include "des3-ofb.h"
83 #include "rc2-ofb.h"
84 #include "rc5-ofb.h"
85 #include "mars-ofb.h"
86 #include "skipjack-ofb.h"
87 #include "tea-ofb.h"
88 #include "xtea-ofb.h"
89 #include "blowfish-ofb.h"
90 #include "twofish-ofb.h"
91 #include "idea-ofb.h"
92 #include "cast128-ofb.h"
93 #include "cast256-ofb.h"
94 #include "noekeon-ofb.h"
95 #include "rijndael-ofb.h"
96 #include "rijndael192-ofb.h"
97 #include "rijndael256-ofb.h"
98 #include "safer-ofb.h"
99 #include "safersk-ofb.h"
100 #include "square-ofb.h"
101 #include "serpent-ofb.h"
102
103 #include "des-counter.h"
104 #include "des3-counter.h"
105 #include "rc2-counter.h"
106 #include "rc5-counter.h"
107 #include "mars-counter.h"
108 #include "skipjack-counter.h"
109 #include "tea-counter.h"
110 #include "xtea-counter.h"
111 #include "blowfish-counter.h"
112 #include "twofish-counter.h"
113 #include "idea-counter.h"
114 #include "cast128-counter.h"
115 #include "cast256-counter.h"
116 #include "noekeon-counter.h"
117 #include "rijndael-counter.h"
118 #include "rijndael192-counter.h"
119 #include "rijndael256-counter.h"
120 #include "safer-counter.h"
121 #include "safersk-counter.h"
122 #include "square-counter.h"
123 #include "serpent-counter.h"
124
125 #include "md2-mgf.h"
126 #include "md4-mgf.h"
127 #include "md5-mgf.h"
128 #include "sha-mgf.h"
129 #include "tiger-mgf.h"
130 #include "rmd128-mgf.h"
131 #include "rmd160-mgf.h"
132 #include "rmd256-mgf.h"
133 #include "rmd320-mgf.h"
134
135 #include "rmd160.h"
136
137 /*----- Data structures ---------------------------------------------------*/
138
139 typedef struct gen {
140 const char *name;
141 grand *(*seed)(unsigned /*i*/);
142 unsigned i;
143 const char *help;
144 } gen;
145
146 extern gen generators[];
147
148 #define CIPHERS \
149 E(DES, des) \
150 E(DES3, des3) \
151 E(RC2, rc2) \
152 E(RC5, rc5) \
153 E(MARS, mars) \
154 E(SKIPJACK, skipjack) \
155 E(TEA, tea) \
156 E(XTEA, xtea) \
157 E(BLOWFISH, blowfish) \
158 E(TWOFISH, twofish) \
159 E(IDEA, idea) \
160 E(CAST128, cast128) \
161 E(CAST256, cast256) \
162 E(SQUARE, square) \
163 E(SAFER, safer) \
164 E(SAFERSK, safersk) \
165 E(NOEKEON, noekeon) \
166 E(RIJNDAEL, rijndael) \
167 E(RIJNDAEL192, rijndael192) \
168 E(RIJNDAEL256, rijndael256) \
169 E(SERPENT, serpent)
170
171 #define HASHES \
172 E(MD2, md2) \
173 E(MD4, md4) \
174 E(MD5, md5) \
175 E(SHA, sha) \
176 E(TIGER, tiger) \
177 E(RMD128, rmd128) \
178 E(RMD160, rmd160) \
179 E(RMD256, rmd256) \
180 E(RMD320, rmd320)
181
182 #define E(PRE, pre) CIPHER_##PRE,
183 enum { CIPHERS CIPHER__bogus };
184 #undef E
185
186 #define E(PRE, pre) HASH_##PRE,
187 enum { HASHES HASH__bogus };
188 #undef E
189
190 static const struct {
191 const octet *keysz;
192 size_t blksz;
193 grand *(*ofb)(const void */*k*/, size_t /*sz*/);
194 grand *(*counter)(const void */*k*/, size_t /*sz*/);
195 } ciphertab[] = {
196 #define E(PRE, pre) \
197 { pre##_keysz, PRE##_BLKSZ, pre##_ofbrand, pre##_counterrand },
198 CIPHERS
199 #undef E
200 };
201
202 static const struct {
203 const gchash *h;
204 const octet *keysz;
205 grand *(*mgf)(const void */*k*/, size_t /*sz*/);
206 } hashtab[] = {
207 #define E(PRE, pre) \
208 { &pre, pre##_mgfkeysz, pre##_mgfrand },
209 HASHES
210 #undef E
211 };
212
213 #define SALSAE \
214 E(salsa20, 20,, SALSA20) \
215 E(salsa20, 12,, SALSA20) \
216 E(salsa20, 8,, SALSA20) \
217 E(xsalsa20, 20, X, SALSA20) \
218 E(xsalsa20, 12, X, SALSA20) \
219 E(xsalsa20, 8, X, SALSA20) \
220 E(chacha, 20,, CHACHA) \
221 E(chacha, 12,, CHACHA) \
222 E(chacha, 8,, CHACHA) \
223 E(xchacha, 20, X, CHACHA) \
224 E(xchacha, 12, X, CHACHA) \
225 E(xchacha, 8, X, CHACHA)
226
227 #define E(pre, r, x, BASE) pre##_##r##_INDEX,
228 enum { SALSAE BOGUS_SALSA };
229 #undef E
230
231 #define SALSA20_GEN(pre, r) SALSA20_DECOR(pre, r, _rand)
232 #define CHACHA_GEN(pre, r) pre##r##_rand
233
234 #define SALSA20_NAME(r) SALSA20_NAME_##r
235 #define XSALSA20_NAME(r) "x" SALSA20_NAME_##r
236 #define CHACHA_NAME(r) "chacha" #r
237 #define XCHACHA_NAME(r) "xchacha" #r
238
239 static const struct {
240 size_t noncesz;
241 grand *(*gen)(const void *, size_t, const void *);
242 } salsatab[] = {
243 #define E(pre, r, x, BASE) { x##BASE##_NONCESZ, BASE##_GEN(pre, r) },
244 SALSAE
245 #undef E
246 };
247
248 #define SHAKES E(128) E(256)
249
250 enum {
251 #define E(sz) SHAKE##sz##_INDEX,
252 SHAKES
253 #undef E
254 SHAKE__LIMIT
255 };
256
257 static const struct {
258 const octet *ksz;
259 grand *(*shake)(const void *, size_t, const void *, size_t,
260 const void *, size_t);
261 grand *(*kmac)(const void *, size_t,
262 const void *, size_t);
263 } shaketab[] = {
264 #define E(sz) { shake##sz##_keysz, cshake##sz##_rand, kmac##sz##_rand },
265 SHAKES
266 #undef E
267 };
268
269 /*----- Miscellaneous static data -----------------------------------------*/
270
271 static FILE *outfp;
272 static mp *outsz = 0;
273 static unsigned maurer_lo = 5, maurer_hi = 8;
274
275 static int argc;
276 static char **argv;
277
278 static unsigned flags = 0;
279
280 #define f_progress 1u
281 #define f_file 2u
282 #define f_fips 4u
283 #define f_maurer 8u
284 #define f_timer 16u
285 #define f_discard 32u
286
287 /*----- Help options ------------------------------------------------------*/
288
289 static void usage(FILE *fp)
290 {
291 pquis(fp, "Usage: $ generator [options]\n");
292 }
293
294 static void version(FILE *fp)
295 {
296 pquis(fp, "$, Catacomb version " VERSION "\n");
297 }
298
299 static void help(FILE *fp)
300 {
301 version(fp);
302 fputc('\n', fp);
303 usage(fp);
304 pquis(fp, "\n\
305 Emits a stream of random bytes suitable for, well, all sorts of things.\n\
306 The primary objective is to be able to generate streams of input for\n\
307 statistical tests, such as Diehard.\n\
308 \n\
309 Options are specific to the particular generator, although there's a\n\
310 common core set:\n\
311 \n\
312 -h, --help Display this help message.\n\
313 -v, --version Display the program's version number.\n\
314 -u, --usage Display a useless usage message.\n\
315 \n\
316 -l, --list Show a list of the supported generators, with\n\
317 their options.\n\
318 -f, --fipstest Run the FIPS 140-1 randomness test.\n\
319 -m, --maurer[=LO-HI] Run Maurer's universal statistical test.\n\
320 -o, --output FILE Write output to FILE, not stdout.\n\
321 -z, --size SIZE Emit SIZE bytes, not an unlimited number.\n\
322 -p, --progress Show a little progress meter (on stderr).\n\
323 -T, --timer Keep track of the CPU time used by the generator.\n\
324 -d, --discard Discard the generated output.\n\
325 \n\
326 (A SIZE may be followed by `g' for gigabytes, `m' for megabytes, or\n\
327 `k' for kilobytes. If unqualified, an amount in bytes is assumed.)\n\
328 ");
329 }
330
331 /*----- Main options parser -----------------------------------------------*/
332
333 static struct option opts[] = {
334
335 /* --- Standard GNU help options --- */
336
337 { "help", 0, 0, 'h' },
338 { "version", 0, 0, 'v' },
339 { "usage", 0, 0, 'u' },
340
341 /* --- Other useful things --- */
342
343 { "list", 0, 0, 'l' },
344 { "fipstest", 0, 0, 'f' },
345 { "maurer", OPTF_ARGOPT, 0, 'm' },
346 { "output", OPTF_ARGREQ, 0, 'o' },
347 { "size", OPTF_ARGREQ, 0, 'z' },
348 { "progress", 0, 0, 'p' },
349 { "timer", 0, 0, 'T' },
350 { "discard", 0, 0, 'd' },
351
352 /* --- End of main table --- */
353
354 { 0, 0, 0, 0 }
355 };
356
357 static const char *sopts = "hvu lfm::o:z:pTd";
358
359 #ifndef OPTION_V
360 DA_DECL(option_v, struct option);
361 # define OPTION_V
362 #endif
363
364 static option_v optv = DA_INIT;
365 static dstr optd = DSTR_INIT;
366
367 /* --- @addopts@ --- *
368 *
369 * Arguments: @const char *s@ = pointer to short options
370 * @struct option *l@ = pointer to long options
371 *
372 * Returns: ---
373 *
374 * Use: Adds a collection of options to the table.
375 */
376
377 static void addopts(const char *s, struct option *l)
378 {
379 dstr_puts(&optd, s);
380 if (DA_LEN(&optv))
381 DA_SHRINK(&optv, 1);
382 while (l->name)
383 DA_PUSH(&optv, *l++);
384 DA_PUSH(&optv, *l);
385 }
386
387 /* --- @opt@ --- *
388 *
389 * Arguments: ---
390 *
391 * Returns: Next option from argument array.
392 *
393 * Use: Fetches options, handling the standard ones.
394 */
395
396 static int opt(void)
397 {
398 for (;;) {
399 int i = mdwopt(argc, argv, optd.buf, DA(&optv), 0, 0, 0);
400 switch (i) {
401 case 'h':
402 help(stdout);
403 exit(0);
404 case 'v':
405 version(stdout);
406 exit(0);
407 case 'u':
408 usage(stdout);
409 exit(0);
410 case 'l': {
411 gen *g;
412 puts("Generators supported:");
413 for (g = generators; g->name; g++)
414 printf(" %s %s\n", g->name, g->help);
415 exit(0);
416 } break;
417 case 'f':
418 flags |= f_fips;
419 break;
420 case 'm':
421 flags |= f_maurer;
422 if (optarg) {
423 char *p;
424 unsigned long lo, hi;
425 lo = strtoul(optarg, &p, 0);
426 if (*p == '-' || *p == ',')
427 hi = strtoul(p + 1, &p, 0);
428 else
429 hi = lo;
430 if (*p != 0 || hi < lo || lo == 0)
431 die(EXIT_FAILURE, "bad bit range `%s'", optarg);
432 maurer_lo = lo;
433 maurer_hi = hi;
434 }
435 break;
436 case 'o':
437 if (flags & f_file)
438 die(EXIT_FAILURE, "already set an output file");
439 if (STRCMP(optarg, ==, "-"))
440 outfp = stdout;
441 else {
442 outfp = fopen(optarg, "w");
443 if (!outfp) {
444 die(EXIT_FAILURE, "couldn't open output file `%s': %s",
445 optarg, strerror(errno));
446 }
447 }
448 flags |= f_file;
449 break;
450 case 'z': {
451 char *p;
452 outsz = mp_readstring(outsz, optarg, &p, 0);
453 if (!outsz || MP_NEGP(outsz))
454 die(EXIT_FAILURE, "bad number `%s'", optarg);
455 switch (*p) {
456 case 'G': case 'g': outsz = mp_lsl(outsz, outsz, 10);
457 case 'M': case 'm': outsz = mp_lsl(outsz, outsz, 10);
458 case 'K': case 'k': outsz = mp_lsl(outsz, outsz, 10);
459 case 0:
460 break;
461 default:
462 die(EXIT_FAILURE, "bad suffix `%s'", p);
463 break;
464 }
465 if (*p && p[1] != 0)
466 die(EXIT_FAILURE, "bad suffix `%s'", p);
467 } break;
468 case 'p':
469 flags |= f_progress;
470 break;
471 case 'T':
472 flags |= f_timer;
473 break;
474 case 'd':
475 flags |= f_discard;
476 break;
477 default:
478 return (i);
479 }
480 }
481 }
482
483 /*----- Manglers for seed strings -----------------------------------------*/
484
485 /* --- @unhex@ --- *
486 *
487 * Arguments: @const char *p@ = pointer to input string
488 * @char **end@ = where the end goes
489 * @dstr *d@ = output buffer
490 *
491 * Returns: ---
492 *
493 * Use: Transforms a hex string into a chunk of binary data.
494 */
495
496 static void unhex(const char *p, char **end, dstr *d)
497 {
498 while (p[0] && p[1]) {
499 int x = p[0], y = p[1];
500 if ('0' <= x && x <= '9') x -= '0';
501 else if ('A' <= x && x <= 'F') x -= 'A' - 10;
502 else if ('a' <= x && x <= 'f') x -= 'a' - 10;
503 else x = 0;
504 if ('0' <= y && y <= '9') y -= '0';
505 else if ('A' <= y && y <= 'F') y -= 'A' - 10;
506 else if ('a' <= y && y <= 'f') y -= 'a' - 10;
507 else y = 0;
508 DPUTC(d, (x << 4) + y);
509 p += 2;
510 }
511 *end = (char *)p;
512 }
513
514 /* --- Generate a key --- */
515
516 static void textkey(dstr *d, const char *p, const octet *ksz)
517 {
518 size_t sz = strlen(p);
519
520 if (!sz)
521 die(EXIT_FAILURE, "zero-length key string");
522 if (keysz(sz, ksz) != sz)
523 DPUTM(d, p, sz);
524 else {
525 rmd160_mgfctx g;
526 rmd160_mgfinit(&g, p, sz);
527 sz = keysz(0, ksz);
528 dstr_ensure(d, sz);
529 rmd160_mgfencrypt(&g, 0, d->buf, sz);
530 d->len += sz;
531 }
532 assert(((void)"I can't seem to choose a good key size",
533 keysz(d->len, ksz) == d->len));
534 }
535
536 static void hexkey(dstr *d, const char *p, const octet *ksz)
537 {
538 char *q;
539 unhex(optarg, &q, d);
540 if (*q)
541 die(EXIT_FAILURE, "bad hex key `%s'", p);
542 if (keysz(d->len, ksz) != d->len)
543 die(EXIT_FAILURE, "bad key length");
544 }
545
546 static void randkey(dstr *d, const octet *ksz)
547 {
548 size_t sz = keysz(0, ksz);
549 dstr_ensure(d, sz);
550 rand_get(RAND_GLOBAL, d->buf, sz);
551 d->len += sz;
552 }
553
554 /*----- Generators --------------------------------------------------------*/
555
556 /* --- Blum-Blum-Shub strong generator --- */
557
558 static grand *gen_bbs(unsigned i)
559 {
560 /* --- Default modulus --- *
561 *
562 * The factors of this number are
563 *
564 * @p = 1229936431484295969649886203367009966370895964206162032259292413@
565 * @7754313537966036459299022912838407755462506416274551744201653277@
566 * @313130311731673973886822067@
567 *
568 * @q = 9798171783943489959487301695884963889684294764514008432498259742@
569 * @5374320073594018817245784145742769603334292182227671519041431067@
570 * @61344781426317516045890159@
571 *
572 * Both %$p$% and %$q$% are prime; %$(p - 1)/2$% and %$(q - 1)/2$% have no
573 * common factors. They were found using this program, with random
574 * starting points.
575 *
576 * I hope that, by publishing these factors, I'll dissuade people from
577 * actually using this modulus in an attempt to attain real security. The
578 * program is quite quick at finding Blum numbers, so there's no excuse for
579 * not generating your own.
580 */
581
582 const char *mt =
583 "12051128439013574251357214209433471144307319411973256935382082"
584 "84356405274180923922403660880355098909699130818163691602989614"
585 "90135716255689660470370755013177656905237112577648090277537209"
586 "93607817155427455344810369808478266925293635284364998010510985"
587 "0503830397166360721262431179505917248447259735253684659338653";
588
589 /* --- Other things --- */
590
591 grand *r;
592 const char *xt = 0;
593 unsigned bits = 1024;
594 mp *m, *x;
595 unsigned show = 0;
596 const char *kfile = 0, *id = 0, *ktype = 0;
597
598 /* --- Parse options --- */
599
600 static struct option opts[] = {
601 { "modulus", OPTF_ARGREQ, 0, 'M' },
602 { "generate", 0, 0, 'g' },
603 { "seed", OPTF_ARGREQ, 0, 's' },
604 { "bits", OPTF_ARGREQ, 0, 'b' },
605 { "show", 0, 0, 'S' },
606 { "keyring", OPTF_ARGREQ, 0, 'k' },
607 { "id", OPTF_ARGREQ, 0, 'i' },
608 { "type", OPTF_ARGREQ, 0, 't' },
609 { 0, 0, 0, 0 }
610 };
611
612 addopts("M:gs:b:Sk:i:t:", opts);
613
614 for (;;) {
615 int o = opt();
616 if (o < 0)
617 break;
618 switch (o) {
619 case 'M':
620 mt = optarg;
621 break;
622 case 'g':
623 mt = 0;
624 break;
625 case 's':
626 xt = optarg;
627 break;
628 case 'b':
629 bits = strtoul(optarg, 0, 0);
630 if (bits == 0)
631 die(EXIT_FAILURE, "bad number of bits `%s'", optarg);
632 break;
633 case 'S':
634 show = 1;
635 break;
636 case 'k':
637 kfile = optarg;
638 mt = 0;
639 break;
640 case 'i':
641 id = optarg;
642 mt = 0;
643 break;
644 case 't':
645 ktype = optarg;
646 mt = 0;
647 break;
648 default:
649 return (0);
650 }
651 }
652
653 /* --- Generate a modulus if one is requested --- */
654
655 if (mt) {
656 char *p;
657 m = mp_readstring(MP_NEW, mt, &p, 0);
658 if (!m || *p || (m->v[0] & 3) != 1)
659 die(EXIT_FAILURE, "bad modulus `%s'", mt);
660 /* Unfortunately I don't know how to test for a Blum integer */
661 } else if (kfile || id || ktype) {
662 key_file kf;
663 key *kk;
664 key_data *kd;
665
666 /* --- Open the key file --- */
667
668 if (!kfile)
669 kfile = "keyring";
670 if (key_open(&kf, kfile, KOPEN_READ, key_moan, 0)) {
671 die(EXIT_FAILURE, "error opening key file `%s': %s",
672 kfile, strerror(errno));
673 }
674
675 /* --- Find the key --- */
676
677 if (id) {
678 if ((kk = key_bytag(&kf, id)) == 0)
679 die(EXIT_FAILURE, "key `%s' not found", id);
680 } else {
681 if (!ktype)
682 ktype = "bbs";
683 if ((kk = key_bytype(&kf, ktype)) == 0)
684 die(EXIT_FAILURE, "no suitable key with type `%s' found", ktype);
685 }
686
687 /* --- Read the key data --- */
688
689 if ((kk->k->e & KF_ENCMASK) != KENC_STRUCT)
690 die(EXIT_FAILURE, "key is not structured");
691 if ((kd = key_structfind(kk->k, "n")) == 0)
692 die(EXIT_FAILURE, "key has no subkey `n'");
693 if ((kd->e & KF_ENCMASK) != KENC_MP)
694 die(EXIT_FAILURE, "incompatible subkey encoding");
695 m = MP_COPY(kd->u.m);
696 key_close(&kf);
697 } else {
698 bbs_priv bp;
699
700 if (bbs_gen(&bp, bits, &rand_global, 0,
701 (flags & f_progress) ? pgen_ev : 0, 0))
702 die(EXIT_FAILURE, "modulus generation failed");
703 m = bp.n;
704
705 if (show) {
706 fputs("p = ", stderr);
707 mp_writefile(bp.p, stderr, 10);
708 fputs("\nq = ", stderr);
709 mp_writefile(bp.q, stderr, 10);
710 fputs("\nn = ", stderr);
711 mp_writefile(bp.n, stderr, 10);
712 fputc('\n', stderr);
713 }
714
715 mp_drop(bp.p);
716 mp_drop(bp.q);
717 }
718
719 /* --- Set up a seed --- */
720
721 if (!xt)
722 x = mprand(MP_NEW, mp_bits(m) - 1, &rand_global, 1);
723 else {
724 char *p;
725 x = mp_readstring(MP_NEW, xt, &p, 0);
726 if (*p)
727 die(EXIT_FAILURE, "bad modulus `%s'", xt);
728 }
729
730 /* --- Right --- */
731
732 r = bbs_rand(m, x);
733
734 mp_drop(m);
735 mp_drop(x);
736 return (r);
737 }
738
739 /* --- Catacomb's random number generator --- */
740
741 static grand *gen_rand(unsigned i)
742 {
743 grand *r = rand_create();
744 dstr d = DSTR_INIT;
745
746 static struct option opts[] = {
747 { "key", OPTF_ARGREQ, 0, 'k' },
748 { "text", OPTF_ARGREQ, 0, 't' },
749 { "hex", OPTF_ARGREQ, 0, 'H' },
750 { 0, 0, 0, 0 }
751 };
752
753 addopts("k:t:H:n", opts);
754
755 r->ops->misc(r, RAND_NOISESRC, &noise_source);
756 r->ops->misc(r, RAND_SEED, 160);
757
758 for (;;) {
759 int o = opt();
760 if (o < 0)
761 break;
762 switch (o) {
763 case 'k':
764 DRESET(&d);
765 textkey(&d, optarg, rmd160_hmackeysz);
766 r->ops->misc(r, RAND_KEY, d.buf, d.len);
767 break;
768 case 't':
769 r->ops->misc(r, GRAND_SEEDBLOCK, optarg, strlen(optarg));
770 break;
771 case 'H':
772 DRESET(&d);
773 hexkey(&d, optarg, rmd160_hmackeysz);
774 r->ops->misc(r, GRAND_SEEDBLOCK, d.buf, d.len);
775 break;
776 }
777 }
778
779 dstr_destroy(&d);
780 return (r);
781 }
782
783 /* --- RC4 output --- */
784
785 static grand *gen_rc4(unsigned i)
786 {
787 grand *r;
788 dstr d = DSTR_INIT;
789
790 static struct option opts[] = {
791 { "key", OPTF_ARGREQ, 0, 'k' },
792 { "hex", OPTF_ARGREQ, 0, 'H' },
793 { 0, 0, 0, 0 }
794 };
795
796 addopts("k:H:", opts);
797
798 for (;;) {
799 int o = opt();
800 if (o < 0)
801 break;
802 switch (o) {
803 case 'k':
804 DRESET(&d);
805 textkey(&d, optarg, rc4_keysz);
806 break;
807 case 'H':
808 DRESET(&d);
809 hexkey(&d, optarg, rc4_keysz);
810 break;
811 default:
812 return (0);
813 }
814 }
815
816 if (!d.len)
817 randkey(&d, rc4_keysz);
818 r = rc4_rand(d.buf, d.len);
819 dstr_destroy(&d);
820 return (r);
821 }
822
823 /* --- SEAL output --- */
824
825 static grand *gen_seal(unsigned i)
826 {
827 grand *r;
828 dstr d = DSTR_INIT;
829 uint32 n = 0;
830
831 static struct option opts[] = {
832 { "key", OPTF_ARGREQ, 0, 'k' },
833 { "hex", OPTF_ARGREQ, 0, 'H' },
834 { "sequence", OPTF_ARGREQ, 0, 'n' },
835 { 0, 0, 0, 0 }
836 };
837
838 addopts("k:H:n:", opts);
839
840 for (;;) {
841 int o = opt();
842 if (o < 0)
843 break;
844 switch (o) {
845 case 'k':
846 DRESET(&d);
847 textkey(&d, optarg, seal_keysz);
848 break;
849 case 'H':
850 DRESET(&d);
851 hexkey(&d, optarg, seal_keysz);
852 break;
853 case 'n': {
854 char *p;
855 n = strtoul(optarg, &p, 0);
856 if (*p)
857 die(EXIT_FAILURE, "bad number `%s'", optarg);
858 } break;
859 default:
860 return (0);
861 }
862 }
863
864 if (!d.len)
865 randkey(&d, seal_keysz);
866 r = seal_rand(d.buf, d.len, n);
867 dstr_destroy(&d);
868 return (r);
869 }
870
871 /* --- Salsa20, XSalsa20, ChaCha, and XChaCha --- */
872
873 static grand *gen_salsae(unsigned i)
874 {
875 grand *r;
876 char *p;
877 dstr d = DSTR_INIT;
878 dstr n = DSTR_INIT;
879 kludge64 pos = { 0 };
880 octet posbuf[8];
881 mp *x;
882
883 static struct option opts[] = {
884 { "key", OPTF_ARGREQ, 0, 'k' },
885 { "hex", OPTF_ARGREQ, 0, 'H' },
886 { "nonce", OPTF_ARGREQ, 0, 'n' },
887 { "seek", OPTF_ARGREQ, 0, 's' },
888 { 0, 0, 0, 0 }
889 };
890
891 addopts("k:H:n:s:", opts);
892
893 for (;;) {
894 int o = opt();
895 if (o < 0)
896 break;
897 switch (o) {
898 case 'k':
899 DRESET(&d);
900 textkey(&d, optarg, salsa20_keysz);
901 break;
902 case 'H':
903 DRESET(&d);
904 hexkey(&d, optarg, salsa20_keysz);
905 break;
906 case 'n':
907 DRESET(&n);
908 unhex(optarg, &p, &n);
909 if (*p)
910 die(EXIT_FAILURE, "bad hex IV `%s'", optarg);
911 if (n.len != salsatab[i].noncesz) {
912 die(EXIT_FAILURE, "bad nonce length %lu (must be %lu)",
913 (unsigned long)n.len, (unsigned long)salsatab[i].noncesz);
914 }
915 break;
916 case 's':
917 x = mp_readstring(MP_NEW, optarg, &p, 0);
918 if (*p || MP_NEGP(x) || mp_bits(x) > 64)
919 die(EXIT_FAILURE, "bad position `%s'", optarg);
920 mp_storeb(x, posbuf, sizeof(posbuf));
921 mp_drop(x);
922 LOAD64_(pos, posbuf);
923 break;
924 default:
925 return (0);
926 }
927 }
928
929 if (!d.len)
930 randkey(&d, salsa20_keysz);
931 r = salsatab[i].gen(d.buf, d.len, n.len ? n.buf : 0);
932 r->ops->misc(r, SALSA20_SEEKU64, pos);
933
934 dstr_destroy(&d);
935 dstr_destroy(&n);
936
937 return (r);
938 }
939
940 /* --- Output feedback generators --- */
941
942 static grand *gen_ofb(unsigned i)
943 {
944 grand *r;
945 dstr d = DSTR_INIT;
946 dstr iv = DSTR_INIT;
947
948 static struct option opts[] = {
949 { "key", OPTF_ARGREQ, 0, 'k' },
950 { "hex", OPTF_ARGREQ, 0, 'H' },
951 { "iv", OPTF_ARGREQ, 0, 'i' },
952 { 0, 0, 0, 0 }
953 };
954
955 addopts("k:H:i:", opts);
956
957 for (;;) {
958 int o = opt();
959 if (o < 0)
960 break;
961 switch (o) {
962 case 'k':
963 DRESET(&d);
964 textkey(&d, optarg, ciphertab[i].keysz);
965 break;
966 case 'H':
967 DRESET(&d);
968 hexkey(&d, optarg, ciphertab[i].keysz);
969 break;
970 case 'i': {
971 char *p;
972 DRESET(&iv);
973 unhex(optarg, &p, &iv);
974 if (*p)
975 die(EXIT_FAILURE, "bad hex IV `%s'", optarg);
976 if (iv.len != ciphertab[i].blksz) {
977 die(EXIT_FAILURE, "bad IV length %lu (must be %lu)",
978 (unsigned long)iv.len, (unsigned long)ciphertab[i].blksz);
979 }
980 } break;
981 default:
982 return (0);
983 }
984 }
985
986 if (!d.len)
987 randkey(&d, ciphertab[i].keysz);
988 r = ciphertab[i].ofb(d.buf, d.len);
989 if (iv.len)
990 r->ops->misc(r, GRAND_SEEDBLOCK, iv.buf);
991
992 dstr_destroy(&d);
993 dstr_destroy(&iv);
994 return (r);
995 }
996
997 /* --- Counter generators --- */
998
999 static grand *gen_counter(unsigned i)
1000 {
1001 grand *r;
1002 dstr d = DSTR_INIT;
1003 dstr iv = DSTR_INIT;
1004
1005 static struct option opts[] = {
1006 { "key", OPTF_ARGREQ, 0, 'k' },
1007 { "hex", OPTF_ARGREQ, 0, 'H' },
1008 { "iv", OPTF_ARGREQ, 0, 'i' },
1009 { 0, 0, 0, 0 }
1010 };
1011
1012 addopts("k:H:i:", opts);
1013
1014 for (;;) {
1015 int o = opt();
1016 if (o < 0)
1017 break;
1018 switch (o) {
1019 case 'k':
1020 DRESET(&d);
1021 textkey(&d, optarg, ciphertab[i].keysz);
1022 break;
1023 case 'H':
1024 DRESET(&d);
1025 hexkey(&d, optarg, ciphertab[i].keysz);
1026 break;
1027 case 'i': {
1028 char *p;
1029 DRESET(&iv);
1030 unhex(optarg, &p, &iv);
1031 if (*p)
1032 die(EXIT_FAILURE, "bad hex IV `%s'", optarg);
1033 if (iv.len != ciphertab[i].blksz) {
1034 die(EXIT_FAILURE, "bad IV length %lu (must be %lu)",
1035 (unsigned long)iv.len, (unsigned long)ciphertab[i].blksz);
1036 }
1037 } break;
1038 default:
1039 return (0);
1040 }
1041 }
1042
1043 if (!d.len)
1044 randkey(&d, ciphertab[i].keysz);
1045 r = ciphertab[i].counter(d.buf, d.len);
1046 if (iv.len)
1047 r->ops->misc(r, GRAND_SEEDBLOCK, iv.buf);
1048
1049 dstr_destroy(&d);
1050 dstr_destroy(&iv);
1051 return (r);
1052 }
1053
1054 /* --- Mask generators --- */
1055
1056 static grand *gen_mgf(unsigned i)
1057 {
1058 grand *r;
1059 dstr d = DSTR_INIT;
1060 uint32 c = 0;
1061
1062 static struct option opts[] = {
1063 { "key", OPTF_ARGREQ, 0, 'k' },
1064 { "hex", OPTF_ARGREQ, 0, 'H' },
1065 { "index", OPTF_ARGREQ, 0, 'i' },
1066 { 0, 0, 0, 0 }
1067 };
1068
1069 addopts("k:H:i:", opts);
1070
1071 for (;;) {
1072 int o = opt();
1073 if (o < 0)
1074 break;
1075 switch (o) {
1076 case 'k':
1077 DRESET(&d);
1078 textkey(&d, optarg, hashtab[i].keysz);
1079 break;
1080 case 'H':
1081 DRESET(&d);
1082 hexkey(&d, optarg, hashtab[i].keysz);
1083 break;
1084 case 'i': {
1085 char *p;
1086 c = strtoul(optarg, &p, 0);
1087 if (*p)
1088 die(EXIT_FAILURE, "bad index `%s'", optarg);
1089 } break;
1090 default:
1091 return (0);
1092 }
1093 }
1094
1095 if (!d.len)
1096 randkey(&d, hashtab[i].keysz);
1097
1098 r = hashtab[i].mgf(d.buf, d.len);
1099 if (c)
1100 r->ops->misc(r, GRAND_SEEDUINT32, c);
1101
1102 dstr_destroy(&d);
1103 return (r);
1104 }
1105
1106 /* --- SHAKE generators --- */
1107
1108 static grand *gen_shake(unsigned i)
1109 {
1110 dstr d = DSTR_INIT;
1111 const char *func = 0, *perso = 0;
1112 grand *r;
1113
1114 static struct option opts[] = {
1115 { "function", OPTF_ARGREQ, 0, 'F' },
1116 { "personalization", OPTF_ARGREQ, 0, 'P' },
1117 { "key", OPTF_ARGREQ, 0, 'k' },
1118 { "hex", OPTF_ARGREQ, 0, 'H' },
1119 { 0, 0, 0, 0 }
1120 };
1121
1122 addopts("F:P:k:H:", opts);
1123
1124 for (;;) {
1125 int o = opt();
1126 if (o < 0)
1127 break;
1128 switch (o) {
1129 case 'F':
1130 func = optarg;
1131 break;
1132 case 'P':
1133 perso = optarg;
1134 break;
1135 case 'k':
1136 DRESET(&d);
1137 textkey(&d, optarg, shaketab[i].ksz);
1138 break;
1139 case 'H':
1140 DRESET(&d);
1141 hexkey(&d, optarg, shaketab[i].ksz);
1142 break;
1143 default:
1144 return (0);
1145 }
1146 }
1147
1148 if (!d.len) randkey(&d, shaketab[i].ksz);
1149 r = shaketab[i].shake(func, func ? strlen(func) : 0,
1150 perso, perso ? strlen(perso) : 0,
1151 d.buf, d.len);
1152 dstr_destroy(&d);
1153 return (r);
1154 }
1155
1156 /* --- KMAC generators --- */
1157
1158 static grand *gen_kmac(unsigned i)
1159 {
1160 dstr d = DSTR_INIT, m = DSTR_INIT;
1161 const char *perso = 0;
1162 char *q;
1163 grand *r;
1164
1165 static struct option opts[] = {
1166 { "personalization", OPTF_ARGREQ, 0, 'P' },
1167 { "key", OPTF_ARGREQ, 0, 'k' },
1168 { "hex", OPTF_ARGREQ, 0, 'H' },
1169 { "message", OPTF_ARGREQ, 0, 'M' },
1170 { "msghex", OPTF_ARGREQ, 0, 'N' },
1171 { 0, 0, 0, 0 }
1172 };
1173
1174 addopts("P:k:H:M:N:", opts);
1175
1176 for (;;) {
1177 int o = opt();
1178 if (o < 0)
1179 break;
1180 switch (o) {
1181 case 'P':
1182 perso = optarg;
1183 break;
1184 case 'k':
1185 DRESET(&d);
1186 textkey(&d, optarg, shaketab[i].ksz);
1187 break;
1188 case 'H':
1189 DRESET(&d);
1190 hexkey(&d, optarg, shaketab[i].ksz);
1191 break;
1192 case 'M':
1193 DRESET(&m);
1194 DPUTS(&d, optarg);
1195 break;
1196 case 'N':
1197 DRESET(&m);
1198 unhex(optarg, &q, &m);
1199 if (*q) die(EXIT_FAILURE, "bad hex");
1200 break;
1201 default:
1202 return (0);
1203 }
1204 }
1205
1206 if (!d.len) randkey(&d, shaketab[i].ksz);
1207 r = shaketab[i].kmac(perso, perso ? strlen(perso) : 0, d.buf, d.len);
1208 r->ops->misc(r, GRAND_SEEDBLOCK, (void *)m.buf, m.len);
1209 dstr_destroy(&d); dstr_destroy(&m);
1210 return (r);
1211 }
1212
1213 /* --- Fibonacci generator --- */
1214
1215 static grand *gen_fib(unsigned i)
1216 {
1217 grand *r;
1218 uint32 s = 0;
1219 char *p;
1220 unsigned set = 0;
1221
1222 static struct option opts[] = {
1223 { "seed", OPTF_ARGREQ, 0, 's' },
1224 { 0, 0, 0, 0 }
1225 };
1226
1227 addopts("s:", opts);
1228
1229 for (;;) {
1230 int o = opt();
1231 if (o < 0)
1232 break;
1233 switch (o) {
1234 case 's':
1235 s = strtoul(optarg, &p, 0);
1236 if (*p)
1237 die(EXIT_FAILURE, "bad integer `%s'", optarg);
1238 set = 1;
1239 break;
1240 default:
1241 return (0);
1242 }
1243 }
1244 r = fibrand_create(s);
1245 if (!set)
1246 r->ops->misc(r, GRAND_SEEDRAND, &rand_global);
1247 return (r);
1248 }
1249
1250 /* --- LC generator --- */
1251
1252 static grand *gen_lc(unsigned i)
1253 {
1254 uint32 s = 0;
1255 char *p;
1256 unsigned set = 0;
1257
1258 static struct option opts[] = {
1259 { "seed", OPTF_ARGREQ, 0, 's' },
1260 { 0, 0, 0, 0 }
1261 };
1262
1263 addopts("s:", opts);
1264
1265 for (;;) {
1266 int o = opt();
1267 if (o < 0)
1268 break;
1269 switch (o) {
1270 case 's':
1271 s = strtoul(optarg, &p, 0);
1272 if (*p)
1273 die(EXIT_FAILURE, "bad integer `%s'", optarg);
1274 set = 1;
1275 break;
1276 default:
1277 return (0);
1278 }
1279 }
1280 if (!set) {
1281 do
1282 s = rand_global.ops->range(&rand_global, LCRAND_P);
1283 while (s == LCRAND_FIXEDPT);
1284 }
1285 return (lcrand_create(s));
1286 }
1287
1288 /* --- Basic options parser -- can't generate output --- */
1289
1290 static grand *gen_opts(unsigned i)
1291 {
1292 while (opt() >= 0)
1293 ;
1294 return (0);
1295 }
1296
1297 /*----- Generators table --------------------------------------------------*/
1298
1299 gen generators[] = {
1300 { "fibonacci", gen_fib, 0,
1301 "[-s SEED]" },
1302 { "lc", gen_lc, 0,
1303 "[-s SEED]" },
1304 #define E(PRE, pre) \
1305 { #pre "-ofb", gen_ofb, CIPHER_##PRE, \
1306 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
1307 CIPHERS
1308 #undef E
1309 #define E(PRE, pre) \
1310 { #pre "-counter", gen_counter, CIPHER_##PRE, \
1311 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
1312 CIPHERS
1313 #undef E
1314 #define E(PRE, pre) \
1315 { #pre "-mgf", gen_mgf, HASH_##PRE, \
1316 "[-k KEY-PHRASE] [-H HEX-KEY] [-i INDEX]" },
1317 HASHES
1318 #undef E
1319 #define E(pre, r, x, BASE) \
1320 { x##BASE##_NAME(r), gen_salsae, pre##_##r##_INDEX, \
1321 "[-k KEY-PHRASE] [-H HEX-KEY] [-n NONCE]" },
1322 SALSAE
1323 #undef E
1324 #define E(sz) \
1325 { "shake" #sz, gen_shake, SHAKE##sz##_INDEX, \
1326 "[-k KEY-PHRASE] [-H HEX-KEY]" },
1327 SHAKES
1328 #undef E
1329 #define E(sz) \
1330 { "kmac" #sz, gen_kmac, SHAKE##sz##_INDEX, \
1331 "[-k KEY-PHRASE] [-H HEX-KEY] [-m MSG]" },
1332 SHAKES
1333 #undef E
1334 { "rc4", gen_rc4, 0,
1335 "[-k KEY-PHRASE] [-H HEX-KEY]" },
1336 { "seal", gen_seal, 0,
1337 "[-k KEY-PHRASE] [-H HEX-KEY] [-n SEQ]" },
1338 { "rand", gen_rand, 0,
1339 "[-n] [-k KEY-PHRASE] [-t TEXT-BLOCK] [-H HEX-BLOCK]" },
1340 { "bbs", gen_bbs, 0,
1341 "[-gS] [-s SEED] [-M MODULUS] [-b BITS] [-k KEYRING] [-i TAG] [-t TYPE]"
1342 },
1343 { 0, 0, 0, 0 },
1344 };
1345
1346 static gen optsg = { "options", gen_opts, 0,
1347 "This message shouldn't be printed." };
1348
1349 /*----- Random number generation ------------------------------------------*/
1350
1351 static int genfile(const void *buf, size_t sz, void *p)
1352 {
1353 FILE *fp = p;
1354 if (fwrite(buf, 1, sz, fp) != sz)
1355 die(EXIT_FAILURE, "error writing to file: %s", strerror(errno));
1356 return (0);
1357 }
1358
1359 static int genbuf(const void *buf, size_t sz, void *p)
1360 {
1361 octet **pp = p;
1362 memcpy(*pp, buf, sz);
1363 *pp += sz;
1364 return (0);
1365 }
1366
1367 typedef struct genmaurer_ctx {
1368 size_t n;
1369 maurer_ctx *m;
1370 } genmaurer_ctx;
1371
1372 static int genmaurer(const void *buf, size_t sz, void *p)
1373 {
1374 genmaurer_ctx *g = p;
1375 size_t i;
1376
1377 for (i = 0; i < g->n; i++)
1378 maurer_test(&g->m[i], buf, sz);
1379 return (0);
1380 }
1381
1382 static double doubletime(void)
1383 {
1384 #ifdef PORTABLE
1385 static time_t start = (time_t)-1;
1386 time_t now = time(0);
1387
1388 if (start == (time_t)-1) start = now;
1389 return difftime(now, start);
1390 #else
1391 struct timeval tv;
1392
1393 gettimeofday(&tv, 0);
1394 return (tv.tv_sec + tv.tv_usec/1000000.0);
1395 #endif
1396 }
1397
1398 static int generate(grand *r, mp *outsz,
1399 int (*func)(const void *buf, size_t sz, void *p),
1400 void *p)
1401 {
1402 static char kmg[] = { ' ', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 0 };
1403
1404 unsigned percent = 0;
1405 mp *kb = MP_ZERO, *t = MP_NEW;
1406 dstr d = DSTR_INIT;
1407 double now, last;
1408 static char baton[] = "-\\|/";
1409 char *bp;
1410 int rc;
1411 clock_t clk = 0;
1412
1413 /* --- Spit out random data --- */
1414
1415 last = doubletime();
1416 bp = baton;
1417 if (flags & f_progress) {
1418 char *errbuf = xmalloc(BUFSIZ);
1419 setvbuf(stderr, errbuf, _IOLBF, BUFSIZ);
1420 if (outsz)
1421 fprintf(stderr, "[%*s] 0%% 0\r[/\b", 50, "");
1422 else
1423 fputs("[ ] 0\r[/\b", stderr);
1424 fflush(stderr);
1425 }
1426
1427 #ifdef SIGPIPE
1428 signal(SIGPIPE, SIG_IGN);
1429 #endif
1430
1431 while (!outsz || MP_CMP(kb, <, outsz)) {
1432 octet buf[BUFSIZ];
1433 size_t sz = sizeof(buf), left;
1434 clock_t c_start, c_stop;
1435
1436 /* --- Emit a bufferful (or less) of data --- */
1437
1438 if (outsz) {
1439 t = mp_sub(t, outsz, kb);
1440 assert(!MP_NEGP(t));
1441 if (MP_CMP(t, <=, MP_SIZET_MAX)) {
1442 left = mp_tosizet(t);
1443 if (sz > left) sz = left;
1444 }
1445 }
1446 c_start = clock();
1447 r->ops->fill(r, buf, sz);
1448 c_stop = clock();
1449 clk += c_stop - c_start;
1450 if (func && (rc = func(buf, sz, p)) != 0)
1451 return (rc);
1452 t = mp_fromsizet(t, sz);
1453 kb = mp_add(kb, kb, t);
1454
1455 /* --- Update the display --- */
1456
1457 if (flags & f_progress) {
1458 unsigned up = 0;
1459
1460 now = doubletime();
1461
1462 if (percent > 100)
1463 up = 1;
1464
1465 if (!outsz) {
1466 if (now - last > 0.1) {
1467 up = 1;
1468 }
1469 if (up)
1470 fputs(" ] ", stderr);
1471 } else {
1472 unsigned pc;
1473 t = mp_fromulong(t, 100);
1474 t = mp_mul(t, t, kb);
1475 mp_div(&t, 0, t, outsz);
1476 assert(!MP_NEGP(t) && MP_CMP(t, <, MP_UINT_MAX));
1477 pc = mp_touint(t);
1478 if (pc > percent || percent > 100 || now - last > 0.1) {
1479 if (percent > 100)
1480 percent = 0;
1481 percent &= ~1;
1482 for (; percent < (pc & ~1); percent += 2)
1483 putc('.', stderr);
1484 percent = pc;
1485 for (; pc < 100; pc += 2)
1486 putc(' ', stderr);
1487 fprintf(stderr, "] %3i%% ", percent);
1488 up = 1;
1489 }
1490 }
1491
1492 if (up) {
1493 char *kk = kmg;
1494 t = mp_add(t, kb, MP_ZERO);
1495 while (mp_bits(t) >= 14) {
1496 t = mp_lsr(t, t, 10);
1497 kk++;
1498 }
1499 DRESET(&d);
1500 mp_writedstr(t, &d, 10);
1501 fprintf(stderr, "%4s%c\r[", d.buf, *kk);
1502 if (outsz) {
1503 unsigned pc;
1504 for (pc = 0; pc < (percent & ~1); pc += 2)
1505 putc('.', stderr);
1506 }
1507 last = now;
1508 }
1509
1510 if (percent > 100)
1511 percent = 0;
1512
1513 if (percent < 100 && up) {
1514 putc(*bp++, stderr);
1515 putc('\b', stderr);
1516 if (!*bp)
1517 bp = baton;
1518 }
1519 fflush(stderr);
1520 }
1521 }
1522
1523 if (flags & f_progress)
1524 fputc('\n', stderr);
1525 if (flags & f_timer) {
1526 DRESET(&d);
1527 dstr_puts(&d, "generated ");
1528 mp_writedstr(kb, &d, 10);
1529 dstr_puts(&d, " bytes ");
1530 if (!clk)
1531 dstr_puts(&d, "too quickly to measure\n");
1532 else {
1533 char *kk;
1534 double out;
1535 double sec = (double)clk/CLOCKS_PER_SEC;
1536 unsigned long sh;
1537 double bps;
1538
1539 MP_SHRINK(kb);
1540 switch (MP_LEN(kb)) {
1541 case 0: out = 0; break;
1542 case 1: out = kb->v[0]; break;
1543 default:
1544 sh = mp_bits(kb) - MPW_BITS;
1545 t = mp_lsr(t, kb, sh);
1546 out = ldexp(t->v[0], sh);
1547 break;
1548 }
1549 bps = (8*out)/sec;
1550 for (kk = kmg; bps > 1024 && kk[1]; kk++, bps /= 1024)
1551 ;
1552 dstr_putf(&d, "in %g secs (%g %cb/s)\n", sec, bps, *kk);
1553 fwrite(d.buf, 1, d.len, stderr);
1554 }
1555 }
1556
1557 mp_drop(t);
1558 DDESTROY(&d);
1559 return (0);
1560 }
1561
1562 /*----- Main code ---------------------------------------------------------*/
1563
1564 int main(int ac, char *av[])
1565 {
1566 gen *g = &optsg;
1567 grand *r;
1568
1569 /* --- Initialize mLib --- */
1570
1571 ego(av[0]);
1572 sub_init();
1573
1574 /* --- Set up the main Catacomb generator --- */
1575
1576 rand_noisesrc(RAND_GLOBAL, &noise_source);
1577 rand_seed(RAND_GLOBAL, 160);
1578
1579 /* --- Initialize the options table --- */
1580
1581 addopts(sopts, opts);
1582 argc = ac;
1583 argv = av;
1584 outfp = stdout;
1585
1586 /* --- Read the generator out of the first argument --- */
1587
1588 if (argc > 1 && *argv[1] != '-') {
1589 const char *arg = av[1];
1590 size_t sz = strlen(arg);
1591 gen *gg;
1592
1593 g = 0;
1594 for (gg = generators; gg->name; gg++) {
1595 if (STRNCMP(arg, ==, gg->name, sz)) {
1596 if (gg->name[sz] == 0) {
1597 g = gg;
1598 break;
1599 } else if (g)
1600 die(EXIT_FAILURE, "ambiguous generator name `%s'", arg);
1601 else
1602 g = gg;
1603 }
1604 }
1605 if (!g)
1606 die(EXIT_FAILURE, "unknown generator name `%s'", arg);
1607 argc--;
1608 argv++;
1609 }
1610
1611 /* --- Get a generic random number generator --- */
1612
1613 r = g->seed(g->i);
1614 if (!r || optind != ac - 1) {
1615 usage(stderr);
1616 exit(EXIT_FAILURE);
1617 }
1618
1619 /* --- Do the FIPS test --- */
1620
1621 if (flags & f_fips) {
1622 octet buf[FIPSTEST_BUFSZ];
1623 unsigned rc;
1624 mp *t;
1625 octet *p = buf;
1626
1627 t = mp_fromsizet(MP_NEW, sizeof(buf));
1628 generate(r, t, genbuf, &p);
1629 mp_drop(t);
1630 rc = fipstest(buf);
1631 if (rc & FIPSTEST_MONOBIT)
1632 moan("failed monobit test");
1633 if (rc & FIPSTEST_POKER)
1634 moan("failed poker test");
1635 if (rc & FIPSTEST_RUNS)
1636 moan("failed runs test");
1637 if (rc & FIPSTEST_LONGRUNS)
1638 moan("failed long runs test");
1639 if (!rc && (flags & f_progress))
1640 fputs("test passed\n", stderr);
1641 return (rc ? EXIT_FAILURE : 0);
1642 }
1643
1644 /* --- Do Maurer's test --- */
1645
1646 if (flags & f_maurer) {
1647 size_t bufsz;
1648 unsigned i;
1649 unsigned rc = 0;
1650 mp *t;
1651 genmaurer_ctx g;
1652
1653 static struct { double x; const char *sig; } sigtab[] = {
1654 { 3.2905, "1e-3" },
1655 { 3.0902, "2e-3" },
1656 { 2.8070, "5e-3" },
1657 { 2.5758, "1e-2" },
1658 { 0 , 0 }
1659 };
1660
1661 g.n = maurer_hi - maurer_lo + 1;
1662 g.m = xmalloc(g.n * sizeof(maurer_ctx));
1663 for (i = 0; i < g.n; i++)
1664 maurer_init(&g.m[i], i + maurer_lo);
1665 bufsz = (100 * maurer_hi) << maurer_hi;
1666
1667 t = mp_fromsizet(MP_NEW, bufsz);
1668 generate(r, t, genmaurer, &g);
1669 mp_drop(t);
1670
1671 for (i = maurer_lo; i <= maurer_hi; i++) {
1672 double z = maurer_done(&g.m[i - maurer_lo]);
1673 double zz = fabs(z);
1674 unsigned j;
1675
1676 for (j = 0; sigtab[j].sig; j++) {
1677 if (zz > sigtab[j].x) {
1678 rc = EXIT_FAILURE;
1679 moan("failed, bits = %u, sig = %s, Z_u = %g",
1680 i, sigtab[j].sig, z);
1681 break;
1682 }
1683 }
1684 if (flags & f_progress)
1685 fprintf(stderr, "bits = %u, Z_u = %g\n", i, z);
1686 }
1687
1688 xfree(g.m);
1689 return (rc);
1690 }
1691
1692 /* --- Discard --- */
1693
1694 if (flags & f_discard) {
1695 generate(r, outsz, 0, 0);
1696 return (0);
1697 }
1698
1699 /* --- Write to a file --- */
1700
1701 #ifndef PORTABLE
1702 if (!(flags & f_file) && isatty(STDOUT_FILENO))
1703 die(EXIT_FAILURE, "writing output to a terminal is a bad idea");
1704 #endif
1705
1706 generate(r, outsz, genfile, outfp);
1707
1708 /* --- Done --- */
1709
1710 r->ops->destroy(r);
1711 return (0);
1712 }
1713
1714 /*----- That's all, folks -------------------------------------------------*/