Breaks ABI! Add identification slots to abstract groups and elliptic
authormdw <mdw>
Mon, 4 Oct 2004 17:42:21 +0000 (17:42 +0000)
committermdw <mdw>
Mon, 4 Oct 2004 17:42:21 +0000 (17:42 +0000)
curves.  Add more Oakley groups.  Change test output.  Expose internals
of group, field and curve contexts to interested parties -- there will
be some.

18 files changed:
Makefile.m4
blkc.h
dh-param.c
ec-bin.c
ec-guts.h [new file with mode: 0644]
ec-info.c
ec-prime.c
ec-test.c
ec.h
f-binpoly.c
f-niceprime.c
f-prime.c
field-guts.h [new file with mode: 0644]
g-ec.c
g-prime.c
group-guts.h [new file with mode: 0644]
group.h
ptab.in

index 1cccc9b..21c6d34 100644 (file)
@@ -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 (file)
--- 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
  *
 
 #ifdef TEST_RIG
 
+#include <string.h>
+    
 #include <mLib/quis.h>
 #include <mLib/testrig.h>
 
index 2e31c83..5ecb3cb 100644 (file)
@@ -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);
 }
 
index 30e19a9..1a70fe2 100644 (file)
--- 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
  *
 #include <mLib/sub.h>
 
 #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 (file)
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
index ea584de..6b5e08e 100644 (file)
--- 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);
index 8f3c731..c146931 100644 (file)
@@ -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
 };
index 30d1069..6b24357 100644 (file)
--- 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 (file)
--- 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))
index 8fae42a..23d9984 100644 (file)
 #include <mLib/sub.h>
 
 #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;
index d9ec1ac..a6191da 100644 (file)
 #include <mLib/sub.h>
 
 #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;
index 1dcfded..9b1ceb6 100644 (file)
--- a/f-prime.c
+++ b/f-prime.c
 #include <mLib/sub.h>
 
 #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 (file)
index 0000000..ded616c
--- /dev/null
@@ -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 (file)
--- 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
  *
 #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;
index 6b9d28b..a33634d 100644 (file)
--- a/g-prime.c
+++ b/g-prime.c
 
 #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 (file)
index 0000000..c684579
--- /dev/null
@@ -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 (file)
--- 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 (file)
--- 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 -------------------------------------