From f94b972d1c0389e4e9203cc9919ceaadbe655b61 Mon Sep 17 00:00:00 2001 From: mdw Date: Mon, 4 Oct 2004 17:42:21 +0000 Subject: [PATCH] Breaks ABI! Add identification slots to abstract groups and elliptic curves. Add more Oakley groups. Change test output. Expose internals of group, field and curve contexts to interested parties -- there will be some. --- Makefile.m4 | 5 +-- blkc.h | 4 ++- dh-param.c | 23 +++++++++----- ec-bin.c | 20 +++++------- ec-guts.h | 60 ++++++++++++++++++++++++++++++++++++ ec-info.c | 13 +++++--- ec-prime.c | 5 ++- ec-test.c | 1 + ec.h | 5 ++- f-binpoly.c | 75 +++++++++++++++++++++++--------------------- f-niceprime.c | 63 +++++++++++++++++++++---------------- f-prime.c | 69 +++++++++++++++++++++++------------------ field-guts.h | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ g-ec.c | 57 +++++++++++++++------------------- g-prime.c | 55 ++++++++++++++++----------------- group-guts.h | 75 ++++++++++++++++++++++++++++++++++++++++++++ group.h | 9 +++++- ptab.in | 41 ++++++++++++++++++++----- 18 files changed, 489 insertions(+), 190 deletions(-) create mode 100644 ec-guts.h create mode 100644 field-guts.h create mode 100644 group-guts.h diff --git a/Makefile.m4 b/Makefile.m4 index 1cccc9b..21c6d34 100644 --- a/Makefile.m4 +++ b/Makefile.m4 @@ -161,8 +161,9 @@ pkginclude_HEADERS = \ tlsprf.h sslprf.h \ gfshare.h share.h \ rho.h \ - field.h ec.h ec-exp.h ec-test.h ectab.h ec-keys.h ec-raw.h \ - ptab.h group.h \ + field.h field-guts.h \ + ec.h ec-guts.h ec-exp.h ec-test.h ectab.h ec-keys.h ec-raw.h \ + ptab.h group.h group-guts.h \ allwithsuffix(`ciphers', `cipher_modes', `.h') \ allwithsuffix(`hashes', `hash_modes', `.h') \ addsuffix(`cipher_modes', `-def.h') \ diff --git a/blkc.h b/blkc.h index 77ecf0e..d785f1d 100644 --- a/blkc.h +++ b/blkc.h @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: blkc.h,v 1.8 2004/04/17 09:58:36 mdw Exp $ + * $Id$ * * Common definitions for block ciphers * @@ -257,6 +257,8 @@ #ifdef TEST_RIG +#include + #include #include diff --git a/dh-param.c b/dh-param.c index 2e31c83..5ecb3cb 100644 --- a/dh-param.c +++ b/dh-param.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: dh-param.c,v 1.2 2004/04/08 01:36:15 mdw Exp $ + * $Id$ * * Reading Diffie-Hellman parameters * @@ -78,7 +78,7 @@ fail: #include "fibrand.h" -int main(void) +int main(int argc, char *argv[]) { const pentry *pe; const char *e; @@ -86,24 +86,31 @@ int main(void) grand *gr; gr = fibrand_create(0); - fputs("checking standard prime fields: ", stdout); + fputs("checking standard prime fields...\n", stdout); for (pe = ptab; pe->name; pe++) { dh_param dp; group *g; getinfo(&dp, pe->data); + printf(" %s: ", pe->name); g = group_prime(&dp); + if (mp_bits(dp.q) > 2048 && + (!argv[1] || strcmp(argv[1], "keen") != 0)) { + fputs("skipping\n", stdout); + continue; + } + fflush(stdout); e = G_CHECK(g, gr); G_DESTROYGROUP(g); dh_paramfree(&dp); if (e) { - fprintf(stderr, "\n*** group %s fails: %s\n", pe->name, e); + printf("fails: %s\n", e); ok = 0; - } - putchar('.'); - fflush(stdout); + } else + fputs("ok\n", stdout); } gr->ops->destroy(gr); - fputs(ok ? " ok\n" : " failed\n", stdout); + if (ok) + fputs("all ok\n", stdout); return (!ok); } diff --git a/ec-bin.c b/ec-bin.c index 30e19a9..1a70fe2 100644 --- a/ec-bin.c +++ b/ec-bin.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: ec-bin.c,v 1.9 2004/04/08 01:36:15 mdw Exp $ + * $Id$ * * Arithmetic for elliptic curves over binary fields * @@ -32,13 +32,7 @@ #include #include "ec.h" - -/*----- Data structures ---------------------------------------------------*/ - -typedef struct ecctx { - ec_curve c; - mp *bb; -} ecctx; +#include "ec-guts.h" /*----- Main code ---------------------------------------------------------*/ @@ -130,7 +124,7 @@ static ec *ecprojdbl(ec_curve *c, ec *d, const ec *a) EC_SETINF(d); else { field *f = c->f; - ecctx *cc = (ecctx *)c; + ecctx_bin *cc = (ecctx_bin *)c; mp *dx, *dy, *dz, *u, *v; dy = F_SQR(f, MP_NEW, a->z); /* %$z^2$% */ @@ -326,7 +320,7 @@ static int ecprojcheck(ec_curve *c, const ec *p) static void ecdestroy(ec_curve *c) { - ecctx *cc = (ecctx *)c; + ecctx_bin *cc = (ecctx_bin *)c; MP_DROP(cc->c.a); MP_DROP(cc->c.b); if (cc->bb) MP_DROP(cc->bb); @@ -347,7 +341,7 @@ static void ecdestroy(ec_curve *c) ec_curve *ec_bin(field *f, mp *a, mp *b) { - ecctx *cc = CREATE(ecctx); + ecctx_bin *cc = CREATE(ecctx_bin); cc->c.ops = &ec_binops; cc->c.f = f; cc->c.a = F_IN(f, MP_NEW, a); @@ -358,7 +352,7 @@ ec_curve *ec_bin(field *f, mp *a, mp *b) ec_curve *ec_binproj(field *f, mp *a, mp *b) { - ecctx *cc = CREATE(ecctx); + ecctx_bin *cc = CREATE(ecctx_bin); cc->c.ops = &ec_binprojops; cc->c.f = f; cc->c.a = F_IN(f, MP_NEW, a); @@ -376,11 +370,13 @@ ec_curve *ec_binproj(field *f, mp *a, mp *b) } static const ec_ops ec_binops = { + "bin", ecdestroy, ec_stdsamep, ec_idin, ec_idout, ec_idfix, ecfind, ecneg, ecadd, ec_stdsub, ecdbl, eccheck }; static const ec_ops ec_binprojops = { + "binproj", ecdestroy, ec_stdsamep, ec_projin, ec_projout, ec_projfix, ecfind, ecprojneg, ecprojadd, ec_stdsub, ecprojdbl, ecprojcheck }; diff --git a/ec-guts.h b/ec-guts.h new file mode 100644 index 0000000..2bb0427 --- /dev/null +++ b/ec-guts.h @@ -0,0 +1,60 @@ +/* -*-c-*- + * + * $Id$ + * + * Internal structures for built-in elliptic curve types + * + * (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. + */ + +#ifndef CATACOMB_EC_GUTS_H +#define CATACOMB_EC_GUTS_H + +#ifdef __cplusplus + extern "C" { +#endif + +/*----- Header files ------------------------------------------------------*/ + +#ifndef CATACOMB_MP_H +# include "mp.h" +#endif + +#ifndef CATACOMB_EC_H +# include "ec.h" +#endif + +/*----- Data structures ---------------------------------------------------*/ + +typedef struct ecctx_bin { + ec_curve c; + mp *bb; +} ecctx_bin; + +/*----- That's all, folks -------------------------------------------------*/ + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/ec-info.c b/ec-info.c index ea584de..6b5e08e 100644 --- a/ec-info.c +++ b/ec-info.c @@ -551,20 +551,23 @@ int main(int argc, char *argv[]) } } } else { - fputs("checking standard curves: ", stdout); + fputs("checking standard curves...\n", stdout); for (ee = ectab; ee->name; ee++) { ec_info ei; + printf(" %s: ", ee->name); + fflush(stdout); getinfo(&ei, ee->data); e = ec_checkinfo(&ei, gr); ec_freeinfo(&ei); if (e) { - fprintf(stderr, "\n*** curve %s fails: %s\n", ee->name, e); + printf("fails: %s\n", e); ok = 0; - } - putchar('.'); + } else + fputs("ok\n", stdout); fflush(stdout); } - fputs(ok ? " ok\n" : " failed\n", stdout); + if (ok) + fputs("all ok\n", stdout); } gr->ops->destroy(gr); return (!ok); diff --git a/ec-prime.c b/ec-prime.c index 8f3c731..c146931 100644 --- a/ec-prime.c +++ b/ec-prime.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: ec-prime.c,v 1.11 2004/04/08 01:36:15 mdw Exp $ + * $Id$ * * Elliptic curves over prime fields * @@ -384,16 +384,19 @@ extern ec_curve *ec_primeproj(field *f, mp *a, mp *b) } static const ec_ops ec_primeops = { + "prime", ecdestroy, ec_stdsamep, ec_idin, ec_idout, ec_idfix, ecfind, ecneg, ecadd, ec_stdsub, ecdbl, eccheck }; static const ec_ops ec_primeprojops = { + "primeproj", ecdestroy, ec_stdsamep, ec_projin, ec_projout, ec_projfix, ecfind, ecneg, ecprojadd, ec_stdsub, ecprojdbl, ecprojcheck }; static const ec_ops ec_primeprojxops = { + "primeproj", ecdestroy, ec_stdsamep, ec_projin, ec_projout, ec_projfix, ecfind, ecneg, ecprojadd, ec_stdsub, ecprojxdbl, ecprojcheck }; diff --git a/ec-test.c b/ec-test.c index 30d1069..6b24357 100644 --- a/ec-test.c +++ b/ec-test.c @@ -103,6 +103,7 @@ static int ecSAMEP(ec_curve *cc, ec_curve *dd) } static const ec_ops ecops = { + "cardboard", ecDESTROY, ecSAMEP, ecIN, ecOUT, ecFIX, ecFIND, ecNEG, ecADD, ecSUB, ecDBL, ecCHECK }; diff --git a/ec.h b/ec.h index bd71810..92acc41 100644 --- a/ec.h +++ b/ec.h @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: ec.h,v 1.11 2004/04/08 01:36:15 mdw Exp $ + * $Id$ * * Elliptic curve definitions * @@ -84,6 +84,7 @@ typedef struct ec_mulfactor { */ typedef struct ec_ops { + const char *name; void (*destroy)(ec_curve */*c*/); int (*samep)(ec_curve */*c*/, ec_curve */*d*/); ec *(*in)(ec_curve */*c*/, ec */*d*/, const ec */*p*/); @@ -97,6 +98,8 @@ typedef struct ec_ops { int (*check)(ec_curve */*c*/, const ec */*p*/); } ec_ops; +#define EC_NAME(c) (c)->ops->name + #define EC_SAMEP(c, d) (c)->ops->samep((c), (d)) #define EC_IN(c, d, p) (c)->ops->in((c), (d), (p)) #define EC_OUT(c, d, p) (c)->ops->out((c), (d), (p)) diff --git a/f-binpoly.c b/f-binpoly.c index 8fae42a..23d9984 100644 --- a/f-binpoly.c +++ b/f-binpoly.c @@ -32,51 +32,57 @@ #include #include "field.h" -#include "gf.h" -#include "gfreduce.h" +#include "field-guts.h" #include "mprand.h" -#include "gfn.h" /*----- Polynomial basis --------------------------------------------------*/ -typedef struct fctx { - field f; - gfreduce r; -} fctx; - /* --- Field operations --- */ -static void fdestroy(field *ff) - { fctx *f = (fctx *)ff; gfreduce_destroy(&f->r); DESTROY(f); } +static void fdestroy(field *ff) { + fctx_binpoly *f = (fctx_binpoly *)ff; + gfreduce_destroy(&f->r); + DESTROY(f); +} -static mp *frand(field *f, mp *d, grand *r) - { return (mprand(d, f->nbits, r, 0)); } +static mp *frand(field *f, mp *d, grand *r) { + return (mprand(d, f->nbits, r, 0)); +} static int fzerop(field *ff, mp *x) { return (MP_ZEROP(x)); } static mp *fadd(field *ff, mp *d, mp *x, mp *y) { return (gf_add(d, x, y)); } static mp *fmul(field *ff, mp *d, mp *x, mp *y) { - fctx *f = (fctx *)ff; d = gf_mul(d, x, y); + fctx_binpoly *f = (fctx_binpoly *)ff; d = gf_mul(d, x, y); return (gfreduce_do(&f->r, d, d)); } static mp *fsqr(field *ff, mp *d, mp *x) { - fctx *f = (fctx *)ff; d = gf_sqr(d, x); + fctx_binpoly *f = (fctx_binpoly *)ff; d = gf_sqr(d, x); return (gfreduce_do(&f->r, d, d)); } -static mp *finv(field *ff, mp *d, mp *x) - { fctx *f = (fctx *)ff; d = gf_modinv(d, x, f->r.p); return (d); } +static mp *finv(field *ff, mp *d, mp *x) { + fctx_binpoly *f = (fctx_binpoly *)ff; + d = gf_modinv(d, x, f->r.p); + return (d); +} -static mp *freduce(field *ff, mp *d, mp *x) - { fctx *f = (fctx *)ff; return (gfreduce_do(&f->r, d, x)); } +static mp *freduce(field *ff, mp *d, mp *x) { + fctx_binpoly *f = (fctx_binpoly *)ff; + return (gfreduce_do(&f->r, d, x)); +} -static mp *fsqrt(field *ff, mp *d, mp *x) - { fctx *f = (fctx *)ff; return (gfreduce_sqrt(&f->r, d, x)); } +static mp *fsqrt(field *ff, mp *d, mp *x) { + fctx_binpoly *f = (fctx_binpoly *)ff; + return (gfreduce_sqrt(&f->r, d, x)); +} -static mp *fquadsolve(field *ff, mp *d, mp *x) - { fctx *f = (fctx *)ff; return (gfreduce_quadsolve(&f->r, d, x)); } +static mp *fquadsolve(field *ff, mp *d, mp *x) { + fctx_binpoly *f = (fctx_binpoly *)ff; + return (gfreduce_quadsolve(&f->r, d, x)); +} /* --- Field operations table --- */ @@ -100,7 +106,7 @@ static const field_ops fops = { field *field_binpoly(mp *p) { - fctx *f = CREATE(fctx); + fctx_binpoly *f = CREATE(fctx_binpoly); f->f.ops = &fops; f->f.zero = MP_ZERO; f->f.one = MP_ONE; @@ -113,29 +119,28 @@ field *field_binpoly(mp *p) /*----- Normal basis ------------------------------------------------------*/ -typedef struct fnctx { - fctx f; - gfn ntop, pton; -} fnctx; - /* --- Field operations --- */ static void fndestroy(field *ff) { - fnctx *f = (fnctx *)ff; gfreduce_destroy(&f->f.r); + fctx_binnorm *f = (fctx_binnorm *)ff; gfreduce_destroy(&f->f.r); gfn_destroy(&f->ntop); gfn_destroy(&f->pton); DESTROY(f); } static int fnsamep(field *ff, field *gg) { - fnctx *f = (fnctx *)ff, *g = (fnctx *)gg; + fctx_binnorm *f = (fctx_binnorm *)ff, *g = (fctx_binnorm *)gg; return (MP_EQ(f->ntop.r[0], g->ntop.r[0]) && field_stdsamep(ff, gg)); } -static mp *fnin(field *ff, mp *d, mp *x) - { fnctx *f = (fnctx *)ff; return (gfn_transform(&f->ntop, d, x)); } +static mp *fnin(field *ff, mp *d, mp *x) { + fctx_binnorm *f = (fctx_binnorm *)ff; + return (gfn_transform(&f->ntop, d, x)); +} -static mp *fnout(field *ff, mp *d, mp *x) - { fnctx *f = (fnctx *)ff; return (gfn_transform(&f->pton, d, x)); } +static mp *fnout(field *ff, mp *d, mp *x) { + fctx_binnorm *f = (fctx_binnorm *)ff; + return (gfn_transform(&f->pton, d, x)); +} /* --- Field operations table --- */ @@ -162,7 +167,7 @@ static const field_ops fnops = { field *field_binnorm(mp *p, mp *beta) { - fnctx *f = CREATE(fnctx); + fctx_binnorm *f = CREATE(fctx_binnorm); f->f.f.ops = &fnops; f->f.f.zero = MP_ZERO; f->f.f.one = MP_ONE; diff --git a/f-niceprime.c b/f-niceprime.c index d9ec1ac..a6191da 100644 --- a/f-niceprime.c +++ b/f-niceprime.c @@ -32,83 +32,92 @@ #include #include "field.h" -#include "mpreduce.h" +#include "field-guts.h" #include "mprand.h" /*----- Main code ---------------------------------------------------------*/ -typedef struct fctx { - field f; - mpreduce r; -} fctx; - /* --- Field operations --- */ -static void fdestroy(field *ff) - { fctx *f = (fctx *)ff; mpreduce_destroy(&f->r); DESTROY(f); } +static void fdestroy(field *ff) { + fctx_niceprime *f = (fctx_niceprime *)ff; + mpreduce_destroy(&f->r); + DESTROY(f); +} -static mp *frand(field *ff, mp *d, grand *r) - { fctx *f = (fctx *)ff; return (mprand_range(d, f->r.p, r, 0)); } +static mp *frand(field *ff, mp *d, grand *r) { + fctx_niceprime *f = (fctx_niceprime *)ff; + return (mprand_range(d, f->r.p, r, 0)); +} static int fzerop(field *ff, mp *x) { return (MP_ZEROP(x)); } -static mp *fneg(field *ff, mp *d, mp *x) - { fctx *f = (fctx *)ff; return (mp_sub(d, f->r.p, x)); } +static mp *fneg(field *ff, mp *d, mp *x) { + fctx_niceprime *f = (fctx_niceprime *)ff; + return (mp_sub(d, f->r.p, x)); +} static mp *fadd(field *ff, mp *d, mp *x, mp *y) { - fctx *f = (fctx *)ff; d = mp_add(d, x, y); + fctx_niceprime *f = (fctx_niceprime *)ff; d = mp_add(d, x, y); if (MP_NEGP(d)) d = mp_add(d, d, f->r.p); else if (MP_CMP(d, >, f->r.p)) d = mp_sub(d, d, f->r.p); return (d); } static mp *fsub(field *ff, mp *d, mp *x, mp *y) { - fctx *f = (fctx *)ff; d = mp_sub(d, x, y); + fctx_niceprime *f = (fctx_niceprime *)ff; d = mp_sub(d, x, y); if (MP_NEGP(d)) d = mp_add(d, d, f->r.p); else if (MP_CMP(d, >, f->r.p)) d = mp_sub(d, d, f->r.p); return (d); } static mp *fmul(field *ff, mp *d, mp *x, mp *y) { - fctx *f = (fctx *)ff; d = mp_mul(d, x, y); + fctx_niceprime *f = (fctx_niceprime *)ff; d = mp_mul(d, x, y); return (mpreduce_do(&f->r, d, d)); } static mp *fsqr(field *ff, mp *d, mp *x) { - fctx *f = (fctx *)ff; d = mp_sqr(d, x); + fctx_niceprime *f = (fctx_niceprime *)ff; d = mp_sqr(d, x); return (mpreduce_do(&f->r, d, d)); } -static mp *finv(field *ff, mp *d, mp *x) - { fctx *f = (fctx *)ff; d = mp_modinv(d, x, f->r.p); return (d); } +static mp *finv(field *ff, mp *d, mp *x) { + fctx_niceprime *f = (fctx_niceprime *)ff; + d = mp_modinv(d, x, f->r.p); + return (d); +} -static mp *freduce(field *ff, mp *d, mp *x) - { fctx *f = (fctx *)ff; return (mpreduce_do(&f->r, d, x)); } +static mp *freduce(field *ff, mp *d, mp *x) { + fctx_niceprime *f = (fctx_niceprime *)ff; + return (mpreduce_do(&f->r, d, x)); +} -static mp *fsqrt(field *ff, mp *d, mp *x) - { fctx *f = (fctx *)ff; return (mp_modsqrt(d, x, f->r.p)); } +static mp *fsqrt(field *ff, mp *d, mp *x) { + fctx_niceprime *f = (fctx_niceprime *)ff; + return (mp_modsqrt(d, x, f->r.p)); +} static mp *fdbl(field *ff, mp *d, mp *x) { - fctx *f = (fctx *)ff; d = mp_lsl(d, x, 1); + fctx_niceprime *f = (fctx_niceprime *)ff; d = mp_lsl(d, x, 1); if (MP_CMP(d, >, f->r.p)) d = mp_sub(d, d, f->r.p); return (d); } static mp *ftpl(field *ff, mp *d, mp *x) { - fctx *f = (fctx *)ff; MP_DEST(d, MP_LEN(x) + 1, x->f); + fctx_niceprime *f = (fctx_niceprime *)ff; MP_DEST(d, MP_LEN(x) + 1, x->f); MPX_UMULN(d->v, d->vl, x->v, x->vl, 3); while (MP_CMP(d, >, f->r.p)) d = mp_sub(d, d, f->r.p); return (d); } static mp *fqdl(field *ff, mp *d, mp *x) { - fctx *f = (fctx *)ff; d = mp_lsl(d, x, 2); + fctx_niceprime *f = (fctx_niceprime *)ff; d = mp_lsl(d, x, 2); while (MP_CMP(d, >, f->r.p)) d = mp_sub(d, d, f->r.p); return (d); } static mp *fhlv(field *ff, mp *d, mp *x) { - fctx *f = (fctx *)ff; + fctx_niceprime *f = (fctx_niceprime *)ff; if (MP_ZEROP(x)) { MP_COPY(x); MP_DROP(d); return (x); } if (x->v[0] & 1) { d = mp_add(d, x, f->r.p); x = d; } return (mp_lsr(d, x, 1)); @@ -137,7 +146,7 @@ static const field_ops fops = { field *field_niceprime(mp *p) { - fctx *f = CREATE(fctx); + fctx_niceprime *f = CREATE(fctx_niceprime); f->f.ops = &fops; f->f.zero = MP_ZERO; f->f.one = MP_ONE; diff --git a/f-prime.c b/f-prime.c index 1dcfded..9b1ceb6 100644 --- a/f-prime.c +++ b/f-prime.c @@ -32,95 +32,104 @@ #include #include "field.h" -#include "mpmont.h" #include "mprand.h" +#include "field-guts.h" /*----- Main code ---------------------------------------------------------*/ -typedef struct fctx { - field f; - mpmont mm; -} fctx; - /* --- Field operations --- */ -static void fdestroy(field *ff) - { fctx *f = (fctx *)ff; mpmont_destroy(&f->mm); DESTROY(f); } +static void fdestroy(field *ff) { + fctx_prime *f = (fctx_prime *)ff; + mpmont_destroy(&f->mm); + DESTROY(f); +} -static mp *frand(field *ff, mp *d, grand *r) - { fctx *f = (fctx *)ff; return (mprand_range(d, f->mm.m, r, 0)); } +static mp *frand(field *ff, mp *d, grand *r) { + fctx_prime *f = (fctx_prime *)ff; + return (mprand_range(d, f->mm.m, r, 0)); +} static mp *fin(field *ff, mp *d, mp *x) { - fctx *f = (fctx *)ff; + fctx_prime *f = (fctx_prime *)ff; mp_div(0, &d, x, f->mm.m); return (mpmont_mul(&f->mm, d, d, f->mm.r2)); } -static mp *fout(field *ff, mp *d, mp *x) - { fctx *f = (fctx *)ff; return (mpmont_reduce(&f->mm, d, x)); } +static mp *fout(field *ff, mp *d, mp *x) { + fctx_prime *f = (fctx_prime *)ff; + return (mpmont_reduce(&f->mm, d, x)); +} static int fzerop(field *ff, mp *x) { return (MP_ZEROP(x)); } -static mp *fneg(field *ff, mp *d, mp *x) - { fctx *f = (fctx *)ff; return (mp_sub(d, f->mm.m, x)); } +static mp *fneg(field *ff, mp *d, mp *x) { + fctx_prime *f = (fctx_prime *)ff; + return (mp_sub(d, f->mm.m, x)); +} static mp *fadd(field *ff, mp *d, mp *x, mp *y) { - fctx *f = (fctx *)ff; d = mp_add(d, x, y); + fctx_prime *f = (fctx_prime *)ff; d = mp_add(d, x, y); if (MP_NEGP(d)) d = mp_add(d, d, f->mm.m); else if (MP_CMP(d, >, f->mm.m)) d = mp_sub(d, d, f->mm.m); return (d); } static mp *fsub(field *ff, mp *d, mp *x, mp *y) { - fctx *f = (fctx *)ff; d = mp_sub(d, x, y); + fctx_prime *f = (fctx_prime *)ff; d = mp_sub(d, x, y); if (MP_NEGP(d)) d = mp_add(d, d, f->mm.m); else if (MP_CMP(d, >, f->mm.m)) d = mp_sub(d, d, f->mm.m); return (d); } -static mp *fmul(field *ff, mp *d, mp *x, mp *y) - { fctx *f = (fctx *)ff; return (mpmont_mul(&f->mm, d, x, y)); } +static mp *fmul(field *ff, mp *d, mp *x, mp *y) { + fctx_prime *f = (fctx_prime *)ff; + return (mpmont_mul(&f->mm, d, x, y)); +} static mp *fsqr(field *ff, mp *d, mp *x) { - fctx *f = (fctx *)ff; d = mp_sqr(d, x); + fctx_prime *f = (fctx_prime *)ff; d = mp_sqr(d, x); return (mpmont_reduce(&f->mm, d, d)); } static mp *finv(field *ff, mp *d, mp *x) { - fctx *f = (fctx *)ff; d = mpmont_reduce(&f->mm, d, x); + fctx_prime *f = (fctx_prime *)ff; d = mpmont_reduce(&f->mm, d, x); d = mp_modinv(d, d, f->mm.m); return (mpmont_mul(&f->mm, d, d, f->mm.r2)); } -static mp *freduce(field *ff, mp *d, mp *x) - { fctx *f = (fctx *)ff; mp_div(0, &d, x, f->mm.m); return (d); } +static mp *freduce(field *ff, mp *d, mp *x) { + fctx_prime *f = (fctx_prime *)ff; + mp_div(0, &d, x, f->mm.m); + return (d); +} static mp *fsqrt(field *ff, mp *d, mp *x) { - fctx *f = (fctx *)ff; d = mpmont_reduce(&f->mm, d, x); + fctx_prime *f = (fctx_prime *)ff; d = mpmont_reduce(&f->mm, d, x); d = mp_modsqrt(d, d, f->mm.m); if (!d) return (d); return (mpmont_mul(&f->mm, d, d, f->mm.r2)); } static mp *fdbl(field *ff, mp *d, mp *x) { - fctx *f = (fctx *)ff; d = mp_lsl(d, x, 1); + fctx_prime *f = (fctx_prime *)ff; d = mp_lsl(d, x, 1); if (MP_CMP(d, >, f->mm.m)) d = mp_sub(d, d, f->mm.m); return (d); } static mp *ftpl(field *ff, mp *d, mp *x) { - fctx *f = (fctx *)ff; MP_DEST(d, MP_LEN(x) + 1, x->f); + fctx_prime *f = (fctx_prime *)ff; MP_DEST(d, MP_LEN(x) + 1, x->f); MPX_UMULN(d->v, d->vl, x->v, x->vl, 3); while (MP_CMP(d, >, f->mm.m)) d = mp_sub(d, d, f->mm.m); return (d); } static mp *fqdl(field *ff, mp *d, mp *x) { - fctx *f = (fctx *)ff; d = mp_lsl(d, x, 2); + fctx_prime *f = (fctx_prime *)ff; d = mp_lsl(d, x, 2); while (MP_CMP(d, >, f->mm.m)) d = mp_sub(d, d, f->mm.m); return (d); } static mp *fhlv(field *ff, mp *d, mp *x) { - fctx *f = (fctx *)ff; + fctx_prime *f = (fctx_prime *)ff; if (MP_ZEROP(x)) { MP_COPY(x); MP_DROP(d); return (x); } if (x->v[0] & 1) { d = mp_add(d, x, f->mm.m); x = d; } return (mp_lsr(d, x, 1)); @@ -149,11 +158,11 @@ static const field_ops fops = { field *field_prime(mp *p) { - fctx *f; + fctx_prime *f; if (!MP_POSP(p) || !MP_ODDP(p)) return (0); - f = CREATE(fctx); + f = CREATE(fctx_prime); f->f.ops = &fops; mpmont_create(&f->mm, p); f->f.zero = MP_ZERO; diff --git a/field-guts.h b/field-guts.h new file mode 100644 index 0000000..ded616c --- /dev/null +++ b/field-guts.h @@ -0,0 +1,99 @@ +/* -*-c-*- + * + * $Id$ + * + * Internal structures for built-in fields + * + * (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. + */ + +#ifndef CATACOMB_FIELD_GUTS_H +#define CATACOMB_FIELD_GUTS_H + +#ifdef __cplusplus + extern "C" { +#endif + +/*----- Header files ------------------------------------------------------*/ + +#ifndef CATACOMB_MP_H +# include "mp.h" +#endif + +#ifndef CATACOMB_EC_H +# include "ec.h" +#endif + +#ifndef CATACOMB_MPMONT_H +# include "mpmont.h" +#endif + +#ifndef CATACOMB_MPREDUCE_H +# include "mpreduce.h" +#endif + +#ifndef CATACOMB_GF_H +# include "gf.h" +#endif + +#ifndef CATACOMB_GFN_H +# include "gfn.h" +#endif + +#ifndef CATACOMB_GFREDUCE_H +# include "gfreduce.h" +#endif + +#ifndef CATACOMB_FIELD_H +# include "field.h" +#endif + +/*----- Data structures ---------------------------------------------------*/ + +typedef struct fctx_prime { + field f; + mpmont mm; +} fctx_prime; + +typedef struct fctx_niceprime { + field f; + mpreduce r; +} fctx_niceprime; + +typedef struct fctx_binpoly { + field f; + gfreduce r; +} fctx_binpoly; + +typedef struct fctx_binnorm { + fctx_binpoly f; + gfn ntop, pton; +} fctx_binnorm; + +/*----- That's all, folks -------------------------------------------------*/ + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/g-ec.c b/g-ec.c index 32220ff..0b55020 100644 --- a/g-ec.c +++ b/g-ec.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: g-ec.c,v 1.5 2004/04/17 09:58:37 mdw Exp $ + * $Id$ * * Abstraction for elliptic curve groups * @@ -36,21 +36,14 @@ #define ge ec #include "group.h" #include "ec-raw.h" - -/*----- Data structures ---------------------------------------------------*/ - -typedef struct gctx { - group g; - ec id, gen; - ec_info ei; -} gctx; +#include "group-guts.h" /*----- Main code ---------------------------------------------------------*/ /* --- Group operations --- */ static void gdestroygroup(group *gg) { - gctx *g = (gctx *)gg; + gctx_ec *g = (gctx_ec *)gg; EC_DESTROY(&g->gen); ec_freeinfo(&g->ei); DESTROY(g); @@ -66,44 +59,44 @@ static void gburn(group *gg, ec *x) { if (x->x) (x->x)->f |= MP_BURN; } static void gdestroy(group *gg, ec *x) { EC_DESTROY(x); DESTROY(x); } static int gsamep(group *gg, group *hh) { - gctx *g = (gctx *)gg, *h = (gctx *)hh; + gctx_ec *g = (gctx_ec *)gg, *h = (gctx_ec *)hh; return (ec_sameinfop(&g->ei, &h->ei)); } static int geq(group *gg, ec *x, ec *y) { - gctx *g = (gctx *)gg; EC_FIX(g->ei.c, x, x); EC_FIX(g->ei.c, y, y); + gctx_ec *g = (gctx_ec *)gg; EC_FIX(g->ei.c, x, x); EC_FIX(g->ei.c, y, y); return (EC_EQ(x, y)); } static int gidentp(group *gg, ec *x) { return (EC_ATINF(x)); } static const char *gcheck(group *gg, grand *gr) - { gctx *g = (gctx *)gg; return (ec_checkinfo(&g->ei, gr)); } + { gctx_ec *g = (gctx_ec *)gg; return (ec_checkinfo(&g->ei, gr)); } static void gmul(group *gg, ec *d, ec *x, ec *y) - { gctx *g = (gctx *)gg; EC_ADD(g->ei.c, d, x, y); } + { gctx_ec *g = (gctx_ec *)gg; EC_ADD(g->ei.c, d, x, y); } static void gsqr(group *gg, ec *d, ec *x) - { gctx *g = (gctx *)gg; EC_DBL(g->ei.c, d, x); } + { gctx_ec *g = (gctx_ec *)gg; EC_DBL(g->ei.c, d, x); } static void ginv(group *gg, ec *d, ec *x) - { gctx *g = (gctx *)gg; EC_NEG(g->ei.c, d, x); } + { gctx_ec *g = (gctx_ec *)gg; EC_NEG(g->ei.c, d, x); } static void gdiv(group *gg, ec *d, ec *x, ec *y) - { gctx *g = (gctx *)gg; EC_SUB(g->ei.c, d, x, y); } + { gctx_ec *g = (gctx_ec *)gg; EC_SUB(g->ei.c, d, x, y); } static void gexp(group *gg, ec *d, ec *x, mp *n) - { gctx *g = (gctx *)gg; ec_imul(g->ei.c, d, x, n); } + { gctx_ec *g = (gctx_ec *)gg; ec_imul(g->ei.c, d, x, n); } static void gmexp(group *gg, ec *d, const group_expfactor *f, size_t n) { - gctx *g = (gctx *)gg; size_t i; + gctx_ec *g = (gctx_ec *)gg; size_t i; ec_mulfactor *ff = xmalloc(n * sizeof(ec_mulfactor)); for (i = 0; i < n; i++) { ff[i].base = *f[i].base; ff[i].exp = f[i].exp; } ec_immul(g->ei.c, d, ff, n); xfree(ff); } static int gread(group *gg, ec *d, const mptext_ops *ops, void *p) { - gctx *g = (gctx *)gg; + gctx_ec *g = (gctx_ec *)gg; ec t = EC_INIT; int rc = -1; int ch; @@ -128,54 +121,54 @@ done: } static int gwrite(group *gg, ec *x, const mptext_ops *ops, void *p) { - gctx *g = (gctx *)gg; int rc = -1; ec t = EC_INIT; EC_OUT(g->ei.c, &t, x); - if (EC_ATINF(&t)) rc = ops->put("inf", 3, p); + gctx_ec *g = (gctx_ec *)gg; int rc = -1; ec t = EC_INIT; + EC_OUT(g->ei.c, &t, x); if (EC_ATINF(&t)) rc = ops->put("inf", 3, p); else if (!ops->put("0x", 2, p) && !mp_write(t.x, 16, ops, p) && !ops->put(", 0x", 4, p) && !mp_write(t.y, 16, ops, p)) rc = 0; EC_DESTROY(&t); return (rc); } static mp *gtoint(group *gg, mp *d, ec *x) { - gctx *g = (gctx *)gg; ec t = EC_INIT; mp *i; if (EC_ATINF(x)) i = 0; + gctx_ec *g = (gctx_ec *)gg; ec t = EC_INIT; mp *i; if (EC_ATINF(x)) i = 0; else { EC_OUT(g->ei.c, &t, x); i = MP_COPY(t.x); EC_DESTROY(&t); } mp_drop(d); return (i); } static int gfromint(group *gg, ec *d, mp *x) { - gctx *g = (gctx *)gg; ec t = EC_INIT; + gctx_ec *g = (gctx_ec *)gg; ec t = EC_INIT; if (!ec_find(g->ei.c, &t, x)) return (-1); EC_IN(g->ei.c, d, &t); EC_DESTROY(&t); return (0); } static int gtoec(group *gg, ec *d, ec *x) - { gctx *g = (gctx *)gg; EC_OUT(g->ei.c, d, x); return (0); } + { gctx_ec *g = (gctx_ec *)gg; EC_OUT(g->ei.c, d, x); return (0); } static int gfromec(group *gg, ec *d, const ec *x) { - gctx *g = (gctx *)gg; ec t = EC_INIT; int rc; EC_IN(g->ei.c, &t, x); + gctx_ec *g = (gctx_ec *)gg; ec t = EC_INIT; int rc; EC_IN(g->ei.c, &t, x); rc = EC_CHECK(g->ei.c, &t); if (!rc) EC_COPY(d, &t); EC_DESTROY(&t); return (rc); } static int gtobuf(group *gg, buf *b, ec *x) { - gctx *g = (gctx *)gg; ec t = EC_INIT; int rc; + gctx_ec *g = (gctx_ec *)gg; ec t = EC_INIT; int rc; EC_OUT(g->ei.c, &t, x); rc = buf_putec(b, &t); EC_DESTROY(&t); return (rc); } static int gfrombuf(group *gg, buf *b, ec *d) { - gctx *g = (gctx *)gg; ec t = EC_INIT; int rc; + gctx_ec *g = (gctx_ec *)gg; ec t = EC_INIT; int rc; if (buf_getec(b, &t)) return (-1); EC_IN(g->ei.c, &t, &t); rc = EC_CHECK(g->ei.c, &t); if (!rc) EC_COPY(d, &t); EC_DESTROY(&t); return (rc); } static int gtoraw(group *gg, buf *b, ec *x) { - gctx *g = (gctx *)gg; ec t = EC_INIT; int rc; + gctx_ec *g = (gctx_ec *)gg; ec t = EC_INIT; int rc; EC_OUT(g->ei.c, &t, x); rc = ec_putraw(g->ei.c, b, &t); EC_DESTROY(&t); return (rc); } static int gfromraw(group *gg, buf *b, ec *d) { - gctx *g = (gctx *)gg; ec t = EC_INIT; int rc; + gctx_ec *g = (gctx_ec *)gg; ec t = EC_INIT; int rc; if (ec_getraw(g->ei.c, b, &t)) return (-1); EC_IN(g->ei.c, &t, &t); rc = EC_CHECK(g->ei.c, &t); if (!rc) EC_COPY(d, &t); EC_DESTROY(&t); return (rc); @@ -195,7 +188,7 @@ static int gfromraw(group *gg, buf *b, ec *d) { */ static const group_ops gops = { - GTY_EC, + GTY_EC, "ec", gdestroygroup, gcreate, gcopy, gburn, gdestroy, gsamep, geq, gidentp, gcheck, @@ -206,7 +199,7 @@ static const group_ops gops = { group *group_ec(const ec_info *ei) { - gctx *g = CREATE(gctx); + gctx_ec *g = CREATE(gctx_ec); g->g.ops = &gops; g->g.nbits = ei->c->f->nbits * 2; diff --git a/g-prime.c b/g-prime.c index 6b9d28b..a33634d 100644 --- a/g-prime.c +++ b/g-prime.c @@ -36,21 +36,14 @@ #define ge mp * #include "group.h" - -/*----- Data structures ---------------------------------------------------*/ - -typedef struct gctx { - group g; - mp *gen; - mpmont mm; -} gctx; +#include "group-guts.h" /*----- Main code ---------------------------------------------------------*/ /* --- Group operations --- */ static void gdestroygroup(group *gg) { - gctx *g = (gctx *)gg; + gctx_prime *g = (gctx_prime *)gg; mp_drop(g->gen); mp_drop(g->g.r); mp_drop(g->g.h); mpmont_destroy(&g->mm); DESTROY(g); @@ -67,14 +60,14 @@ static void gburn(group *gg, mp **x) { (*x)->f |= MP_BURN; } static void gdestroy(group *gg, mp **x) { MP_DROP(*x); DESTROY(x); } static int gsamep(group *gg, group *hh) { - gctx *g = (gctx *)gg, *h = (gctx *)hh; + gctx_prime *g = (gctx_prime *)gg, *h = (gctx_prime *)hh; return (MP_EQ(g->mm.m, h->mm.m)); } static int geq(group *gg, mp **x, mp **y) { return (MP_EQ(*x, *y)); } static const char *gcheck(group *gg, grand *gr) { - gctx *g = (gctx *)gg; int rc; mp *t; + gctx_prime *g = (gctx_prime *)gg; int rc; mp *t; if (!pgen_primep(g->mm.m, gr)) return ("p is not prime"); t = mp_mul(MP_NEW, g->g.r, g->g.h); t = mp_add(t, t, MP_ONE); rc = MP_EQ(t, g->mm.m); MP_DROP(t); if (!rc) return ("not a subgroup"); @@ -82,66 +75,72 @@ static const char *gcheck(group *gg, grand *gr) { } static void gmul(group *gg, mp **d, mp **x, mp **y) - { gctx *g = (gctx *)gg; *d = mpmont_mul(&g->mm, *d, *x, *y); } + { gctx_prime *g = (gctx_prime *)gg; *d = mpmont_mul(&g->mm, *d, *x, *y); } static void gsqr(group *gg, mp **d, mp **x) { - gctx *g = (gctx *)gg; mp *r = mp_sqr(*d, *x); + gctx_prime *g = (gctx_prime *)gg; mp *r = mp_sqr(*d, *x); *d = mpmont_reduce(&g->mm, r, r); } static void ginv(group *gg, mp **d, mp **x) { - gctx *g = (gctx *)gg; mp *r = mpmont_reduce(&g->mm, *d, *x); + gctx_prime *g = (gctx_prime *)gg; mp *r = mpmont_reduce(&g->mm, *d, *x); r = mp_modinv(r, r, g->mm.m); *d = mpmont_mul(&g->mm, r, r, g->mm.r2); } static void gexp(group *gg, mp **d, mp **x, mp *n) - { gctx *g = (gctx *)gg; *d = mpmont_expr(&g->mm, *d, *x, n); } + { gctx_prime *g = (gctx_prime *)gg; *d = mpmont_expr(&g->mm, *d, *x, n); } static void gmexp(group *gg, mp **d, const group_expfactor *f, size_t n) { - gctx *g = (gctx *)gg; size_t i; + gctx_prime *g = (gctx_prime *)gg; size_t i; mp_expfactor *ff = xmalloc(n * sizeof(mp_expfactor)); for (i = 0; i < n; i++) { ff[i].base = *f[i].base; ff[i].exp = f[i].exp; } *d = mpmont_mexpr(&g->mm, *d, ff, n); xfree(ff); } static int gread(group *gg, mp **d, const mptext_ops *ops, void *p) { - gctx *g = (gctx *)gg; mp *t; + gctx_prime *g = (gctx_prime *)gg; mp *t; if ((t = mp_read(MP_NEW, 0, ops, p)) == 0) return (-1); mp_drop(*d); *d = mpmont_mul(&g->mm, t, t, g->mm.r2); return (0); } static int gwrite(group *gg, mp **x, const mptext_ops *ops, void *p) { - gctx *g = (gctx *)gg; mp *t = mpmont_reduce(&g->mm, MP_NEW, *x); + gctx_prime *g = (gctx_prime *)gg; + mp *t = mpmont_reduce(&g->mm, MP_NEW, *x); int rc = mp_write(t, 10, ops, p); MP_DROP(t); return (rc); } -static mp *gtoint(group *gg, mp *d, mp **x) - { gctx *g = (gctx *)gg; return (mpmont_reduce(&g->mm, d, *x)); } +static mp *gtoint(group *gg, mp *d, mp **x) { + gctx_prime *g = (gctx_prime *)gg; + return (mpmont_reduce(&g->mm, d, *x)); +} static int gfromint(group *gg, mp **d, mp *x) { - gctx *g = (gctx *)gg; mp_div(0, d, x, g->mm.m); + gctx_prime *g = (gctx_prime *)gg; mp_div(0, d, x, g->mm.m); *d = mpmont_mul(&g->mm, *d, *d, g->mm.r2); return (0); } static int gtobuf(group *gg, buf *b, mp **x) { - gctx *g = (gctx *)gg; mp *t = mpmont_reduce(&g->mm, MP_NEW, *x); + gctx_prime *g = (gctx_prime *)gg; + mp *t = mpmont_reduce(&g->mm, MP_NEW, *x); int rc = buf_putmp(b, t); MP_DROP(t); return (rc); } static int gfrombuf(group *gg, buf *b, mp **d) { - gctx * g = (gctx *)gg; mp *x; if ((x = buf_getmp(b)) == 0) return (-1); + gctx_prime * g = (gctx_prime *)gg; mp *x; + if ((x = buf_getmp(b)) == 0) return (-1); mp_div(0, &x, x, g->mm.m); mp_drop(*d); *d = mpmont_mul(&g->mm, x, x, g->mm.r2); return(0); } static int gtoraw(group *gg, buf *b, mp **x) { - gctx *g = (gctx *)gg; octet *q; mp *t = mpmont_reduce(&g->mm, MP_NEW, *x); + gctx_prime *g = (gctx_prime *)gg; octet *q; + mp *t = mpmont_reduce(&g->mm, MP_NEW, *x); if ((q = buf_get(b, g->g.noctets)) == 0) { MP_DROP(t); return (-1); } mp_storeb(t, q, g->g.noctets); MP_DROP(t); return (0); } static int gfromraw(group *gg, buf *b, mp **d) { - gctx * g = (gctx *)gg; mp *x; octet *q; + gctx_prime * g = (gctx_prime *)gg; mp *x; octet *q; if ((q = buf_get(b, g->g.noctets)) == 0) return (-1); x = mp_loadb(MP_NEW, q, g->g.noctets); mp_div(0, &x, x, g->mm.m); mp_drop(*d); @@ -159,7 +158,7 @@ static int gfromraw(group *gg, buf *b, mp **d) { */ static const group_ops gops = { - GTY_PRIME, + GTY_PRIME, "prime", gdestroygroup, gcreate, gcopy, gburn, gdestroy, gsamep, geq, group_stdidentp, gcheck, @@ -171,11 +170,11 @@ static const group_ops gops = { group *group_prime(const gprime_param *gp) { - gctx *g; + gctx_prime *g; if (!MP_POSP(gp->p) || !MP_ODDP(gp->p)) return (0); - g = CREATE(gctx); + g = CREATE(gctx_prime); g->g.ops = &gops; g->g.nbits = mp_bits(gp->p); g->g.noctets = (g->g.nbits + 7) >> 3; diff --git a/group-guts.h b/group-guts.h new file mode 100644 index 0000000..c684579 --- /dev/null +++ b/group-guts.h @@ -0,0 +1,75 @@ +/* -*-c-*- + * + * $Id$ + * + * Internal structures for built-in groups + * + * (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. + */ + +#ifndef CATACOMB_GROUP_GUTS_H +#define CATACOMB_GROUP_GUTS_H + +#ifdef __cplusplus + extern "C" { +#endif + +/*----- Header files ------------------------------------------------------*/ + +#ifndef CATACOMB_MP_H +# include "mp.h" +#endif + +#ifndef CATACOMB_EC_H +# include "ec.h" +#endif + +#ifndef CATACOMB_MPMONT_H +# include "mpmont.h" +#endif + +#ifndef CATACOMB_GROUP_H +# include "group.h" +#endif + +/*----- Data structures ---------------------------------------------------*/ + +typedef struct gctx_prime { + group g; + mp *gen; + mpmont mm; +} gctx_prime; + +typedef struct gctx_ec { + group g; + ec id, gen; + ec_info ei; +} gctx_ec; + +/*----- That's all, folks -------------------------------------------------*/ + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/group.h b/group.h index 9578f33..aae0e60 100644 --- a/group.h +++ b/group.h @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: group.h,v 1.5 2004/04/17 09:58:37 mdw Exp $ + * $Id$ * * General cyclic group abstraction * @@ -80,7 +80,11 @@ typedef struct group_expfactor { } group_expfactor; typedef struct group_ops { + + /* --- General information --- */ + unsigned ty; /* Type of this group */ + const char *name; /* Textual name string */ /* --- Memory management --- */ @@ -136,6 +140,9 @@ enum { GTY_EC /* Elliptic curve group */ }; +#define G_NAME(g) (g)->ops->name +#define G_TYPE(g) (g)->ops->ty + #define G_DESTROYGROUP(g) (g)->ops->destroygroup((g)) #define G_CREATE(g) (g)->ops->create((g)) #define G_COPY(g, d, x) (g)->ops->copy((g), (d), (x)) diff --git a/ptab.in b/ptab.in index 7f99f64..dfcf63b 100644 --- a/ptab.in +++ b/ptab.in @@ -1,22 +1,49 @@ -# $Id: ptab.in,v 1.1 2004/04/01 12:50:09 mdw Exp $ +# $Id$ # # Standard prime groups #----- Groups from Oakley (RFC2412) ----------------------------------------- group oakley768 - p 1552518092300708935130918131258481755631334049434514313202351194902966239949102107258669453876591642442910007680288864229150803718918046342632727613031282983744380820890196288509170691316593175367469551763119843371637221007210577919 - q 776259046150354467565459065629240877815667024717257156601175597451483119974551053629334726938295821221455003840144432114575401859459023171316363806515641491872190410445098144254585345658296587683734775881559921685818610503605288959 + p 0xffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a63a3620ffffffffffffffff + q 0x7fffffffffffffffe487ed5110b4611a62633145c06e0e68948127044533e63a0105df531d89cd9128a5043cc71a026ef7ca8cd9e69d218d98158536f92f8a1ba7f09ab6b6a8e122f242dabb312f3f637a262174d31d1b107fffffffffffffff g 2 group oakley1024 - p 179769313486231590770839156793787453197860296048756011706444423684197180216158519368947833795864925541502180565485980503646440548199239100050792877003355816639229553136239076508735759914822574862575007425302077447712589550957937778424442426617334727629299387668709205606050270810842907692932019128194467627007 - q 89884656743115795385419578396893726598930148024378005853222211842098590108079259684473916897932462770751090282742990251823220274099619550025396438501677908319614776568119538254367879957411287431287503712651038723856294775478968889212221213308667363814649693834354602803025135405421453846466009564097233813503 + p 0xffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece65381ffffffffffffffff + q 0x7fffffffffffffffe487ed5110b4611a62633145c06e0e68948127044533e63a0105df531d89cd9128a5043cc71a026ef7ca8cd9e69d218d98158536f92f8a1ba7f09ab6b6a8e122f242dabb312f3f637a262174d31bf6b585ffae5b7a035bf6f71c35fdad44cfd2d74f9208be258ff324943328f67329c0ffffffffffffffff g 2 group oakley1536 - p 2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919 - q 1205156213460516294276038011098783037428475274251229971327058470979054415841306114445046929130670807336613570738952006098251824478525291315971365353402504611531367372670536703348123007294680829887020513584624726600189364717085162921889329599071881596888429934762044470097788673059921772650773521873603874984881875042154463169647779984441228936206496905064565147296499973963182632029642323604865192473605840717232357219244260470063729922144429668263448160459816959 + p 0xffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff + q 0x7fffffffffffffffe487ed5110b4611a62633145c06e0e68948127044533e63a0105df531d89cd9128a5043cc71a026ef7ca8cd9e69d218d98158536f92f8a1ba7f09ab6b6a8e122f242dabb312f3f637a262174d31bf6b585ffae5b7a035bf6f71c35fdad44cfd2d74f9208be258ff324943328f6722d9ee1003e5c50b1df82cc6d241b0e2ae9cd348b1fd47e9267afc1b2ae91ee51d6cb0e3179ab1042a95dcf6a9483b84b4b36b3861aa7255e4c0278ba36046511b993ffffffffffffffff + g 2 + +#----- Groups from RFC3526 -------------------------------------------------- + +group oakley2048 + p 0xffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff + q 0x7fffffffffffffffe487ed5110b4611a62633145c06e0e68948127044533e63a0105df531d89cd9128a5043cc71a026ef7ca8cd9e69d218d98158536f92f8a1ba7f09ab6b6a8e122f242dabb312f3f637a262174d31bf6b585ffae5b7a035bf6f71c35fdad44cfd2d74f9208be258ff324943328f6722d9ee1003e5c50b1df82cc6d241b0e2ae9cd348b1fd47e9267afc1b2ae91ee51d6cb0e3179ab1042a95dcf6a9483b84b4b36b3861aa7255e4c0278ba36046511b993ffffffffffffffff + g 2 + +group oakley3072 + p 0xffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a93ad2caffffffffffffffff + q 0x7fffffffffffffffe487ed5110b4611a62633145c06e0e68948127044533e63a0105df531d89cd9128a5043cc71a026ef7ca8cd9e69d218d98158536f92f8a1ba7f09ab6b6a8e122f242dabb312f3f637a262174d31bf6b585ffae5b7a035bf6f71c35fdad44cfd2d74f9208be258ff324943328f6722d9ee1003e5c50b1df82cc6d241b0e2ae9cd348b1fd47e9267afc1b2ae91ee51d6cb0e3179ab1042a95dcf6a9483b84b4b36b3861aa7255e4c0278ba3604650c10be19482f23171b671df1cf3b960c074301cd93c1d17603d147dae2aef837a62964ef15e5fb4aac0b8c1ccaa4be754ab5728ae9130c4c7d02880ab9472d45556216d6998b8682283d19d42a90d5ef8e5d32767dc2822c6df785457538abae83063ed9cb87c2d370f263d5fad7466d8499eb8f464a702512b0cee771e9130d697735f897fd036cc504326c3b01399f643532290f958c0bbd90065df08babbd30aeb63b84c4605d6ca371047127d03a72d598a1edadfe707e884725c16890549d69657fffffffffffffff + g 2 + +group oakley4096 + p 0xffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c934063199ffffffffffffffff + q 0x7fffffffffffffffe487ed5110b4611a62633145c06e0e68948127044533e63a0105df531d89cd9128a5043cc71a026ef7ca8cd9e69d218d98158536f92f8a1ba7f09ab6b6a8e122f242dabb312f3f637a262174d31bf6b585ffae5b7a035bf6f71c35fdad44cfd2d74f9208be258ff324943328f6722d9ee1003e5c50b1df82cc6d241b0e2ae9cd348b1fd47e9267afc1b2ae91ee51d6cb0e3179ab1042a95dcf6a9483b84b4b36b3861aa7255e4c0278ba3604650c10be19482f23171b671df1cf3b960c074301cd93c1d17603d147dae2aef837a62964ef15e5fb4aac0b8c1ccaa4be754ab5728ae9130c4c7d02880ab9472d45556216d6998b8682283d19d42a90d5ef8e5d32767dc2822c6df785457538abae83063ed9cb87c2d370f263d5fad7466d8499eb8f464a702512b0cee771e9130d697735f897fd036cc504326c3b01399f643532290f958c0bbd90065df08babbd30aeb63b84c4605d6ca371047127d03a72d598a1edadfe707e884725c16890549084008d391e0953c3f36bc438cd085edd2d934ce1938c357a711e0d4a341a5b0a85ed12c1f4e5156a26746ddde16d826f477c97477e0a0fdf6553143e2ca3a735e02eccd94b27d04861d1119dd0c328adf3f68fb094b867716bd7dc0deebb10b8240e68034893ead82d54c9da754c46c7eee0c37fdbee48536047a6fa1ae49a0318ccffffffffffffffff + g 2 + +group oakley6144 + p 0xffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c93402849236c3fab4d27c7026c1d4dcb2602646dec9751e763dba37bdf8ff9406ad9e530ee5db382f413001aeb06a53ed9027d831179727b0865a8918da3edbebcf9b14ed44ce6cbaced4bb1bdb7f1447e6cc254b332051512bd7af426fb8f401378cd2bf5983ca01c64b92ecf032ea15d1721d03f482d7ce6e74fef6d55e702f46980c82b5a84031900b1c9e59e7c97fbec7e8f323a97a7e36cc88be0f1d45b7ff585ac54bd407b22b4154aacc8f6d7ebf48e1d814cc5ed20f8037e0a79715eef29be32806a1d58bb7c5da76f550aa3d8a1fbff0eb19ccb1a313d55cda56c9ec2ef29632387fe8d76e3c0468043e8f663f4860ee12bf2d5b0b7474d6e694f91e6dcc4024ffffffffffffffff + q 0x7fffffffffffffffe487ed5110b4611a62633145c06e0e68948127044533e63a0105df531d89cd9128a5043cc71a026ef7ca8cd9e69d218d98158536f92f8a1ba7f09ab6b6a8e122f242dabb312f3f637a262174d31bf6b585ffae5b7a035bf6f71c35fdad44cfd2d74f9208be258ff324943328f6722d9ee1003e5c50b1df82cc6d241b0e2ae9cd348b1fd47e9267afc1b2ae91ee51d6cb0e3179ab1042a95dcf6a9483b84b4b36b3861aa7255e4c0278ba3604650c10be19482f23171b671df1cf3b960c074301cd93c1d17603d147dae2aef837a62964ef15e5fb4aac0b8c1ccaa4be754ab5728ae9130c4c7d02880ab9472d45556216d6998b8682283d19d42a90d5ef8e5d32767dc2822c6df785457538abae83063ed9cb87c2d370f263d5fad7466d8499eb8f464a702512b0cee771e9130d697735f897fd036cc504326c3b01399f643532290f958c0bbd90065df08babbd30aeb63b84c4605d6ca371047127d03a72d598a1edadfe707e884725c16890549084008d391e0953c3f36bc438cd085edd2d934ce1938c357a711e0d4a341a5b0a85ed12c1f4e5156a26746ddde16d826f477c97477e0a0fdf6553143e2ca3a735e02eccd94b27d04861d1119dd0c328adf3f68fb094b867716bd7dc0deebb10b8240e68034893ead82d54c9da754c46c7eee0c37fdbee48536047a6fa1ae49a0142491b61fd5a693e381360ea6e593013236f64ba8f3b1edd1bdefc7fca0356cf298772ed9c17a09800d7583529f6c813ec188bcb93d8432d448c6d1f6df5e7cd8a76a267365d676a5d8dedbf8a23f36612a5999028a895ebd7a137dc7a009bc6695facc1e500e325c9767819750ae8b90e81fa416be7373a7f7b6aaf3817a34c06415ad42018c8058e4f2cf3e4bfdf63f47991d4bd3f1b66445f078ea2dbffac2d62a5ea03d915a0aa556647b6bf5fa470ec0a662f6907c01bf053cb8af7794df1940350eac5dbe2ed3b7aa8551ec50fdff8758ce658d189eaae6d2b64f617794b191c3ff46bb71e0234021f47b31fa43077095f96ad85ba3a6b734a7c8f36e620127fffffffffffffff + g 2 + +group oakley8192 + p 0xffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c93402849236c3fab4d27c7026c1d4dcb2602646dec9751e763dba37bdf8ff9406ad9e530ee5db382f413001aeb06a53ed9027d831179727b0865a8918da3edbebcf9b14ed44ce6cbaced4bb1bdb7f1447e6cc254b332051512bd7af426fb8f401378cd2bf5983ca01c64b92ecf032ea15d1721d03f482d7ce6e74fef6d55e702f46980c82b5a84031900b1c9e59e7c97fbec7e8f323a97a7e36cc88be0f1d45b7ff585ac54bd407b22b4154aacc8f6d7ebf48e1d814cc5ed20f8037e0a79715eef29be32806a1d58bb7c5da76f550aa3d8a1fbff0eb19ccb1a313d55cda56c9ec2ef29632387fe8d76e3c0468043e8f663f4860ee12bf2d5b0b7474d6e694f91e6dbe115974a3926f12fee5e438777cb6a932df8cd8bec4d073b931ba3bc832b68d9dd300741fa7bf8afc47ed2576f6936ba424663aab639c5ae4f5683423b4742bf1c978238f16cbe39d652de3fdb8befc848ad922222e04a4037c0713eb57a81a23f0c73473fc646cea306b4bcbc8862f8385ddfa9d4b7fa2c087e879683303ed5bdd3a062b3cf5b3a278a66d2a13f83f44f82ddf310ee074ab6a364597e899a0255dc164f31cc50846851df9ab48195ded7ea1b1d510bd7ee74d73faf36bc31ecfa268359046f4eb879f924009438b481c6cd7889a002ed5ee382bc9190da6fc026e479558e4475677e9aa9e3050e2765694dfc81f56e880b96e7160c980dd98edd3dfffffffffffffffff + q 0x7fffffffffffffffe487ed5110b4611a62633145c06e0e68948127044533e63a0105df531d89cd9128a5043cc71a026ef7ca8cd9e69d218d98158536f92f8a1ba7f09ab6b6a8e122f242dabb312f3f637a262174d31bf6b585ffae5b7a035bf6f71c35fdad44cfd2d74f9208be258ff324943328f6722d9ee1003e5c50b1df82cc6d241b0e2ae9cd348b1fd47e9267afc1b2ae91ee51d6cb0e3179ab1042a95dcf6a9483b84b4b36b3861aa7255e4c0278ba3604650c10be19482f23171b671df1cf3b960c074301cd93c1d17603d147dae2aef837a62964ef15e5fb4aac0b8c1ccaa4be754ab5728ae9130c4c7d02880ab9472d45556216d6998b8682283d19d42a90d5ef8e5d32767dc2822c6df785457538abae83063ed9cb87c2d370f263d5fad7466d8499eb8f464a702512b0cee771e9130d697735f897fd036cc504326c3b01399f643532290f958c0bbd90065df08babbd30aeb63b84c4605d6ca371047127d03a72d598a1edadfe707e884725c16890549084008d391e0953c3f36bc438cd085edd2d934ce1938c357a711e0d4a341a5b0a85ed12c1f4e5156a26746ddde16d826f477c97477e0a0fdf6553143e2ca3a735e02eccd94b27d04861d1119dd0c328adf3f68fb094b867716bd7dc0deebb10b8240e68034893ead82d54c9da754c46c7eee0c37fdbee48536047a6fa1ae49a0142491b61fd5a693e381360ea6e593013236f64ba8f3b1edd1bdefc7fca0356cf298772ed9c17a09800d7583529f6c813ec188bcb93d8432d448c6d1f6df5e7cd8a76a267365d676a5d8dedbf8a23f36612a5999028a895ebd7a137dc7a009bc6695facc1e500e325c9767819750ae8b90e81fa416be7373a7f7b6aaf3817a34c06415ad42018c8058e4f2cf3e4bfdf63f47991d4bd3f1b66445f078ea2dbffac2d62a5ea03d915a0aa556647b6bf5fa470ec0a662f6907c01bf053cb8af7794df1940350eac5dbe2ed3b7aa8551ec50fdff8758ce658d189eaae6d2b64f617794b191c3ff46bb71e0234021f47b31fa43077095f96ad85ba3a6b734a7c8f36df08acba51c937897f72f21c3bbe5b54996fc66c5f626839dc98dd1de4195b46cee9803a0fd3dfc57e23f692bb7b49b5d212331d55b1ce2d727ab41a11da3a15f8e4bc11c78b65f1ceb296f1fedc5f7e42456c911117025201be0389f5abd40d11f8639a39fe3236751835a5e5e44317c1c2eefd4ea5bfd16043f43cb41981f6adee9d03159e7ad9d13c53369509fc1fa27c16ef9887703a55b51b22cbf44cd012aee0b2798e628423428efcd5a40caef6bf50d8ea885ebf73a6b9fd79b5e18f67d1341ac8237a75c3cfc92004a1c5a40e366bc44d00176af71c15e48c86d37e013723caac7223ab3bf4d54f1828713b2b4a6fe40fab74405cb738b064c06ecc76e9efffffffffffffffff g 2 #----- Lim-Lee groups generated by hand ------------------------------------- -- 2.11.0