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>
78 #include "skipjack-ofb.h"
81 #include "blowfish-ofb.h"
82 #include "twofish-ofb.h"
84 #include "cast128-ofb.h"
85 #include "cast256-ofb.h"
86 #include "noekeon-ofb.h"
87 #include "rijndael-ofb.h"
88 #include "rijndael192-ofb.h"
89 #include "rijndael256-ofb.h"
90 #include "safer-ofb.h"
91 #include "safersk-ofb.h"
92 #include "square-ofb.h"
93 #include "serpent-ofb.h"
95 #include "des-counter.h"
96 #include "des3-counter.h"
97 #include "rc2-counter.h"
98 #include "rc5-counter.h"
99 #include "mars-counter.h"
100 #include "skipjack-counter.h"
101 #include "tea-counter.h"
102 #include "xtea-counter.h"
103 #include "blowfish-counter.h"
104 #include "twofish-counter.h"
105 #include "idea-counter.h"
106 #include "cast128-counter.h"
107 #include "cast256-counter.h"
108 #include "noekeon-counter.h"
109 #include "rijndael-counter.h"
110 #include "rijndael192-counter.h"
111 #include "rijndael256-counter.h"
112 #include "safer-counter.h"
113 #include "safersk-counter.h"
114 #include "square-counter.h"
115 #include "serpent-counter.h"
121 #include "tiger-mgf.h"
122 #include "rmd128-mgf.h"
123 #include "rmd160-mgf.h"
124 #include "rmd256-mgf.h"
125 #include "rmd320-mgf.h"
129 /*----- Data structures ---------------------------------------------------*/
133 grand *(*seed)(unsigned /*i*/);
138 extern gen generators[];
146 E(SKIPJACK, skipjack) \
149 E(BLOWFISH, blowfish) \
150 E(TWOFISH, twofish) \
152 E(CAST128, cast128) \
153 E(CAST256, cast256) \
156 E(SAFERSK, safersk) \
157 E(NOEKEON, noekeon) \
158 E(RIJNDAEL, rijndael) \
159 E(RIJNDAEL192, rijndael192) \
160 E(RIJNDAEL256, rijndael256) \
174 #define E(PRE, pre) CIPHER_##PRE,
175 enum { CIPHERS CIPHER__bogus };
178 #define E(PRE, pre) HASH_##PRE,
179 enum { HASHES HASH__bogus };
182 static const struct {
185 grand *(*ofb)(const void */*k*/, size_t /*sz*/);
186 grand *(*counter)(const void */*k*/, size_t /*sz*/);
188 #define E(PRE, pre) \
189 { pre##_keysz, PRE##_BLKSZ, pre##_ofbrand, pre##_counterrand },
194 static const struct {
197 grand *(*mgf)(const void */*k*/, size_t /*sz*/);
199 #define E(PRE, pre) \
200 { &pre, pre##_mgfkeysz, pre##_mgfrand },
205 /*----- Miscellaneous static data -----------------------------------------*/
208 static mp *outsz = 0;
209 static unsigned maurer_lo = 5, maurer_hi = 8;
214 static unsigned flags = 0;
216 #define f_progress 1u
221 #define f_discard 32u
223 /*----- Help options ------------------------------------------------------*/
225 static void usage(FILE *fp)
227 pquis(fp, "Usage: $ generator [options]\n");
230 static void version(FILE *fp)
232 pquis(fp, "$, Catacomb version " VERSION "\n");
235 static void help(FILE *fp)
241 Emits a stream of random bytes suitable for, well, all sorts of things.\n\
242 The primary objective is to be able to generate streams of input for\n\
243 statistical tests, such as Diehard.\n\
245 Options are specific to the particular generator, although there's a\n\
248 -h, --help Display this help message.\n\
249 -v, --version Display the program's version number.\n\
250 -u, --usage Display a useless usage message.\n\
252 -l, --list Show a list of the supported generators, with\n\
254 -f, --fipstest Run the FIPS 140-1 randomness test.\n\
255 -m, --maurer[=LO-HI] Run Maurer's universal statistical test.\n\
256 -o, --output FILE Write output to FILE, not stdout.\n\
257 -z, --size SIZE Emit SIZE bytes, not an unlimited number.\n\
258 -p, --progress Show a little progress meter (on stderr).\n\
259 -T, --timer Keep track of the CPU time used by the generator.\n\
260 -d, --discard Discard the generated output.\n\
262 (A SIZE may be followed by `g' for gigabytes, `m' for megabytes, or\n\
263 `k' for kilobytes. If unqualified, an amount in bytes is assumed.)\n\
267 /*----- Main options parser -----------------------------------------------*/
269 static struct option opts[] = {
271 /* --- Standard GNU help options --- */
273 { "help", 0, 0, 'h' },
274 { "version", 0, 0, 'v' },
275 { "usage", 0, 0, 'u' },
277 /* --- Other useful things --- */
279 { "list", 0, 0, 'l' },
280 { "fipstest", 0, 0, 'f' },
281 { "maurer", OPTF_ARGOPT, 0, 'm' },
282 { "output", OPTF_ARGREQ, 0, 'o' },
283 { "size", OPTF_ARGREQ, 0, 'z' },
284 { "progress", 0, 0, 'p' },
285 { "timer", 0, 0, 'T' },
286 { "discard", 0, 0, 'd' },
288 /* --- End of main table --- */
293 static const char *sopts = "hvu lfm::o:z:pTd";
296 DA_DECL(option_v, struct option);
300 static option_v optv = DA_INIT;
301 static dstr optd = DSTR_INIT;
303 /* --- @addopts@ --- *
305 * Arguments: @const char *s@ = pointer to short options
306 * @struct option *l@ = pointer to long options
310 * Use: Adds a collection of options to the table.
313 static void addopts(const char *s, struct option *l)
319 DA_PUSH(&optv, *l++);
327 * Returns: Next option from argument array.
329 * Use: Fetches options, handling the standard ones.
335 int i = mdwopt(argc, argv, optd.buf, DA(&optv), 0, 0, 0);
348 puts("Generators supported:");
349 for (g = generators; g->name; g++)
350 printf(" %s %s\n", g->name, g->help);
360 unsigned long lo, hi;
361 lo = strtoul(optarg, &p, 0);
362 if (*p == '-' || *p == ',')
363 hi = strtoul(p + 1, &p, 0);
366 if (*p != 0 || hi < lo || lo == 0)
367 die(EXIT_FAILURE, "bad bit range `%s'", optarg);
374 die(EXIT_FAILURE, "already set an output file");
375 if (strcmp(optarg, "-") == 0)
378 outfp = fopen(optarg, "w");
380 die(EXIT_FAILURE, "couldn't open output file `%s': %s",
381 optarg, strerror(errno));
388 outsz = mp_readstring(outsz, optarg, &p, 0);
389 if (!outsz || MP_NEGP(outsz))
390 die(EXIT_FAILURE, "bad number `%s'", optarg);
392 case 'G': case 'g': outsz = mp_lsl(outsz, outsz, 10);
393 case 'M': case 'm': outsz = mp_lsl(outsz, outsz, 10);
394 case 'K': case 'k': outsz = mp_lsl(outsz, outsz, 10);
398 die(EXIT_FAILURE, "bad suffix `%s'", p);
402 die(EXIT_FAILURE, "bad suffix `%s'", p);
419 /*----- Manglers for seed strings -----------------------------------------*/
423 * Arguments: @const char *p@ = pointer to input string
424 * @char **end@ = where the end goes
425 * @dstr *d@ = output buffer
429 * Use: Transforms a hex string into a chunk of binary data.
432 static void unhex(const char *p, char **end, dstr *d)
434 while (p[0] && p[1]) {
435 int x = p[0], y = p[1];
436 if ('0' <= x && x <= '9') x -= '0';
437 else if ('A' <= x && x <= 'F') x -= 'A' - 10;
438 else if ('a' <= x && x <= 'f') x -= 'a' - 10;
440 if ('0' <= y && y <= '9') y -= '0';
441 else if ('A' <= y && y <= 'F') y -= 'A' - 10;
442 else if ('a' <= y && y <= 'f') y -= 'a' - 10;
444 DPUTC(d, (x << 4) + y);
450 /* --- Generate a key --- */
452 static void textkey(dstr *d, const char *p, const octet *ksz)
454 size_t sz = strlen(p);
457 die(EXIT_FAILURE, "zero-length key string");
458 if (keysz(sz, ksz) != sz)
462 rmd160_mgfinit(&g, p, sz);
465 rmd160_mgfencrypt(&g, 0, d->buf, sz);
468 assert(((void)"I can't seem to choose a good key size",
469 keysz(d->len, ksz) == d->len));
472 static void hexkey(dstr *d, const char *p, const octet *ksz)
475 unhex(optarg, &q, d);
477 die(EXIT_FAILURE, "bad hex key `%s'", p);
478 if (keysz(d->len, ksz) != d->len)
479 die(EXIT_FAILURE, "bad key length");
482 static void randkey(dstr *d, const octet *ksz)
484 size_t sz = keysz(0, ksz);
486 rand_get(RAND_GLOBAL, d->buf, sz);
490 /*----- Generators --------------------------------------------------------*/
492 /* --- Blum-Blum-Shub strong generator --- */
494 static grand *gen_bbs(unsigned i)
496 /* --- Default modulus --- *
498 * The factors of this number are
500 * @p = 1229936431484295969649886203367009966370895964206162032259292413@
501 * @7754313537966036459299022912838407755462506416274551744201653277@
502 * @313130311731673973886822067@
504 * @q = 9798171783943489959487301695884963889684294764514008432498259742@
505 * @5374320073594018817245784145742769603334292182227671519041431067@
506 * @61344781426317516045890159@
508 * Both %$p$% and %$q$% are prime; %$(p - 1)/2$% and %$(q - 1)/2$% have no
509 * common factors. They were found using this program, with random
512 * I hope that, by publishing these factors, I'll dissuade people from
513 * actually using this modulus in an attempt to attain real security. The
514 * program is quite quick at finding Blum numbers, so there's no excuse for
515 * not generating your own.
519 "12051128439013574251357214209433471144307319411973256935382082"
520 "84356405274180923922403660880355098909699130818163691602989614"
521 "90135716255689660470370755013177656905237112577648090277537209"
522 "93607817155427455344810369808478266925293635284364998010510985"
523 "0503830397166360721262431179505917248447259735253684659338653";
525 /* --- Other things --- */
529 unsigned bits = 1024;
532 const char *kfile = 0, *id = 0, *ktype = 0;
534 /* --- Parse options --- */
536 static struct option opts[] = {
537 { "modulus", OPTF_ARGREQ, 0, 'M' },
538 { "generate", 0, 0, 'g' },
539 { "seed", OPTF_ARGREQ, 0, 's' },
540 { "bits", OPTF_ARGREQ, 0, 'b' },
541 { "show", 0, 0, 'S' },
542 { "keyring", OPTF_ARGREQ, 0, 'k' },
543 { "id", OPTF_ARGREQ, 0, 'i' },
544 { "type", OPTF_ARGREQ, 0, 't' },
548 addopts("M:gs:b:Sk:i:t:", opts);
565 bits = strtoul(optarg, 0, 0);
567 die(EXIT_FAILURE, "bad number of bits `%s'", optarg);
589 /* --- Generate a modulus if one is requested --- */
593 m = mp_readstring(MP_NEW, mt, &p, 0);
594 if (!m || *p || (m->v[0] & 3) != 1)
595 die(EXIT_FAILURE, "bad modulus `%s'", mt);
596 /* Unfortunately I don't know how to test for a Blum integer */
597 } else if (kfile || id || ktype) {
602 /* --- Open the key file --- */
606 if (key_open(&kf, kfile, KOPEN_READ, key_moan, 0)) {
607 die(EXIT_FAILURE, "error opening key file `%s': %s",
608 kfile, strerror(errno));
611 /* --- Find the key --- */
614 if ((kk = key_bytag(&kf, id)) == 0)
615 die(EXIT_FAILURE, "key `%s' not found", id);
619 if ((kk = key_bytype(&kf, ktype)) == 0)
620 die(EXIT_FAILURE, "no suitable key with type `%s' found", ktype);
623 /* --- Read the key data --- */
625 if ((kk->k->e & KF_ENCMASK) != KENC_STRUCT)
626 die(EXIT_FAILURE, "key is not structured");
627 if ((kd = key_structfind(kk->k, "n")) == 0)
628 die(EXIT_FAILURE, "key has no subkey `n'");
629 if ((kd->e & KF_ENCMASK) != KENC_MP)
630 die(EXIT_FAILURE, "incompatible subkey encoding");
631 m = MP_COPY(kd->u.m);
636 if (bbs_gen(&bp, bits, &rand_global, 0,
637 (flags & f_progress) ? pgen_ev : 0, 0))
638 die(EXIT_FAILURE, "modulus generation failed");
642 fputs("p = ", stderr);
643 mp_writefile(bp.p, stderr, 10);
644 fputs("\nq = ", stderr);
645 mp_writefile(bp.q, stderr, 10);
646 fputs("\nn = ", stderr);
647 mp_writefile(bp.n, stderr, 10);
655 /* --- Set up a seed --- */
658 x = mprand(MP_NEW, mp_bits(m) - 1, &rand_global, 1);
661 x = mp_readstring(MP_NEW, xt, &p, 0);
663 die(EXIT_FAILURE, "bad modulus `%s'", xt);
675 /* --- Catacomb's random number generator --- */
677 static grand *gen_rand(unsigned i)
679 grand *r = rand_create();
682 static struct option opts[] = {
683 { "key", OPTF_ARGREQ, 0, 'k' },
684 { "text", OPTF_ARGREQ, 0, 't' },
685 { "hex", OPTF_ARGREQ, 0, 'H' },
689 addopts("k:t:H:n", opts);
691 r->ops->misc(r, RAND_NOISESRC, &noise_source);
692 r->ops->misc(r, RAND_SEED, 160);
701 textkey(&d, optarg, rmd160_hmackeysz);
702 r->ops->misc(r, RAND_KEY, d.buf, d.len);
705 r->ops->misc(r, GRAND_SEEDBLOCK, optarg, strlen(optarg));
709 hexkey(&d, optarg, rmd160_hmackeysz);
710 r->ops->misc(r, GRAND_SEEDBLOCK, d.buf, d.len);
719 /* --- RC4 output --- */
721 static grand *gen_rc4(unsigned i)
726 static struct option opts[] = {
727 { "key", OPTF_ARGREQ, 0, 'k' },
728 { "hex", OPTF_ARGREQ, 0, 'H' },
732 addopts("k:H:", opts);
741 textkey(&d, optarg, rc4_keysz);
745 hexkey(&d, optarg, rc4_keysz);
753 randkey(&d, rc4_keysz);
754 r = rc4_rand(d.buf, d.len);
759 /* --- SEAL output --- */
761 static grand *gen_seal(unsigned i)
767 static struct option opts[] = {
768 { "key", OPTF_ARGREQ, 0, 'k' },
769 { "hex", OPTF_ARGREQ, 0, 'H' },
770 { "sequence", OPTF_ARGREQ, 0, 'n' },
774 addopts("k:H:n:", opts);
783 textkey(&d, optarg, seal_keysz);
787 hexkey(&d, optarg, seal_keysz);
791 n = strtoul(optarg, &p, 0);
793 die(EXIT_FAILURE, "bad number `%s'", optarg);
801 randkey(&d, seal_keysz);
802 r = seal_rand(d.buf, d.len, n);
807 /* --- Output feedback generators --- */
809 static grand *gen_ofb(unsigned i)
815 static struct option opts[] = {
816 { "key", OPTF_ARGREQ, 0, 'k' },
817 { "hex", OPTF_ARGREQ, 0, 'H' },
818 { "iv", OPTF_ARGREQ, 0, 'i' },
822 addopts("k:H:i:", opts);
831 textkey(&d, optarg, ciphertab[i].keysz);
835 hexkey(&d, optarg, ciphertab[i].keysz);
840 unhex(optarg, &p, &iv);
842 die(EXIT_FAILURE, "bad hex IV `%s'", optarg);
843 if (iv.len != ciphertab[i].blksz) {
844 die(EXIT_FAILURE, "bad IV length %lu (must be %lu)",
845 (unsigned long)iv.len, (unsigned long)ciphertab[i].blksz);
854 randkey(&d, ciphertab[i].keysz);
855 r = ciphertab[i].ofb(d.buf, d.len);
857 r->ops->misc(r, GRAND_SEEDBLOCK, iv.buf);
864 /* --- Counter generators --- */
866 static grand *gen_counter(unsigned i)
872 static struct option opts[] = {
873 { "key", OPTF_ARGREQ, 0, 'k' },
874 { "hex", OPTF_ARGREQ, 0, 'H' },
875 { "iv", OPTF_ARGREQ, 0, 'i' },
879 addopts("k:H:i:", opts);
888 textkey(&d, optarg, ciphertab[i].keysz);
892 hexkey(&d, optarg, ciphertab[i].keysz);
897 unhex(optarg, &p, &iv);
899 die(EXIT_FAILURE, "bad hex IV `%s'", optarg);
900 if (iv.len != ciphertab[i].blksz) {
901 die(EXIT_FAILURE, "bad IV length %lu (must be %lu)",
902 (unsigned long)iv.len, (unsigned long)ciphertab[i].blksz);
911 randkey(&d, ciphertab[i].keysz);
912 r = ciphertab[i].counter(d.buf, d.len);
914 r->ops->misc(r, GRAND_SEEDBLOCK, iv.buf);
921 /* --- Mask generators --- */
923 static grand *gen_mgf(unsigned i)
929 static struct option opts[] = {
930 { "key", OPTF_ARGREQ, 0, 'k' },
931 { "hex", OPTF_ARGREQ, 0, 'H' },
932 { "index", OPTF_ARGREQ, 0, 'i' },
936 addopts("k:H:i:", opts);
945 textkey(&d, optarg, hashtab[i].keysz);
949 hexkey(&d, optarg, hashtab[i].keysz);
953 c = strtoul(optarg, &p, 0);
955 die(EXIT_FAILURE, "bad index `%s'", optarg);
963 randkey(&d, hashtab[i].keysz);
965 r = hashtab[i].mgf(d.buf, d.len);
967 r->ops->misc(r, GRAND_SEEDUINT32, c);
973 /* --- Fibonacci generator --- */
975 static grand *gen_fib(unsigned i)
982 static struct option opts[] = {
983 { "seed", OPTF_ARGREQ, 0, 's' },
995 s = strtoul(optarg, &p, 0);
997 die(EXIT_FAILURE, "bad integer `%s'", optarg);
1004 r = fibrand_create(s);
1006 r->ops->misc(r, GRAND_SEEDRAND, &rand_global);
1010 /* --- LC generator --- */
1012 static grand *gen_lc(unsigned i)
1018 static struct option opts[] = {
1019 { "seed", OPTF_ARGREQ, 0, 's' },
1023 addopts("s:", opts);
1031 s = strtoul(optarg, &p, 0);
1033 die(EXIT_FAILURE, "bad integer `%s'", optarg);
1042 s = rand_global.ops->range(&rand_global, LCRAND_P);
1043 while (s == LCRAND_FIXEDPT);
1045 return (lcrand_create(s));
1048 /* --- Basic options parser -- can't generate output --- */
1050 static grand *gen_opts(unsigned i)
1057 /*----- Generators table --------------------------------------------------*/
1059 gen generators[] = {
1060 { "fibonacci", gen_fib, 0,
1064 #define E(PRE, pre) \
1065 { #pre "-ofb", gen_ofb, CIPHER_##PRE, \
1066 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
1069 #define E(PRE, pre) \
1070 { #pre "-counter", gen_counter, CIPHER_##PRE, \
1071 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
1074 #define E(PRE, pre) \
1075 { #pre "-mgf", gen_mgf, HASH_##PRE, \
1076 "[-k KEY-PHRASE] [-H HEX-KEY] [-i INDEX]" },
1079 { "rc4", gen_rc4, 0,
1080 "[-k KEY-PHRASE] [-H HEX-KEY]" },
1081 { "seal", gen_seal, 0,
1082 "[-k KEY-PHRASE] [-H HEX-KEY] [-n SEQ]" },
1083 { "rand", gen_rand, 0,
1084 "[-n] [-k KEY-PHRASE] [-t TEXT-BLOCK] [-H HEX-BLOCK]" },
1085 { "bbs", gen_bbs, 0,
1086 "[-gS] [-s SEED] [-M MODULUS] [-b BITS] [-k KEYRING] [-i TAG] [-t TYPE]"
1091 static gen optsg = { "options", gen_opts, 0,
1092 "This message shouldn't be printed." };
1094 /*----- Random number generation ------------------------------------------*/
1096 static int genfile(const void *buf, size_t sz, void *p)
1099 if (fwrite(buf, 1, sz, fp) != sz)
1100 die(EXIT_FAILURE, "error writing to file: %s", strerror(errno));
1104 static int genbuf(const void *buf, size_t sz, void *p)
1107 memcpy(*pp, buf, sz);
1112 typedef struct genmaurer_ctx {
1117 static int genmaurer(const void *buf, size_t sz, void *p)
1119 genmaurer_ctx *g = p;
1122 for (i = 0; i < g->n; i++)
1123 maurer_test(&g->m[i], buf, sz);
1127 static int generate(grand *r, mp *outsz,
1128 int (*func)(const void *buf, size_t sz, void *p),
1131 static char kmg[] = { ' ', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 0 };
1133 unsigned percent = 0;
1134 mp *kb = MP_ZERO, *t = MP_NEW;
1137 static char baton[] = "-\\|/";
1142 /* --- Spit out random data --- */
1146 if (flags & f_progress) {
1147 char *errbuf = xmalloc(BUFSIZ);
1148 setvbuf(stderr, errbuf, _IOLBF, BUFSIZ);
1150 fprintf(stderr, "[%*s] 0%% 0\r[/\b", 50, "");
1152 fputs("[ ] 0\r[/\b", stderr);
1157 signal(SIGPIPE, SIG_IGN);
1160 while (!outsz || MP_CMP(kb, <, outsz)) {
1162 size_t sz = sizeof(buf), left;
1163 clock_t c_start, c_stop;
1165 /* --- Emit a bufferful (or less) of data --- */
1168 t = mp_sub(t, outsz, kb);
1169 assert(!MP_NEGP(t));
1170 if (MP_CMP(t, <=, MP_SIZET_MAX)) {
1171 left = mp_tosizet(t);
1172 if (sz > left) sz = left;
1176 r->ops->fill(r, buf, sz);
1178 clk += c_stop - c_start;
1179 if (func && (rc = func(buf, sz, p)) != 0)
1181 t = mp_fromsizet(t, sz);
1182 kb = mp_add(kb, kb, t);
1184 /* --- Update the display --- */
1186 if (flags & f_progress) {
1187 time_t now = time(0);
1194 if (difftime(now, last) > 1.0) {
1198 fputs(" ] ", stderr);
1201 t = mp_fromulong(t, 100);
1202 t = mp_mul(t, t, kb);
1203 mp_div(&t, 0, t, outsz);
1204 assert(!MP_NEGP(t) && MP_CMP(t, <, MP_UINT_MAX));
1206 if (pc > percent || percent > 100 || difftime(now, last) > 1.0) {
1210 for (; percent < (pc & ~1); percent += 2)
1213 for (; pc < 100; pc += 2)
1215 fprintf(stderr, "] %3i%% ", percent);
1222 t = mp_add(t, kb, MP_ZERO);
1223 while (mp_bits(t) >= 14) {
1224 t = mp_lsr(t, t, 10);
1228 mp_writedstr(t, &d, 10);
1229 fprintf(stderr, "%4s%c\r[", d.buf, *kk);
1232 for (pc = 0; pc < (percent & ~1); pc += 2)
1241 if (percent < 100) {
1242 putc(*bp++, stderr);
1251 if (flags & f_progress)
1252 fputc('\n', stderr);
1253 if (flags & f_timer) {
1255 dstr_puts(&d, "generated ");
1256 mp_writedstr(kb, &d, 10);
1257 dstr_puts(&d, " bytes ");
1259 dstr_puts(&d, "too quickly to measure\n");
1263 double sec = (double)clk/CLOCKS_PER_SEC;
1268 switch (MP_LEN(kb)) {
1269 case 0: out = 0; break;
1270 case 1: out = kb->v[0]; break;
1272 sh = mp_bits(kb) - MPW_BITS;
1273 t = mp_lsr(t, kb, sh);
1274 out = ldexp(t->v[0], sh);
1278 for (kk = kmg; bps > 1024 && kk[1]; kk++, bps /= 1024)
1280 dstr_putf(&d, "in %g secs (%g %cb/s)\n", sec, bps, *kk);
1281 fwrite(d.buf, 1, d.len, stderr);
1290 /*----- Main code ---------------------------------------------------------*/
1292 int main(int ac, char *av[])
1297 /* --- Initialize mLib --- */
1302 /* --- Set up the main Catacomb generator --- */
1304 rand_noisesrc(RAND_GLOBAL, &noise_source);
1305 rand_seed(RAND_GLOBAL, 160);
1307 /* --- Initialize the options table --- */
1309 addopts(sopts, opts);
1314 /* --- Read the generator out of the first argument --- */
1316 if (argc > 1 && *argv[1] != '-') {
1317 const char *arg = av[1];
1318 size_t sz = strlen(arg);
1322 for (gg = generators; gg->name; gg++) {
1323 if (strncmp(arg, gg->name, sz) == 0) {
1324 if (gg->name[sz] == 0) {
1328 die(EXIT_FAILURE, "ambiguous generator name `%s'", arg);
1334 die(EXIT_FAILURE, "unknown generator name `%s'", arg);
1339 /* --- Get a generic random number generator --- */
1342 if (!r || optind != ac - 1) {
1347 /* --- Do the FIPS test --- */
1349 if (flags & f_fips) {
1350 octet buf[FIPSTEST_BUFSZ];
1355 t = mp_fromsizet(MP_NEW, sizeof(buf));
1356 generate(r, t, genbuf, &p);
1359 if (rc & FIPSTEST_MONOBIT)
1360 moan("failed monobit test");
1361 if (rc & FIPSTEST_POKER)
1362 moan("failed poker test");
1363 if (rc & FIPSTEST_RUNS)
1364 moan("failed runs test");
1365 if (rc & FIPSTEST_LONGRUNS)
1366 moan("failed long runs test");
1367 if (!rc && (flags & f_progress))
1368 fputs("test passed\n", stderr);
1369 return (rc ? EXIT_FAILURE : 0);
1372 /* --- Do Maurer's test --- */
1374 if (flags & f_maurer) {
1381 static struct { double x; const char *sig; } sigtab[] = {
1389 g.n = maurer_hi - maurer_lo + 1;
1390 g.m = xmalloc(g.n * sizeof(maurer_ctx));
1391 for (i = 0; i < g.n; i++)
1392 maurer_init(&g.m[i], i + maurer_lo);
1393 bufsz = (100 * maurer_hi) << maurer_hi;
1395 t = mp_fromsizet(MP_NEW, bufsz);
1396 generate(r, t, genmaurer, &g);
1399 for (i = maurer_lo; i <= maurer_hi; i++) {
1400 double z = maurer_done(&g.m[i - maurer_lo]);
1401 double zz = fabs(z);
1404 for (j = 0; sigtab[j].sig; j++) {
1405 if (zz > sigtab[j].x) {
1407 moan("failed, bits = %u, sig = %s, Z_u = %g",
1408 i, sigtab[j].sig, z);
1412 if (flags & f_progress)
1413 fprintf(stderr, "bits = %u, Z_u = %g\n", i, z);
1420 /* --- Discard --- */
1422 if (flags & f_discard) {
1423 generate(r, outsz, 0, 0);
1427 /* --- Write to a file --- */
1430 if (!(flags & f_file) && isatty(STDOUT_FILENO))
1431 die(EXIT_FAILURE, "writing output to a terminal is a bad idea");
1434 generate(r, outsz, genfile, outfp);
1442 /*----- That's all, folks -------------------------------------------------*/