3 * $Id: rspit.c,v 1.10 2000/08/11 21:34:59 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.10 2000/08/11 21:34:59 mdw
34 * New restartable interface to Maurer testing.
36 * Revision 1.9 2000/08/04 23:24:15 mdw
37 * Add a timer and a discard option.
39 * Revision 1.8 2000/07/29 22:05:47 mdw
40 * Fix error in help message about Maurer test syntax.
42 * Revision 1.7 2000/07/18 23:01:26 mdw
43 * Improve progress indications, and allow user to choose chunk sizes for
46 * Revision 1.6 2000/07/15 20:53:35 mdw
47 * Add a load of new ciphers and hashes.
49 * Revision 1.5 2000/07/01 11:27:03 mdw
50 * Portability fix: don't assume that `stdout' is a constant expression.
51 * Remove old type name `bbs_param'.
53 * Revision 1.4 2000/06/17 12:08:28 mdw
54 * Restructure handling of cipher-based generators. Add counter-mode
55 * ciphers and MGF-1 hash functions. Add FIPS 140-1 and Maurer's tests.
57 * Revision 1.3 2000/02/12 18:21:03 mdw
58 * Overhaul of key management (again).
60 * Revision 1.2 1999/12/22 15:59:51 mdw
61 * New prime-search system. Read BBS keys from key files.
63 * Revision 1.1 1999/12/10 23:29:13 mdw
64 * Emit random numbers for statistical tests.
68 /*----- Header files ------------------------------------------------------*/
85 #include <mLib/darray.h>
86 #include <mLib/dstr.h>
87 #include <mLib/mdwopt.h>
88 #include <mLib/quis.h>
89 #include <mLib/report.h>
109 #include "des3-ofb.h"
112 #include "skipjack-ofb.h"
114 #include "xtea-ofb.h"
115 #include "blowfish-ofb.h"
116 #include "twofish-ofb.h"
117 #include "idea-ofb.h"
118 #include "cast128-ofb.h"
119 #include "cast256-ofb.h"
120 #include "rijndael-ofb.h"
121 #include "square-ofb.h"
122 #include "serpent-ofb.h"
124 #include "des-counter.h"
125 #include "des3-counter.h"
126 #include "rc2-counter.h"
127 #include "rc5-counter.h"
128 #include "skipjack-counter.h"
129 #include "tea-counter.h"
130 #include "xtea-counter.h"
131 #include "blowfish-counter.h"
132 #include "twofish-counter.h"
133 #include "idea-counter.h"
134 #include "cast128-counter.h"
135 #include "cast256-counter.h"
136 #include "rijndael-counter.h"
137 #include "square-counter.h"
138 #include "serpent-counter.h"
143 #include "tiger-mgf.h"
144 #include "rmd128-mgf.h"
145 #include "rmd160-mgf.h"
146 #include "rmd256-mgf.h"
147 #include "rmd320-mgf.h"
151 /*----- Data structures ---------------------------------------------------*/
155 grand
*(*seed
)(unsigned /*i*/);
160 static gen generators
[];
167 E(SKIPJACK, skipjack) \
170 E(BLOWFISH, blowfish) \
171 E(TWOFISH, twofish) \
173 E(CAST128, cast128) \
174 E(CAST256, cast256) \
176 E(RIJNDAEL, rijndael) \
189 #define E(PRE, pre) CIPHER_##PRE,
190 enum { CIPHERS CIPHER__bogus
};
193 #define E(PRE, pre) HASH_##PRE,
194 enum { HASHES HASH__bogus
};
200 grand
*(*ofb
)(const void */
*k*/
, size_t /*sz*/);
201 grand
*(*counter
)(const void */
*k*/
, size_t /*sz*/);
203 #define E(PRE, pre) \
204 { pre##_keysz, PRE##_BLKSZ, pre##_ofbrand, pre##_counterrand },
212 grand
*(*mgf
)(const void */
*k*/
, size_t /*sz*/);
214 #define E(PRE, pre) \
215 { &pre, pre##_mgfkeysz, pre##_mgfrand },
220 /*----- Miscellaneous static data -----------------------------------------*/
223 static size_t outsz
= 0;
224 static unsigned maurer_lo
= 5, maurer_hi
= 8;
229 static unsigned flags
= 0;
240 /*----- Help options ------------------------------------------------------*/
242 static void usage(FILE *fp
)
244 pquis(fp
, "Usage: $ generator [options]\n");
247 static void version(FILE *fp
)
249 pquis(fp
, "$, Catacomb version " VERSION
"\n");
252 static void help(FILE *fp
)
258 Emits a stream of random bytes suitable for, well, all sorts of things.\n\
259 The primary objective is to be able to generate streams of input for\n\
260 statistical tests, such as Diehard.\n\
262 Options are specific to the particular generator, although there's a\n\
265 -h, --help Display this help message.\n\
266 -v, --version Display the program's version number.\n\
267 -u, --usage Display a useless usage message.\n\
269 -l, --list Show a list of the supported generators, with\n\
271 -f, --fipstest Run the FIPS 140-1 randomness test.\n\
272 -m, --maurer[=LO-HI] Run Maurer's universal statistical test.\n\
273 -o, --output FILE Write output to FILE, not stdout.\n\
274 -z, --size SIZE Emit SIZE bytes, not an unlimited number.\n\
275 -p, --progress Show a little progress meter (on stderr).\n\
276 -T, --timer Keep track of the CPU time used by the generator.\n\
277 -d, --discard Discard the generated output.\n\
279 (A SIZE may be followed by `g' for gigabytes, `m' for megabytes, or\n\
280 `k' for kilobytes. If unqualified, an amount in bytes is assumed.)\n\
284 /*----- Main options parser -----------------------------------------------*/
286 static struct option opts
[] = {
288 /* --- Standard GNU help options --- */
290 { "help", 0, 0, 'h' },
291 { "version", 0, 0, 'v' },
292 { "usage", 0, 0, 'u' },
294 /* --- Other useful things --- */
296 { "list", 0, 0, 'l' },
297 { "fipstest", 0, 0, 'f' },
298 { "maurer", OPTF_ARGOPT
, 0, 'm' },
299 { "output", OPTF_ARGREQ
, 0, 'o' },
300 { "size", OPTF_ARGREQ
, 0, 'z' },
301 { "progress", 0, 0, 'p' },
302 { "timer", 0, 0, 'T' },
303 { "discard", 0, 0, 'd' },
305 /* --- End of main table --- */
310 static const char *sopts
= "hvu lfm::o:z:pTd";
313 DA_DECL(option_v
, struct option
);
317 static option_v optv
= DA_INIT
;
318 static dstr optd
= DSTR_INIT
;
320 /* --- @addopts@ --- *
322 * Arguments: @const char *s@ = pointer to short options
323 * @struct option *l@ = pointer to long options
327 * Use: Adds a collection of options to the table.
330 static void addopts(const char *s
, struct option
*l
)
336 DA_PUSH(&optv
, *l
++);
344 * Returns: Next option from argument array.
346 * Use: Fetches options, handling the standard ones.
352 int i
= mdwopt(argc
, argv
, optd
.buf
, DA(&optv
), 0, 0, 0);
365 puts("Generators supported:");
366 for (g
= generators
; g
->name
; g
++)
367 printf(" %s %s\n", g
->name
, g
->help
);
377 unsigned long lo
, hi
;
378 lo
= strtoul(optarg
, &p
, 0);
379 if (*p
== '-' || *p
== ',')
380 hi
= strtoul(p
+ 1, &p
, 0);
383 if (*p
!= 0 || hi
< lo
|| lo
== 0)
384 die(EXIT_FAILURE
, "bad bit range `%s'", optarg
);
391 die(EXIT_FAILURE
, "already set an output file");
392 if (strcmp(optarg
, "-") == 0)
395 outfp
= fopen(optarg
, "w");
397 die(EXIT_FAILURE
, "couldn't open output file `%s': %s",
398 optarg
, strerror(errno
));
405 outsz
= strtoul(optarg
, &p
, 0);
407 die(EXIT_FAILURE
, "bad number `%s'", optarg
);
409 case 'G': case 'g': outsz
*= 1024;
410 case 'M': case 'm': outsz
*= 1024;
411 case 'K': case 'k': outsz
*= 1024;
415 die(EXIT_FAILURE
, "bad suffix `%s'", p
);
419 die(EXIT_FAILURE
, "bad suffix `%s'", p
);
436 /*----- Manglers for seed strings -----------------------------------------*/
440 * Arguments: @const char *p@ = pointer to input string
441 * @char **end@ = where the end goes
442 * @dstr *d@ = output buffer
446 * Use: Transforms a hex string into a chunk of binary data.
449 static void unhex(const char *p
, char **end
, dstr
*d
)
451 while (p
[0] && p
[1]) {
452 int x
= p
[0], y
= p
[1];
453 if ('0' <= x
&& x
<= '9') x
-= '0';
454 else if ('A' <= x
&& x
<= 'F') x
-= 'A' - 10;
455 else if ('a' <= x
&& x
<= 'f') x
-= 'a' - 10;
457 if ('0' <= y
&& y
<= '9') y
-= '0';
458 else if ('A' <= y
&& y
<= 'F') y
-= 'A' - 10;
459 else if ('a' <= y
&& y
<= 'f') y
-= 'a' - 10;
461 DPUTC(d
, (x
<< 4) + y
);
467 /* --- Generate a key --- */
469 static void textkey(dstr
*d
, const char *p
, const octet
*ksz
)
471 size_t sz
= strlen(p
);
474 die(EXIT_FAILURE
, "zero-length key string");
475 if (keysz(sz
, ksz
) != sz
)
479 rmd160_mgfinit(&g
, p
, sz
);
482 rmd160_mgfencrypt(&g
, 0, d
->buf
, sz
);
485 assert(((void)"I can't seem to choose a good key size",
486 keysz(d
->len
, ksz
) == d
->len
));
489 static void hexkey(dstr
*d
, const char *p
, const octet
*ksz
)
492 unhex(optarg
, &q
, d
);
494 die(EXIT_FAILURE
, "bad hex key `%s'", p
);
495 if (keysz(d
->len
, ksz
) != d
->len
)
496 die(EXIT_FAILURE
, "bad key length");
499 static void randkey(dstr
*d
, const octet
*ksz
)
501 size_t sz
= keysz(0, ksz
);
503 rand_get(RAND_GLOBAL
, d
->buf
, sz
);
507 /*----- Generators --------------------------------------------------------*/
509 /* --- Blum-Blum-Shub strong generator --- */
511 static grand
*gen_bbs(unsigned i
)
513 /* --- Default modulus --- *
515 * The factors of this number are
517 * @p = 1229936431484295969649886203367009966370895964206162032259292413@
518 * @7754313537966036459299022912838407755462506416274551744201653277@
519 * @313130311731673973886822067@
521 * @q = 9798171783943489959487301695884963889684294764514008432498259742@
522 * @5374320073594018817245784145742769603334292182227671519041431067@
523 * @61344781426317516045890159@
525 * Both %$p$% and %$q$% are prime; %$(p - 1)/2$% and %$(q - 1)/2$% have no
526 * common factors. They were found using this program, with random
529 * I hope that, by publishing these factors, I'll dissuade people from
530 * actually using this modulus in an attempt to attain real security. The
531 * program is quite quick at finding Blum numbers, so there's no excuse for
532 * not generating your own.
536 "120511284390135742513572142094334711443073194119732569353820828435640527418092392240366088035509890969913081816369160298961490135716255689660470370755013177656905237112577648090277537209936078171554274553448103698084782669252936352843649980105109850503830397166360721262431179505917248447259735253684659338653";
538 /* --- Other things --- */
542 unsigned bits
= 1024;
545 const char *kfile
= 0, *id
= 0, *ktype
= 0;
547 /* --- Parse options --- */
549 static struct option opts
[] = {
550 { "modulus", OPTF_ARGREQ
, 0, 'M' },
551 { "generate", 0, 0, 'g' },
552 { "seed", OPTF_ARGREQ
, 0, 's' },
553 { "bits", OPTF_ARGREQ
, 0, 'b' },
554 { "show", 0, 0, 'S' },
555 { "keyring", OPTF_ARGREQ
, 0, 'k' },
556 { "id", OPTF_ARGREQ
, 0, 'i' },
557 { "type", OPTF_ARGREQ
, 0, 't' },
561 addopts("M:gs:b:Sk:i:t:", opts
);
578 bits
= strtoul(optarg
, 0, 0);
580 die(EXIT_FAILURE
, "bad number of bits `%s'", optarg
);
602 /* --- Generate a modulus if one is requested --- */
606 m
= mp_readstring(MP_NEW
, mt
, &p
, 0);
607 if (!m
|| *p
|| (m
->v
[0] & 3) != 1)
608 die(EXIT_FAILURE
, "bad modulus `%s'", mt
);
609 /* Unfortunately I don't know how to test for a Blum integer */
610 } else if (kfile
|| id
|| ktype
) {
615 /* --- Open the key file --- */
619 if (key_open(&kf
, kfile
, KOPEN_READ
, key_moan
, 0)) {
620 die(EXIT_FAILURE
, "error opening key file `%s': %s",
621 kfile
, strerror(errno
));
624 /* --- Find the key --- */
627 if ((kk
= key_bytag(&kf
, id
)) == 0)
628 die(EXIT_FAILURE
, "key `%s' not found", id
);
632 if ((kk
= key_bytype(&kf
, ktype
)) == 0)
633 die(EXIT_FAILURE
, "no suitable key with type `%s' found", ktype
);
636 /* --- Read the key data --- */
638 if ((kk
->k
.e
& KF_ENCMASK
) != KENC_STRUCT
)
639 die(EXIT_FAILURE
, "key is not structured");
640 if ((kd
= key_structfind(&kk
->k
, "n")) == 0)
641 die(EXIT_FAILURE
, "key has no subkey `n'");
642 if ((kd
->e
& KF_ENCMASK
) != KENC_MP
)
643 die(EXIT_FAILURE
, "incomatible subkey encoding");
644 m
= MP_COPY(kd
->u
.m
);
649 if (bbs_gen(&bp
, bits
, &rand_global
, 0,
650 (flags
& f_progress
) ? pgen_ev
: 0, 0))
651 die(EXIT_FAILURE
, "modulus generation failed");
655 fputs("p = ", stderr
);
656 mp_writefile(bp
.p
, stderr
, 10);
657 fputs("\nq = ", stderr
);
658 mp_writefile(bp
.q
, stderr
, 10);
659 fputs("\nn = ", stderr
);
660 mp_writefile(bp
.n
, stderr
, 10);
668 /* --- Set up a seed --- */
671 x
= mprand(MP_NEW
, mp_bits(m
) - 1, &rand_global
, 1);
674 x
= mp_readstring(MP_NEW
, xt
, &p
, 0);
676 die(EXIT_FAILURE
, "bad modulus `%s'", xt
);
688 /* --- Catacomb's random number generator --- */
690 static grand
*gen_rand(unsigned i
)
692 grand
*r
= rand_create();
695 static struct option opts
[] = {
696 { "key", OPTF_ARGREQ
, 0, 'k' },
697 { "text", OPTF_ARGREQ
, 0, 't' },
698 { "hex", OPTF_ARGREQ
, 0, 'H' },
702 addopts("k:t:H:n", opts
);
704 r
->ops
->misc(r
, RAND_NOISESRC
, &noise_source
);
705 r
->ops
->misc(r
, RAND_SEED
, 160);
714 textkey(&d
, optarg
, rmd160_mackeysz
);
715 r
->ops
->misc(r
, RAND_KEY
, d
.buf
, d
.len
);
718 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, optarg
, strlen(optarg
));
722 hexkey(&d
, optarg
, rmd160_mackeysz
);
723 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, d
.buf
, d
.len
);
732 /* --- RC4 output --- */
734 static grand
*gen_rc4(unsigned i
)
739 static struct option opts
[] = {
740 { "key", OPTF_ARGREQ
, 0, 'k' },
741 { "hex", OPTF_ARGREQ
, 0, 'H' },
745 addopts("k:H:", opts
);
754 textkey(&d
, optarg
, rc4_keysz
);
758 hexkey(&d
, optarg
, rc4_keysz
);
766 randkey(&d
, rc4_keysz
);
767 r
= rc4_rand(d
.buf
, d
.len
);
772 /* --- SEAL output --- */
774 static grand
*gen_seal(unsigned i
)
780 static struct option opts
[] = {
781 { "key", OPTF_ARGREQ
, 0, 'k' },
782 { "hex", OPTF_ARGREQ
, 0, 'H' },
783 { "sequence", OPTF_ARGREQ
, 0, 'n' },
787 addopts("k:H:n:", opts
);
796 textkey(&d
, optarg
, seal_keysz
);
800 hexkey(&d
, optarg
, seal_keysz
);
804 n
= strtoul(optarg
, &p
, 0);
806 die(EXIT_FAILURE
, "bad number `%s'", optarg
);
814 randkey(&d
, seal_keysz
);
815 r
= seal_rand(d
.buf
, d
.len
, n
);
820 /* --- Output feedback generators --- */
822 static grand
*gen_ofb(unsigned i
)
828 static struct option opts
[] = {
829 { "key", OPTF_ARGREQ
, 0, 'k' },
830 { "hex", OPTF_ARGREQ
, 0, 'H' },
831 { "iv", OPTF_ARGREQ
, 0, 'i' },
835 addopts("k:H:i:", opts
);
844 textkey(&d
, optarg
, ciphertab
[i
].keysz
);
848 hexkey(&d
, optarg
, ciphertab
[i
].keysz
);
852 unhex(optarg
, &p
, &iv
);
854 die(EXIT_FAILURE
, "bad hex IV `%s'", optarg
);
862 randkey(&d
, ciphertab
[i
].keysz
);
863 r
= ciphertab
[i
].ofb(d
.buf
, d
.len
);
865 if (iv
.len
!= ciphertab
[i
].blksz
) {
866 die(EXIT_FAILURE
, "bad IV length %lu (must be %lu)",
867 (unsigned long)iv
.len
, (unsigned long)ciphertab
[i
].blksz
);
869 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, iv
.buf
);
877 /* --- Counter generators --- */
879 static grand
*gen_counter(unsigned i
)
885 static struct option opts
[] = {
886 { "key", OPTF_ARGREQ
, 0, 'k' },
887 { "hex", OPTF_ARGREQ
, 0, 'H' },
888 { "iv", OPTF_ARGREQ
, 0, 'i' },
892 addopts("k:H:i:", opts
);
901 textkey(&d
, optarg
, ciphertab
[i
].keysz
);
905 hexkey(&d
, optarg
, ciphertab
[i
].keysz
);
909 unhex(optarg
, &p
, &iv
);
911 die(EXIT_FAILURE
, "bad hex IV `%s'", optarg
);
919 randkey(&d
, ciphertab
[i
].keysz
);
920 r
= ciphertab
[i
].counter(d
.buf
, d
.len
);
922 if (iv
.len
!= ciphertab
[i
].blksz
) {
923 die(EXIT_FAILURE
, "bad IV length %lu (must be %lu)",
924 (unsigned long)iv
.len
, (unsigned long)ciphertab
[i
].blksz
);
926 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, iv
.buf
);
934 /* --- Mask generators --- */
936 static grand
*gen_mgf(unsigned i
)
942 static struct option opts
[] = {
943 { "key", OPTF_ARGREQ
, 0, 'k' },
944 { "hex", OPTF_ARGREQ
, 0, 'H' },
945 { "index", OPTF_ARGREQ
, 0, 'i' },
949 addopts("k:H:i:", opts
);
958 textkey(&d
, optarg
, hashtab
[i
].keysz
);
962 hexkey(&d
, optarg
, hashtab
[i
].keysz
);
966 c
= strtoul(optarg
, &p
, 0);
968 die(EXIT_FAILURE
, "bad index `%s'", optarg
);
976 randkey(&d
, hashtab
[i
].keysz
);
978 r
= hashtab
[i
].mgf(d
.buf
, d
.len
);
980 r
->ops
->misc(r
, GRAND_SEEDUINT32
, c
);
986 /* --- Fibonacci generator --- */
988 static grand
*gen_fib(unsigned i
)
995 static struct option opts
[] = {
996 { "seed", OPTF_ARGREQ
, 0, 's' },
1000 addopts("s:", opts
);
1008 s
= strtoul(optarg
, &p
, 0);
1010 die(EXIT_FAILURE
, "bad integer `%s'", optarg
);
1017 r
= fibrand_create(s
);
1019 r
->ops
->misc(r
, GRAND_SEEDRAND
, &rand_global
);
1023 /* --- LC generator --- */
1025 static grand
*gen_lc(unsigned i
)
1031 static struct option opts
[] = {
1032 { "seed", OPTF_ARGREQ
, 0, 's' },
1036 addopts("s:", opts
);
1044 s
= strtoul(optarg
, &p
, 0);
1046 die(EXIT_FAILURE
, "bad integer `%s'", optarg
);
1055 s
= rand_global
.ops
->range(&rand_global
, LCRAND_P
);
1056 while (s
== LCRAND_FIXEDPT
);
1058 return (lcrand_create(s
));
1061 /* --- Basic options parser -- can't generate output --- */
1063 static grand
*gen_opts(unsigned i
)
1070 /*----- Generators table --------------------------------------------------*/
1072 static gen generators
[] = {
1073 { "fibonacci", gen_fib
, 0,
1077 #define E(PRE, pre) \
1078 { #pre "-ofb", gen_ofb, CIPHER_##PRE, \
1079 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
1082 #define E(PRE, pre) \
1083 { #pre "-counter", gen_counter, CIPHER_##PRE, \
1084 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
1087 #define E(PRE, pre) \
1088 { #pre "-mgf", gen_mgf, HASH_##PRE, \
1089 "[-k KEY-PHRASE] [-H HEX-KEY] [-i INDEX]" },
1092 { "rc4", gen_rc4
, 0,
1093 "[-k KEY-PHRASE] [-H HEX-KEY]" },
1094 { "seal", gen_seal
, 0,
1095 "[-k KEY-PHRASE] [-H HEX-KEY] [-n SEQ]" },
1096 { "rand", gen_rand
, 0,
1097 "[-n] [-k KEY-PHRASE] [-t TEXT-BLOCK] [-H HEX-BLOCK]" },
1098 { "bbs", gen_bbs
, 0,
1099 "[-gS] [-s SEED] [-M MODULUS] [-b BITS] [-k KEYRING] [-i TAG] [-t TYPE]"
1104 static gen optsg
= { "options", gen_opts
, 0,
1105 "This message shouldn't be printed." };
1107 /*----- Random number generation ------------------------------------------*/
1109 static int genfile(const void *buf
, size_t sz
, void *p
)
1112 if (fwrite(buf
, 1, sz
, fp
) != sz
)
1113 die(EXIT_FAILURE
, "error writing to file: %s", strerror(errno
));
1117 static int genbuf(const void *buf
, size_t sz
, void *p
)
1120 memcpy(*pp
, buf
, sz
);
1125 typedef struct genmaurer_ctx
{
1130 static int genmaurer(const void *buf
, size_t sz
, void *p
)
1132 genmaurer_ctx
*g
= p
;
1135 for (i
= 0; i
< g
->n
; i
++)
1136 maurer_test(&g
->m
[i
], buf
, sz
);
1140 static int generate(grand
*r
, size_t outsz
,
1141 int (*func
)(const void *buf
, size_t sz
, void *p
),
1144 static char kmg
[] = { ' ', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 0 };
1146 unsigned percent
= 0;
1149 static char baton
[] = "-\\|/";
1154 /* --- Spit out random data --- */
1158 if (flags
& f_progress
) {
1159 char *errbuf
= xmalloc(BUFSIZ
);
1160 setvbuf(stderr
, errbuf
, _IOLBF
, BUFSIZ
);
1162 fprintf(stderr
, "[%*s] 0%% 0\r[/\b", 50, "");
1164 fputs("[ ] 0\r[/\b", stderr
);
1169 signal(SIGPIPE
, SIG_IGN
);
1174 size_t sz
= sizeof(buf
);
1175 clock_t c_start
, c_stop
;
1177 /* --- Emit a bufferful (or less) of data --- */
1180 if (sz
> outsz
- kb
)
1184 r
->ops
->fill(r
, buf
, sz
);
1186 clk
+= c_stop
- c_start
;
1187 if (func
&& (rc
= func(buf
, sz
, p
)) != 0)
1191 /* --- Update the display --- */
1193 if (flags
& f_progress
) {
1201 if (difftime(t
, last
) > 1.0) {
1205 fputs(" ] ", stderr
);
1207 unsigned pc
= kb
* 100.0 / outsz
;
1208 if (pc
> percent
|| percent
> 100 || difftime(t
, last
) > 1.0) {
1212 for (; percent
< (pc
& ~1); percent
+= 2)
1215 for (; pc
< 100; pc
+= 2)
1217 fprintf(stderr
, "] %3i%% ", percent
);
1225 while (q
> 8192 && kk
[1]) {
1229 fprintf(stderr
, "%4i%c\r[", q
, *kk
);
1232 for (pc
= 0; pc
< (percent
& ~1); pc
+= 2)
1241 if (percent
< 100) {
1242 putc(*bp
++, stderr
);
1250 /* --- Terminate the loop --- */
1252 } while (!outsz
|| kb
< outsz
);
1254 if (flags
& f_progress
)
1255 fputc('\n', stderr
);
1256 if (flags
& f_timer
) {
1257 fprintf(stderr
, "generated %lu bytes ", (unsigned long)outsz
);
1259 fputs("too quickly to measure\n", stderr
);
1262 double sec
= (double)clk
/CLOCKS_PER_SEC
;
1263 double bps
= (outsz
<< 3)/sec
;
1264 for (kk
= kmg
; bps
> 1024 && kk
[1]; kk
++, bps
/= 1024)
1266 fprintf(stderr
, "in %g secs (%g %cb/s)\n", sec
, bps
, *kk
);
1272 /*----- Main code ---------------------------------------------------------*/
1274 int main(int ac
, char *av
[])
1279 /* --- Initialize mLib --- */
1284 /* --- Set up the main Catacomb generator --- */
1286 rand_noisesrc(RAND_GLOBAL
, &noise_source
);
1287 rand_seed(RAND_GLOBAL
, 160);
1289 /* --- Initialize the options table --- */
1291 addopts(sopts
, opts
);
1296 /* --- Read the generator out of the first argument --- */
1298 if (argc
> 1 && *argv
[1] != '-') {
1299 const char *arg
= av
[1];
1300 size_t sz
= strlen(arg
);
1304 for (gg
= generators
; gg
->name
; gg
++) {
1305 if (strncmp(arg
, gg
->name
, sz
) == 0) {
1306 if (gg
->name
[sz
] == 0) {
1310 die(EXIT_FAILURE
, "ambiguous generator name `%s'", arg
);
1316 die(EXIT_FAILURE
, "unknown generator name `%s'", arg
);
1321 /* --- Get a generic random number generator --- */
1324 if (!r
|| optind
!= ac
- 1) {
1329 /* --- Do the FIPS test --- */
1331 if (flags
& f_fips
) {
1332 octet buf
[FIPSTEST_BUFSZ
];
1336 generate(r
, sizeof(buf
), genbuf
, &p
);
1338 if (rc
& FIPSTEST_MONOBIT
)
1339 moan("failed monobit test");
1340 if (rc
& FIPSTEST_POKER
)
1341 moan("failed poker test");
1342 if (rc
& FIPSTEST_RUNS
)
1343 moan("failed runs test");
1344 if (rc
& FIPSTEST_LONGRUNS
)
1345 moan("failed long runs test");
1346 if (!rc
&& (flags
& f_progress
))
1347 fputs("test passed\n", stderr
);
1348 return (rc ? EXIT_FAILURE
: 0);
1351 /* --- Do Maurer's test --- */
1353 if (flags
& f_maurer
) {
1359 static struct { double x
; const char *sig
; } sigtab
[] = {
1367 g
.n
= maurer_hi
- maurer_lo
+ 1;
1368 g
.m
= xmalloc(g
.n
* sizeof(maurer_ctx
));
1369 for (i
= 0; i
< g
.n
; i
++)
1370 maurer_init(&g
.m
[i
], i
+ maurer_lo
);
1371 bufsz
= (100 * maurer_hi
) << maurer_hi
;
1373 generate(r
, bufsz
, genmaurer
, &g
);
1375 for (i
= maurer_lo
; i
<= maurer_hi
; i
++) {
1376 double z
= maurer_done(&g
.m
[i
- maurer_lo
]);
1377 double zz
= fabs(z
);
1380 for (j
= 0; sigtab
[j
].sig
; j
++) {
1381 if (zz
> sigtab
[j
].x
) {
1383 moan("failed, bits = %u, sig = %s, Z_u = %g",
1384 i
, sigtab
[j
].sig
, z
);
1388 if (flags
& f_progress
)
1389 fprintf(stderr
, "bits = %u, Z_u = %g\n", i
, z
);
1396 /* --- Discard --- */
1398 if (flags
& f_discard
) {
1399 generate(r
, outsz
, 0, 0);
1403 /* --- Write to a file --- */
1406 if (!(flags
& f_file
) && isatty(STDOUT_FILENO
))
1407 die(EXIT_FAILURE
, "writing output to a terminal is a bad idea");
1410 generate(r
, outsz
, genfile
, outfp
);
1418 /*----- That's all, folks -------------------------------------------------*/