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