3 * $Id: dsa-gen.c,v 1.10 2004/04/08 01:36:15 mdw Exp $
5 * Generate DSA shared parameters
7 * (c) 1999 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 /*----- Header files ------------------------------------------------------*/
44 /*----- The DSA stepper ---------------------------------------------------*/
48 * Arguments: @pgen_event *ev@ = pointer to event block
49 * @dsa_stepctx *d@ = pointer to stepping context
51 * Returns: A @PGEN@ result code.
53 * Use: Steps the generator once, reads the result, and tests it.
56 static int next(pgen_event *ev, dsa_stepctx *d)
61 /* --- Load the new candidate --- */
64 d->r->ops->misc(d->r, DSARAND_GETSEED, d->seedbuf);
65 m = mprand(ev->m, d->bits, d->r, 0);
67 /* --- Force to be a multiple of @q@ --- */
71 mp_div(0, &r, m, d->q);
78 /* --- Do the trial division --- */
80 rc = pfilt_smallfactor(m);
83 /* --- Return the result --- */
88 /* --- @dsa_step@ --- */
90 int dsa_step(int rq, pgen_event *ev, void *p)
104 /*----- Glue code ---------------------------------------------------------*/
106 /* --- @dsa_gen@ --- *
108 * Arguments: @dsa_param *dp@ = where to store parameters
109 * @unsigned ql@ = length of @q@ in bits
110 * @unsigned pl@ = length of @p@ in bits
111 * @unsigned steps@ = number of steps to find @q@
112 * @const void *k@ = pointer to key material
113 * @size_t sz@ = size of key material
114 * @dsa_seed *ds@ = optional pointer for output seed information
115 * @pgen_proc *event@ = event handler function
116 * @void *ectx@ = argument for event handler
118 * Returns: @PGEN_DONE@ if everything worked ok; @PGEN_ABORT@ otherwise.
120 * Use: Generates the DSA shared parameters from a given seed value.
122 * The parameters are a prime %$q$%, relatively small, and a
123 * large prime %$p = kq + 1$% for some %$k$%, together with a
124 * generator %$g$% of the cyclic subgroup of order %$q$%. These
125 * are actually the same as the Diffie-Hellman parameter set,
126 * but the generation algorithm is different.
128 * The algorithm used is a compatible extension of the method
129 * described in the DSA standard, FIPS 186. The standard
130 * requires that %$q$% be 160 bits in size (i.e., @ql == 160@)
131 * and that the length of %$p$% be %$L = 512 + 64l$% for some
132 * %$l$%. Neither limitation applies to this implementation.
135 int dsa_gen(dsa_param *dp, unsigned ql, unsigned pl, unsigned steps,
136 const void *k, size_t sz, dsa_seed *ds,
137 pgen_proc *event, void *ectx)
145 /* --- Initialize the stepping context --- */
147 s.r = dsarand_create(k, sz);
149 /* --- Find @q@ --- */
152 s.r->ops->misc(s.r, DSARAND_PASSES, 2);
160 ds->p = s.seedbuf = xmalloc(sz);
162 if ((dp->q = pgen("q", MP_NEW, MP_NEW, event, ectx, steps, dsa_step, &s,
163 rabin_iters(ql), pgen_test, &r)) == 0)
166 /* --- Find @p@ --- */
169 s.q = mp_lsl(MP_NEW, dp->q, 1);
170 s.r->ops->misc(s.r, DSARAND_PASSES, 1);
173 if ((dp->p = pgen("p", MP_NEW, MP_NEW, event, ectx, 4096, dsa_step, &s,
174 rabin_iters(pl), pgen_test, &r)) == 0)
180 /* --- Find @g@ --- *
182 * The division returns remainder 1. This doesn't matter.
185 mpmont_create(&p.mm, dp->p);
186 qc = MP_NEW; mp_div(&qc, 0, dp->p, dp->q);
190 if ((dp->g = pgen("g", MP_NEW, MP_NEW, event, ectx, 0, prim_step, &i,
191 1, prim_test, &p)) == 0)
197 mpmont_destroy(&p.mm);
198 s.r->ops->destroy(s.r);
201 /* --- Tidy up when things go wrong --- */
205 mpmont_destroy(&p.mm);
210 s.r->ops->destroy(s.r);
216 /*----- Test rig ----------------------------------------------------------*/
220 static int verify(dstr *v)
222 mp *q = *(mp **)v[4].buf;
223 mp *p = *(mp **)v[5].buf;
224 mp *g = *(mp **)v[6].buf;
227 unsigned long l = *(unsigned long *)v[1].buf;
228 unsigned long n = *(unsigned long *)v[3].buf;
232 keycheck_reportctx kcr;
234 rc = dsa_gen(&dp, 160, l, 16, v[0].buf, v[0].len, &ds, pgen_evspin, 0);
235 if (rc || ds.count != n || ds.sz != v[2].len ||
236 memcmp(ds.p, v[2].buf, v[2].len) != 0 ||
237 !MP_EQ(q, dp.q) || !MP_EQ(p, dp.p) || !MP_EQ(g, dp.g)) {
238 fputs("\n*** gen failed", stderr);
239 fputs("\nseed_in = ", stderr); type_hex.dump(&v[0], stderr);
240 fprintf(stderr, "\nl = %lu", l);
241 fputs("\nseed_out = ", stderr); type_hex.dump(&v[2], stderr);
242 fprintf(stderr, "\ncount = %lu", n);
243 fputs("\n q = ", stderr); mp_writefile(q, stderr, 16);
244 fputs("\n p = ", stderr); mp_writefile(p, stderr, 16);
245 fputs("\n g = ", stderr); mp_writefile(g, stderr, 16);
248 d.buf = ds.p; d.len = ds.sz;
249 fputs("\nds.seed = ", stderr); type_hex.dump(&d, stderr);
250 fprintf(stderr, "\nds.count = %u", ds.count);
251 fputs("\ndp.q = ", stderr); mp_writefile(dp.q, stderr, 16);
252 fputs("\ndp.p = ", stderr); mp_writefile(dp.p, stderr, 16);
253 fputs("\ndp.g = ", stderr); mp_writefile(dp.g, stderr, 16);
261 keycheck_init(&kc, keycheck_stdreport, &kcr);
263 dsa_checkparam(&kc, &dp, &ds);
264 if (!keycheck_allclear(&kc, KCSEV_ERR)) {
265 fputs("\n*** gen failed check", stderr);
266 fputs("\nseed_in = ", stderr); type_hex.dump(&v[0], stderr);
267 fprintf(stderr, "\nl = %lu", l);
268 fputs("\nseed_out = ", stderr); type_hex.dump(&v[2], stderr);
269 fprintf(stderr, "\ncount = %lu", n);
270 fputs("\n q = ", stderr); mp_writefile(q, stderr, 16);
271 fputs("\n p = ", stderr); mp_writefile(p, stderr, 16);
272 fputs("\n g = ", stderr); mp_writefile(g, stderr, 16);
277 mp_drop(q); mp_drop(p); mp_drop(g);
279 mp_drop(dp.q); mp_drop(dp.p); mp_drop(dp.g); xfree(ds.p);
281 assert(mparena_count(MPARENA_GLOBAL) == 0);
285 static test_chunk tests[] = {
287 { &type_hex, &type_ulong, &type_hex, &type_ulong,
288 &type_mp, &type_mp, &type_mp, 0 } },
292 int main(int argc, char *argv[])
295 test_run(argc, argv, tests, SRCDIR "/tests/dsa");
301 /*----- That's all, folks -------------------------------------------------*/