New event handler for showing in detail sub-prime generation.
[u/mdw/catacomb] / limlee.c
CommitLineData
04361334 1/* -*-c-*-
2 *
8a33545f 3 * $Id: limlee.c,v 1.4 2000/08/15 21:45:05 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 $
8a33545f 33 * Revision 1.4 2000/08/15 21:45:05 mdw
34 * Use the new trial division equipment in pfilt. This gives a 10%
35 * performance improvement in dsa-gen.t.
36 *
2f627546 37 * Revision 1.3 2000/07/29 09:58:32 mdw
38 * (limlee): Bug fix. Old versions didn't set the filter step if @ql@ was
39 * an exact divisor of @pl@.
40 *
d28d625a 41 * Revision 1.2 2000/07/26 18:00:00 mdw
42 * No footer line!
43 *
04361334 44 * Revision 1.1 2000/07/09 21:30:58 mdw
45 * Lim-Lee prime generation.
46 *
47 */
48
49/*----- Header files ------------------------------------------------------*/
50
51#include <mLib/alloc.h>
52#include <mLib/dstr.h>
53
54#include "limlee.h"
55#include "mpmul.h"
56#include "mprand.h"
57#include "pgen.h"
58#include "primorial.h"
59#include "rabin.h"
60
61/*----- Main code ---------------------------------------------------------*/
62
63/* --- @limlee@ --- *
64 *
65 * Arguments: @const char *name@ = pointer to name root
66 * @mp *d@ = pointer to destination integer
67 * @mp *newp@ = how to generate factor primes
68 * @unsigned ql@ = size of individual factors
69 * @unsigned pl@ = size of large prime
70 * @grand *r@ = a random number source
71 * @unsigned on@ = number of outer attempts to make
72 * @pgen_proc *oev@ = outer event handler function
73 * @void *oec@ = argument for the outer event handler
74 * @pgen_proc *iev@ = inner event handler function
75 * @void *iec@ = argument for the inner event handler
76 * @size_t *nf@, @mp ***f@ = output array for factors
77 *
78 * Returns: A Lim-Lee prime, or null if generation failed.
79 *
80 * Use: Generates Lim-Lee primes. A Lim-Lee prime %$p$% is one which
81 * satisfies %$p = 2 \prod_i q_i + 1$%, where all of the %$q_i$%
82 * are large enough to resist square-root discrete log
83 * algorithms.
84 *
85 * If we succeed, and @f@ is non-null, we write the array of
86 * factors chosen to @f@ for the benefit of the caller.
87 */
88
89static void comb_init(octet *c, unsigned n, unsigned r)
90{
91 memset(c, 0, n - r);
92 memset(c + (n - r), 1, r);
93}
94
95static int comb_next(octet *c, unsigned n, unsigned r)
96{
97 unsigned g = 0;
98
99 /* --- How the algorithm works --- *
100 *
101 * Set bits start at the end and work their way towards the start.
102 * Excepting bits already at the start, we scan for the lowest set bit, and
103 * move it one place nearer the start. A group of bits at the start are
104 * counted and reset just below the `moved' bit. If there is no moved bit
105 * then we're done.
106 */
107
108 /* --- Count the group at the start --- */
109
110 for (; *c; c++) {
111 g++;
112 *c = 0;
113 }
114 if (g == r)
115 return (0);
116
117 /* --- Move the next bit down one --- *
118 *
119 * There must be one, because otherwise we'd have counted %$r$% bits
120 * earlier.
121 */
122
123 for (; !*c; c++)
124 ;
125 *c = 0;
126 g++;
127 for (; g; g--)
128 *--c = 1;
129 return (1);
130}
131
132mp *limlee(const char *name, mp *d, mp *newp,
133 unsigned ql, unsigned pl, grand *r,
134 unsigned on, pgen_proc *oev, void *oec,
135 pgen_proc *iev, void *iec,
136 size_t *nf, mp ***f)
137{
138 dstr dn = DSTR_INIT;
139 unsigned qql;
140 mp *qq = 0;
141 unsigned nn;
142 unsigned mm;
143 mp **v;
144 octet *c;
145 unsigned i;
146 unsigned long seq = 0;
147 pgen_event ev;
148 unsigned ntest;
149 rabin rb;
150 pgen_filterctx pf;
151
152 /* --- First of all, decide on a number of factors to make --- */
153
154 nn = pl/ql;
155 qql = pl%ql;
156 if (!nn)
157 return (0);
158 else if (qql && nn > 1) {
159 nn--;
160 qql += ql;
161 }
162
163 /* --- Now decide on how many primes I'll actually generate --- *
164 *
165 * The formula %$m = \max(3 n + 5, 25)$% comes from GPG's prime generation
166 * library.
167 */
168
169 mm = nn * 3 + 5;
170 if (mm < 25)
171 mm = 25;
172
173 /* --- Now allocate the working memory --- */
174
04361334 175 v = xmalloc(mm * sizeof(mp *));
176 c = xmalloc(mm);
177
178 /* --- Initialize everything and try to find a prime --- */
179
180 ev.name = name;
181 ev.m = 0;
182 ev.steps = on;
183 ev.tests = ntest = rabin_iters(pl);
184 ev.r = r;
185
186 if (oev && oev(PGEN_BEGIN, &ev, oec) == PGEN_ABORT)
187 goto fail;
188
2f627546 189 pf.step = 2;
04361334 190 if (qql) {
191 dstr_putf(&dn, "%s [+]", name);
192 qq = mprand(d, qql, r, 1);
04361334 193 qq = pgen(dn.buf, qq, qq, iev, iec,
194 0, pgen_filter, &pf, rabin_iters(qql), pgen_test, &rb);
195 }
196
197again:
198 comb_init(c, mm, nn);
199 for (i = 0; i < mm; i++)
200 v[i] = 0;
201
202 /* --- The main combinations loop --- */
203
204 do {
205 mpmul mmul = MPMUL_INIT;
206
207 /* --- Multiply a bunch of primes together --- */
208
209 if (qq) {
210 mpmul_add(&mmul, qq);
211 }
212 for (i = 0; i < mm; i++) {
213 if (!c[i])
214 continue;
215 if (!v[i]) {
216 mp *z;
217
218 DRESET(&dn);
219 dstr_putf(&dn, "%s [%lu] = ", name, seq++);
220 z = mprand(newp, ql, ev.r, 1);
221 z = pgen(dn.buf, z, z, iev, iec,
222 0, pgen_filter, &pf, rabin_iters(ql), pgen_test, &rb);
223 v[i] = z;
224 }
225 mpmul_add(&mmul, v[i]);
226 }
227
228 /* --- Now do some testing --- */
229
230 {
231 mp *p = mpmul_done(&mmul);
8a33545f 232 mp *g;
04361334 233 int rc;
234
235 /* --- Check for small factors --- */
236
237 p = mp_lsl(p, p, 1);
238 p = mp_add(p, p, MP_ONE);
8a33545f 239 rc = pfilt_smallfactor(p);
240 if (rc == PGEN_FAIL) {
04361334 241 mp_drop(p);
242 continue;
243 }
04361334 244
245 /* --- Send an event out --- */
246
247 ev.m = p;
248 if (oev && oev(PGEN_TRY, &ev, oec) == PGEN_ABORT) {
249 mp_drop(p);
250 goto fail;
251 }
252
253 /* --- Do the Rabin testing --- */
254
255 rabin_create(&rb, p);
256 g = MP_NEW;
257 do {
258 g = mprand_range(g, p, ev.r, 1);
259 rc = rabin_test(&rb, g);
260 if (rc == PGEN_PASS) {
261 ev.tests--;
262 if (!ev.tests)
263 rc = PGEN_DONE;
264 }
265 if (oev &&oev(rc, &ev, oec) == PGEN_ABORT)
266 rc = PGEN_ABORT;
267 } while (rc == PGEN_PASS);
268
269 rabin_destroy(&rb);
270 mp_drop(g);
271 if (rc == PGEN_DONE)
272 d = p;
273 else
274 mp_drop(p);
275 if (rc == PGEN_ABORT)
276 goto fail;
277 if (rc == PGEN_DONE)
278 goto done;
279 ev.tests = ntest;
280 ev.m = 0;
281 }
282 } while (comb_next(c, mm, nn));
283
284 /* --- That failed --- */
285
286 if (ev.steps) {
287 ev.steps--;
288 if (!ev.steps) {
289 if (oev)
290 oev(PGEN_ABORT, &ev, &oec);
291 goto fail;
292 }
293 }
294
295 for (i = 0; i < mm; i++)
296 mp_drop(v[i]);
297 goto again;
298
299 /* --- We did it! --- */
300
301done: {
302 mp **vv = 0;
303 if (f) {
304 if (qq)
305 nn++;
306 *nf = nn;
307 *f = vv = xmalloc(nn * sizeof(mp *));
308 }
2f627546 309
04361334 310 for (i = 0; i < mm; i++) {
311 if (c[i] && vv)
312 *vv++ = v[i];
313 else if (v[i])
314 mp_drop(v[i]);
315 }
316 if (qq) {
317 if (vv)
318 *vv++ = qq;
319 else
320 mp_drop(qq);
321 }
322 xfree(v);
323 xfree(c);
324 dstr_destroy(&dn);
325 return (d);
326 }
327
328 /* --- We blew it --- */
329
330fail:
331 for (i = 0; i < mm; i++)
332 mp_drop(v[i]);
333 if (qq)
334 mp_drop(qq);
335 xfree(v);
336 xfree(c);
337 dstr_destroy(&dn);
338 return (0);
339}
340
d28d625a 341/*----- That's all, folks -------------------------------------------------*/