3 * $Id: rspit.c,v 1.13 2000/12/06 20:33:27 mdw Exp $
5 * Spit out random numbers
7 * (c) 1999 Straylight/Edgeware
10 /*----- Licensing notice --------------------------------------------------*
12 * This file is part of Catacomb.
14 * Catacomb is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Library General Public License as
16 * published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
19 * Catacomb is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
24 * You should have received a copy of the GNU Library General Public
25 * License along with Catacomb; if not, write to the Free
26 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
30 /*----- Revision history --------------------------------------------------*
33 * Revision 1.13 2000/12/06 20:33:27 mdw
34 * Make flags be macros rather than enumerations, to ensure that they're
37 * Revision 1.12 2000/10/08 15:49:18 mdw
38 * Remove failed kludge for shutting up a warning.
40 * Revision 1.11 2000/10/08 12:10:32 mdw
41 * Make table have external linkage to bodge around deficiency in C. The
42 * problem is that @static gen generators[];@ is considered to be a
43 * `tentative definition', and therefore mustn't have incomplete type,
44 * which it obviously has.
46 * Revision 1.10 2000/08/11 21:34:59 mdw
47 * New restartable interface to Maurer testing.
49 * Revision 1.9 2000/08/04 23:24:15 mdw
50 * Add a timer and a discard option.
52 * Revision 1.8 2000/07/29 22:05:47 mdw
53 * Fix error in help message about Maurer test syntax.
55 * Revision 1.7 2000/07/18 23:01:26 mdw
56 * Improve progress indications, and allow user to choose chunk sizes for
59 * Revision 1.6 2000/07/15 20:53:35 mdw
60 * Add a load of new ciphers and hashes.
62 * Revision 1.5 2000/07/01 11:27:03 mdw
63 * Portability fix: don't assume that `stdout' is a constant expression.
64 * Remove old type name `bbs_param'.
66 * Revision 1.4 2000/06/17 12:08:28 mdw
67 * Restructure handling of cipher-based generators. Add counter-mode
68 * ciphers and MGF-1 hash functions. Add FIPS 140-1 and Maurer's tests.
70 * Revision 1.3 2000/02/12 18:21:03 mdw
71 * Overhaul of key management (again).
73 * Revision 1.2 1999/12/22 15:59:51 mdw
74 * New prime-search system. Read BBS keys from key files.
76 * Revision 1.1 1999/12/10 23:29:13 mdw
77 * Emit random numbers for statistical tests.
81 /*----- Header files ------------------------------------------------------*/
98 #include <mLib/darray.h>
99 #include <mLib/dstr.h>
100 #include <mLib/mdwopt.h>
101 #include <mLib/quis.h>
102 #include <mLib/report.h>
103 #include <mLib/sub.h>
105 #include "fipstest.h"
122 #include "des3-ofb.h"
125 #include "skipjack-ofb.h"
127 #include "xtea-ofb.h"
128 #include "blowfish-ofb.h"
129 #include "twofish-ofb.h"
130 #include "idea-ofb.h"
131 #include "cast128-ofb.h"
132 #include "cast256-ofb.h"
133 #include "rijndael-ofb.h"
134 #include "square-ofb.h"
135 #include "serpent-ofb.h"
137 #include "des-counter.h"
138 #include "des3-counter.h"
139 #include "rc2-counter.h"
140 #include "rc5-counter.h"
141 #include "skipjack-counter.h"
142 #include "tea-counter.h"
143 #include "xtea-counter.h"
144 #include "blowfish-counter.h"
145 #include "twofish-counter.h"
146 #include "idea-counter.h"
147 #include "cast128-counter.h"
148 #include "cast256-counter.h"
149 #include "rijndael-counter.h"
150 #include "square-counter.h"
151 #include "serpent-counter.h"
156 #include "tiger-mgf.h"
157 #include "rmd128-mgf.h"
158 #include "rmd160-mgf.h"
159 #include "rmd256-mgf.h"
160 #include "rmd320-mgf.h"
164 /*----- Data structures ---------------------------------------------------*/
168 grand
*(*seed
)(unsigned /*i*/);
173 extern gen generators
[];
180 E(SKIPJACK, skipjack) \
183 E(BLOWFISH, blowfish) \
184 E(TWOFISH, twofish) \
186 E(CAST128, cast128) \
187 E(CAST256, cast256) \
189 E(RIJNDAEL, rijndael) \
202 #define E(PRE, pre) CIPHER_##PRE,
203 enum { CIPHERS CIPHER__bogus
};
206 #define E(PRE, pre) HASH_##PRE,
207 enum { HASHES HASH__bogus
};
213 grand
*(*ofb
)(const void */
*k*/
, size_t /*sz*/);
214 grand
*(*counter
)(const void */
*k*/
, size_t /*sz*/);
216 #define E(PRE, pre) \
217 { pre##_keysz, PRE##_BLKSZ, pre##_ofbrand, pre##_counterrand },
225 grand
*(*mgf
)(const void */
*k*/
, size_t /*sz*/);
227 #define E(PRE, pre) \
228 { &pre, pre##_mgfkeysz, pre##_mgfrand },
233 /*----- Miscellaneous static data -----------------------------------------*/
236 static size_t outsz
= 0;
237 static unsigned maurer_lo
= 5, maurer_hi
= 8;
242 static unsigned flags
= 0;
244 #define f_progress 1u
249 #define f_discard 32u
251 /*----- Help options ------------------------------------------------------*/
253 static void usage(FILE *fp
)
255 pquis(fp
, "Usage: $ generator [options]\n");
258 static void version(FILE *fp
)
260 pquis(fp
, "$, Catacomb version " VERSION
"\n");
263 static void help(FILE *fp
)
269 Emits a stream of random bytes suitable for, well, all sorts of things.\n\
270 The primary objective is to be able to generate streams of input for\n\
271 statistical tests, such as Diehard.\n\
273 Options are specific to the particular generator, although there's a\n\
276 -h, --help Display this help message.\n\
277 -v, --version Display the program's version number.\n\
278 -u, --usage Display a useless usage message.\n\
280 -l, --list Show a list of the supported generators, with\n\
282 -f, --fipstest Run the FIPS 140-1 randomness test.\n\
283 -m, --maurer[=LO-HI] Run Maurer's universal statistical test.\n\
284 -o, --output FILE Write output to FILE, not stdout.\n\
285 -z, --size SIZE Emit SIZE bytes, not an unlimited number.\n\
286 -p, --progress Show a little progress meter (on stderr).\n\
287 -T, --timer Keep track of the CPU time used by the generator.\n\
288 -d, --discard Discard the generated output.\n\
290 (A SIZE may be followed by `g' for gigabytes, `m' for megabytes, or\n\
291 `k' for kilobytes. If unqualified, an amount in bytes is assumed.)\n\
295 /*----- Main options parser -----------------------------------------------*/
297 static struct option opts
[] = {
299 /* --- Standard GNU help options --- */
301 { "help", 0, 0, 'h' },
302 { "version", 0, 0, 'v' },
303 { "usage", 0, 0, 'u' },
305 /* --- Other useful things --- */
307 { "list", 0, 0, 'l' },
308 { "fipstest", 0, 0, 'f' },
309 { "maurer", OPTF_ARGOPT
, 0, 'm' },
310 { "output", OPTF_ARGREQ
, 0, 'o' },
311 { "size", OPTF_ARGREQ
, 0, 'z' },
312 { "progress", 0, 0, 'p' },
313 { "timer", 0, 0, 'T' },
314 { "discard", 0, 0, 'd' },
316 /* --- End of main table --- */
321 static const char *sopts
= "hvu lfm::o:z:pTd";
324 DA_DECL(option_v
, struct option
);
328 static option_v optv
= DA_INIT
;
329 static dstr optd
= DSTR_INIT
;
331 /* --- @addopts@ --- *
333 * Arguments: @const char *s@ = pointer to short options
334 * @struct option *l@ = pointer to long options
338 * Use: Adds a collection of options to the table.
341 static void addopts(const char *s
, struct option
*l
)
347 DA_PUSH(&optv
, *l
++);
355 * Returns: Next option from argument array.
357 * Use: Fetches options, handling the standard ones.
363 int i
= mdwopt(argc
, argv
, optd
.buf
, DA(&optv
), 0, 0, 0);
376 puts("Generators supported:");
377 for (g
= generators
; g
->name
; g
++)
378 printf(" %s %s\n", g
->name
, g
->help
);
388 unsigned long lo
, hi
;
389 lo
= strtoul(optarg
, &p
, 0);
390 if (*p
== '-' || *p
== ',')
391 hi
= strtoul(p
+ 1, &p
, 0);
394 if (*p
!= 0 || hi
< lo
|| lo
== 0)
395 die(EXIT_FAILURE
, "bad bit range `%s'", optarg
);
402 die(EXIT_FAILURE
, "already set an output file");
403 if (strcmp(optarg
, "-") == 0)
406 outfp
= fopen(optarg
, "w");
408 die(EXIT_FAILURE
, "couldn't open output file `%s': %s",
409 optarg
, strerror(errno
));
416 outsz
= strtoul(optarg
, &p
, 0);
418 die(EXIT_FAILURE
, "bad number `%s'", optarg
);
420 case 'G': case 'g': outsz
*= 1024;
421 case 'M': case 'm': outsz
*= 1024;
422 case 'K': case 'k': outsz
*= 1024;
426 die(EXIT_FAILURE
, "bad suffix `%s'", p
);
430 die(EXIT_FAILURE
, "bad suffix `%s'", p
);
447 /*----- Manglers for seed strings -----------------------------------------*/
451 * Arguments: @const char *p@ = pointer to input string
452 * @char **end@ = where the end goes
453 * @dstr *d@ = output buffer
457 * Use: Transforms a hex string into a chunk of binary data.
460 static void unhex(const char *p
, char **end
, dstr
*d
)
462 while (p
[0] && p
[1]) {
463 int x
= p
[0], y
= p
[1];
464 if ('0' <= x
&& x
<= '9') x
-= '0';
465 else if ('A' <= x
&& x
<= 'F') x
-= 'A' - 10;
466 else if ('a' <= x
&& x
<= 'f') x
-= 'a' - 10;
468 if ('0' <= y
&& y
<= '9') y
-= '0';
469 else if ('A' <= y
&& y
<= 'F') y
-= 'A' - 10;
470 else if ('a' <= y
&& y
<= 'f') y
-= 'a' - 10;
472 DPUTC(d
, (x
<< 4) + y
);
478 /* --- Generate a key --- */
480 static void textkey(dstr
*d
, const char *p
, const octet
*ksz
)
482 size_t sz
= strlen(p
);
485 die(EXIT_FAILURE
, "zero-length key string");
486 if (keysz(sz
, ksz
) != sz
)
490 rmd160_mgfinit(&g
, p
, sz
);
493 rmd160_mgfencrypt(&g
, 0, d
->buf
, sz
);
496 assert(((void)"I can't seem to choose a good key size",
497 keysz(d
->len
, ksz
) == d
->len
));
500 static void hexkey(dstr
*d
, const char *p
, const octet
*ksz
)
503 unhex(optarg
, &q
, d
);
505 die(EXIT_FAILURE
, "bad hex key `%s'", p
);
506 if (keysz(d
->len
, ksz
) != d
->len
)
507 die(EXIT_FAILURE
, "bad key length");
510 static void randkey(dstr
*d
, const octet
*ksz
)
512 size_t sz
= keysz(0, ksz
);
514 rand_get(RAND_GLOBAL
, d
->buf
, sz
);
518 /*----- Generators --------------------------------------------------------*/
520 /* --- Blum-Blum-Shub strong generator --- */
522 static grand
*gen_bbs(unsigned i
)
524 /* --- Default modulus --- *
526 * The factors of this number are
528 * @p = 1229936431484295969649886203367009966370895964206162032259292413@
529 * @7754313537966036459299022912838407755462506416274551744201653277@
530 * @313130311731673973886822067@
532 * @q = 9798171783943489959487301695884963889684294764514008432498259742@
533 * @5374320073594018817245784145742769603334292182227671519041431067@
534 * @61344781426317516045890159@
536 * Both %$p$% and %$q$% are prime; %$(p - 1)/2$% and %$(q - 1)/2$% have no
537 * common factors. They were found using this program, with random
540 * I hope that, by publishing these factors, I'll dissuade people from
541 * actually using this modulus in an attempt to attain real security. The
542 * program is quite quick at finding Blum numbers, so there's no excuse for
543 * not generating your own.
547 "120511284390135742513572142094334711443073194119732569353820828435640527418092392240366088035509890969913081816369160298961490135716255689660470370755013177656905237112577648090277537209936078171554274553448103698084782669252936352843649980105109850503830397166360721262431179505917248447259735253684659338653";
549 /* --- Other things --- */
553 unsigned bits
= 1024;
556 const char *kfile
= 0, *id
= 0, *ktype
= 0;
558 /* --- Parse options --- */
560 static struct option opts
[] = {
561 { "modulus", OPTF_ARGREQ
, 0, 'M' },
562 { "generate", 0, 0, 'g' },
563 { "seed", OPTF_ARGREQ
, 0, 's' },
564 { "bits", OPTF_ARGREQ
, 0, 'b' },
565 { "show", 0, 0, 'S' },
566 { "keyring", OPTF_ARGREQ
, 0, 'k' },
567 { "id", OPTF_ARGREQ
, 0, 'i' },
568 { "type", OPTF_ARGREQ
, 0, 't' },
572 addopts("M:gs:b:Sk:i:t:", opts
);
589 bits
= strtoul(optarg
, 0, 0);
591 die(EXIT_FAILURE
, "bad number of bits `%s'", optarg
);
613 /* --- Generate a modulus if one is requested --- */
617 m
= mp_readstring(MP_NEW
, mt
, &p
, 0);
618 if (!m
|| *p
|| (m
->v
[0] & 3) != 1)
619 die(EXIT_FAILURE
, "bad modulus `%s'", mt
);
620 /* Unfortunately I don't know how to test for a Blum integer */
621 } else if (kfile
|| id
|| ktype
) {
626 /* --- Open the key file --- */
630 if (key_open(&kf
, kfile
, KOPEN_READ
, key_moan
, 0)) {
631 die(EXIT_FAILURE
, "error opening key file `%s': %s",
632 kfile
, strerror(errno
));
635 /* --- Find the key --- */
638 if ((kk
= key_bytag(&kf
, id
)) == 0)
639 die(EXIT_FAILURE
, "key `%s' not found", id
);
643 if ((kk
= key_bytype(&kf
, ktype
)) == 0)
644 die(EXIT_FAILURE
, "no suitable key with type `%s' found", ktype
);
647 /* --- Read the key data --- */
649 if ((kk
->k
.e
& KF_ENCMASK
) != KENC_STRUCT
)
650 die(EXIT_FAILURE
, "key is not structured");
651 if ((kd
= key_structfind(&kk
->k
, "n")) == 0)
652 die(EXIT_FAILURE
, "key has no subkey `n'");
653 if ((kd
->e
& KF_ENCMASK
) != KENC_MP
)
654 die(EXIT_FAILURE
, "incomatible subkey encoding");
655 m
= MP_COPY(kd
->u
.m
);
660 if (bbs_gen(&bp
, bits
, &rand_global
, 0,
661 (flags
& f_progress
) ? pgen_ev
: 0, 0))
662 die(EXIT_FAILURE
, "modulus generation failed");
666 fputs("p = ", stderr
);
667 mp_writefile(bp
.p
, stderr
, 10);
668 fputs("\nq = ", stderr
);
669 mp_writefile(bp
.q
, stderr
, 10);
670 fputs("\nn = ", stderr
);
671 mp_writefile(bp
.n
, stderr
, 10);
679 /* --- Set up a seed --- */
682 x
= mprand(MP_NEW
, mp_bits(m
) - 1, &rand_global
, 1);
685 x
= mp_readstring(MP_NEW
, xt
, &p
, 0);
687 die(EXIT_FAILURE
, "bad modulus `%s'", xt
);
699 /* --- Catacomb's random number generator --- */
701 static grand
*gen_rand(unsigned i
)
703 grand
*r
= rand_create();
706 static struct option opts
[] = {
707 { "key", OPTF_ARGREQ
, 0, 'k' },
708 { "text", OPTF_ARGREQ
, 0, 't' },
709 { "hex", OPTF_ARGREQ
, 0, 'H' },
713 addopts("k:t:H:n", opts
);
715 r
->ops
->misc(r
, RAND_NOISESRC
, &noise_source
);
716 r
->ops
->misc(r
, RAND_SEED
, 160);
725 textkey(&d
, optarg
, rmd160_mackeysz
);
726 r
->ops
->misc(r
, RAND_KEY
, d
.buf
, d
.len
);
729 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, optarg
, strlen(optarg
));
733 hexkey(&d
, optarg
, rmd160_mackeysz
);
734 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, d
.buf
, d
.len
);
743 /* --- RC4 output --- */
745 static grand
*gen_rc4(unsigned i
)
750 static struct option opts
[] = {
751 { "key", OPTF_ARGREQ
, 0, 'k' },
752 { "hex", OPTF_ARGREQ
, 0, 'H' },
756 addopts("k:H:", opts
);
765 textkey(&d
, optarg
, rc4_keysz
);
769 hexkey(&d
, optarg
, rc4_keysz
);
777 randkey(&d
, rc4_keysz
);
778 r
= rc4_rand(d
.buf
, d
.len
);
783 /* --- SEAL output --- */
785 static grand
*gen_seal(unsigned i
)
791 static struct option opts
[] = {
792 { "key", OPTF_ARGREQ
, 0, 'k' },
793 { "hex", OPTF_ARGREQ
, 0, 'H' },
794 { "sequence", OPTF_ARGREQ
, 0, 'n' },
798 addopts("k:H:n:", opts
);
807 textkey(&d
, optarg
, seal_keysz
);
811 hexkey(&d
, optarg
, seal_keysz
);
815 n
= strtoul(optarg
, &p
, 0);
817 die(EXIT_FAILURE
, "bad number `%s'", optarg
);
825 randkey(&d
, seal_keysz
);
826 r
= seal_rand(d
.buf
, d
.len
, n
);
831 /* --- Output feedback generators --- */
833 static grand
*gen_ofb(unsigned i
)
839 static struct option opts
[] = {
840 { "key", OPTF_ARGREQ
, 0, 'k' },
841 { "hex", OPTF_ARGREQ
, 0, 'H' },
842 { "iv", OPTF_ARGREQ
, 0, 'i' },
846 addopts("k:H:i:", opts
);
855 textkey(&d
, optarg
, ciphertab
[i
].keysz
);
859 hexkey(&d
, optarg
, ciphertab
[i
].keysz
);
863 unhex(optarg
, &p
, &iv
);
865 die(EXIT_FAILURE
, "bad hex IV `%s'", optarg
);
873 randkey(&d
, ciphertab
[i
].keysz
);
874 r
= ciphertab
[i
].ofb(d
.buf
, d
.len
);
876 if (iv
.len
!= ciphertab
[i
].blksz
) {
877 die(EXIT_FAILURE
, "bad IV length %lu (must be %lu)",
878 (unsigned long)iv
.len
, (unsigned long)ciphertab
[i
].blksz
);
880 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, iv
.buf
);
888 /* --- Counter generators --- */
890 static grand
*gen_counter(unsigned i
)
896 static struct option opts
[] = {
897 { "key", OPTF_ARGREQ
, 0, 'k' },
898 { "hex", OPTF_ARGREQ
, 0, 'H' },
899 { "iv", OPTF_ARGREQ
, 0, 'i' },
903 addopts("k:H:i:", opts
);
912 textkey(&d
, optarg
, ciphertab
[i
].keysz
);
916 hexkey(&d
, optarg
, ciphertab
[i
].keysz
);
920 unhex(optarg
, &p
, &iv
);
922 die(EXIT_FAILURE
, "bad hex IV `%s'", optarg
);
930 randkey(&d
, ciphertab
[i
].keysz
);
931 r
= ciphertab
[i
].counter(d
.buf
, d
.len
);
933 if (iv
.len
!= ciphertab
[i
].blksz
) {
934 die(EXIT_FAILURE
, "bad IV length %lu (must be %lu)",
935 (unsigned long)iv
.len
, (unsigned long)ciphertab
[i
].blksz
);
937 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, iv
.buf
);
945 /* --- Mask generators --- */
947 static grand
*gen_mgf(unsigned i
)
953 static struct option opts
[] = {
954 { "key", OPTF_ARGREQ
, 0, 'k' },
955 { "hex", OPTF_ARGREQ
, 0, 'H' },
956 { "index", OPTF_ARGREQ
, 0, 'i' },
960 addopts("k:H:i:", opts
);
969 textkey(&d
, optarg
, hashtab
[i
].keysz
);
973 hexkey(&d
, optarg
, hashtab
[i
].keysz
);
977 c
= strtoul(optarg
, &p
, 0);
979 die(EXIT_FAILURE
, "bad index `%s'", optarg
);
987 randkey(&d
, hashtab
[i
].keysz
);
989 r
= hashtab
[i
].mgf(d
.buf
, d
.len
);
991 r
->ops
->misc(r
, GRAND_SEEDUINT32
, c
);
997 /* --- Fibonacci generator --- */
999 static grand
*gen_fib(unsigned i
)
1006 static struct option opts
[] = {
1007 { "seed", OPTF_ARGREQ
, 0, 's' },
1011 addopts("s:", opts
);
1019 s
= strtoul(optarg
, &p
, 0);
1021 die(EXIT_FAILURE
, "bad integer `%s'", optarg
);
1028 r
= fibrand_create(s
);
1030 r
->ops
->misc(r
, GRAND_SEEDRAND
, &rand_global
);
1034 /* --- LC generator --- */
1036 static grand
*gen_lc(unsigned i
)
1042 static struct option opts
[] = {
1043 { "seed", OPTF_ARGREQ
, 0, 's' },
1047 addopts("s:", opts
);
1055 s
= strtoul(optarg
, &p
, 0);
1057 die(EXIT_FAILURE
, "bad integer `%s'", optarg
);
1066 s
= rand_global
.ops
->range(&rand_global
, LCRAND_P
);
1067 while (s
== LCRAND_FIXEDPT
);
1069 return (lcrand_create(s
));
1072 /* --- Basic options parser -- can't generate output --- */
1074 static grand
*gen_opts(unsigned i
)
1081 /*----- Generators table --------------------------------------------------*/
1083 gen generators
[] = {
1084 { "fibonacci", gen_fib
, 0,
1088 #define E(PRE, pre) \
1089 { #pre "-ofb", gen_ofb, CIPHER_##PRE, \
1090 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
1093 #define E(PRE, pre) \
1094 { #pre "-counter", gen_counter, CIPHER_##PRE, \
1095 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
1098 #define E(PRE, pre) \
1099 { #pre "-mgf", gen_mgf, HASH_##PRE, \
1100 "[-k KEY-PHRASE] [-H HEX-KEY] [-i INDEX]" },
1103 { "rc4", gen_rc4
, 0,
1104 "[-k KEY-PHRASE] [-H HEX-KEY]" },
1105 { "seal", gen_seal
, 0,
1106 "[-k KEY-PHRASE] [-H HEX-KEY] [-n SEQ]" },
1107 { "rand", gen_rand
, 0,
1108 "[-n] [-k KEY-PHRASE] [-t TEXT-BLOCK] [-H HEX-BLOCK]" },
1109 { "bbs", gen_bbs
, 0,
1110 "[-gS] [-s SEED] [-M MODULUS] [-b BITS] [-k KEYRING] [-i TAG] [-t TYPE]"
1115 static gen optsg
= { "options", gen_opts
, 0,
1116 "This message shouldn't be printed." };
1118 /*----- Random number generation ------------------------------------------*/
1120 static int genfile(const void *buf
, size_t sz
, void *p
)
1123 if (fwrite(buf
, 1, sz
, fp
) != sz
)
1124 die(EXIT_FAILURE
, "error writing to file: %s", strerror(errno
));
1128 static int genbuf(const void *buf
, size_t sz
, void *p
)
1131 memcpy(*pp
, buf
, sz
);
1136 typedef struct genmaurer_ctx
{
1141 static int genmaurer(const void *buf
, size_t sz
, void *p
)
1143 genmaurer_ctx
*g
= p
;
1146 for (i
= 0; i
< g
->n
; i
++)
1147 maurer_test(&g
->m
[i
], buf
, sz
);
1151 static int generate(grand
*r
, size_t outsz
,
1152 int (*func
)(const void *buf
, size_t sz
, void *p
),
1155 static char kmg
[] = { ' ', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 0 };
1157 unsigned percent
= 0;
1160 static char baton
[] = "-\\|/";
1165 /* --- Spit out random data --- */
1169 if (flags
& f_progress
) {
1170 char *errbuf
= xmalloc(BUFSIZ
);
1171 setvbuf(stderr
, errbuf
, _IOLBF
, BUFSIZ
);
1173 fprintf(stderr
, "[%*s] 0%% 0\r[/\b", 50, "");
1175 fputs("[ ] 0\r[/\b", stderr
);
1180 signal(SIGPIPE
, SIG_IGN
);
1185 size_t sz
= sizeof(buf
);
1186 clock_t c_start
, c_stop
;
1188 /* --- Emit a bufferful (or less) of data --- */
1191 if (sz
> outsz
- kb
)
1195 r
->ops
->fill(r
, buf
, sz
);
1197 clk
+= c_stop
- c_start
;
1198 if (func
&& (rc
= func(buf
, sz
, p
)) != 0)
1202 /* --- Update the display --- */
1204 if (flags
& f_progress
) {
1212 if (difftime(t
, last
) > 1.0) {
1216 fputs(" ] ", stderr
);
1218 unsigned pc
= kb
* 100.0 / outsz
;
1219 if (pc
> percent
|| percent
> 100 || difftime(t
, last
) > 1.0) {
1223 for (; percent
< (pc
& ~1); percent
+= 2)
1226 for (; pc
< 100; pc
+= 2)
1228 fprintf(stderr
, "] %3i%% ", percent
);
1236 while (q
> 8192 && kk
[1]) {
1240 fprintf(stderr
, "%4i%c\r[", q
, *kk
);
1243 for (pc
= 0; pc
< (percent
& ~1); pc
+= 2)
1252 if (percent
< 100) {
1253 putc(*bp
++, stderr
);
1261 /* --- Terminate the loop --- */
1263 } while (!outsz
|| kb
< outsz
);
1265 if (flags
& f_progress
)
1266 fputc('\n', stderr
);
1267 if (flags
& f_timer
) {
1268 fprintf(stderr
, "generated %lu bytes ", (unsigned long)outsz
);
1270 fputs("too quickly to measure\n", stderr
);
1273 double sec
= (double)clk
/CLOCKS_PER_SEC
;
1274 double bps
= (outsz
<< 3)/sec
;
1275 for (kk
= kmg
; bps
> 1024 && kk
[1]; kk
++, bps
/= 1024)
1277 fprintf(stderr
, "in %g secs (%g %cb/s)\n", sec
, bps
, *kk
);
1283 /*----- Main code ---------------------------------------------------------*/
1285 int main(int ac
, char *av
[])
1290 /* --- Initialize mLib --- */
1295 /* --- Set up the main Catacomb generator --- */
1297 rand_noisesrc(RAND_GLOBAL
, &noise_source
);
1298 rand_seed(RAND_GLOBAL
, 160);
1300 /* --- Initialize the options table --- */
1302 addopts(sopts
, opts
);
1307 /* --- Read the generator out of the first argument --- */
1309 if (argc
> 1 && *argv
[1] != '-') {
1310 const char *arg
= av
[1];
1311 size_t sz
= strlen(arg
);
1315 for (gg
= generators
; gg
->name
; gg
++) {
1316 if (strncmp(arg
, gg
->name
, sz
) == 0) {
1317 if (gg
->name
[sz
] == 0) {
1321 die(EXIT_FAILURE
, "ambiguous generator name `%s'", arg
);
1327 die(EXIT_FAILURE
, "unknown generator name `%s'", arg
);
1332 /* --- Get a generic random number generator --- */
1335 if (!r
|| optind
!= ac
- 1) {
1340 /* --- Do the FIPS test --- */
1342 if (flags
& f_fips
) {
1343 octet buf
[FIPSTEST_BUFSZ
];
1347 generate(r
, sizeof(buf
), genbuf
, &p
);
1349 if (rc
& FIPSTEST_MONOBIT
)
1350 moan("failed monobit test");
1351 if (rc
& FIPSTEST_POKER
)
1352 moan("failed poker test");
1353 if (rc
& FIPSTEST_RUNS
)
1354 moan("failed runs test");
1355 if (rc
& FIPSTEST_LONGRUNS
)
1356 moan("failed long runs test");
1357 if (!rc
&& (flags
& f_progress
))
1358 fputs("test passed\n", stderr
);
1359 return (rc ? EXIT_FAILURE
: 0);
1362 /* --- Do Maurer's test --- */
1364 if (flags
& f_maurer
) {
1370 static struct { double x
; const char *sig
; } sigtab
[] = {
1378 g
.n
= maurer_hi
- maurer_lo
+ 1;
1379 g
.m
= xmalloc(g
.n
* sizeof(maurer_ctx
));
1380 for (i
= 0; i
< g
.n
; i
++)
1381 maurer_init(&g
.m
[i
], i
+ maurer_lo
);
1382 bufsz
= (100 * maurer_hi
) << maurer_hi
;
1384 generate(r
, bufsz
, genmaurer
, &g
);
1386 for (i
= maurer_lo
; i
<= maurer_hi
; i
++) {
1387 double z
= maurer_done(&g
.m
[i
- maurer_lo
]);
1388 double zz
= fabs(z
);
1391 for (j
= 0; sigtab
[j
].sig
; j
++) {
1392 if (zz
> sigtab
[j
].x
) {
1394 moan("failed, bits = %u, sig = %s, Z_u = %g",
1395 i
, sigtab
[j
].sig
, z
);
1399 if (flags
& f_progress
)
1400 fprintf(stderr
, "bits = %u, Z_u = %g\n", i
, z
);
1407 /* --- Discard --- */
1409 if (flags
& f_discard
) {
1410 generate(r
, outsz
, 0, 0);
1414 /* --- Write to a file --- */
1417 if (!(flags
& f_file
) && isatty(STDOUT_FILENO
))
1418 die(EXIT_FAILURE
, "writing output to a terminal is a bad idea");
1421 generate(r
, outsz
, genfile
, outfp
);
1429 /*----- That's all, folks -------------------------------------------------*/