3 * Spit out random numbers
5 * (c) 1999 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of Catacomb.
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.
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.
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,
28 /*----- Header files ------------------------------------------------------*/
45 #include <mLib/darray.h>
46 #include <mLib/dstr.h>
47 #include <mLib/mdwopt.h>
48 #include <mLib/quis.h>
49 #include <mLib/report.h>
73 #include "skipjack-ofb.h"
76 #include "blowfish-ofb.h"
77 #include "twofish-ofb.h"
79 #include "cast128-ofb.h"
80 #include "cast256-ofb.h"
81 #include "noekeon-ofb.h"
82 #include "rijndael-ofb.h"
83 #include "rijndael192-ofb.h"
84 #include "rijndael256-ofb.h"
85 #include "safer-ofb.h"
86 #include "safersk-ofb.h"
87 #include "square-ofb.h"
88 #include "serpent-ofb.h"
90 #include "des-counter.h"
91 #include "des3-counter.h"
92 #include "rc2-counter.h"
93 #include "rc5-counter.h"
94 #include "mars-counter.h"
95 #include "skipjack-counter.h"
96 #include "tea-counter.h"
97 #include "xtea-counter.h"
98 #include "blowfish-counter.h"
99 #include "twofish-counter.h"
100 #include "idea-counter.h"
101 #include "cast128-counter.h"
102 #include "cast256-counter.h"
103 #include "noekeon-counter.h"
104 #include "rijndael-counter.h"
105 #include "rijndael192-counter.h"
106 #include "rijndael256-counter.h"
107 #include "safer-counter.h"
108 #include "safersk-counter.h"
109 #include "square-counter.h"
110 #include "serpent-counter.h"
116 #include "tiger-mgf.h"
117 #include "rmd128-mgf.h"
118 #include "rmd160-mgf.h"
119 #include "rmd256-mgf.h"
120 #include "rmd320-mgf.h"
124 /*----- Data structures ---------------------------------------------------*/
128 grand *(*seed)(unsigned /*i*/);
133 extern gen generators[];
141 E(SKIPJACK, skipjack) \
144 E(BLOWFISH, blowfish) \
145 E(TWOFISH, twofish) \
147 E(CAST128, cast128) \
148 E(CAST256, cast256) \
151 E(SAFERSK, safersk) \
152 E(NOEKEON, noekeon) \
153 E(RIJNDAEL, rijndael) \
154 E(RIJNDAEL192, rijndael192) \
155 E(RIJNDAEL256, rijndael256) \
169 #define E(PRE, pre) CIPHER_##PRE,
170 enum { CIPHERS CIPHER__bogus };
173 #define E(PRE, pre) HASH_##PRE,
174 enum { HASHES HASH__bogus };
177 static const struct {
180 grand *(*ofb)(const void */*k*/, size_t /*sz*/);
181 grand *(*counter)(const void */*k*/, size_t /*sz*/);
183 #define E(PRE, pre) \
184 { pre##_keysz, PRE##_BLKSZ, pre##_ofbrand, pre##_counterrand },
189 static const struct {
192 grand *(*mgf)(const void */*k*/, size_t /*sz*/);
194 #define E(PRE, pre) \
195 { &pre, pre##_mgfkeysz, pre##_mgfrand },
200 /*----- Miscellaneous static data -----------------------------------------*/
203 static size_t outsz = 0;
204 static unsigned maurer_lo = 5, maurer_hi = 8;
209 static unsigned flags = 0;
211 #define f_progress 1u
216 #define f_discard 32u
218 /*----- Help options ------------------------------------------------------*/
220 static void usage(FILE *fp)
222 pquis(fp, "Usage: $ generator [options]\n");
225 static void version(FILE *fp)
227 pquis(fp, "$, Catacomb version " VERSION "\n");
230 static void help(FILE *fp)
236 Emits a stream of random bytes suitable for, well, all sorts of things.\n\
237 The primary objective is to be able to generate streams of input for\n\
238 statistical tests, such as Diehard.\n\
240 Options are specific to the particular generator, although there's a\n\
243 -h, --help Display this help message.\n\
244 -v, --version Display the program's version number.\n\
245 -u, --usage Display a useless usage message.\n\
247 -l, --list Show a list of the supported generators, with\n\
249 -f, --fipstest Run the FIPS 140-1 randomness test.\n\
250 -m, --maurer[=LO-HI] Run Maurer's universal statistical test.\n\
251 -o, --output FILE Write output to FILE, not stdout.\n\
252 -z, --size SIZE Emit SIZE bytes, not an unlimited number.\n\
253 -p, --progress Show a little progress meter (on stderr).\n\
254 -T, --timer Keep track of the CPU time used by the generator.\n\
255 -d, --discard Discard the generated output.\n\
257 (A SIZE may be followed by `g' for gigabytes, `m' for megabytes, or\n\
258 `k' for kilobytes. If unqualified, an amount in bytes is assumed.)\n\
262 /*----- Main options parser -----------------------------------------------*/
264 static struct option opts[] = {
266 /* --- Standard GNU help options --- */
268 { "help", 0, 0, 'h' },
269 { "version", 0, 0, 'v' },
270 { "usage", 0, 0, 'u' },
272 /* --- Other useful things --- */
274 { "list", 0, 0, 'l' },
275 { "fipstest", 0, 0, 'f' },
276 { "maurer", OPTF_ARGOPT, 0, 'm' },
277 { "output", OPTF_ARGREQ, 0, 'o' },
278 { "size", OPTF_ARGREQ, 0, 'z' },
279 { "progress", 0, 0, 'p' },
280 { "timer", 0, 0, 'T' },
281 { "discard", 0, 0, 'd' },
283 /* --- End of main table --- */
288 static const char *sopts = "hvu lfm::o:z:pTd";
291 DA_DECL(option_v, struct option);
295 static option_v optv = DA_INIT;
296 static dstr optd = DSTR_INIT;
298 /* --- @addopts@ --- *
300 * Arguments: @const char *s@ = pointer to short options
301 * @struct option *l@ = pointer to long options
305 * Use: Adds a collection of options to the table.
308 static void addopts(const char *s, struct option *l)
314 DA_PUSH(&optv, *l++);
322 * Returns: Next option from argument array.
324 * Use: Fetches options, handling the standard ones.
330 int i = mdwopt(argc, argv, optd.buf, DA(&optv), 0, 0, 0);
343 puts("Generators supported:");
344 for (g = generators; g->name; g++)
345 printf(" %s %s\n", g->name, g->help);
355 unsigned long lo, hi;
356 lo = strtoul(optarg, &p, 0);
357 if (*p == '-' || *p == ',')
358 hi = strtoul(p + 1, &p, 0);
361 if (*p != 0 || hi < lo || lo == 0)
362 die(EXIT_FAILURE, "bad bit range `%s'", optarg);
369 die(EXIT_FAILURE, "already set an output file");
370 if (strcmp(optarg, "-") == 0)
373 outfp = fopen(optarg, "w");
375 die(EXIT_FAILURE, "couldn't open output file `%s': %s",
376 optarg, strerror(errno));
383 outsz = strtoul(optarg, &p, 0);
385 die(EXIT_FAILURE, "bad number `%s'", optarg);
387 case 'G': case 'g': outsz *= 1024;
388 case 'M': case 'm': outsz *= 1024;
389 case 'K': case 'k': outsz *= 1024;
393 die(EXIT_FAILURE, "bad suffix `%s'", p);
397 die(EXIT_FAILURE, "bad suffix `%s'", p);
414 /*----- Manglers for seed strings -----------------------------------------*/
418 * Arguments: @const char *p@ = pointer to input string
419 * @char **end@ = where the end goes
420 * @dstr *d@ = output buffer
424 * Use: Transforms a hex string into a chunk of binary data.
427 static void unhex(const char *p, char **end, dstr *d)
429 while (p[0] && p[1]) {
430 int x = p[0], y = p[1];
431 if ('0' <= x && x <= '9') x -= '0';
432 else if ('A' <= x && x <= 'F') x -= 'A' - 10;
433 else if ('a' <= x && x <= 'f') x -= 'a' - 10;
435 if ('0' <= y && y <= '9') y -= '0';
436 else if ('A' <= y && y <= 'F') y -= 'A' - 10;
437 else if ('a' <= y && y <= 'f') y -= 'a' - 10;
439 DPUTC(d, (x << 4) + y);
445 /* --- Generate a key --- */
447 static void textkey(dstr *d, const char *p, const octet *ksz)
449 size_t sz = strlen(p);
452 die(EXIT_FAILURE, "zero-length key string");
453 if (keysz(sz, ksz) != sz)
457 rmd160_mgfinit(&g, p, sz);
460 rmd160_mgfencrypt(&g, 0, d->buf, sz);
463 assert(((void)"I can't seem to choose a good key size",
464 keysz(d->len, ksz) == d->len));
467 static void hexkey(dstr *d, const char *p, const octet *ksz)
470 unhex(optarg, &q, d);
472 die(EXIT_FAILURE, "bad hex key `%s'", p);
473 if (keysz(d->len, ksz) != d->len)
474 die(EXIT_FAILURE, "bad key length");
477 static void randkey(dstr *d, const octet *ksz)
479 size_t sz = keysz(0, ksz);
481 rand_get(RAND_GLOBAL, d->buf, sz);
485 /*----- Generators --------------------------------------------------------*/
487 /* --- Blum-Blum-Shub strong generator --- */
489 static grand *gen_bbs(unsigned i)
491 /* --- Default modulus --- *
493 * The factors of this number are
495 * @p = 1229936431484295969649886203367009966370895964206162032259292413@
496 * @7754313537966036459299022912838407755462506416274551744201653277@
497 * @313130311731673973886822067@
499 * @q = 9798171783943489959487301695884963889684294764514008432498259742@
500 * @5374320073594018817245784145742769603334292182227671519041431067@
501 * @61344781426317516045890159@
503 * Both %$p$% and %$q$% are prime; %$(p - 1)/2$% and %$(q - 1)/2$% have no
504 * common factors. They were found using this program, with random
507 * I hope that, by publishing these factors, I'll dissuade people from
508 * actually using this modulus in an attempt to attain real security. The
509 * program is quite quick at finding Blum numbers, so there's no excuse for
510 * not generating your own.
514 "12051128439013574251357214209433471144307319411973256935382082"
515 "84356405274180923922403660880355098909699130818163691602989614"
516 "90135716255689660470370755013177656905237112577648090277537209"
517 "93607817155427455344810369808478266925293635284364998010510985"
518 "0503830397166360721262431179505917248447259735253684659338653";
520 /* --- Other things --- */
524 unsigned bits = 1024;
527 const char *kfile = 0, *id = 0, *ktype = 0;
529 /* --- Parse options --- */
531 static struct option opts[] = {
532 { "modulus", OPTF_ARGREQ, 0, 'M' },
533 { "generate", 0, 0, 'g' },
534 { "seed", OPTF_ARGREQ, 0, 's' },
535 { "bits", OPTF_ARGREQ, 0, 'b' },
536 { "show", 0, 0, 'S' },
537 { "keyring", OPTF_ARGREQ, 0, 'k' },
538 { "id", OPTF_ARGREQ, 0, 'i' },
539 { "type", OPTF_ARGREQ, 0, 't' },
543 addopts("M:gs:b:Sk:i:t:", opts);
560 bits = strtoul(optarg, 0, 0);
562 die(EXIT_FAILURE, "bad number of bits `%s'", optarg);
584 /* --- Generate a modulus if one is requested --- */
588 m = mp_readstring(MP_NEW, mt, &p, 0);
589 if (!m || *p || (m->v[0] & 3) != 1)
590 die(EXIT_FAILURE, "bad modulus `%s'", mt);
591 /* Unfortunately I don't know how to test for a Blum integer */
592 } else if (kfile || id || ktype) {
597 /* --- Open the key file --- */
601 if (key_open(&kf, kfile, KOPEN_READ, key_moan, 0)) {
602 die(EXIT_FAILURE, "error opening key file `%s': %s",
603 kfile, strerror(errno));
606 /* --- Find the key --- */
609 if ((kk = key_bytag(&kf, id)) == 0)
610 die(EXIT_FAILURE, "key `%s' not found", id);
614 if ((kk = key_bytype(&kf, ktype)) == 0)
615 die(EXIT_FAILURE, "no suitable key with type `%s' found", ktype);
618 /* --- Read the key data --- */
620 if ((kk->k->e & KF_ENCMASK) != KENC_STRUCT)
621 die(EXIT_FAILURE, "key is not structured");
622 if ((kd = key_structfind(kk->k, "n")) == 0)
623 die(EXIT_FAILURE, "key has no subkey `n'");
624 if ((kd->e & KF_ENCMASK) != KENC_MP)
625 die(EXIT_FAILURE, "incompatible subkey encoding");
626 m = MP_COPY(kd->u.m);
631 if (bbs_gen(&bp, bits, &rand_global, 0,
632 (flags & f_progress) ? pgen_ev : 0, 0))
633 die(EXIT_FAILURE, "modulus generation failed");
637 fputs("p = ", stderr);
638 mp_writefile(bp.p, stderr, 10);
639 fputs("\nq = ", stderr);
640 mp_writefile(bp.q, stderr, 10);
641 fputs("\nn = ", stderr);
642 mp_writefile(bp.n, stderr, 10);
650 /* --- Set up a seed --- */
653 x = mprand(MP_NEW, mp_bits(m) - 1, &rand_global, 1);
656 x = mp_readstring(MP_NEW, xt, &p, 0);
658 die(EXIT_FAILURE, "bad modulus `%s'", xt);
670 /* --- Catacomb's random number generator --- */
672 static grand *gen_rand(unsigned i)
674 grand *r = rand_create();
677 static struct option opts[] = {
678 { "key", OPTF_ARGREQ, 0, 'k' },
679 { "text", OPTF_ARGREQ, 0, 't' },
680 { "hex", OPTF_ARGREQ, 0, 'H' },
684 addopts("k:t:H:n", opts);
686 r->ops->misc(r, RAND_NOISESRC, &noise_source);
687 r->ops->misc(r, RAND_SEED, 160);
696 textkey(&d, optarg, rmd160_hmackeysz);
697 r->ops->misc(r, RAND_KEY, d.buf, d.len);
700 r->ops->misc(r, GRAND_SEEDBLOCK, optarg, strlen(optarg));
704 hexkey(&d, optarg, rmd160_hmackeysz);
705 r->ops->misc(r, GRAND_SEEDBLOCK, d.buf, d.len);
714 /* --- RC4 output --- */
716 static grand *gen_rc4(unsigned i)
721 static struct option opts[] = {
722 { "key", OPTF_ARGREQ, 0, 'k' },
723 { "hex", OPTF_ARGREQ, 0, 'H' },
727 addopts("k:H:", opts);
736 textkey(&d, optarg, rc4_keysz);
740 hexkey(&d, optarg, rc4_keysz);
748 randkey(&d, rc4_keysz);
749 r = rc4_rand(d.buf, d.len);
754 /* --- SEAL output --- */
756 static grand *gen_seal(unsigned i)
762 static struct option opts[] = {
763 { "key", OPTF_ARGREQ, 0, 'k' },
764 { "hex", OPTF_ARGREQ, 0, 'H' },
765 { "sequence", OPTF_ARGREQ, 0, 'n' },
769 addopts("k:H:n:", opts);
778 textkey(&d, optarg, seal_keysz);
782 hexkey(&d, optarg, seal_keysz);
786 n = strtoul(optarg, &p, 0);
788 die(EXIT_FAILURE, "bad number `%s'", optarg);
796 randkey(&d, seal_keysz);
797 r = seal_rand(d.buf, d.len, n);
802 /* --- Output feedback generators --- */
804 static grand *gen_ofb(unsigned i)
810 static struct option opts[] = {
811 { "key", OPTF_ARGREQ, 0, 'k' },
812 { "hex", OPTF_ARGREQ, 0, 'H' },
813 { "iv", OPTF_ARGREQ, 0, 'i' },
817 addopts("k:H:i:", opts);
826 textkey(&d, optarg, ciphertab[i].keysz);
830 hexkey(&d, optarg, ciphertab[i].keysz);
835 unhex(optarg, &p, &iv);
837 die(EXIT_FAILURE, "bad hex IV `%s'", optarg);
838 if (iv.len != ciphertab[i].blksz) {
839 die(EXIT_FAILURE, "bad IV length %lu (must be %lu)",
840 (unsigned long)iv.len, (unsigned long)ciphertab[i].blksz);
849 randkey(&d, ciphertab[i].keysz);
850 r = ciphertab[i].ofb(d.buf, d.len);
852 r->ops->misc(r, GRAND_SEEDBLOCK, iv.buf);
859 /* --- Counter generators --- */
861 static grand *gen_counter(unsigned i)
867 static struct option opts[] = {
868 { "key", OPTF_ARGREQ, 0, 'k' },
869 { "hex", OPTF_ARGREQ, 0, 'H' },
870 { "iv", OPTF_ARGREQ, 0, 'i' },
874 addopts("k:H:i:", opts);
883 textkey(&d, optarg, ciphertab[i].keysz);
887 hexkey(&d, optarg, ciphertab[i].keysz);
892 unhex(optarg, &p, &iv);
894 die(EXIT_FAILURE, "bad hex IV `%s'", optarg);
895 if (iv.len != ciphertab[i].blksz) {
896 die(EXIT_FAILURE, "bad IV length %lu (must be %lu)",
897 (unsigned long)iv.len, (unsigned long)ciphertab[i].blksz);
906 randkey(&d, ciphertab[i].keysz);
907 r = ciphertab[i].counter(d.buf, d.len);
909 r->ops->misc(r, GRAND_SEEDBLOCK, iv.buf);
916 /* --- Mask generators --- */
918 static grand *gen_mgf(unsigned i)
924 static struct option opts[] = {
925 { "key", OPTF_ARGREQ, 0, 'k' },
926 { "hex", OPTF_ARGREQ, 0, 'H' },
927 { "index", OPTF_ARGREQ, 0, 'i' },
931 addopts("k:H:i:", opts);
940 textkey(&d, optarg, hashtab[i].keysz);
944 hexkey(&d, optarg, hashtab[i].keysz);
948 c = strtoul(optarg, &p, 0);
950 die(EXIT_FAILURE, "bad index `%s'", optarg);
958 randkey(&d, hashtab[i].keysz);
960 r = hashtab[i].mgf(d.buf, d.len);
962 r->ops->misc(r, GRAND_SEEDUINT32, c);
968 /* --- Fibonacci generator --- */
970 static grand *gen_fib(unsigned i)
977 static struct option opts[] = {
978 { "seed", OPTF_ARGREQ, 0, 's' },
990 s = strtoul(optarg, &p, 0);
992 die(EXIT_FAILURE, "bad integer `%s'", optarg);
999 r = fibrand_create(s);
1001 r->ops->misc(r, GRAND_SEEDRAND, &rand_global);
1005 /* --- LC generator --- */
1007 static grand *gen_lc(unsigned i)
1013 static struct option opts[] = {
1014 { "seed", OPTF_ARGREQ, 0, 's' },
1018 addopts("s:", opts);
1026 s = strtoul(optarg, &p, 0);
1028 die(EXIT_FAILURE, "bad integer `%s'", optarg);
1037 s = rand_global.ops->range(&rand_global, LCRAND_P);
1038 while (s == LCRAND_FIXEDPT);
1040 return (lcrand_create(s));
1043 /* --- Basic options parser -- can't generate output --- */
1045 static grand *gen_opts(unsigned i)
1052 /*----- Generators table --------------------------------------------------*/
1054 gen generators[] = {
1055 { "fibonacci", gen_fib, 0,
1059 #define E(PRE, pre) \
1060 { #pre "-ofb", gen_ofb, CIPHER_##PRE, \
1061 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
1064 #define E(PRE, pre) \
1065 { #pre "-counter", gen_counter, CIPHER_##PRE, \
1066 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
1069 #define E(PRE, pre) \
1070 { #pre "-mgf", gen_mgf, HASH_##PRE, \
1071 "[-k KEY-PHRASE] [-H HEX-KEY] [-i INDEX]" },
1074 { "rc4", gen_rc4, 0,
1075 "[-k KEY-PHRASE] [-H HEX-KEY]" },
1076 { "seal", gen_seal, 0,
1077 "[-k KEY-PHRASE] [-H HEX-KEY] [-n SEQ]" },
1078 { "rand", gen_rand, 0,
1079 "[-n] [-k KEY-PHRASE] [-t TEXT-BLOCK] [-H HEX-BLOCK]" },
1080 { "bbs", gen_bbs, 0,
1081 "[-gS] [-s SEED] [-M MODULUS] [-b BITS] [-k KEYRING] [-i TAG] [-t TYPE]"
1086 static gen optsg = { "options", gen_opts, 0,
1087 "This message shouldn't be printed." };
1089 /*----- Random number generation ------------------------------------------*/
1091 static int genfile(const void *buf, size_t sz, void *p)
1094 if (fwrite(buf, 1, sz, fp) != sz)
1095 die(EXIT_FAILURE, "error writing to file: %s", strerror(errno));
1099 static int genbuf(const void *buf, size_t sz, void *p)
1102 memcpy(*pp, buf, sz);
1107 typedef struct genmaurer_ctx {
1112 static int genmaurer(const void *buf, size_t sz, void *p)
1114 genmaurer_ctx *g = p;
1117 for (i = 0; i < g->n; i++)
1118 maurer_test(&g->m[i], buf, sz);
1122 static int generate(grand *r, size_t outsz,
1123 int (*func)(const void *buf, size_t sz, void *p),
1126 static char kmg[] = { ' ', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 0 };
1128 unsigned percent = 0;
1131 static char baton[] = "-\\|/";
1136 /* --- Spit out random data --- */
1140 if (flags & f_progress) {
1141 char *errbuf = xmalloc(BUFSIZ);
1142 setvbuf(stderr, errbuf, _IOLBF, BUFSIZ);
1144 fprintf(stderr, "[%*s] 0%% 0\r[/\b", 50, "");
1146 fputs("[ ] 0\r[/\b", stderr);
1151 signal(SIGPIPE, SIG_IGN);
1156 size_t sz = sizeof(buf);
1157 clock_t c_start, c_stop;
1159 /* --- Emit a bufferful (or less) of data --- */
1162 if (sz > outsz - kb)
1166 r->ops->fill(r, buf, sz);
1168 clk += c_stop - c_start;
1169 if (func && (rc = func(buf, sz, p)) != 0)
1173 /* --- Update the display --- */
1175 if (flags & f_progress) {
1183 if (difftime(t, last) > 1.0) {
1187 fputs(" ] ", stderr);
1189 unsigned pc = kb * 100.0 / outsz;
1190 if (pc > percent || percent > 100 || difftime(t, last) > 1.0) {
1194 for (; percent < (pc & ~1); percent += 2)
1197 for (; pc < 100; pc += 2)
1199 fprintf(stderr, "] %3i%% ", percent);
1207 while (q > 8192 && kk[1]) {
1211 fprintf(stderr, "%4i%c\r[", (int)q, *kk);
1214 for (pc = 0; pc < (percent & ~1); pc += 2)
1223 if (percent < 100) {
1224 putc(*bp++, stderr);
1232 /* --- Terminate the loop --- */
1234 } while (!outsz || kb < outsz);
1236 if (flags & f_progress)
1237 fputc('\n', stderr);
1238 if (flags & f_timer) {
1239 fprintf(stderr, "generated %lu bytes ", (unsigned long)outsz);
1241 fputs("too quickly to measure\n", stderr);
1244 double sec = (double)clk/CLOCKS_PER_SEC;
1245 double bps = (outsz << 3)/sec;
1246 for (kk = kmg; bps > 1024 && kk[1]; kk++, bps /= 1024)
1248 fprintf(stderr, "in %g secs (%g %cb/s)\n", sec, bps, *kk);
1254 /*----- Main code ---------------------------------------------------------*/
1256 int main(int ac, char *av[])
1261 /* --- Initialize mLib --- */
1266 /* --- Set up the main Catacomb generator --- */
1268 rand_noisesrc(RAND_GLOBAL, &noise_source);
1269 rand_seed(RAND_GLOBAL, 160);
1271 /* --- Initialize the options table --- */
1273 addopts(sopts, opts);
1278 /* --- Read the generator out of the first argument --- */
1280 if (argc > 1 && *argv[1] != '-') {
1281 const char *arg = av[1];
1282 size_t sz = strlen(arg);
1286 for (gg = generators; gg->name; gg++) {
1287 if (strncmp(arg, gg->name, sz) == 0) {
1288 if (gg->name[sz] == 0) {
1292 die(EXIT_FAILURE, "ambiguous generator name `%s'", arg);
1298 die(EXIT_FAILURE, "unknown generator name `%s'", arg);
1303 /* --- Get a generic random number generator --- */
1306 if (!r || optind != ac - 1) {
1311 /* --- Do the FIPS test --- */
1313 if (flags & f_fips) {
1314 octet buf[FIPSTEST_BUFSZ];
1318 generate(r, sizeof(buf), genbuf, &p);
1320 if (rc & FIPSTEST_MONOBIT)
1321 moan("failed monobit test");
1322 if (rc & FIPSTEST_POKER)
1323 moan("failed poker test");
1324 if (rc & FIPSTEST_RUNS)
1325 moan("failed runs test");
1326 if (rc & FIPSTEST_LONGRUNS)
1327 moan("failed long runs test");
1328 if (!rc && (flags & f_progress))
1329 fputs("test passed\n", stderr);
1330 return (rc ? EXIT_FAILURE : 0);
1333 /* --- Do Maurer's test --- */
1335 if (flags & f_maurer) {
1341 static struct { double x; const char *sig; } sigtab[] = {
1349 g.n = maurer_hi - maurer_lo + 1;
1350 g.m = xmalloc(g.n * sizeof(maurer_ctx));
1351 for (i = 0; i < g.n; i++)
1352 maurer_init(&g.m[i], i + maurer_lo);
1353 bufsz = (100 * maurer_hi) << maurer_hi;
1355 generate(r, bufsz, genmaurer, &g);
1357 for (i = maurer_lo; i <= maurer_hi; i++) {
1358 double z = maurer_done(&g.m[i - maurer_lo]);
1359 double zz = fabs(z);
1362 for (j = 0; sigtab[j].sig; j++) {
1363 if (zz > sigtab[j].x) {
1365 moan("failed, bits = %u, sig = %s, Z_u = %g",
1366 i, sigtab[j].sig, z);
1370 if (flags & f_progress)
1371 fprintf(stderr, "bits = %u, Z_u = %g\n", i, z);
1378 /* --- Discard --- */
1380 if (flags & f_discard) {
1381 generate(r, outsz, 0, 0);
1385 /* --- Write to a file --- */
1388 if (!(flags & f_file) && isatty(STDOUT_FILENO))
1389 die(EXIT_FAILURE, "writing output to a terminal is a bad idea");
1392 generate(r, outsz, genfile, outfp);
1400 /*----- That's all, folks -------------------------------------------------*/