Support for new SHA variants added.
[u/mdw/catacomb] / limlee.c
CommitLineData
04361334 1/* -*-c-*-
2 *
3c0e5a02 3 * $Id: limlee.c,v 1.6 2001/01/25 21:16:20 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 $
3c0e5a02 33 * Revision 1.6 2001/01/25 21:16:20 mdw
34 * Boring cosmetic stuff.
35 *
10217a5c 36 * Revision 1.5 2000/08/18 19:16:51 mdw
37 * New stepper interface for constructing Lim-Lee primes.
38 *
8a33545f 39 * Revision 1.4 2000/08/15 21:45:05 mdw
40 * Use the new trial division equipment in pfilt. This gives a 10%
41 * performance improvement in dsa-gen.t.
42 *
2f627546 43 * Revision 1.3 2000/07/29 09:58:32 mdw
44 * (limlee): Bug fix. Old versions didn't set the filter step if @ql@ was
45 * an exact divisor of @pl@.
46 *
d28d625a 47 * Revision 1.2 2000/07/26 18:00:00 mdw
48 * No footer line!
49 *
04361334 50 * Revision 1.1 2000/07/09 21:30:58 mdw
51 * Lim-Lee prime generation.
52 *
53 */
54
55/*----- Header files ------------------------------------------------------*/
56
57#include <mLib/alloc.h>
58#include <mLib/dstr.h>
59
60#include "limlee.h"
61#include "mpmul.h"
62#include "mprand.h"
63#include "pgen.h"
04361334 64#include "rabin.h"
65
10217a5c 66/*----- Stepping through combinations -------------------------------------*/
04361334 67
10217a5c 68/* --- @comb_init@ --- *
04361334 69 *
10217a5c 70 * Arguments: @octet *c@ = pointer to byte-flag array
71 * @unsigned n@ = number of items in the array
72 * @unsigned r@ = number of desired items
04361334 73 *
10217a5c 74 * Returns: ---
04361334 75 *
10217a5c 76 * Use: Initializes a byte-flag array which, under the control of
77 * @comb_next@, will step through all combinations of @r@ chosen
78 * elements.
04361334 79 */
80
81static void comb_init(octet *c, unsigned n, unsigned r)
82{
83 memset(c, 0, n - r);
84 memset(c + (n - r), 1, r);
85}
86
10217a5c 87/* --- @comb_next@ --- *
88 *
89 * Arguments: @octet *c@ = pointer to byte-flag array
90 * @unsigned n@ = number of items in the array
91 * @unsigned r@ = number of desired items
92 *
93 * Returns: Nonzero if another combination was returned, zero if we've
94 * reached the end.
95 *
96 * Use: Steps on to the next combination in sequence.
97 */
98
04361334 99static int comb_next(octet *c, unsigned n, unsigned r)
100{
101 unsigned g = 0;
102
103 /* --- How the algorithm works --- *
104 *
105 * Set bits start at the end and work their way towards the start.
106 * Excepting bits already at the start, we scan for the lowest set bit, and
107 * move it one place nearer the start. A group of bits at the start are
108 * counted and reset just below the `moved' bit. If there is no moved bit
109 * then we're done.
110 */
111
112 /* --- Count the group at the start --- */
113
114 for (; *c; c++) {
115 g++;
116 *c = 0;
117 }
118 if (g == r)
119 return (0);
120
121 /* --- Move the next bit down one --- *
122 *
123 * There must be one, because otherwise we'd have counted %$r$% bits
124 * earlier.
125 */
126
127 for (; !*c; c++)
128 ;
129 *c = 0;
130 g++;
131 for (; g; g--)
132 *--c = 1;
133 return (1);
134}
135
10217a5c 136/*----- Default prime generator -------------------------------------------*/
137
138static void llgen(limlee_factor *f, unsigned pl, limlee_stepctx *l)
139{
140 pgen_filterctx pf;
141 rabin r;
142 mp *p;
143
144again:
145 p = mprand(l->newp, pl, l->r, 1);
146 pf.step = 2;
147 p = pgen(l->d.buf, p, p, l->iev, l->iec, 0, pgen_filter, &pf,
148 rabin_iters(pl), pgen_test, &r);
149 if (!p)
150 goto again;
151 f->p = p;
152}
153
154static void llfree(limlee_factor *f, limlee_stepctx *l)
155{
156 if (f->p)
157 mp_drop(f->p);
158}
159
160static const limlee_primeops primeops_simple = { llgen, llfree };
161
162/*----- Lim-Lee stepper ---------------------------------------------------*/
163
164/* --- @init@ --- *
165 *
166 * Arguments: @pgen_event *ev@ = pointer to event block
167 * @limlee_stepctx *l@ = pointer to Lim-Lee context
168 *
169 * Returns: A @PGEN@ result code.
170 *
171 * Use: Initializes the stepper.
172 */
173
174static int init(pgen_event *ev, limlee_stepctx *l)
175{
176 size_t i;
177 unsigned qql;
178
179 /* --- First of all, decide on a number of factors to make --- */
180
181 l->nf = l->pl / l->ql;
182 qql = l->pl % l->ql;
183 if (!l->nf)
184 return (PGEN_ABORT);
185 else if (qql && l->nf > 1) {
186 l->nf--;
187 qql += l->ql;
188 }
189
190 /* --- Now decide on how many primes I'll actually generate --- *
191 *
192 * The formula %$m = \max(3 n + 5, 25)$% comes from GPG's prime generation
193 * library.
194 */
195
196 l->poolsz = l->nf * 3 + 5;
197 if (l->poolsz < 25)
198 l->poolsz = 25;
199
200 /* --- Allocate and initialize the various tables --- */
201
202 l->c = xmalloc(l->poolsz);
203 l->v = xmalloc(l->poolsz * sizeof(limlee_factor));
204 comb_init(l->c, l->poolsz, l->nf);
205 for (i = 0; i < l->poolsz; i++)
206 l->v[i].p = 0;
207
208 /* --- Other bits of initialization --- */
209
210 l->seq = 0;
211 l->r = ev->r;
212 dstr_create(&l->d);
213 if (!l->pops) {
214 l->pops = &primeops_simple;
215 l->pc = 0;
216 }
217
218 /* --- Find a big prime --- */
219
220 if (!qql)
221 l->qq.p = 0;
222 else {
223 dstr_putf(&l->d, "%s*", ev->name);
224 l->pops->pgen(&l->qq, qql, l);
225 }
226
227 return (PGEN_TRY);
228}
229
230/* --- @next@ --- *
231 *
232 * Arguments: @int rq@ = request which triggered this call
233 * @pgen_event *ev@ = pointer to event block
234 * @limlee_stepctx *l@ = pointer to Lim-Lee context
235 *
236 * Returns: A @PGEN@ result code.
237 *
238 * Use: Initializes the stepper.
239 */
240
241static int next(int rq, pgen_event *ev, limlee_stepctx *l)
242{
243 mp *p;
244 int rc;
245
246 if (ev->m)
247 mp_drop(ev->m);
248 l->r = ev->r;
249
250 for (;;) {
251 size_t i;
252 mpmul mm = MPMUL_INIT;
253
254 /* --- Step on to next combination --- */
255
256 if (rq == PGEN_TRY && !comb_next(l->c, l->poolsz, l->nf)) {
257 for (i = 0; i < l->poolsz; i++) {
258 l->pops->pfree(&l->v[i], l);
259 l->v[i].p = 0;
260 }
261 }
262 rq = PGEN_TRY; /* For next time through */
263
264 /* --- Gather up some factors --- */
265
266 if (l->qq.p)
267 mpmul_add(&mm, l->qq.p);
268 for (i = 0; i < l->poolsz; i++) {
269 if (!l->c[i])
270 continue;
271 if (!l->v[i].p) {
272 DRESET(&l->d);
273 dstr_putf(&l->d, "%s_%lu", ev->name, l->seq++);
274 l->pops->pgen(&l->v[i], l->ql, l);
275 }
276 mpmul_add(&mm, l->v[i].p);
277 }
278
279 /* --- Check it for small factors --- */
280
281 p = mpmul_done(&mm);
282 p = mp_lsl(p, p, 1);
283 p->v[0] |= 1;
284 if ((rc = pfilt_smallfactor(p)) != PGEN_FAIL)
285 break;
286 mp_drop(p);
287 }
288
289 ev->m = p;
290 return (rc);
291}
292
293/* --- @done@ --- *
294 *
295 * Arguments: @pgen_event *ev@ = pointer to event block
296 * @limlee_stepctx *l@ = pointer to Lim-Lee context
297 *
298 * Returns: A @PGEN@ result code.
299 *
300 * Use: Finalizes the stepper. The output values in the context
301 * take on their final results; other resources are discarded.
302 */
303
304static int done(pgen_event *ev, limlee_stepctx *l)
305{
306 size_t i, j;
307 limlee_factor *v;
308
309 /* --- If an output vector of factors is wanted, produce one --- */
310
311 if (!(l->f & LIMLEE_KEEPFACTORS))
312 v = 0;
313 else {
314 if (l->qq.p)
315 l->nf++;
316 v = xmalloc(l->nf * sizeof(limlee_factor));
317 }
318
319 for (i = 0, j = 0; i < l->poolsz; i++) {
320 if (v && l->c[i])
321 v[j++] = l->v[i];
322 else if (l->v[i].p)
323 l->pops->pfree(&l->v[i], l);
324 }
325
326 if (l->qq.p) {
327 if (v)
328 v[j++] = l->qq;
329 else
330 l->pops->pfree(&l->qq, l);
331 }
332
333 xfree(l->v);
334 l->v = v;
335
336 /* --- Free other resources --- */
337
338 xfree(l->c);
339 dstr_destroy(&l->d);
340
341 /* --- Done --- */
342
343 return (PGEN_DONE);
344}
345
346/* --- @limlee_step@ --- */
347
348int limlee_step(int rq, pgen_event *ev, void *p)
349{
350 limlee_stepctx *l = p;
351 int rc;
352
353 switch (rq) {
354 case PGEN_BEGIN:
355 if ((rc = init(ev, l)) != PGEN_TRY)
356 return (rc);
357 case PGEN_TRY:
358 return (next(rq, ev, l));
359 case PGEN_DONE:
360 return (done(ev, l));
361 }
362 return (PGEN_ABORT);
363}
364
365/*----- Main code ---------------------------------------------------------*/
366
367/* --- @limlee@ --- *
368 *
369 * Arguments: @const char *name@ = pointer to name root
370 * @mp *d@ = pointer to destination integer
371 * @mp *newp@ = how to generate factor primes
372 * @unsigned ql@ = size of individual factors
373 * @unsigned pl@ = size of large prime
374 * @grand *r@ = a random number source
375 * @unsigned on@ = number of outer attempts to make
376 * @pgen_proc *oev@ = outer event handler function
377 * @void *oec@ = argument for the outer event handler
378 * @pgen_proc *iev@ = inner event handler function
379 * @void *iec@ = argument for the inner event handler
380 * @size_t *nf@, @mp ***f@ = output array for factors
381 *
382 * Returns: A Lim-Lee prime, or null if generation failed.
383 *
384 * Use: Generates Lim-Lee primes. A Lim-Lee prime %$p$% is one which
385 * satisfies %$p = 2 \prod_i q_i + 1$%, where all of the %$q_i$%
386 * are large enough to resist square-root discrete log
387 * algorithms.
388 *
389 * If we succeed, and @f@ is non-null, we write the array of
390 * factors chosen to @f@ for the benefit of the caller.
391 */
392
04361334 393mp *limlee(const char *name, mp *d, mp *newp,
394 unsigned ql, unsigned pl, grand *r,
395 unsigned on, pgen_proc *oev, void *oec,
396 pgen_proc *iev, void *iec,
397 size_t *nf, mp ***f)
398{
10217a5c 399#ifdef notdef
04361334 400 dstr dn = DSTR_INIT;
401 unsigned qql;
402 mp *qq = 0;
403 unsigned nn;
404 unsigned mm;
405 mp **v;
406 octet *c;
407 unsigned i;
408 unsigned long seq = 0;
409 pgen_event ev;
410 unsigned ntest;
411 rabin rb;
412 pgen_filterctx pf;
413
414 /* --- First of all, decide on a number of factors to make --- */
415
416 nn = pl/ql;
417 qql = pl%ql;
418 if (!nn)
419 return (0);
420 else if (qql && nn > 1) {
421 nn--;
422 qql += ql;
423 }
424
425 /* --- Now decide on how many primes I'll actually generate --- *
426 *
427 * The formula %$m = \max(3 n + 5, 25)$% comes from GPG's prime generation
428 * library.
429 */
430
431 mm = nn * 3 + 5;
432 if (mm < 25)
433 mm = 25;
434
435 /* --- Now allocate the working memory --- */
436
04361334 437 v = xmalloc(mm * sizeof(mp *));
438 c = xmalloc(mm);
439
440 /* --- Initialize everything and try to find a prime --- */
441
442 ev.name = name;
443 ev.m = 0;
444 ev.steps = on;
445 ev.tests = ntest = rabin_iters(pl);
446 ev.r = r;
447
448 if (oev && oev(PGEN_BEGIN, &ev, oec) == PGEN_ABORT)
449 goto fail;
450
2f627546 451 pf.step = 2;
04361334 452 if (qql) {
10217a5c 453 dstr_putf(&dn, "%s*", name);
04361334 454 qq = mprand(d, qql, r, 1);
04361334 455 qq = pgen(dn.buf, qq, qq, iev, iec,
456 0, pgen_filter, &pf, rabin_iters(qql), pgen_test, &rb);
457 }
458
459again:
460 comb_init(c, mm, nn);
461 for (i = 0; i < mm; i++)
462 v[i] = 0;
463
464 /* --- The main combinations loop --- */
465
466 do {
467 mpmul mmul = MPMUL_INIT;
468
469 /* --- Multiply a bunch of primes together --- */
470
3c0e5a02 471 if (qq)
04361334 472 mpmul_add(&mmul, qq);
04361334 473 for (i = 0; i < mm; i++) {
474 if (!c[i])
475 continue;
476 if (!v[i]) {
477 mp *z;
478
479 DRESET(&dn);
10217a5c 480 dstr_putf(&dn, "%s_%lu] = ", name, seq++);
04361334 481 z = mprand(newp, ql, ev.r, 1);
482 z = pgen(dn.buf, z, z, iev, iec,
483 0, pgen_filter, &pf, rabin_iters(ql), pgen_test, &rb);
484 v[i] = z;
485 }
486 mpmul_add(&mmul, v[i]);
487 }
488
489 /* --- Now do some testing --- */
490
491 {
492 mp *p = mpmul_done(&mmul);
8a33545f 493 mp *g;
04361334 494 int rc;
495
496 /* --- Check for small factors --- */
497
498 p = mp_lsl(p, p, 1);
499 p = mp_add(p, p, MP_ONE);
8a33545f 500 rc = pfilt_smallfactor(p);
501 if (rc == PGEN_FAIL) {
04361334 502 mp_drop(p);
503 continue;
504 }
04361334 505
506 /* --- Send an event out --- */
507
508 ev.m = p;
509 if (oev && oev(PGEN_TRY, &ev, oec) == PGEN_ABORT) {
510 mp_drop(p);
511 goto fail;
512 }
513
514 /* --- Do the Rabin testing --- */
515
516 rabin_create(&rb, p);
517 g = MP_NEW;
518 do {
519 g = mprand_range(g, p, ev.r, 1);
520 rc = rabin_test(&rb, g);
521 if (rc == PGEN_PASS) {
522 ev.tests--;
523 if (!ev.tests)
524 rc = PGEN_DONE;
525 }
3c0e5a02 526 if (oev && oev(rc, &ev, oec) == PGEN_ABORT)
04361334 527 rc = PGEN_ABORT;
528 } while (rc == PGEN_PASS);
529
530 rabin_destroy(&rb);
531 mp_drop(g);
532 if (rc == PGEN_DONE)
533 d = p;
534 else
535 mp_drop(p);
536 if (rc == PGEN_ABORT)
537 goto fail;
538 if (rc == PGEN_DONE)
539 goto done;
540 ev.tests = ntest;
541 ev.m = 0;
542 }
543 } while (comb_next(c, mm, nn));
544
545 /* --- That failed --- */
546
547 if (ev.steps) {
548 ev.steps--;
549 if (!ev.steps) {
550 if (oev)
551 oev(PGEN_ABORT, &ev, &oec);
552 goto fail;
553 }
554 }
555
556 for (i = 0; i < mm; i++)
557 mp_drop(v[i]);
558 goto again;
559
560 /* --- We did it! --- */
561
562done: {
563 mp **vv = 0;
564 if (f) {
565 if (qq)
566 nn++;
567 *nf = nn;
568 *f = vv = xmalloc(nn * sizeof(mp *));
569 }
2f627546 570
04361334 571 for (i = 0; i < mm; i++) {
572 if (c[i] && vv)
573 *vv++ = v[i];
574 else if (v[i])
575 mp_drop(v[i]);
576 }
577 if (qq) {
578 if (vv)
579 *vv++ = qq;
580 else
581 mp_drop(qq);
582 }
583 xfree(v);
584 xfree(c);
585 dstr_destroy(&dn);
586 return (d);
587 }
588
589 /* --- We blew it --- */
590
591fail:
592 for (i = 0; i < mm; i++)
593 mp_drop(v[i]);
594 if (qq)
595 mp_drop(qq);
596 xfree(v);
597 xfree(c);
598 dstr_destroy(&dn);
599 return (0);
10217a5c 600#else
601 limlee_stepctx l;
602 rabin rr;
603
604 l.f = 0; if (f) l.f |= LIMLEE_KEEPFACTORS;
605 l.newp = newp;
606 l.pl = pl; l.ql = ql;
607 l.pops = 0;
608 l.iev = iev;
609 l.iec = iec;
610
611 d = pgen(name, d, 0, oev, oec, on, limlee_step, &l,
612 rabin_iters(pl), pgen_test, &rr);
613
614 if (f) {
615 mp **v;
616 size_t i;
617 v = xmalloc(l.nf * sizeof(mp *));
618 for (i = 0; i < l.nf; i++)
619 v[i] = l.v[i].p;
620 xfree(l.v);
621 *f = v;
622 *nf = l.nf;
623 }
624
625 return (d);
626#endif
04361334 627}
628
d28d625a 629/*----- That's all, folks -------------------------------------------------*/