Add an internal-representation no-op function.
[u/mdw/catacomb] / dsa-gen.c
CommitLineData
8b810a45 1/* -*-c-*-
2 *
a63f764a 3 * $Id: dsa-gen.c,v 1.9 2001/02/03 16:09:29 mdw Exp $
8b810a45 4 *
5 * Generate DSA shared parameters
6 *
7 * (c) 1999 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: dsa-gen.c,v $
a63f764a 33 * Revision 1.9 2001/02/03 16:09:29 mdw
34 * Allow the caller to fetch the parameter generation seed and counter.
35 *
7d71fd1a 36 * Revision 1.8 2000/10/08 12:12:47 mdw
37 * Use @MP_EQ@ instead of @MP_CMP@. Remove vestages of @primorial@.
38 *
8a33545f 39 * Revision 1.7 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 *
2b31b269 43 * Revision 1.6 2000/07/29 10:00:14 mdw
44 * Rename `dsa_seed' to `dsa_gen' for consistency with other parameter-
45 * generation interfaces.
46 *
052b36d0 47 * Revision 1.5 2000/02/12 18:21:02 mdw
48 * Overhaul of key management (again).
49 *
b04a7659 50 * Revision 1.4 1999/12/22 15:52:44 mdw
51 * Reworking for new prime-search system.
52 *
ef5f4810 53 * Revision 1.3 1999/12/10 23:18:38 mdw
54 * Change interface for suggested destinations.
55 *
987bb691 56 * Revision 1.2 1999/11/20 22:23:48 mdw
57 * Allow event handler to abort the search process.
58 *
8b810a45 59 * Revision 1.1 1999/11/19 19:28:00 mdw
60 * Implementation of the Digital Signature Algorithm.
61 *
62 */
63
64/*----- Header files ------------------------------------------------------*/
65
66#include <stdio.h>
67#include <stdlib.h>
68
69#include "dsa.h"
b04a7659 70#include "dsarand.h"
ef5f4810 71#include "fibrand.h"
8b810a45 72#include "mp.h"
ef5f4810 73#include "mprand.h"
8b810a45 74#include "pgen.h"
b04a7659 75#include "prim.h"
8b810a45 76#include "sha.h"
77
b04a7659 78/*----- The DSA stepper ---------------------------------------------------*/
8b810a45 79
b04a7659 80/* --- @next@ --- *
8b810a45 81 *
b04a7659 82 * Arguments: @pgen_event *ev@ = pointer to event block
83 * @dsa_stepctx *d@ = pointer to stepping context
8b810a45 84 *
b04a7659 85 * Returns: A @PGEN@ result code.
8b810a45 86 *
b04a7659 87 * Use: Steps the generator once, reads the result, and tests it.
8b810a45 88 */
89
b04a7659 90static int next(pgen_event *ev, dsa_stepctx *d)
8b810a45 91{
b04a7659 92 mp *m;
93 int rc;
8b810a45 94
b04a7659 95 /* --- Load the new candidate --- */
8b810a45 96
a63f764a 97 if (d->seedbuf)
98 d->r->ops->misc(d->r, DSARAND_GETSEED, d->seedbuf);
99 m = mprand(ev->m, d->bits, d->r, 0);
8b810a45 100
b04a7659 101 /* --- Force to be a multiple of @q@ --- */
ef5f4810 102
b04a7659 103 if (d->q) {
104 mp *r = MP_NEW;
105 mp_div(0, &r, m, d->q);
106 m = mp_sub(m, m, r);
107 mp_drop(r);
8b810a45 108 }
b04a7659 109 m->v[0] |= d->or;
110 ev->m = m;
8b810a45 111
b04a7659 112 /* --- Do the trial division --- */
8b810a45 113
8a33545f 114 rc = pfilt_smallfactor(m);
a63f764a 115 d->count++;
8b810a45 116
b04a7659 117 /* --- Return the result --- */
8b810a45 118
b04a7659 119 return (rc);
120}
8b810a45 121
b04a7659 122/* --- @dsa_step@ --- */
123
124int dsa_step(int rq, pgen_event *ev, void *p)
125{
126 dsa_stepctx *d = p;
127
128 switch (rq) {
129 case PGEN_BEGIN:
b04a7659 130 case PGEN_TRY:
131 return (next(ev, d));
132 case PGEN_DONE:
133 return (PGEN_DONE);
8b810a45 134 }
b04a7659 135 return (PGEN_ABORT);
136}
8b810a45 137
b04a7659 138/*----- Glue code ---------------------------------------------------------*/
8b810a45 139
2b31b269 140/* --- @dsa_gen@ --- *
b04a7659 141 *
142 * Arguments: @dsa_param *dp@ = where to store parameters
143 * @unsigned ql@ = length of @q@ in bits
144 * @unsigned pl@ = length of @p@ in bits
145 * @unsigned steps@ = number of steps to find @q@
146 * @const void *k@ = pointer to key material
147 * @size_t sz@ = size of key material
a63f764a 148 * @dsa_seed *ds@ = optional pointer for output seed information
b04a7659 149 * @pgen_proc *event@ = event handler function
150 * @void *ectx@ = argument for event handler
151 *
152 * Returns: @PGEN_DONE@ if everything worked ok; @PGEN_ABORT@ otherwise.
153 *
154 * Use: Generates the DSA shared parameters from a given seed value.
052b36d0 155 *
156 * The parameters are a prime %$q$%, relatively small, and a
157 * large prime %$p = kq + 1$% for some %$k$%, together with a
158 * generator %$g$% of the cyclic subgroup of order %$q$%. These
159 * are actually the same as the Diffie-Hellman parameter set,
160 * but the generation algorithm is different.
b04a7659 161 *
162 * The algorithm used is a compatible extension of the method
163 * described in the DSA standard, FIPS 186. The standard
164 * requires that %$q$% be 160 bits in size (i.e., @ql == 160@)
165 * and that the length of %$p$% be %$L = 512 + 64l$% for some
166 * %$l$%. Neither limitation applies to this implementation.
167 */
8b810a45 168
2b31b269 169int dsa_gen(dsa_param *dp, unsigned ql, unsigned pl, unsigned steps,
a63f764a 170 const void *k, size_t sz, dsa_seed *ds,
171 pgen_proc *event, void *ectx)
b04a7659 172{
173 dsa_stepctx s;
174 prim_ctx p;
175 int i;
176 rabin r;
177 mp *qc;
8b810a45 178
b04a7659 179 /* --- Initialize the stepping context --- */
8b810a45 180
b04a7659 181 s.r = dsarand_create(k, sz);
8b810a45 182
b04a7659 183 /* --- Find @q@ --- */
8b810a45 184
b04a7659 185 s.q = 0;
186 s.r->ops->misc(s.r, DSARAND_PASSES, 2);
187 s.bits = ql;
a63f764a 188 s.count = 0;
189 s.or = 1;
190 if (!ds)
191 s.seedbuf = 0;
192 else {
193 ds->sz = sz;
194 ds->p = s.seedbuf = xmalloc(sz);
195 }
b04a7659 196 if ((dp->q = pgen("q", MP_NEW, MP_NEW, event, ectx, steps, dsa_step, &s,
197 rabin_iters(ql), pgen_test, &r)) == 0)
198 goto fail_q;
8b810a45 199
b04a7659 200 /* --- Find @p@ --- */
8b810a45 201
a63f764a 202 s.count = ~0;
b04a7659 203 s.q = mp_lsl(MP_NEW, dp->q, 1);
204 s.r->ops->misc(s.r, DSARAND_PASSES, 1);
205 s.bits = pl;
a63f764a 206 s.seedbuf = 0;
b04a7659 207 if ((dp->p = pgen("p", MP_NEW, MP_NEW, event, ectx, 4096, dsa_step, &s,
208 rabin_iters(pl), pgen_test, &r)) == 0)
209 goto fail_p;
210 mp_drop(s.q);
a63f764a 211 if (ds)
212 ds->count = s.count;
b04a7659 213
214 /* --- Find @g@ --- *
215 *
216 * The division returns remainder 1. This doesn't matter.
217 */
218
219 mpmont_create(&p.mm, dp->p);
220 qc = MP_NEW; mp_div(&qc, 0, dp->p, dp->q);
221 i = 0;
2b31b269 222 p.exp = qc;
b04a7659 223 p.n = 0;
224 if ((dp->g = pgen("g", MP_NEW, MP_NEW, event, ectx, 0, prim_step, &i,
225 1, prim_test, &p)) == 0)
226 goto fail_g;
227
228 /* --- Done --- */
229
230 mp_drop(qc);
231 mpmont_destroy(&p.mm);
232 s.r->ops->destroy(s.r);
233 return (PGEN_DONE);
234
235 /* --- Tidy up when things go wrong --- */
236
237fail_g:
238 mp_drop(qc);
239 mpmont_destroy(&p.mm);
240fail_p:
241 mp_drop(dp->q);
242 mp_drop(s.q);
243fail_q:
244 s.r->ops->destroy(s.r);
a63f764a 245 if (ds)
246 xfree(ds->p);
b04a7659 247 return (PGEN_ABORT);
8b810a45 248}
249
b04a7659 250/*----- Test rig ----------------------------------------------------------*/
251
252#ifdef TEST_RIG
253
8b810a45 254static int verify(dstr *v)
255{
a63f764a 256 mp *q = *(mp **)v[4].buf;
257 mp *p = *(mp **)v[5].buf;
258 mp *g = *(mp **)v[6].buf;
8b810a45 259 dsa_param dp;
a63f764a 260 dsa_seed ds;
261 unsigned long l = *(unsigned long *)v[1].buf;
262 unsigned long n = *(unsigned long *)v[3].buf;
8b810a45 263 int ok = 1;
264 int rc;
a63f764a 265 keycheck kc;
266 keycheck_reportctx kcr;
8b810a45 267
a63f764a 268 rc = dsa_gen(&dp, 160, l, 16, v[0].buf, v[0].len, &ds, pgen_evspin, 0);
269 if (rc || ds.count != n || ds.sz != v[2].len ||
270 memcmp(ds.p, v[2].buf, v[2].len) != 0 ||
271 !MP_EQ(q, dp.q) || !MP_EQ(p, dp.p) || !MP_EQ(g, dp.g)) {
8b810a45 272 fputs("\n*** gen failed", stderr);
a63f764a 273 fputs("\nseed_in = ", stderr); type_hex.dump(&v[0], stderr);
274 fprintf(stderr, "\nl = %lu", l);
275 fputs("\nseed_out = ", stderr); type_hex.dump(&v[2], stderr);
276 fprintf(stderr, "\ncount = %lu", n);
8b810a45 277 fputs("\n q = ", stderr); mp_writefile(q, stderr, 16);
b04a7659 278 fputs("\n p = ", stderr); mp_writefile(p, stderr, 16);
8b810a45 279 fputs("\n g = ", stderr); mp_writefile(g, stderr, 16);
280 if (!rc) {
a63f764a 281 dstr d;
282 d.buf = ds.p; d.len = ds.sz;
283 fputs("\nds.seed = ", stderr); type_hex.dump(&d, stderr);
284 fprintf(stderr, "\nds.count = %u", ds.count);
8b810a45 285 fputs("\ndp.q = ", stderr); mp_writefile(dp.q, stderr, 16);
286 fputs("\ndp.p = ", stderr); mp_writefile(dp.p, stderr, 16);
287 fputs("\ndp.g = ", stderr); mp_writefile(dp.g, stderr, 16);
288 }
289 fputc('\n', stderr);
290 ok = 0;
291 }
292
a63f764a 293 kcr.fp = stderr;
294 kcr.sev = KCSEV_ERR;
295 keycheck_init(&kc, keycheck_stdreport, &kcr);
296 if (!rc)
297 dsa_checkparam(&kc, &dp, &ds);
298 if (!keycheck_allclear(&kc, KCSEV_ERR)) {
299 fputs("\n*** gen failed check", stderr);
300 fputs("\nseed_in = ", stderr); type_hex.dump(&v[0], stderr);
301 fprintf(stderr, "\nl = %lu", l);
302 fputs("\nseed_out = ", stderr); type_hex.dump(&v[2], stderr);
303 fprintf(stderr, "\ncount = %lu", n);
304 fputs("\n q = ", stderr); mp_writefile(q, stderr, 16);
305 fputs("\n p = ", stderr); mp_writefile(p, stderr, 16);
306 fputs("\n g = ", stderr); mp_writefile(g, stderr, 16);
307 fputc('\n', stderr);
308 ok = 0;
309 }
310
8b810a45 311 mp_drop(q); mp_drop(p); mp_drop(g);
312 if (!rc) {
a63f764a 313 mp_drop(dp.q); mp_drop(dp.p); mp_drop(dp.g); xfree(ds.p);
8b810a45 314 }
8a33545f 315 assert(mparena_count(MPARENA_GLOBAL) == 0);
8b810a45 316 return (ok);
317}
318
319static test_chunk tests[] = {
320 { "gen", verify,
a63f764a 321 { &type_hex, &type_ulong, &type_hex, &type_ulong,
322 &type_mp, &type_mp, &type_mp, 0 } },
8b810a45 323 { 0, 0, { 0 } }
324};
325
326int main(int argc, char *argv[])
327{
328 sub_init();
329 test_run(argc, argv, tests, SRCDIR "/tests/dsa");
330 return (0);
331}
332
333#endif
334
335/*----- That's all, folks -------------------------------------------------*/