hashsum.1: Write some notes about compatibility with GNU Coreutils.
[u/mdw/catacomb] / dsa-gen.c
index d26bfe4..adb8d9a 100644 (file)
--- a/dsa-gen.c
+++ b/dsa-gen.c
@@ -1,13 +1,13 @@
 /* -*-c-*-
  *
- * $Id: dsa-gen.c,v 1.4 1999/12/22 15:52:44 mdw Exp $
+ * $Id: dsa-gen.c,v 1.10 2004/04/08 01:36:15 mdw Exp $
  *
  * Generate DSA shared parameters
  *
  * (c) 1999 Straylight/Edgeware
  */
 
-/*----- Licensing notice --------------------------------------------------* 
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of Catacomb.
  *
  * it under the terms of the GNU Library General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
- * 
+ *
  * Catacomb is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU Library General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU Library General Public
  * License along with Catacomb; if not, write to the Free
  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
  * MA 02111-1307, USA.
  */
 
-/*----- Revision history --------------------------------------------------* 
- *
- * $Log: dsa-gen.c,v $
- * Revision 1.4  1999/12/22 15:52:44  mdw
- * Reworking for new prime-search system.
- *
- * Revision 1.3  1999/12/10 23:18:38  mdw
- * Change interface for suggested destinations.
- *
- * Revision 1.2  1999/11/20 22:23:48  mdw
- * Allow event handler to abort the search process.
- *
- * Revision 1.1  1999/11/19 19:28:00  mdw
- * Implementation of the Digital Signature Algorithm.
- *
- */
-
 /*----- Header files ------------------------------------------------------*/
 
 #include <stdio.h>
@@ -56,7 +39,6 @@
 #include "mprand.h"
 #include "pgen.h"
 #include "prim.h"
-#include "primorial.h"
 #include "sha.h"
 
 /*----- The DSA stepper ---------------------------------------------------*/
@@ -78,7 +60,9 @@ static int next(pgen_event *ev, dsa_stepctx *d)
 
   /* --- Load the new candidate --- */
 
-  m = mprand(ev->m, d->bits, d->r, d->or);
+  if (d->seedbuf)
+    d->r->ops->misc(d->r, DSARAND_GETSEED, d->seedbuf);
+  m = mprand(ev->m, d->bits, d->r, 0);
 
   /* --- Force to be a multiple of @q@ --- */
 
@@ -93,15 +77,8 @@ static int next(pgen_event *ev, dsa_stepctx *d)
 
   /* --- Do the trial division --- */
 
-  {
-    mp *g = MP_NEW;
-    mp_gcd(&g, 0, 0, m, primorial);
-    if (MP_CMP(g, ==, MP_ONE) || MP_CMP(g, ==, m))
-      rc = PGEN_TRY;
-    else
-      rc = PGEN_FAIL;
-    mp_drop(g);
-  }
+  rc = pfilt_smallfactor(m);
+  d->count++;
 
   /* --- Return the result --- */
 
@@ -116,7 +93,6 @@ int dsa_step(int rq, pgen_event *ev, void *p)
 
   switch (rq) {
     case PGEN_BEGIN:
-      primorial_setup();
     case PGEN_TRY:
       return (next(ev, d));
     case PGEN_DONE:
@@ -127,7 +103,7 @@ int dsa_step(int rq, pgen_event *ev, void *p)
 
 /*----- Glue code ---------------------------------------------------------*/
 
-/* --- @dsa_seed@ --- *
+/* --- @dsa_gen@ --- *
  *
  * Arguments:  @dsa_param *dp@ = where to store parameters
  *             @unsigned ql@ = length of @q@ in bits
@@ -135,13 +111,19 @@ int dsa_step(int rq, pgen_event *ev, void *p)
  *             @unsigned steps@ = number of steps to find @q@
  *             @const void *k@ = pointer to key material
  *             @size_t sz@ = size of key material
+ *             @dsa_seed *ds@ = optional pointer for output seed information
  *             @pgen_proc *event@ = event handler function
  *             @void *ectx@ = argument for event handler
  *
  * Returns:    @PGEN_DONE@ if everything worked ok; @PGEN_ABORT@ otherwise.
  *
  * Use:                Generates the DSA shared parameters from a given seed value.
- *             This can take quite a long time.
+ *
+ *             The parameters are a prime %$q$%, relatively small, and a
+ *             large prime %$p = kq + 1$% for some %$k$%, together with a
+ *             generator %$g$% of the cyclic subgroup of order %$q$%.  These
+ *             are actually the same as the Diffie-Hellman parameter set,
+ *             but the generation algorithm is different.
  *
  *             The algorithm used is a compatible extension of the method
  *             described in the DSA standard, FIPS 186.  The standard
@@ -150,8 +132,9 @@ int dsa_step(int rq, pgen_event *ev, void *p)
  *             %$l$%.  Neither limitation applies to this implementation.
  */
 
-int dsa_seed(dsa_param *dp, unsigned ql, unsigned pl, unsigned steps,
-            const void *k, size_t sz, pgen_proc *event, void *ectx)
+int dsa_gen(dsa_param *dp, unsigned ql, unsigned pl, unsigned steps,
+           const void *k, size_t sz, dsa_seed *ds,
+           pgen_proc *event, void *ectx)
 {
   dsa_stepctx s;
   prim_ctx p;
@@ -162,26 +145,37 @@ int dsa_seed(dsa_param *dp, unsigned ql, unsigned pl, unsigned steps,
   /* --- Initialize the stepping context --- */
 
   s.r = dsarand_create(k, sz);
-  s.or = 1;
 
   /* --- Find @q@ --- */
 
   s.q = 0;
   s.r->ops->misc(s.r, DSARAND_PASSES, 2);
   s.bits = ql;
+  s.count = 0;
+  s.or = 1;
+  if (!ds)
+    s.seedbuf = 0;
+  else {
+    ds->sz = sz;
+    ds->p = s.seedbuf = xmalloc(sz);
+  }
   if ((dp->q = pgen("q", MP_NEW, MP_NEW, event, ectx, steps, dsa_step, &s,
                    rabin_iters(ql), pgen_test, &r)) == 0)
     goto fail_q;
 
   /* --- Find @p@ --- */
 
+  s.count = ~0;
   s.q = mp_lsl(MP_NEW, dp->q, 1);
   s.r->ops->misc(s.r, DSARAND_PASSES, 1);
   s.bits = pl;
+  s.seedbuf = 0;
   if ((dp->p = pgen("p", MP_NEW, MP_NEW, event, ectx, 4096, dsa_step, &s,
                    rabin_iters(pl), pgen_test, &r)) == 0)
     goto fail_p;
   mp_drop(s.q);
+  if (ds)
+    ds->count = s.count;
 
   /* --- Find @g@ --- *
    *
@@ -191,7 +185,7 @@ int dsa_seed(dsa_param *dp, unsigned ql, unsigned pl, unsigned steps,
   mpmont_create(&p.mm, dp->p);
   qc = MP_NEW; mp_div(&qc, 0, dp->p, dp->q);
   i = 0;
-  p.f = qc;
+  p.exp = qc;
   p.n = 0;
   if ((dp->g = pgen("g", MP_NEW, MP_NEW, event, ectx, 0, prim_step, &i,
                    1, prim_test, &p)) == 0)
@@ -214,6 +208,8 @@ fail_p:
   mp_drop(s.q);
 fail_q:
   s.r->ops->destroy(s.r);
+  if (ds)
+    xfree(ds->p);
   return (PGEN_ABORT);
 }
 
@@ -223,24 +219,35 @@ fail_q:
 
 static int verify(dstr *v)
 {
-  mp *q = *(mp **)v[2].buf;
-  mp *p = *(mp **)v[3].buf;
-  mp *g = *(mp **)v[4].buf;
+  mp *q = *(mp **)v[4].buf;
+  mp *p = *(mp **)v[5].buf;
+  mp *g = *(mp **)v[6].buf;
   dsa_param dp;
-  unsigned l = *(unsigned *)v[1].buf;
+  dsa_seed ds;
+  unsigned long l = *(unsigned long *)v[1].buf;
+  unsigned long n = *(unsigned long *)v[3].buf;
   int ok = 1;
   int rc;
+  keycheck kc;
+  keycheck_reportctx kcr;
 
-  rc = dsa_seed(&dp, 160, l, 1, v[0].buf, v[0].len, pgen_evspin, 0);
-  if (rc || MP_CMP(q, !=, dp.q) ||
-      MP_CMP(p, !=, dp.p) || MP_CMP(g, !=, dp.g)) {
+  rc = dsa_gen(&dp, 160, l, 16, v[0].buf, v[0].len, &ds, pgen_evspin, 0);
+  if (rc || ds.count != n || ds.sz != v[2].len ||
+      memcmp(ds.p, v[2].buf, v[2].len) != 0 ||
+      !MP_EQ(q, dp.q) || !MP_EQ(p, dp.p) || !MP_EQ(g, dp.g)) {
     fputs("\n*** gen failed", stderr);
-    fputs("\nseed = ", stderr); type_hex.dump(&v[0], stderr);
-    fprintf(stderr, "\nl = %u", l);
-    fputs("\n   q = ", stderr); mp_writefile(q, stderr, 16);
-    fputs("\n   p = ", stderr); mp_writefile(p, stderr, 16);
-    fputs("\n   g = ", stderr); mp_writefile(g, stderr, 16);
+    fputs("\nseed_in = ", stderr); type_hex.dump(&v[0], stderr);
+    fprintf(stderr, "\nl = %lu", l);
+    fputs("\nseed_out = ", stderr); type_hex.dump(&v[2], stderr);
+    fprintf(stderr, "\ncount = %lu", n);
+    fputs("\n  q = ", stderr); mp_writefile(q, stderr, 16);
+    fputs("\n  p = ", stderr); mp_writefile(p, stderr, 16);
+    fputs("\n  g = ", stderr); mp_writefile(g, stderr, 16);
     if (!rc) {
+      dstr d;
+      d.buf = ds.p; d.len = ds.sz;
+      fputs("\nds.seed = ", stderr); type_hex.dump(&d, stderr);
+      fprintf(stderr, "\nds.count = %u", ds.count);
       fputs("\ndp.q = ", stderr); mp_writefile(dp.q, stderr, 16);
       fputs("\ndp.p = ", stderr); mp_writefile(dp.p, stderr, 16);
       fputs("\ndp.g = ", stderr); mp_writefile(dp.g, stderr, 16);
@@ -249,17 +256,36 @@ static int verify(dstr *v)
     ok = 0;
   }
 
+  kcr.fp = stderr;
+  kcr.sev = KCSEV_ERR;
+  keycheck_init(&kc, keycheck_stdreport, &kcr);
+  if (!rc)
+    dsa_checkparam(&kc, &dp, &ds);
+  if (!keycheck_allclear(&kc, KCSEV_ERR)) {
+    fputs("\n*** gen failed check", stderr);
+    fputs("\nseed_in = ", stderr); type_hex.dump(&v[0], stderr);
+    fprintf(stderr, "\nl = %lu", l);
+    fputs("\nseed_out = ", stderr); type_hex.dump(&v[2], stderr);
+    fprintf(stderr, "\ncount = %lu", n);
+    fputs("\n  q = ", stderr); mp_writefile(q, stderr, 16);
+    fputs("\n  p = ", stderr); mp_writefile(p, stderr, 16);
+    fputs("\n  g = ", stderr); mp_writefile(g, stderr, 16);
+    fputc('\n', stderr);
+    ok = 0;
+  }
+
   mp_drop(q); mp_drop(p); mp_drop(g);
   if (!rc) {
-    mp_drop(dp.q); mp_drop(dp.p); mp_drop(dp.g);
+    mp_drop(dp.q); mp_drop(dp.p); mp_drop(dp.g); xfree(ds.p);
   }
-  assert(mparena_count(MPARENA_GLOBAL) == 1); /* Primorial! */
+  assert(mparena_count(MPARENA_GLOBAL) == 0);
   return (ok);
 }
 
 static test_chunk tests[] = {
   { "gen", verify,
-    { &type_hex, &type_int, &type_mp, &type_mp, &type_mp, 0 }  },
+    { &type_hex, &type_ulong, &type_hex, &type_ulong,
+      &type_mp, &type_mp, &type_mp, 0 }         },
   { 0, 0, { 0 } }
 };