math/mpreduce.h: Missing include files.
[u/mdw/catacomb] / pub / dsa-gen.c
CommitLineData
8b810a45 1/* -*-c-*-
2 *
8b810a45 3 * Generate DSA shared parameters
4 *
5 * (c) 1999 Straylight/Edgeware
6 */
7
45c0fd36 8/*----- Licensing notice --------------------------------------------------*
8b810a45 9 *
10 * This file is part of Catacomb.
11 *
12 * Catacomb is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as
14 * published by the Free Software Foundation; either version 2 of the
15 * License, or (at your option) any later version.
45c0fd36 16 *
8b810a45 17 * Catacomb is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
45c0fd36 21 *
8b810a45 22 * You should have received a copy of the GNU Library General Public
23 * License along with Catacomb; if not, write to the Free
24 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25 * MA 02111-1307, USA.
26 */
27
8b810a45 28/*----- Header files ------------------------------------------------------*/
29
30#include <stdio.h>
31#include <stdlib.h>
32
33#include "dsa.h"
b04a7659 34#include "dsarand.h"
ef5f4810 35#include "fibrand.h"
8b810a45 36#include "mp.h"
ef5f4810 37#include "mprand.h"
8b810a45 38#include "pgen.h"
b04a7659 39#include "prim.h"
8b810a45 40#include "sha.h"
41
b04a7659 42/*----- The DSA stepper ---------------------------------------------------*/
8b810a45 43
b04a7659 44/* --- @next@ --- *
8b810a45 45 *
b04a7659 46 * Arguments: @pgen_event *ev@ = pointer to event block
47 * @dsa_stepctx *d@ = pointer to stepping context
8b810a45 48 *
b04a7659 49 * Returns: A @PGEN@ result code.
8b810a45 50 *
b04a7659 51 * Use: Steps the generator once, reads the result, and tests it.
8b810a45 52 */
53
b04a7659 54static int next(pgen_event *ev, dsa_stepctx *d)
8b810a45 55{
b04a7659 56 mp *m;
57 int rc;
8b810a45 58
b04a7659 59 /* --- Load the new candidate --- */
8b810a45 60
a63f764a 61 if (d->seedbuf)
62 d->r->ops->misc(d->r, DSARAND_GETSEED, d->seedbuf);
63 m = mprand(ev->m, d->bits, d->r, 0);
8b810a45 64
b04a7659 65 /* --- Force to be a multiple of @q@ --- */
ef5f4810 66
b04a7659 67 if (d->q) {
68 mp *r = MP_NEW;
69 mp_div(0, &r, m, d->q);
70 m = mp_sub(m, m, r);
71 mp_drop(r);
8b810a45 72 }
b04a7659 73 m->v[0] |= d->or;
74 ev->m = m;
8b810a45 75
b04a7659 76 /* --- Do the trial division --- */
8b810a45 77
8a33545f 78 rc = pfilt_smallfactor(m);
a63f764a 79 d->count++;
8b810a45 80
b04a7659 81 /* --- Return the result --- */
8b810a45 82
b04a7659 83 return (rc);
84}
8b810a45 85
b04a7659 86/* --- @dsa_step@ --- */
87
88int dsa_step(int rq, pgen_event *ev, void *p)
89{
90 dsa_stepctx *d = p;
91
92 switch (rq) {
93 case PGEN_BEGIN:
b04a7659 94 case PGEN_TRY:
95 return (next(ev, d));
96 case PGEN_DONE:
97 return (PGEN_DONE);
8b810a45 98 }
b04a7659 99 return (PGEN_ABORT);
100}
8b810a45 101
b04a7659 102/*----- Glue code ---------------------------------------------------------*/
8b810a45 103
2b31b269 104/* --- @dsa_gen@ --- *
b04a7659 105 *
106 * Arguments: @dsa_param *dp@ = where to store parameters
107 * @unsigned ql@ = length of @q@ in bits
108 * @unsigned pl@ = length of @p@ in bits
109 * @unsigned steps@ = number of steps to find @q@
110 * @const void *k@ = pointer to key material
111 * @size_t sz@ = size of key material
a63f764a 112 * @dsa_seed *ds@ = optional pointer for output seed information
b04a7659 113 * @pgen_proc *event@ = event handler function
114 * @void *ectx@ = argument for event handler
115 *
116 * Returns: @PGEN_DONE@ if everything worked ok; @PGEN_ABORT@ otherwise.
117 *
118 * Use: Generates the DSA shared parameters from a given seed value.
052b36d0 119 *
120 * The parameters are a prime %$q$%, relatively small, and a
121 * large prime %$p = kq + 1$% for some %$k$%, together with a
122 * generator %$g$% of the cyclic subgroup of order %$q$%. These
123 * are actually the same as the Diffie-Hellman parameter set,
124 * but the generation algorithm is different.
b04a7659 125 *
126 * The algorithm used is a compatible extension of the method
127 * described in the DSA standard, FIPS 186. The standard
128 * requires that %$q$% be 160 bits in size (i.e., @ql == 160@)
129 * and that the length of %$p$% be %$L = 512 + 64l$% for some
130 * %$l$%. Neither limitation applies to this implementation.
131 */
8b810a45 132
2b31b269 133int dsa_gen(dsa_param *dp, unsigned ql, unsigned pl, unsigned steps,
a63f764a 134 const void *k, size_t sz, dsa_seed *ds,
135 pgen_proc *event, void *ectx)
b04a7659 136{
137 dsa_stepctx s;
138 prim_ctx p;
139 int i;
140 rabin r;
141 mp *qc;
8b810a45 142
b04a7659 143 /* --- Initialize the stepping context --- */
8b810a45 144
b04a7659 145 s.r = dsarand_create(k, sz);
8b810a45 146
b04a7659 147 /* --- Find @q@ --- */
8b810a45 148
b04a7659 149 s.q = 0;
150 s.r->ops->misc(s.r, DSARAND_PASSES, 2);
151 s.bits = ql;
a63f764a 152 s.count = 0;
153 s.or = 1;
154 if (!ds)
155 s.seedbuf = 0;
156 else {
157 ds->sz = sz;
158 ds->p = s.seedbuf = xmalloc(sz);
159 }
b04a7659 160 if ((dp->q = pgen("q", MP_NEW, MP_NEW, event, ectx, steps, dsa_step, &s,
161 rabin_iters(ql), pgen_test, &r)) == 0)
162 goto fail_q;
8b810a45 163
b04a7659 164 /* --- Find @p@ --- */
8b810a45 165
a63f764a 166 s.count = ~0;
b04a7659 167 s.q = mp_lsl(MP_NEW, dp->q, 1);
168 s.r->ops->misc(s.r, DSARAND_PASSES, 1);
169 s.bits = pl;
a63f764a 170 s.seedbuf = 0;
b04a7659 171 if ((dp->p = pgen("p", MP_NEW, MP_NEW, event, ectx, 4096, dsa_step, &s,
172 rabin_iters(pl), pgen_test, &r)) == 0)
173 goto fail_p;
174 mp_drop(s.q);
a63f764a 175 if (ds)
176 ds->count = s.count;
b04a7659 177
178 /* --- Find @g@ --- *
179 *
180 * The division returns remainder 1. This doesn't matter.
181 */
182
183 mpmont_create(&p.mm, dp->p);
184 qc = MP_NEW; mp_div(&qc, 0, dp->p, dp->q);
185 i = 0;
2b31b269 186 p.exp = qc;
b04a7659 187 p.n = 0;
188 if ((dp->g = pgen("g", MP_NEW, MP_NEW, event, ectx, 0, prim_step, &i,
189 1, prim_test, &p)) == 0)
190 goto fail_g;
191
192 /* --- Done --- */
193
194 mp_drop(qc);
195 mpmont_destroy(&p.mm);
196 s.r->ops->destroy(s.r);
197 return (PGEN_DONE);
198
199 /* --- Tidy up when things go wrong --- */
200
201fail_g:
202 mp_drop(qc);
203 mpmont_destroy(&p.mm);
204fail_p:
205 mp_drop(dp->q);
206 mp_drop(s.q);
207fail_q:
208 s.r->ops->destroy(s.r);
a63f764a 209 if (ds)
210 xfree(ds->p);
b04a7659 211 return (PGEN_ABORT);
8b810a45 212}
213
b04a7659 214/*----- Test rig ----------------------------------------------------------*/
215
216#ifdef TEST_RIG
217
8b810a45 218static int verify(dstr *v)
219{
a63f764a 220 mp *q = *(mp **)v[4].buf;
221 mp *p = *(mp **)v[5].buf;
222 mp *g = *(mp **)v[6].buf;
8b810a45 223 dsa_param dp;
a63f764a 224 dsa_seed ds;
225 unsigned long l = *(unsigned long *)v[1].buf;
226 unsigned long n = *(unsigned long *)v[3].buf;
8b810a45 227 int ok = 1;
228 int rc;
a63f764a 229 keycheck kc;
230 keycheck_reportctx kcr;
8b810a45 231
a63f764a 232 rc = dsa_gen(&dp, 160, l, 16, v[0].buf, v[0].len, &ds, pgen_evspin, 0);
233 if (rc || ds.count != n || ds.sz != v[2].len ||
234 memcmp(ds.p, v[2].buf, v[2].len) != 0 ||
235 !MP_EQ(q, dp.q) || !MP_EQ(p, dp.p) || !MP_EQ(g, dp.g)) {
8b810a45 236 fputs("\n*** gen failed", stderr);
a63f764a 237 fputs("\nseed_in = ", stderr); type_hex.dump(&v[0], stderr);
238 fprintf(stderr, "\nl = %lu", l);
239 fputs("\nseed_out = ", stderr); type_hex.dump(&v[2], stderr);
45c0fd36
MW
240 fprintf(stderr, "\ncount = %lu", n);
241 fputs("\n q = ", stderr); mp_writefile(q, stderr, 16);
242 fputs("\n p = ", stderr); mp_writefile(p, stderr, 16);
243 fputs("\n g = ", stderr); mp_writefile(g, stderr, 16);
8b810a45 244 if (!rc) {
a63f764a 245 dstr d;
246 d.buf = ds.p; d.len = ds.sz;
247 fputs("\nds.seed = ", stderr); type_hex.dump(&d, stderr);
45c0fd36 248 fprintf(stderr, "\nds.count = %u", ds.count);
8b810a45 249 fputs("\ndp.q = ", stderr); mp_writefile(dp.q, stderr, 16);
250 fputs("\ndp.p = ", stderr); mp_writefile(dp.p, stderr, 16);
251 fputs("\ndp.g = ", stderr); mp_writefile(dp.g, stderr, 16);
252 }
253 fputc('\n', stderr);
254 ok = 0;
255 }
256
a63f764a 257 kcr.fp = stderr;
258 kcr.sev = KCSEV_ERR;
259 keycheck_init(&kc, keycheck_stdreport, &kcr);
260 if (!rc)
261 dsa_checkparam(&kc, &dp, &ds);
262 if (!keycheck_allclear(&kc, KCSEV_ERR)) {
263 fputs("\n*** gen failed check", stderr);
264 fputs("\nseed_in = ", stderr); type_hex.dump(&v[0], stderr);
265 fprintf(stderr, "\nl = %lu", l);
266 fputs("\nseed_out = ", stderr); type_hex.dump(&v[2], stderr);
45c0fd36
MW
267 fprintf(stderr, "\ncount = %lu", n);
268 fputs("\n q = ", stderr); mp_writefile(q, stderr, 16);
269 fputs("\n p = ", stderr); mp_writefile(p, stderr, 16);
270 fputs("\n g = ", stderr); mp_writefile(g, stderr, 16);
a63f764a 271 fputc('\n', stderr);
272 ok = 0;
273 }
274
8b810a45 275 mp_drop(q); mp_drop(p); mp_drop(g);
276 if (!rc) {
a63f764a 277 mp_drop(dp.q); mp_drop(dp.p); mp_drop(dp.g); xfree(ds.p);
8b810a45 278 }
8a33545f 279 assert(mparena_count(MPARENA_GLOBAL) == 0);
8b810a45 280 return (ok);
281}
282
283static test_chunk tests[] = {
284 { "gen", verify,
a63f764a 285 { &type_hex, &type_ulong, &type_hex, &type_ulong,
45c0fd36 286 &type_mp, &type_mp, &type_mp, 0 } },
8b810a45 287 { 0, 0, { 0 } }
288};
289
290int main(int argc, char *argv[])
291{
292 sub_init();
0f00dc4c 293 test_run(argc, argv, tests, SRCDIR "/t/dsa");
8b810a45 294 return (0);
295}
296
297#endif
298
299/*----- That's all, folks -------------------------------------------------*/