bc985cef |
1 | /* -*-c-*- |
2 | * |
3 | * $Id: ec-test.c,v 1.1 2004/03/23 15:19:32 mdw Exp $ |
4 | * |
5 | * Code for testing elliptic-curve stuff |
6 | * |
7 | * (c) 2004 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: ec-test.c,v $ |
33 | * Revision 1.1 2004/03/23 15:19:32 mdw |
34 | * Test elliptic curves more thoroughly. |
35 | * |
36 | */ |
37 | |
38 | /*----- Header files ------------------------------------------------------*/ |
39 | |
40 | #include <assert.h> |
41 | #include <ctype.h> |
42 | #include <stdio.h> |
43 | #include <stdlib.h> |
44 | #include <string.h> |
45 | |
46 | #include <mLib/alloc.h> |
47 | #include <mLib/testrig.h> |
48 | #include <mLib/sub.h> |
49 | |
50 | #include "ec.h" |
51 | #include "ec-test.h" |
52 | |
53 | /*----- Cardboard cut-out elliptic curve ----------------------------------*/ |
54 | |
55 | typedef struct ecctx { |
56 | ec_curve c; |
57 | unsigned long magic; |
58 | char *name; |
59 | ec_curve *real; |
60 | } ecctx; |
61 | |
62 | #define MAGIC 0x3a1f0b07 |
63 | |
64 | static void ecDESTROY(ec_curve *cc) |
65 | { |
66 | ecctx *c = (ecctx *)cc; |
67 | xfree(c->name); |
68 | ec_destroycurve(c->real); |
69 | DESTROY(c); |
70 | } |
71 | |
72 | #define UNOP(OP) \ |
73 | static ec *ec##OP(ec_curve *cc, ec *d, const ec *p) { \ |
74 | ecctx *c = (ecctx *)cc; \ |
75 | return (EC_##OP(c->real, d, p)); \ |
76 | } |
77 | |
78 | #define BINOP(OP) \ |
79 | static ec *ec##OP(ec_curve *cc, ec *d, const ec *p, const ec *q) { \ |
80 | ecctx *c = (ecctx *)cc; \ |
81 | return (EC_##OP(c->real, d, p, q)); \ |
82 | } |
83 | |
84 | UNOP(IN) |
85 | UNOP(OUT) |
86 | UNOP(FIX) |
87 | UNOP(NEG) |
88 | UNOP(DBL) |
89 | BINOP(ADD) |
90 | BINOP(SUB) |
91 | |
92 | #undef UNOP |
93 | #undef BINOP |
94 | |
95 | static ec *ecFIND(ec_curve *cc, ec *d, mp *x) |
96 | { |
97 | ecctx *c = (ecctx *)cc; |
98 | return (EC_FIND(c->real, d, x)); |
99 | } |
100 | |
101 | static int ecCHECK(ec_curve *cc, const ec *p) |
102 | { |
103 | ecctx *c = (ecctx *)cc; |
104 | return (EC_CHECK(c->real, p)); |
105 | } |
106 | |
107 | static ec_ops ecops = { |
108 | ecDESTROY, ecIN, ecOUT, ecFIX, |
109 | ecFIND, ecNEG, ecADD, ecSUB, ecDBL, ecCHECK |
110 | }; |
111 | |
112 | static ec_curve *ec_cutout(ec_curve *real, const char *name) |
113 | { |
114 | ecctx *c = CREATE(ecctx); |
115 | c->c.f = real->f; |
116 | c->c.ops = &ecops; |
117 | c->magic = MAGIC; |
118 | c->name = xstrdup(name); |
119 | c->real = real; |
120 | return (&c->c); |
121 | } |
122 | |
123 | static const char *ec_name(ec_curve *cc) |
124 | { |
125 | ecctx *c = (ecctx *)cc; |
126 | assert(c->magic == MAGIC); |
127 | return (c->name); |
128 | } |
129 | |
130 | /*----- Test field types --------------------------------------------------* |
131 | * |
132 | * Really lazy parser. Sorry. |
133 | */ |
134 | |
135 | static void skipws(const char **p) |
136 | { |
137 | while (isspace((unsigned char)**p)) (*p)++; |
138 | } |
139 | |
140 | static void ckchar(const char **p, int ch) |
141 | { skipws(p); if (**p == ch) (*p)++; } |
142 | |
143 | static void ckend(const char **p) |
144 | { |
145 | skipws(p); |
146 | if (**p) { |
147 | fprintf(stderr, "syntax error: junk at end of line\n"); |
148 | abort(); |
149 | } |
150 | } |
151 | |
152 | static int ckstring(const char **p, const char **s) |
153 | { |
154 | int i; |
155 | size_t n; |
156 | |
157 | skipws(p); |
158 | for (i = 0; s[i]; i++) { |
159 | n = strlen(s[i]); |
160 | if (strncmp(*p, s[i], n) == 0 && !isalnum((unsigned char)(*p)[n])) { |
161 | *p += n; |
162 | return (i); |
163 | } |
164 | } |
165 | fprintf(stderr, "syntax error: couldn't recognize keyword\n"); |
166 | abort(); |
167 | } |
168 | |
169 | static mp *getmp(const char **p) |
170 | { |
171 | char *q; |
172 | mp *m; |
173 | skipws(p); |
174 | m = mp_readstring(MP_NEW, *p, &q, 0); |
175 | if (!m || isalnum((unsigned char)*q)) { |
176 | fprintf(stderr, "syntax error: bad number\n"); |
177 | abort(); |
178 | } |
179 | *p = q; |
180 | return (m); |
181 | } |
182 | |
183 | static void ecvcvt(const char *buf, dstr *d) |
184 | { |
185 | field *f; |
186 | ec_curve *v; |
187 | mp *m, *n; |
188 | const char *p = buf; |
189 | int i; |
190 | |
191 | static const char *fnames[] = { |
192 | "prime", "binpoly", 0 |
193 | }; |
194 | static const char *ecnames[] = { |
195 | "prime", "primeproj", "bin", "binproj", 0 |
196 | }; |
197 | |
198 | switch (i = ckstring(&p, fnames), ckchar(&p, ':'), i) { |
199 | case 0: m = getmp(&p); f = field_prime(m); mp_drop(m); break; |
200 | case 1: m = getmp(&p); f = field_binpoly(m); mp_drop(m); break; |
201 | default: abort(); |
202 | } |
203 | ckchar(&p, '/'); |
204 | |
205 | switch (i = ckstring(&p, ecnames), ckchar(&p, ':'), i) { |
206 | case 0: m = getmp(&p); ckchar(&p, ','); n = getmp(&p); |
207 | v = ec_prime(f, m, n); mp_drop(m); mp_drop(n); break; |
208 | case 1: m = getmp(&p); ckchar(&p, ','); n = getmp(&p); |
209 | v = ec_primeproj(f, m, n); mp_drop(m); mp_drop(n); break; |
210 | case 2: m = getmp(&p); ckchar(&p, ','); n = getmp(&p); |
211 | v = ec_bin(f, m, n); mp_drop(m); mp_drop(n); break; |
212 | case 3: m = getmp(&p); ckchar(&p, ','); n = getmp(&p); |
213 | v = ec_binproj(f, m, n); mp_drop(m); mp_drop(n); break; |
214 | default: abort(); |
215 | } |
216 | ckend(&p); |
217 | |
218 | dstr_ensure(d, sizeof(v)); |
219 | *(ec_curve **)d->buf = ec_cutout(v, buf); |
220 | d->len += sizeof(v); |
221 | } |
222 | |
223 | static void ecvdump(dstr *d, FILE *fp) |
224 | { |
225 | ec_curve *v = *(ec_curve **)d->buf; |
226 | fprintf(fp, "%s", ec_name(v)); |
227 | } |
228 | |
229 | test_type type_ecurve = { ecvcvt, ecvdump }; |
230 | |
231 | static void eccvt(const char *p, dstr *d) |
232 | { |
233 | ec *a; |
234 | |
235 | dstr_ensure(d, sizeof(ec)); |
236 | a = (ec *)d->buf; |
237 | d->len += sizeof(ec); |
238 | ec_create(a); |
239 | skipws(&p); |
240 | if (strcmp(p, "inf") == 0) |
241 | EC_SETINF(a); |
242 | else |
243 | { a->x = getmp(&p); ckchar(&p, ','); a->y = getmp(&p); ckend(&p); } |
244 | } |
245 | |
246 | static void ecdodump(ec *a, FILE *fp) |
247 | { |
248 | if (EC_ATINF(a)) |
249 | fputs("inf", fp); |
250 | else { |
251 | fputs("0x", fp); |
252 | mp_writefile(a->x, fp, 16); |
253 | fputs(", 0x", fp); |
254 | mp_writefile(a->y, fp, 16); |
255 | } |
256 | } |
257 | |
258 | static void ecdump(dstr *d, FILE *fp) |
259 | { |
260 | ec *a = (ec *)d->buf; |
261 | ecdodump(a, fp); |
262 | } |
263 | |
264 | test_type type_ec = { eccvt, ecdump }; |
265 | |
266 | /*----- Testing elliptic curve functionality ------------------------------*/ |
267 | |
268 | #ifdef TEST_RIG |
269 | |
270 | static void ecdestroy(ec_curve *c) |
271 | { |
272 | field *f = c->f; |
273 | ec_destroycurve(c); |
274 | F_DESTROY(f); |
275 | } |
276 | |
277 | #define UNOP(op) \ |
278 | static int v##op(dstr v[]) \ |
279 | { \ |
280 | ec_curve *e = *(ec_curve **)v[0].buf; \ |
281 | ec *a = (ec *)v[1].buf; \ |
282 | ec *r = (ec *)v[2].buf; \ |
283 | ec c = EC_INIT; \ |
284 | int ok = 1; \ |
285 | ec_##op(e, &c, a); \ |
286 | if (!EC_EQ(r, &c)) { \ |
287 | fprintf(stderr, #op "failed"); \ |
288 | fprintf(stderr, "\ncurve = "); type_ecurve.dump(v, stderr); \ |
289 | fprintf(stderr, "\n a = "); ecdodump(a, stderr); \ |
290 | fprintf(stderr, "\n r = "); ecdodump(r, stderr); \ |
291 | fprintf(stderr, "\n c = "); ecdodump(&c, stderr); \ |
292 | fprintf(stderr, "\n"); \ |
293 | ok = 0; \ |
294 | } \ |
295 | EC_DESTROY(a); EC_DESTROY(r); EC_DESTROY(&c); \ |
296 | ecdestroy(e); \ |
297 | return (ok); \ |
298 | } |
299 | |
300 | #define BINOP(op) \ |
301 | static int v##op(dstr v[]) \ |
302 | { \ |
303 | ec_curve *e = *(ec_curve **)v[0].buf; \ |
304 | ec *a = (ec *)v[1].buf; \ |
305 | ec *b = (ec *)v[2].buf; \ |
306 | ec *r = (ec *)v[3].buf; \ |
307 | ec c = EC_INIT; \ |
308 | int ok = 1; \ |
309 | ec_##op(e, &c, a, b); \ |
310 | if (!EC_EQ(r, &c)) { \ |
311 | fprintf(stderr, #op "failed"); \ |
312 | fprintf(stderr, "\ncurve = "); type_ecurve.dump(v, stderr); \ |
313 | fprintf(stderr, "\n a = "); ecdodump(a, stderr); \ |
314 | fprintf(stderr, "\n b = "); ecdodump(b, stderr); \ |
315 | fprintf(stderr, "\n r = "); ecdodump(r, stderr); \ |
316 | fprintf(stderr, "\n c = "); ecdodump(&c, stderr); \ |
317 | fprintf(stderr, "\n"); \ |
318 | ok = 0; \ |
319 | } \ |
320 | EC_DESTROY(a); EC_DESTROY(b); EC_DESTROY(r); EC_DESTROY(&c); \ |
321 | ecdestroy(e); \ |
322 | return (ok); \ |
323 | } |
324 | |
325 | UNOP(neg) |
326 | UNOP(dbl) |
327 | BINOP(add) |
328 | BINOP(sub) |
329 | |
330 | static int vcheck(dstr v[]) |
331 | { |
332 | ec_curve *e = *(ec_curve **)v[0].buf; |
333 | ec *a = (ec *)v[1].buf; |
334 | int r = *(int *)v[2].buf; |
335 | int c; |
336 | int ok = 1; |
337 | c = ec_check(e, a); |
338 | if (r != c) { |
339 | fprintf(stderr, "check failed"); |
340 | fprintf(stderr, "\ncurve = "); type_ecurve.dump(v, stderr); |
341 | fprintf(stderr, "\n a = "); ecdodump(a, stderr); |
342 | fprintf(stderr, "\n r = %d", r); |
343 | fprintf(stderr, "\n c = %d", c); |
344 | fprintf(stderr, "\n"); |
345 | ok = 0; |
346 | } |
347 | EC_DESTROY(a); |
348 | ecdestroy(e); |
349 | return (ok); |
350 | } |
351 | |
352 | static int vmul(dstr v[]) |
353 | { |
354 | ec_curve *e = *(ec_curve **)v[0].buf; |
355 | ec *a = (ec *)v[1].buf; |
356 | mp *n = *(mp **)v[2].buf; |
357 | ec *r = (ec *)v[3].buf; |
358 | ec c = EC_INIT; |
359 | int ok = 1; |
360 | ec_mul(e, &c, a, n); |
361 | if (!EC_EQ(r, &c)) { |
362 | fprintf(stderr, "mul failed"); |
363 | fprintf(stderr, "\ncurve = "); type_ecurve.dump(v, stderr); |
364 | fprintf(stderr, "\n a = "); ecdodump(a, stderr); |
365 | fprintf(stderr, "\n n = "); mp_writefile(n, stderr, 10); |
366 | fprintf(stderr, "\n r = "); ecdodump(r, stderr); |
367 | fprintf(stderr, "\n c = "); ecdodump(&c, stderr); |
368 | fprintf(stderr, "\n"); |
369 | ok = 0; |
370 | } |
371 | EC_DESTROY(a); EC_DESTROY(r); EC_DESTROY(&c); MP_DROP(n); |
372 | ecdestroy(e); |
373 | return (ok); |
374 | } |
375 | |
376 | static int vfind(dstr v[]) |
377 | { |
378 | ec_curve *e = *(ec_curve **)v[0].buf; |
379 | mp *x = *(mp **)v[1].buf; |
380 | ec *r = (ec *)v[2].buf; |
381 | ec c = EC_INIT; |
382 | int ok = 1; |
383 | if (!ec_find(e, &c, x)) EC_SETINF(&c); |
384 | if (!EC_EQ(r, &c)) { |
385 | fprintf(stderr, "find failed"); |
386 | fprintf(stderr, "\ncurve = "); type_ecurve.dump(v, stderr); |
387 | fprintf(stderr, "\n x = "); mp_writefile(x, stderr, 16); |
388 | fprintf(stderr, "\n r = "); ecdodump(r, stderr); |
389 | fprintf(stderr, "\n c = "); ecdodump(&c, stderr); |
390 | fprintf(stderr, "\n"); |
391 | ok = 0; |
392 | } |
393 | MP_DROP(x); EC_DESTROY(r); EC_DESTROY(&c); |
394 | ecdestroy(e); |
395 | return (ok); |
396 | } |
397 | |
398 | static test_chunk tests[] = { |
399 | { "neg", vneg, { &type_ecurve, &type_ec, &type_ec } }, |
400 | { "dbl", vdbl, { &type_ecurve, &type_ec, &type_ec } }, |
401 | { "add", vadd, { &type_ecurve, &type_ec, &type_ec, &type_ec } }, |
402 | { "sub", vsub, { &type_ecurve, &type_ec, &type_ec, &type_ec } }, |
403 | { "mul", vmul, { &type_ecurve, &type_ec, &type_mp, &type_ec } }, |
404 | { "check", vcheck, { &type_ecurve, &type_ec, &type_int } }, |
405 | { "find", vfind, { &type_ecurve, &type_mp, &type_ec } }, |
406 | { 0, 0, { 0 } } |
407 | }; |
408 | |
409 | int main(int argc, char *argv[]) |
410 | { |
411 | sub_init(); |
412 | test_run(argc, argv, tests, SRCDIR "/tests/ec"); |
413 | return (0); |
414 | } |
415 | |
416 | #endif |
417 | |
418 | /*----- That's all, folks -------------------------------------------------*/ |