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