X-Git-Url: https://git.distorted.org.uk/u/mdw/catacomb/blobdiff_plain/ba6e6b64033b1f9de49feccb5c9cd438354481f7..0f00dc4c8eb47e67bc0f148c2dd109f73a451e0a:/math/ec-test.c diff --git a/math/ec-test.c b/math/ec-test.c new file mode 100644 index 0000000..db59294 --- /dev/null +++ b/math/ec-test.c @@ -0,0 +1,345 @@ +/* -*-c-*- + * + * Code for testing elliptic-curve stuff + * + * (c) 2004 Straylight/Edgeware + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of Catacomb. + * + * Catacomb is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * Catacomb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with Catacomb; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +/*----- Header files ------------------------------------------------------*/ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ec.h" +#include "ec-test.h" + +/*----- Cardboard cut-out elliptic curve ----------------------------------*/ + +typedef struct ecctx { + ec_curve c; + unsigned long magic; + char *name; + ec_curve *real; +} ecctx; + +#define MAGIC 0x3a1f0b07 + +static void ecDESTROY(ec_curve *cc) +{ + ecctx *c = (ecctx *)cc; + xfree(c->name); + ec_destroycurve(c->real); + DESTROY(c); +} + +#define UNOP(OP) \ + static ec *ec##OP(ec_curve *cc, ec *d, const ec *p) { \ + ecctx *c = (ecctx *)cc; \ + return (EC_##OP(c->real, d, p)); \ + } + +#define BINOP(OP) \ + static ec *ec##OP(ec_curve *cc, ec *d, const ec *p, const ec *q) { \ + ecctx *c = (ecctx *)cc; \ + return (EC_##OP(c->real, d, p, q)); \ + } + +UNOP(IN) +UNOP(OUT) +UNOP(FIX) +UNOP(NEG) +UNOP(DBL) +BINOP(ADD) +BINOP(SUB) + +#undef UNOP +#undef BINOP + +static ec *ecFIND(ec_curve *cc, ec *d, mp *x) +{ + ecctx *c = (ecctx *)cc; + return (EC_FIND(c->real, d, x)); +} + +static int ecCHECK(ec_curve *cc, const ec *p) +{ + ecctx *c = (ecctx *)cc; + return (EC_CHECK(c->real, p)); +} + +static int ecSAMEP(ec_curve *cc, ec_curve *dd) +{ + ecctx *c = (ecctx *)cc, *d = (ecctx *)dd; + return (ec_samep(c->real, d->real)); +} + +static const ec_ops ecops = { + "cardboard", + ecDESTROY, ecSAMEP, ecIN, ecOUT, ecFIX, + ecFIND, ecNEG, ecADD, ecSUB, ecDBL, ecCHECK +}; + +static ec_curve *ec_cutout(ec_curve *real, const char *name) +{ + ecctx *c = CREATE(ecctx); + c->c.f = real->f; + c->c.ops = &ecops; + c->c.a = real->a; + c->c.b = real->b; + c->magic = MAGIC; + c->name = xstrdup(name); + c->real = real; + return (&c->c); +} + +static const char *ec_name(ec_curve *cc) +{ + ecctx *c = (ecctx *)cc; + assert(c->magic == MAGIC); + return (c->name); +} + +/*----- Test field types --------------------------------------------------*/ + +static void ecvcvt(const char *buf, dstr *d) +{ + ec_curve *v; + qd_parse qd; + + qd.p = buf; + qd.e = 0; + if ((v = ec_curveparse(&qd)) == 0) { + fprintf(stderr, "bad curve `%.*s|%s': %s\n", + qd.p - buf, buf, qd.p, qd.e); + exit(1); + } + dstr_ensure(d, sizeof(v)); + *(ec_curve **)d->buf = ec_cutout(v, buf); + d->len += sizeof(v); +} + +static void ecvdump(dstr *d, FILE *fp) +{ + ec_curve *v = *(ec_curve **)d->buf; + fprintf(fp, "%s", ec_name(v)); +} + +const test_type type_ecurve = { ecvcvt, ecvdump }; + +static void eccvt(const char *p, dstr *d) +{ + ec *a; + qd_parse qd; + + qd.p = p; + qd.e = 0; + dstr_ensure(d, sizeof(ec)); + a = (ec *)d->buf; + d->len += sizeof(ec); + ec_create(a); + if (!ec_ptparse(&qd, a)) { + fprintf(stderr, "bad point `%.*s|%s': %s\n", qd.p - p, p, qd.p, qd.e); + exit(1); + } +} + +static void ecdodump(ec *a, FILE *fp) +{ + if (EC_ATINF(a)) + fputs("inf", fp); + else { + fputs("0x", fp); + mp_writefile(a->x, fp, 16); + fputs(", 0x", fp); + mp_writefile(a->y, fp, 16); + } +} + +static void ecdump(dstr *d, FILE *fp) +{ + ec *a = (ec *)d->buf; + ecdodump(a, fp); +} + +const test_type type_ec = { eccvt, ecdump }; + +/*----- Testing elliptic curve functionality ------------------------------*/ + +#ifdef TEST_RIG + +static void ecdestroy(ec_curve *c) +{ + field *f = c->f; + ec_destroycurve(c); + F_DESTROY(f); +} + +#define UNOP(op) \ + static int v##op(dstr v[]) \ + { \ + ec_curve *e = *(ec_curve **)v[0].buf; \ + ec *a = (ec *)v[1].buf; \ + ec *r = (ec *)v[2].buf; \ + ec c = EC_INIT; \ + int ok = 1; \ + ec_##op(e, &c, a); \ + if (!EC_EQ(r, &c)) { \ + fprintf(stderr, #op "failed"); \ + fprintf(stderr, "\ncurve = "); type_ecurve.dump(v, stderr); \ + fprintf(stderr, "\n a = "); ecdodump(a, stderr); \ + fprintf(stderr, "\n r = "); ecdodump(r, stderr); \ + fprintf(stderr, "\n c = "); ecdodump(&c, stderr); \ + fprintf(stderr, "\n"); \ + ok = 0; \ + } \ + EC_DESTROY(a); EC_DESTROY(r); EC_DESTROY(&c); \ + ecdestroy(e); \ + return (ok); \ + } + +#define BINOP(op) \ + static int v##op(dstr v[]) \ + { \ + ec_curve *e = *(ec_curve **)v[0].buf; \ + ec *a = (ec *)v[1].buf; \ + ec *b = (ec *)v[2].buf; \ + ec *r = (ec *)v[3].buf; \ + ec c = EC_INIT; \ + int ok = 1; \ + ec_##op(e, &c, a, b); \ + if (!EC_EQ(r, &c)) { \ + fprintf(stderr, #op "failed"); \ + fprintf(stderr, "\ncurve = "); type_ecurve.dump(v, stderr); \ + fprintf(stderr, "\n a = "); ecdodump(a, stderr); \ + fprintf(stderr, "\n b = "); ecdodump(b, stderr); \ + fprintf(stderr, "\n r = "); ecdodump(r, stderr); \ + fprintf(stderr, "\n c = "); ecdodump(&c, stderr); \ + fprintf(stderr, "\n"); \ + ok = 0; \ + } \ + EC_DESTROY(a); EC_DESTROY(b); EC_DESTROY(r); EC_DESTROY(&c); \ + ecdestroy(e); \ + return (ok); \ + } + +UNOP(neg) +UNOP(dbl) +BINOP(add) +BINOP(sub) + +static int vcheck(dstr v[]) +{ + ec_curve *e = *(ec_curve **)v[0].buf; + ec *a = (ec *)v[1].buf; + int r = *(int *)v[2].buf; + int c; + int ok = 1; + c = ec_check(e, a); + if (r != c) { + fprintf(stderr, "check failed"); + fprintf(stderr, "\ncurve = "); type_ecurve.dump(v, stderr); + fprintf(stderr, "\n a = "); ecdodump(a, stderr); + fprintf(stderr, "\n r = %d", r); + fprintf(stderr, "\n c = %d", c); + fprintf(stderr, "\n"); + ok = 0; + } + EC_DESTROY(a); + ecdestroy(e); + return (ok); +} + +static int vmul(dstr v[]) +{ + ec_curve *e = *(ec_curve **)v[0].buf; + ec *a = (ec *)v[1].buf; + mp *n = *(mp **)v[2].buf; + ec *r = (ec *)v[3].buf; + ec c = EC_INIT; + int ok = 1; + ec_mul(e, &c, a, n); + if (!EC_EQ(r, &c)) { + fprintf(stderr, "mul failed"); + fprintf(stderr, "\ncurve = "); type_ecurve.dump(v, stderr); + fprintf(stderr, "\n a = "); ecdodump(a, stderr); + fprintf(stderr, "\n n = "); mp_writefile(n, stderr, 10); + fprintf(stderr, "\n r = "); ecdodump(r, stderr); + fprintf(stderr, "\n c = "); ecdodump(&c, stderr); + fprintf(stderr, "\n"); + ok = 0; + } + EC_DESTROY(a); EC_DESTROY(r); EC_DESTROY(&c); MP_DROP(n); + ecdestroy(e); + return (ok); +} + +static int vfind(dstr v[]) +{ + ec_curve *e = *(ec_curve **)v[0].buf; + mp *x = *(mp **)v[1].buf; + ec *r = (ec *)v[2].buf; + ec c = EC_INIT; + int ok = 1; + if (!ec_find(e, &c, x)) EC_SETINF(&c); + if (!EC_EQ(r, &c)) { + fprintf(stderr, "find failed"); + fprintf(stderr, "\ncurve = "); type_ecurve.dump(v, stderr); + fprintf(stderr, "\n x = "); mp_writefile(x, stderr, 16); + fprintf(stderr, "\n r = "); ecdodump(r, stderr); + fprintf(stderr, "\n c = "); ecdodump(&c, stderr); + fprintf(stderr, "\n"); + ok = 0; + } + MP_DROP(x); EC_DESTROY(r); EC_DESTROY(&c); + ecdestroy(e); + return (ok); +} + +static test_chunk tests[] = { + { "neg", vneg, { &type_ecurve, &type_ec, &type_ec } }, + { "dbl", vdbl, { &type_ecurve, &type_ec, &type_ec } }, + { "add", vadd, { &type_ecurve, &type_ec, &type_ec, &type_ec } }, + { "sub", vsub, { &type_ecurve, &type_ec, &type_ec, &type_ec } }, + { "mul", vmul, { &type_ecurve, &type_ec, &type_mp, &type_ec } }, + { "check", vcheck, { &type_ecurve, &type_ec, &type_int } }, + { "find", vfind, { &type_ecurve, &type_mp, &type_ec } }, + { 0, 0, { 0 } } +}; + +int main(int argc, char *argv[]) +{ + sub_init(); + test_run(argc, argv, tests, SRCDIR "/t/ec"); + return (0); +} + +#endif + +/*----- That's all, folks -------------------------------------------------*/