f3de422902c2347fb388fef96f6488b00185e825
[catacomb] / progs / rspit.c
1 /* -*-c-*-
2 *
3 * Spit out random numbers
4 *
5 * (c) 1999 Straylight/Edgeware
6 */
7
8 /*----- Licensing notice --------------------------------------------------*
9 *
10 * This file is part of Catacomb.
11 *
12 * Catacomb is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as
14 * published by the Free Software Foundation; either version 2 of the
15 * License, or (at your option) any later version.
16 *
17 * Catacomb is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with Catacomb; if not, write to the Free
24 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25 * MA 02111-1307, USA.
26 */
27
28 /*----- Header files ------------------------------------------------------*/
29
30 #include "config.h"
31
32 #include <assert.h>
33 #include <errno.h>
34 #include <math.h>
35 #include <signal.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <time.h>
40
41 #ifndef PORTABLE
42 # include <unistd.h>
43 # include <sys/time.h>
44 #endif
45
46 #include <mLib/darray.h>
47 #include <mLib/dstr.h>
48 #include <mLib/mdwopt.h>
49 #include <mLib/quis.h>
50 #include <mLib/report.h>
51 #include <mLib/sub.h>
52
53 #include "mp.h"
54 #include "mpint.h"
55 #include "mplimits.h"
56 #include "mptext.h"
57
58 #include "fipstest.h"
59 #include "grand.h"
60 #include "maurer.h"
61 #include "key.h"
62
63 #include "lcrand.h"
64 #include "fibrand.h"
65 #include "rand.h"
66 #include "noise.h"
67
68 #include "bbs.h"
69 #include "mprand.h"
70
71 #include "chacha.h"
72 #include "rc4.h"
73 #include "salsa20.h"
74 #include "salsa20-core.h"
75 #include "seal.h"
76
77 #include "des-ofb.h"
78 #include "des3-ofb.h"
79 #include "rc2-ofb.h"
80 #include "rc5-ofb.h"
81 #include "mars-ofb.h"
82 #include "skipjack-ofb.h"
83 #include "tea-ofb.h"
84 #include "xtea-ofb.h"
85 #include "blowfish-ofb.h"
86 #include "twofish-ofb.h"
87 #include "idea-ofb.h"
88 #include "cast128-ofb.h"
89 #include "cast256-ofb.h"
90 #include "noekeon-ofb.h"
91 #include "rijndael-ofb.h"
92 #include "rijndael192-ofb.h"
93 #include "rijndael256-ofb.h"
94 #include "safer-ofb.h"
95 #include "safersk-ofb.h"
96 #include "square-ofb.h"
97 #include "serpent-ofb.h"
98
99 #include "des-counter.h"
100 #include "des3-counter.h"
101 #include "rc2-counter.h"
102 #include "rc5-counter.h"
103 #include "mars-counter.h"
104 #include "skipjack-counter.h"
105 #include "tea-counter.h"
106 #include "xtea-counter.h"
107 #include "blowfish-counter.h"
108 #include "twofish-counter.h"
109 #include "idea-counter.h"
110 #include "cast128-counter.h"
111 #include "cast256-counter.h"
112 #include "noekeon-counter.h"
113 #include "rijndael-counter.h"
114 #include "rijndael192-counter.h"
115 #include "rijndael256-counter.h"
116 #include "safer-counter.h"
117 #include "safersk-counter.h"
118 #include "square-counter.h"
119 #include "serpent-counter.h"
120
121 #include "md2-mgf.h"
122 #include "md4-mgf.h"
123 #include "md5-mgf.h"
124 #include "sha-mgf.h"
125 #include "tiger-mgf.h"
126 #include "rmd128-mgf.h"
127 #include "rmd160-mgf.h"
128 #include "rmd256-mgf.h"
129 #include "rmd320-mgf.h"
130
131 #include "rmd160.h"
132
133 /*----- Data structures ---------------------------------------------------*/
134
135 typedef struct gen {
136 const char *name;
137 grand *(*seed)(unsigned /*i*/);
138 unsigned i;
139 const char *help;
140 } gen;
141
142 extern gen generators[];
143
144 #define CIPHERS \
145 E(DES, des) \
146 E(DES3, des3) \
147 E(RC2, rc2) \
148 E(RC5, rc5) \
149 E(MARS, mars) \
150 E(SKIPJACK, skipjack) \
151 E(TEA, tea) \
152 E(XTEA, xtea) \
153 E(BLOWFISH, blowfish) \
154 E(TWOFISH, twofish) \
155 E(IDEA, idea) \
156 E(CAST128, cast128) \
157 E(CAST256, cast256) \
158 E(SQUARE, square) \
159 E(SAFER, safer) \
160 E(SAFERSK, safersk) \
161 E(NOEKEON, noekeon) \
162 E(RIJNDAEL, rijndael) \
163 E(RIJNDAEL192, rijndael192) \
164 E(RIJNDAEL256, rijndael256) \
165 E(SERPENT, serpent)
166
167 #define HASHES \
168 E(MD2, md2) \
169 E(MD4, md4) \
170 E(MD5, md5) \
171 E(SHA, sha) \
172 E(TIGER, tiger) \
173 E(RMD128, rmd128) \
174 E(RMD160, rmd160) \
175 E(RMD256, rmd256) \
176 E(RMD320, rmd320)
177
178 #define E(PRE, pre) CIPHER_##PRE,
179 enum { CIPHERS CIPHER__bogus };
180 #undef E
181
182 #define E(PRE, pre) HASH_##PRE,
183 enum { HASHES HASH__bogus };
184 #undef E
185
186 static const struct {
187 const octet *keysz;
188 size_t blksz;
189 grand *(*ofb)(const void */*k*/, size_t /*sz*/);
190 grand *(*counter)(const void */*k*/, size_t /*sz*/);
191 } ciphertab[] = {
192 #define E(PRE, pre) \
193 { pre##_keysz, PRE##_BLKSZ, pre##_ofbrand, pre##_counterrand },
194 CIPHERS
195 #undef E
196 };
197
198 static const struct {
199 const gchash *h;
200 const octet *keysz;
201 grand *(*mgf)(const void */*k*/, size_t /*sz*/);
202 } hashtab[] = {
203 #define E(PRE, pre) \
204 { &pre, pre##_mgfkeysz, pre##_mgfrand },
205 HASHES
206 #undef E
207 };
208
209 #define SALSAE \
210 E(salsa20, 20,, SALSA20) \
211 E(salsa20, 12,, SALSA20) \
212 E(salsa20, 8,, SALSA20) \
213 E(xsalsa20, 20, X, SALSA20) \
214 E(xsalsa20, 12, X, SALSA20) \
215 E(xsalsa20, 8, X, SALSA20) \
216 E(chacha, 20,, CHACHA) \
217 E(chacha, 12,, CHACHA) \
218 E(chacha, 8,, CHACHA) \
219 E(xchacha, 20, X, CHACHA) \
220 E(xchacha, 12, X, CHACHA) \
221 E(xchacha, 8, X, CHACHA)
222
223 #define E(pre, r, x, BASE) pre##_##r##_INDEX,
224 enum { SALSAE BOGUS_SALSA };
225 #undef E
226
227 #define SALSA20_GEN(pre, r) SALSA20_DECOR(pre, r, _rand)
228 #define CHACHA_GEN(pre, r) pre##r##_rand
229
230 #define SALSA20_NAME(r) SALSA20_NAME_##r
231 #define XSALSA20_NAME(r) "x" SALSA20_NAME_##r
232 #define CHACHA_NAME(r) "chacha" #r
233 #define XCHACHA_NAME(r) "xchacha" #r
234
235 static const struct {
236 size_t noncesz;
237 grand *(*gen)(const void *, size_t, const void *);
238 } salsatab[] = {
239 #define E(pre, r, x, BASE) { x##BASE##_NONCESZ, BASE##_GEN(pre, r) },
240 SALSAE
241 #undef E
242 };
243
244 /*----- Miscellaneous static data -----------------------------------------*/
245
246 static FILE *outfp;
247 static mp *outsz = 0;
248 static unsigned maurer_lo = 5, maurer_hi = 8;
249
250 static int argc;
251 static char **argv;
252
253 static unsigned flags = 0;
254
255 #define f_progress 1u
256 #define f_file 2u
257 #define f_fips 4u
258 #define f_maurer 8u
259 #define f_timer 16u
260 #define f_discard 32u
261
262 /*----- Help options ------------------------------------------------------*/
263
264 static void usage(FILE *fp)
265 {
266 pquis(fp, "Usage: $ generator [options]\n");
267 }
268
269 static void version(FILE *fp)
270 {
271 pquis(fp, "$, Catacomb version " VERSION "\n");
272 }
273
274 static void help(FILE *fp)
275 {
276 version(fp);
277 fputc('\n', fp);
278 usage(fp);
279 pquis(fp, "\n\
280 Emits a stream of random bytes suitable for, well, all sorts of things.\n\
281 The primary objective is to be able to generate streams of input for\n\
282 statistical tests, such as Diehard.\n\
283 \n\
284 Options are specific to the particular generator, although there's a\n\
285 common core set:\n\
286 \n\
287 -h, --help Display this help message.\n\
288 -v, --version Display the program's version number.\n\
289 -u, --usage Display a useless usage message.\n\
290 \n\
291 -l, --list Show a list of the supported generators, with\n\
292 their options.\n\
293 -f, --fipstest Run the FIPS 140-1 randomness test.\n\
294 -m, --maurer[=LO-HI] Run Maurer's universal statistical test.\n\
295 -o, --output FILE Write output to FILE, not stdout.\n\
296 -z, --size SIZE Emit SIZE bytes, not an unlimited number.\n\
297 -p, --progress Show a little progress meter (on stderr).\n\
298 -T, --timer Keep track of the CPU time used by the generator.\n\
299 -d, --discard Discard the generated output.\n\
300 \n\
301 (A SIZE may be followed by `g' for gigabytes, `m' for megabytes, or\n\
302 `k' for kilobytes. If unqualified, an amount in bytes is assumed.)\n\
303 ");
304 }
305
306 /*----- Main options parser -----------------------------------------------*/
307
308 static struct option opts[] = {
309
310 /* --- Standard GNU help options --- */
311
312 { "help", 0, 0, 'h' },
313 { "version", 0, 0, 'v' },
314 { "usage", 0, 0, 'u' },
315
316 /* --- Other useful things --- */
317
318 { "list", 0, 0, 'l' },
319 { "fipstest", 0, 0, 'f' },
320 { "maurer", OPTF_ARGOPT, 0, 'm' },
321 { "output", OPTF_ARGREQ, 0, 'o' },
322 { "size", OPTF_ARGREQ, 0, 'z' },
323 { "progress", 0, 0, 'p' },
324 { "timer", 0, 0, 'T' },
325 { "discard", 0, 0, 'd' },
326
327 /* --- End of main table --- */
328
329 { 0, 0, 0, 0 }
330 };
331
332 static const char *sopts = "hvu lfm::o:z:pTd";
333
334 #ifndef OPTION_V
335 DA_DECL(option_v, struct option);
336 # define OPTION_V
337 #endif
338
339 static option_v optv = DA_INIT;
340 static dstr optd = DSTR_INIT;
341
342 /* --- @addopts@ --- *
343 *
344 * Arguments: @const char *s@ = pointer to short options
345 * @struct option *l@ = pointer to long options
346 *
347 * Returns: ---
348 *
349 * Use: Adds a collection of options to the table.
350 */
351
352 static void addopts(const char *s, struct option *l)
353 {
354 dstr_puts(&optd, s);
355 if (DA_LEN(&optv))
356 DA_SHRINK(&optv, 1);
357 while (l->name)
358 DA_PUSH(&optv, *l++);
359 DA_PUSH(&optv, *l);
360 }
361
362 /* --- @opt@ --- *
363 *
364 * Arguments: ---
365 *
366 * Returns: Next option from argument array.
367 *
368 * Use: Fetches options, handling the standard ones.
369 */
370
371 static int opt(void)
372 {
373 for (;;) {
374 int i = mdwopt(argc, argv, optd.buf, DA(&optv), 0, 0, 0);
375 switch (i) {
376 case 'h':
377 help(stdout);
378 exit(0);
379 case 'v':
380 version(stdout);
381 exit(0);
382 case 'u':
383 usage(stdout);
384 exit(0);
385 case 'l': {
386 gen *g;
387 puts("Generators supported:");
388 for (g = generators; g->name; g++)
389 printf(" %s %s\n", g->name, g->help);
390 exit(0);
391 } break;
392 case 'f':
393 flags |= f_fips;
394 break;
395 case 'm':
396 flags |= f_maurer;
397 if (optarg) {
398 char *p;
399 unsigned long lo, hi;
400 lo = strtoul(optarg, &p, 0);
401 if (*p == '-' || *p == ',')
402 hi = strtoul(p + 1, &p, 0);
403 else
404 hi = lo;
405 if (*p != 0 || hi < lo || lo == 0)
406 die(EXIT_FAILURE, "bad bit range `%s'", optarg);
407 maurer_lo = lo;
408 maurer_hi = hi;
409 }
410 break;
411 case 'o':
412 if (flags & f_file)
413 die(EXIT_FAILURE, "already set an output file");
414 if (strcmp(optarg, "-") == 0)
415 outfp = stdout;
416 else {
417 outfp = fopen(optarg, "w");
418 if (!outfp) {
419 die(EXIT_FAILURE, "couldn't open output file `%s': %s",
420 optarg, strerror(errno));
421 }
422 }
423 flags |= f_file;
424 break;
425 case 'z': {
426 char *p;
427 outsz = mp_readstring(outsz, optarg, &p, 0);
428 if (!outsz || MP_NEGP(outsz))
429 die(EXIT_FAILURE, "bad number `%s'", optarg);
430 switch (*p) {
431 case 'G': case 'g': outsz = mp_lsl(outsz, outsz, 10);
432 case 'M': case 'm': outsz = mp_lsl(outsz, outsz, 10);
433 case 'K': case 'k': outsz = mp_lsl(outsz, outsz, 10);
434 case 0:
435 break;
436 default:
437 die(EXIT_FAILURE, "bad suffix `%s'", p);
438 break;
439 }
440 if (*p && p[1] != 0)
441 die(EXIT_FAILURE, "bad suffix `%s'", p);
442 } break;
443 case 'p':
444 flags |= f_progress;
445 break;
446 case 'T':
447 flags |= f_timer;
448 break;
449 case 'd':
450 flags |= f_discard;
451 break;
452 default:
453 return (i);
454 }
455 }
456 }
457
458 /*----- Manglers for seed strings -----------------------------------------*/
459
460 /* --- @unhex@ --- *
461 *
462 * Arguments: @const char *p@ = pointer to input string
463 * @char **end@ = where the end goes
464 * @dstr *d@ = output buffer
465 *
466 * Returns: ---
467 *
468 * Use: Transforms a hex string into a chunk of binary data.
469 */
470
471 static void unhex(const char *p, char **end, dstr *d)
472 {
473 while (p[0] && p[1]) {
474 int x = p[0], y = p[1];
475 if ('0' <= x && x <= '9') x -= '0';
476 else if ('A' <= x && x <= 'F') x -= 'A' - 10;
477 else if ('a' <= x && x <= 'f') x -= 'a' - 10;
478 else x = 0;
479 if ('0' <= y && y <= '9') y -= '0';
480 else if ('A' <= y && y <= 'F') y -= 'A' - 10;
481 else if ('a' <= y && y <= 'f') y -= 'a' - 10;
482 else y = 0;
483 DPUTC(d, (x << 4) + y);
484 p += 2;
485 }
486 *end = (char *)p;
487 }
488
489 /* --- Generate a key --- */
490
491 static void textkey(dstr *d, const char *p, const octet *ksz)
492 {
493 size_t sz = strlen(p);
494
495 if (!sz)
496 die(EXIT_FAILURE, "zero-length key string");
497 if (keysz(sz, ksz) != sz)
498 DPUTM(d, p, sz);
499 else {
500 rmd160_mgfctx g;
501 rmd160_mgfinit(&g, p, sz);
502 sz = keysz(0, ksz);
503 dstr_ensure(d, sz);
504 rmd160_mgfencrypt(&g, 0, d->buf, sz);
505 d->len += sz;
506 }
507 assert(((void)"I can't seem to choose a good key size",
508 keysz(d->len, ksz) == d->len));
509 }
510
511 static void hexkey(dstr *d, const char *p, const octet *ksz)
512 {
513 char *q;
514 unhex(optarg, &q, d);
515 if (*q)
516 die(EXIT_FAILURE, "bad hex key `%s'", p);
517 if (keysz(d->len, ksz) != d->len)
518 die(EXIT_FAILURE, "bad key length");
519 }
520
521 static void randkey(dstr *d, const octet *ksz)
522 {
523 size_t sz = keysz(0, ksz);
524 dstr_ensure(d, sz);
525 rand_get(RAND_GLOBAL, d->buf, sz);
526 d->len += sz;
527 }
528
529 /*----- Generators --------------------------------------------------------*/
530
531 /* --- Blum-Blum-Shub strong generator --- */
532
533 static grand *gen_bbs(unsigned i)
534 {
535 /* --- Default modulus --- *
536 *
537 * The factors of this number are
538 *
539 * @p = 1229936431484295969649886203367009966370895964206162032259292413@
540 * @7754313537966036459299022912838407755462506416274551744201653277@
541 * @313130311731673973886822067@
542 *
543 * @q = 9798171783943489959487301695884963889684294764514008432498259742@
544 * @5374320073594018817245784145742769603334292182227671519041431067@
545 * @61344781426317516045890159@
546 *
547 * Both %$p$% and %$q$% are prime; %$(p - 1)/2$% and %$(q - 1)/2$% have no
548 * common factors. They were found using this program, with random
549 * starting points.
550 *
551 * I hope that, by publishing these factors, I'll dissuade people from
552 * actually using this modulus in an attempt to attain real security. The
553 * program is quite quick at finding Blum numbers, so there's no excuse for
554 * not generating your own.
555 */
556
557 const char *mt =
558 "12051128439013574251357214209433471144307319411973256935382082"
559 "84356405274180923922403660880355098909699130818163691602989614"
560 "90135716255689660470370755013177656905237112577648090277537209"
561 "93607817155427455344810369808478266925293635284364998010510985"
562 "0503830397166360721262431179505917248447259735253684659338653";
563
564 /* --- Other things --- */
565
566 grand *r;
567 const char *xt = 0;
568 unsigned bits = 1024;
569 mp *m, *x;
570 unsigned show = 0;
571 const char *kfile = 0, *id = 0, *ktype = 0;
572
573 /* --- Parse options --- */
574
575 static struct option opts[] = {
576 { "modulus", OPTF_ARGREQ, 0, 'M' },
577 { "generate", 0, 0, 'g' },
578 { "seed", OPTF_ARGREQ, 0, 's' },
579 { "bits", OPTF_ARGREQ, 0, 'b' },
580 { "show", 0, 0, 'S' },
581 { "keyring", OPTF_ARGREQ, 0, 'k' },
582 { "id", OPTF_ARGREQ, 0, 'i' },
583 { "type", OPTF_ARGREQ, 0, 't' },
584 { 0, 0, 0, 0 }
585 };
586
587 addopts("M:gs:b:Sk:i:t:", opts);
588
589 for (;;) {
590 int o = opt();
591 if (o < 0)
592 break;
593 switch (o) {
594 case 'M':
595 mt = optarg;
596 break;
597 case 'g':
598 mt = 0;
599 break;
600 case 's':
601 xt = optarg;
602 break;
603 case 'b':
604 bits = strtoul(optarg, 0, 0);
605 if (bits == 0)
606 die(EXIT_FAILURE, "bad number of bits `%s'", optarg);
607 break;
608 case 'S':
609 show = 1;
610 break;
611 case 'k':
612 kfile = optarg;
613 mt = 0;
614 break;
615 case 'i':
616 id = optarg;
617 mt = 0;
618 break;
619 case 't':
620 ktype = optarg;
621 mt = 0;
622 break;
623 default:
624 return (0);
625 }
626 }
627
628 /* --- Generate a modulus if one is requested --- */
629
630 if (mt) {
631 char *p;
632 m = mp_readstring(MP_NEW, mt, &p, 0);
633 if (!m || *p || (m->v[0] & 3) != 1)
634 die(EXIT_FAILURE, "bad modulus `%s'", mt);
635 /* Unfortunately I don't know how to test for a Blum integer */
636 } else if (kfile || id || ktype) {
637 key_file kf;
638 key *kk;
639 key_data *kd;
640
641 /* --- Open the key file --- */
642
643 if (!kfile)
644 kfile = "keyring";
645 if (key_open(&kf, kfile, KOPEN_READ, key_moan, 0)) {
646 die(EXIT_FAILURE, "error opening key file `%s': %s",
647 kfile, strerror(errno));
648 }
649
650 /* --- Find the key --- */
651
652 if (id) {
653 if ((kk = key_bytag(&kf, id)) == 0)
654 die(EXIT_FAILURE, "key `%s' not found", id);
655 } else {
656 if (!ktype)
657 ktype = "bbs";
658 if ((kk = key_bytype(&kf, ktype)) == 0)
659 die(EXIT_FAILURE, "no suitable key with type `%s' found", ktype);
660 }
661
662 /* --- Read the key data --- */
663
664 if ((kk->k->e & KF_ENCMASK) != KENC_STRUCT)
665 die(EXIT_FAILURE, "key is not structured");
666 if ((kd = key_structfind(kk->k, "n")) == 0)
667 die(EXIT_FAILURE, "key has no subkey `n'");
668 if ((kd->e & KF_ENCMASK) != KENC_MP)
669 die(EXIT_FAILURE, "incompatible subkey encoding");
670 m = MP_COPY(kd->u.m);
671 key_close(&kf);
672 } else {
673 bbs_priv bp;
674
675 if (bbs_gen(&bp, bits, &rand_global, 0,
676 (flags & f_progress) ? pgen_ev : 0, 0))
677 die(EXIT_FAILURE, "modulus generation failed");
678 m = bp.n;
679
680 if (show) {
681 fputs("p = ", stderr);
682 mp_writefile(bp.p, stderr, 10);
683 fputs("\nq = ", stderr);
684 mp_writefile(bp.q, stderr, 10);
685 fputs("\nn = ", stderr);
686 mp_writefile(bp.n, stderr, 10);
687 fputc('\n', stderr);
688 }
689
690 mp_drop(bp.p);
691 mp_drop(bp.q);
692 }
693
694 /* --- Set up a seed --- */
695
696 if (!xt)
697 x = mprand(MP_NEW, mp_bits(m) - 1, &rand_global, 1);
698 else {
699 char *p;
700 x = mp_readstring(MP_NEW, xt, &p, 0);
701 if (*p)
702 die(EXIT_FAILURE, "bad modulus `%s'", xt);
703 }
704
705 /* --- Right --- */
706
707 r = bbs_rand(m, x);
708
709 mp_drop(m);
710 mp_drop(x);
711 return (r);
712 }
713
714 /* --- Catacomb's random number generator --- */
715
716 static grand *gen_rand(unsigned i)
717 {
718 grand *r = rand_create();
719 dstr d = DSTR_INIT;
720
721 static struct option opts[] = {
722 { "key", OPTF_ARGREQ, 0, 'k' },
723 { "text", OPTF_ARGREQ, 0, 't' },
724 { "hex", OPTF_ARGREQ, 0, 'H' },
725 { 0, 0, 0, 0 }
726 };
727
728 addopts("k:t:H:n", opts);
729
730 r->ops->misc(r, RAND_NOISESRC, &noise_source);
731 r->ops->misc(r, RAND_SEED, 160);
732
733 for (;;) {
734 int o = opt();
735 if (o < 0)
736 break;
737 switch (o) {
738 case 'k':
739 DRESET(&d);
740 textkey(&d, optarg, rmd160_hmackeysz);
741 r->ops->misc(r, RAND_KEY, d.buf, d.len);
742 break;
743 case 't':
744 r->ops->misc(r, GRAND_SEEDBLOCK, optarg, strlen(optarg));
745 break;
746 case 'H':
747 DRESET(&d);
748 hexkey(&d, optarg, rmd160_hmackeysz);
749 r->ops->misc(r, GRAND_SEEDBLOCK, d.buf, d.len);
750 break;
751 }
752 }
753
754 dstr_destroy(&d);
755 return (r);
756 }
757
758 /* --- RC4 output --- */
759
760 static grand *gen_rc4(unsigned i)
761 {
762 grand *r;
763 dstr d = DSTR_INIT;
764
765 static struct option opts[] = {
766 { "key", OPTF_ARGREQ, 0, 'k' },
767 { "hex", OPTF_ARGREQ, 0, 'H' },
768 { 0, 0, 0, 0 }
769 };
770
771 addopts("k:H:", opts);
772
773 for (;;) {
774 int o = opt();
775 if (o < 0)
776 break;
777 switch (o) {
778 case 'k':
779 DRESET(&d);
780 textkey(&d, optarg, rc4_keysz);
781 break;
782 case 'H':
783 DRESET(&d);
784 hexkey(&d, optarg, rc4_keysz);
785 break;
786 default:
787 return (0);
788 }
789 }
790
791 if (!d.len)
792 randkey(&d, rc4_keysz);
793 r = rc4_rand(d.buf, d.len);
794 dstr_destroy(&d);
795 return (r);
796 }
797
798 /* --- SEAL output --- */
799
800 static grand *gen_seal(unsigned i)
801 {
802 grand *r;
803 dstr d = DSTR_INIT;
804 uint32 n = 0;
805
806 static struct option opts[] = {
807 { "key", OPTF_ARGREQ, 0, 'k' },
808 { "hex", OPTF_ARGREQ, 0, 'H' },
809 { "sequence", OPTF_ARGREQ, 0, 'n' },
810 { 0, 0, 0, 0 }
811 };
812
813 addopts("k:H:n:", opts);
814
815 for (;;) {
816 int o = opt();
817 if (o < 0)
818 break;
819 switch (o) {
820 case 'k':
821 DRESET(&d);
822 textkey(&d, optarg, seal_keysz);
823 break;
824 case 'H':
825 DRESET(&d);
826 hexkey(&d, optarg, seal_keysz);
827 break;
828 case 'n': {
829 char *p;
830 n = strtoul(optarg, &p, 0);
831 if (*p)
832 die(EXIT_FAILURE, "bad number `%s'", optarg);
833 } break;
834 default:
835 return (0);
836 }
837 }
838
839 if (!d.len)
840 randkey(&d, seal_keysz);
841 r = seal_rand(d.buf, d.len, n);
842 dstr_destroy(&d);
843 return (r);
844 }
845
846 /* --- Salsa20, XSalsa20, ChaCha, and XChaCha --- */
847
848 static grand *gen_salsae(unsigned i)
849 {
850 grand *r;
851 char *p;
852 dstr d = DSTR_INIT;
853 dstr n = DSTR_INIT;
854 kludge64 pos = { 0 };
855 octet posbuf[8];
856 mp *x;
857
858 static struct option opts[] = {
859 { "key", OPTF_ARGREQ, 0, 'k' },
860 { "hex", OPTF_ARGREQ, 0, 'H' },
861 { "nonce", OPTF_ARGREQ, 0, 'n' },
862 { "seek", OPTF_ARGREQ, 0, 's' },
863 { 0, 0, 0, 0 }
864 };
865
866 addopts("k:H:n:s:", opts);
867
868 for (;;) {
869 int o = opt();
870 if (o < 0)
871 break;
872 switch (o) {
873 case 'k':
874 DRESET(&d);
875 textkey(&d, optarg, salsa20_keysz);
876 break;
877 case 'H':
878 DRESET(&d);
879 hexkey(&d, optarg, salsa20_keysz);
880 break;
881 case 'n':
882 DRESET(&n);
883 unhex(optarg, &p, &n);
884 if (*p)
885 die(EXIT_FAILURE, "bad hex IV `%s'", optarg);
886 if (n.len != salsatab[i].noncesz) {
887 die(EXIT_FAILURE, "bad nonce length %lu (must be %lu)",
888 (unsigned long)n.len, (unsigned long)salsatab[i].noncesz);
889 }
890 break;
891 case 's':
892 x = mp_readstring(MP_NEW, optarg, &p, 0);
893 if (*p || MP_NEGP(x) || mp_bits(x) > 64)
894 die(EXIT_FAILURE, "bad position `%s'", optarg);
895 mp_storeb(x, posbuf, sizeof(posbuf));
896 mp_drop(x);
897 LOAD64_(pos, posbuf);
898 break;
899 default:
900 return (0);
901 }
902 }
903
904 if (!d.len)
905 randkey(&d, salsa20_keysz);
906 r = salsatab[i].gen(d.buf, d.len, n.len ? n.buf : 0);
907 r->ops->misc(r, SALSA20_SEEKU64, pos);
908
909 dstr_destroy(&d);
910 dstr_destroy(&n);
911
912 return (r);
913 }
914
915 /* --- Output feedback generators --- */
916
917 static grand *gen_ofb(unsigned i)
918 {
919 grand *r;
920 dstr d = DSTR_INIT;
921 dstr iv = DSTR_INIT;
922
923 static struct option opts[] = {
924 { "key", OPTF_ARGREQ, 0, 'k' },
925 { "hex", OPTF_ARGREQ, 0, 'H' },
926 { "iv", OPTF_ARGREQ, 0, 'i' },
927 { 0, 0, 0, 0 }
928 };
929
930 addopts("k:H:i:", opts);
931
932 for (;;) {
933 int o = opt();
934 if (o < 0)
935 break;
936 switch (o) {
937 case 'k':
938 DRESET(&d);
939 textkey(&d, optarg, ciphertab[i].keysz);
940 break;
941 case 'H':
942 DRESET(&d);
943 hexkey(&d, optarg, ciphertab[i].keysz);
944 break;
945 case 'i': {
946 char *p;
947 DRESET(&iv);
948 unhex(optarg, &p, &iv);
949 if (*p)
950 die(EXIT_FAILURE, "bad hex IV `%s'", optarg);
951 if (iv.len != ciphertab[i].blksz) {
952 die(EXIT_FAILURE, "bad IV length %lu (must be %lu)",
953 (unsigned long)iv.len, (unsigned long)ciphertab[i].blksz);
954 }
955 } break;
956 default:
957 return (0);
958 }
959 }
960
961 if (!d.len)
962 randkey(&d, ciphertab[i].keysz);
963 r = ciphertab[i].ofb(d.buf, d.len);
964 if (iv.len)
965 r->ops->misc(r, GRAND_SEEDBLOCK, iv.buf);
966
967 dstr_destroy(&d);
968 dstr_destroy(&iv);
969 return (r);
970 }
971
972 /* --- Counter generators --- */
973
974 static grand *gen_counter(unsigned i)
975 {
976 grand *r;
977 dstr d = DSTR_INIT;
978 dstr iv = DSTR_INIT;
979
980 static struct option opts[] = {
981 { "key", OPTF_ARGREQ, 0, 'k' },
982 { "hex", OPTF_ARGREQ, 0, 'H' },
983 { "iv", OPTF_ARGREQ, 0, 'i' },
984 { 0, 0, 0, 0 }
985 };
986
987 addopts("k:H:i:", opts);
988
989 for (;;) {
990 int o = opt();
991 if (o < 0)
992 break;
993 switch (o) {
994 case 'k':
995 DRESET(&d);
996 textkey(&d, optarg, ciphertab[i].keysz);
997 break;
998 case 'H':
999 DRESET(&d);
1000 hexkey(&d, optarg, ciphertab[i].keysz);
1001 break;
1002 case 'i': {
1003 char *p;
1004 DRESET(&iv);
1005 unhex(optarg, &p, &iv);
1006 if (*p)
1007 die(EXIT_FAILURE, "bad hex IV `%s'", optarg);
1008 if (iv.len != ciphertab[i].blksz) {
1009 die(EXIT_FAILURE, "bad IV length %lu (must be %lu)",
1010 (unsigned long)iv.len, (unsigned long)ciphertab[i].blksz);
1011 }
1012 } break;
1013 default:
1014 return (0);
1015 }
1016 }
1017
1018 if (!d.len)
1019 randkey(&d, ciphertab[i].keysz);
1020 r = ciphertab[i].counter(d.buf, d.len);
1021 if (iv.len)
1022 r->ops->misc(r, GRAND_SEEDBLOCK, iv.buf);
1023
1024 dstr_destroy(&d);
1025 dstr_destroy(&iv);
1026 return (r);
1027 }
1028
1029 /* --- Mask generators --- */
1030
1031 static grand *gen_mgf(unsigned i)
1032 {
1033 grand *r;
1034 dstr d = DSTR_INIT;
1035 uint32 c = 0;
1036
1037 static struct option opts[] = {
1038 { "key", OPTF_ARGREQ, 0, 'k' },
1039 { "hex", OPTF_ARGREQ, 0, 'H' },
1040 { "index", OPTF_ARGREQ, 0, 'i' },
1041 { 0, 0, 0, 0 }
1042 };
1043
1044 addopts("k:H:i:", opts);
1045
1046 for (;;) {
1047 int o = opt();
1048 if (o < 0)
1049 break;
1050 switch (o) {
1051 case 'k':
1052 DRESET(&d);
1053 textkey(&d, optarg, hashtab[i].keysz);
1054 break;
1055 case 'H':
1056 DRESET(&d);
1057 hexkey(&d, optarg, hashtab[i].keysz);
1058 break;
1059 case 'i': {
1060 char *p;
1061 c = strtoul(optarg, &p, 0);
1062 if (*p)
1063 die(EXIT_FAILURE, "bad index `%s'", optarg);
1064 } break;
1065 default:
1066 return (0);
1067 }
1068 }
1069
1070 if (!d.len)
1071 randkey(&d, hashtab[i].keysz);
1072
1073 r = hashtab[i].mgf(d.buf, d.len);
1074 if (c)
1075 r->ops->misc(r, GRAND_SEEDUINT32, c);
1076
1077 dstr_destroy(&d);
1078 return (r);
1079 }
1080
1081 /* --- Fibonacci generator --- */
1082
1083 static grand *gen_fib(unsigned i)
1084 {
1085 grand *r;
1086 uint32 s = 0;
1087 char *p;
1088 unsigned set = 0;
1089
1090 static struct option opts[] = {
1091 { "seed", OPTF_ARGREQ, 0, 's' },
1092 { 0, 0, 0, 0 }
1093 };
1094
1095 addopts("s:", opts);
1096
1097 for (;;) {
1098 int o = opt();
1099 if (o < 0)
1100 break;
1101 switch (o) {
1102 case 's':
1103 s = strtoul(optarg, &p, 0);
1104 if (*p)
1105 die(EXIT_FAILURE, "bad integer `%s'", optarg);
1106 set = 1;
1107 break;
1108 default:
1109 return (0);
1110 }
1111 }
1112 r = fibrand_create(s);
1113 if (!set)
1114 r->ops->misc(r, GRAND_SEEDRAND, &rand_global);
1115 return (r);
1116 }
1117
1118 /* --- LC generator --- */
1119
1120 static grand *gen_lc(unsigned i)
1121 {
1122 uint32 s = 0;
1123 char *p;
1124 unsigned set = 0;
1125
1126 static struct option opts[] = {
1127 { "seed", OPTF_ARGREQ, 0, 's' },
1128 { 0, 0, 0, 0 }
1129 };
1130
1131 addopts("s:", opts);
1132
1133 for (;;) {
1134 int o = opt();
1135 if (o < 0)
1136 break;
1137 switch (o) {
1138 case 's':
1139 s = strtoul(optarg, &p, 0);
1140 if (*p)
1141 die(EXIT_FAILURE, "bad integer `%s'", optarg);
1142 set = 1;
1143 break;
1144 default:
1145 return (0);
1146 }
1147 }
1148 if (!set) {
1149 do
1150 s = rand_global.ops->range(&rand_global, LCRAND_P);
1151 while (s == LCRAND_FIXEDPT);
1152 }
1153 return (lcrand_create(s));
1154 }
1155
1156 /* --- Basic options parser -- can't generate output --- */
1157
1158 static grand *gen_opts(unsigned i)
1159 {
1160 while (opt() >= 0)
1161 ;
1162 return (0);
1163 }
1164
1165 /*----- Generators table --------------------------------------------------*/
1166
1167 gen generators[] = {
1168 { "fibonacci", gen_fib, 0,
1169 "[-s SEED]" },
1170 { "lc", gen_lc, 0,
1171 "[-s SEED]" },
1172 #define E(PRE, pre) \
1173 { #pre "-ofb", gen_ofb, CIPHER_##PRE, \
1174 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
1175 CIPHERS
1176 #undef E
1177 #define E(PRE, pre) \
1178 { #pre "-counter", gen_counter, CIPHER_##PRE, \
1179 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
1180 CIPHERS
1181 #undef E
1182 #define E(PRE, pre) \
1183 { #pre "-mgf", gen_mgf, HASH_##PRE, \
1184 "[-k KEY-PHRASE] [-H HEX-KEY] [-i INDEX]" },
1185 HASHES
1186 #undef E
1187 #define E(pre, r, x, BASE) \
1188 { x##BASE##_NAME(r), gen_salsae, pre##_##r##_INDEX, \
1189 "[-k KEY-PHRASE] [-H HEX-KEY] [-n NONCE]" },
1190 SALSAE
1191 #undef E
1192 { "rc4", gen_rc4, 0,
1193 "[-k KEY-PHRASE] [-H HEX-KEY]" },
1194 { "seal", gen_seal, 0,
1195 "[-k KEY-PHRASE] [-H HEX-KEY] [-n SEQ]" },
1196 { "rand", gen_rand, 0,
1197 "[-n] [-k KEY-PHRASE] [-t TEXT-BLOCK] [-H HEX-BLOCK]" },
1198 { "bbs", gen_bbs, 0,
1199 "[-gS] [-s SEED] [-M MODULUS] [-b BITS] [-k KEYRING] [-i TAG] [-t TYPE]"
1200 },
1201 { 0, 0, 0, 0 },
1202 };
1203
1204 static gen optsg = { "options", gen_opts, 0,
1205 "This message shouldn't be printed." };
1206
1207 /*----- Random number generation ------------------------------------------*/
1208
1209 static int genfile(const void *buf, size_t sz, void *p)
1210 {
1211 FILE *fp = p;
1212 if (fwrite(buf, 1, sz, fp) != sz)
1213 die(EXIT_FAILURE, "error writing to file: %s", strerror(errno));
1214 return (0);
1215 }
1216
1217 static int genbuf(const void *buf, size_t sz, void *p)
1218 {
1219 octet **pp = p;
1220 memcpy(*pp, buf, sz);
1221 *pp += sz;
1222 return (0);
1223 }
1224
1225 typedef struct genmaurer_ctx {
1226 size_t n;
1227 maurer_ctx *m;
1228 } genmaurer_ctx;
1229
1230 static int genmaurer(const void *buf, size_t sz, void *p)
1231 {
1232 genmaurer_ctx *g = p;
1233 size_t i;
1234
1235 for (i = 0; i < g->n; i++)
1236 maurer_test(&g->m[i], buf, sz);
1237 return (0);
1238 }
1239
1240 static double doubletime(void)
1241 {
1242 #ifdef PORTABLE
1243 static time_t start = (time_t)-1;
1244 time_t now = time(0);
1245
1246 if (start == (time_t)-1) start = now;
1247 return difftime(now, start);
1248 #else
1249 struct timeval tv;
1250
1251 gettimeofday(&tv, 0);
1252 return (tv.tv_sec + tv.tv_usec/1000000.0);
1253 #endif
1254 }
1255
1256 static int generate(grand *r, mp *outsz,
1257 int (*func)(const void *buf, size_t sz, void *p),
1258 void *p)
1259 {
1260 static char kmg[] = { ' ', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 0 };
1261
1262 unsigned percent = 0;
1263 mp *kb = MP_ZERO, *t = MP_NEW;
1264 dstr d = DSTR_INIT;
1265 double now, last;
1266 static char baton[] = "-\\|/";
1267 char *bp;
1268 int rc;
1269 clock_t clk = 0;
1270
1271 /* --- Spit out random data --- */
1272
1273 last = doubletime();
1274 bp = baton;
1275 if (flags & f_progress) {
1276 char *errbuf = xmalloc(BUFSIZ);
1277 setvbuf(stderr, errbuf, _IOLBF, BUFSIZ);
1278 if (outsz)
1279 fprintf(stderr, "[%*s] 0%% 0\r[/\b", 50, "");
1280 else
1281 fputs("[ ] 0\r[/\b", stderr);
1282 fflush(stderr);
1283 }
1284
1285 #ifdef SIGPIPE
1286 signal(SIGPIPE, SIG_IGN);
1287 #endif
1288
1289 while (!outsz || MP_CMP(kb, <, outsz)) {
1290 octet buf[BUFSIZ];
1291 size_t sz = sizeof(buf), left;
1292 clock_t c_start, c_stop;
1293
1294 /* --- Emit a bufferful (or less) of data --- */
1295
1296 if (outsz) {
1297 t = mp_sub(t, outsz, kb);
1298 assert(!MP_NEGP(t));
1299 if (MP_CMP(t, <=, MP_SIZET_MAX)) {
1300 left = mp_tosizet(t);
1301 if (sz > left) sz = left;
1302 }
1303 }
1304 c_start = clock();
1305 r->ops->fill(r, buf, sz);
1306 c_stop = clock();
1307 clk += c_stop - c_start;
1308 if (func && (rc = func(buf, sz, p)) != 0)
1309 return (rc);
1310 t = mp_fromsizet(t, sz);
1311 kb = mp_add(kb, kb, t);
1312
1313 /* --- Update the display --- */
1314
1315 if (flags & f_progress) {
1316 unsigned up = 0;
1317
1318 now = doubletime();
1319
1320 if (percent > 100)
1321 up = 1;
1322
1323 if (!outsz) {
1324 if (now - last > 0.1) {
1325 up = 1;
1326 }
1327 if (up)
1328 fputs(" ] ", stderr);
1329 } else {
1330 unsigned pc;
1331 t = mp_fromulong(t, 100);
1332 t = mp_mul(t, t, kb);
1333 mp_div(&t, 0, t, outsz);
1334 assert(!MP_NEGP(t) && MP_CMP(t, <, MP_UINT_MAX));
1335 pc = mp_touint(t);
1336 if (pc > percent || percent > 100 || now - last > 0.1) {
1337 if (percent > 100)
1338 percent = 0;
1339 percent &= ~1;
1340 for (; percent < (pc & ~1); percent += 2)
1341 putc('.', stderr);
1342 percent = pc;
1343 for (; pc < 100; pc += 2)
1344 putc(' ', stderr);
1345 fprintf(stderr, "] %3i%% ", percent);
1346 up = 1;
1347 }
1348 }
1349
1350 if (up) {
1351 char *kk = kmg;
1352 t = mp_add(t, kb, MP_ZERO);
1353 while (mp_bits(t) >= 14) {
1354 t = mp_lsr(t, t, 10);
1355 kk++;
1356 }
1357 DRESET(&d);
1358 mp_writedstr(t, &d, 10);
1359 fprintf(stderr, "%4s%c\r[", d.buf, *kk);
1360 if (outsz) {
1361 unsigned pc;
1362 for (pc = 0; pc < (percent & ~1); pc += 2)
1363 putc('.', stderr);
1364 }
1365 last = now;
1366 }
1367
1368 if (percent > 100)
1369 percent = 0;
1370
1371 if (percent < 100 && up) {
1372 putc(*bp++, stderr);
1373 putc('\b', stderr);
1374 if (!*bp)
1375 bp = baton;
1376 }
1377 fflush(stderr);
1378 }
1379 }
1380
1381 if (flags & f_progress)
1382 fputc('\n', stderr);
1383 if (flags & f_timer) {
1384 DRESET(&d);
1385 dstr_puts(&d, "generated ");
1386 mp_writedstr(kb, &d, 10);
1387 dstr_puts(&d, " bytes ");
1388 if (!clk)
1389 dstr_puts(&d, "too quickly to measure\n");
1390 else {
1391 char *kk;
1392 double out;
1393 double sec = (double)clk/CLOCKS_PER_SEC;
1394 unsigned long sh;
1395 double bps;
1396
1397 MP_SHRINK(kb);
1398 switch (MP_LEN(kb)) {
1399 case 0: out = 0; break;
1400 case 1: out = kb->v[0]; break;
1401 default:
1402 sh = mp_bits(kb) - MPW_BITS;
1403 t = mp_lsr(t, kb, sh);
1404 out = ldexp(t->v[0], sh);
1405 break;
1406 }
1407 bps = (8*out)/sec;
1408 for (kk = kmg; bps > 1024 && kk[1]; kk++, bps /= 1024)
1409 ;
1410 dstr_putf(&d, "in %g secs (%g %cb/s)\n", sec, bps, *kk);
1411 fwrite(d.buf, 1, d.len, stderr);
1412 }
1413 }
1414
1415 mp_drop(t);
1416 DDESTROY(&d);
1417 return (0);
1418 }
1419
1420 /*----- Main code ---------------------------------------------------------*/
1421
1422 int main(int ac, char *av[])
1423 {
1424 gen *g = &optsg;
1425 grand *r;
1426
1427 /* --- Initialize mLib --- */
1428
1429 ego(av[0]);
1430 sub_init();
1431
1432 /* --- Set up the main Catacomb generator --- */
1433
1434 rand_noisesrc(RAND_GLOBAL, &noise_source);
1435 rand_seed(RAND_GLOBAL, 160);
1436
1437 /* --- Initialize the options table --- */
1438
1439 addopts(sopts, opts);
1440 argc = ac;
1441 argv = av;
1442 outfp = stdout;
1443
1444 /* --- Read the generator out of the first argument --- */
1445
1446 if (argc > 1 && *argv[1] != '-') {
1447 const char *arg = av[1];
1448 size_t sz = strlen(arg);
1449 gen *gg;
1450
1451 g = 0;
1452 for (gg = generators; gg->name; gg++) {
1453 if (strncmp(arg, gg->name, sz) == 0) {
1454 if (gg->name[sz] == 0) {
1455 g = gg;
1456 break;
1457 } else if (g)
1458 die(EXIT_FAILURE, "ambiguous generator name `%s'", arg);
1459 else
1460 g = gg;
1461 }
1462 }
1463 if (!g)
1464 die(EXIT_FAILURE, "unknown generator name `%s'", arg);
1465 argc--;
1466 argv++;
1467 }
1468
1469 /* --- Get a generic random number generator --- */
1470
1471 r = g->seed(g->i);
1472 if (!r || optind != ac - 1) {
1473 usage(stderr);
1474 exit(EXIT_FAILURE);
1475 }
1476
1477 /* --- Do the FIPS test --- */
1478
1479 if (flags & f_fips) {
1480 octet buf[FIPSTEST_BUFSZ];
1481 unsigned rc;
1482 mp *t;
1483 octet *p = buf;
1484
1485 t = mp_fromsizet(MP_NEW, sizeof(buf));
1486 generate(r, t, genbuf, &p);
1487 mp_drop(t);
1488 rc = fipstest(buf);
1489 if (rc & FIPSTEST_MONOBIT)
1490 moan("failed monobit test");
1491 if (rc & FIPSTEST_POKER)
1492 moan("failed poker test");
1493 if (rc & FIPSTEST_RUNS)
1494 moan("failed runs test");
1495 if (rc & FIPSTEST_LONGRUNS)
1496 moan("failed long runs test");
1497 if (!rc && (flags & f_progress))
1498 fputs("test passed\n", stderr);
1499 return (rc ? EXIT_FAILURE : 0);
1500 }
1501
1502 /* --- Do Maurer's test --- */
1503
1504 if (flags & f_maurer) {
1505 size_t bufsz;
1506 unsigned i;
1507 unsigned rc = 0;
1508 mp *t;
1509 genmaurer_ctx g;
1510
1511 static struct { double x; const char *sig; } sigtab[] = {
1512 { 3.2905, "1e-3" },
1513 { 3.0902, "2e-3" },
1514 { 2.8070, "5e-3" },
1515 { 2.5758, "1e-2" },
1516 { 0 , 0 }
1517 };
1518
1519 g.n = maurer_hi - maurer_lo + 1;
1520 g.m = xmalloc(g.n * sizeof(maurer_ctx));
1521 for (i = 0; i < g.n; i++)
1522 maurer_init(&g.m[i], i + maurer_lo);
1523 bufsz = (100 * maurer_hi) << maurer_hi;
1524
1525 t = mp_fromsizet(MP_NEW, bufsz);
1526 generate(r, t, genmaurer, &g);
1527 mp_drop(t);
1528
1529 for (i = maurer_lo; i <= maurer_hi; i++) {
1530 double z = maurer_done(&g.m[i - maurer_lo]);
1531 double zz = fabs(z);
1532 unsigned j;
1533
1534 for (j = 0; sigtab[j].sig; j++) {
1535 if (zz > sigtab[j].x) {
1536 rc = EXIT_FAILURE;
1537 moan("failed, bits = %u, sig = %s, Z_u = %g",
1538 i, sigtab[j].sig, z);
1539 break;
1540 }
1541 }
1542 if (flags & f_progress)
1543 fprintf(stderr, "bits = %u, Z_u = %g\n", i, z);
1544 }
1545
1546 xfree(g.m);
1547 return (rc);
1548 }
1549
1550 /* --- Discard --- */
1551
1552 if (flags & f_discard) {
1553 generate(r, outsz, 0, 0);
1554 return (0);
1555 }
1556
1557 /* --- Write to a file --- */
1558
1559 #ifndef PORTABLE
1560 if (!(flags & f_file) && isatty(STDOUT_FILENO))
1561 die(EXIT_FAILURE, "writing output to a terminal is a bad idea");
1562 #endif
1563
1564 generate(r, outsz, genfile, outfp);
1565
1566 /* --- Done --- */
1567
1568 r->ops->destroy(r);
1569 return (0);
1570 }
1571
1572 /*----- That's all, folks -------------------------------------------------*/