+/* --- @dsa_gen@ --- *
+ *
+ * Arguments: @dsa_param *dp@ = where to store parameters
+ * @unsigned ql@ = length of @q@ in bits
+ * @unsigned pl@ = length of @p@ in bits
+ * @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.
+ *
+ * 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
+ * requires that %$q$% be 160 bits in size (i.e., @ql == 160@)
+ * and that the length of %$p$% be %$L = 512 + 64l$% for some
+ * %$l$%. Neither limitation applies to this implementation.
+ */
+
+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;
+ int i;
+ rabin r;
+ mp *qc;
+
+ /* --- Initialize the stepping context --- */
+
+ s.r = dsarand_create(k, sz);
+
+ /* --- 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@ --- *
+ *
+ * The division returns remainder 1. This doesn't matter.
+ */