chiark / gitweb /
26daeef1ff3c49e9e95a725817caeac928b691be
[catacomb] / math / ec-test.c
1 /* -*-c-*-
2  *
3  * Code for testing elliptic-curve stuff
4  *
5  * (c) 2004 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
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.
16  *
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.
21  *
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
28 /*----- Header files ------------------------------------------------------*/
29
30 #include <assert.h>
31 #include <ctype.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include <mLib/alloc.h>
37 #include <mLib/testrig.h>
38 #include <mLib/sub.h>
39
40 #include "ec.h"
41 #include "ec-test.h"
42
43 /*----- Cardboard cut-out elliptic curve ----------------------------------*/
44
45 typedef struct ecctx {
46   ec_curve c;
47   unsigned long magic;
48   char *name;
49   ec_curve *real;
50 } ecctx;
51
52 #define MAGIC 0x3a1f0b07
53
54 static void ecDESTROY(ec_curve *cc)
55 {
56   ecctx *c = (ecctx *)cc;
57   xfree(c->name);
58   ec_destroycurve(c->real);
59   DESTROY(c);
60 }
61
62 #define UNOP(OP)                                                        \
63   static ec *ec##OP(ec_curve *cc, ec *d, const ec *p) {                 \
64     ecctx *c = (ecctx *)cc;                                             \
65     return (EC_##OP(c->real, d, p));                                    \
66   }
67
68 #define BINOP(OP)                                                       \
69   static ec *ec##OP(ec_curve *cc, ec *d, const ec *p, const ec *q) {    \
70     ecctx *c = (ecctx *)cc;                                             \
71     return (EC_##OP(c->real, d, p, q));                                 \
72   }
73
74 UNOP(IN)
75 UNOP(OUT)
76 UNOP(FIX)
77 UNOP(NEG)
78 UNOP(DBL)
79 BINOP(ADD)
80 BINOP(SUB)
81
82 #undef UNOP
83 #undef BINOP
84
85 static ec *ecFIND(ec_curve *cc, ec *d, mp *x)
86 {
87   ecctx *c = (ecctx *)cc;
88   return (EC_FIND(c->real, d, x));
89 }
90
91 static int ecCHECK(ec_curve *cc, const ec *p)
92 {
93   ecctx *c = (ecctx *)cc;
94   return (EC_CHECK(c->real, p));
95 }
96
97 static int ecSAMEP(ec_curve *cc, ec_curve *dd)
98 {
99   ecctx *c = (ecctx *)cc, *d = (ecctx *)dd;
100   return (ec_samep(c->real, d->real));
101 }
102
103 static const ec_ops ecops = {
104   "cardboard",
105   ecDESTROY, ecSAMEP, ecIN, ecOUT, ecFIX,
106   ecFIND, ecNEG, ecADD, ecSUB, ecDBL, ecCHECK
107 };
108
109 static ec_curve *ec_cutout(ec_curve *real, const char *name)
110 {
111   ecctx *c = CREATE(ecctx);
112   c->c.f = real->f;
113   c->c.ops = &ecops;
114   c->c.a = real->a;
115   c->c.b = real->b;
116   c->magic = MAGIC;
117   c->name = xstrdup(name);
118   c->real = real;
119   return (&c->c);
120 }
121
122 static const char *ec_name(ec_curve *cc)
123 {
124   ecctx *c = (ecctx *)cc;
125   assert(c->magic == MAGIC);
126   return (c->name);
127 }
128
129 /*----- Test field types --------------------------------------------------*/
130
131 static void ecvcvt(const char *buf, dstr *d)
132 {
133   ec_curve *v;
134   qd_parse qd;
135
136   qd.p = buf;
137   qd.e = 0;
138   if ((v = ec_curveparse(&qd)) == 0) {
139     fprintf(stderr, "bad curve `%.*s|%s': %s\n",
140             (int)(qd.p - buf), buf, qd.p, qd.e);
141     exit(1);
142   }
143   dstr_ensure(d, sizeof(v));
144   *(ec_curve **)d->buf = ec_cutout(v, buf);
145   d->len += sizeof(v);
146 }
147
148 static void ecvdump(dstr *d, FILE *fp)
149 {
150   ec_curve *v = *(ec_curve **)d->buf;
151   fprintf(fp, "%s", ec_name(v));
152 }
153
154 const test_type type_ecurve = { ecvcvt, ecvdump };
155
156 static void eccvt(const char *p, dstr *d)
157 {
158   ec *a;
159   qd_parse qd;
160
161   qd.p = p;
162   qd.e = 0;
163   dstr_ensure(d, sizeof(ec));
164   a = (ec *)d->buf;
165   d->len += sizeof(ec);
166   ec_create(a);
167   if (!ec_ptparse(&qd, a)) {
168     fprintf(stderr, "bad point `%.*s|%s': %s\n",
169             (int)(qd.p - p), p, qd.p, qd.e);
170     exit(1);
171   }
172 }
173
174 static void ecdodump(ec *a, FILE *fp)
175 {
176   if (EC_ATINF(a))
177     fputs("inf", fp);
178   else {
179     fputs("0x", fp);
180     mp_writefile(a->x, fp, 16);
181     fputs(", 0x", fp);
182     mp_writefile(a->y, fp, 16);
183   }
184 }
185
186 static void ecdump(dstr *d, FILE *fp)
187 {
188   ec *a = (ec *)d->buf;
189   ecdodump(a, fp);
190 }
191
192 const test_type type_ec = { eccvt, ecdump };
193
194 /*----- Testing elliptic curve functionality ------------------------------*/
195
196 #ifdef TEST_RIG
197
198 static void ecdestroy(ec_curve *c)
199 {
200   field *f = c->f;
201   ec_destroycurve(c);
202   F_DESTROY(f);
203 }
204
205 #define UNOP(op)                                                        \
206   static int v##op(dstr v[])                                            \
207   {                                                                     \
208     ec_curve *e = *(ec_curve **)v[0].buf;                               \
209     ec *a = (ec *)v[1].buf;                                             \
210     ec *r = (ec *)v[2].buf;                                             \
211     ec c = EC_INIT;                                                     \
212     int ok = 1;                                                         \
213     ec_##op(e, &c, a);                                                  \
214     if (!EC_EQ(r, &c)) {                                                \
215       fprintf(stderr, #op "failed");                                    \
216       fprintf(stderr, "\ncurve = "); type_ecurve.dump(v, stderr);       \
217       fprintf(stderr, "\n    a = "); ecdodump(a, stderr);               \
218       fprintf(stderr, "\n    r = "); ecdodump(r, stderr);               \
219       fprintf(stderr, "\n    c = "); ecdodump(&c, stderr);              \
220       fprintf(stderr, "\n");                                            \
221       ok = 0;                                                           \
222     }                                                                   \
223     EC_DESTROY(a); EC_DESTROY(r); EC_DESTROY(&c);                       \
224     ecdestroy(e);                                                       \
225     return (ok);                                                        \
226   }
227
228 #define BINOP(op)                                                       \
229   static int v##op(dstr v[])                                            \
230   {                                                                     \
231     ec_curve *e = *(ec_curve **)v[0].buf;                               \
232     ec *a = (ec *)v[1].buf;                                             \
233     ec *b = (ec *)v[2].buf;                                             \
234     ec *r = (ec *)v[3].buf;                                             \
235     ec c = EC_INIT;                                                     \
236     int ok = 1;                                                         \
237     ec_##op(e, &c, a, b);                                               \
238     if (!EC_EQ(r, &c)) {                                                \
239       fprintf(stderr, #op "failed");                                    \
240       fprintf(stderr, "\ncurve = "); type_ecurve.dump(v, stderr);       \
241       fprintf(stderr, "\n    a = "); ecdodump(a, stderr);               \
242       fprintf(stderr, "\n    b = "); ecdodump(b, stderr);               \
243       fprintf(stderr, "\n    r = "); ecdodump(r, stderr);               \
244       fprintf(stderr, "\n    c = "); ecdodump(&c, stderr);              \
245       fprintf(stderr, "\n");                                            \
246       ok = 0;                                                           \
247     }                                                                   \
248     EC_DESTROY(a); EC_DESTROY(b); EC_DESTROY(r); EC_DESTROY(&c);        \
249     ecdestroy(e);                                                       \
250     return (ok);                                                        \
251   }
252
253 UNOP(neg)
254 UNOP(dbl)
255 BINOP(add)
256 BINOP(sub)
257
258 static int vcheck(dstr v[])
259 {
260   ec_curve *e = *(ec_curve **)v[0].buf;
261   ec *a = (ec *)v[1].buf;
262   int r = *(int *)v[2].buf;
263   int c;
264   int ok = 1;
265   c = ec_check(e, a);
266   if (r != c) {
267     fprintf(stderr, "check failed");
268     fprintf(stderr, "\ncurve = "); type_ecurve.dump(v, stderr);
269     fprintf(stderr, "\n    a = "); ecdodump(a, stderr);
270     fprintf(stderr, "\n    r = %d", r);
271     fprintf(stderr, "\n    c = %d", c);
272     fprintf(stderr, "\n");
273     ok = 0;
274   }
275   EC_DESTROY(a);
276   ecdestroy(e);
277   return (ok);
278 }
279
280 static int vmul(dstr v[])
281 {
282   ec_curve *e = *(ec_curve **)v[0].buf;
283   ec *a = (ec *)v[1].buf;
284   mp *n = *(mp **)v[2].buf;
285   ec *r = (ec *)v[3].buf;
286   ec c = EC_INIT;
287   int ok = 1;
288   ec_mul(e, &c, a, n);
289   if (!EC_EQ(r, &c)) {
290     fprintf(stderr, "mul failed");
291     fprintf(stderr, "\ncurve = "); type_ecurve.dump(v, stderr);
292     fprintf(stderr, "\n    a = "); ecdodump(a, stderr);
293     fprintf(stderr, "\n    n = "); mp_writefile(n, stderr, 10);
294     fprintf(stderr, "\n    r = "); ecdodump(r, stderr);
295     fprintf(stderr, "\n    c = "); ecdodump(&c, stderr);
296     fprintf(stderr, "\n");
297     ok = 0;
298   }
299   EC_DESTROY(a); EC_DESTROY(r); EC_DESTROY(&c); MP_DROP(n);
300   ecdestroy(e);
301   return (ok);
302 }
303
304 static int vfind(dstr v[])
305 {
306   ec_curve *e = *(ec_curve **)v[0].buf;
307   mp *x = *(mp **)v[1].buf;
308   ec *r = (ec *)v[2].buf;
309   ec c = EC_INIT;
310   int ok = 1;
311   if (!ec_find(e, &c, x)) EC_SETINF(&c);
312   if (!EC_EQ(r, &c)) {
313     fprintf(stderr, "find failed");
314     fprintf(stderr, "\ncurve = "); type_ecurve.dump(v, stderr);
315     fprintf(stderr, "\n    x = "); mp_writefile(x, stderr, 16);
316     fprintf(stderr, "\n    r = "); ecdodump(r, stderr);
317     fprintf(stderr, "\n    c = "); ecdodump(&c, stderr);
318     fprintf(stderr, "\n");
319     ok = 0;
320   }
321   MP_DROP(x); EC_DESTROY(r); EC_DESTROY(&c);
322   ecdestroy(e);
323   return (ok);
324 }
325
326 static test_chunk tests[] = {
327   { "neg", vneg, { &type_ecurve, &type_ec, &type_ec } },
328   { "dbl", vdbl, { &type_ecurve, &type_ec, &type_ec } },
329   { "add", vadd, { &type_ecurve, &type_ec, &type_ec, &type_ec } },
330   { "sub", vsub, { &type_ecurve, &type_ec, &type_ec, &type_ec } },
331   { "mul", vmul, { &type_ecurve, &type_ec, &type_mp, &type_ec } },
332   { "check", vcheck, { &type_ecurve, &type_ec, &type_int } },
333   { "find", vfind, { &type_ecurve, &type_mp, &type_ec } },
334   { 0, 0, { 0 } }
335 };
336
337 int main(int argc, char *argv[])
338 {
339   sub_init();
340   test_run(argc, argv, tests, SRCDIR "/t/ec");
341   return (0);
342 }
343
344 #endif
345
346 /*----- That's all, folks -------------------------------------------------*/