symm/gcm.c: Add low-level multiplication tests.
[catacomb] / symm / gcm.c
index 749f9d6..330ec7b 100644 (file)
@@ -267,6 +267,16 @@ void gcm_mulk_##nbits(uint32 *a, const uint32 *ktab)                       \
 }
 GCM_WIDTHS(DEF_MULK)
 
+#define GCM_MULK_CASE(nbits)                                           \
+  case nbits/32: gcm_mulk_##nbits(_a, _ktab); break;
+#define MULK(n, a, ktab) do {                                          \
+  uint32 *_a = (a); const uint32 *_ktab = (ktab);                      \
+  switch (n) {                                                         \
+    GCM_WIDTHS(GCM_MULK_CASE)                                          \
+    default: abort();                                                  \
+  }                                                                    \
+} while (0)
+
 /*----- Other utilities ---------------------------------------------------*/
 
 /* --- @putlen@ --- *
@@ -327,21 +337,11 @@ static void mix(const gcm_params *p, uint32 *a,
 {
   unsigned i;
 
-  /* Convert the block from bytes into words, using the appropriate
-   * convention.
-   */
   if (p->f&GCMF_SWAP)
     for (i = 0; i < p->n; i++) { a[i] ^= LOAD32_L(q); q += 4; }
   else
     for (i = 0; i < p->n; i++) { a[i] ^= LOAD32_B(q); q += 4; }
-
-  /* Dispatch to the correct multiply-by-%$k$% function. */
-  switch (p->n) {
-#define CASE(nbits) case nbits/32: gcm_mulk_##nbits(a, ktab); break;
-    GCM_WIDTHS(CASE)
-#undef CASE
-    default: abort();
-  }
+  MULK(p->n, a, ktab);
 }
 
 /* --- @gcm_ghashdone@ --- *
@@ -453,4 +453,107 @@ void gcm_concat(const gcm_params *p, uint32 *z, const uint32 *x,
   }
 }
 
+/*----- Test rig ----------------------------------------------------------*/
+
+#ifdef TEST_RIG
+
+#include <mLib/quis.h>
+#include <mLib/testrig.h>
+
+static void report_failure(const char *test, unsigned nbits,
+                          dstr v[], dstr *d)
+{
+  printf("test %s failed (nbits = %u)", test, nbits);
+  printf("\n\tx  = "); type_hex.dump(&v[0], stdout);
+  printf("\n\ty  = "); type_hex.dump(&v[1], stdout);
+  printf("\n\tz  = "); type_hex.dump(&v[2], stdout);
+  printf("\n\tz' = "); type_hex.dump(d, stdout);
+  putchar('\n');
+}
+
+static void mulk(unsigned nbits, uint32 *x, const uint32 *ktab)
+  { MULK(nbits/32, x, ktab); }
+
+static int test_mul(uint32 poly, dstr v[])
+{
+  uint32 x[GCM_NMAX], y[GCM_NMAX], z[GCM_NMAX], ktab[32*GCM_NMAX*GCM_NMAX];
+  gcm_params p;
+  dstr d = DSTR_INIT;
+  unsigned i, nbits;
+  int ok = 1;
+
+  nbits = 8*v[0].len; p.f = 0; p.n = nbits/32; p.poly = poly;
+  dstr_ensure(&d, nbits/8); d.len = nbits/8;
+
+  /* First, test plain multiply. */
+  for (i = 0; i < nbits/32; i++)
+    { x[i] = LOAD32_B(v[0].buf + 4*i); y[i] = LOAD32_B(v[1].buf + 4*i); }
+  mul(&p, z, x, y);
+  for (i = 0; i < nbits/32; i++) STORE32_B(d.buf + 4*i, z[i]);
+  if (memcmp(d.buf, v[2].buf, nbits/8) != 0)
+    { ok = 0; report_failure("gcm_mul", nbits, v, &d); }
+
+  /* Next, test big-endian prepared key. */
+  for (i = 0; i < nbits/32; i++)
+    { x[i] = LOAD32_B(v[0].buf + 4*i); y[i] = LOAD32_B(v[1].buf + 4*i); }
+  gcm_mktable(&p, ktab, y);
+  mulk(nbits, x, ktab);
+  for (i = 0; i < nbits/32; i++) STORE32_B(d.buf + 4*i, x[i]);
+  if (memcmp(d.buf, v[2].buf, nbits/8) != 0)
+    { ok = 0; report_failure("gcm_kmul_b(k = y)", nbits, v, &d); }
+
+  for (i = 0; i < nbits/32; i++)
+    { x[i] = LOAD32_B(v[0].buf + 4*i); y[i] = LOAD32_B(v[1].buf + 4*i); }
+  gcm_mktable(&p, ktab, x);
+  mulk(nbits, y, ktab);
+  for (i = 0; i < nbits/32; i++) STORE32_B(d.buf + 4*i, y[i]);
+  if (memcmp(d.buf, v[2].buf, nbits/8) != 0)
+    { ok = 0; report_failure("gcm_kmul_b(k = x)", nbits, v, &d); }
+
+  /* Finally, test little-endian prepared key. */
+  p.f = GCMF_SWAP;
+  for (i = 0; i < nbits/32; i++)
+    { x[i] = LOAD32_L(v[0].buf + 4*i); y[i] = LOAD32_L(v[1].buf + 4*i); }
+  gcm_mktable(&p, ktab, y);
+  mulk(nbits, x, ktab);
+  for (i = 0; i < nbits/32; i++) STORE32_L(d.buf + 4*i, x[i]);
+  if (memcmp(d.buf, v[2].buf, nbits/8) != 0)
+    { ok = 0; report_failure("gcm_kmul_l(k = y)", nbits, v, &d); }
+
+  for (i = 0; i < nbits/32; i++)
+    { x[i] = LOAD32_L(v[0].buf + 4*i); y[i] = LOAD32_L(v[1].buf + 4*i); }
+  gcm_mktable(&p, ktab, x);
+  mulk(nbits, y, ktab);
+  for (i = 0; i < nbits/32; i++) STORE32_L(d.buf + 4*i, y[i]);
+  if (memcmp(d.buf, v[2].buf, nbits/8) != 0)
+    { ok = 0; report_failure("gcm_kmul_l(k = x)", nbits, v, &d); }
+
+  /* All done. */
+  return (ok);
+}
+
+#define TEST(nbits)                                                    \
+static int test_mul_##nbits(dstr v[])                                  \
+  { return (test_mul(GCM_POLY_##nbits, v)); }
+GCM_WIDTHS(TEST)
+#undef TEST
+
+static test_chunk defs[] = {
+#define TEST(nbits)                                                    \
+  { "gcm-mul" #nbits, test_mul_##nbits,                                        \
+    { &type_hex, &type_hex, &type_hex, 0 } },
+GCM_WIDTHS(TEST)
+#undef TEST
+  { 0, 0, { 0 } }
+};
+
+int main(int argc,  char *argv[])
+{
+  ego(argv[0]);
+  test_run(argc, argv, defs, SRCDIR"/t/gcm");
+  return (0);
+}
+
+#endif
+
 /*----- That's all, folks -------------------------------------------------*/