math/Makefile.am, symm/Makefile.am: Use `--no-install' on oddball tests.
[catacomb] / progs / rspit.c
index 1fb33a9..66a0538 100644 (file)
@@ -27,6 +27,8 @@
 
 /*----- Header files ------------------------------------------------------*/
 
+#define _FILE_OFFSET_BITS 64
+
 #include "config.h"
 
 #include <assert.h>
@@ -40,6 +42,7 @@
 
 #ifndef PORTABLE
 #  include <unistd.h>
+#  include <sys/time.h>
 #endif
 
 #include <mLib/darray.h>
 #include "bbs.h"
 #include "mprand.h"
 
+#include "chacha.h"
 #include "rc4.h"
+#include "salsa20.h"
+#include "salsa20-core.h"
 #include "seal.h"
+#include "sha3.h"
 
 #include "des-ofb.h"
 #include "des3-ofb.h"
@@ -202,6 +209,62 @@ static const struct {
 #undef E
 };
 
+#define SALSAE                                                         \
+  E(salsa20, 20,, SALSA20)                                             \
+  E(salsa20, 12,, SALSA20)                                             \
+  E(salsa20, 8,, SALSA20)                                              \
+  E(xsalsa20, 20, X, SALSA20)                                          \
+  E(xsalsa20, 12, X, SALSA20)                                          \
+  E(xsalsa20, 8, X, SALSA20)                                           \
+  E(chacha, 20,, CHACHA)                                               \
+  E(chacha, 12,, CHACHA)                                               \
+  E(chacha, 8,, CHACHA)                                                        \
+  E(xchacha, 20, X, CHACHA)                                            \
+  E(xchacha, 12, X, CHACHA)                                            \
+  E(xchacha, 8, X, CHACHA)
+
+#define E(pre, r, x, BASE) pre##_##r##_INDEX,
+enum { SALSAE BOGUS_SALSA };
+#undef E
+
+#define SALSA20_GEN(pre, r) SALSA20_DECOR(pre, r, _rand)
+#define CHACHA_GEN(pre, r) pre##r##_rand
+
+#define SALSA20_NAME(r) SALSA20_NAME_##r
+#define XSALSA20_NAME(r) "x" SALSA20_NAME_##r
+#define CHACHA_NAME(r) "chacha" #r
+#define XCHACHA_NAME(r) "xchacha" #r
+
+static const struct {
+  size_t noncesz;
+  grand *(*gen)(const void *, size_t, const void *);
+} salsatab[] = {
+#define E(pre, r, x, BASE) { x##BASE##_NONCESZ, BASE##_GEN(pre, r) },
+  SALSAE
+#undef E
+};
+
+#define SHAKES E(128) E(256)
+
+enum {
+#define E(sz) SHAKE##sz##_INDEX,
+  SHAKES
+#undef E
+  SHAKE__LIMIT
+};
+
+static const struct {
+  const octet *ksz;
+  grand *(*shake)(const void *, size_t, const void *, size_t,
+                 const void *, size_t);
+  grand *(*kmac)(const void *, size_t,
+                const void *, size_t);
+} shaketab[] = {
+#define E(sz) { shake##sz##_keysz, cshake##sz##_rand, kmac##sz##_rand },
+  SHAKES
+#undef E
+};
+
 /*----- Miscellaneous static data -----------------------------------------*/
 
 static FILE *outfp;
@@ -804,6 +867,75 @@ static grand *gen_seal(unsigned i)
   return (r);
 }
 
+/* --- Salsa20, XSalsa20, ChaCha, and XChaCha --- */
+
+static grand *gen_salsae(unsigned i)
+{
+  grand *r;
+  char *p;
+  dstr d = DSTR_INIT;
+  dstr n = DSTR_INIT;
+  kludge64 pos = { 0 };
+  octet posbuf[8];
+  mp *x;
+
+  static struct option opts[] = {
+    { "key",           OPTF_ARGREQ,    0,      'k' },
+    { "hex",           OPTF_ARGREQ,    0,      'H' },
+    { "nonce",         OPTF_ARGREQ,    0,      'n' },
+    { "seek",          OPTF_ARGREQ,    0,      's' },
+    { 0,               0,              0,      0 }
+  };
+
+  addopts("k:H:n:s:", opts);
+
+  for (;;) {
+    int o = opt();
+    if (o < 0)
+      break;
+    switch (o) {
+      case 'k':
+       DRESET(&d);
+       textkey(&d, optarg, salsa20_keysz);
+       break;
+      case 'H':
+       DRESET(&d);
+       hexkey(&d, optarg, salsa20_keysz);
+       break;
+      case 'n':
+       DRESET(&n);
+       unhex(optarg, &p, &n);
+       if (*p)
+         die(EXIT_FAILURE, "bad hex IV `%s'", optarg);
+       if (n.len != salsatab[i].noncesz) {
+         die(EXIT_FAILURE, "bad nonce length %lu (must be %lu)",
+             (unsigned long)n.len, (unsigned long)salsatab[i].noncesz);
+       }
+       break;
+      case 's':
+       x = mp_readstring(MP_NEW, optarg, &p, 0);
+       if (*p || MP_NEGP(x) || mp_bits(x) > 64)
+         die(EXIT_FAILURE, "bad position `%s'", optarg);
+       mp_storeb(x, posbuf, sizeof(posbuf));
+       mp_drop(x);
+       LOAD64_(pos, posbuf);
+       break;
+      default:
+       return (0);
+    }
+  }
+
+  if (!d.len)
+    randkey(&d, salsa20_keysz);
+  r = salsatab[i].gen(d.buf, d.len, n.len ? n.buf : 0);
+  r->ops->misc(r, SALSA20_SEEKU64, pos);
+
+  dstr_destroy(&d);
+  dstr_destroy(&n);
+
+  return (r);
+}
+
 /* --- Output feedback generators --- */
 
 static grand *gen_ofb(unsigned i)
@@ -970,6 +1102,113 @@ static grand *gen_mgf(unsigned i)
   return (r);
 }
 
+/* --- SHAKE generators --- */
+
+static grand *gen_shake(unsigned i)
+{
+  dstr d = DSTR_INIT;
+  const char *func = 0, *perso = 0;
+  grand *r;
+
+  static struct option opts[] = {
+    { "function",      OPTF_ARGREQ,    0,      'F' },
+    { "personalization", OPTF_ARGREQ,  0,      'P' },
+    { "key",           OPTF_ARGREQ,    0,      'k' },
+    { "hex",           OPTF_ARGREQ,    0,      'H' },
+    { 0,               0,              0,      0 }
+  };
+
+  addopts("F:P:k:H:", opts);
+
+  for (;;) {
+    int o = opt();
+    if (o < 0)
+      break;
+    switch (o) {
+      case 'F':
+       func = optarg;
+       break;
+      case 'P':
+       perso = optarg;
+       break;
+      case 'k':
+       DRESET(&d);
+       textkey(&d, optarg, shaketab[i].ksz);
+       break;
+      case 'H':
+       DRESET(&d);
+       hexkey(&d, optarg, shaketab[i].ksz);
+       break;
+      default:
+       return (0);
+    }
+  }
+
+  if (!d.len) randkey(&d, shaketab[i].ksz);
+  r = shaketab[i].shake(func, func ? strlen(func) : 0,
+                       perso, perso ? strlen(perso) : 0,
+                       d.buf, d.len);
+  dstr_destroy(&d);
+  return (r);
+}
+
+/* --- KMAC generators --- */
+
+static grand *gen_kmac(unsigned i)
+{
+  dstr d = DSTR_INIT, m = DSTR_INIT;
+  const char *perso = 0;
+  char *q;
+  grand *r;
+
+  static struct option opts[] = {
+    { "personalization", OPTF_ARGREQ,  0,      'P' },
+    { "key",           OPTF_ARGREQ,    0,      'k' },
+    { "hex",           OPTF_ARGREQ,    0,      'H' },
+    { "message",       OPTF_ARGREQ,    0,      'M' },
+    { "msghex",                OPTF_ARGREQ,    0,      'N' },
+    { 0,               0,              0,      0 }
+  };
+
+  addopts("P:k:H:M:N:", opts);
+
+  for (;;) {
+    int o = opt();
+    if (o < 0)
+      break;
+    switch (o) {
+      case 'P':
+       perso = optarg;
+       break;
+      case 'k':
+       DRESET(&d);
+       textkey(&d, optarg, shaketab[i].ksz);
+       break;
+      case 'H':
+       DRESET(&d);
+       hexkey(&d, optarg, shaketab[i].ksz);
+       break;
+      case 'M':
+       DRESET(&m);
+       DPUTS(&d, optarg);
+       break;
+      case 'N':
+       DRESET(&m);
+       unhex(optarg, &q, &m);
+       if (*q) die(EXIT_FAILURE, "bad hex");
+       break;
+      default:
+       return (0);
+    }
+  }
+
+  if (!d.len) randkey(&d, shaketab[i].ksz);
+  r = shaketab[i].kmac(perso, perso ? strlen(perso) : 0, d.buf, d.len);
+  r->ops->misc(r, GRAND_SEEDBLOCK, (void *)m.buf, m.len);
+  dstr_destroy(&d); dstr_destroy(&m);
+  return (r);
+}
+
 /* --- Fibonacci generator --- */
 
 static grand *gen_fib(unsigned i)
@@ -1076,6 +1315,21 @@ gen generators[] = {
     "[-k KEY-PHRASE] [-H HEX-KEY] [-i INDEX]" },
   HASHES
 #undef E
+#define E(pre, r, x, BASE)                                             \
+  { x##BASE##_NAME(r), gen_salsae,     pre##_##r##_INDEX,              \
+    "[-k KEY-PHRASE] [-H HEX-KEY] [-n NONCE]" },
+  SALSAE
+#undef E
+#define E(sz)                                                          \
+  { "shake" #sz,       gen_shake,      SHAKE##sz##_INDEX,              \
+    "[-k KEY-PHRASE] [-H HEX-KEY]" },
+  SHAKES
+#undef E
+#define E(sz)                                                          \
+  { "kmac" #sz,                gen_kmac,       SHAKE##sz##_INDEX,              \
+    "[-k KEY-PHRASE] [-H HEX-KEY] [-m MSG]" },
+  SHAKES
+#undef E
   { "rc4",             gen_rc4,        0,
     "[-k KEY-PHRASE] [-H HEX-KEY]" },
   { "seal",            gen_seal,       0,
@@ -1124,6 +1378,22 @@ static int genmaurer(const void *buf, size_t sz, void *p)
   return (0);
 }
 
+static double doubletime(void)
+{
+#ifdef PORTABLE
+  static time_t start = (time_t)-1;
+  time_t now = time(0);
+
+  if (start == (time_t)-1) start = now;
+  return difftime(now, start);
+#else
+  struct timeval tv;
+
+  gettimeofday(&tv, 0);
+  return (tv.tv_sec + tv.tv_usec/1000000.0);
+#endif
+}
+
 static int generate(grand *r, mp *outsz,
                    int (*func)(const void *buf, size_t sz, void *p),
                    void *p)
@@ -1133,7 +1403,7 @@ static int generate(grand *r, mp *outsz,
   unsigned percent = 0;
   mp *kb = MP_ZERO, *t = MP_NEW;
   dstr d = DSTR_INIT;
-  time_t last;
+  double now, last;
   static char baton[] = "-\\|/";
   char *bp;
   int rc;
@@ -1141,7 +1411,7 @@ static int generate(grand *r, mp *outsz,
 
   /* --- Spit out random data --- */
 
-  last = time(0);
+  last = doubletime();
   bp = baton;
   if (flags & f_progress) {
     char *errbuf = xmalloc(BUFSIZ);
@@ -1184,14 +1454,15 @@ static int generate(grand *r, mp *outsz,
     /* --- Update the display --- */
 
     if (flags & f_progress) {
-      time_t now = time(0);
       unsigned up = 0;
 
+      now = doubletime();
+
       if (percent > 100)
        up = 1;
 
       if (!outsz) {
-       if (difftime(now, last) > 1.0) {
+       if (now - last > 0.1) {
          up = 1;
        }
        if (up)
@@ -1203,7 +1474,7 @@ static int generate(grand *r, mp *outsz,
        mp_div(&t, 0, t, outsz);
        assert(!MP_NEGP(t) && MP_CMP(t, <, MP_UINT_MAX));
        pc = mp_touint(t);
-       if (pc > percent || percent > 100 || difftime(now, last) > 1.0) {
+       if (pc > percent || percent > 100 || now - last > 0.1) {
          if (percent > 100)
            percent = 0;
          percent &= ~1;
@@ -1238,7 +1509,7 @@ static int generate(grand *r, mp *outsz,
       if (percent > 100)
        percent = 0;
 
-      if (percent < 100) {
+      if (percent < 100 && up) {
        putc(*bp++, stderr);
        putc('\b', stderr);
        if (!*bp)