3 * $Id: rspit.c,v 1.7 2000/07/18 23:01:26 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.7 2000/07/18 23:01:26 mdw
34 * Improve progress indications, and allow user to choose chunk sizes for
37 * Revision 1.6 2000/07/15 20:53:35 mdw
38 * Add a load of new ciphers and hashes.
40 * Revision 1.5 2000/07/01 11:27:03 mdw
41 * Portability fix: don't assume that `stdout' is a constant expression.
42 * Remove old type name `bbs_param'.
44 * Revision 1.4 2000/06/17 12:08:28 mdw
45 * Restructure handling of cipher-based generators. Add counter-mode
46 * ciphers and MGF-1 hash functions. Add FIPS 140-1 and Maurer's tests.
48 * Revision 1.3 2000/02/12 18:21:03 mdw
49 * Overhaul of key management (again).
51 * Revision 1.2 1999/12/22 15:59:51 mdw
52 * New prime-search system. Read BBS keys from key files.
54 * Revision 1.1 1999/12/10 23:29:13 mdw
55 * Emit random numbers for statistical tests.
59 /*----- Header files ------------------------------------------------------*/
76 #include <mLib/darray.h>
77 #include <mLib/dstr.h>
78 #include <mLib/mdwopt.h>
79 #include <mLib/quis.h>
80 #include <mLib/report.h>
100 #include "des3-ofb.h"
103 #include "skipjack-ofb.h"
105 #include "xtea-ofb.h"
106 #include "blowfish-ofb.h"
107 #include "twofish-ofb.h"
108 #include "idea-ofb.h"
109 #include "cast128-ofb.h"
110 #include "cast256-ofb.h"
111 #include "rijndael-ofb.h"
112 #include "square-ofb.h"
113 #include "serpent-ofb.h"
115 #include "des-counter.h"
116 #include "des3-counter.h"
117 #include "rc2-counter.h"
118 #include "rc5-counter.h"
119 #include "skipjack-counter.h"
120 #include "tea-counter.h"
121 #include "xtea-counter.h"
122 #include "blowfish-counter.h"
123 #include "twofish-counter.h"
124 #include "idea-counter.h"
125 #include "cast128-counter.h"
126 #include "cast256-counter.h"
127 #include "rijndael-counter.h"
128 #include "square-counter.h"
129 #include "serpent-counter.h"
134 #include "tiger-mgf.h"
135 #include "rmd128-mgf.h"
136 #include "rmd160-mgf.h"
137 #include "rmd256-mgf.h"
138 #include "rmd320-mgf.h"
142 /*----- Data structures ---------------------------------------------------*/
146 grand
*(*seed
)(unsigned /*i*/);
151 static gen generators
[];
158 E(SKIPJACK, skipjack) \
161 E(BLOWFISH, blowfish) \
162 E(TWOFISH, twofish) \
164 E(CAST128, cast128) \
165 E(CAST256, cast256) \
167 E(RIJNDAEL, rijndael) \
180 #define E(PRE, pre) CIPHER_##PRE,
181 enum { CIPHERS CIPHER__bogus
};
184 #define E(PRE, pre) HASH_##PRE,
185 enum { HASHES HASH__bogus
};
191 grand
*(*ofb
)(const void */
*k*/
, size_t /*sz*/);
192 grand
*(*counter
)(const void */
*k*/
, size_t /*sz*/);
194 #define E(PRE, pre) \
195 { pre##_keysz, PRE##_BLKSZ, pre##_ofbrand, pre##_counterrand },
203 grand
*(*mgf
)(const void */
*k*/
, size_t /*sz*/);
205 #define E(PRE, pre) \
206 { &pre, pre##_mgfkeysz, pre##_mgfrand },
211 /*----- Miscellaneous static data -----------------------------------------*/
214 static size_t outsz
= 0;
215 static unsigned maurer_lo
= 5, maurer_hi
= 8;
220 static unsigned flags
= 0;
229 /*----- Help options ------------------------------------------------------*/
231 static void usage(FILE *fp
)
233 pquis(fp
, "Usage: $ generator [options]\n");
236 static void version(FILE *fp
)
238 pquis(fp
, "$, Catacomb version " VERSION
"\n");
241 static void help(FILE *fp
)
247 Emits a stream of random bytes suitable for, well, all sorts of things.\n\
248 The primary objective is to be able to generate streams of input for\n\
249 statistical tests, such as Diehard.\n\
251 Options are specific to the particular generator, although there's a\n\
254 -h, --help Display this help message.\n\
255 -v, --version Display the program's version number.\n\
256 -u, --usage Display a useless usage message.\n\
258 -l, --list Show a list of the supported generators, with\n\
260 -f, --fipstest Run the FIPS 140-1 randomness test.\n\
261 -m, --maurer[=LO,HI] Run Maurer's universal statistical test.\n\
262 -o, --output FILE Write output to FILE, not stdout.\n\
263 -z, --size SIZE Emit SIZE bytes, not an unlimited number.\n\
264 -p, --progress Show a little progress meter (on stderr).\n\
266 (A SIZE may be followed by `g' for gigabytes, `m' for megabytes, or\n\
267 `k' for kilobytes. If unqualified, an amount in bytes is assumed.)\n\
271 /*----- Main options parser -----------------------------------------------*/
273 static struct option opts
[] = {
275 /* --- Standard GNU help options --- */
277 { "help", 0, 0, 'h' },
278 { "version", 0, 0, 'v' },
279 { "usage", 0, 0, 'u' },
281 /* --- Other useful things --- */
283 { "list", 0, 0, 'l' },
284 { "fipstest", 0, 0, 'f' },
285 { "maurer", OPTF_ARGOPT
, 0, 'm' },
286 { "output", OPTF_ARGREQ
, 0, 'o' },
287 { "size", OPTF_ARGREQ
, 0, 'z' },
288 { "progress", 0, 0, 'p' },
290 /* --- End of main table --- */
295 static const char *sopts
= "hvu lfm::o:z:p";
298 DA_DECL(option_v
, struct option
);
302 static option_v optv
= DA_INIT
;
303 static dstr optd
= DSTR_INIT
;
305 /* --- @addopts@ --- *
307 * Arguments: @const char *s@ = pointer to short options
308 * @struct option *l@ = pointer to long options
312 * Use: Adds a collection of options to the table.
315 static void addopts(const char *s
, struct option
*l
)
321 DA_PUSH(&optv
, *l
++);
329 * Returns: Next option from argument array.
331 * Use: Fetches options, handling the standard ones.
337 int i
= mdwopt(argc
, argv
, optd
.buf
, DA(&optv
), 0, 0, 0);
350 puts("Generators supported:");
351 for (g
= generators
; g
->name
; g
++)
352 printf(" %s %s\n", g
->name
, g
->help
);
362 unsigned long lo
, hi
;
363 lo
= strtoul(optarg
, &p
, 0);
365 hi
= strtoul(p
+ 1, &p
, 0);
368 if (*p
!= 0 || hi
< lo
|| lo
== 0)
369 die(EXIT_FAILURE
, "bad bit range `%s'", optarg
);
376 die(EXIT_FAILURE
, "already set an output file");
377 if (strcmp(optarg
, "-") == 0)
380 outfp
= fopen(optarg
, "w");
382 die(EXIT_FAILURE
, "couldn't open output file `%s': %s",
383 optarg
, strerror(errno
));
390 outsz
= strtoul(optarg
, &p
, 0);
392 die(EXIT_FAILURE
, "bad number `%s'", optarg
);
394 case 'G': case 'g': outsz
*= 1024;
395 case 'M': case 'm': outsz
*= 1024;
396 case 'K': case 'k': outsz
*= 1024;
400 die(EXIT_FAILURE
, "bad suffix `%s'", p
);
404 die(EXIT_FAILURE
, "bad suffix `%s'", p
);
415 /*----- Manglers for seed strings -----------------------------------------*/
419 * Arguments: @const char *p@ = pointer to input string
420 * @char **end@ = where the end goes
421 * @dstr *d@ = output buffer
425 * Use: Transforms a hex string into a chunk of binary data.
428 static void unhex(const char *p
, char **end
, dstr
*d
)
430 while (p
[0] && p
[1]) {
431 int x
= p
[0], y
= p
[1];
432 if ('0' <= x
&& x
<= '9') x
-= '0';
433 else if ('A' <= x
&& x
<= 'F') x
-= 'A' - 10;
434 else if ('a' <= x
&& x
<= 'f') x
-= 'a' - 10;
436 if ('0' <= y
&& y
<= '9') y
-= '0';
437 else if ('A' <= y
&& y
<= 'F') y
-= 'A' - 10;
438 else if ('a' <= y
&& y
<= 'f') y
-= 'a' - 10;
440 DPUTC(d
, (x
<< 4) + y
);
446 /* --- Generate a key --- */
448 static void textkey(dstr
*d
, const char *p
, const octet
*ksz
)
450 size_t sz
= strlen(p
);
453 die(EXIT_FAILURE
, "zero-length key string");
454 if (keysz(sz
, ksz
) != sz
)
458 rmd160_mgfinit(&g
, p
, sz
);
461 rmd160_mgfencrypt(&g
, 0, d
->buf
, sz
);
464 assert(((void)"I can't seem to choose a good key size",
465 keysz(d
->len
, ksz
) == d
->len
));
468 static void hexkey(dstr
*d
, const char *p
, const octet
*ksz
)
471 unhex(optarg
, &q
, d
);
473 die(EXIT_FAILURE
, "bad hex key `%s'", p
);
474 if (keysz(d
->len
, ksz
) != d
->len
)
475 die(EXIT_FAILURE
, "bad key length");
478 static void randkey(dstr
*d
, const octet
*ksz
)
480 size_t sz
= keysz(0, ksz
);
482 rand_get(RAND_GLOBAL
, d
->buf
, sz
);
486 /*----- Generators --------------------------------------------------------*/
488 /* --- Blum-Blum-Shub strong generator --- */
490 static grand
*gen_bbs(unsigned i
)
492 /* --- Default modulus --- *
494 * The factors of this number are
496 * @p = 1229936431484295969649886203367009966370895964206162032259292413@
497 * @7754313537966036459299022912838407755462506416274551744201653277@
498 * @313130311731673973886822067@
500 * @q = 9798171783943489959487301695884963889684294764514008432498259742@
501 * @5374320073594018817245784145742769603334292182227671519041431067@
502 * @61344781426317516045890159@
504 * Both %$p$% and %$q$% are prime; %$(p - 1)/2$% and %$(q - 1)/2$% have no
505 * common factors. They were found using this program, with random
508 * I hope that, by publishing these factors, I'll dissuade people from
509 * actually using this modulus in an attempt to attain real security. The
510 * program is quite quick at finding Blum numbers, so there's no excuse for
511 * not generating your own.
515 "120511284390135742513572142094334711443073194119732569353820828435640527418092392240366088035509890969913081816369160298961490135716255689660470370755013177656905237112577648090277537209936078171554274553448103698084782669252936352843649980105109850503830397166360721262431179505917248447259735253684659338653";
517 /* --- Other things --- */
521 unsigned bits
= 1024;
524 const char *kfile
= 0, *id
= 0, *ktype
= 0;
526 /* --- Parse options --- */
528 static struct option opts
[] = {
529 { "modulus", OPTF_ARGREQ
, 0, 'M' },
530 { "generate", 0, 0, 'g' },
531 { "seed", OPTF_ARGREQ
, 0, 's' },
532 { "bits", OPTF_ARGREQ
, 0, 'b' },
533 { "show", 0, 0, 'S' },
534 { "keyring", OPTF_ARGREQ
, 0, 'k' },
535 { "id", OPTF_ARGREQ
, 0, 'i' },
536 { "type", OPTF_ARGREQ
, 0, 't' },
540 addopts("M:gs:b:Sk:i:t:", opts
);
557 bits
= strtoul(optarg
, 0, 0);
559 die(EXIT_FAILURE
, "bad number of bits `%s'", optarg
);
581 /* --- Generate a modulus if one is requested --- */
585 m
= mp_readstring(MP_NEW
, mt
, &p
, 0);
586 if (!m
|| *p
|| (m
->v
[0] & 3) != 1)
587 die(EXIT_FAILURE
, "bad modulus `%s'", mt
);
588 /* Unfortunately I don't know how to test for a Blum integer */
589 } else if (kfile
|| id
|| ktype
) {
594 /* --- Open the key file --- */
598 if (key_open(&kf
, kfile
, KOPEN_READ
, key_moan
, 0)) {
599 die(EXIT_FAILURE
, "error opening key file `%s': %s",
600 kfile
, strerror(errno
));
603 /* --- Find the key --- */
606 if ((kk
= key_bytag(&kf
, id
)) == 0)
607 die(EXIT_FAILURE
, "key `%s' not found", id
);
611 if ((kk
= key_bytype(&kf
, ktype
)) == 0)
612 die(EXIT_FAILURE
, "no suitable key with type `%s' found", ktype
);
615 /* --- Read the key data --- */
617 if ((kk
->k
.e
& KF_ENCMASK
) != KENC_STRUCT
)
618 die(EXIT_FAILURE
, "key is not structured");
619 if ((kd
= key_structfind(&kk
->k
, "n")) == 0)
620 die(EXIT_FAILURE
, "key has no subkey `n'");
621 if ((kd
->e
& KF_ENCMASK
) != KENC_MP
)
622 die(EXIT_FAILURE
, "incomatible subkey encoding");
623 m
= MP_COPY(kd
->u
.m
);
628 if (bbs_gen(&bp
, bits
, &rand_global
, 0,
629 (flags
& f_progress
) ? pgen_ev
: 0, 0))
630 die(EXIT_FAILURE
, "modulus generation failed");
634 fputs("p = ", stderr
);
635 mp_writefile(bp
.p
, stderr
, 10);
636 fputs("\nq = ", stderr
);
637 mp_writefile(bp
.q
, stderr
, 10);
638 fputs("\nn = ", stderr
);
639 mp_writefile(bp
.n
, stderr
, 10);
647 /* --- Set up a seed --- */
650 x
= mprand(MP_NEW
, mp_bits(m
) - 1, &rand_global
, 1);
653 x
= mp_readstring(MP_NEW
, xt
, &p
, 0);
655 die(EXIT_FAILURE
, "bad modulus `%s'", xt
);
667 /* --- Catacomb's random number generator --- */
669 static grand
*gen_rand(unsigned i
)
671 grand
*r
= rand_create();
674 static struct option opts
[] = {
675 { "key", OPTF_ARGREQ
, 0, 'k' },
676 { "text", OPTF_ARGREQ
, 0, 't' },
677 { "hex", OPTF_ARGREQ
, 0, 'H' },
681 addopts("k:t:H:n", opts
);
683 r
->ops
->misc(r
, RAND_NOISESRC
, &noise_source
);
684 r
->ops
->misc(r
, RAND_SEED
, 160);
693 textkey(&d
, optarg
, rmd160_mackeysz
);
694 r
->ops
->misc(r
, RAND_KEY
, d
.buf
, d
.len
);
697 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, optarg
, strlen(optarg
));
701 hexkey(&d
, optarg
, rmd160_mackeysz
);
702 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, d
.buf
, d
.len
);
711 /* --- RC4 output --- */
713 static grand
*gen_rc4(unsigned i
)
718 static struct option opts
[] = {
719 { "key", OPTF_ARGREQ
, 0, 'k' },
720 { "hex", OPTF_ARGREQ
, 0, 'H' },
724 addopts("k:H:", opts
);
733 textkey(&d
, optarg
, rc4_keysz
);
737 hexkey(&d
, optarg
, rc4_keysz
);
745 randkey(&d
, rc4_keysz
);
746 r
= rc4_rand(d
.buf
, d
.len
);
751 /* --- SEAL output --- */
753 static grand
*gen_seal(unsigned i
)
759 static struct option opts
[] = {
760 { "key", OPTF_ARGREQ
, 0, 'k' },
761 { "hex", OPTF_ARGREQ
, 0, 'H' },
762 { "sequence", OPTF_ARGREQ
, 0, 'n' },
766 addopts("k:H:n:", opts
);
775 textkey(&d
, optarg
, seal_keysz
);
779 hexkey(&d
, optarg
, seal_keysz
);
783 n
= strtoul(optarg
, &p
, 0);
785 die(EXIT_FAILURE
, "bad number `%s'", optarg
);
793 randkey(&d
, seal_keysz
);
794 r
= seal_rand(d
.buf
, d
.len
, n
);
799 /* --- Output feedback generators --- */
801 static grand
*gen_ofb(unsigned i
)
807 static struct option opts
[] = {
808 { "key", OPTF_ARGREQ
, 0, 'k' },
809 { "hex", OPTF_ARGREQ
, 0, 'H' },
810 { "iv", OPTF_ARGREQ
, 0, 'i' },
814 addopts("k:H:i:", opts
);
823 textkey(&d
, optarg
, ciphertab
[i
].keysz
);
827 hexkey(&d
, optarg
, ciphertab
[i
].keysz
);
831 unhex(optarg
, &p
, &iv
);
833 die(EXIT_FAILURE
, "bad hex IV `%s'", optarg
);
841 randkey(&d
, ciphertab
[i
].keysz
);
842 r
= ciphertab
[i
].ofb(d
.buf
, d
.len
);
844 if (iv
.len
!= ciphertab
[i
].blksz
) {
845 die(EXIT_FAILURE
, "bad IV length %lu (must be %lu)",
846 (unsigned long)iv
.len
, (unsigned long)ciphertab
[i
].blksz
);
848 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, iv
.buf
);
856 /* --- Counter generators --- */
858 static grand
*gen_counter(unsigned i
)
864 static struct option opts
[] = {
865 { "key", OPTF_ARGREQ
, 0, 'k' },
866 { "hex", OPTF_ARGREQ
, 0, 'H' },
867 { "iv", OPTF_ARGREQ
, 0, 'i' },
871 addopts("k:H:i:", opts
);
880 textkey(&d
, optarg
, ciphertab
[i
].keysz
);
884 hexkey(&d
, optarg
, ciphertab
[i
].keysz
);
888 unhex(optarg
, &p
, &iv
);
890 die(EXIT_FAILURE
, "bad hex IV `%s'", optarg
);
898 randkey(&d
, ciphertab
[i
].keysz
);
899 r
= ciphertab
[i
].counter(d
.buf
, d
.len
);
901 if (iv
.len
!= ciphertab
[i
].blksz
) {
902 die(EXIT_FAILURE
, "bad IV length %lu (must be %lu)",
903 (unsigned long)iv
.len
, (unsigned long)ciphertab
[i
].blksz
);
905 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, iv
.buf
);
913 /* --- Mask generators --- */
915 static grand
*gen_mgf(unsigned i
)
921 static struct option opts
[] = {
922 { "key", OPTF_ARGREQ
, 0, 'k' },
923 { "hex", OPTF_ARGREQ
, 0, 'H' },
924 { "index", OPTF_ARGREQ
, 0, 'i' },
928 addopts("k:H:i:", opts
);
937 textkey(&d
, optarg
, hashtab
[i
].keysz
);
941 hexkey(&d
, optarg
, hashtab
[i
].keysz
);
945 c
= strtoul(optarg
, &p
, 0);
947 die(EXIT_FAILURE
, "bad index `%s'", optarg
);
955 randkey(&d
, hashtab
[i
].keysz
);
957 r
= hashtab
[i
].mgf(d
.buf
, d
.len
);
959 r
->ops
->misc(r
, GRAND_SEEDUINT32
, c
);
965 /* --- Fibonacci generator --- */
967 static grand
*gen_fib(unsigned i
)
974 static struct option opts
[] = {
975 { "seed", OPTF_ARGREQ
, 0, 's' },
987 s
= strtoul(optarg
, &p
, 0);
989 die(EXIT_FAILURE
, "bad integer `%s'", optarg
);
996 r
= fibrand_create(s
);
998 r
->ops
->misc(r
, GRAND_SEEDRAND
, &rand_global
);
1002 /* --- LC generator --- */
1004 static grand
*gen_lc(unsigned i
)
1010 static struct option opts
[] = {
1011 { "seed", OPTF_ARGREQ
, 0, 's' },
1015 addopts("s:", opts
);
1023 s
= strtoul(optarg
, &p
, 0);
1025 die(EXIT_FAILURE
, "bad integer `%s'", optarg
);
1034 s
= rand_global
.ops
->range(&rand_global
, LCRAND_P
);
1035 while (s
== LCRAND_FIXEDPT
);
1037 return (lcrand_create(s
));
1040 /* --- Basic options parser -- can't generate output --- */
1042 static grand
*gen_opts(unsigned i
)
1049 /*----- Generators table --------------------------------------------------*/
1051 static gen generators
[] = {
1052 { "fibonacci", gen_fib
, 0,
1056 #define E(PRE, pre) \
1057 { #pre "-ofb", gen_ofb, CIPHER_##PRE, \
1058 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
1061 #define E(PRE, pre) \
1062 { #pre "-counter", gen_counter, CIPHER_##PRE, \
1063 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
1066 #define E(PRE, pre) \
1067 { #pre "-mgf", gen_mgf, HASH_##PRE, \
1068 "[-k KEY-PHRASE] [-H HEX-KEY] [-i INDEX]" },
1071 { "rc4", gen_rc4
, 0,
1072 "[-k KEY-PHRASE] [-H HEX-KEY]" },
1073 { "seal", gen_seal
, 0,
1074 "[-k KEY-PHRASE] [-H HEX-KEY] [-n SEQ]" },
1075 { "rand", gen_rand
, 0,
1076 "[-n] [-k KEY-PHRASE] [-t TEXT-BLOCK] [-H HEX-BLOCK]" },
1077 { "bbs", gen_bbs
, 0,
1078 "[-gS] [-s SEED] [-M MODULUS] [-b BITS] [-k KEYRING] [-i TAG] [-t TYPE]"
1083 static gen optsg
= { "options", gen_opts
, 0,
1084 "This message shouldn't be printed." };
1086 /*----- Random number generation ------------------------------------------*/
1088 static int genfile(const void *buf
, size_t sz
, void *p
)
1091 if (fwrite(buf
, 1, sz
, fp
) != sz
)
1092 die(EXIT_FAILURE
, "error writing to file: %s", strerror(errno
));
1096 static int genbuf(const void *buf
, size_t sz
, void *p
)
1099 memcpy(*pp
, buf
, sz
);
1104 static int generate(grand
*r
, size_t outsz
,
1105 int (*func
)(const void *buf
, size_t sz
, void *p
),
1108 unsigned percent
= 0;
1111 static char baton
[] = "-\\|/";
1115 /* --- Spit out random data --- */
1119 if (flags
& f_progress
) {
1120 char *errbuf
= xmalloc(BUFSIZ
);
1121 setvbuf(stderr
, errbuf
, _IOLBF
, BUFSIZ
);
1123 fprintf(stderr
, "[%*s] 0%% 0\r[/\b", 50, "");
1125 fputs("[ ] 0\r[/\b", stderr
);
1130 signal(SIGPIPE
, SIG_IGN
);
1135 size_t sz
= sizeof(buf
);
1137 /* --- Emit a bufferful (or less) of data --- */
1140 if (sz
> outsz
- kb
)
1143 r
->ops
->fill(r
, buf
, sz
);
1144 if ((rc
= func(buf
, sz
, p
)) != 0)
1148 /* --- Update the display --- */
1150 if (flags
& f_progress
) {
1158 if (difftime(t
, last
) > 1.0) {
1162 fputs(" ] ", stderr
);
1164 unsigned pc
= kb
* 100.0 / outsz
;
1165 if (pc
> percent
|| percent
> 100 || difftime(t
, last
) > 1.0) {
1169 for (; percent
< (pc
& ~1); percent
+= 2)
1172 for (; pc
< 100; pc
+= 2)
1174 fprintf(stderr
, "] %3i%% ", percent
);
1181 char *suff
= " KMG";
1182 while (q
> 8192 && suff
[1]) {
1186 fprintf(stderr
, "%4i%c\r[", q
, *suff
);
1189 for (pc
= 0; pc
< (percent
& ~1); pc
+= 2)
1198 if (percent
< 100) {
1199 putc(*bp
++, stderr
);
1207 /* --- Terminate the loop --- */
1209 if (outsz
&& kb
>= outsz
)
1213 if (flags
& f_progress
)
1214 fputc('\n', stderr
);
1218 /*----- Main code ---------------------------------------------------------*/
1220 int main(int ac
, char *av
[])
1225 /* --- Initialize mLib --- */
1230 /* --- Set up the main Catacomb generator --- */
1232 rand_noisesrc(RAND_GLOBAL
, &noise_source
);
1233 rand_seed(RAND_GLOBAL
, 160);
1235 /* --- Initialize the options table --- */
1237 addopts(sopts
, opts
);
1242 /* --- Read the generator out of the first argument --- */
1244 if (argc
> 1 && *argv
[1] != '-') {
1245 const char *arg
= av
[1];
1246 size_t sz
= strlen(arg
);
1250 for (gg
= generators
; gg
->name
; gg
++) {
1251 if (strncmp(arg
, gg
->name
, sz
) == 0) {
1252 if (gg
->name
[sz
] == 0) {
1256 die(EXIT_FAILURE
, "ambiguous generator name `%s'", arg
);
1262 die(EXIT_FAILURE
, "unknown generator name `%s'", arg
);
1267 /* --- Get a generic random number generator --- */
1270 if (!r
|| optind
!= ac
- 1) {
1275 /* --- Do the FIPS test --- */
1277 if (flags
& f_fips
) {
1278 octet buf
[FIPSTEST_BUFSZ
];
1282 generate(r
, sizeof(buf
), genbuf
, &p
);
1284 if (rc
& FIPSTEST_MONOBIT
)
1285 moan("failed monobit test");
1286 if (rc
& FIPSTEST_POKER
)
1287 moan("failed poker test");
1288 if (rc
& FIPSTEST_RUNS
)
1289 moan("failed runs test");
1290 if (rc
& FIPSTEST_LONGRUNS
)
1291 moan("failed long runs test");
1292 if (!rc
&& (flags
& f_progress
))
1293 puts("test passed");
1294 return (rc ? EXIT_FAILURE
: 0);
1297 /* --- Do Maurer's test --- */
1299 if (flags
& f_maurer
) {
1304 unsigned f
= 0, jj
= 0;
1308 static struct { double x
; const char *sig
; } sigtab
[] = {
1316 bufsz
= (100 * maurer_hi
) << maurer_hi
;
1317 if ((buf
= a_alloc(arena_global
, bufsz
)) == 0)
1318 die(EXIT_FAILURE
, "not enough memory for data buffer");
1320 generate(r
, bufsz
, genbuf
, &p
);
1322 for (i
= maurer_lo
; i
<= maurer_hi
; i
++) {
1323 double z
= maurer(buf
, bufsz
, i
);
1324 double zz
= fabs(z
);
1327 for (j
= 0; sigtab
[j
].sig
; j
++) {
1328 if (zz
> sigtab
[j
].x
) {
1329 if (zz
> fabs(maxz
)) {
1335 moan("failed, bits = %u, sig = %s, Z_u = %g",
1336 i
, sigtab
[j
].sig
, z
);
1340 if (flags
& f_progress
)
1341 printf("bits = %u, Z_u = %g\n", i
, z
);
1347 /* --- Write to a file --- */
1350 if (!(flags
& f_file
) && isatty(STDOUT_FILENO
))
1351 die(EXIT_FAILURE
, "writing output to a terminal is a bad idea");
1354 generate(r
, outsz
, genfile
, outfp
);
1362 /*----- That's all, folks -------------------------------------------------*/