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 ------------------------------------------------------*/
43 # include <sys/time.h>
46 #include <mLib/darray.h>
47 #include <mLib/dstr.h>
48 #include <mLib/mdwopt.h>
49 #include <mLib/quis.h>
50 #include <mLib/report.h>
79 #include "skipjack-ofb.h"
82 #include "blowfish-ofb.h"
83 #include "twofish-ofb.h"
85 #include "cast128-ofb.h"
86 #include "cast256-ofb.h"
87 #include "noekeon-ofb.h"
88 #include "rijndael-ofb.h"
89 #include "rijndael192-ofb.h"
90 #include "rijndael256-ofb.h"
91 #include "safer-ofb.h"
92 #include "safersk-ofb.h"
93 #include "square-ofb.h"
94 #include "serpent-ofb.h"
96 #include "des-counter.h"
97 #include "des3-counter.h"
98 #include "rc2-counter.h"
99 #include "rc5-counter.h"
100 #include "mars-counter.h"
101 #include "skipjack-counter.h"
102 #include "tea-counter.h"
103 #include "xtea-counter.h"
104 #include "blowfish-counter.h"
105 #include "twofish-counter.h"
106 #include "idea-counter.h"
107 #include "cast128-counter.h"
108 #include "cast256-counter.h"
109 #include "noekeon-counter.h"
110 #include "rijndael-counter.h"
111 #include "rijndael192-counter.h"
112 #include "rijndael256-counter.h"
113 #include "safer-counter.h"
114 #include "safersk-counter.h"
115 #include "square-counter.h"
116 #include "serpent-counter.h"
122 #include "tiger-mgf.h"
123 #include "rmd128-mgf.h"
124 #include "rmd160-mgf.h"
125 #include "rmd256-mgf.h"
126 #include "rmd320-mgf.h"
130 /*----- Data structures ---------------------------------------------------*/
134 grand *(*seed)(unsigned /*i*/);
139 extern gen generators[];
147 E(SKIPJACK, skipjack) \
150 E(BLOWFISH, blowfish) \
151 E(TWOFISH, twofish) \
153 E(CAST128, cast128) \
154 E(CAST256, cast256) \
157 E(SAFERSK, safersk) \
158 E(NOEKEON, noekeon) \
159 E(RIJNDAEL, rijndael) \
160 E(RIJNDAEL192, rijndael192) \
161 E(RIJNDAEL256, rijndael256) \
175 #define E(PRE, pre) CIPHER_##PRE,
176 enum { CIPHERS CIPHER__bogus };
179 #define E(PRE, pre) HASH_##PRE,
180 enum { HASHES HASH__bogus };
183 static const struct {
186 grand *(*ofb)(const void */*k*/, size_t /*sz*/);
187 grand *(*counter)(const void */*k*/, size_t /*sz*/);
189 #define E(PRE, pre) \
190 { pre##_keysz, PRE##_BLKSZ, pre##_ofbrand, pre##_counterrand },
195 static const struct {
198 grand *(*mgf)(const void */*k*/, size_t /*sz*/);
200 #define E(PRE, pre) \
201 { &pre, pre##_mgfkeysz, pre##_mgfrand },
206 /*----- Miscellaneous static data -----------------------------------------*/
209 static mp *outsz = 0;
210 static unsigned maurer_lo = 5, maurer_hi = 8;
215 static unsigned flags = 0;
217 #define f_progress 1u
222 #define f_discard 32u
224 /*----- Help options ------------------------------------------------------*/
226 static void usage(FILE *fp)
228 pquis(fp, "Usage: $ generator [options]\n");
231 static void version(FILE *fp)
233 pquis(fp, "$, Catacomb version " VERSION "\n");
236 static void help(FILE *fp)
242 Emits a stream of random bytes suitable for, well, all sorts of things.\n\
243 The primary objective is to be able to generate streams of input for\n\
244 statistical tests, such as Diehard.\n\
246 Options are specific to the particular generator, although there's a\n\
249 -h, --help Display this help message.\n\
250 -v, --version Display the program's version number.\n\
251 -u, --usage Display a useless usage message.\n\
253 -l, --list Show a list of the supported generators, with\n\
255 -f, --fipstest Run the FIPS 140-1 randomness test.\n\
256 -m, --maurer[=LO-HI] Run Maurer's universal statistical test.\n\
257 -o, --output FILE Write output to FILE, not stdout.\n\
258 -z, --size SIZE Emit SIZE bytes, not an unlimited number.\n\
259 -p, --progress Show a little progress meter (on stderr).\n\
260 -T, --timer Keep track of the CPU time used by the generator.\n\
261 -d, --discard Discard the generated output.\n\
263 (A SIZE may be followed by `g' for gigabytes, `m' for megabytes, or\n\
264 `k' for kilobytes. If unqualified, an amount in bytes is assumed.)\n\
268 /*----- Main options parser -----------------------------------------------*/
270 static struct option opts[] = {
272 /* --- Standard GNU help options --- */
274 { "help", 0, 0, 'h' },
275 { "version", 0, 0, 'v' },
276 { "usage", 0, 0, 'u' },
278 /* --- Other useful things --- */
280 { "list", 0, 0, 'l' },
281 { "fipstest", 0, 0, 'f' },
282 { "maurer", OPTF_ARGOPT, 0, 'm' },
283 { "output", OPTF_ARGREQ, 0, 'o' },
284 { "size", OPTF_ARGREQ, 0, 'z' },
285 { "progress", 0, 0, 'p' },
286 { "timer", 0, 0, 'T' },
287 { "discard", 0, 0, 'd' },
289 /* --- End of main table --- */
294 static const char *sopts = "hvu lfm::o:z:pTd";
297 DA_DECL(option_v, struct option);
301 static option_v optv = DA_INIT;
302 static dstr optd = DSTR_INIT;
304 /* --- @addopts@ --- *
306 * Arguments: @const char *s@ = pointer to short options
307 * @struct option *l@ = pointer to long options
311 * Use: Adds a collection of options to the table.
314 static void addopts(const char *s, struct option *l)
320 DA_PUSH(&optv, *l++);
328 * Returns: Next option from argument array.
330 * Use: Fetches options, handling the standard ones.
336 int i = mdwopt(argc, argv, optd.buf, DA(&optv), 0, 0, 0);
349 puts("Generators supported:");
350 for (g = generators; g->name; g++)
351 printf(" %s %s\n", g->name, g->help);
361 unsigned long lo, hi;
362 lo = strtoul(optarg, &p, 0);
363 if (*p == '-' || *p == ',')
364 hi = strtoul(p + 1, &p, 0);
367 if (*p != 0 || hi < lo || lo == 0)
368 die(EXIT_FAILURE, "bad bit range `%s'", optarg);
375 die(EXIT_FAILURE, "already set an output file");
376 if (strcmp(optarg, "-") == 0)
379 outfp = fopen(optarg, "w");
381 die(EXIT_FAILURE, "couldn't open output file `%s': %s",
382 optarg, strerror(errno));
389 outsz = mp_readstring(outsz, optarg, &p, 0);
390 if (!outsz || MP_NEGP(outsz))
391 die(EXIT_FAILURE, "bad number `%s'", optarg);
393 case 'G': case 'g': outsz = mp_lsl(outsz, outsz, 10);
394 case 'M': case 'm': outsz = mp_lsl(outsz, outsz, 10);
395 case 'K': case 'k': outsz = mp_lsl(outsz, outsz, 10);
399 die(EXIT_FAILURE, "bad suffix `%s'", p);
403 die(EXIT_FAILURE, "bad suffix `%s'", p);
420 /*----- Manglers for seed strings -----------------------------------------*/
424 * Arguments: @const char *p@ = pointer to input string
425 * @char **end@ = where the end goes
426 * @dstr *d@ = output buffer
430 * Use: Transforms a hex string into a chunk of binary data.
433 static void unhex(const char *p, char **end, dstr *d)
435 while (p[0] && p[1]) {
436 int x = p[0], y = p[1];
437 if ('0' <= x && x <= '9') x -= '0';
438 else if ('A' <= x && x <= 'F') x -= 'A' - 10;
439 else if ('a' <= x && x <= 'f') x -= 'a' - 10;
441 if ('0' <= y && y <= '9') y -= '0';
442 else if ('A' <= y && y <= 'F') y -= 'A' - 10;
443 else if ('a' <= y && y <= 'f') y -= 'a' - 10;
445 DPUTC(d, (x << 4) + y);
451 /* --- Generate a key --- */
453 static void textkey(dstr *d, const char *p, const octet *ksz)
455 size_t sz = strlen(p);
458 die(EXIT_FAILURE, "zero-length key string");
459 if (keysz(sz, ksz) != sz)
463 rmd160_mgfinit(&g, p, sz);
466 rmd160_mgfencrypt(&g, 0, d->buf, sz);
469 assert(((void)"I can't seem to choose a good key size",
470 keysz(d->len, ksz) == d->len));
473 static void hexkey(dstr *d, const char *p, const octet *ksz)
476 unhex(optarg, &q, d);
478 die(EXIT_FAILURE, "bad hex key `%s'", p);
479 if (keysz(d->len, ksz) != d->len)
480 die(EXIT_FAILURE, "bad key length");
483 static void randkey(dstr *d, const octet *ksz)
485 size_t sz = keysz(0, ksz);
487 rand_get(RAND_GLOBAL, d->buf, sz);
491 /*----- Generators --------------------------------------------------------*/
493 /* --- Blum-Blum-Shub strong generator --- */
495 static grand *gen_bbs(unsigned i)
497 /* --- Default modulus --- *
499 * The factors of this number are
501 * @p = 1229936431484295969649886203367009966370895964206162032259292413@
502 * @7754313537966036459299022912838407755462506416274551744201653277@
503 * @313130311731673973886822067@
505 * @q = 9798171783943489959487301695884963889684294764514008432498259742@
506 * @5374320073594018817245784145742769603334292182227671519041431067@
507 * @61344781426317516045890159@
509 * Both %$p$% and %$q$% are prime; %$(p - 1)/2$% and %$(q - 1)/2$% have no
510 * common factors. They were found using this program, with random
513 * I hope that, by publishing these factors, I'll dissuade people from
514 * actually using this modulus in an attempt to attain real security. The
515 * program is quite quick at finding Blum numbers, so there's no excuse for
516 * not generating your own.
520 "12051128439013574251357214209433471144307319411973256935382082"
521 "84356405274180923922403660880355098909699130818163691602989614"
522 "90135716255689660470370755013177656905237112577648090277537209"
523 "93607817155427455344810369808478266925293635284364998010510985"
524 "0503830397166360721262431179505917248447259735253684659338653";
526 /* --- Other things --- */
530 unsigned bits = 1024;
533 const char *kfile = 0, *id = 0, *ktype = 0;
535 /* --- Parse options --- */
537 static struct option opts[] = {
538 { "modulus", OPTF_ARGREQ, 0, 'M' },
539 { "generate", 0, 0, 'g' },
540 { "seed", OPTF_ARGREQ, 0, 's' },
541 { "bits", OPTF_ARGREQ, 0, 'b' },
542 { "show", 0, 0, 'S' },
543 { "keyring", OPTF_ARGREQ, 0, 'k' },
544 { "id", OPTF_ARGREQ, 0, 'i' },
545 { "type", OPTF_ARGREQ, 0, 't' },
549 addopts("M:gs:b:Sk:i:t:", opts);
566 bits = strtoul(optarg, 0, 0);
568 die(EXIT_FAILURE, "bad number of bits `%s'", optarg);
590 /* --- Generate a modulus if one is requested --- */
594 m = mp_readstring(MP_NEW, mt, &p, 0);
595 if (!m || *p || (m->v[0] & 3) != 1)
596 die(EXIT_FAILURE, "bad modulus `%s'", mt);
597 /* Unfortunately I don't know how to test for a Blum integer */
598 } else if (kfile || id || ktype) {
603 /* --- Open the key file --- */
607 if (key_open(&kf, kfile, KOPEN_READ, key_moan, 0)) {
608 die(EXIT_FAILURE, "error opening key file `%s': %s",
609 kfile, strerror(errno));
612 /* --- Find the key --- */
615 if ((kk = key_bytag(&kf, id)) == 0)
616 die(EXIT_FAILURE, "key `%s' not found", id);
620 if ((kk = key_bytype(&kf, ktype)) == 0)
621 die(EXIT_FAILURE, "no suitable key with type `%s' found", ktype);
624 /* --- Read the key data --- */
626 if ((kk->k->e & KF_ENCMASK) != KENC_STRUCT)
627 die(EXIT_FAILURE, "key is not structured");
628 if ((kd = key_structfind(kk->k, "n")) == 0)
629 die(EXIT_FAILURE, "key has no subkey `n'");
630 if ((kd->e & KF_ENCMASK) != KENC_MP)
631 die(EXIT_FAILURE, "incompatible subkey encoding");
632 m = MP_COPY(kd->u.m);
637 if (bbs_gen(&bp, bits, &rand_global, 0,
638 (flags & f_progress) ? pgen_ev : 0, 0))
639 die(EXIT_FAILURE, "modulus generation failed");
643 fputs("p = ", stderr);
644 mp_writefile(bp.p, stderr, 10);
645 fputs("\nq = ", stderr);
646 mp_writefile(bp.q, stderr, 10);
647 fputs("\nn = ", stderr);
648 mp_writefile(bp.n, stderr, 10);
656 /* --- Set up a seed --- */
659 x = mprand(MP_NEW, mp_bits(m) - 1, &rand_global, 1);
662 x = mp_readstring(MP_NEW, xt, &p, 0);
664 die(EXIT_FAILURE, "bad modulus `%s'", xt);
676 /* --- Catacomb's random number generator --- */
678 static grand *gen_rand(unsigned i)
680 grand *r = rand_create();
683 static struct option opts[] = {
684 { "key", OPTF_ARGREQ, 0, 'k' },
685 { "text", OPTF_ARGREQ, 0, 't' },
686 { "hex", OPTF_ARGREQ, 0, 'H' },
690 addopts("k:t:H:n", opts);
692 r->ops->misc(r, RAND_NOISESRC, &noise_source);
693 r->ops->misc(r, RAND_SEED, 160);
702 textkey(&d, optarg, rmd160_hmackeysz);
703 r->ops->misc(r, RAND_KEY, d.buf, d.len);
706 r->ops->misc(r, GRAND_SEEDBLOCK, optarg, strlen(optarg));
710 hexkey(&d, optarg, rmd160_hmackeysz);
711 r->ops->misc(r, GRAND_SEEDBLOCK, d.buf, d.len);
720 /* --- RC4 output --- */
722 static grand *gen_rc4(unsigned i)
727 static struct option opts[] = {
728 { "key", OPTF_ARGREQ, 0, 'k' },
729 { "hex", OPTF_ARGREQ, 0, 'H' },
733 addopts("k:H:", opts);
742 textkey(&d, optarg, rc4_keysz);
746 hexkey(&d, optarg, rc4_keysz);
754 randkey(&d, rc4_keysz);
755 r = rc4_rand(d.buf, d.len);
760 /* --- SEAL output --- */
762 static grand *gen_seal(unsigned i)
768 static struct option opts[] = {
769 { "key", OPTF_ARGREQ, 0, 'k' },
770 { "hex", OPTF_ARGREQ, 0, 'H' },
771 { "sequence", OPTF_ARGREQ, 0, 'n' },
775 addopts("k:H:n:", opts);
784 textkey(&d, optarg, seal_keysz);
788 hexkey(&d, optarg, seal_keysz);
792 n = strtoul(optarg, &p, 0);
794 die(EXIT_FAILURE, "bad number `%s'", optarg);
802 randkey(&d, seal_keysz);
803 r = seal_rand(d.buf, d.len, n);
808 /* --- Output feedback generators --- */
810 static grand *gen_ofb(unsigned i)
816 static struct option opts[] = {
817 { "key", OPTF_ARGREQ, 0, 'k' },
818 { "hex", OPTF_ARGREQ, 0, 'H' },
819 { "iv", OPTF_ARGREQ, 0, 'i' },
823 addopts("k:H:i:", opts);
832 textkey(&d, optarg, ciphertab[i].keysz);
836 hexkey(&d, optarg, ciphertab[i].keysz);
841 unhex(optarg, &p, &iv);
843 die(EXIT_FAILURE, "bad hex IV `%s'", optarg);
844 if (iv.len != ciphertab[i].blksz) {
845 die(EXIT_FAILURE, "bad IV length %lu (must be %lu)",
846 (unsigned long)iv.len, (unsigned long)ciphertab[i].blksz);
855 randkey(&d, ciphertab[i].keysz);
856 r = ciphertab[i].ofb(d.buf, d.len);
858 r->ops->misc(r, GRAND_SEEDBLOCK, iv.buf);
865 /* --- Counter generators --- */
867 static grand *gen_counter(unsigned i)
873 static struct option opts[] = {
874 { "key", OPTF_ARGREQ, 0, 'k' },
875 { "hex", OPTF_ARGREQ, 0, 'H' },
876 { "iv", OPTF_ARGREQ, 0, 'i' },
880 addopts("k:H:i:", opts);
889 textkey(&d, optarg, ciphertab[i].keysz);
893 hexkey(&d, optarg, ciphertab[i].keysz);
898 unhex(optarg, &p, &iv);
900 die(EXIT_FAILURE, "bad hex IV `%s'", optarg);
901 if (iv.len != ciphertab[i].blksz) {
902 die(EXIT_FAILURE, "bad IV length %lu (must be %lu)",
903 (unsigned long)iv.len, (unsigned long)ciphertab[i].blksz);
912 randkey(&d, ciphertab[i].keysz);
913 r = ciphertab[i].counter(d.buf, d.len);
915 r->ops->misc(r, GRAND_SEEDBLOCK, iv.buf);
922 /* --- Mask generators --- */
924 static grand *gen_mgf(unsigned i)
930 static struct option opts[] = {
931 { "key", OPTF_ARGREQ, 0, 'k' },
932 { "hex", OPTF_ARGREQ, 0, 'H' },
933 { "index", OPTF_ARGREQ, 0, 'i' },
937 addopts("k:H:i:", opts);
946 textkey(&d, optarg, hashtab[i].keysz);
950 hexkey(&d, optarg, hashtab[i].keysz);
954 c = strtoul(optarg, &p, 0);
956 die(EXIT_FAILURE, "bad index `%s'", optarg);
964 randkey(&d, hashtab[i].keysz);
966 r = hashtab[i].mgf(d.buf, d.len);
968 r->ops->misc(r, GRAND_SEEDUINT32, c);
974 /* --- Fibonacci generator --- */
976 static grand *gen_fib(unsigned i)
983 static struct option opts[] = {
984 { "seed", OPTF_ARGREQ, 0, 's' },
996 s = strtoul(optarg, &p, 0);
998 die(EXIT_FAILURE, "bad integer `%s'", optarg);
1005 r = fibrand_create(s);
1007 r->ops->misc(r, GRAND_SEEDRAND, &rand_global);
1011 /* --- LC generator --- */
1013 static grand *gen_lc(unsigned i)
1019 static struct option opts[] = {
1020 { "seed", OPTF_ARGREQ, 0, 's' },
1024 addopts("s:", opts);
1032 s = strtoul(optarg, &p, 0);
1034 die(EXIT_FAILURE, "bad integer `%s'", optarg);
1043 s = rand_global.ops->range(&rand_global, LCRAND_P);
1044 while (s == LCRAND_FIXEDPT);
1046 return (lcrand_create(s));
1049 /* --- Basic options parser -- can't generate output --- */
1051 static grand *gen_opts(unsigned i)
1058 /*----- Generators table --------------------------------------------------*/
1060 gen generators[] = {
1061 { "fibonacci", gen_fib, 0,
1065 #define E(PRE, pre) \
1066 { #pre "-ofb", gen_ofb, CIPHER_##PRE, \
1067 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
1070 #define E(PRE, pre) \
1071 { #pre "-counter", gen_counter, CIPHER_##PRE, \
1072 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
1075 #define E(PRE, pre) \
1076 { #pre "-mgf", gen_mgf, HASH_##PRE, \
1077 "[-k KEY-PHRASE] [-H HEX-KEY] [-i INDEX]" },
1080 { "rc4", gen_rc4, 0,
1081 "[-k KEY-PHRASE] [-H HEX-KEY]" },
1082 { "seal", gen_seal, 0,
1083 "[-k KEY-PHRASE] [-H HEX-KEY] [-n SEQ]" },
1084 { "rand", gen_rand, 0,
1085 "[-n] [-k KEY-PHRASE] [-t TEXT-BLOCK] [-H HEX-BLOCK]" },
1086 { "bbs", gen_bbs, 0,
1087 "[-gS] [-s SEED] [-M MODULUS] [-b BITS] [-k KEYRING] [-i TAG] [-t TYPE]"
1092 static gen optsg = { "options", gen_opts, 0,
1093 "This message shouldn't be printed." };
1095 /*----- Random number generation ------------------------------------------*/
1097 static int genfile(const void *buf, size_t sz, void *p)
1100 if (fwrite(buf, 1, sz, fp) != sz)
1101 die(EXIT_FAILURE, "error writing to file: %s", strerror(errno));
1105 static int genbuf(const void *buf, size_t sz, void *p)
1108 memcpy(*pp, buf, sz);
1113 typedef struct genmaurer_ctx {
1118 static int genmaurer(const void *buf, size_t sz, void *p)
1120 genmaurer_ctx *g = p;
1123 for (i = 0; i < g->n; i++)
1124 maurer_test(&g->m[i], buf, sz);
1128 static double doubletime(void)
1131 static time_t start = (time_t)-1;
1132 time_t now = time(0);
1134 if (start == (time_t)-1) start = now;
1135 return difftime(now, start);
1139 gettimeofday(&tv, 0);
1140 return (tv.tv_sec + tv.tv_usec/1000000.0);
1144 static int generate(grand *r, mp *outsz,
1145 int (*func)(const void *buf, size_t sz, void *p),
1148 static char kmg[] = { ' ', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 0 };
1150 unsigned percent = 0;
1151 mp *kb = MP_ZERO, *t = MP_NEW;
1154 static char baton[] = "-\\|/";
1159 /* --- Spit out random data --- */
1161 last = doubletime();
1163 if (flags & f_progress) {
1164 char *errbuf = xmalloc(BUFSIZ);
1165 setvbuf(stderr, errbuf, _IOLBF, BUFSIZ);
1167 fprintf(stderr, "[%*s] 0%% 0\r[/\b", 50, "");
1169 fputs("[ ] 0\r[/\b", stderr);
1174 signal(SIGPIPE, SIG_IGN);
1177 while (!outsz || MP_CMP(kb, <, outsz)) {
1179 size_t sz = sizeof(buf), left;
1180 clock_t c_start, c_stop;
1182 /* --- Emit a bufferful (or less) of data --- */
1185 t = mp_sub(t, outsz, kb);
1186 assert(!MP_NEGP(t));
1187 if (MP_CMP(t, <=, MP_SIZET_MAX)) {
1188 left = mp_tosizet(t);
1189 if (sz > left) sz = left;
1193 r->ops->fill(r, buf, sz);
1195 clk += c_stop - c_start;
1196 if (func && (rc = func(buf, sz, p)) != 0)
1198 t = mp_fromsizet(t, sz);
1199 kb = mp_add(kb, kb, t);
1201 /* --- Update the display --- */
1203 if (flags & f_progress) {
1212 if (now - last > 0.1) {
1216 fputs(" ] ", stderr);
1219 t = mp_fromulong(t, 100);
1220 t = mp_mul(t, t, kb);
1221 mp_div(&t, 0, t, outsz);
1222 assert(!MP_NEGP(t) && MP_CMP(t, <, MP_UINT_MAX));
1224 if (pc > percent || percent > 100 || now - last > 0.1) {
1228 for (; percent < (pc & ~1); percent += 2)
1231 for (; pc < 100; pc += 2)
1233 fprintf(stderr, "] %3i%% ", percent);
1240 t = mp_add(t, kb, MP_ZERO);
1241 while (mp_bits(t) >= 14) {
1242 t = mp_lsr(t, t, 10);
1246 mp_writedstr(t, &d, 10);
1247 fprintf(stderr, "%4s%c\r[", d.buf, *kk);
1250 for (pc = 0; pc < (percent & ~1); pc += 2)
1259 if (percent < 100 && up) {
1260 putc(*bp++, stderr);
1269 if (flags & f_progress)
1270 fputc('\n', stderr);
1271 if (flags & f_timer) {
1273 dstr_puts(&d, "generated ");
1274 mp_writedstr(kb, &d, 10);
1275 dstr_puts(&d, " bytes ");
1277 dstr_puts(&d, "too quickly to measure\n");
1281 double sec = (double)clk/CLOCKS_PER_SEC;
1286 switch (MP_LEN(kb)) {
1287 case 0: out = 0; break;
1288 case 1: out = kb->v[0]; break;
1290 sh = mp_bits(kb) - MPW_BITS;
1291 t = mp_lsr(t, kb, sh);
1292 out = ldexp(t->v[0], sh);
1296 for (kk = kmg; bps > 1024 && kk[1]; kk++, bps /= 1024)
1298 dstr_putf(&d, "in %g secs (%g %cb/s)\n", sec, bps, *kk);
1299 fwrite(d.buf, 1, d.len, stderr);
1308 /*----- Main code ---------------------------------------------------------*/
1310 int main(int ac, char *av[])
1315 /* --- Initialize mLib --- */
1320 /* --- Set up the main Catacomb generator --- */
1322 rand_noisesrc(RAND_GLOBAL, &noise_source);
1323 rand_seed(RAND_GLOBAL, 160);
1325 /* --- Initialize the options table --- */
1327 addopts(sopts, opts);
1332 /* --- Read the generator out of the first argument --- */
1334 if (argc > 1 && *argv[1] != '-') {
1335 const char *arg = av[1];
1336 size_t sz = strlen(arg);
1340 for (gg = generators; gg->name; gg++) {
1341 if (strncmp(arg, gg->name, sz) == 0) {
1342 if (gg->name[sz] == 0) {
1346 die(EXIT_FAILURE, "ambiguous generator name `%s'", arg);
1352 die(EXIT_FAILURE, "unknown generator name `%s'", arg);
1357 /* --- Get a generic random number generator --- */
1360 if (!r || optind != ac - 1) {
1365 /* --- Do the FIPS test --- */
1367 if (flags & f_fips) {
1368 octet buf[FIPSTEST_BUFSZ];
1373 t = mp_fromsizet(MP_NEW, sizeof(buf));
1374 generate(r, t, genbuf, &p);
1377 if (rc & FIPSTEST_MONOBIT)
1378 moan("failed monobit test");
1379 if (rc & FIPSTEST_POKER)
1380 moan("failed poker test");
1381 if (rc & FIPSTEST_RUNS)
1382 moan("failed runs test");
1383 if (rc & FIPSTEST_LONGRUNS)
1384 moan("failed long runs test");
1385 if (!rc && (flags & f_progress))
1386 fputs("test passed\n", stderr);
1387 return (rc ? EXIT_FAILURE : 0);
1390 /* --- Do Maurer's test --- */
1392 if (flags & f_maurer) {
1399 static struct { double x; const char *sig; } sigtab[] = {
1407 g.n = maurer_hi - maurer_lo + 1;
1408 g.m = xmalloc(g.n * sizeof(maurer_ctx));
1409 for (i = 0; i < g.n; i++)
1410 maurer_init(&g.m[i], i + maurer_lo);
1411 bufsz = (100 * maurer_hi) << maurer_hi;
1413 t = mp_fromsizet(MP_NEW, bufsz);
1414 generate(r, t, genmaurer, &g);
1417 for (i = maurer_lo; i <= maurer_hi; i++) {
1418 double z = maurer_done(&g.m[i - maurer_lo]);
1419 double zz = fabs(z);
1422 for (j = 0; sigtab[j].sig; j++) {
1423 if (zz > sigtab[j].x) {
1425 moan("failed, bits = %u, sig = %s, Z_u = %g",
1426 i, sigtab[j].sig, z);
1430 if (flags & f_progress)
1431 fprintf(stderr, "bits = %u, Z_u = %g\n", i, z);
1438 /* --- Discard --- */
1440 if (flags & f_discard) {
1441 generate(r, outsz, 0, 0);
1445 /* --- Write to a file --- */
1448 if (!(flags & f_file) && isatty(STDOUT_FILENO))
1449 die(EXIT_FAILURE, "writing output to a terminal is a bad idea");
1452 generate(r, outsz, genfile, outfp);
1460 /*----- That's all, folks -------------------------------------------------*/