3 * $Id: rspit.c,v 1.21 2004/04/21 00:37:32 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 /*----- Header files ------------------------------------------------------*/
47 #include <mLib/darray.h>
48 #include <mLib/dstr.h>
49 #include <mLib/mdwopt.h>
50 #include <mLib/quis.h>
51 #include <mLib/report.h>
75 #include "skipjack-ofb.h"
78 #include "blowfish-ofb.h"
79 #include "twofish-ofb.h"
81 #include "cast128-ofb.h"
82 #include "cast256-ofb.h"
83 #include "noekeon-ofb.h"
84 #include "rijndael-ofb.h"
85 #include "rijndael192-ofb.h"
86 #include "rijndael256-ofb.h"
87 #include "safer-ofb.h"
88 #include "safersk-ofb.h"
89 #include "square-ofb.h"
90 #include "serpent-ofb.h"
92 #include "des-counter.h"
93 #include "des3-counter.h"
94 #include "rc2-counter.h"
95 #include "rc5-counter.h"
96 #include "mars-counter.h"
97 #include "skipjack-counter.h"
98 #include "tea-counter.h"
99 #include "xtea-counter.h"
100 #include "blowfish-counter.h"
101 #include "twofish-counter.h"
102 #include "idea-counter.h"
103 #include "cast128-counter.h"
104 #include "cast256-counter.h"
105 #include "noekeon-counter.h"
106 #include "rijndael-counter.h"
107 #include "rijndael192-counter.h"
108 #include "rijndael256-counter.h"
109 #include "safer-counter.h"
110 #include "safersk-counter.h"
111 #include "square-counter.h"
112 #include "serpent-counter.h"
118 #include "tiger-mgf.h"
119 #include "rmd128-mgf.h"
120 #include "rmd160-mgf.h"
121 #include "rmd256-mgf.h"
122 #include "rmd320-mgf.h"
126 /*----- Data structures ---------------------------------------------------*/
130 grand
*(*seed
)(unsigned /*i*/);
135 extern gen generators
[];
143 E(SKIPJACK, skipjack) \
146 E(BLOWFISH, blowfish) \
147 E(TWOFISH, twofish) \
149 E(CAST128, cast128) \
150 E(CAST256, cast256) \
153 E(SAFERSK, safersk) \
154 E(NOEKEON, noekeon) \
155 E(RIJNDAEL, rijndael) \
156 E(RIJNDAEL192, rijndael192) \
157 E(RIJNDAEL256, rijndael256) \
171 #define E(PRE, pre) CIPHER_##PRE,
172 enum { CIPHERS CIPHER__bogus
};
175 #define E(PRE, pre) HASH_##PRE,
176 enum { HASHES HASH__bogus
};
182 grand
*(*ofb
)(const void */
*k*/
, size_t /*sz*/);
183 grand
*(*counter
)(const void */
*k*/
, size_t /*sz*/);
185 #define E(PRE, pre) \
186 { pre##_keysz, PRE##_BLKSZ, pre##_ofbrand, pre##_counterrand },
194 grand
*(*mgf
)(const void */
*k*/
, size_t /*sz*/);
196 #define E(PRE, pre) \
197 { &pre, pre##_mgfkeysz, pre##_mgfrand },
202 /*----- Miscellaneous static data -----------------------------------------*/
205 static size_t outsz
= 0;
206 static unsigned maurer_lo
= 5, maurer_hi
= 8;
211 static unsigned flags
= 0;
213 #define f_progress 1u
218 #define f_discard 32u
220 /*----- Help options ------------------------------------------------------*/
222 static void usage(FILE *fp
)
224 pquis(fp
, "Usage: $ generator [options]\n");
227 static void version(FILE *fp
)
229 pquis(fp
, "$, Catacomb version " VERSION
"\n");
232 static void help(FILE *fp
)
238 Emits a stream of random bytes suitable for, well, all sorts of things.\n\
239 The primary objective is to be able to generate streams of input for\n\
240 statistical tests, such as Diehard.\n\
242 Options are specific to the particular generator, although there's a\n\
245 -h, --help Display this help message.\n\
246 -v, --version Display the program's version number.\n\
247 -u, --usage Display a useless usage message.\n\
249 -l, --list Show a list of the supported generators, with\n\
251 -f, --fipstest Run the FIPS 140-1 randomness test.\n\
252 -m, --maurer[=LO-HI] Run Maurer's universal statistical test.\n\
253 -o, --output FILE Write output to FILE, not stdout.\n\
254 -z, --size SIZE Emit SIZE bytes, not an unlimited number.\n\
255 -p, --progress Show a little progress meter (on stderr).\n\
256 -T, --timer Keep track of the CPU time used by the generator.\n\
257 -d, --discard Discard the generated output.\n\
259 (A SIZE may be followed by `g' for gigabytes, `m' for megabytes, or\n\
260 `k' for kilobytes. If unqualified, an amount in bytes is assumed.)\n\
264 /*----- Main options parser -----------------------------------------------*/
266 static struct option opts
[] = {
268 /* --- Standard GNU help options --- */
270 { "help", 0, 0, 'h' },
271 { "version", 0, 0, 'v' },
272 { "usage", 0, 0, 'u' },
274 /* --- Other useful things --- */
276 { "list", 0, 0, 'l' },
277 { "fipstest", 0, 0, 'f' },
278 { "maurer", OPTF_ARGOPT
, 0, 'm' },
279 { "output", OPTF_ARGREQ
, 0, 'o' },
280 { "size", OPTF_ARGREQ
, 0, 'z' },
281 { "progress", 0, 0, 'p' },
282 { "timer", 0, 0, 'T' },
283 { "discard", 0, 0, 'd' },
285 /* --- End of main table --- */
290 static const char *sopts
= "hvu lfm::o:z:pTd";
293 DA_DECL(option_v
, struct option
);
297 static option_v optv
= DA_INIT
;
298 static dstr optd
= DSTR_INIT
;
300 /* --- @addopts@ --- *
302 * Arguments: @const char *s@ = pointer to short options
303 * @struct option *l@ = pointer to long options
307 * Use: Adds a collection of options to the table.
310 static void addopts(const char *s
, struct option
*l
)
316 DA_PUSH(&optv
, *l
++);
324 * Returns: Next option from argument array.
326 * Use: Fetches options, handling the standard ones.
332 int i
= mdwopt(argc
, argv
, optd
.buf
, DA(&optv
), 0, 0, 0);
345 puts("Generators supported:");
346 for (g
= generators
; g
->name
; g
++)
347 printf(" %s %s\n", g
->name
, g
->help
);
357 unsigned long lo
, hi
;
358 lo
= strtoul(optarg
, &p
, 0);
359 if (*p
== '-' || *p
== ',')
360 hi
= strtoul(p
+ 1, &p
, 0);
363 if (*p
!= 0 || hi
< lo
|| lo
== 0)
364 die(EXIT_FAILURE
, "bad bit range `%s'", optarg
);
371 die(EXIT_FAILURE
, "already set an output file");
372 if (strcmp(optarg
, "-") == 0)
375 outfp
= fopen(optarg
, "w");
377 die(EXIT_FAILURE
, "couldn't open output file `%s': %s",
378 optarg
, strerror(errno
));
385 outsz
= strtoul(optarg
, &p
, 0);
387 die(EXIT_FAILURE
, "bad number `%s'", optarg
);
389 case 'G': case 'g': outsz
*= 1024;
390 case 'M': case 'm': outsz
*= 1024;
391 case 'K': case 'k': outsz
*= 1024;
395 die(EXIT_FAILURE
, "bad suffix `%s'", p
);
399 die(EXIT_FAILURE
, "bad suffix `%s'", p
);
416 /*----- Manglers for seed strings -----------------------------------------*/
420 * Arguments: @const char *p@ = pointer to input string
421 * @char **end@ = where the end goes
422 * @dstr *d@ = output buffer
426 * Use: Transforms a hex string into a chunk of binary data.
429 static void unhex(const char *p
, char **end
, dstr
*d
)
431 while (p
[0] && p
[1]) {
432 int x
= p
[0], y
= p
[1];
433 if ('0' <= x
&& x
<= '9') x
-= '0';
434 else if ('A' <= x
&& x
<= 'F') x
-= 'A' - 10;
435 else if ('a' <= x
&& x
<= 'f') x
-= 'a' - 10;
437 if ('0' <= y
&& y
<= '9') y
-= '0';
438 else if ('A' <= y
&& y
<= 'F') y
-= 'A' - 10;
439 else if ('a' <= y
&& y
<= 'f') y
-= 'a' - 10;
441 DPUTC(d
, (x
<< 4) + y
);
447 /* --- Generate a key --- */
449 static void textkey(dstr
*d
, const char *p
, const octet
*ksz
)
451 size_t sz
= strlen(p
);
454 die(EXIT_FAILURE
, "zero-length key string");
455 if (keysz(sz
, ksz
) != sz
)
459 rmd160_mgfinit(&g
, p
, sz
);
462 rmd160_mgfencrypt(&g
, 0, d
->buf
, sz
);
465 assert(((void)"I can't seem to choose a good key size",
466 keysz(d
->len
, ksz
) == d
->len
));
469 static void hexkey(dstr
*d
, const char *p
, const octet
*ksz
)
472 unhex(optarg
, &q
, d
);
474 die(EXIT_FAILURE
, "bad hex key `%s'", p
);
475 if (keysz(d
->len
, ksz
) != d
->len
)
476 die(EXIT_FAILURE
, "bad key length");
479 static void randkey(dstr
*d
, const octet
*ksz
)
481 size_t sz
= keysz(0, ksz
);
483 rand_get(RAND_GLOBAL
, d
->buf
, sz
);
487 /*----- Generators --------------------------------------------------------*/
489 /* --- Blum-Blum-Shub strong generator --- */
491 static grand
*gen_bbs(unsigned i
)
493 /* --- Default modulus --- *
495 * The factors of this number are
497 * @p = 1229936431484295969649886203367009966370895964206162032259292413@
498 * @7754313537966036459299022912838407755462506416274551744201653277@
499 * @313130311731673973886822067@
501 * @q = 9798171783943489959487301695884963889684294764514008432498259742@
502 * @5374320073594018817245784145742769603334292182227671519041431067@
503 * @61344781426317516045890159@
505 * Both %$p$% and %$q$% are prime; %$(p - 1)/2$% and %$(q - 1)/2$% have no
506 * common factors. They were found using this program, with random
509 * I hope that, by publishing these factors, I'll dissuade people from
510 * actually using this modulus in an attempt to attain real security. The
511 * program is quite quick at finding Blum numbers, so there's no excuse for
512 * not generating your own.
516 "12051128439013574251357214209433471144307319411973256935382082"
517 "84356405274180923922403660880355098909699130818163691602989614"
518 "90135716255689660470370755013177656905237112577648090277537209"
519 "93607817155427455344810369808478266925293635284364998010510985"
520 "0503830397166360721262431179505917248447259735253684659338653";
522 /* --- Other things --- */
526 unsigned bits
= 1024;
529 const char *kfile
= 0, *id
= 0, *ktype
= 0;
531 /* --- Parse options --- */
533 static struct option opts
[] = {
534 { "modulus", OPTF_ARGREQ
, 0, 'M' },
535 { "generate", 0, 0, 'g' },
536 { "seed", OPTF_ARGREQ
, 0, 's' },
537 { "bits", OPTF_ARGREQ
, 0, 'b' },
538 { "show", 0, 0, 'S' },
539 { "keyring", OPTF_ARGREQ
, 0, 'k' },
540 { "id", OPTF_ARGREQ
, 0, 'i' },
541 { "type", OPTF_ARGREQ
, 0, 't' },
545 addopts("M:gs:b:Sk:i:t:", opts
);
562 bits
= strtoul(optarg
, 0, 0);
564 die(EXIT_FAILURE
, "bad number of bits `%s'", optarg
);
586 /* --- Generate a modulus if one is requested --- */
590 m
= mp_readstring(MP_NEW
, mt
, &p
, 0);
591 if (!m
|| *p
|| (m
->v
[0] & 3) != 1)
592 die(EXIT_FAILURE
, "bad modulus `%s'", mt
);
593 /* Unfortunately I don't know how to test for a Blum integer */
594 } else if (kfile
|| id
|| ktype
) {
599 /* --- Open the key file --- */
603 if (key_open(&kf
, kfile
, KOPEN_READ
, key_moan
, 0)) {
604 die(EXIT_FAILURE
, "error opening key file `%s': %s",
605 kfile
, strerror(errno
));
608 /* --- Find the key --- */
611 if ((kk
= key_bytag(&kf
, id
)) == 0)
612 die(EXIT_FAILURE
, "key `%s' not found", id
);
616 if ((kk
= key_bytype(&kf
, ktype
)) == 0)
617 die(EXIT_FAILURE
, "no suitable key with type `%s' found", ktype
);
620 /* --- Read the key data --- */
622 if ((kk
->k
.e
& KF_ENCMASK
) != KENC_STRUCT
)
623 die(EXIT_FAILURE
, "key is not structured");
624 if ((kd
= key_structfind(&kk
->k
, "n")) == 0)
625 die(EXIT_FAILURE
, "key has no subkey `n'");
626 if ((kd
->e
& KF_ENCMASK
) != KENC_MP
)
627 die(EXIT_FAILURE
, "incompatible subkey encoding");
628 m
= MP_COPY(kd
->u
.m
);
633 if (bbs_gen(&bp
, bits
, &rand_global
, 0,
634 (flags
& f_progress
) ? pgen_ev
: 0, 0))
635 die(EXIT_FAILURE
, "modulus generation failed");
639 fputs("p = ", stderr
);
640 mp_writefile(bp
.p
, stderr
, 10);
641 fputs("\nq = ", stderr
);
642 mp_writefile(bp
.q
, stderr
, 10);
643 fputs("\nn = ", stderr
);
644 mp_writefile(bp
.n
, stderr
, 10);
652 /* --- Set up a seed --- */
655 x
= mprand(MP_NEW
, mp_bits(m
) - 1, &rand_global
, 1);
658 x
= mp_readstring(MP_NEW
, xt
, &p
, 0);
660 die(EXIT_FAILURE
, "bad modulus `%s'", xt
);
672 /* --- Catacomb's random number generator --- */
674 static grand
*gen_rand(unsigned i
)
676 grand
*r
= rand_create();
679 static struct option opts
[] = {
680 { "key", OPTF_ARGREQ
, 0, 'k' },
681 { "text", OPTF_ARGREQ
, 0, 't' },
682 { "hex", OPTF_ARGREQ
, 0, 'H' },
686 addopts("k:t:H:n", opts
);
688 r
->ops
->misc(r
, RAND_NOISESRC
, &noise_source
);
689 r
->ops
->misc(r
, RAND_SEED
, 160);
698 textkey(&d
, optarg
, rmd160_hmackeysz
);
699 r
->ops
->misc(r
, RAND_KEY
, d
.buf
, d
.len
);
702 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, optarg
, strlen(optarg
));
706 hexkey(&d
, optarg
, rmd160_hmackeysz
);
707 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, d
.buf
, d
.len
);
716 /* --- RC4 output --- */
718 static grand
*gen_rc4(unsigned i
)
723 static struct option opts
[] = {
724 { "key", OPTF_ARGREQ
, 0, 'k' },
725 { "hex", OPTF_ARGREQ
, 0, 'H' },
729 addopts("k:H:", opts
);
738 textkey(&d
, optarg
, rc4_keysz
);
742 hexkey(&d
, optarg
, rc4_keysz
);
750 randkey(&d
, rc4_keysz
);
751 r
= rc4_rand(d
.buf
, d
.len
);
756 /* --- SEAL output --- */
758 static grand
*gen_seal(unsigned i
)
764 static struct option opts
[] = {
765 { "key", OPTF_ARGREQ
, 0, 'k' },
766 { "hex", OPTF_ARGREQ
, 0, 'H' },
767 { "sequence", OPTF_ARGREQ
, 0, 'n' },
771 addopts("k:H:n:", opts
);
780 textkey(&d
, optarg
, seal_keysz
);
784 hexkey(&d
, optarg
, seal_keysz
);
788 n
= strtoul(optarg
, &p
, 0);
790 die(EXIT_FAILURE
, "bad number `%s'", optarg
);
798 randkey(&d
, seal_keysz
);
799 r
= seal_rand(d
.buf
, d
.len
, n
);
804 /* --- Output feedback generators --- */
806 static grand
*gen_ofb(unsigned i
)
812 static struct option opts
[] = {
813 { "key", OPTF_ARGREQ
, 0, 'k' },
814 { "hex", OPTF_ARGREQ
, 0, 'H' },
815 { "iv", OPTF_ARGREQ
, 0, 'i' },
819 addopts("k:H:i:", opts
);
828 textkey(&d
, optarg
, ciphertab
[i
].keysz
);
832 hexkey(&d
, optarg
, ciphertab
[i
].keysz
);
836 unhex(optarg
, &p
, &iv
);
838 die(EXIT_FAILURE
, "bad hex IV `%s'", optarg
);
846 randkey(&d
, ciphertab
[i
].keysz
);
847 r
= ciphertab
[i
].ofb(d
.buf
, d
.len
);
849 if (iv
.len
!= ciphertab
[i
].blksz
) {
850 die(EXIT_FAILURE
, "bad IV length %lu (must be %lu)",
851 (unsigned long)iv
.len
, (unsigned long)ciphertab
[i
].blksz
);
853 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, iv
.buf
);
861 /* --- Counter generators --- */
863 static grand
*gen_counter(unsigned i
)
869 static struct option opts
[] = {
870 { "key", OPTF_ARGREQ
, 0, 'k' },
871 { "hex", OPTF_ARGREQ
, 0, 'H' },
872 { "iv", OPTF_ARGREQ
, 0, 'i' },
876 addopts("k:H:i:", opts
);
885 textkey(&d
, optarg
, ciphertab
[i
].keysz
);
889 hexkey(&d
, optarg
, ciphertab
[i
].keysz
);
893 unhex(optarg
, &p
, &iv
);
895 die(EXIT_FAILURE
, "bad hex IV `%s'", optarg
);
903 randkey(&d
, ciphertab
[i
].keysz
);
904 r
= ciphertab
[i
].counter(d
.buf
, d
.len
);
906 if (iv
.len
!= ciphertab
[i
].blksz
) {
907 die(EXIT_FAILURE
, "bad IV length %lu (must be %lu)",
908 (unsigned long)iv
.len
, (unsigned long)ciphertab
[i
].blksz
);
910 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, iv
.buf
);
918 /* --- Mask generators --- */
920 static grand
*gen_mgf(unsigned i
)
926 static struct option opts
[] = {
927 { "key", OPTF_ARGREQ
, 0, 'k' },
928 { "hex", OPTF_ARGREQ
, 0, 'H' },
929 { "index", OPTF_ARGREQ
, 0, 'i' },
933 addopts("k:H:i:", opts
);
942 textkey(&d
, optarg
, hashtab
[i
].keysz
);
946 hexkey(&d
, optarg
, hashtab
[i
].keysz
);
950 c
= strtoul(optarg
, &p
, 0);
952 die(EXIT_FAILURE
, "bad index `%s'", optarg
);
960 randkey(&d
, hashtab
[i
].keysz
);
962 r
= hashtab
[i
].mgf(d
.buf
, d
.len
);
964 r
->ops
->misc(r
, GRAND_SEEDUINT32
, c
);
970 /* --- Fibonacci generator --- */
972 static grand
*gen_fib(unsigned i
)
979 static struct option opts
[] = {
980 { "seed", OPTF_ARGREQ
, 0, 's' },
992 s
= strtoul(optarg
, &p
, 0);
994 die(EXIT_FAILURE
, "bad integer `%s'", optarg
);
1001 r
= fibrand_create(s
);
1003 r
->ops
->misc(r
, GRAND_SEEDRAND
, &rand_global
);
1007 /* --- LC generator --- */
1009 static grand
*gen_lc(unsigned i
)
1015 static struct option opts
[] = {
1016 { "seed", OPTF_ARGREQ
, 0, 's' },
1020 addopts("s:", opts
);
1028 s
= strtoul(optarg
, &p
, 0);
1030 die(EXIT_FAILURE
, "bad integer `%s'", optarg
);
1039 s
= rand_global
.ops
->range(&rand_global
, LCRAND_P
);
1040 while (s
== LCRAND_FIXEDPT
);
1042 return (lcrand_create(s
));
1045 /* --- Basic options parser -- can't generate output --- */
1047 static grand
*gen_opts(unsigned i
)
1054 /*----- Generators table --------------------------------------------------*/
1056 gen generators
[] = {
1057 { "fibonacci", gen_fib
, 0,
1061 #define E(PRE, pre) \
1062 { #pre "-ofb", gen_ofb, CIPHER_##PRE, \
1063 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
1066 #define E(PRE, pre) \
1067 { #pre "-counter", gen_counter, CIPHER_##PRE, \
1068 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
1071 #define E(PRE, pre) \
1072 { #pre "-mgf", gen_mgf, HASH_##PRE, \
1073 "[-k KEY-PHRASE] [-H HEX-KEY] [-i INDEX]" },
1076 { "rc4", gen_rc4
, 0,
1077 "[-k KEY-PHRASE] [-H HEX-KEY]" },
1078 { "seal", gen_seal
, 0,
1079 "[-k KEY-PHRASE] [-H HEX-KEY] [-n SEQ]" },
1080 { "rand", gen_rand
, 0,
1081 "[-n] [-k KEY-PHRASE] [-t TEXT-BLOCK] [-H HEX-BLOCK]" },
1082 { "bbs", gen_bbs
, 0,
1083 "[-gS] [-s SEED] [-M MODULUS] [-b BITS] [-k KEYRING] [-i TAG] [-t TYPE]"
1088 static gen optsg
= { "options", gen_opts
, 0,
1089 "This message shouldn't be printed." };
1091 /*----- Random number generation ------------------------------------------*/
1093 static int genfile(const void *buf
, size_t sz
, void *p
)
1096 if (fwrite(buf
, 1, sz
, fp
) != sz
)
1097 die(EXIT_FAILURE
, "error writing to file: %s", strerror(errno
));
1101 static int genbuf(const void *buf
, size_t sz
, void *p
)
1104 memcpy(*pp
, buf
, sz
);
1109 typedef struct genmaurer_ctx
{
1114 static int genmaurer(const void *buf
, size_t sz
, void *p
)
1116 genmaurer_ctx
*g
= p
;
1119 for (i
= 0; i
< g
->n
; i
++)
1120 maurer_test(&g
->m
[i
], buf
, sz
);
1124 static int generate(grand
*r
, size_t outsz
,
1125 int (*func
)(const void *buf
, size_t sz
, void *p
),
1128 static char kmg
[] = { ' ', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 0 };
1130 unsigned percent
= 0;
1133 static char baton
[] = "-\\|/";
1138 /* --- Spit out random data --- */
1142 if (flags
& f_progress
) {
1143 char *errbuf
= xmalloc(BUFSIZ
);
1144 setvbuf(stderr
, errbuf
, _IOLBF
, BUFSIZ
);
1146 fprintf(stderr
, "[%*s] 0%% 0\r[/\b", 50, "");
1148 fputs("[ ] 0\r[/\b", stderr
);
1153 signal(SIGPIPE
, SIG_IGN
);
1158 size_t sz
= sizeof(buf
);
1159 clock_t c_start
, c_stop
;
1161 /* --- Emit a bufferful (or less) of data --- */
1164 if (sz
> outsz
- kb
)
1168 r
->ops
->fill(r
, buf
, sz
);
1170 clk
+= c_stop
- c_start
;
1171 if (func
&& (rc
= func(buf
, sz
, p
)) != 0)
1175 /* --- Update the display --- */
1177 if (flags
& f_progress
) {
1185 if (difftime(t
, last
) > 1.0) {
1189 fputs(" ] ", stderr
);
1191 unsigned pc
= kb
* 100.0 / outsz
;
1192 if (pc
> percent
|| percent
> 100 || difftime(t
, last
) > 1.0) {
1196 for (; percent
< (pc
& ~1); percent
+= 2)
1199 for (; pc
< 100; pc
+= 2)
1201 fprintf(stderr
, "] %3i%% ", percent
);
1209 while (q
> 8192 && kk
[1]) {
1213 fprintf(stderr
, "%4i%c\r[", q
, *kk
);
1216 for (pc
= 0; pc
< (percent
& ~1); pc
+= 2)
1225 if (percent
< 100) {
1226 putc(*bp
++, stderr
);
1234 /* --- Terminate the loop --- */
1236 } while (!outsz
|| kb
< outsz
);
1238 if (flags
& f_progress
)
1239 fputc('\n', stderr
);
1240 if (flags
& f_timer
) {
1241 fprintf(stderr
, "generated %lu bytes ", (unsigned long)outsz
);
1243 fputs("too quickly to measure\n", stderr
);
1246 double sec
= (double)clk
/CLOCKS_PER_SEC
;
1247 double bps
= (outsz
<< 3)/sec
;
1248 for (kk
= kmg
; bps
> 1024 && kk
[1]; kk
++, bps
/= 1024)
1250 fprintf(stderr
, "in %g secs (%g %cb/s)\n", sec
, bps
, *kk
);
1256 /*----- Main code ---------------------------------------------------------*/
1258 int main(int ac
, char *av
[])
1263 /* --- Initialize mLib --- */
1268 /* --- Set up the main Catacomb generator --- */
1270 rand_noisesrc(RAND_GLOBAL
, &noise_source
);
1271 rand_seed(RAND_GLOBAL
, 160);
1273 /* --- Initialize the options table --- */
1275 addopts(sopts
, opts
);
1280 /* --- Read the generator out of the first argument --- */
1282 if (argc
> 1 && *argv
[1] != '-') {
1283 const char *arg
= av
[1];
1284 size_t sz
= strlen(arg
);
1288 for (gg
= generators
; gg
->name
; gg
++) {
1289 if (strncmp(arg
, gg
->name
, sz
) == 0) {
1290 if (gg
->name
[sz
] == 0) {
1294 die(EXIT_FAILURE
, "ambiguous generator name `%s'", arg
);
1300 die(EXIT_FAILURE
, "unknown generator name `%s'", arg
);
1305 /* --- Get a generic random number generator --- */
1308 if (!r
|| optind
!= ac
- 1) {
1313 /* --- Do the FIPS test --- */
1315 if (flags
& f_fips
) {
1316 octet buf
[FIPSTEST_BUFSZ
];
1320 generate(r
, sizeof(buf
), genbuf
, &p
);
1322 if (rc
& FIPSTEST_MONOBIT
)
1323 moan("failed monobit test");
1324 if (rc
& FIPSTEST_POKER
)
1325 moan("failed poker test");
1326 if (rc
& FIPSTEST_RUNS
)
1327 moan("failed runs test");
1328 if (rc
& FIPSTEST_LONGRUNS
)
1329 moan("failed long runs test");
1330 if (!rc
&& (flags
& f_progress
))
1331 fputs("test passed\n", stderr
);
1332 return (rc ? EXIT_FAILURE
: 0);
1335 /* --- Do Maurer's test --- */
1337 if (flags
& f_maurer
) {
1343 static struct { double x
; const char *sig
; } sigtab
[] = {
1351 g
.n
= maurer_hi
- maurer_lo
+ 1;
1352 g
.m
= xmalloc(g
.n
* sizeof(maurer_ctx
));
1353 for (i
= 0; i
< g
.n
; i
++)
1354 maurer_init(&g
.m
[i
], i
+ maurer_lo
);
1355 bufsz
= (100 * maurer_hi
) << maurer_hi
;
1357 generate(r
, bufsz
, genmaurer
, &g
);
1359 for (i
= maurer_lo
; i
<= maurer_hi
; i
++) {
1360 double z
= maurer_done(&g
.m
[i
- maurer_lo
]);
1361 double zz
= fabs(z
);
1364 for (j
= 0; sigtab
[j
].sig
; j
++) {
1365 if (zz
> sigtab
[j
].x
) {
1367 moan("failed, bits = %u, sig = %s, Z_u = %g",
1368 i
, sigtab
[j
].sig
, z
);
1372 if (flags
& f_progress
)
1373 fprintf(stderr
, "bits = %u, Z_u = %g\n", i
, z
);
1380 /* --- Discard --- */
1382 if (flags
& f_discard
) {
1383 generate(r
, outsz
, 0, 0);
1387 /* --- Write to a file --- */
1390 if (!(flags
& f_file
) && isatty(STDOUT_FILENO
))
1391 die(EXIT_FAILURE
, "writing output to a terminal is a bad idea");
1394 generate(r
, outsz
, genfile
, outfp
);
1402 /*----- That's all, folks -------------------------------------------------*/