3 * $Id: rspit.c,v 1.9 2000/08/04 23:24:15 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.9 2000/08/04 23:24:15 mdw
34 * Add a timer and a discard option.
36 * Revision 1.8 2000/07/29 22:05:47 mdw
37 * Fix error in help message about Maurer test syntax.
39 * Revision 1.7 2000/07/18 23:01:26 mdw
40 * Improve progress indications, and allow user to choose chunk sizes for
43 * Revision 1.6 2000/07/15 20:53:35 mdw
44 * Add a load of new ciphers and hashes.
46 * Revision 1.5 2000/07/01 11:27:03 mdw
47 * Portability fix: don't assume that `stdout' is a constant expression.
48 * Remove old type name `bbs_param'.
50 * Revision 1.4 2000/06/17 12:08:28 mdw
51 * Restructure handling of cipher-based generators. Add counter-mode
52 * ciphers and MGF-1 hash functions. Add FIPS 140-1 and Maurer's tests.
54 * Revision 1.3 2000/02/12 18:21:03 mdw
55 * Overhaul of key management (again).
57 * Revision 1.2 1999/12/22 15:59:51 mdw
58 * New prime-search system. Read BBS keys from key files.
60 * Revision 1.1 1999/12/10 23:29:13 mdw
61 * Emit random numbers for statistical tests.
65 /*----- Header files ------------------------------------------------------*/
82 #include <mLib/darray.h>
83 #include <mLib/dstr.h>
84 #include <mLib/mdwopt.h>
85 #include <mLib/quis.h>
86 #include <mLib/report.h>
106 #include "des3-ofb.h"
109 #include "skipjack-ofb.h"
111 #include "xtea-ofb.h"
112 #include "blowfish-ofb.h"
113 #include "twofish-ofb.h"
114 #include "idea-ofb.h"
115 #include "cast128-ofb.h"
116 #include "cast256-ofb.h"
117 #include "rijndael-ofb.h"
118 #include "square-ofb.h"
119 #include "serpent-ofb.h"
121 #include "des-counter.h"
122 #include "des3-counter.h"
123 #include "rc2-counter.h"
124 #include "rc5-counter.h"
125 #include "skipjack-counter.h"
126 #include "tea-counter.h"
127 #include "xtea-counter.h"
128 #include "blowfish-counter.h"
129 #include "twofish-counter.h"
130 #include "idea-counter.h"
131 #include "cast128-counter.h"
132 #include "cast256-counter.h"
133 #include "rijndael-counter.h"
134 #include "square-counter.h"
135 #include "serpent-counter.h"
140 #include "tiger-mgf.h"
141 #include "rmd128-mgf.h"
142 #include "rmd160-mgf.h"
143 #include "rmd256-mgf.h"
144 #include "rmd320-mgf.h"
148 /*----- Data structures ---------------------------------------------------*/
152 grand
*(*seed
)(unsigned /*i*/);
157 static gen generators
[];
164 E(SKIPJACK, skipjack) \
167 E(BLOWFISH, blowfish) \
168 E(TWOFISH, twofish) \
170 E(CAST128, cast128) \
171 E(CAST256, cast256) \
173 E(RIJNDAEL, rijndael) \
186 #define E(PRE, pre) CIPHER_##PRE,
187 enum { CIPHERS CIPHER__bogus
};
190 #define E(PRE, pre) HASH_##PRE,
191 enum { HASHES HASH__bogus
};
197 grand
*(*ofb
)(const void */
*k*/
, size_t /*sz*/);
198 grand
*(*counter
)(const void */
*k*/
, size_t /*sz*/);
200 #define E(PRE, pre) \
201 { pre##_keysz, PRE##_BLKSZ, pre##_ofbrand, pre##_counterrand },
209 grand
*(*mgf
)(const void */
*k*/
, size_t /*sz*/);
211 #define E(PRE, pre) \
212 { &pre, pre##_mgfkeysz, pre##_mgfrand },
217 /*----- Miscellaneous static data -----------------------------------------*/
220 static size_t outsz
= 0;
221 static unsigned maurer_lo
= 5, maurer_hi
= 8;
226 static unsigned flags
= 0;
237 /*----- Help options ------------------------------------------------------*/
239 static void usage(FILE *fp
)
241 pquis(fp
, "Usage: $ generator [options]\n");
244 static void version(FILE *fp
)
246 pquis(fp
, "$, Catacomb version " VERSION
"\n");
249 static void help(FILE *fp
)
255 Emits a stream of random bytes suitable for, well, all sorts of things.\n\
256 The primary objective is to be able to generate streams of input for\n\
257 statistical tests, such as Diehard.\n\
259 Options are specific to the particular generator, although there's a\n\
262 -h, --help Display this help message.\n\
263 -v, --version Display the program's version number.\n\
264 -u, --usage Display a useless usage message.\n\
266 -l, --list Show a list of the supported generators, with\n\
268 -f, --fipstest Run the FIPS 140-1 randomness test.\n\
269 -m, --maurer[=LO-HI] Run Maurer's universal statistical test.\n\
270 -o, --output FILE Write output to FILE, not stdout.\n\
271 -z, --size SIZE Emit SIZE bytes, not an unlimited number.\n\
272 -p, --progress Show a little progress meter (on stderr).\n\
273 -T, --timer Keep track of the CPU time used by the generator.\n\
274 -d, --discard Discard the generated output.\n\
276 (A SIZE may be followed by `g' for gigabytes, `m' for megabytes, or\n\
277 `k' for kilobytes. If unqualified, an amount in bytes is assumed.)\n\
281 /*----- Main options parser -----------------------------------------------*/
283 static struct option opts
[] = {
285 /* --- Standard GNU help options --- */
287 { "help", 0, 0, 'h' },
288 { "version", 0, 0, 'v' },
289 { "usage", 0, 0, 'u' },
291 /* --- Other useful things --- */
293 { "list", 0, 0, 'l' },
294 { "fipstest", 0, 0, 'f' },
295 { "maurer", OPTF_ARGOPT
, 0, 'm' },
296 { "output", OPTF_ARGREQ
, 0, 'o' },
297 { "size", OPTF_ARGREQ
, 0, 'z' },
298 { "progress", 0, 0, 'p' },
299 { "timer", 0, 0, 'T' },
300 { "discard", 0, 0, 'd' },
302 /* --- End of main table --- */
307 static const char *sopts
= "hvu lfm::o:z:pTd";
310 DA_DECL(option_v
, struct option
);
314 static option_v optv
= DA_INIT
;
315 static dstr optd
= DSTR_INIT
;
317 /* --- @addopts@ --- *
319 * Arguments: @const char *s@ = pointer to short options
320 * @struct option *l@ = pointer to long options
324 * Use: Adds a collection of options to the table.
327 static void addopts(const char *s
, struct option
*l
)
333 DA_PUSH(&optv
, *l
++);
341 * Returns: Next option from argument array.
343 * Use: Fetches options, handling the standard ones.
349 int i
= mdwopt(argc
, argv
, optd
.buf
, DA(&optv
), 0, 0, 0);
362 puts("Generators supported:");
363 for (g
= generators
; g
->name
; g
++)
364 printf(" %s %s\n", g
->name
, g
->help
);
374 unsigned long lo
, hi
;
375 lo
= strtoul(optarg
, &p
, 0);
377 hi
= strtoul(p
+ 1, &p
, 0);
380 if (*p
!= 0 || hi
< lo
|| lo
== 0)
381 die(EXIT_FAILURE
, "bad bit range `%s'", optarg
);
388 die(EXIT_FAILURE
, "already set an output file");
389 if (strcmp(optarg
, "-") == 0)
392 outfp
= fopen(optarg
, "w");
394 die(EXIT_FAILURE
, "couldn't open output file `%s': %s",
395 optarg
, strerror(errno
));
402 outsz
= strtoul(optarg
, &p
, 0);
404 die(EXIT_FAILURE
, "bad number `%s'", optarg
);
406 case 'G': case 'g': outsz
*= 1024;
407 case 'M': case 'm': outsz
*= 1024;
408 case 'K': case 'k': outsz
*= 1024;
412 die(EXIT_FAILURE
, "bad suffix `%s'", p
);
416 die(EXIT_FAILURE
, "bad suffix `%s'", p
);
433 /*----- Manglers for seed strings -----------------------------------------*/
437 * Arguments: @const char *p@ = pointer to input string
438 * @char **end@ = where the end goes
439 * @dstr *d@ = output buffer
443 * Use: Transforms a hex string into a chunk of binary data.
446 static void unhex(const char *p
, char **end
, dstr
*d
)
448 while (p
[0] && p
[1]) {
449 int x
= p
[0], y
= p
[1];
450 if ('0' <= x
&& x
<= '9') x
-= '0';
451 else if ('A' <= x
&& x
<= 'F') x
-= 'A' - 10;
452 else if ('a' <= x
&& x
<= 'f') x
-= 'a' - 10;
454 if ('0' <= y
&& y
<= '9') y
-= '0';
455 else if ('A' <= y
&& y
<= 'F') y
-= 'A' - 10;
456 else if ('a' <= y
&& y
<= 'f') y
-= 'a' - 10;
458 DPUTC(d
, (x
<< 4) + y
);
464 /* --- Generate a key --- */
466 static void textkey(dstr
*d
, const char *p
, const octet
*ksz
)
468 size_t sz
= strlen(p
);
471 die(EXIT_FAILURE
, "zero-length key string");
472 if (keysz(sz
, ksz
) != sz
)
476 rmd160_mgfinit(&g
, p
, sz
);
479 rmd160_mgfencrypt(&g
, 0, d
->buf
, sz
);
482 assert(((void)"I can't seem to choose a good key size",
483 keysz(d
->len
, ksz
) == d
->len
));
486 static void hexkey(dstr
*d
, const char *p
, const octet
*ksz
)
489 unhex(optarg
, &q
, d
);
491 die(EXIT_FAILURE
, "bad hex key `%s'", p
);
492 if (keysz(d
->len
, ksz
) != d
->len
)
493 die(EXIT_FAILURE
, "bad key length");
496 static void randkey(dstr
*d
, const octet
*ksz
)
498 size_t sz
= keysz(0, ksz
);
500 rand_get(RAND_GLOBAL
, d
->buf
, sz
);
504 /*----- Generators --------------------------------------------------------*/
506 /* --- Blum-Blum-Shub strong generator --- */
508 static grand
*gen_bbs(unsigned i
)
510 /* --- Default modulus --- *
512 * The factors of this number are
514 * @p = 1229936431484295969649886203367009966370895964206162032259292413@
515 * @7754313537966036459299022912838407755462506416274551744201653277@
516 * @313130311731673973886822067@
518 * @q = 9798171783943489959487301695884963889684294764514008432498259742@
519 * @5374320073594018817245784145742769603334292182227671519041431067@
520 * @61344781426317516045890159@
522 * Both %$p$% and %$q$% are prime; %$(p - 1)/2$% and %$(q - 1)/2$% have no
523 * common factors. They were found using this program, with random
526 * I hope that, by publishing these factors, I'll dissuade people from
527 * actually using this modulus in an attempt to attain real security. The
528 * program is quite quick at finding Blum numbers, so there's no excuse for
529 * not generating your own.
533 "120511284390135742513572142094334711443073194119732569353820828435640527418092392240366088035509890969913081816369160298961490135716255689660470370755013177656905237112577648090277537209936078171554274553448103698084782669252936352843649980105109850503830397166360721262431179505917248447259735253684659338653";
535 /* --- Other things --- */
539 unsigned bits
= 1024;
542 const char *kfile
= 0, *id
= 0, *ktype
= 0;
544 /* --- Parse options --- */
546 static struct option opts
[] = {
547 { "modulus", OPTF_ARGREQ
, 0, 'M' },
548 { "generate", 0, 0, 'g' },
549 { "seed", OPTF_ARGREQ
, 0, 's' },
550 { "bits", OPTF_ARGREQ
, 0, 'b' },
551 { "show", 0, 0, 'S' },
552 { "keyring", OPTF_ARGREQ
, 0, 'k' },
553 { "id", OPTF_ARGREQ
, 0, 'i' },
554 { "type", OPTF_ARGREQ
, 0, 't' },
558 addopts("M:gs:b:Sk:i:t:", opts
);
575 bits
= strtoul(optarg
, 0, 0);
577 die(EXIT_FAILURE
, "bad number of bits `%s'", optarg
);
599 /* --- Generate a modulus if one is requested --- */
603 m
= mp_readstring(MP_NEW
, mt
, &p
, 0);
604 if (!m
|| *p
|| (m
->v
[0] & 3) != 1)
605 die(EXIT_FAILURE
, "bad modulus `%s'", mt
);
606 /* Unfortunately I don't know how to test for a Blum integer */
607 } else if (kfile
|| id
|| ktype
) {
612 /* --- Open the key file --- */
616 if (key_open(&kf
, kfile
, KOPEN_READ
, key_moan
, 0)) {
617 die(EXIT_FAILURE
, "error opening key file `%s': %s",
618 kfile
, strerror(errno
));
621 /* --- Find the key --- */
624 if ((kk
= key_bytag(&kf
, id
)) == 0)
625 die(EXIT_FAILURE
, "key `%s' not found", id
);
629 if ((kk
= key_bytype(&kf
, ktype
)) == 0)
630 die(EXIT_FAILURE
, "no suitable key with type `%s' found", ktype
);
633 /* --- Read the key data --- */
635 if ((kk
->k
.e
& KF_ENCMASK
) != KENC_STRUCT
)
636 die(EXIT_FAILURE
, "key is not structured");
637 if ((kd
= key_structfind(&kk
->k
, "n")) == 0)
638 die(EXIT_FAILURE
, "key has no subkey `n'");
639 if ((kd
->e
& KF_ENCMASK
) != KENC_MP
)
640 die(EXIT_FAILURE
, "incomatible subkey encoding");
641 m
= MP_COPY(kd
->u
.m
);
646 if (bbs_gen(&bp
, bits
, &rand_global
, 0,
647 (flags
& f_progress
) ? pgen_ev
: 0, 0))
648 die(EXIT_FAILURE
, "modulus generation failed");
652 fputs("p = ", stderr
);
653 mp_writefile(bp
.p
, stderr
, 10);
654 fputs("\nq = ", stderr
);
655 mp_writefile(bp
.q
, stderr
, 10);
656 fputs("\nn = ", stderr
);
657 mp_writefile(bp
.n
, stderr
, 10);
665 /* --- Set up a seed --- */
668 x
= mprand(MP_NEW
, mp_bits(m
) - 1, &rand_global
, 1);
671 x
= mp_readstring(MP_NEW
, xt
, &p
, 0);
673 die(EXIT_FAILURE
, "bad modulus `%s'", xt
);
685 /* --- Catacomb's random number generator --- */
687 static grand
*gen_rand(unsigned i
)
689 grand
*r
= rand_create();
692 static struct option opts
[] = {
693 { "key", OPTF_ARGREQ
, 0, 'k' },
694 { "text", OPTF_ARGREQ
, 0, 't' },
695 { "hex", OPTF_ARGREQ
, 0, 'H' },
699 addopts("k:t:H:n", opts
);
701 r
->ops
->misc(r
, RAND_NOISESRC
, &noise_source
);
702 r
->ops
->misc(r
, RAND_SEED
, 160);
711 textkey(&d
, optarg
, rmd160_mackeysz
);
712 r
->ops
->misc(r
, RAND_KEY
, d
.buf
, d
.len
);
715 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, optarg
, strlen(optarg
));
719 hexkey(&d
, optarg
, rmd160_mackeysz
);
720 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, d
.buf
, d
.len
);
729 /* --- RC4 output --- */
731 static grand
*gen_rc4(unsigned i
)
736 static struct option opts
[] = {
737 { "key", OPTF_ARGREQ
, 0, 'k' },
738 { "hex", OPTF_ARGREQ
, 0, 'H' },
742 addopts("k:H:", opts
);
751 textkey(&d
, optarg
, rc4_keysz
);
755 hexkey(&d
, optarg
, rc4_keysz
);
763 randkey(&d
, rc4_keysz
);
764 r
= rc4_rand(d
.buf
, d
.len
);
769 /* --- SEAL output --- */
771 static grand
*gen_seal(unsigned i
)
777 static struct option opts
[] = {
778 { "key", OPTF_ARGREQ
, 0, 'k' },
779 { "hex", OPTF_ARGREQ
, 0, 'H' },
780 { "sequence", OPTF_ARGREQ
, 0, 'n' },
784 addopts("k:H:n:", opts
);
793 textkey(&d
, optarg
, seal_keysz
);
797 hexkey(&d
, optarg
, seal_keysz
);
801 n
= strtoul(optarg
, &p
, 0);
803 die(EXIT_FAILURE
, "bad number `%s'", optarg
);
811 randkey(&d
, seal_keysz
);
812 r
= seal_rand(d
.buf
, d
.len
, n
);
817 /* --- Output feedback generators --- */
819 static grand
*gen_ofb(unsigned i
)
825 static struct option opts
[] = {
826 { "key", OPTF_ARGREQ
, 0, 'k' },
827 { "hex", OPTF_ARGREQ
, 0, 'H' },
828 { "iv", OPTF_ARGREQ
, 0, 'i' },
832 addopts("k:H:i:", opts
);
841 textkey(&d
, optarg
, ciphertab
[i
].keysz
);
845 hexkey(&d
, optarg
, ciphertab
[i
].keysz
);
849 unhex(optarg
, &p
, &iv
);
851 die(EXIT_FAILURE
, "bad hex IV `%s'", optarg
);
859 randkey(&d
, ciphertab
[i
].keysz
);
860 r
= ciphertab
[i
].ofb(d
.buf
, d
.len
);
862 if (iv
.len
!= ciphertab
[i
].blksz
) {
863 die(EXIT_FAILURE
, "bad IV length %lu (must be %lu)",
864 (unsigned long)iv
.len
, (unsigned long)ciphertab
[i
].blksz
);
866 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, iv
.buf
);
874 /* --- Counter generators --- */
876 static grand
*gen_counter(unsigned i
)
882 static struct option opts
[] = {
883 { "key", OPTF_ARGREQ
, 0, 'k' },
884 { "hex", OPTF_ARGREQ
, 0, 'H' },
885 { "iv", OPTF_ARGREQ
, 0, 'i' },
889 addopts("k:H:i:", opts
);
898 textkey(&d
, optarg
, ciphertab
[i
].keysz
);
902 hexkey(&d
, optarg
, ciphertab
[i
].keysz
);
906 unhex(optarg
, &p
, &iv
);
908 die(EXIT_FAILURE
, "bad hex IV `%s'", optarg
);
916 randkey(&d
, ciphertab
[i
].keysz
);
917 r
= ciphertab
[i
].counter(d
.buf
, d
.len
);
919 if (iv
.len
!= ciphertab
[i
].blksz
) {
920 die(EXIT_FAILURE
, "bad IV length %lu (must be %lu)",
921 (unsigned long)iv
.len
, (unsigned long)ciphertab
[i
].blksz
);
923 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, iv
.buf
);
931 /* --- Mask generators --- */
933 static grand
*gen_mgf(unsigned i
)
939 static struct option opts
[] = {
940 { "key", OPTF_ARGREQ
, 0, 'k' },
941 { "hex", OPTF_ARGREQ
, 0, 'H' },
942 { "index", OPTF_ARGREQ
, 0, 'i' },
946 addopts("k:H:i:", opts
);
955 textkey(&d
, optarg
, hashtab
[i
].keysz
);
959 hexkey(&d
, optarg
, hashtab
[i
].keysz
);
963 c
= strtoul(optarg
, &p
, 0);
965 die(EXIT_FAILURE
, "bad index `%s'", optarg
);
973 randkey(&d
, hashtab
[i
].keysz
);
975 r
= hashtab
[i
].mgf(d
.buf
, d
.len
);
977 r
->ops
->misc(r
, GRAND_SEEDUINT32
, c
);
983 /* --- Fibonacci generator --- */
985 static grand
*gen_fib(unsigned i
)
992 static struct option opts
[] = {
993 { "seed", OPTF_ARGREQ
, 0, 's' },
1005 s
= strtoul(optarg
, &p
, 0);
1007 die(EXIT_FAILURE
, "bad integer `%s'", optarg
);
1014 r
= fibrand_create(s
);
1016 r
->ops
->misc(r
, GRAND_SEEDRAND
, &rand_global
);
1020 /* --- LC generator --- */
1022 static grand
*gen_lc(unsigned i
)
1028 static struct option opts
[] = {
1029 { "seed", OPTF_ARGREQ
, 0, 's' },
1033 addopts("s:", opts
);
1041 s
= strtoul(optarg
, &p
, 0);
1043 die(EXIT_FAILURE
, "bad integer `%s'", optarg
);
1052 s
= rand_global
.ops
->range(&rand_global
, LCRAND_P
);
1053 while (s
== LCRAND_FIXEDPT
);
1055 return (lcrand_create(s
));
1058 /* --- Basic options parser -- can't generate output --- */
1060 static grand
*gen_opts(unsigned i
)
1067 /*----- Generators table --------------------------------------------------*/
1069 static gen generators
[] = {
1070 { "fibonacci", gen_fib
, 0,
1074 #define E(PRE, pre) \
1075 { #pre "-ofb", gen_ofb, CIPHER_##PRE, \
1076 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
1079 #define E(PRE, pre) \
1080 { #pre "-counter", gen_counter, CIPHER_##PRE, \
1081 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
1084 #define E(PRE, pre) \
1085 { #pre "-mgf", gen_mgf, HASH_##PRE, \
1086 "[-k KEY-PHRASE] [-H HEX-KEY] [-i INDEX]" },
1089 { "rc4", gen_rc4
, 0,
1090 "[-k KEY-PHRASE] [-H HEX-KEY]" },
1091 { "seal", gen_seal
, 0,
1092 "[-k KEY-PHRASE] [-H HEX-KEY] [-n SEQ]" },
1093 { "rand", gen_rand
, 0,
1094 "[-n] [-k KEY-PHRASE] [-t TEXT-BLOCK] [-H HEX-BLOCK]" },
1095 { "bbs", gen_bbs
, 0,
1096 "[-gS] [-s SEED] [-M MODULUS] [-b BITS] [-k KEYRING] [-i TAG] [-t TYPE]"
1101 static gen optsg
= { "options", gen_opts
, 0,
1102 "This message shouldn't be printed." };
1104 /*----- Random number generation ------------------------------------------*/
1106 static int genfile(const void *buf
, size_t sz
, void *p
)
1109 if (fwrite(buf
, 1, sz
, fp
) != sz
)
1110 die(EXIT_FAILURE
, "error writing to file: %s", strerror(errno
));
1114 static int genbuf(const void *buf
, size_t sz
, void *p
)
1117 memcpy(*pp
, buf
, sz
);
1122 static int generate(grand
*r
, size_t outsz
,
1123 int (*func
)(const void *buf
, size_t sz
, void *p
),
1126 static char kmg
[] = { ' ', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 0 };
1128 unsigned percent
= 0;
1131 static char baton
[] = "-\\|/";
1136 /* --- Spit out random data --- */
1140 if (flags
& f_progress
) {
1141 char *errbuf
= xmalloc(BUFSIZ
);
1142 setvbuf(stderr
, errbuf
, _IOLBF
, BUFSIZ
);
1144 fprintf(stderr
, "[%*s] 0%% 0\r[/\b", 50, "");
1146 fputs("[ ] 0\r[/\b", stderr
);
1151 signal(SIGPIPE
, SIG_IGN
);
1156 size_t sz
= sizeof(buf
);
1157 clock_t c_start
, c_stop
;
1159 /* --- Emit a bufferful (or less) of data --- */
1162 if (sz
> outsz
- kb
)
1166 r
->ops
->fill(r
, buf
, sz
);
1168 clk
+= c_stop
- c_start
;
1169 if (func
&& (rc
= func(buf
, sz
, p
)) != 0)
1173 /* --- Update the display --- */
1175 if (flags
& f_progress
) {
1183 if (difftime(t
, last
) > 1.0) {
1187 fputs(" ] ", stderr
);
1189 unsigned pc
= kb
* 100.0 / outsz
;
1190 if (pc
> percent
|| percent
> 100 || difftime(t
, last
) > 1.0) {
1194 for (; percent
< (pc
& ~1); percent
+= 2)
1197 for (; pc
< 100; pc
+= 2)
1199 fprintf(stderr
, "] %3i%% ", percent
);
1207 while (q
> 8192 && kk
[1]) {
1211 fprintf(stderr
, "%4i%c\r[", q
, *kk
);
1214 for (pc
= 0; pc
< (percent
& ~1); pc
+= 2)
1223 if (percent
< 100) {
1224 putc(*bp
++, stderr
);
1232 /* --- Terminate the loop --- */
1234 } while (!outsz
|| kb
< outsz
);
1236 if (flags
& f_progress
)
1237 fputc('\n', stderr
);
1238 if (flags
& f_timer
) {
1239 double sec
= (double)clk
/CLOCKS_PER_SEC
;
1240 double bps
= (outsz
<< 3)/sec
;
1243 for (kk
= kmg
; bps
> 1024 && kk
[1]; kk
++, bps
/= 1024)
1245 fprintf(stderr
, "generated %lu bytes in %g secs (%g %cb/s)\n",
1246 (unsigned long)outsz
, sec
, bps
, *kk
);
1251 /*----- Main code ---------------------------------------------------------*/
1253 int main(int ac
, char *av
[])
1258 /* --- Initialize mLib --- */
1263 /* --- Set up the main Catacomb generator --- */
1265 rand_noisesrc(RAND_GLOBAL
, &noise_source
);
1266 rand_seed(RAND_GLOBAL
, 160);
1268 /* --- Initialize the options table --- */
1270 addopts(sopts
, opts
);
1275 /* --- Read the generator out of the first argument --- */
1277 if (argc
> 1 && *argv
[1] != '-') {
1278 const char *arg
= av
[1];
1279 size_t sz
= strlen(arg
);
1283 for (gg
= generators
; gg
->name
; gg
++) {
1284 if (strncmp(arg
, gg
->name
, sz
) == 0) {
1285 if (gg
->name
[sz
] == 0) {
1289 die(EXIT_FAILURE
, "ambiguous generator name `%s'", arg
);
1295 die(EXIT_FAILURE
, "unknown generator name `%s'", arg
);
1300 /* --- Get a generic random number generator --- */
1303 if (!r
|| optind
!= ac
- 1) {
1308 /* --- Do the FIPS test --- */
1310 if (flags
& f_fips
) {
1311 octet buf
[FIPSTEST_BUFSZ
];
1315 generate(r
, sizeof(buf
), genbuf
, &p
);
1317 if (rc
& FIPSTEST_MONOBIT
)
1318 moan("failed monobit test");
1319 if (rc
& FIPSTEST_POKER
)
1320 moan("failed poker test");
1321 if (rc
& FIPSTEST_RUNS
)
1322 moan("failed runs test");
1323 if (rc
& FIPSTEST_LONGRUNS
)
1324 moan("failed long runs test");
1325 if (!rc
&& (flags
& f_progress
))
1326 fputs("test passed\n", stderr
);
1327 return (rc ? EXIT_FAILURE
: 0);
1330 /* --- Do Maurer's test --- */
1332 if (flags
& f_maurer
) {
1337 unsigned f
= 0, jj
= 0;
1341 static struct { double x
; const char *sig
; } sigtab
[] = {
1349 bufsz
= (100 * maurer_hi
) << maurer_hi
;
1350 if ((buf
= a_alloc(arena_global
, bufsz
)) == 0)
1351 die(EXIT_FAILURE
, "not enough memory for data buffer");
1353 generate(r
, bufsz
, genbuf
, &p
);
1355 for (i
= maurer_lo
; i
<= maurer_hi
; i
++) {
1356 double z
= maurer(buf
, bufsz
, i
);
1357 double zz
= fabs(z
);
1360 for (j
= 0; sigtab
[j
].sig
; j
++) {
1361 if (zz
> sigtab
[j
].x
) {
1362 if (zz
> fabs(maxz
)) {
1368 moan("failed, bits = %u, sig = %s, Z_u = %g",
1369 i
, sigtab
[j
].sig
, z
);
1373 if (flags
& f_progress
)
1374 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 -------------------------------------------------*/