3 * $Id: rspit.c,v 1.6 2000/07/15 20:53:35 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.6 2000/07/15 20:53:35 mdw
34 * Add a load of new ciphers and hashes.
36 * Revision 1.5 2000/07/01 11:27:03 mdw
37 * Portability fix: don't assume that `stdout' is a constant expression.
38 * Remove old type name `bbs_param'.
40 * Revision 1.4 2000/06/17 12:08:28 mdw
41 * Restructure handling of cipher-based generators. Add counter-mode
42 * ciphers and MGF-1 hash functions. Add FIPS 140-1 and Maurer's tests.
44 * Revision 1.3 2000/02/12 18:21:03 mdw
45 * Overhaul of key management (again).
47 * Revision 1.2 1999/12/22 15:59:51 mdw
48 * New prime-search system. Read BBS keys from key files.
50 * Revision 1.1 1999/12/10 23:29:13 mdw
51 * Emit random numbers for statistical tests.
55 /*----- Header files ------------------------------------------------------*/
72 #include <mLib/darray.h>
73 #include <mLib/dstr.h>
74 #include <mLib/mdwopt.h>
75 #include <mLib/quis.h>
76 #include <mLib/report.h>
99 #include "skipjack-ofb.h"
101 #include "xtea-ofb.h"
102 #include "blowfish-ofb.h"
103 #include "twofish-ofb.h"
104 #include "idea-ofb.h"
105 #include "cast128-ofb.h"
106 #include "cast256-ofb.h"
107 #include "rijndael-ofb.h"
108 #include "square-ofb.h"
109 #include "serpent-ofb.h"
111 #include "des-counter.h"
112 #include "des3-counter.h"
113 #include "rc2-counter.h"
114 #include "rc5-counter.h"
115 #include "skipjack-counter.h"
116 #include "tea-counter.h"
117 #include "xtea-counter.h"
118 #include "blowfish-counter.h"
119 #include "twofish-counter.h"
120 #include "idea-counter.h"
121 #include "cast128-counter.h"
122 #include "cast256-counter.h"
123 #include "rijndael-counter.h"
124 #include "square-counter.h"
125 #include "serpent-counter.h"
130 #include "tiger-mgf.h"
131 #include "rmd128-mgf.h"
132 #include "rmd160-mgf.h"
133 #include "rmd256-mgf.h"
134 #include "rmd320-mgf.h"
138 /*----- Data structures ---------------------------------------------------*/
142 grand
*(*seed
)(unsigned /*i*/);
147 static gen generators
[];
154 E(SKIPJACK, skipjack) \
157 E(BLOWFISH, blowfish) \
158 E(TWOFISH, twofish) \
160 E(CAST128, cast128) \
161 E(CAST256, cast256) \
163 E(RIJNDAEL, rijndael) \
176 #define E(PRE, pre) CIPHER_##PRE,
177 enum { CIPHERS CIPHER__bogus
};
180 #define E(PRE, pre) HASH_##PRE,
181 enum { HASHES HASH__bogus
};
187 grand
*(*ofb
)(const void */
*k*/
, size_t /*sz*/);
188 grand
*(*counter
)(const void */
*k*/
, size_t /*sz*/);
190 #define E(PRE, pre) \
191 { pre##_keysz, PRE##_BLKSZ, pre##_ofbrand, pre##_counterrand },
199 grand
*(*mgf
)(const void */
*k*/
, size_t /*sz*/);
201 #define E(PRE, pre) \
202 { &pre, pre##_mgfkeysz, pre##_mgfrand },
207 /*----- Miscellaneous static data -----------------------------------------*/
210 static size_t outsz
= 0;
215 static unsigned flags
= 0;
224 /*----- Help options ------------------------------------------------------*/
226 static void usage(FILE *fp
)
228 pquis(fp
, "Usage: $ generator [options]\n");
231 static void version(FILE *fp
)
233 pquis(fp
, "$, Catacomb version " VERSION
"\n");
236 static void help(FILE *fp
)
242 Emits a stream of random bytes suitable for, well, all sorts of things.\n\
243 The primary objective is to be able to generate streams of input for\n\
244 statistical tests, such as Diehard.\n\
246 Options are specific to the particular generator, although there's a\n\
249 -h, --help Display this help message.\n\
250 -v, --version Display the program's version number.\n\
251 -u, --usage Display a useless usage message.\n\
253 -l, --list Show a list of the supported generators, with\n\
255 -f, --fipstest Run the FIPS 140-1 randomness test.\n\
256 -m, --maurer Run Maurer's universal statistical test.\n\
257 -o, --output FILE Write output to FILE, not stdout.\n\
258 -z, --size SIZE Emit SIZE bytes, not an unlimited number.\n\
259 -p, --progress Show a little progress meter (on stderr).\n\
261 (A SIZE may be followed by `g' for gigabytes, `m' for megabytes, or\n\
262 `k' for kilobytes. If unqualified, an amount in bytes is assumed.)\n\
266 /*----- Main options parser -----------------------------------------------*/
268 static struct option opts
[] = {
270 /* --- Standard GNU help options --- */
272 { "help", 0, 0, 'h' },
273 { "version", 0, 0, 'v' },
274 { "usage", 0, 0, 'u' },
276 /* --- Other useful things --- */
278 { "list", 0, 0, 'l' },
279 { "fipstest", 0, 0, 'f' },
280 { "maurer", 0, 0, 'm' },
281 { "output", OPTF_ARGREQ
, 0, 'o' },
282 { "size", OPTF_ARGREQ
, 0, 'z' },
283 { "progress", 0, 0, 'p' },
285 /* --- End of main table --- */
290 static const char *sopts
= "hvu lfmo:z:p";
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
);
358 die(EXIT_FAILURE
, "already set an output file");
359 if (strcmp(optarg
, "-") == 0)
362 outfp
= fopen(optarg
, "w");
364 die(EXIT_FAILURE
, "couldn't open output file `%s': %s",
365 optarg
, strerror(errno
));
372 outsz
= strtoul(optarg
, &p
, 0);
374 die(EXIT_FAILURE
, "bad number `%s'", optarg
);
376 case 'G': case 'g': outsz
*= 1024;
377 case 'M': case 'm': outsz
*= 1024;
378 case 'K': case 'k': outsz
*= 1024;
382 die(EXIT_FAILURE
, "bad suffix `%s'", p
);
386 die(EXIT_FAILURE
, "bad suffix `%s'", p
);
397 /*----- Manglers for seed strings -----------------------------------------*/
401 * Arguments: @const char *p@ = pointer to input string
402 * @char **end@ = where the end goes
403 * @dstr *d@ = output buffer
407 * Use: Transforms a hex string into a chunk of binary data.
410 static void unhex(const char *p
, char **end
, dstr
*d
)
412 while (p
[0] && p
[1]) {
413 int x
= p
[0], y
= p
[1];
414 if ('0' <= x
&& x
<= '9') x
-= '0';
415 else if ('A' <= x
&& x
<= 'F') x
-= 'A' - 10;
416 else if ('a' <= x
&& x
<= 'f') x
-= 'a' - 10;
418 if ('0' <= y
&& y
<= '9') y
-= '0';
419 else if ('A' <= y
&& y
<= 'F') y
-= 'A' - 10;
420 else if ('a' <= y
&& y
<= 'f') y
-= 'a' - 10;
422 DPUTC(d
, (x
<< 4) + y
);
428 /* --- Generate a key --- */
430 static void textkey(dstr
*d
, const char *p
, const octet
*ksz
)
432 size_t sz
= strlen(p
);
435 die(EXIT_FAILURE
, "zero-length key string");
436 if (keysz(sz
, ksz
) != sz
)
440 rmd160_mgfinit(&g
, p
, sz
);
443 rmd160_mgfencrypt(&g
, 0, d
->buf
, sz
);
446 assert(((void)"I can't seem to choose a good key size",
447 keysz(d
->len
, ksz
) == d
->len
));
450 static void hexkey(dstr
*d
, const char *p
, const octet
*ksz
)
453 unhex(optarg
, &q
, d
);
455 die(EXIT_FAILURE
, "bad hex key `%s'", p
);
456 if (keysz(d
->len
, ksz
) != d
->len
)
457 die(EXIT_FAILURE
, "bad key length");
460 static void randkey(dstr
*d
, const octet
*ksz
)
462 size_t sz
= keysz(0, ksz
);
464 rand_get(RAND_GLOBAL
, d
->buf
, sz
);
468 /*----- Generators --------------------------------------------------------*/
470 /* --- Blum-Blum-Shub strong generator --- */
472 static grand
*gen_bbs(unsigned i
)
474 /* --- Default modulus --- *
476 * The factors of this number are
478 * @p = 1229936431484295969649886203367009966370895964206162032259292413@
479 * @7754313537966036459299022912838407755462506416274551744201653277@
480 * @313130311731673973886822067@
482 * @q = 9798171783943489959487301695884963889684294764514008432498259742@
483 * @5374320073594018817245784145742769603334292182227671519041431067@
484 * @61344781426317516045890159@
486 * Both %$p$% and %$q$% are prime; %$(p - 1)/2$% and %$(q - 1)/2$% have no
487 * common factors. They were found using this program, with random
490 * I hope that, by publishing these factors, I'll dissuade people from
491 * actually using this modulus in an attempt to attain real security. The
492 * program is quite quick at finding Blum numbers, so there's no excuse for
493 * not generating your own.
497 "120511284390135742513572142094334711443073194119732569353820828435640527418092392240366088035509890969913081816369160298961490135716255689660470370755013177656905237112577648090277537209936078171554274553448103698084782669252936352843649980105109850503830397166360721262431179505917248447259735253684659338653";
499 /* --- Other things --- */
503 unsigned bits
= 1024;
506 const char *kfile
= 0, *id
= 0, *ktype
= 0;
508 /* --- Parse options --- */
510 static struct option opts
[] = {
511 { "modulus", OPTF_ARGREQ
, 0, 'M' },
512 { "generate", 0, 0, 'g' },
513 { "seed", OPTF_ARGREQ
, 0, 's' },
514 { "bits", OPTF_ARGREQ
, 0, 'b' },
515 { "show", 0, 0, 'S' },
516 { "keyring", OPTF_ARGREQ
, 0, 'k' },
517 { "id", OPTF_ARGREQ
, 0, 'i' },
518 { "type", OPTF_ARGREQ
, 0, 't' },
522 addopts("M:gs:b:Sk:i:t:", opts
);
539 bits
= strtoul(optarg
, 0, 0);
541 die(EXIT_FAILURE
, "bad number of bits `%s'", optarg
);
563 /* --- Generate a modulus if one is requested --- */
567 m
= mp_readstring(MP_NEW
, mt
, &p
, 0);
568 if (!m
|| *p
|| (m
->v
[0] & 3) != 1)
569 die(EXIT_FAILURE
, "bad modulus `%s'", mt
);
570 /* Unfortunately I don't know how to test for a Blum integer */
571 } else if (kfile
|| id
|| ktype
) {
576 /* --- Open the key file --- */
580 if (key_open(&kf
, kfile
, KOPEN_READ
, key_moan
, 0)) {
581 die(EXIT_FAILURE
, "error opening key file `%s': %s",
582 kfile
, strerror(errno
));
585 /* --- Find the key --- */
588 if ((kk
= key_bytag(&kf
, id
)) == 0)
589 die(EXIT_FAILURE
, "key `%s' not found", id
);
593 if ((kk
= key_bytype(&kf
, ktype
)) == 0)
594 die(EXIT_FAILURE
, "no suitable key with type `%s' found", ktype
);
597 /* --- Read the key data --- */
599 if ((kk
->k
.e
& KF_ENCMASK
) != KENC_STRUCT
)
600 die(EXIT_FAILURE
, "key is not structured");
601 if ((kd
= key_structfind(&kk
->k
, "n")) == 0)
602 die(EXIT_FAILURE
, "key has no subkey `n'");
603 if ((kd
->e
& KF_ENCMASK
) != KENC_MP
)
604 die(EXIT_FAILURE
, "incomatible subkey encoding");
605 m
= MP_COPY(kd
->u
.m
);
610 if (bbs_gen(&bp
, bits
, &rand_global
, 0,
611 (flags
& f_progress
) ? pgen_ev
: 0, 0))
612 die(EXIT_FAILURE
, "modulus generation failed");
616 fputs("p = ", stderr
);
617 mp_writefile(bp
.p
, stderr
, 10);
618 fputs("\nq = ", stderr
);
619 mp_writefile(bp
.q
, stderr
, 10);
620 fputs("\nn = ", stderr
);
621 mp_writefile(bp
.n
, stderr
, 10);
629 /* --- Set up a seed --- */
632 x
= mprand(MP_NEW
, mp_bits(m
) - 1, &rand_global
, 1);
635 x
= mp_readstring(MP_NEW
, xt
, &p
, 0);
637 die(EXIT_FAILURE
, "bad modulus `%s'", xt
);
649 /* --- Catacomb's random number generator --- */
651 static grand
*gen_rand(unsigned i
)
653 grand
*r
= rand_create();
656 static struct option opts
[] = {
657 { "key", OPTF_ARGREQ
, 0, 'k' },
658 { "text", OPTF_ARGREQ
, 0, 't' },
659 { "hex", OPTF_ARGREQ
, 0, 'H' },
663 addopts("k:t:H:n", opts
);
665 r
->ops
->misc(r
, RAND_NOISESRC
, &noise_source
);
666 r
->ops
->misc(r
, RAND_SEED
, 160);
675 textkey(&d
, optarg
, rmd160_mackeysz
);
676 r
->ops
->misc(r
, RAND_KEY
, d
.buf
, d
.len
);
679 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, optarg
, strlen(optarg
));
683 hexkey(&d
, optarg
, rmd160_mackeysz
);
684 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, d
.buf
, d
.len
);
693 /* --- RC4 output --- */
695 static grand
*gen_rc4(unsigned i
)
700 static struct option opts
[] = {
701 { "key", OPTF_ARGREQ
, 0, 'k' },
702 { "hex", OPTF_ARGREQ
, 0, 'H' },
706 addopts("k:H:", opts
);
715 textkey(&d
, optarg
, rc4_keysz
);
719 hexkey(&d
, optarg
, rc4_keysz
);
727 randkey(&d
, rc4_keysz
);
728 r
= rc4_rand(d
.buf
, d
.len
);
733 /* --- SEAL output --- */
735 static grand
*gen_seal(unsigned i
)
741 static struct option opts
[] = {
742 { "key", OPTF_ARGREQ
, 0, 'k' },
743 { "hex", OPTF_ARGREQ
, 0, 'H' },
744 { "sequence", OPTF_ARGREQ
, 0, 'n' },
748 addopts("k:H:n:", opts
);
757 textkey(&d
, optarg
, seal_keysz
);
761 hexkey(&d
, optarg
, seal_keysz
);
765 n
= strtoul(optarg
, &p
, 0);
767 die(EXIT_FAILURE
, "bad number `%s'", optarg
);
775 randkey(&d
, seal_keysz
);
776 r
= seal_rand(d
.buf
, d
.len
, n
);
781 /* --- Output feedback generators --- */
783 static grand
*gen_ofb(unsigned i
)
789 static struct option opts
[] = {
790 { "key", OPTF_ARGREQ
, 0, 'k' },
791 { "hex", OPTF_ARGREQ
, 0, 'H' },
792 { "iv", OPTF_ARGREQ
, 0, 'i' },
796 addopts("k:H:i:", opts
);
805 textkey(&d
, optarg
, ciphertab
[i
].keysz
);
809 hexkey(&d
, optarg
, ciphertab
[i
].keysz
);
813 unhex(optarg
, &p
, &iv
);
815 die(EXIT_FAILURE
, "bad hex IV `%s'", optarg
);
823 randkey(&d
, ciphertab
[i
].keysz
);
824 r
= ciphertab
[i
].ofb(d
.buf
, d
.len
);
826 if (iv
.len
!= ciphertab
[i
].blksz
) {
827 die(EXIT_FAILURE
, "bad IV length %lu (must be %lu)",
828 (unsigned long)iv
.len
, (unsigned long)ciphertab
[i
].blksz
);
830 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, iv
.buf
);
838 /* --- Counter generators --- */
840 static grand
*gen_counter(unsigned i
)
846 static struct option opts
[] = {
847 { "key", OPTF_ARGREQ
, 0, 'k' },
848 { "hex", OPTF_ARGREQ
, 0, 'H' },
849 { "iv", OPTF_ARGREQ
, 0, 'i' },
853 addopts("k:H:i:", opts
);
862 textkey(&d
, optarg
, ciphertab
[i
].keysz
);
866 hexkey(&d
, optarg
, ciphertab
[i
].keysz
);
870 unhex(optarg
, &p
, &iv
);
872 die(EXIT_FAILURE
, "bad hex IV `%s'", optarg
);
880 randkey(&d
, ciphertab
[i
].keysz
);
881 r
= ciphertab
[i
].counter(d
.buf
, d
.len
);
883 if (iv
.len
!= ciphertab
[i
].blksz
) {
884 die(EXIT_FAILURE
, "bad IV length %lu (must be %lu)",
885 (unsigned long)iv
.len
, (unsigned long)ciphertab
[i
].blksz
);
887 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, iv
.buf
);
895 /* --- Mask generators --- */
897 static grand
*gen_mgf(unsigned i
)
903 static struct option opts
[] = {
904 { "key", OPTF_ARGREQ
, 0, 'k' },
905 { "hex", OPTF_ARGREQ
, 0, 'H' },
906 { "index", OPTF_ARGREQ
, 0, 'i' },
910 addopts("k:H:i:", opts
);
919 textkey(&d
, optarg
, hashtab
[i
].keysz
);
923 hexkey(&d
, optarg
, hashtab
[i
].keysz
);
927 c
= strtoul(optarg
, &p
, 0);
929 die(EXIT_FAILURE
, "bad index `%s'", optarg
);
937 randkey(&d
, hashtab
[i
].keysz
);
939 r
= hashtab
[i
].mgf(d
.buf
, d
.len
);
941 r
->ops
->misc(r
, GRAND_SEEDUINT32
, c
);
947 /* --- Fibonacci generator --- */
949 static grand
*gen_fib(unsigned i
)
956 static struct option opts
[] = {
957 { "seed", OPTF_ARGREQ
, 0, 's' },
969 s
= strtoul(optarg
, &p
, 0);
971 die(EXIT_FAILURE
, "bad integer `%s'", optarg
);
978 r
= fibrand_create(s
);
980 r
->ops
->misc(r
, GRAND_SEEDRAND
, &rand_global
);
984 /* --- LC generator --- */
986 static grand
*gen_lc(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
);
1016 s
= rand_global
.ops
->range(&rand_global
, LCRAND_P
);
1017 while (s
== LCRAND_FIXEDPT
);
1019 return (lcrand_create(s
));
1022 /* --- Basic options parser -- can't generate output --- */
1024 static grand
*gen_opts(unsigned i
)
1031 /*----- Generators table --------------------------------------------------*/
1033 static gen generators
[] = {
1034 { "fibonacci", gen_fib
, 0,
1038 #define E(PRE, pre) \
1039 { #pre "-ofb", gen_ofb, CIPHER_##PRE, \
1040 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
1043 #define E(PRE, pre) \
1044 { #pre "-counter", gen_counter, CIPHER_##PRE, \
1045 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
1048 #define E(PRE, pre) \
1049 { #pre "-mgf", gen_mgf, HASH_##PRE, \
1050 "[-k KEY-PHRASE] [-H HEX-KEY] [-i INDEX]" },
1053 { "rc4", gen_rc4
, 0,
1054 "[-k KEY-PHRASE] [-H HEX-KEY]" },
1055 { "seal", gen_seal
, 0,
1056 "[-k KEY-PHRASE] [-H HEX-KEY] [-n SEQ]" },
1057 { "rand", gen_rand
, 0,
1058 "[-n] [-k KEY-PHRASE] [-t TEXT-BLOCK] [-H HEX-BLOCK]" },
1059 { "bbs", gen_bbs
, 0,
1060 "[-gS] [-s SEED] [-M MODULUS] [-b BITS] [-k KEYRING] [-i TAG] [-t TYPE]"
1065 static gen optsg
= { "options", gen_opts
, 0,
1066 "This message shouldn't be printed." };
1068 /*----- Main code ---------------------------------------------------------*/
1070 int main(int ac
, char *av
[])
1074 unsigned percent
= 0;
1077 static char baton
[] = "-\\|/";
1080 /* --- Initialize mLib --- */
1085 /* --- Set up the main Catacomb generator --- */
1087 rand_noisesrc(RAND_GLOBAL
, &noise_source
);
1088 rand_seed(RAND_GLOBAL
, 160);
1090 /* --- Initialize the options table --- */
1092 addopts(sopts
, opts
);
1097 /* --- Read the generator out of the first argument --- */
1099 if (argc
> 1 && *argv
[1] != '-') {
1100 const char *arg
= av
[1];
1101 size_t sz
= strlen(arg
);
1105 for (gg
= generators
; gg
->name
; gg
++) {
1106 if (strncmp(arg
, gg
->name
, sz
) == 0) {
1107 if (gg
->name
[sz
] == 0) {
1111 die(EXIT_FAILURE
, "ambiguous generator name `%s'", arg
);
1117 die(EXIT_FAILURE
, "unknown generator name `%s'", arg
);
1122 /* --- Get a generic random number generator --- */
1125 if (!r
|| optind
!= ac
- 1) {
1130 /* --- Do the FIPS test --- */
1132 if (flags
& f_fips
) {
1133 octet buf
[FIPSTEST_BUFSZ
];
1136 r
->ops
->fill(r
, buf
, sizeof(buf
));
1138 if (rc
& FIPSTEST_MONOBIT
)
1139 moan("failed monobit test");
1140 if (rc
& FIPSTEST_POKER
)
1141 moan("failed poker test");
1142 if (rc
& FIPSTEST_RUNS
)
1143 moan("failed runs test");
1144 if (rc
& FIPSTEST_LONGRUNS
)
1145 moan("failed long runs test");
1146 if (!rc
&& (flags
& f_progress
))
1147 puts("test passed");
1148 return (rc ? EXIT_FAILURE
: 0);
1151 /* --- Do Maurer's test --- */
1153 if (flags
& f_maurer
) {
1154 octet buf
[250 * 1024];
1157 unsigned f
= 0, jj
= 0;
1160 static struct { double x
; const char *sig
; } sigtab
[] = {
1168 r
->ops
->fill(r
, buf
, sizeof(buf
));
1169 for (i
= 5; i
< 8; i
++) {
1170 double z
= maurer(buf
, sizeof(buf
), i
+ 1);
1171 double zz
= fabs(z
);
1174 for (j
= 0; sigtab
[j
].sig
; j
++) {
1175 if (zz
> sigtab
[j
].x
) {
1176 if (zz
> fabs(maxz
)) {
1182 moan("failed, bits = %u, sig = %s, Z_u = %g",
1183 i
+ 1, sigtab
[j
].sig
, z
);
1187 if (flags
& f_progress
)
1188 printf("bits = %u, Z_u = %g\n", i
+ 1, z
);
1194 /* --- Make sure we don't write to the terminal --- */
1197 if (!(flags
& f_file
) && isatty(STDOUT_FILENO
))
1198 die(EXIT_FAILURE
, "writing output to a terminal is a bad idea");
1201 /* --- Spit out random data --- */
1205 if (flags
& f_progress
) {
1206 char *errbuf
= xmalloc(BUFSIZ
);
1207 setvbuf(stderr
, errbuf
, _IOLBF
, BUFSIZ
);
1209 fprintf(stderr
, "[%*s] 0%% 0\r[/\b", 50, "");
1211 fputs("[ ] 0\r[/\b", stderr
);
1216 signal(SIGPIPE
, SIG_IGN
);
1221 size_t sz
= sizeof(buf
);
1223 /* --- Emit a bufferful (or less) of data --- */
1226 if (sz
> outsz
- kb
)
1229 r
->ops
->fill(r
, buf
, sz
);
1230 if (fwrite(buf
, 1, sz
, outfp
) != sz
) {
1231 if (flags
& f_progress
)
1232 fputc('\n', stderr
);
1233 die(EXIT_FAILURE
, "error writing data: %s", strerror(errno
));
1237 /* --- Update the display --- */
1239 if (flags
& f_progress
) {
1247 if (difftime(t
, last
) > 1.0) {
1251 fputs(" ] ", stderr
);
1253 unsigned pc
= kb
* 100.0 / outsz
;
1254 if (pc
> percent
|| percent
> 100 || difftime(t
, last
) > 1.0) {
1258 for (; percent
< (pc
& ~1); percent
+= 2)
1261 for (; pc
< 100; pc
+= 2)
1263 fprintf(stderr
, "] %3i%% ", percent
);
1270 char *suff
= " KMG";
1271 while (q
> 8192 && suff
[1]) {
1275 fprintf(stderr
, "%4i%c\r[", q
, *suff
);
1278 for (pc
= 0; pc
< (percent
& ~1); pc
+= 2)
1287 if (percent
< 100) {
1288 putc(*bp
++, stderr
);
1296 /* --- Terminate the loop --- */
1298 if (outsz
&& kb
>= outsz
)
1305 if (flags
& f_progress
)
1306 fputc('\n', stderr
);
1310 /*----- That's all, folks -------------------------------------------------*/