3 * $Id: limlee.c,v 1.8 2001/02/03 11:59:07 mdw Exp $
5 * Generate Lim-Lee primes
7 * (c) 2000 Straylight/Edgeware
10 /*----- Licensing notice --------------------------------------------------*
12 * This file is part of Catacomb.
14 * Catacomb is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Library General Public License as
16 * published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
19 * Catacomb is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
24 * You should have received a copy of the GNU Library General Public
25 * License along with Catacomb; if not, write to the Free
26 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
30 /*----- Revision history --------------------------------------------------*
33 * Revision 1.8 2001/02/03 11:59:07 mdw
34 * Don't use the @pgen@ random number generator for generating primes: it's
35 * only for testing them. Use a caller-supplied one instead.
37 * Revision 1.7 2001/01/25 21:40:44 mdw
38 * Remove dead code now that the new stepper structure is trustworthy.
40 * Revision 1.6 2001/01/25 21:16:20 mdw
41 * Boring cosmetic stuff.
43 * Revision 1.5 2000/08/18 19:16:51 mdw
44 * New stepper interface for constructing Lim-Lee primes.
46 * Revision 1.4 2000/08/15 21:45:05 mdw
47 * Use the new trial division equipment in pfilt. This gives a 10%
48 * performance improvement in dsa-gen.t.
50 * Revision 1.3 2000/07/29 09:58:32 mdw
51 * (limlee): Bug fix. Old versions didn't set the filter step if @ql@ was
52 * an exact divisor of @pl@.
54 * Revision 1.2 2000/07/26 18:00:00 mdw
57 * Revision 1.1 2000/07/09 21:30:58 mdw
58 * Lim-Lee prime generation.
62 /*----- Header files ------------------------------------------------------*/
64 #include <mLib/alloc.h>
65 #include <mLib/dstr.h>
73 /*----- Stepping through combinations -------------------------------------*/
75 /* --- @comb_init@ --- *
77 * Arguments: @octet *c@ = pointer to byte-flag array
78 * @unsigned n@ = number of items in the array
79 * @unsigned r@ = number of desired items
83 * Use: Initializes a byte-flag array which, under the control of
84 * @comb_next@, will step through all combinations of @r@ chosen
88 static void comb_init(octet *c, unsigned n, unsigned r)
91 memset(c + (n - r), 1, r);
94 /* --- @comb_next@ --- *
96 * Arguments: @octet *c@ = pointer to byte-flag array
97 * @unsigned n@ = number of items in the array
98 * @unsigned r@ = number of desired items
100 * Returns: Nonzero if another combination was returned, zero if we've
103 * Use: Steps on to the next combination in sequence.
106 static int comb_next(octet *c, unsigned n, unsigned r)
110 /* --- How the algorithm works --- *
112 * Set bits start at the end and work their way towards the start.
113 * Excepting bits already at the start, we scan for the lowest set bit, and
114 * move it one place nearer the start. A group of bits at the start are
115 * counted and reset just below the `moved' bit. If there is no moved bit
119 /* --- Count the group at the start --- */
128 /* --- Move the next bit down one --- *
130 * There must be one, because otherwise we'd have counted %$r$% bits
143 /*----- Default prime generator -------------------------------------------*/
145 static void llgen(limlee_factor *f, unsigned pl, limlee_stepctx *l)
152 p = mprand(l->newp, pl, l->r, 1);
154 p = pgen(l->d.buf, p, p, l->iev, l->iec, 0, pgen_filter, &pf,
155 rabin_iters(pl), pgen_test, &r);
161 static void llfree(limlee_factor *f, limlee_stepctx *l)
166 static const limlee_primeops primeops_simple = { llgen, llfree };
168 /*----- Lim-Lee stepper ---------------------------------------------------*/
172 * Arguments: @pgen_event *ev@ = pointer to event block
173 * @limlee_stepctx *l@ = pointer to Lim-Lee context
175 * Returns: A @PGEN@ result code.
177 * Use: Initializes the stepper.
180 static int init(pgen_event *ev, limlee_stepctx *l)
185 /* --- First of all, decide on a number of factors to make --- */
187 l->nf = l->pl / l->ql;
191 else if (qql && l->nf > 1) {
196 /* --- Now decide on how many primes I'll actually generate --- *
198 * The formula %$m = \max(3 n + 5, 25)$% comes from GPG's prime generation
202 l->poolsz = l->nf * 3 + 5;
206 /* --- Allocate and initialize the various tables --- */
208 l->c = xmalloc(l->poolsz);
209 l->v = xmalloc(l->poolsz * sizeof(limlee_factor));
210 comb_init(l->c, l->poolsz, l->nf);
211 for (i = 0; i < l->poolsz; i++)
214 /* --- Other bits of initialization --- */
219 l->pops = &primeops_simple;
223 /* --- Find a big prime --- */
228 dstr_putf(&l->d, "%s*", ev->name);
229 l->pops->pgen(&l->qq, qql, l);
237 * Arguments: @int rq@ = request which triggered this call
238 * @pgen_event *ev@ = pointer to event block
239 * @limlee_stepctx *l@ = pointer to Lim-Lee context
241 * Returns: A @PGEN@ result code.
243 * Use: Initializes the stepper.
246 static int next(int rq, pgen_event *ev, limlee_stepctx *l)
255 mpmul mm = MPMUL_INIT;
257 /* --- Step on to next combination --- */
259 if (rq == PGEN_TRY && !comb_next(l->c, l->poolsz, l->nf)) {
260 for (i = 0; i < l->poolsz; i++) {
261 l->pops->pfree(&l->v[i], l);
265 rq = PGEN_TRY; /* For next time through */
267 /* --- Gather up some factors --- */
270 mpmul_add(&mm, l->qq.p);
271 for (i = 0; i < l->poolsz; i++) {
276 dstr_putf(&l->d, "%s_%lu", ev->name, l->seq++);
277 l->pops->pgen(&l->v[i], l->ql, l);
279 mpmul_add(&mm, l->v[i].p);
282 /* --- Check it for small factors --- */
287 if ((rc = pfilt_smallfactor(p)) != PGEN_FAIL)
298 * Arguments: @pgen_event *ev@ = pointer to event block
299 * @limlee_stepctx *l@ = pointer to Lim-Lee context
301 * Returns: A @PGEN@ result code.
303 * Use: Finalizes the stepper. The output values in the context
304 * take on their final results; other resources are discarded.
307 static int done(pgen_event *ev, limlee_stepctx *l)
312 /* --- If an output vector of factors is wanted, produce one --- */
314 if (!(l->f & LIMLEE_KEEPFACTORS))
319 v = xmalloc(l->nf * sizeof(limlee_factor));
322 for (i = 0, j = 0; i < l->poolsz; i++) {
326 l->pops->pfree(&l->v[i], l);
333 l->pops->pfree(&l->qq, l);
339 /* --- Free other resources --- */
349 /* --- @limlee_step@ --- */
351 int limlee_step(int rq, pgen_event *ev, void *p)
353 limlee_stepctx *l = p;
358 if ((rc = init(ev, l)) != PGEN_TRY)
361 return (next(rq, ev, l));
363 return (done(ev, l));
368 /*----- Main code ---------------------------------------------------------*/
370 /* --- @limlee@ --- *
372 * Arguments: @const char *name@ = pointer to name root
373 * @mp *d@ = pointer to destination integer
374 * @mp *newp@ = how to generate factor primes
375 * @unsigned ql@ = size of individual factors
376 * @unsigned pl@ = size of large prime
377 * @grand *r@ = a random number source
378 * @unsigned on@ = number of outer attempts to make
379 * @pgen_proc *oev@ = outer event handler function
380 * @void *oec@ = argument for the outer event handler
381 * @pgen_proc *iev@ = inner event handler function
382 * @void *iec@ = argument for the inner event handler
383 * @size_t *nf@, @mp ***f@ = output array for factors
385 * Returns: A Lim-Lee prime, or null if generation failed.
387 * Use: Generates Lim-Lee primes. A Lim-Lee prime %$p$% is one which
388 * satisfies %$p = 2 \prod_i q_i + 1$%, where all of the %$q_i$%
389 * are large enough to resist square-root discrete log
392 * If we succeed, and @f@ is non-null, we write the array of
393 * factors chosen to @f@ for the benefit of the caller.
396 mp *limlee(const char *name, mp *d, mp *newp,
397 unsigned ql, unsigned pl, grand *r,
398 unsigned on, pgen_proc *oev, void *oec,
399 pgen_proc *iev, void *iec,
405 l.f = 0; if (f) l.f |= LIMLEE_KEEPFACTORS;
407 l.pl = pl; l.ql = ql;
413 d = pgen(name, d, 0, oev, oec, on, limlee_step, &l,
414 rabin_iters(pl), pgen_test, &rr);
419 v = xmalloc(l.nf * sizeof(mp *));
420 for (i = 0; i < l.nf; i++)
430 /*----- That's all, folks -------------------------------------------------*/