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>
74 #include "salsa20-core.h"
82 #include "skipjack-ofb.h"
85 #include "blowfish-ofb.h"
86 #include "twofish-ofb.h"
88 #include "cast128-ofb.h"
89 #include "cast256-ofb.h"
90 #include "noekeon-ofb.h"
91 #include "rijndael-ofb.h"
92 #include "rijndael192-ofb.h"
93 #include "rijndael256-ofb.h"
94 #include "safer-ofb.h"
95 #include "safersk-ofb.h"
96 #include "square-ofb.h"
97 #include "serpent-ofb.h"
99 #include "des-counter.h"
100 #include "des3-counter.h"
101 #include "rc2-counter.h"
102 #include "rc5-counter.h"
103 #include "mars-counter.h"
104 #include "skipjack-counter.h"
105 #include "tea-counter.h"
106 #include "xtea-counter.h"
107 #include "blowfish-counter.h"
108 #include "twofish-counter.h"
109 #include "idea-counter.h"
110 #include "cast128-counter.h"
111 #include "cast256-counter.h"
112 #include "noekeon-counter.h"
113 #include "rijndael-counter.h"
114 #include "rijndael192-counter.h"
115 #include "rijndael256-counter.h"
116 #include "safer-counter.h"
117 #include "safersk-counter.h"
118 #include "square-counter.h"
119 #include "serpent-counter.h"
125 #include "tiger-mgf.h"
126 #include "rmd128-mgf.h"
127 #include "rmd160-mgf.h"
128 #include "rmd256-mgf.h"
129 #include "rmd320-mgf.h"
133 /*----- Data structures ---------------------------------------------------*/
137 grand *(*seed)(unsigned /*i*/);
142 extern gen generators[];
150 E(SKIPJACK, skipjack) \
153 E(BLOWFISH, blowfish) \
154 E(TWOFISH, twofish) \
156 E(CAST128, cast128) \
157 E(CAST256, cast256) \
160 E(SAFERSK, safersk) \
161 E(NOEKEON, noekeon) \
162 E(RIJNDAEL, rijndael) \
163 E(RIJNDAEL192, rijndael192) \
164 E(RIJNDAEL256, rijndael256) \
178 #define E(PRE, pre) CIPHER_##PRE,
179 enum { CIPHERS CIPHER__bogus };
182 #define E(PRE, pre) HASH_##PRE,
183 enum { HASHES HASH__bogus };
186 static const struct {
189 grand *(*ofb)(const void */*k*/, size_t /*sz*/);
190 grand *(*counter)(const void */*k*/, size_t /*sz*/);
192 #define E(PRE, pre) \
193 { pre##_keysz, PRE##_BLKSZ, pre##_ofbrand, pre##_counterrand },
198 static const struct {
201 grand *(*mgf)(const void */*k*/, size_t /*sz*/);
203 #define E(PRE, pre) \
204 { &pre, pre##_mgfkeysz, pre##_mgfrand },
210 E(salsa20, 20,, SALSA20) \
211 E(salsa20, 12,, SALSA20) \
212 E(salsa20, 8,, SALSA20) \
213 E(xsalsa20, 20, X, SALSA20) \
214 E(xsalsa20, 12, X, SALSA20) \
215 E(xsalsa20, 8, X, SALSA20) \
216 E(chacha, 20,, CHACHA) \
217 E(chacha, 12,, CHACHA) \
218 E(chacha, 8,, CHACHA) \
219 E(xchacha, 20, X, CHACHA) \
220 E(xchacha, 12, X, CHACHA) \
221 E(xchacha, 8, X, CHACHA)
223 #define E(pre, r, x, BASE) pre##_##r##_INDEX,
224 enum { SALSAE BOGUS_SALSA };
227 #define SALSA20_GEN(pre, r) SALSA20_DECOR(pre, r, _rand)
228 #define CHACHA_GEN(pre, r) pre##r##_rand
230 #define SALSA20_NAME(r) SALSA20_NAME_##r
231 #define XSALSA20_NAME(r) "x" SALSA20_NAME_##r
232 #define CHACHA_NAME(r) "chacha" #r
233 #define XCHACHA_NAME(r) "xchacha" #r
235 static const struct {
237 grand *(*gen)(const void *, size_t, const void *);
239 #define E(pre, r, x, BASE) { x##BASE##_NONCESZ, BASE##_GEN(pre, r) },
244 /*----- Miscellaneous static data -----------------------------------------*/
247 static mp *outsz = 0;
248 static unsigned maurer_lo = 5, maurer_hi = 8;
253 static unsigned flags = 0;
255 #define f_progress 1u
260 #define f_discard 32u
262 /*----- Help options ------------------------------------------------------*/
264 static void usage(FILE *fp)
266 pquis(fp, "Usage: $ generator [options]\n");
269 static void version(FILE *fp)
271 pquis(fp, "$, Catacomb version " VERSION "\n");
274 static void help(FILE *fp)
280 Emits a stream of random bytes suitable for, well, all sorts of things.\n\
281 The primary objective is to be able to generate streams of input for\n\
282 statistical tests, such as Diehard.\n\
284 Options are specific to the particular generator, although there's a\n\
287 -h, --help Display this help message.\n\
288 -v, --version Display the program's version number.\n\
289 -u, --usage Display a useless usage message.\n\
291 -l, --list Show a list of the supported generators, with\n\
293 -f, --fipstest Run the FIPS 140-1 randomness test.\n\
294 -m, --maurer[=LO-HI] Run Maurer's universal statistical test.\n\
295 -o, --output FILE Write output to FILE, not stdout.\n\
296 -z, --size SIZE Emit SIZE bytes, not an unlimited number.\n\
297 -p, --progress Show a little progress meter (on stderr).\n\
298 -T, --timer Keep track of the CPU time used by the generator.\n\
299 -d, --discard Discard the generated output.\n\
301 (A SIZE may be followed by `g' for gigabytes, `m' for megabytes, or\n\
302 `k' for kilobytes. If unqualified, an amount in bytes is assumed.)\n\
306 /*----- Main options parser -----------------------------------------------*/
308 static struct option opts[] = {
310 /* --- Standard GNU help options --- */
312 { "help", 0, 0, 'h' },
313 { "version", 0, 0, 'v' },
314 { "usage", 0, 0, 'u' },
316 /* --- Other useful things --- */
318 { "list", 0, 0, 'l' },
319 { "fipstest", 0, 0, 'f' },
320 { "maurer", OPTF_ARGOPT, 0, 'm' },
321 { "output", OPTF_ARGREQ, 0, 'o' },
322 { "size", OPTF_ARGREQ, 0, 'z' },
323 { "progress", 0, 0, 'p' },
324 { "timer", 0, 0, 'T' },
325 { "discard", 0, 0, 'd' },
327 /* --- End of main table --- */
332 static const char *sopts = "hvu lfm::o:z:pTd";
335 DA_DECL(option_v, struct option);
339 static option_v optv = DA_INIT;
340 static dstr optd = DSTR_INIT;
342 /* --- @addopts@ --- *
344 * Arguments: @const char *s@ = pointer to short options
345 * @struct option *l@ = pointer to long options
349 * Use: Adds a collection of options to the table.
352 static void addopts(const char *s, struct option *l)
358 DA_PUSH(&optv, *l++);
366 * Returns: Next option from argument array.
368 * Use: Fetches options, handling the standard ones.
374 int i = mdwopt(argc, argv, optd.buf, DA(&optv), 0, 0, 0);
387 puts("Generators supported:");
388 for (g = generators; g->name; g++)
389 printf(" %s %s\n", g->name, g->help);
399 unsigned long lo, hi;
400 lo = strtoul(optarg, &p, 0);
401 if (*p == '-' || *p == ',')
402 hi = strtoul(p + 1, &p, 0);
405 if (*p != 0 || hi < lo || lo == 0)
406 die(EXIT_FAILURE, "bad bit range `%s'", optarg);
413 die(EXIT_FAILURE, "already set an output file");
414 if (strcmp(optarg, "-") == 0)
417 outfp = fopen(optarg, "w");
419 die(EXIT_FAILURE, "couldn't open output file `%s': %s",
420 optarg, strerror(errno));
427 outsz = mp_readstring(outsz, optarg, &p, 0);
428 if (!outsz || MP_NEGP(outsz))
429 die(EXIT_FAILURE, "bad number `%s'", optarg);
431 case 'G': case 'g': outsz = mp_lsl(outsz, outsz, 10);
432 case 'M': case 'm': outsz = mp_lsl(outsz, outsz, 10);
433 case 'K': case 'k': outsz = mp_lsl(outsz, outsz, 10);
437 die(EXIT_FAILURE, "bad suffix `%s'", p);
441 die(EXIT_FAILURE, "bad suffix `%s'", p);
458 /*----- Manglers for seed strings -----------------------------------------*/
462 * Arguments: @const char *p@ = pointer to input string
463 * @char **end@ = where the end goes
464 * @dstr *d@ = output buffer
468 * Use: Transforms a hex string into a chunk of binary data.
471 static void unhex(const char *p, char **end, dstr *d)
473 while (p[0] && p[1]) {
474 int x = p[0], y = p[1];
475 if ('0' <= x && x <= '9') x -= '0';
476 else if ('A' <= x && x <= 'F') x -= 'A' - 10;
477 else if ('a' <= x && x <= 'f') x -= 'a' - 10;
479 if ('0' <= y && y <= '9') y -= '0';
480 else if ('A' <= y && y <= 'F') y -= 'A' - 10;
481 else if ('a' <= y && y <= 'f') y -= 'a' - 10;
483 DPUTC(d, (x << 4) + y);
489 /* --- Generate a key --- */
491 static void textkey(dstr *d, const char *p, const octet *ksz)
493 size_t sz = strlen(p);
496 die(EXIT_FAILURE, "zero-length key string");
497 if (keysz(sz, ksz) != sz)
501 rmd160_mgfinit(&g, p, sz);
504 rmd160_mgfencrypt(&g, 0, d->buf, sz);
507 assert(((void)"I can't seem to choose a good key size",
508 keysz(d->len, ksz) == d->len));
511 static void hexkey(dstr *d, const char *p, const octet *ksz)
514 unhex(optarg, &q, d);
516 die(EXIT_FAILURE, "bad hex key `%s'", p);
517 if (keysz(d->len, ksz) != d->len)
518 die(EXIT_FAILURE, "bad key length");
521 static void randkey(dstr *d, const octet *ksz)
523 size_t sz = keysz(0, ksz);
525 rand_get(RAND_GLOBAL, d->buf, sz);
529 /*----- Generators --------------------------------------------------------*/
531 /* --- Blum-Blum-Shub strong generator --- */
533 static grand *gen_bbs(unsigned i)
535 /* --- Default modulus --- *
537 * The factors of this number are
539 * @p = 1229936431484295969649886203367009966370895964206162032259292413@
540 * @7754313537966036459299022912838407755462506416274551744201653277@
541 * @313130311731673973886822067@
543 * @q = 9798171783943489959487301695884963889684294764514008432498259742@
544 * @5374320073594018817245784145742769603334292182227671519041431067@
545 * @61344781426317516045890159@
547 * Both %$p$% and %$q$% are prime; %$(p - 1)/2$% and %$(q - 1)/2$% have no
548 * common factors. They were found using this program, with random
551 * I hope that, by publishing these factors, I'll dissuade people from
552 * actually using this modulus in an attempt to attain real security. The
553 * program is quite quick at finding Blum numbers, so there's no excuse for
554 * not generating your own.
558 "12051128439013574251357214209433471144307319411973256935382082"
559 "84356405274180923922403660880355098909699130818163691602989614"
560 "90135716255689660470370755013177656905237112577648090277537209"
561 "93607817155427455344810369808478266925293635284364998010510985"
562 "0503830397166360721262431179505917248447259735253684659338653";
564 /* --- Other things --- */
568 unsigned bits = 1024;
571 const char *kfile = 0, *id = 0, *ktype = 0;
573 /* --- Parse options --- */
575 static struct option opts[] = {
576 { "modulus", OPTF_ARGREQ, 0, 'M' },
577 { "generate", 0, 0, 'g' },
578 { "seed", OPTF_ARGREQ, 0, 's' },
579 { "bits", OPTF_ARGREQ, 0, 'b' },
580 { "show", 0, 0, 'S' },
581 { "keyring", OPTF_ARGREQ, 0, 'k' },
582 { "id", OPTF_ARGREQ, 0, 'i' },
583 { "type", OPTF_ARGREQ, 0, 't' },
587 addopts("M:gs:b:Sk:i:t:", opts);
604 bits = strtoul(optarg, 0, 0);
606 die(EXIT_FAILURE, "bad number of bits `%s'", optarg);
628 /* --- Generate a modulus if one is requested --- */
632 m = mp_readstring(MP_NEW, mt, &p, 0);
633 if (!m || *p || (m->v[0] & 3) != 1)
634 die(EXIT_FAILURE, "bad modulus `%s'", mt);
635 /* Unfortunately I don't know how to test for a Blum integer */
636 } else if (kfile || id || ktype) {
641 /* --- Open the key file --- */
645 if (key_open(&kf, kfile, KOPEN_READ, key_moan, 0)) {
646 die(EXIT_FAILURE, "error opening key file `%s': %s",
647 kfile, strerror(errno));
650 /* --- Find the key --- */
653 if ((kk = key_bytag(&kf, id)) == 0)
654 die(EXIT_FAILURE, "key `%s' not found", id);
658 if ((kk = key_bytype(&kf, ktype)) == 0)
659 die(EXIT_FAILURE, "no suitable key with type `%s' found", ktype);
662 /* --- Read the key data --- */
664 if ((kk->k->e & KF_ENCMASK) != KENC_STRUCT)
665 die(EXIT_FAILURE, "key is not structured");
666 if ((kd = key_structfind(kk->k, "n")) == 0)
667 die(EXIT_FAILURE, "key has no subkey `n'");
668 if ((kd->e & KF_ENCMASK) != KENC_MP)
669 die(EXIT_FAILURE, "incompatible subkey encoding");
670 m = MP_COPY(kd->u.m);
675 if (bbs_gen(&bp, bits, &rand_global, 0,
676 (flags & f_progress) ? pgen_ev : 0, 0))
677 die(EXIT_FAILURE, "modulus generation failed");
681 fputs("p = ", stderr);
682 mp_writefile(bp.p, stderr, 10);
683 fputs("\nq = ", stderr);
684 mp_writefile(bp.q, stderr, 10);
685 fputs("\nn = ", stderr);
686 mp_writefile(bp.n, stderr, 10);
694 /* --- Set up a seed --- */
697 x = mprand(MP_NEW, mp_bits(m) - 1, &rand_global, 1);
700 x = mp_readstring(MP_NEW, xt, &p, 0);
702 die(EXIT_FAILURE, "bad modulus `%s'", xt);
714 /* --- Catacomb's random number generator --- */
716 static grand *gen_rand(unsigned i)
718 grand *r = rand_create();
721 static struct option opts[] = {
722 { "key", OPTF_ARGREQ, 0, 'k' },
723 { "text", OPTF_ARGREQ, 0, 't' },
724 { "hex", OPTF_ARGREQ, 0, 'H' },
728 addopts("k:t:H:n", opts);
730 r->ops->misc(r, RAND_NOISESRC, &noise_source);
731 r->ops->misc(r, RAND_SEED, 160);
740 textkey(&d, optarg, rmd160_hmackeysz);
741 r->ops->misc(r, RAND_KEY, d.buf, d.len);
744 r->ops->misc(r, GRAND_SEEDBLOCK, optarg, strlen(optarg));
748 hexkey(&d, optarg, rmd160_hmackeysz);
749 r->ops->misc(r, GRAND_SEEDBLOCK, d.buf, d.len);
758 /* --- RC4 output --- */
760 static grand *gen_rc4(unsigned i)
765 static struct option opts[] = {
766 { "key", OPTF_ARGREQ, 0, 'k' },
767 { "hex", OPTF_ARGREQ, 0, 'H' },
771 addopts("k:H:", opts);
780 textkey(&d, optarg, rc4_keysz);
784 hexkey(&d, optarg, rc4_keysz);
792 randkey(&d, rc4_keysz);
793 r = rc4_rand(d.buf, d.len);
798 /* --- SEAL output --- */
800 static grand *gen_seal(unsigned i)
806 static struct option opts[] = {
807 { "key", OPTF_ARGREQ, 0, 'k' },
808 { "hex", OPTF_ARGREQ, 0, 'H' },
809 { "sequence", OPTF_ARGREQ, 0, 'n' },
813 addopts("k:H:n:", opts);
822 textkey(&d, optarg, seal_keysz);
826 hexkey(&d, optarg, seal_keysz);
830 n = strtoul(optarg, &p, 0);
832 die(EXIT_FAILURE, "bad number `%s'", optarg);
840 randkey(&d, seal_keysz);
841 r = seal_rand(d.buf, d.len, n);
846 /* --- Salsa20, XSalsa20, ChaCha, and XChaCha --- */
848 static grand *gen_salsae(unsigned i)
854 kludge64 pos = { 0 };
858 static struct option opts[] = {
859 { "key", OPTF_ARGREQ, 0, 'k' },
860 { "hex", OPTF_ARGREQ, 0, 'H' },
861 { "nonce", OPTF_ARGREQ, 0, 'n' },
862 { "seek", OPTF_ARGREQ, 0, 's' },
866 addopts("k:H:n:s:", opts);
875 textkey(&d, optarg, salsa20_keysz);
879 hexkey(&d, optarg, salsa20_keysz);
883 unhex(optarg, &p, &n);
885 die(EXIT_FAILURE, "bad hex IV `%s'", optarg);
886 if (n.len != salsatab[i].noncesz) {
887 die(EXIT_FAILURE, "bad nonce length %lu (must be %lu)",
888 (unsigned long)n.len, (unsigned long)salsatab[i].noncesz);
892 x = mp_readstring(MP_NEW, optarg, &p, 0);
893 if (*p || MP_NEGP(x) || mp_bits(x) > 64)
894 die(EXIT_FAILURE, "bad position `%s'", optarg);
895 mp_storeb(x, posbuf, sizeof(posbuf));
897 LOAD64_(pos, posbuf);
905 randkey(&d, salsa20_keysz);
906 r = salsatab[i].gen(d.buf, d.len, n.len ? n.buf : 0);
907 r->ops->misc(r, SALSA20_SEEKU64, pos);
915 /* --- Output feedback generators --- */
917 static grand *gen_ofb(unsigned i)
923 static struct option opts[] = {
924 { "key", OPTF_ARGREQ, 0, 'k' },
925 { "hex", OPTF_ARGREQ, 0, 'H' },
926 { "iv", OPTF_ARGREQ, 0, 'i' },
930 addopts("k:H:i:", opts);
939 textkey(&d, optarg, ciphertab[i].keysz);
943 hexkey(&d, optarg, ciphertab[i].keysz);
948 unhex(optarg, &p, &iv);
950 die(EXIT_FAILURE, "bad hex IV `%s'", optarg);
951 if (iv.len != ciphertab[i].blksz) {
952 die(EXIT_FAILURE, "bad IV length %lu (must be %lu)",
953 (unsigned long)iv.len, (unsigned long)ciphertab[i].blksz);
962 randkey(&d, ciphertab[i].keysz);
963 r = ciphertab[i].ofb(d.buf, d.len);
965 r->ops->misc(r, GRAND_SEEDBLOCK, iv.buf);
972 /* --- Counter generators --- */
974 static grand *gen_counter(unsigned i)
980 static struct option opts[] = {
981 { "key", OPTF_ARGREQ, 0, 'k' },
982 { "hex", OPTF_ARGREQ, 0, 'H' },
983 { "iv", OPTF_ARGREQ, 0, 'i' },
987 addopts("k:H:i:", opts);
996 textkey(&d, optarg, ciphertab[i].keysz);
1000 hexkey(&d, optarg, ciphertab[i].keysz);
1005 unhex(optarg, &p, &iv);
1007 die(EXIT_FAILURE, "bad hex IV `%s'", optarg);
1008 if (iv.len != ciphertab[i].blksz) {
1009 die(EXIT_FAILURE, "bad IV length %lu (must be %lu)",
1010 (unsigned long)iv.len, (unsigned long)ciphertab[i].blksz);
1019 randkey(&d, ciphertab[i].keysz);
1020 r = ciphertab[i].counter(d.buf, d.len);
1022 r->ops->misc(r, GRAND_SEEDBLOCK, iv.buf);
1029 /* --- Mask generators --- */
1031 static grand *gen_mgf(unsigned i)
1037 static struct option opts[] = {
1038 { "key", OPTF_ARGREQ, 0, 'k' },
1039 { "hex", OPTF_ARGREQ, 0, 'H' },
1040 { "index", OPTF_ARGREQ, 0, 'i' },
1044 addopts("k:H:i:", opts);
1053 textkey(&d, optarg, hashtab[i].keysz);
1057 hexkey(&d, optarg, hashtab[i].keysz);
1061 c = strtoul(optarg, &p, 0);
1063 die(EXIT_FAILURE, "bad index `%s'", optarg);
1071 randkey(&d, hashtab[i].keysz);
1073 r = hashtab[i].mgf(d.buf, d.len);
1075 r->ops->misc(r, GRAND_SEEDUINT32, c);
1081 /* --- Fibonacci generator --- */
1083 static grand *gen_fib(unsigned i)
1090 static struct option opts[] = {
1091 { "seed", OPTF_ARGREQ, 0, 's' },
1095 addopts("s:", opts);
1103 s = strtoul(optarg, &p, 0);
1105 die(EXIT_FAILURE, "bad integer `%s'", optarg);
1112 r = fibrand_create(s);
1114 r->ops->misc(r, GRAND_SEEDRAND, &rand_global);
1118 /* --- LC generator --- */
1120 static grand *gen_lc(unsigned i)
1126 static struct option opts[] = {
1127 { "seed", OPTF_ARGREQ, 0, 's' },
1131 addopts("s:", opts);
1139 s = strtoul(optarg, &p, 0);
1141 die(EXIT_FAILURE, "bad integer `%s'", optarg);
1150 s = rand_global.ops->range(&rand_global, LCRAND_P);
1151 while (s == LCRAND_FIXEDPT);
1153 return (lcrand_create(s));
1156 /* --- Basic options parser -- can't generate output --- */
1158 static grand *gen_opts(unsigned i)
1165 /*----- Generators table --------------------------------------------------*/
1167 gen generators[] = {
1168 { "fibonacci", gen_fib, 0,
1172 #define E(PRE, pre) \
1173 { #pre "-ofb", gen_ofb, CIPHER_##PRE, \
1174 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
1177 #define E(PRE, pre) \
1178 { #pre "-counter", gen_counter, CIPHER_##PRE, \
1179 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
1182 #define E(PRE, pre) \
1183 { #pre "-mgf", gen_mgf, HASH_##PRE, \
1184 "[-k KEY-PHRASE] [-H HEX-KEY] [-i INDEX]" },
1187 #define E(pre, r, x, BASE) \
1188 { x##BASE##_NAME(r), gen_salsae, pre##_##r##_INDEX, \
1189 "[-k KEY-PHRASE] [-H HEX-KEY] [-n NONCE]" },
1192 { "rc4", gen_rc4, 0,
1193 "[-k KEY-PHRASE] [-H HEX-KEY]" },
1194 { "seal", gen_seal, 0,
1195 "[-k KEY-PHRASE] [-H HEX-KEY] [-n SEQ]" },
1196 { "rand", gen_rand, 0,
1197 "[-n] [-k KEY-PHRASE] [-t TEXT-BLOCK] [-H HEX-BLOCK]" },
1198 { "bbs", gen_bbs, 0,
1199 "[-gS] [-s SEED] [-M MODULUS] [-b BITS] [-k KEYRING] [-i TAG] [-t TYPE]"
1204 static gen optsg = { "options", gen_opts, 0,
1205 "This message shouldn't be printed." };
1207 /*----- Random number generation ------------------------------------------*/
1209 static int genfile(const void *buf, size_t sz, void *p)
1212 if (fwrite(buf, 1, sz, fp) != sz)
1213 die(EXIT_FAILURE, "error writing to file: %s", strerror(errno));
1217 static int genbuf(const void *buf, size_t sz, void *p)
1220 memcpy(*pp, buf, sz);
1225 typedef struct genmaurer_ctx {
1230 static int genmaurer(const void *buf, size_t sz, void *p)
1232 genmaurer_ctx *g = p;
1235 for (i = 0; i < g->n; i++)
1236 maurer_test(&g->m[i], buf, sz);
1240 static double doubletime(void)
1243 static time_t start = (time_t)-1;
1244 time_t now = time(0);
1246 if (start == (time_t)-1) start = now;
1247 return difftime(now, start);
1251 gettimeofday(&tv, 0);
1252 return (tv.tv_sec + tv.tv_usec/1000000.0);
1256 static int generate(grand *r, mp *outsz,
1257 int (*func)(const void *buf, size_t sz, void *p),
1260 static char kmg[] = { ' ', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 0 };
1262 unsigned percent = 0;
1263 mp *kb = MP_ZERO, *t = MP_NEW;
1266 static char baton[] = "-\\|/";
1271 /* --- Spit out random data --- */
1273 last = doubletime();
1275 if (flags & f_progress) {
1276 char *errbuf = xmalloc(BUFSIZ);
1277 setvbuf(stderr, errbuf, _IOLBF, BUFSIZ);
1279 fprintf(stderr, "[%*s] 0%% 0\r[/\b", 50, "");
1281 fputs("[ ] 0\r[/\b", stderr);
1286 signal(SIGPIPE, SIG_IGN);
1289 while (!outsz || MP_CMP(kb, <, outsz)) {
1291 size_t sz = sizeof(buf), left;
1292 clock_t c_start, c_stop;
1294 /* --- Emit a bufferful (or less) of data --- */
1297 t = mp_sub(t, outsz, kb);
1298 assert(!MP_NEGP(t));
1299 if (MP_CMP(t, <=, MP_SIZET_MAX)) {
1300 left = mp_tosizet(t);
1301 if (sz > left) sz = left;
1305 r->ops->fill(r, buf, sz);
1307 clk += c_stop - c_start;
1308 if (func && (rc = func(buf, sz, p)) != 0)
1310 t = mp_fromsizet(t, sz);
1311 kb = mp_add(kb, kb, t);
1313 /* --- Update the display --- */
1315 if (flags & f_progress) {
1324 if (now - last > 0.1) {
1328 fputs(" ] ", stderr);
1331 t = mp_fromulong(t, 100);
1332 t = mp_mul(t, t, kb);
1333 mp_div(&t, 0, t, outsz);
1334 assert(!MP_NEGP(t) && MP_CMP(t, <, MP_UINT_MAX));
1336 if (pc > percent || percent > 100 || now - last > 0.1) {
1340 for (; percent < (pc & ~1); percent += 2)
1343 for (; pc < 100; pc += 2)
1345 fprintf(stderr, "] %3i%% ", percent);
1352 t = mp_add(t, kb, MP_ZERO);
1353 while (mp_bits(t) >= 14) {
1354 t = mp_lsr(t, t, 10);
1358 mp_writedstr(t, &d, 10);
1359 fprintf(stderr, "%4s%c\r[", d.buf, *kk);
1362 for (pc = 0; pc < (percent & ~1); pc += 2)
1371 if (percent < 100 && up) {
1372 putc(*bp++, stderr);
1381 if (flags & f_progress)
1382 fputc('\n', stderr);
1383 if (flags & f_timer) {
1385 dstr_puts(&d, "generated ");
1386 mp_writedstr(kb, &d, 10);
1387 dstr_puts(&d, " bytes ");
1389 dstr_puts(&d, "too quickly to measure\n");
1393 double sec = (double)clk/CLOCKS_PER_SEC;
1398 switch (MP_LEN(kb)) {
1399 case 0: out = 0; break;
1400 case 1: out = kb->v[0]; break;
1402 sh = mp_bits(kb) - MPW_BITS;
1403 t = mp_lsr(t, kb, sh);
1404 out = ldexp(t->v[0], sh);
1408 for (kk = kmg; bps > 1024 && kk[1]; kk++, bps /= 1024)
1410 dstr_putf(&d, "in %g secs (%g %cb/s)\n", sec, bps, *kk);
1411 fwrite(d.buf, 1, d.len, stderr);
1420 /*----- Main code ---------------------------------------------------------*/
1422 int main(int ac, char *av[])
1427 /* --- Initialize mLib --- */
1432 /* --- Set up the main Catacomb generator --- */
1434 rand_noisesrc(RAND_GLOBAL, &noise_source);
1435 rand_seed(RAND_GLOBAL, 160);
1437 /* --- Initialize the options table --- */
1439 addopts(sopts, opts);
1444 /* --- Read the generator out of the first argument --- */
1446 if (argc > 1 && *argv[1] != '-') {
1447 const char *arg = av[1];
1448 size_t sz = strlen(arg);
1452 for (gg = generators; gg->name; gg++) {
1453 if (strncmp(arg, gg->name, sz) == 0) {
1454 if (gg->name[sz] == 0) {
1458 die(EXIT_FAILURE, "ambiguous generator name `%s'", arg);
1464 die(EXIT_FAILURE, "unknown generator name `%s'", arg);
1469 /* --- Get a generic random number generator --- */
1472 if (!r || optind != ac - 1) {
1477 /* --- Do the FIPS test --- */
1479 if (flags & f_fips) {
1480 octet buf[FIPSTEST_BUFSZ];
1485 t = mp_fromsizet(MP_NEW, sizeof(buf));
1486 generate(r, t, genbuf, &p);
1489 if (rc & FIPSTEST_MONOBIT)
1490 moan("failed monobit test");
1491 if (rc & FIPSTEST_POKER)
1492 moan("failed poker test");
1493 if (rc & FIPSTEST_RUNS)
1494 moan("failed runs test");
1495 if (rc & FIPSTEST_LONGRUNS)
1496 moan("failed long runs test");
1497 if (!rc && (flags & f_progress))
1498 fputs("test passed\n", stderr);
1499 return (rc ? EXIT_FAILURE : 0);
1502 /* --- Do Maurer's test --- */
1504 if (flags & f_maurer) {
1511 static struct { double x; const char *sig; } sigtab[] = {
1519 g.n = maurer_hi - maurer_lo + 1;
1520 g.m = xmalloc(g.n * sizeof(maurer_ctx));
1521 for (i = 0; i < g.n; i++)
1522 maurer_init(&g.m[i], i + maurer_lo);
1523 bufsz = (100 * maurer_hi) << maurer_hi;
1525 t = mp_fromsizet(MP_NEW, bufsz);
1526 generate(r, t, genmaurer, &g);
1529 for (i = maurer_lo; i <= maurer_hi; i++) {
1530 double z = maurer_done(&g.m[i - maurer_lo]);
1531 double zz = fabs(z);
1534 for (j = 0; sigtab[j].sig; j++) {
1535 if (zz > sigtab[j].x) {
1537 moan("failed, bits = %u, sig = %s, Z_u = %g",
1538 i, sigtab[j].sig, z);
1542 if (flags & f_progress)
1543 fprintf(stderr, "bits = %u, Z_u = %g\n", i, z);
1550 /* --- Discard --- */
1552 if (flags & f_discard) {
1553 generate(r, outsz, 0, 0);
1557 /* --- Write to a file --- */
1560 if (!(flags & f_file) && isatty(STDOUT_FILENO))
1561 die(EXIT_FAILURE, "writing output to a terminal is a bad idea");
1564 generate(r, outsz, genfile, outfp);
1572 /*----- That's all, folks -------------------------------------------------*/