chiark / gitweb /
ec, group: Bug squashing.
[catacomb-python] / group.c
1 /* -*-c-*-
2  *
3  * $Id$
4  *
5  * Abstract group inteface
6  *
7  * (c) 2004 Straylight/Edgeware
8  */
9
10 /*----- Licensing notice --------------------------------------------------* 
11  *
12  * This file is part of the Python interface to Catacomb.
13  *
14  * Catacomb/Python is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  * 
19  * Catacomb/Python is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  * 
24  * You should have received a copy of the GNU General Public License
25  * along with Catacomb/Python; if not, write to the Free Software Foundation,
26  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27  */
28
29 /*----- Header files ------------------------------------------------------*/
30
31 #include "catacomb-python.h"
32
33 /*----- DH and binary group infos -----------------------------------------*/
34
35 PyObject *fginfo_pywrap(gprime_param *dp, PyTypeObject *ty)
36 {
37   fginfo_pyobj *z = PyObject_New(fginfo_pyobj, ty);
38   z->dp.p = MP_COPY(dp->p);
39   z->dp.q = MP_COPY(dp->q);
40   z->dp.g = MP_COPY(dp->g);
41   return ((PyObject *)z);
42 }
43
44 static PyObject *fginfo_pynew(PyTypeObject *ty,
45                               PyObject *arg, PyObject *kw)
46 {
47   char *kwlist[] = { "p", "r", "g", 0 };
48   gprime_param dp = { 0 };
49   fginfo_pyobj *z = 0;
50
51   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&O&:new", kwlist,
52                                    convmp, &dp.p,
53                                    convmp, &dp.q,
54                                    convmp, &dp.g))
55     goto end;
56   z = PyObject_New(fginfo_pyobj, ty);
57   z->dp = dp;
58   return ((PyObject *)z);
59 end:
60   mp_drop(dp.p);
61   mp_drop(dp.q);
62   mp_drop(dp.g);
63   return (0);
64 }
65
66 static PyObject *figet_r(PyObject *me, void *hunoz)
67   { return mp_pywrap(FGINFO_DP(me)->q); }
68
69 static PyObject *diget_p(PyObject *me, void *hunoz)
70   { return mp_pywrap(FGINFO_DP(me)->p); }
71
72 static PyObject *diget_g(PyObject *me, void *hunoz)
73   { return mp_pywrap(FGINFO_DP(me)->g); }
74
75 static PyObject *biget_p(PyObject *me, void *hunoz)
76   { return gf_pywrap(FGINFO_DP(me)->p); }
77
78 static PyObject *biget_m(PyObject *me, void *hunoz)
79   { return PyInt_FromLong(mp_octets(FGINFO_DP(me)->p) - 1); }
80
81 static PyObject *biget_g(PyObject *me, void *hunoz)
82   { return gf_pywrap(FGINFO_DP(me)->g); }
83
84 static void fginfo_pydealloc(PyObject *me)
85 {
86   mp_drop(FGINFO_DP(me)->p);
87   mp_drop(FGINFO_DP(me)->q);
88   mp_drop(FGINFO_DP(me)->g);
89   FREEOBJ(me);
90 }
91
92 static PyObject *meth__DHInfo_generate(PyObject *me,
93                                        PyObject *arg, PyObject *kw)
94 {
95   dh_param dp;
96   unsigned ql = 0, pl;
97   unsigned steps = 0;
98   grand *r = &rand_global;
99   pgev evt = { 0 };
100   char *kwlist[] =
101     { "class", "pbits", "qbits", "event", "rng", "nsteps", 0 };
102   PyObject *rc = 0;
103
104   if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO&|O&O&O&O&:generate", kwlist,
105                                    &me, convuint, &pl, convuint, &ql,
106                                    convpgev, &evt, convgrand, &r,
107                                    convuint, &steps))
108     goto end;
109   if (dh_gen(&dp, ql, pl, steps, r, evt.proc, evt.ctx))
110     PGENERR;
111   rc = fginfo_pywrap(&dp, dhinfo_pytype);
112 end:
113   droppgev(&evt);
114   return (rc);
115 }
116
117 static PyObject *meth__DHInfo_genlimlee(PyObject *me,
118                                         PyObject *arg, PyObject *kw)
119 {
120   dh_param dp;
121   unsigned ql, pl;
122   unsigned steps = 0;
123   grand *r = &rand_global;
124   pgev oe = { 0 }, ie = { 0 };
125   int subgroupp = 1;
126   unsigned f = 0;
127   char *kwlist[] = { "class", "pbits", "qbits", "event", "ievent",
128                      "rng", "nsteps", "subgroupp", 0 };
129   size_t i, nf;
130   mp **v = 0;
131   PyObject *rc = 0, *vec = 0;
132
133   if (!PyArg_ParseTupleAndKeywords(arg, kw,
134                                    "OO&O&|O&O&O&O&O&:genlimlee", kwlist,
135                                    &me, convuint, &pl, convuint, &ql,
136                                    convpgev, &oe, convpgev, &ie,
137                                    convgrand, &r, convuint, &steps,
138                                    convbool, &subgroupp))
139     goto end;
140   if (subgroupp) f |= DH_SUBGROUP;
141   if (dh_limlee(&dp, ql, pl, f, steps, r,
142                 oe.proc, oe.ctx, ie.proc, ie.ctx, &nf, &v))
143     PGENERR;
144   vec = PyList_New(nf);
145   for (i = 0; i < nf; i++)
146     PyList_SetItem(vec, i, mp_pywrap(v[i]));
147   xfree(v);
148   rc = Py_BuildValue("(NN)", fginfo_pywrap(&dp, dhinfo_pytype), vec);
149 end:
150   droppgev(&oe); droppgev(&ie);
151   return (rc);
152 }
153
154 static PyObject *meth__DHInfo_gendsa(PyObject *me,
155                                      PyObject *arg, PyObject *kw)
156 {
157   dsa_param dp;
158   unsigned ql, pl;
159   unsigned steps = 0;
160   dsa_seed ds;
161   char *k;
162   int ksz;
163   pgev evt = { 0 };
164   char *kwlist[] =
165     { "class", "pbits", "qbits", "seed", "event", "nsteps", 0 };
166   PyObject *rc = 0;
167
168   if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO&O&s#|O&O&:gendsa", kwlist,
169                                    &me, convuint, &pl, convuint, &ql,
170                                    &k, &ksz, convpgev, &evt,
171                                    convuint, &steps))
172     goto end;
173   if (dsa_gen(&dp, ql, pl, steps, k, ksz, &ds, evt.proc, evt.ctx))
174     PGENERR;
175   rc = Py_BuildValue("(NNl)", fginfo_pywrap(&dp, dhinfo_pytype),
176                      bytestring_pywrap(ds.p, ds.sz), (long)ds.count);
177   xfree(ds.p);
178 end:
179   droppgev(&evt);
180   return (rc);
181 }
182
183 static int npgroups = -1, nbingroups = -1;
184
185 static PyObject *namedgroups(const pentry *pp, int *ne)
186 {
187   int i, j;
188   const char *p;
189   PyObject *d, *c;
190
191   d = PyDict_New();
192   for (i = 0; pp[i].name; i++) {
193     p = pp[i].name;
194     for (j = 0; j < i; j++) {
195       if (pp[i].data == pp[j].data) {
196         c = PyDict_GetItemString(d, (/*unconst*/ char *)pp[j].name);
197         Py_INCREF(c);
198         goto found;
199       }
200     }
201     c = PyInt_FromLong(i);
202   found:
203     PyDict_SetItemString(d, (/*unconst*/ char *)pp[i].name, c);
204     Py_DECREF(c);
205   }
206   *ne = i;
207   return (d);  
208 }
209
210 static PyObject *meth__groupn(PyObject *me, PyObject *arg,
211                               PyTypeObject *ty, const pentry *pp, int ne)
212 {
213   int i;
214   gprime_param gp;
215   PyObject *rc = 0;
216
217   if (!PyArg_ParseTuple(arg, "Oi:_groupn", &me, &i)) goto end;
218   if (i < 0 || i >= ne) VALERR("group index out of range");
219   dh_infofromdata(&gp, pp[i].data);
220   rc = fginfo_pywrap(&gp, ty);
221 end:
222   return (rc);
223 }
224
225 static PyObject *meth__DHInfo__groupn(PyObject *me, PyObject *arg)
226   { return (meth__groupn(me, arg, dhinfo_pytype, ptab, npgroups)); }
227
228 static PyObject *meth__BinDHInfo__groupn(PyObject *me, PyObject *arg)
229   { return (meth__groupn(me, arg, bindhinfo_pytype, bintab, nbingroups)); }
230
231 static PyObject *meth__parse(PyObject *me, PyObject *arg, PyTypeObject *ty,
232                              int (*parse)(qd_parse *, gprime_param *))
233 {
234   qd_parse qd;
235   char *p;
236   gprime_param gp;
237   PyObject *rc = 0;
238
239   if (!PyArg_ParseTuple(arg, "Os:parse", &me, &p)) goto end;
240   qd.p = p;
241   qd.e = 0;
242   if (parse(&qd, &gp)) SYNERR(qd.e);
243   rc = fginfo_pywrap(&gp, ty);
244 end:
245   return (rc);  
246 }
247
248 static PyObject *meth__DHInfo_parse(PyObject *me, PyObject *arg)
249   { return (meth__parse(me, arg, dhinfo_pytype, dh_parse)); }
250
251 static PyObject *meth__BinDHInfo_parse(PyObject *me, PyObject *arg)
252   { return (meth__parse(me, arg, bindhinfo_pytype, dhbin_parse)); }
253
254 static PyGetSetDef fginfo_pygetset[] = {
255 #define GETSETNAME(op, name) fi##op##_##name
256   GET   (r,                     "I.r -> group order")
257 #undef GETSETNAME
258   { 0 }
259 };
260
261 static PyGetSetDef dhinfo_pygetset[] = {
262 #define GETSETNAME(op, name) di##op##_##name
263   GET   (p,                     "I.p -> prime")
264   GET   (g,                     "I.g -> generator")
265 #undef GETSETNAME
266   { 0 }
267 };
268
269 static PyGetSetDef bindhinfo_pygetset[] = {
270 #define GETSETNAME(op, name) bi##op##_##name
271   GET   (p,                     "I.p -> irreducible polynomial")
272   GET   (m,                     "I.m -> degree of polynomial")
273   GET   (g,                     "I.g -> generator")
274 #undef GETSETNAME
275   { 0 }
276 };
277
278 static PyTypeObject fginfo_pytype_skel = {
279   PyObject_HEAD_INIT(0) 0,              /* Header */
280   "catacomb.FGInfo",                    /* @tp_name@ */
281   sizeof(fginfo_pyobj),                 /* @tp_basicsize@ */
282   0,                                    /* @tp_itemsize@ */
283
284   fginfo_pydealloc,                     /* @tp_dealloc@ */
285   0,                                    /* @tp_print@ */
286   0,                                    /* @tp_getattr@ */
287   0,                                    /* @tp_setattr@ */
288   0,                                    /* @tp_compare@ */
289   0,                                    /* @tp_repr@ */
290   0,                                    /* @tp_as_number@ */
291   0,                                    /* @tp_as_sequence@ */
292   0,                                    /* @tp_as_mapping@ */
293   0,                                    /* @tp_hash@ */
294   0,                                    /* @tp_call@ */
295   0,                                    /* @tp_str@ */
296   0,                                    /* @tp_getattro@ */
297   0,                                    /* @tp_setattro@ */
298   0,                                    /* @tp_as_buffer@ */
299   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
300     Py_TPFLAGS_BASETYPE,
301
302   /* @tp_doc@ */
303   "Abstract base class for field-group information objects.",
304
305   0,                                    /* @tp_traverse@ */
306   0,                                    /* @tp_clear@ */
307   0,                                    /* @tp_richcompare@ */
308   0,                                    /* @tp_weaklistoffset@ */
309   0,                                    /* @tp_iter@ */
310   0,                                    /* @tp_iternext@ */
311   0,                                    /* @tp_methods@ */
312   0,                                    /* @tp_members@ */
313   fginfo_pygetset,                      /* @tp_getset@ */
314   0,                                    /* @tp_base@ */
315   0,                                    /* @tp_dict@ */
316   0,                                    /* @tp_descr_get@ */
317   0,                                    /* @tp_descr_set@ */
318   0,                                    /* @tp_dictoffset@ */
319   0,                                    /* @tp_init@ */
320   PyType_GenericAlloc,                  /* @tp_alloc@ */
321   abstract_pynew,                       /* @tp_new@ */
322   0,                                    /* @tp_free@ */
323   0                                     /* @tp_is_gc@ */
324 };
325
326 static PyTypeObject dhinfo_pytype_skel = {
327   PyObject_HEAD_INIT(0) 0,              /* Header */
328   "catacomb.DHInfo",                    /* @tp_name@ */
329   sizeof(fginfo_pyobj),                 /* @tp_basicsize@ */
330   0,                                    /* @tp_itemsize@ */
331
332   fginfo_pydealloc,                     /* @tp_dealloc@ */
333   0,                                    /* @tp_print@ */
334   0,                                    /* @tp_getattr@ */
335   0,                                    /* @tp_setattr@ */
336   0,                                    /* @tp_compare@ */
337   0,                                    /* @tp_repr@ */
338   0,                                    /* @tp_as_number@ */
339   0,                                    /* @tp_as_sequence@ */
340   0,                                    /* @tp_as_mapping@ */
341   0,                                    /* @tp_hash@ */
342   0,                                    /* @tp_call@ */
343   0,                                    /* @tp_str@ */
344   0,                                    /* @tp_getattro@ */
345   0,                                    /* @tp_setattro@ */
346   0,                                    /* @tp_as_buffer@ */
347   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
348     Py_TPFLAGS_BASETYPE,
349
350   /* @tp_doc@ */
351   "Standard (integer) Diffie-Hellman group information.",
352
353   0,                                    /* @tp_traverse@ */
354   0,                                    /* @tp_clear@ */
355   0,                                    /* @tp_richcompare@ */
356   0,                                    /* @tp_weaklistoffset@ */
357   0,                                    /* @tp_iter@ */
358   0,                                    /* @tp_iternext@ */
359   0,                                    /* @tp_methods@ */
360   0,                                    /* @tp_members@ */
361   dhinfo_pygetset,                      /* @tp_getset@ */
362   0,                                    /* @tp_base@ */
363   0,                                    /* @tp_dict@ */
364   0,                                    /* @tp_descr_get@ */
365   0,                                    /* @tp_descr_set@ */
366   0,                                    /* @tp_dictoffset@ */
367   0,                                    /* @tp_init@ */
368   PyType_GenericAlloc,                  /* @tp_alloc@ */
369   fginfo_pynew,                         /* @tp_new@ */
370   0,                                    /* @tp_free@ */
371   0                                     /* @tp_is_gc@ */
372 };
373
374 static PyTypeObject bindhinfo_pytype_skel = {
375   PyObject_HEAD_INIT(0) 0,              /* Header */
376   "catacomb.BinDHInfo",                 /* @tp_name@ */
377   sizeof(fginfo_pyobj),                 /* @tp_basicsize@ */
378   0,                                    /* @tp_itemsize@ */
379
380   fginfo_pydealloc,                     /* @tp_dealloc@ */
381   0,                                    /* @tp_print@ */
382   0,                                    /* @tp_getattr@ */
383   0,                                    /* @tp_setattr@ */
384   0,                                    /* @tp_compare@ */
385   0,                                    /* @tp_repr@ */
386   0,                                    /* @tp_as_number@ */
387   0,                                    /* @tp_as_sequence@ */
388   0,                                    /* @tp_as_mapping@ */
389   0,                                    /* @tp_hash@ */
390   0,                                    /* @tp_call@ */
391   0,                                    /* @tp_str@ */
392   0,                                    /* @tp_getattro@ */
393   0,                                    /* @tp_setattro@ */
394   0,                                    /* @tp_as_buffer@ */
395   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
396     Py_TPFLAGS_BASETYPE,
397
398   /* @tp_doc@ */
399   "Binary-field Diffie-Hellman group information.",
400
401   0,                                    /* @tp_traverse@ */
402   0,                                    /* @tp_clear@ */
403   0,                                    /* @tp_richcompare@ */
404   0,                                    /* @tp_weaklistoffset@ */
405   0,                                    /* @tp_iter@ */
406   0,                                    /* @tp_iternext@ */
407   0,                                    /* @tp_methods@ */
408   0,                                    /* @tp_members@ */
409   bindhinfo_pygetset,                   /* @tp_getset@ */
410   0,                                    /* @tp_base@ */
411   0,                                    /* @tp_dict@ */
412   0,                                    /* @tp_descr_get@ */
413   0,                                    /* @tp_descr_set@ */
414   0,                                    /* @tp_dictoffset@ */
415   0,                                    /* @tp_init@ */
416   PyType_GenericAlloc,                  /* @tp_alloc@ */
417   fginfo_pynew,                         /* @tp_new@ */
418   0,                                    /* @tp_free@ */
419   0                                     /* @tp_is_gc@ */
420 };
421
422 /*----- General utilities -------------------------------------------------*/
423
424 PyTypeObject *ge_pytype, *group_pytype;
425 PyTypeObject *primegroup_pytype, *bingroup_pytype, *ecgroup_pytype;
426
427 group *group_copy(group *g)
428 {
429   if (strcmp(G_NAME(g), "prime") == 0) {
430     gctx_prime *gc = (gctx_prime *)g;
431     gprime_param gp;
432     gp.g = G_TOINT(g, MP_NEW, g->g);
433     gp.p = gc->mm.m;
434     gp.q = gc->g.r;
435     g = group_prime(&gp);
436     MP_DROP(gp.g);
437   } else if (strcmp(G_NAME(g), "bin") == 0) {
438     gctx_bin *gc = (gctx_bin *)g;
439     gbin_param gb;
440     gb.g = G_TOINT(g, MP_NEW, g->g);
441     gb.p = gc->r.p;
442     gb.q = gc->g.r;
443     g = group_binary(&gb);
444     MP_DROP(gb.g);    
445   } else if (strcmp(G_NAME(g), "ec") == 0) {
446     gctx_ec *gc = (gctx_ec *)g;
447     ec_info ei;
448     if ((ei.c = eccurve_copy(gc->ei.c)) == 0)
449       return (0);
450     EC_CREATE(&ei.g);
451     EC_COPY(&ei.g, &gc->ei.g);
452     ei.r = MP_COPY(gc->ei.r);
453     ei.h = MP_COPY(gc->ei.h);
454     g = group_ec(&ei);
455   } else
456     g = 0;
457   return (g);
458 }
459
460 PyObject *ge_pywrap(PyObject *gobj, ge *x)
461 {
462   ge_pyobj *z = PyObject_New(ge_pyobj, (PyTypeObject *)gobj);
463   z->x = x;
464   z->g = GROUP_G(gobj);
465   Py_INCREF(gobj);
466   return ((PyObject *)z);
467 }
468
469 static PyObject *ge_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
470 {
471   char *kwlist[] = { "x", 0 };
472   PyObject *x;
473   group *g;
474   ec p = EC_INIT;
475   mp *y = 0;
476   ge *xx = 0;
477   mptext_stringctx sc;
478
479   g = GROUP_G(ty);
480   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O:new", kwlist, &x)) goto end;
481   xx = G_CREATE(g);
482   if (ECPT_PYCHECK(x)) {
483     getecptout(&p, x);
484     if (G_FROMEC(g, xx, &p))
485       TYERR("can't convert from elliptic curve point");
486     EC_DESTROY(&p);
487   } else if ((y = tomp(x)) != 0) {
488     if (G_FROMINT(g, xx, y))
489       TYERR("can't convert from integer");
490     MP_DROP(y);
491   } else if (PyString_Check(x)) {
492     sc.buf = PyString_AS_STRING(x);
493     sc.lim = sc.buf + PyString_GET_SIZE(x);
494     if (G_READ(g, xx, &mptext_stringops, &sc) || sc.buf < sc.lim)
495       SYNERR("malformed group element string");
496   } else
497     TYERR("can't convert to group element");
498   return (ge_pywrap((PyObject *)ty, xx));
499 end:
500   mp_drop(y);
501   EC_DESTROY(&p);
502   if (xx) G_DESTROY(g, xx);
503   return (0);
504 }
505
506 static PyObject *group_dopywrap(PyTypeObject *ty, group *g)
507 {
508   group_pyobj *gobj = newtype(ty, 0, g->ops->name);
509   gobj->g = g;
510   gobj->ty.type.tp_basicsize = sizeof(ge_pyobj);
511   gobj->ty.type.tp_base = ge_pytype;
512   Py_INCREF(group_pytype);
513   gobj->ty.type.tp_flags = (Py_TPFLAGS_DEFAULT |
514                             Py_TPFLAGS_BASETYPE |
515                             Py_TPFLAGS_CHECKTYPES |
516                             Py_TPFLAGS_HEAPTYPE);
517   gobj->ty.type.tp_alloc = PyType_GenericAlloc;
518   gobj->ty.type.tp_free = 0;
519   gobj->ty.type.tp_new = ge_pynew;
520   PyType_Ready(&gobj->ty.type);
521   return ((PyObject *)gobj);
522 }
523
524 PyObject *group_pywrap(group *g)
525 {
526   PyTypeObject *ty;
527
528   if (strcmp(G_NAME(g), "prime") == 0) ty = primegroup_pytype;
529   else if (strcmp(G_NAME(g), "bin") == 0) ty = bingroup_pytype;
530   else if (strcmp(G_NAME(g), "ec") == 0) ty = ecgroup_pytype;
531   else abort();
532   return (group_dopywrap(ty, g));
533 }
534
535 /*----- Group elements ----------------------------------------------------*/
536
537 #define BINOP(name)                                                     \
538   static PyObject *ge_py##name(PyObject *x, PyObject *y)                \
539   {                                                                     \
540     ge *z;                                                              \
541     group *g;                                                           \
542     if (!GE_PYCHECK(x) || !GE_PYCHECK(y) ||                             \
543         (GE_G(x) != GE_G(y) && !group_samep(GE_G(x), GE_G(y))))         \
544       RETURN_NOTIMPL;                                                   \
545     g = GE_G(x);                                                        \
546     z = G_CREATE(g);                                                    \
547     g->ops->name(g, z, GE_X(x), GE_X(y));                               \
548     return (ge_pywrap(GE_GOBJ(x), z));                                  \
549   }
550 BINOP(mul)
551 BINOP(div)
552 #undef BINOP
553
554 #define UNOP(name)                                                      \
555   static PyObject *gemeth_##name(PyObject *me, PyObject *arg)           \
556   {                                                                     \
557     group *g;                                                           \
558     ge *z;                                                              \
559     if (!PyArg_ParseTuple(arg, ":" #name)) return (0);                  \
560     g = GE_G(me);                                                       \
561     z = G_CREATE(g);                                                    \
562     g->ops->name(g, z, GE_X(me));                                       \
563     return (ge_pywrap(GE_GOBJ(me), z));                                 \
564   }
565 UNOP(sqr)
566 UNOP(inv)
567 #undef UNOP
568
569 static PyObject *ge_pyexp(PyObject *x, PyObject *n, PyObject *m)
570 {
571   mp *nn;
572   ge *z;
573
574   if (m != Py_None || !GE_PYCHECK(x) || (nn = getmp(n)) == 0)
575     RETURN_NOTIMPL;
576   z = G_CREATE(GE_G(x));
577   G_EXP(GE_G(x), z, GE_X(x), nn);
578   MP_DROP(nn);
579   return (ge_pywrap(GE_GOBJ(x), z));
580 }
581
582 static void ge_pydealloc(PyObject *me)
583 {
584   G_DESTROY(GE_G(me), GE_X(me));
585   Py_DECREF(GE_GOBJ(me));
586   FREEOBJ(me);
587 }
588
589 static void group_pydealloc(PyObject *me)
590 {
591   G_DESTROYGROUP(GROUP_G(me));
592   PyType_Type.tp_dealloc(me);
593 }
594
595 static PyObject *gmexp_id(PyObject *me)
596 {
597   group *g = GROUP_G(me); ge *x = G_CREATE(g);
598   G_COPY(g, x, g->i); return (ge_pywrap(me, x));
599 }
600
601 static int gmexp_fill(void *pp, PyObject  *me, PyObject *x, PyObject *m)
602 {
603   group_expfactor *f = pp;
604
605   if (!GE_PYCHECK(x) || GE_G(x) != GROUP_G(me) || (f->exp = getmp(m)) == 0)
606     return (-1);
607   f->base = GE_X(x);
608   return (0);
609 }
610
611 static PyObject *ge_pyrichcompare(PyObject *x, PyObject *y, int op)
612 {
613   int b;
614   PyObject *rc = 0;
615
616   if (!GE_PYCHECK(x) || !GE_PYCHECK(y) ||
617       (GE_G(x) != GE_G(y) && !group_samep(GE_G(x), GE_G(y))))
618     RETURN_NOTIMPL;
619   switch (op) {
620     case Py_EQ: b = G_EQ(GE_G(x), GE_X(x), GE_X(y)); break;
621     case Py_NE: b = !G_EQ(GE_G(x), GE_X(x), GE_X(y)); break;
622     default: TYERR("group elements are unordered");
623   }
624   rc = getbool(b);
625 end:
626   return (rc);
627 }
628
629 static PyObject *gemeth_check(PyObject *me, PyObject *arg)
630 {
631   if (!PyArg_ParseTuple(arg, ":check")) goto end;
632   if (group_check(GE_G(me), GE_X(me))) VALERR("bad group element");
633   RETURN_OBJ(me);
634 end:
635   return (0);
636 }
637
638 static int ge_pynonzerop(PyObject *x)
639   { return (!G_IDENTP(GE_G(x), GE_X(x))); }
640
641 static PyObject *ge_pystr(PyObject *me)
642 {
643   dstr d = DSTR_INIT;
644   PyObject *rc;
645
646   group_writedstr(GE_G(me), GE_X(me), &d);
647   rc = PyString_FromStringAndSize(d.buf, d.len);
648   DDESTROY(&d);
649   return (rc);
650 }
651
652 static PyObject *ge_pylong(PyObject *me)
653 {
654   mp *x = 0;
655   PyObject *rc = 0;
656
657   if ((x = G_TOINT(GE_G(me), MP_NEW, GE_X(me))) == 0)
658     TYERR("can't convert to integer");
659   rc = mp_topylong(x);
660 end:
661   mp_drop(x);
662   return (rc);
663 }
664
665 static PyObject *ge_pyint(PyObject *me)
666 {
667   mp *x = 0;
668   PyObject *rc = 0;
669   long l;
670
671   if ((x = G_TOINT(GE_G(me), MP_NEW, GE_X(me))) == 0)
672     TYERR("can't convert to integer");
673   if (mp_tolong_checked(x, &l)) goto end;
674   rc = PyInt_FromLong(l);
675 end:
676   mp_drop(x);
677   return (rc);
678 }
679
680 static PyObject *gemeth_toint(PyObject *me, PyObject *arg)
681 {
682   mp *x;
683
684   if (!PyArg_ParseTuple(arg, ":toint")) goto end;
685   if ((x = G_TOINT(GE_G(me), MP_NEW, GE_X(me))) == 0)
686     TYERR("can't convert to integer");
687   return (mp_pywrap(x));
688 end:
689   return (0);
690 }
691
692 static PyObject *gemeth_toec(PyObject *me, PyObject *arg, PyObject *kw)
693 {
694   char *kwlist[] = { "curve", 0 };
695   PyTypeObject *cty = ecpt_pytype;
696   ec p = EC_INIT;
697
698   if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O:toec", kwlist,
699                                    &cty)) goto end;
700   if (!PyType_Check(cty) || !PyType_IsSubtype(cty, ecpt_pytype))
701     TYERR("want subtype of catacomb.ECPt");
702   if (G_TOEC(GE_G(me), &p, GE_X(me)))
703     TYERR("can't convert to ec point");
704   return (ecpt_pywrapout(cty, &p));
705 end:
706   return (0);
707 }
708
709 static PyObject *gemeth_tobuf(PyObject *me, PyObject *arg)
710 {
711   buf b;
712   PyObject *rc;
713   size_t n;
714
715   if (!PyArg_ParseTuple(arg, ":tobuf")) return (0);
716   n = GE_G(me)->noctets + 4;
717   rc = bytestring_pywrap(0, n);
718   buf_init(&b, PyString_AS_STRING(rc), n);
719   G_TOBUF(GE_G(me), &b, GE_X(me));
720   assert(BOK(&b));
721   _PyString_Resize(&rc, BLEN(&b));
722   return (rc);
723 }
724
725 static PyObject *gemeth_toraw(PyObject *me, PyObject *arg)
726 {
727   buf b;
728   PyObject *rc;
729   size_t n;
730
731   if (!PyArg_ParseTuple(arg, ":toraw")) return (0);
732   n = GE_G(me)->noctets;
733   rc = bytestring_pywrap(0, n);
734   buf_init(&b, PyString_AS_STRING(rc), n);
735   G_TORAW(GE_G(me), &b, GE_X(me));
736   assert(BOK(&b));
737   _PyString_Resize(&rc, BLEN(&b));
738   return (rc);
739 }
740
741 static PyObject *gmexp_exp(PyObject *me, void *pp, int n)
742 {
743   ge *z = G_CREATE(GROUP_G(me));
744   G_MEXP(GROUP_G(me), z, pp, n);
745   return (ge_pywrap(me, z));
746 }
747
748 static void gmexp_drop(void *pp)
749 {
750   group_expfactor *f = pp;
751   MP_DROP(f->exp);
752 }
753
754 static PyObject *gmeth_mexp(PyObject *me, PyObject *arg)
755 {
756   return (mexp_common(me, arg, sizeof(group_expfactor),
757                       gmexp_id, gmexp_fill, gmexp_exp, gmexp_drop));
758 }
759
760 static PyObject *gmeth_check(PyObject *me, PyObject *arg, PyObject *kw)
761 {
762   char *kwlist[] = { "rng", 0 };
763   grand *r = &rand_global;
764   const char *p;
765
766   if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:check", kwlist,
767                                    convgrand, &r))
768     goto end;
769   if ((p = G_CHECK(GROUP_G(me), r)) != 0)
770     VALERR(p);
771   RETURN_OBJ(me);
772 end:
773   return (0);
774 }
775
776 static PyObject *group_pyrichcompare(PyObject *x, PyObject *y, int op)
777 {
778   int b = group_samep(GROUP_G(x), GROUP_G(y));
779   switch (op) {
780     case Py_EQ: break;
781     case Py_NE: b = !b;
782     default: TYERR("can't order groups");
783   }
784   return (getbool(b));
785 end:
786   return (0);
787 }
788
789 static PyObject *meth__GE_frombuf(PyObject *me, PyObject *arg)
790 {
791   buf b;
792   char *p;
793   int n;
794   group *g;
795   ge *x = 0;
796
797   if (!PyArg_ParseTuple(arg, "Os#:frombuf", &me, &p, &n))
798     return (0);
799   g = GROUP_G(me);
800   buf_init(&b, p, n);
801   x = G_CREATE(g);
802   if (G_FROMBUF(g, &b, x))
803     VALERR("invalid data");
804   return (Py_BuildValue("(NN)", ge_pywrap(me, x), bytestring_pywrapbuf(&b)));
805 end:
806   if (x) G_DESTROY(g, x);
807   return (0);
808 }
809
810 static PyObject *meth__GE_fromraw(PyObject *me, PyObject *arg)
811 {
812   buf b;
813   char *p;
814   int n;
815   group *g;
816   ge *x = 0;
817
818   if (!PyArg_ParseTuple(arg, "Os#:fromraw", &me, &p, &n))
819     return (0);
820   g = GROUP_G(me);
821   buf_init(&b, p, n);
822   x = G_CREATE(g);
823   if (G_FROMRAW(g, &b, x))
824     VALERR("invalid data");
825   return (Py_BuildValue("(NN)", ge_pywrap(me, x), bytestring_pywrapbuf(&b)));
826 end:
827   if (x) G_DESTROY(g, x);
828   return (0);
829 }
830
831 static PyObject *meth__GE_fromstring(PyObject *me, PyObject *arg)
832 {
833   mptext_stringctx sc;
834   char *p;
835   int n;
836   group *g;
837   ge *x = 0;
838
839   if (!PyArg_ParseTuple(arg, "Os#:fromstring", &me, &p, &n))
840     return (0);
841   sc.buf = p;
842   sc.lim = sc.buf + n;
843   g = GROUP_G(me);
844   x = G_CREATE(g);
845   if (G_READ(g, x, &mptext_stringops, &sc))
846     SYNERR("bad group element string");
847   return (Py_BuildValue("(Ns#)", ge_pywrap(me, x),
848                         sc.buf, (int)(sc.lim - sc.buf)));
849 end:
850   if (x) G_DESTROY(g, x);
851   return (0);
852 }
853
854 static PyObject *meth__Group_parse(PyObject *me, PyObject *arg)
855 {
856   char *p;
857   qd_parse qd;
858   group *g;
859
860   if (!PyArg_ParseTuple(arg, "Os:parse", &me, &p))
861     goto end;
862   qd.p = p;
863   qd.e = 0;
864   if ((g = group_parse(&qd)) == 0)
865     SYNERR(qd.e);
866   return (group_pywrap(g));
867 end:
868   return (0);
869 }
870
871 static PyObject *geget_group(PyObject *me, void *hunoz)
872   { RETURN_OBJ(GE_GOBJ(me)); }
873
874 static PyObject *gget_nbits(PyObject *me, void *hunoz)
875   { return (PyInt_FromLong(GROUP_G(me)->nbits)); }
876
877 static PyObject *gget_noctets(PyObject *me, void *hunoz)
878   { return (PyInt_FromLong(GROUP_G(me)->noctets)); }
879
880 static PyObject *gget_i(PyObject *me, void *hunoz)
881 {
882   group *g = GROUP_G(me); ge *x = G_CREATE(g);
883   G_COPY(g, x, g->i); return (ge_pywrap(me, x));
884 }
885
886 static PyObject *gget_g(PyObject *me, void *hunoz)
887 {
888   group *g = GROUP_G(me); ge *x = G_CREATE(g);
889   G_COPY(g, x, g->g); return (ge_pywrap(me, x));
890 }
891
892 static PyObject *gget_r(PyObject *me, void *hunoz)
893   { return (mp_pywrap(MP_COPY(GROUP_G(me)->r))); }
894
895 static PyObject *gget_h(PyObject *me, void *hunoz)
896   { return (mp_pywrap(MP_COPY(GROUP_G(me)->h))); }
897
898 static PyGetSetDef ge_pygetset[] = {
899 #define GETSETNAME(op, name) ge##op##_##name
900   GET   (group,         "X.group -> group containing X")
901 #undef GETSETNAME
902   { 0 }
903 };
904
905 static PyMethodDef ge_pymethods[] = {
906 #define METHNAME(name) gemeth_##name
907   METH  (inv,           "X.inv() -> inverse element of X")
908   METH  (sqr,           "X.sqr() -> X^2 = X * X")
909   METH  (check,         "X.check() -> check X really belongs to its group")
910   METH  (toint,         "X.toint() -> X converted to an integer")
911   KWMETH(toec,          "\
912 X.toec(curve = ecpt) -> X converted to elliptic curve point")
913   METH  (tobuf,         "X.tobuf() -> X in buffer representation")
914   METH  (toraw,         "X.toraw() -> X in raw representation")
915 #undef METHNAME
916   { 0 }
917 };
918
919 static PyNumberMethods ge_pynumber = {
920   0,                                    /* @nb_add@ */
921   0,                                    /* @nb_subtract@ */
922   ge_pymul,                             /* @nb_multiply@ */
923   ge_pydiv,                             /* @nb_divide@ */
924   0,                                    /* @nb_remainder@ */
925   0,                                    /* @nb_divmod@ */
926   ge_pyexp,                             /* @nb_power@ */
927   0,                                    /* @nb_negative@ */
928   0,                                    /* @nb_positive@ */
929   0,                                    /* @nb_absolute@ */
930   ge_pynonzerop,                        /* @nb_nonzero@ */
931   0,                                    /* @nb_invert@ */
932   0,                                    /* @nb_lshift@ */
933   0,                                    /* @nb_rshift@ */
934   0,                                    /* @nb_and@ */
935   0,                                    /* @nb_xor@ */
936   0,                                    /* @nb_or@ */
937   0,                                    /* @nb_coerce@ */
938   ge_pyint,                             /* @nb_int@ */
939   ge_pylong,                            /* @nb_long@ */
940   0 /* meaningless */,                  /* @nb_float@ */
941   0,                                    /* @nb_oct@ */
942   0,                                    /* @nb_hex@ */
943
944   0,                                    /* @nb_inplace_add@ */
945   0,                                    /* @nb_inplace_subtract@ */
946   0,                                    /* @nb_inplace_multiply@ */
947   0,                                    /* @nb_inplace_divide@ */
948   0,                                    /* @nb_inplace_remainder@ */
949   0,                                    /* @nb_inplace_power@ */
950   0,                                    /* @nb_inplace_lshift@ */
951   0,                                    /* @nb_inplace_rshift@ */
952   0,                                    /* @nb_inplace_and@ */
953   0,                                    /* @nb_inplace_xor@ */
954   0,                                    /* @nb_inplace_or@ */
955
956   0,                                    /* @nb_floor_divide@ */
957   ge_pydiv,                             /* @nb_true_divide@ */
958   0,                                    /* @nb_inplace_floor_divide@ */
959   0,                                    /* @nb_inplace_true_divide@ */
960 };
961
962 static PyTypeObject ge_pytype_skel = {
963   PyObject_HEAD_INIT(0) 0,              /* Header */
964   "catacomb.GE",                        /* @tp_name@ */
965   sizeof(ge_pyobj),                     /* @tp_basicsize@ */
966   0,                                    /* @tp_itemsize@ */
967
968   ge_pydealloc,                         /* @tp_dealloc@ */
969   0,                                    /* @tp_print@ */
970   0,                                    /* @tp_getattr@ */
971   0,                                    /* @tp_setattr@ */
972   0,                                    /* @tp_compare@ */
973   0,                                    /* @tp_repr@ */
974   &ge_pynumber,                         /* @tp_as_number@ */
975   0,                                    /* @tp_as_sequence@ */
976   0,                                    /* @tp_as_mapping@ */
977   0,                                    /* @tp_hash@ */
978   0,                                    /* @tp_call@ */
979   ge_pystr,                             /* @tp_str@ */
980   0,                                    /* @tp_getattro@ */
981   0,                                    /* @tp_setattro@ */
982   0,                                    /* @tp_as_buffer@ */
983   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
984     Py_TPFLAGS_CHECKTYPES |
985     Py_TPFLAGS_BASETYPE,
986
987   /* @tp_doc@ */
988 "Group elements, abstract base class.",
989
990   0,                                    /* @tp_traverse@ */
991   0,                                    /* @tp_clear@ */
992   ge_pyrichcompare,                     /* @tp_richcompare@ */
993   0,                                    /* @tp_weaklistoffset@ */
994   0,                                    /* @tp_iter@ */
995   0,                                    /* @tp_iternext@ */
996   ge_pymethods,                         /* @tp_methods@ */
997   0,                                    /* @tp_members@ */
998   ge_pygetset,                          /* @tp_getset@ */
999   0,                                    /* @tp_base@ */
1000   0,                                    /* @tp_dict@ */
1001   0,                                    /* @tp_descr_get@ */
1002   0,                                    /* @tp_descr_set@ */
1003   0,                                    /* @tp_dictoffset@ */
1004   0,                                    /* @tp_init@ */
1005   PyType_GenericAlloc,                  /* @tp_alloc@ */
1006   abstract_pynew,                       /* @tp_new@ */
1007   0,                                    /* @tp_free@ */
1008   0                                     /* @tp_is_gc@ */
1009 };
1010
1011 static PyGetSetDef group_pygetset[] = {
1012 #define GETSETNAME(op, name) g##op##_##name
1013   GET   (noctets,       "G.noctets -> size in octets of element")
1014   GET   (nbits,         "G.nbits -> size in bits of element")
1015   GET   (i,             "G.i -> group identity")
1016   GET   (g,             "G.g -> group generator")
1017   GET   (r,             "G.r -> group order")
1018   GET   (h,             "G.h -> group cofactor")
1019 #undef GETSETNAME
1020   { 0 }
1021 };
1022
1023 static PyMethodDef group_pymethods[] = {
1024 #define METHNAME(name) gmeth_##name
1025   METH  (mexp,          "\
1026 G.mexp([(X0, N0), (X1, N1), ...]) -> X0^N0 X1^N1 ...")
1027   KWMETH(check,         "G.check(rand = random): check group is good")
1028 #undef METHNAME
1029   { 0 }
1030 };
1031
1032 static PyTypeObject group_pytype_skel = {
1033   PyObject_HEAD_INIT(0) 0,              /* Header */
1034   "catacomb.Group",                     /* @tp_name@ */
1035   sizeof(group_pyobj),                  /* @tp_basicsize@ */
1036   0,                                    /* @tp_itemsize@ */
1037
1038   group_pydealloc,                      /* @tp_dealloc@ */
1039   0,                                    /* @tp_print@ */
1040   0,                                    /* @tp_getattr@ */
1041   0,                                    /* @tp_setattr@ */
1042   0,                                    /* @tp_compare@ */
1043   0,                                    /* @tp_repr@ */
1044   0,                                    /* @tp_as_number@ */
1045   0,                                    /* @tp_as_sequence@ */
1046   0,                                    /* @tp_as_mapping@ */
1047   0,                                    /* @tp_hash@ */
1048   0,                                    /* @tp_call@ */
1049   0,                                    /* @tp_str@ */
1050   0,                                    /* @tp_getattro@ */
1051   0,                                    /* @tp_setattro@ */
1052   0,                                    /* @tp_as_buffer@ */
1053   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
1054     Py_TPFLAGS_BASETYPE,
1055
1056   /* @tp_doc@ */
1057 "Abstract base class for groups.",
1058
1059   0,                                    /* @tp_traverse@ */
1060   0,                                    /* @tp_clear@ */
1061   group_pyrichcompare,                  /* @tp_richcompare@ */
1062   0,                                    /* @tp_weaklistoffset@ */
1063   0,                                    /* @tp_iter@ */
1064   0,                                    /* @tp_iternext@ */
1065   group_pymethods,                      /* @tp_methods@ */
1066   0,                                    /* @tp_members@ */
1067   group_pygetset,                       /* @tp_getset@ */
1068   0,                                    /* @tp_base@ */
1069   0,                                    /* @tp_dict@ */
1070   0,                                    /* @tp_descr_get@ */
1071   0,                                    /* @tp_descr_set@ */
1072   0,                                    /* @tp_dictoffset@ */
1073   0,                                    /* @tp_init@ */
1074   PyType_GenericAlloc,                  /* @tp_alloc@ */
1075   abstract_pynew,                       /* @tp_new@ */
1076   0,                                    /* @tp_free@ */
1077   0                                     /* @tp_is_gc@ */
1078 };
1079
1080 static PyObject *pgget_info(PyObject *me, void *hunoz)
1081 {
1082   gprime_param dp;
1083   gctx_prime *gg = (gctx_prime *)GROUP_G(me);
1084   dp.p = MP_COPY(gg->mm.m);
1085   dp.q = MP_COPY(gg->g.r);
1086   dp.g = mpmont_reduce(&gg->mm, MP_NEW, gg->gen);
1087   return (fginfo_pywrap(&dp, dhinfo_pytype));
1088 }
1089
1090 static PyGetSetDef primegroup_pygetset[] = {
1091 #define GETSETNAME(op, name) pg##op##_##name
1092   GET   (info,          "G.info -> information about the group")
1093 #undef GETSETNAME
1094   { 0 }
1095 };
1096
1097 static PyObject *primegroup_pynew(PyTypeObject *ty,
1098                                   PyObject *arg, PyObject *kw)
1099 {
1100   PyObject *i;
1101   char *kwlist[] = { "info", 0 };
1102
1103   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!:new", kwlist,
1104                                    dhinfo_pytype, &i))
1105     return (0);
1106   return (group_dopywrap(ty, group_prime(FGINFO_DP(i))));
1107 }
1108
1109 static PyTypeObject primegroup_pytype_skel = {
1110   PyObject_HEAD_INIT(0) 0,              /* Header */
1111   "catacomb.PrimeGroup",                /* @tp_name@ */
1112   sizeof(group_pyobj),                  /* @tp_basicsize@ */
1113   0,                                    /* @tp_itemsize@ */
1114
1115   group_pydealloc,                      /* @tp_dealloc@ */
1116   0,                                    /* @tp_print@ */
1117   0,                                    /* @tp_getattr@ */
1118   0,                                    /* @tp_setattr@ */
1119   0,                                    /* @tp_compare@ */
1120   0,                                    /* @tp_repr@ */
1121   0,                                    /* @tp_as_number@ */
1122   0,                                    /* @tp_as_sequence@ */
1123   0,                                    /* @tp_as_mapping@ */
1124   0,                                    /* @tp_hash@ */
1125   0,                                    /* @tp_call@ */
1126   0,                                    /* @tp_str@ */
1127   0,                                    /* @tp_getattro@ */
1128   0,                                    /* @tp_setattro@ */
1129   0,                                    /* @tp_as_buffer@ */
1130   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
1131     Py_TPFLAGS_BASETYPE,
1132
1133   /* @tp_doc@ */
1134 "Subgroups of prime fields.",
1135
1136   0,                                    /* @tp_traverse@ */
1137   0,                                    /* @tp_clear@ */
1138   0,                                    /* @tp_richcompare@ */
1139   0,                                    /* @tp_weaklistoffset@ */
1140   0,                                    /* @tp_iter@ */
1141   0,                                    /* @tp_iternext@ */
1142   0,                                    /* @tp_methods@ */
1143   0,                                    /* @tp_members@ */
1144   primegroup_pygetset,                  /* @tp_getset@ */
1145   0,                                    /* @tp_base@ */
1146   0,                                    /* @tp_dict@ */
1147   0,                                    /* @tp_descr_get@ */
1148   0,                                    /* @tp_descr_set@ */
1149   0,                                    /* @tp_dictoffset@ */
1150   0,                                    /* @tp_init@ */
1151   PyType_GenericAlloc,                  /* @tp_alloc@ */
1152   primegroup_pynew,                     /* @tp_new@ */
1153   0,                                    /* @tp_free@ */
1154   0                                     /* @tp_is_gc@ */
1155 };
1156
1157 static PyObject *bgget_info(PyObject *me, void *hunoz)
1158 {
1159   gbin_param dp;
1160   gctx_bin *gg = (gctx_bin *)GROUP_G(me);
1161   dp.p = MP_COPY(gg->r.p);
1162   dp.q = MP_COPY(gg->g.r);
1163   dp.g = MP_COPY(gg->gen);
1164   return (fginfo_pywrap(&dp, bindhinfo_pytype));
1165 }
1166
1167 static PyGetSetDef bingroup_pygetset[] = {
1168 #define GETSETNAME(op, name) bg##op##_##name
1169   GET   (info,          "G.info -> information about the group")
1170 #undef GETSETNAME
1171   { 0 }
1172 };
1173
1174 static PyObject *bingroup_pynew(PyTypeObject *ty,
1175                                 PyObject *arg, PyObject *kw)
1176 {
1177   PyObject *i;
1178   char *kwlist[] = { "info", 0 };
1179
1180   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!:new", kwlist,
1181                                    bindhinfo_pytype, &i))
1182     return (0);
1183   return (group_dopywrap(ty, group_binary(FGINFO_DP(i))));
1184 }
1185
1186 static PyTypeObject bingroup_pytype_skel = {
1187   PyObject_HEAD_INIT(0) 0,              /* Header */
1188   "catacomb.BinGroup",                  /* @tp_name@ */
1189   sizeof(group_pyobj),                  /* @tp_basicsize@ */
1190   0,                                    /* @tp_itemsize@ */
1191
1192   group_pydealloc,                      /* @tp_dealloc@ */
1193   0,                                    /* @tp_print@ */
1194   0,                                    /* @tp_getattr@ */
1195   0,                                    /* @tp_setattr@ */
1196   0,                                    /* @tp_compare@ */
1197   0,                                    /* @tp_repr@ */
1198   0,                                    /* @tp_as_number@ */
1199   0,                                    /* @tp_as_sequence@ */
1200   0,                                    /* @tp_as_mapping@ */
1201   0,                                    /* @tp_hash@ */
1202   0,                                    /* @tp_call@ */
1203   0,                                    /* @tp_str@ */
1204   0,                                    /* @tp_getattro@ */
1205   0,                                    /* @tp_setattro@ */
1206   0,                                    /* @tp_as_buffer@ */
1207   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
1208     Py_TPFLAGS_BASETYPE,
1209
1210   /* @tp_doc@ */
1211 "Subgroups of binary fields.",
1212
1213   0,                                    /* @tp_traverse@ */
1214   0,                                    /* @tp_clear@ */
1215   0,                                    /* @tp_richcompare@ */
1216   0,                                    /* @tp_weaklistoffset@ */
1217   0,                                    /* @tp_iter@ */
1218   0,                                    /* @tp_iternext@ */
1219   0,                                    /* @tp_methods@ */
1220   0,                                    /* @tp_members@ */
1221   bingroup_pygetset,                    /* @tp_getset@ */
1222   0,                                    /* @tp_base@ */
1223   0,                                    /* @tp_dict@ */
1224   0,                                    /* @tp_descr_get@ */
1225   0,                                    /* @tp_descr_set@ */
1226   0,                                    /* @tp_dictoffset@ */
1227   0,                                    /* @tp_init@ */
1228   PyType_GenericAlloc,                  /* @tp_alloc@ */
1229   bingroup_pynew,                       /* @tp_new@ */
1230   0,                                    /* @tp_free@ */
1231   0                                     /* @tp_is_gc@ */
1232 };
1233
1234 static PyObject *egget_info(PyObject *me, void *hunoz)
1235 {
1236   ec_info ei;
1237   gctx_ec *gg = (gctx_ec *)GROUP_G(me);
1238
1239   ecinfo_copy(&ei, &gg->ei);
1240   return (ecinfo_pywrap(&ei));
1241 }
1242
1243 static PyGetSetDef ecgroup_pygetset[] = {
1244 #define GETSETNAME(op, name) eg##op##_##name
1245   GET   (info,          "G.info -> information about the group")
1246 #undef GETSETNAME
1247   { 0 }
1248 };
1249
1250 static PyObject *ecgroup_pynew(PyTypeObject *ty,
1251                                PyObject *arg, PyObject *kw)
1252 {
1253   PyObject *i;
1254   ec_info ei;
1255   char *kwlist[] = { "info", 0 };
1256
1257   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!:new", kwlist,
1258                                    ecinfo_pytype, &i))
1259     return (0);
1260   ecinfo_copy(&ei, ECINFO_EI(i));
1261   return (group_dopywrap(ty, group_ec(&ei)));
1262 }
1263
1264 static PyTypeObject ecgroup_pytype_skel = {
1265   PyObject_HEAD_INIT(0) 0,              /* Header */
1266   "catacomb.ECGroup",                   /* @tp_name@ */
1267   sizeof(group_pyobj),                  /* @tp_basicsize@ */
1268   0,                                    /* @tp_itemsize@ */
1269
1270   group_pydealloc,                      /* @tp_dealloc@ */
1271   0,                                    /* @tp_print@ */
1272   0,                                    /* @tp_getattr@ */
1273   0,                                    /* @tp_setattr@ */
1274   0,                                    /* @tp_compare@ */
1275   0,                                    /* @tp_repr@ */
1276   0,                                    /* @tp_as_number@ */
1277   0,                                    /* @tp_as_sequence@ */
1278   0,                                    /* @tp_as_mapping@ */
1279   0,                                    /* @tp_hash@ */
1280   0,                                    /* @tp_call@ */
1281   0,                                    /* @tp_str@ */
1282   0,                                    /* @tp_getattro@ */
1283   0,                                    /* @tp_setattro@ */
1284   0,                                    /* @tp_as_buffer@ */
1285   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
1286     Py_TPFLAGS_BASETYPE,
1287
1288   /* @tp_doc@ */
1289 "Elliptic curve groups.",
1290
1291   0,                                    /* @tp_traverse@ */
1292   0,                                    /* @tp_clear@ */
1293   0,                                    /* @tp_richcompare@ */
1294   0,                                    /* @tp_weaklistoffset@ */
1295   0,                                    /* @tp_iter@ */
1296   0,                                    /* @tp_iternext@ */
1297   0,                                    /* @tp_methods@ */
1298   0,                                    /* @tp_members@ */
1299   ecgroup_pygetset,                     /* @tp_getset@ */
1300   0,                                    /* @tp_base@ */
1301   0,                                    /* @tp_dict@ */
1302   0,                                    /* @tp_descr_get@ */
1303   0,                                    /* @tp_descr_set@ */
1304   0,                                    /* @tp_dictoffset@ */
1305   0,                                    /* @tp_init@ */
1306   PyType_GenericAlloc,                  /* @tp_alloc@ */
1307   ecgroup_pynew,                        /* @tp_new@ */
1308   0,                                    /* @tp_free@ */
1309   0                                     /* @tp_is_gc@ */
1310 };
1311
1312 /*----- Global stuff ------------------------------------------------------*/
1313
1314 static PyMethodDef methods[] = {
1315 #define METHNAME(name) meth_##name
1316   METH  (_GE_frombuf,           "frombuf(BUF) -> X, REST")
1317   METH  (_GE_fromraw,           "fromraw(BUF) -> X, REST")
1318   METH  (_GE_fromstring,        "fromstring(STR) -> X, REST")
1319   METH  (_Group_parse,          "parse(STR) -> G, REST")
1320   METH  (_DHInfo_parse,         "parse(STR) -> D, REST")
1321   METH  (_BinDHInfo_parse,      "parse(STR) -> D, REST")
1322   METH  (_DHInfo__groupn,       0)
1323   METH  (_BinDHInfo__groupn,    0)
1324   KWMETH(_DHInfo_generate,      "\
1325 generate(PBITS, [qbits = 0, event = pgen_nullev,\n\
1326          rng = rand, nsteps = 0]) -> D")
1327   KWMETH(_DHInfo_genlimlee,     "\
1328 genlimlee(PBITS, QBITS, [event = pgen_nullev, ievent = pgen_nullev,\n\
1329           rng = rand, nsteps = 0, subgroupp = True]) -> (D, [Q, ...])")
1330   KWMETH(_DHInfo_gendsa,        "\
1331 gendsa(PBITS, QBITS, SEED, [event = pgen_nullev, nsteps = 0])\n\
1332   -> (D, SEED, COUNT)")
1333 #undef METHNAME
1334   { 0 }
1335 };
1336
1337 void group_pyinit(void)
1338 {
1339   INITTYPE(fginfo, root);
1340   INITTYPE(dhinfo, fginfo);
1341   INITTYPE(bindhinfo, dhinfo);
1342   INITTYPE(ge, root);
1343   INITTYPE(group, type);
1344   INITTYPE(primegroup, group);
1345   INITTYPE(bingroup, group);
1346   INITTYPE(ecgroup, group);
1347   addmethods(methods);
1348 }
1349
1350 void group_pyinsert(PyObject *mod)
1351 {
1352   INSERT("FGInfo", fginfo_pytype);
1353   INSERT("DHInfo", dhinfo_pytype);
1354   INSERT("BinDHInfo", bindhinfo_pytype);
1355   INSERT("GE", ge_pytype);
1356   INSERT("Group", group_pytype);
1357   INSERT("PrimeGroup", primegroup_pytype);
1358   INSERT("BinGroup", bingroup_pytype);
1359   INSERT("ECGroup", ecgroup_pytype);
1360   INSERT("_pgroups", namedgroups(ptab, &npgroups));
1361   INSERT("_bingroups", namedgroups(bintab, &nbingroups));
1362 }
1363
1364 /*----- That's all, folks -------------------------------------------------*/