3 * $Id: ec-test.c,v 1.2 2004/03/27 00:04:46 mdw Exp $
5 * Code for testing elliptic-curve stuff
7 * (c) 2004 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 /*----- Revision history --------------------------------------------------*
33 * Revision 1.2 2004/03/27 00:04:46 mdw
34 * Implement efficient reduction for pleasant-looking primes.
36 * Revision 1.1 2004/03/23 15:19:32 mdw
37 * Test elliptic curves more thoroughly.
41 /*----- Header files ------------------------------------------------------*/
49 #include <mLib/alloc.h>
50 #include <mLib/testrig.h>
56 /*----- Cardboard cut-out elliptic curve ----------------------------------*/
58 typedef struct ecctx
{
65 #define MAGIC 0x3a1f0b07
67 static void ecDESTROY(ec_curve
*cc
)
69 ecctx
*c
= (ecctx
*)cc
;
71 ec_destroycurve(c
->real
);
76 static ec *ec##OP(ec_curve *cc, ec *d, const ec *p) { \
77 ecctx *c = (ecctx *)cc; \
78 return (EC_##OP(c->real, d, p)); \
82 static ec *ec##OP(ec_curve *cc, ec *d, const ec *p, const ec *q) { \
83 ecctx *c = (ecctx *)cc; \
84 return (EC_##OP(c->real, d, p, q)); \
98 static ec
*ecFIND(ec_curve
*cc
, ec
*d
, mp
*x
)
100 ecctx
*c
= (ecctx
*)cc
;
101 return (EC_FIND(c
->real
, d
, x
));
104 static int ecCHECK(ec_curve
*cc
, const ec
*p
)
106 ecctx
*c
= (ecctx
*)cc
;
107 return (EC_CHECK(c
->real
, p
));
110 static ec_ops ecops
= {
111 ecDESTROY
, ecIN
, ecOUT
, ecFIX
,
112 ecFIND
, ecNEG
, ecADD
, ecSUB
, ecDBL
, ecCHECK
115 static ec_curve
*ec_cutout(ec_curve
*real
, const char *name
)
117 ecctx
*c
= CREATE(ecctx
);
121 c
->name
= xstrdup(name
);
126 static const char *ec_name(ec_curve
*cc
)
128 ecctx
*c
= (ecctx
*)cc
;
129 assert(c
->magic
== MAGIC
);
133 /*----- Test field types --------------------------------------------------*
135 * Really lazy parser. Sorry.
138 static void skipws(const char **p
)
140 while (isspace((unsigned char)**p
)) (*p
)++;
143 static void ckchar(const char **p
, int ch
)
144 { skipws(p
); if (**p
== ch
) (*p
)++; }
146 static void ckend(const char **p
)
150 fprintf(stderr
, "syntax error: junk at end of line\n");
155 static int ckstring(const char **p
, const char **s
)
161 for (i
= 0; s
[i
]; i
++) {
163 if (strncmp(*p
, s
[i
], n
) == 0 && !isalnum((unsigned char)(*p
)[n
])) {
168 fprintf(stderr
, "syntax error: couldn't recognize keyword\n");
172 static mp
*getmp(const char **p
)
177 m
= mp_readstring(MP_NEW
, *p
, &q
, 0);
178 if (!m
|| isalnum((unsigned char)*q
)) {
179 fprintf(stderr
, "syntax error: bad number\n");
186 static void ecvcvt(const char *buf
, dstr
*d
)
194 static const char *fnames
[] = {
195 "prime", "niceprime", "binpoly", 0
197 static const char *ecnames
[] = {
198 "prime", "primeproj", "bin", "binproj", 0
201 switch (i
= ckstring(&p
, fnames
), ckchar(&p
, ':'), i
) {
202 case 0: m
= getmp(&p
); f
= field_prime(m
); mp_drop(m
); break;
203 case 1: m
= getmp(&p
); f
= field_niceprime(m
); mp_drop(m
); break;
204 case 2: m
= getmp(&p
); f
= field_binpoly(m
); mp_drop(m
); break;
209 switch (i
= ckstring(&p
, ecnames
), ckchar(&p
, ':'), i
) {
210 case 0: m
= getmp(&p
); ckchar(&p
, ','); n
= getmp(&p
);
211 v
= ec_prime(f
, m
, n
); mp_drop(m
); mp_drop(n
); break;
212 case 1: m
= getmp(&p
); ckchar(&p
, ','); n
= getmp(&p
);
213 v
= ec_primeproj(f
, m
, n
); mp_drop(m
); mp_drop(n
); break;
214 case 2: m
= getmp(&p
); ckchar(&p
, ','); n
= getmp(&p
);
215 v
= ec_bin(f
, m
, n
); mp_drop(m
); mp_drop(n
); break;
216 case 3: m
= getmp(&p
); ckchar(&p
, ','); n
= getmp(&p
);
217 v
= ec_binproj(f
, m
, n
); mp_drop(m
); mp_drop(n
); break;
222 dstr_ensure(d
, sizeof(v
));
223 *(ec_curve
**)d
->buf
= ec_cutout(v
, buf
);
227 static void ecvdump(dstr
*d
, FILE *fp
)
229 ec_curve
*v
= *(ec_curve
**)d
->buf
;
230 fprintf(fp
, "%s", ec_name(v
));
233 test_type type_ecurve
= { ecvcvt
, ecvdump
};
235 static void eccvt(const char *p
, dstr
*d
)
239 dstr_ensure(d
, sizeof(ec
));
241 d
->len
+= sizeof(ec
);
244 if (strcmp(p
, "inf") == 0)
247 { a
->x
= getmp(&p
); ckchar(&p
, ','); a
->y
= getmp(&p
); ckend(&p
); }
250 static void ecdodump(ec
*a
, FILE *fp
)
256 mp_writefile(a
->x
, fp
, 16);
258 mp_writefile(a
->y
, fp
, 16);
262 static void ecdump(dstr
*d
, FILE *fp
)
264 ec
*a
= (ec
*)d
->buf
;
268 test_type type_ec
= { eccvt
, ecdump
};
270 /*----- Testing elliptic curve functionality ------------------------------*/
274 static void ecdestroy(ec_curve
*c
)
282 static int v##op(dstr v[]) \
284 ec_curve *e = *(ec_curve **)v[0].buf; \
285 ec *a = (ec *)v[1].buf; \
286 ec *r = (ec *)v[2].buf; \
290 if (!EC_EQ(r, &c)) { \
291 fprintf(stderr, #op "failed"); \
292 fprintf(stderr, "\ncurve = "); type_ecurve.dump(v, stderr); \
293 fprintf(stderr, "\n a = "); ecdodump(a, stderr); \
294 fprintf(stderr, "\n r = "); ecdodump(r, stderr); \
295 fprintf(stderr, "\n c = "); ecdodump(&c, stderr); \
296 fprintf(stderr, "\n"); \
299 EC_DESTROY(a); EC_DESTROY(r); EC_DESTROY(&c); \
305 static int v##op(dstr v[]) \
307 ec_curve *e = *(ec_curve **)v[0].buf; \
308 ec *a = (ec *)v[1].buf; \
309 ec *b = (ec *)v[2].buf; \
310 ec *r = (ec *)v[3].buf; \
313 ec_##op(e, &c, a, b); \
314 if (!EC_EQ(r, &c)) { \
315 fprintf(stderr, #op "failed"); \
316 fprintf(stderr, "\ncurve = "); type_ecurve.dump(v, stderr); \
317 fprintf(stderr, "\n a = "); ecdodump(a, stderr); \
318 fprintf(stderr, "\n b = "); ecdodump(b, stderr); \
319 fprintf(stderr, "\n r = "); ecdodump(r, stderr); \
320 fprintf(stderr, "\n c = "); ecdodump(&c, stderr); \
321 fprintf(stderr, "\n"); \
324 EC_DESTROY(a); EC_DESTROY(b); EC_DESTROY(r); EC_DESTROY(&c); \
334 static int vcheck(dstr v
[])
336 ec_curve
*e
= *(ec_curve
**)v
[0].buf
;
337 ec
*a
= (ec
*)v
[1].buf
;
338 int r
= *(int *)v
[2].buf
;
343 fprintf(stderr
, "check failed");
344 fprintf(stderr
, "\ncurve = "); type_ecurve
.dump(v
, stderr
);
345 fprintf(stderr
, "\n a = "); ecdodump(a
, stderr
);
346 fprintf(stderr
, "\n r = %d", r
);
347 fprintf(stderr
, "\n c = %d", c
);
348 fprintf(stderr
, "\n");
356 static int vmul(dstr v
[])
358 ec_curve
*e
= *(ec_curve
**)v
[0].buf
;
359 ec
*a
= (ec
*)v
[1].buf
;
360 mp
*n
= *(mp
**)v
[2].buf
;
361 ec
*r
= (ec
*)v
[3].buf
;
366 fprintf(stderr
, "mul failed");
367 fprintf(stderr
, "\ncurve = "); type_ecurve
.dump(v
, stderr
);
368 fprintf(stderr
, "\n a = "); ecdodump(a
, stderr
);
369 fprintf(stderr
, "\n n = "); mp_writefile(n
, stderr
, 10);
370 fprintf(stderr
, "\n r = "); ecdodump(r
, stderr
);
371 fprintf(stderr
, "\n c = "); ecdodump(&c
, stderr
);
372 fprintf(stderr
, "\n");
375 EC_DESTROY(a
); EC_DESTROY(r
); EC_DESTROY(&c
); MP_DROP(n
);
380 static int vfind(dstr v
[])
382 ec_curve
*e
= *(ec_curve
**)v
[0].buf
;
383 mp
*x
= *(mp
**)v
[1].buf
;
384 ec
*r
= (ec
*)v
[2].buf
;
387 if (!ec_find(e
, &c
, x
)) EC_SETINF(&c
);
389 fprintf(stderr
, "find failed");
390 fprintf(stderr
, "\ncurve = "); type_ecurve
.dump(v
, stderr
);
391 fprintf(stderr
, "\n x = "); mp_writefile(x
, stderr
, 16);
392 fprintf(stderr
, "\n r = "); ecdodump(r
, stderr
);
393 fprintf(stderr
, "\n c = "); ecdodump(&c
, stderr
);
394 fprintf(stderr
, "\n");
397 MP_DROP(x
); EC_DESTROY(r
); EC_DESTROY(&c
);
402 static test_chunk tests
[] = {
403 { "neg", vneg
, { &type_ecurve
, &type_ec
, &type_ec
} },
404 { "dbl", vdbl
, { &type_ecurve
, &type_ec
, &type_ec
} },
405 { "add", vadd
, { &type_ecurve
, &type_ec
, &type_ec
, &type_ec
} },
406 { "sub", vsub
, { &type_ecurve
, &type_ec
, &type_ec
, &type_ec
} },
407 { "mul", vmul
, { &type_ecurve
, &type_ec
, &type_mp
, &type_ec
} },
408 { "check", vcheck
, { &type_ecurve
, &type_ec
, &type_int
} },
409 { "find", vfind
, { &type_ecurve
, &type_mp
, &type_ec
} },
413 int main(int argc
, char *argv
[])
416 test_run(argc
, argv
, tests
, SRCDIR
"/tests/ec");
422 /*----- That's all, folks -------------------------------------------------*/