+ /* --- Done --- */
+
+ return (PGEN_DONE);
+}
+
+/* --- @limlee_step@ --- */
+
+int limlee_step(int rq, pgen_event *ev, void *p)
+{
+ limlee_stepctx *l = p;
+ int rc;
+
+ switch (rq) {
+ case PGEN_BEGIN:
+ if ((rc = init(ev, l)) != PGEN_TRY)
+ return (rc);
+ case PGEN_TRY:
+ return (next(rq, ev, l));
+ case PGEN_DONE:
+ return (done(ev, l));
+ }
+ return (PGEN_ABORT);
+}
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @limlee@ --- *
+ *
+ * Arguments: @const char *name@ = pointer to name root
+ * @mp *d@ = pointer to destination integer
+ * @mp *newp@ = how to generate factor primes
+ * @unsigned ql@ = size of individual factors
+ * @unsigned pl@ = size of large prime
+ * @grand *r@ = a random number source
+ * @unsigned on@ = number of outer attempts to make
+ * @pgen_proc *oev@ = outer event handler function
+ * @void *oec@ = argument for the outer event handler
+ * @pgen_proc *iev@ = inner event handler function
+ * @void *iec@ = argument for the inner event handler
+ * @size_t *nf@, @mp ***f@ = output array for factors
+ *
+ * Returns: A Lim-Lee prime, or null if generation failed.
+ *
+ * Use: Generates Lim-Lee primes. A Lim-Lee prime %$p$% is one which
+ * satisfies %$p = 2 \prod_i q_i + 1$%, where all of the %$q_i$%
+ * are large enough to resist square-root discrete log
+ * algorithms.
+ *
+ * If we succeed, and @f@ is non-null, we write the array of
+ * factors chosen to @f@ for the benefit of the caller.
+ */
+
+mp *limlee(const char *name, mp *d, mp *newp,
+ unsigned ql, unsigned pl, grand *r,
+ unsigned on, pgen_proc *oev, void *oec,
+ pgen_proc *iev, void *iec,
+ size_t *nf, mp ***f)
+{
+ limlee_stepctx l;
+ rabin rr;
+
+ l.f = 0; if (f) l.f |= LIMLEE_KEEPFACTORS;
+ l.newp = newp;
+ l.pl = pl; l.ql = ql;
+ l.pops = 0;
+ l.iev = iev;
+ l.iec = iec;
+ l.r = r;
+
+ d = pgen(name, d, 0, oev, oec, on, limlee_step, &l,
+ rabin_iters(pl), pgen_test, &rr);
+
+ if (f) {
+ mp **v;
+ size_t i;
+ v = xmalloc(l.nf * sizeof(mp *));
+ for (i = 0; i < l.nf; i++)
+ v[i] = l.v[i].p;
+ xfree(l.v);
+ *f = v;
+ *nf = l.nf;