Store the correct seed information and count for DSA keys now that it's
[u/mdw/catacomb] / limlee.c
CommitLineData
04361334 1/* -*-c-*-
2 *
d50e18d7 3 * $Id: limlee.c,v 1.7 2001/01/25 21:40:44 mdw Exp $
04361334 4 *
5 * Generate Lim-Lee primes
6 *
7 * (c) 2000 Straylight/Edgeware
8 */
9
10/*----- Licensing notice --------------------------------------------------*
11 *
12 * This file is part of Catacomb.
13 *
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.
18 *
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.
23 *
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,
27 * MA 02111-1307, USA.
28 */
29
30/*----- Revision history --------------------------------------------------*
31 *
32 * $Log: limlee.c,v $
d50e18d7 33 * Revision 1.7 2001/01/25 21:40:44 mdw
34 * Remove dead code now that the new stepper structure is trustworthy.
35 *
3c0e5a02 36 * Revision 1.6 2001/01/25 21:16:20 mdw
37 * Boring cosmetic stuff.
38 *
10217a5c 39 * Revision 1.5 2000/08/18 19:16:51 mdw
40 * New stepper interface for constructing Lim-Lee primes.
41 *
8a33545f 42 * Revision 1.4 2000/08/15 21:45:05 mdw
43 * Use the new trial division equipment in pfilt. This gives a 10%
44 * performance improvement in dsa-gen.t.
45 *
2f627546 46 * Revision 1.3 2000/07/29 09:58:32 mdw
47 * (limlee): Bug fix. Old versions didn't set the filter step if @ql@ was
48 * an exact divisor of @pl@.
49 *
d28d625a 50 * Revision 1.2 2000/07/26 18:00:00 mdw
51 * No footer line!
52 *
04361334 53 * Revision 1.1 2000/07/09 21:30:58 mdw
54 * Lim-Lee prime generation.
55 *
56 */
57
58/*----- Header files ------------------------------------------------------*/
59
60#include <mLib/alloc.h>
61#include <mLib/dstr.h>
62
63#include "limlee.h"
64#include "mpmul.h"
65#include "mprand.h"
66#include "pgen.h"
04361334 67#include "rabin.h"
68
10217a5c 69/*----- Stepping through combinations -------------------------------------*/
04361334 70
10217a5c 71/* --- @comb_init@ --- *
04361334 72 *
10217a5c 73 * Arguments: @octet *c@ = pointer to byte-flag array
74 * @unsigned n@ = number of items in the array
75 * @unsigned r@ = number of desired items
04361334 76 *
10217a5c 77 * Returns: ---
04361334 78 *
10217a5c 79 * Use: Initializes a byte-flag array which, under the control of
80 * @comb_next@, will step through all combinations of @r@ chosen
81 * elements.
04361334 82 */
83
84static void comb_init(octet *c, unsigned n, unsigned r)
85{
86 memset(c, 0, n - r);
87 memset(c + (n - r), 1, r);
88}
89
10217a5c 90/* --- @comb_next@ --- *
91 *
92 * Arguments: @octet *c@ = pointer to byte-flag array
93 * @unsigned n@ = number of items in the array
94 * @unsigned r@ = number of desired items
95 *
96 * Returns: Nonzero if another combination was returned, zero if we've
97 * reached the end.
98 *
99 * Use: Steps on to the next combination in sequence.
100 */
101
04361334 102static int comb_next(octet *c, unsigned n, unsigned r)
103{
104 unsigned g = 0;
105
106 /* --- How the algorithm works --- *
107 *
108 * Set bits start at the end and work their way towards the start.
109 * Excepting bits already at the start, we scan for the lowest set bit, and
110 * move it one place nearer the start. A group of bits at the start are
111 * counted and reset just below the `moved' bit. If there is no moved bit
112 * then we're done.
113 */
114
115 /* --- Count the group at the start --- */
116
117 for (; *c; c++) {
118 g++;
119 *c = 0;
120 }
121 if (g == r)
122 return (0);
123
124 /* --- Move the next bit down one --- *
125 *
126 * There must be one, because otherwise we'd have counted %$r$% bits
127 * earlier.
128 */
129
130 for (; !*c; c++)
131 ;
132 *c = 0;
133 g++;
134 for (; g; g--)
135 *--c = 1;
136 return (1);
137}
138
10217a5c 139/*----- Default prime generator -------------------------------------------*/
140
141static void llgen(limlee_factor *f, unsigned pl, limlee_stepctx *l)
142{
143 pgen_filterctx pf;
144 rabin r;
145 mp *p;
146
147again:
148 p = mprand(l->newp, pl, l->r, 1);
149 pf.step = 2;
150 p = pgen(l->d.buf, p, p, l->iev, l->iec, 0, pgen_filter, &pf,
151 rabin_iters(pl), pgen_test, &r);
152 if (!p)
153 goto again;
154 f->p = p;
155}
156
157static void llfree(limlee_factor *f, limlee_stepctx *l)
158{
159 if (f->p)
160 mp_drop(f->p);
161}
162
163static const limlee_primeops primeops_simple = { llgen, llfree };
164
165/*----- Lim-Lee stepper ---------------------------------------------------*/
166
167/* --- @init@ --- *
168 *
169 * Arguments: @pgen_event *ev@ = pointer to event block
170 * @limlee_stepctx *l@ = pointer to Lim-Lee context
171 *
172 * Returns: A @PGEN@ result code.
173 *
174 * Use: Initializes the stepper.
175 */
176
177static int init(pgen_event *ev, limlee_stepctx *l)
178{
179 size_t i;
180 unsigned qql;
181
182 /* --- First of all, decide on a number of factors to make --- */
183
184 l->nf = l->pl / l->ql;
185 qql = l->pl % l->ql;
186 if (!l->nf)
187 return (PGEN_ABORT);
188 else if (qql && l->nf > 1) {
189 l->nf--;
190 qql += l->ql;
191 }
192
193 /* --- Now decide on how many primes I'll actually generate --- *
194 *
195 * The formula %$m = \max(3 n + 5, 25)$% comes from GPG's prime generation
196 * library.
197 */
198
199 l->poolsz = l->nf * 3 + 5;
200 if (l->poolsz < 25)
201 l->poolsz = 25;
202
203 /* --- Allocate and initialize the various tables --- */
204
205 l->c = xmalloc(l->poolsz);
206 l->v = xmalloc(l->poolsz * sizeof(limlee_factor));
207 comb_init(l->c, l->poolsz, l->nf);
208 for (i = 0; i < l->poolsz; i++)
209 l->v[i].p = 0;
210
211 /* --- Other bits of initialization --- */
212
213 l->seq = 0;
214 l->r = ev->r;
215 dstr_create(&l->d);
216 if (!l->pops) {
217 l->pops = &primeops_simple;
218 l->pc = 0;
219 }
220
221 /* --- Find a big prime --- */
222
223 if (!qql)
224 l->qq.p = 0;
225 else {
226 dstr_putf(&l->d, "%s*", ev->name);
227 l->pops->pgen(&l->qq, qql, l);
228 }
229
230 return (PGEN_TRY);
231}
232
233/* --- @next@ --- *
234 *
235 * Arguments: @int rq@ = request which triggered this call
236 * @pgen_event *ev@ = pointer to event block
237 * @limlee_stepctx *l@ = pointer to Lim-Lee context
238 *
239 * Returns: A @PGEN@ result code.
240 *
241 * Use: Initializes the stepper.
242 */
243
244static int next(int rq, pgen_event *ev, limlee_stepctx *l)
245{
246 mp *p;
247 int rc;
248
249 if (ev->m)
250 mp_drop(ev->m);
251 l->r = ev->r;
252
253 for (;;) {
254 size_t i;
255 mpmul mm = MPMUL_INIT;
256
257 /* --- Step on to next combination --- */
258
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);
262 l->v[i].p = 0;
263 }
264 }
265 rq = PGEN_TRY; /* For next time through */
266
267 /* --- Gather up some factors --- */
268
269 if (l->qq.p)
270 mpmul_add(&mm, l->qq.p);
271 for (i = 0; i < l->poolsz; i++) {
272 if (!l->c[i])
273 continue;
274 if (!l->v[i].p) {
275 DRESET(&l->d);
276 dstr_putf(&l->d, "%s_%lu", ev->name, l->seq++);
277 l->pops->pgen(&l->v[i], l->ql, l);
278 }
279 mpmul_add(&mm, l->v[i].p);
280 }
281
282 /* --- Check it for small factors --- */
283
284 p = mpmul_done(&mm);
285 p = mp_lsl(p, p, 1);
286 p->v[0] |= 1;
287 if ((rc = pfilt_smallfactor(p)) != PGEN_FAIL)
288 break;
289 mp_drop(p);
290 }
291
292 ev->m = p;
293 return (rc);
294}
295
296/* --- @done@ --- *
297 *
298 * Arguments: @pgen_event *ev@ = pointer to event block
299 * @limlee_stepctx *l@ = pointer to Lim-Lee context
300 *
301 * Returns: A @PGEN@ result code.
302 *
303 * Use: Finalizes the stepper. The output values in the context
304 * take on their final results; other resources are discarded.
305 */
306
307static int done(pgen_event *ev, limlee_stepctx *l)
308{
309 size_t i, j;
310 limlee_factor *v;
311
312 /* --- If an output vector of factors is wanted, produce one --- */
313
314 if (!(l->f & LIMLEE_KEEPFACTORS))
315 v = 0;
316 else {
317 if (l->qq.p)
318 l->nf++;
319 v = xmalloc(l->nf * sizeof(limlee_factor));
320 }
321
322 for (i = 0, j = 0; i < l->poolsz; i++) {
323 if (v && l->c[i])
324 v[j++] = l->v[i];
325 else if (l->v[i].p)
326 l->pops->pfree(&l->v[i], l);
327 }
328
329 if (l->qq.p) {
330 if (v)
331 v[j++] = l->qq;
332 else
333 l->pops->pfree(&l->qq, l);
334 }
335
336 xfree(l->v);
337 l->v = v;
338
339 /* --- Free other resources --- */
340
341 xfree(l->c);
342 dstr_destroy(&l->d);
343
344 /* --- Done --- */
345
346 return (PGEN_DONE);
347}
348
349/* --- @limlee_step@ --- */
350
351int limlee_step(int rq, pgen_event *ev, void *p)
352{
353 limlee_stepctx *l = p;
354 int rc;
355
356 switch (rq) {
357 case PGEN_BEGIN:
358 if ((rc = init(ev, l)) != PGEN_TRY)
359 return (rc);
360 case PGEN_TRY:
361 return (next(rq, ev, l));
362 case PGEN_DONE:
363 return (done(ev, l));
364 }
365 return (PGEN_ABORT);
366}
367
368/*----- Main code ---------------------------------------------------------*/
369
370/* --- @limlee@ --- *
371 *
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
384 *
385 * Returns: A Lim-Lee prime, or null if generation failed.
386 *
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
390 * algorithms.
391 *
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.
394 */
395
04361334 396mp *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,
400 size_t *nf, mp ***f)
401{
10217a5c 402 limlee_stepctx l;
403 rabin rr;
404
405 l.f = 0; if (f) l.f |= LIMLEE_KEEPFACTORS;
406 l.newp = newp;
407 l.pl = pl; l.ql = ql;
408 l.pops = 0;
409 l.iev = iev;
410 l.iec = iec;
411
412 d = pgen(name, d, 0, oev, oec, on, limlee_step, &l,
413 rabin_iters(pl), pgen_test, &rr);
414
415 if (f) {
416 mp **v;
417 size_t i;
418 v = xmalloc(l.nf * sizeof(mp *));
419 for (i = 0; i < l.nf; i++)
420 v[i] = l.v[i].p;
421 xfree(l.v);
422 *f = v;
423 *nf = l.nf;
424 }
425
426 return (d);
04361334 427}
428
d28d625a 429/*----- That's all, folks -------------------------------------------------*/