chiark / gitweb /
More fixing for modern Pythons. No longer works with 2.2. Sorry.
[catacomb-python] / ec.c
1 /* -*-c-*-
2  *
3  * $Id$
4  *
5  * Elliptic curves
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 /*----- Utility functions -------------------------------------------------*/
34
35 PyTypeObject *ecpt_pytype;
36 PyTypeObject *ecptcurve_pytype;
37 PyTypeObject *eccurve_pytype;
38 PyTypeObject *ecprimecurve_pytype;
39 PyTypeObject *ecprimeprojcurve_pytype;
40 PyTypeObject *ecbincurve_pytype;
41 PyTypeObject *ecbinprojcurve_pytype;
42 PyTypeObject *ecinfo_pytype;
43
44 ec_curve *eccurve_copy(ec_curve *c)
45 {
46   field *f;
47   mp *a, *b;
48
49   if ((f = field_copy(c->f)) == 0)
50     return (0);
51   a = F_OUT(f, MP_NEW, c->a);
52   b = F_OUT(f, MP_NEW, c->b);
53   if (strcmp(EC_NAME(c), "prime") == 0)
54     c = ec_prime(f, a, b);
55   else if (strcmp(EC_NAME(c), "primeproj") == 0)
56     c = ec_primeproj(f, a, b);
57   else if (strcmp(EC_NAME(c), "bin") == 0)
58     c = ec_bin(f, a, b);
59   else if (strcmp(EC_NAME(c), "binproj") == 0)
60     c = ec_binproj(f, a, b);
61   else
62     c = 0;
63   MP_DROP(a);
64   MP_DROP(b);
65   if (!c) F_DESTROY(f);
66   return (c);
67 }
68
69 static PyObject *ecpt_dopywrap(PyObject *cobj, ec_curve *c, ec *p)
70 {
71   ecpt_pyobj *z = PyObject_New(ecpt_pyobj, (PyTypeObject *)cobj);
72   z->p = *p;
73   z->c = c;
74   Py_INCREF(cobj);
75   return ((PyObject *)z);
76 }
77
78 PyObject *ecpt_pywrap(PyObject *cobj, ec *p)
79   { return (ecpt_dopywrap(cobj, ECCURVE_C(cobj), p)); }
80
81 PyObject *ecpt_pywrapout(void *cobj, ec *p)
82 {
83   ec_curve *c;
84
85   if (!PyType_IsSubtype(cobj, ecptcurve_pytype))
86     c = 0;
87   else {
88     c = ECCURVE_C(cobj);
89     EC_IN(ECCURVE_C(cobj), p, p);
90   }
91   return (ecpt_dopywrap(cobj, c, p));
92 }
93
94 int toecpt(ec_curve *c, ec *d, PyObject *p)
95 {
96   if (ECPTCURVE_PYCHECK(p)) {
97     if (ECPT_C(p) != c && !ec_samep(ECPT_C(p), c))
98       return (-1);
99     EC_COPY(d, ECPT_P(p));
100   } else if (ECPT_PYCHECK(p))
101     EC_IN(c, d, ECPT_P(p));
102   else
103     return (-1);
104   return (0);
105 }
106
107 int getecpt(ec_curve *c, ec *d, PyObject *p)
108 {
109   if (toecpt(c, d, p)) {
110     PyErr_Format(PyExc_TypeError, "can't convert %.100s to ecpt",
111                  p->ob_type->tp_name);
112     return (-1);
113   }
114   return (0);
115 }
116
117 void getecptout(ec *d, PyObject *p)
118 {
119   if (ECPTCURVE_PYCHECK(p))
120     EC_OUT(ECPT_C(p), d, ECPT_P(p));
121   else {
122     assert(ECPT_PYCHECK(p));
123     EC_COPY(d, ECPT_P(p));
124   }
125 }
126
127 int convecpt(PyObject *o, void *p)
128 {
129   if (!ECPT_PYCHECK(o))
130     TYERR("want elliptic curve point");
131   getecptout(p, o);
132   return (1);
133 end:
134   return (0);
135 }
136
137 /*----- Curve points ------------------------------------------------------*/
138
139 static int ecbinop(PyObject *x, PyObject *y,
140                    ec_curve **c, PyObject **cobj, ec *xx, ec *yy)
141 {
142   if (ECPTCURVE_PYCHECK(x)) *cobj = ECPT_COBJ(x);
143   else if (ECPTCURVE_PYCHECK(y)) *cobj = ECPT_COBJ(y);
144   else return (-1);
145   *c = ECCURVE_C(*cobj);
146   if (toecpt(*c, xx, x) || toecpt(*c, yy, y)) return (-1);
147   return (0);
148 }
149
150 #define BINOP(name)                                                     \
151   static PyObject *ecpt_py##name(PyObject *x, PyObject *y) {            \
152     ec xx = EC_INIT, yy = EC_INIT, zz = EC_INIT;                        \
153     PyObject *cobj;                                                     \
154     ec_curve *c;                                                        \
155     if (ecbinop(x, y, &c, &cobj, &xx, &yy)) RETURN_NOTIMPL;             \
156     c->ops->name(c, &zz, &xx, &yy);                                     \
157     EC_DESTROY(&xx); EC_DESTROY(&yy);                                   \
158     return (ecpt_pywrap(ECPT_COBJ(x), &zz));                            \
159   }
160 BINOP(add)
161 BINOP(sub)
162 #undef BINOP
163
164 #define UNOP(name)                                                      \
165   static PyObject *ecpt_py##name(PyObject *x) {                         \
166     ec zz = EC_INIT;                                                    \
167     ec_curve *c = ECPT_C(x);                                            \
168     c->ops->name(c, &zz, ECPT_P(x));                                    \
169     return (ecpt_pywrap(ECPT_COBJ(x), &zz));                            \
170   }
171 UNOP(neg)
172 #undef UNOP
173
174 static PyObject *ecpt_pyid(PyObject *x) { RETURN_OBJ(x); }
175
176 static int ecpt_pynonzerop(PyObject *x) { return (!EC_ATINF(ECPT_P(x))); }
177
178 static void ecpt_pydealloc(PyObject *x)
179 {
180   EC_DESTROY(ECPT_P(x));
181   Py_DECREF(ECPT_COBJ(x));
182   FREEOBJ(x);
183 }
184
185 static PyObject *ecpt_pymul(PyObject *x, PyObject *y)
186 {
187   mp *xx;
188   ec zz = EC_INIT;
189
190   if (ECPT_PYCHECK(x)) { PyObject *t; t = x; x = y; y = t; }
191   if (!ECPT_PYCHECK(y) || (xx = tomp(x)) == 0) RETURN_NOTIMPL;
192   ec_imul(ECPT_C(y), &zz, ECPT_P(y), xx);
193   return (ecpt_pywrap(ECPT_COBJ(y), &zz));
194 }
195
196 static long ecpt_pyhash(PyObject *me)
197 {
198   long i;
199   ec p = EC_INIT;
200
201   EC_OUT(ECPT_C(me), &p, ECPT_P(me));
202   i = 0xe0fdd039; /* random perturbance */
203   if (p.x) i ^= mp_tolong(p.x);
204   if (p.y) i ^= mp_tolong(p.y);
205   if (i == -1) i = -2;
206   EC_DESTROY(&p);
207   return (i);
208 }
209
210 static PyObject *ecpt_pyrichcompare(PyObject *x, PyObject *y, int op)
211 {
212   ec_curve *c;
213   PyObject *cobj;
214   ec p = EC_INIT, q = EC_INIT;
215   int b;
216   PyObject *rc = 0;
217
218   if (ecbinop(x, y, &c, &cobj, &p, &q)) RETURN_NOTIMPL;
219   EC_OUT(c, &p, &p);
220   EC_OUT(c, &q, &q);
221   switch (op) {
222     case Py_EQ: b = EC_EQ(&p, &q); break;
223     case Py_NE: b = !EC_EQ(&p, &q); break;
224     default: TYERR("elliptic curve points are unordered");
225   }
226   rc = getbool(b);
227 end:
228   EC_DESTROY(&p);
229   EC_DESTROY(&q);
230   return (rc);
231 }
232
233 static PyObject *epmeth_oncurvep(PyObject *me, PyObject *arg)
234 {
235   if (!PyArg_ParseTuple(arg, ":oncurvep")) return (0);
236   return (getbool(!ec_check(ECPT_C(me), ECPT_P(me))));
237 }
238
239 static PyObject *epmeth_dbl(PyObject *me, PyObject *arg)
240 {
241   ec p = EC_INIT;
242   if (!PyArg_ParseTuple(arg, ":dbl")) return (0);
243   EC_DBL(ECPT_C(me), &p, ECPT_P(me));
244   return (ecpt_pywrap(ECPT_COBJ(me), &p));
245 }
246
247 static PyObject *epmeth_tobuf(PyObject *me, PyObject *arg)
248 {
249   buf b;
250   ec p = EC_INIT;
251   PyObject *rc;
252   size_t n;
253
254   if (!PyArg_ParseTuple(arg, ":tobuf")) return (0);
255   getecptout(&p, me);
256   if (EC_ATINF(&p))
257     n = 2;
258   else
259     n = mp_octets(p.x) + mp_octets(p.y) + 4;
260   rc = bytestring_pywrap(0, n);
261   buf_init(&b, PyString_AS_STRING(rc), n);
262   buf_putec(&b, &p);
263   assert(BOK(&b));
264   _PyString_Resize(&rc, BLEN(&b));
265   EC_DESTROY(&p);
266   return (rc);
267 }
268
269 static PyObject *epmeth_toraw(PyObject *me, PyObject *arg)
270 {
271   buf b;
272   PyObject *rc;
273   char *p;
274   ec_curve *c = ECPT_C(me);
275   ec pp = EC_INIT;
276   int len;
277
278   if (!PyArg_ParseTuple(arg, ":toraw")) return (0);
279   len = c->f->noctets * 2 + 1;
280   rc = bytestring_pywrap(0, len);
281   p = PyString_AS_STRING(rc);
282   buf_init(&b, p, len);
283   EC_OUT(c, &pp, ECPT_P(me));
284   ec_putraw(c, &b, &pp);
285   EC_DESTROY(&pp);
286   _PyString_Resize(&rc, BLEN(&b));
287   return (rc);
288 }
289
290 static PyObject *epget_curve(PyObject *me, void *hunoz)
291   { RETURN_OBJ(ECPT_COBJ(me)); }
292
293 static PyObject *epncget_ix(PyObject *me, void *hunoz)
294 {
295   ec p = EC_INIT;
296   PyObject *rc;
297   if (EC_ATINF(ECPT_P(me))) RETURN_NONE;
298   getecptout(&p, me);
299   rc = mp_pywrap(MP_COPY(p.x));
300   EC_DESTROY(&p);
301   return (rc);
302 }
303
304 static PyObject *epncget_iy(PyObject *me, void *hunoz)
305 {
306   ec p = EC_INIT;
307   PyObject *rc;
308   if (EC_ATINF(ECPT_P(me))) RETURN_NONE;
309   getecptout(&p, me);
310   rc = mp_pywrap(MP_COPY(p.y));
311   EC_DESTROY(&p);
312   return (rc);
313 }
314
315 static PyObject *epncget_point(PyObject *me, void *hunoz)
316   { RETURN_ME; }
317
318 static PyObject *epget_point(PyObject *me, void *hunoz)
319 {
320   ec p = EC_INIT;
321   getecptout(&p, me);
322   return (ecpt_pywrapout(ecpt_pytype, &p));
323 }
324
325 static PyObject *epget_x(PyObject *me, void *hunoz)
326 {
327   ec_curve *c = ECPT_C(me);
328   ec *pp = ECPT_P(me);
329   PyObject *fobj = ECPT_FOBJ(me);
330   ec p = EC_INIT;
331   PyObject *rc;
332
333   if (EC_ATINF(pp)) RETURN_NONE;
334   EC_OUT(c, &p, pp);
335   rc = fe_pywrap(fobj, F_IN(c->f, MP_NEW, p.x));
336   EC_DESTROY(&p);
337   return (rc);
338 }
339
340 static PyObject *epget_y(PyObject *me, void *hunoz)
341 {
342   ec_curve *c = ECPT_C(me);
343   ec *pp = ECPT_P(me);
344   PyObject *fobj = ECPT_FOBJ(me);
345   ec p = EC_INIT;
346   PyObject *rc;
347
348   if (EC_ATINF(pp)) RETURN_NONE;
349   EC_OUT(c, &p, pp);
350   rc = fe_pywrap(fobj, F_IN(c->f, MP_NEW, p.y));
351   EC_DESTROY(&p);
352   return (rc);
353 }
354
355 static PyObject *epget__x(PyObject *me, void *hunoz)
356 {
357   if (EC_ATINF(ECPT_P(me))) RETURN_NONE;
358   return (fe_pywrap(ECPT_FOBJ(me), MP_COPY(ECPT_P(me)->x)));
359 }
360
361 static PyObject *epget__y(PyObject *me, void *hunoz)
362 {
363   if (EC_ATINF(ECPT_P(me))) RETURN_NONE;
364   return (fe_pywrap(ECPT_FOBJ(me), MP_COPY(ECPT_P(me)->y)));
365 }
366
367 static PyObject *epget__z(PyObject *me, void *hunoz)
368 {
369   if (EC_ATINF(ECPT_P(me)) || !ECPT_P(me)->z) RETURN_NONE;
370   return (fe_pywrap(ECPT_FOBJ(me), MP_COPY(ECPT_P(me)->z)));
371 }
372
373 static mp *coord_in(field *f, PyObject *x)
374 {
375   mp *xx;
376   if (FE_PYCHECK(x) && FE_F(x) == f)
377     return (MP_COPY(FE_X(x)));
378   else if ((xx = getmp(x)) == 0)
379     return (0);
380   else
381     return (F_IN(f, xx, xx));
382 }
383
384 static int ecptxl_3(ec_curve *c, ec *p,
385                     PyObject *x, PyObject *y, PyObject *z)
386 {
387   int rc = -1;
388
389   if (!x || !y || !z) TYERR("missing argument");
390   if (!c) VALERR("internal form with no curve!");
391   if ((p->x == coord_in(c->f, x)) == 0 ||
392       (p->y == coord_in(c->f, y)) == 0 ||
393       (z != Py_None && (p->z = coord_in(c->f, z))) == 0)
394     goto end;
395   if (!p->z) p->z = MP_COPY(c->f->one); /* just in case */
396   rc = 0;
397 end:
398   return (rc);
399 }
400
401 static int ecptxl_2(ec_curve *c, ec *p, PyObject *x, PyObject *y)
402 {
403   int rc = -1;
404
405   if (!x || !y) TYERR("missing argument");
406   if ((p->x = getmp(x)) == 0 ||
407       (p->y = getmp(y)) == 0)
408     goto end;
409   if (c) EC_IN(c, p, p);
410   rc = 0;
411 end:
412   return (rc);
413 }
414
415 static int ecptxl_1(ec_curve *c, ec *p, PyObject *x)
416 {
417   int rc = -1;
418   PyObject *y = 0, *z = 0, *t = 0;
419   mp *xx = 0;
420   const void *q;
421   int n;
422   qd_parse qd;
423
424   Py_XINCREF(x);
425   if (!x || x == Py_None)
426     /*cool*/;
427   else if (ECPT_PYCHECK(x)) {
428     getecptout(p, x);
429     goto fix;
430   } else if (PyString_Check(x)) {
431     if (PyObject_AsReadBuffer(x, &q, 0))
432       goto end;
433     qd.p = q;
434     qd.e = 0;
435     if (!ec_ptparse(&qd, p))
436       SYNERR(qd.e);
437     goto fix;
438   } else if (c && (xx = tomp(x)) != 0) {
439     xx = F_IN(c->f, xx, xx);
440     if (!EC_FIND(c, p, xx)) VALERR("not on the curve");
441   } else if (PySequence_Check(x)) {
442     t = x; x = 0;
443     n = PySequence_Size(t);
444     if (n != 2 && (n != 3 || !c))
445       TYERR("want sequence of two or three items");
446     if ((x = PySequence_GetItem(t, 0)) == 0 ||
447         (y = PySequence_GetItem(t, 1)) == 0 ||
448         (n == 3 && (z = PySequence_GetItem(t, 2)) == 0))
449       goto end;
450     rc = (n == 2) ? ecptxl_2(c, p, x, y) : ecptxl_3(c, p, x, y, z);
451   } else
452     TYERR("can't convert to curve point");
453   goto ok;
454
455 fix:
456   if (c) EC_IN(c, p, p);
457 ok:
458   rc = 0;
459 end:
460   Py_XDECREF(x); Py_XDECREF(y); Py_XDECREF(z); Py_XDECREF(t);
461   mp_drop(xx);
462   return (rc);
463 }
464
465 static int ecptxl(ec_curve *c, ec *p, PyObject *x, PyObject *y, PyObject *z)
466 {
467   if (z)
468     return (ecptxl_3(c, p, x, y, z));
469   else if (y)
470     return (ecptxl_2(c, p, x, y));
471   else
472     return (ecptxl_1(c, p, x));
473 }
474
475 static PyObject *ecptnc_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
476 {
477   PyObject *x = 0, *y = 0, *z = 0;
478   ec p = EC_INIT;
479   char *kwlist[] = { "x", "y", 0 };
480
481   if (!PyArg_ParseTupleAndKeywords(arg, kw, "|OO:new", kwlist, &x, &y) ||
482       ecptxl(0, &p, x, y, z))
483     goto end;
484   return (ecpt_pywrapout(ty, &p));
485 end:
486   EC_DESTROY(&p);
487   return (0);
488 }
489
490 static PyObject *ecpt_pyint(PyObject *me)
491 {
492   ec p = EC_INIT;
493   long l;
494   PyObject *rc = 0;
495   if (EC_ATINF(ECPT_P(me))) VALERR("point at infinity");
496   getecptout(&p, me);
497   if (mp_tolong_checked(p.x, &l)) goto end;
498   rc = PyInt_FromLong(l);
499 end:
500   EC_DESTROY(&p);
501   return (rc);
502 }
503
504 static PyObject *ecpt_pylong(PyObject *me)
505 {
506   ec p = EC_INIT;
507   PyObject *rc = 0;
508   if (EC_ATINF(ECPT_P(me))) VALERR("point at infinity");
509   getecptout(&p, me);
510   rc = (PyObject *)mp_topylong(p.x);
511 end:
512   EC_DESTROY(&p);
513   return (rc);
514 }
515
516 static PyObject *ecpt_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
517 {
518   PyObject *x = 0, *y = 0, *z = 0;
519   ec p = EC_INIT;
520   char *kwlist[] = { "x", "y", "z", 0 };
521
522   if (!PyArg_ParseTupleAndKeywords(arg, kw, "|OOO:new", kwlist,
523                                    &x, &y, &z) ||
524       ecptxl(ECCURVE_C(ty), &p, x, y, z))
525     goto end;
526   return (ecpt_pywrap((PyObject *)ty, &p));
527 end:
528   EC_DESTROY(&p);
529   return (0);
530 }
531
532 static PyGetSetDef ecptnc_pygetset[] = {
533 #define GETSETNAME(op, name) epnc##op##_##name
534   GET   (ix,            "P.ix -> integer x coordinate of P")
535   GET   (iy,            "P.iy -> integer y coordinate of P")
536   GET   (point,         "P.point -> standalone curve point (no-op)")
537 #undef GETSETNAME
538   { 0 }
539 };
540
541 static PyMethodDef ecptnc_pymethods[] = {
542 #define METHNAME(func) epmeth_##func
543   METH  (tobuf,         "X.tobuf() -> BIN")
544 #undef METHNAME
545   { 0 }
546 };
547
548 static PyNumberMethods ecpt_pynumber = {
549   0,                                    /* @nb_add@ */
550   0,                                    /* @nb_subtract@ */
551   0,                                    /* @nb_multiply@ */
552   0,                                    /* @nb_divide@ */
553   0,                                    /* @nb_remainder@ */
554   0,                                    /* @nb_divmod@ */
555   0,                                    /* @nb_power@ */
556   0,                                    /* @nb_negative@ */
557   0,                                    /* @nb_positive@ */
558   0,                                    /* @nb_absolute@ */
559   ecpt_pynonzerop,                      /* @nb_nonzero@ */
560   0,                                    /* @nb_invert@ */
561   0,                                    /* @nb_lshift@ */
562   0,                                    /* @nb_rshift@ */
563   0,                                    /* @nb_and@ */
564   0,                                    /* @nb_xor@ */
565   0,                                    /* @nb_or@ */
566   0,                                    /* @nb_coerce@ */
567   ecpt_pyint,                           /* @nb_int@ */
568   ecpt_pylong,                          /* @nb_long@ */
569   0,                                    /* @nb_float@ */
570   0,                                    /* @nb_oct@ */
571   0,                                    /* @nb_hex@ */
572
573   0,                                    /* @nb_inplace_add@ */
574   0,                                    /* @nb_inplace_subtract@ */
575   0,                                    /* @nb_inplace_multiply@ */
576   0,                                    /* @nb_inplace_divide@ */
577   0,                                    /* @nb_inplace_remainder@ */
578   0,                                    /* @nb_inplace_power@ */
579   0,                                    /* @nb_inplace_lshift@ */
580   0,                                    /* @nb_inplace_rshift@ */
581   0,                                    /* @nb_inplace_and@ */
582   0,                                    /* @nb_inplace_xor@ */
583   0,                                    /* @nb_inplace_or@ */
584
585   0,                                    /* @nb_floor_divide@ */
586   0,                                    /* @nb_true_divide@ */
587   0,                                    /* @nb_inplace_floor_divide@ */
588   0,                                    /* @nb_inplace_true_divide@ */
589 };
590
591 static PyTypeObject ecpt_pytype_skel = {
592   PyObject_HEAD_INIT(&PyType_Type) 0,   /* Header */
593   "catacomb.ECPt",                      /* @tp_name@ */
594   sizeof(ecpt_pyobj),                   /* @tp_basicsize@ */
595   0,                                    /* @tp_itemsize@ */
596
597   ecpt_pydealloc,                       /* @tp_dealloc@ */
598   0,                                    /* @tp_print@ */
599   0,                                    /* @tp_getattr@ */
600   0,                                    /* @tp_setattr@ */
601   0,                                    /* @tp_compare@ */
602   0,                                    /* @tp_repr@ */
603   &ecpt_pynumber,                       /* @tp_as_number@ */
604   0,                                    /* @tp_as_sequence@ */
605   0,                                    /* @tp_as_mapping@ */
606   ecpt_pyhash,                          /* @tp_hash@ */
607   0,                                    /* @tp_call@ */
608   0,                                    /* @tp_str@ */
609   0,                                    /* @tp_getattro@ */
610   0,                                    /* @tp_setattro@ */
611   0,                                    /* @tp_as_buffer@ */
612   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
613     Py_TPFLAGS_CHECKTYPES |
614     Py_TPFLAGS_BASETYPE,
615
616   /* @tp_doc@ */
617 "Elliptic curve points, not associated with any curve.",
618
619   0,                                    /* @tp_traverse@ */
620   0,                                    /* @tp_clear@ */
621   ecpt_pyrichcompare,                   /* @tp_richcompare@ */
622   0,                                    /* @tp_weaklistoffset@ */
623   0,                                    /* @tp_iter@ */
624   0,                                    /* @tp_iternexr@ */
625   ecptnc_pymethods,                     /* @tp_methods@ */
626   0,                                    /* @tp_members@ */
627   ecptnc_pygetset,                      /* @tp_getset@ */
628   0,                                    /* @tp_base@ */
629   0,                                    /* @tp_dict@ */
630   0,                                    /* @tp_descr_get@ */
631   0,                                    /* @tp_descr_set@ */
632   0,                                    /* @tp_dictoffset@ */
633   0,                                    /* @tp_init@ */
634   PyType_GenericAlloc,                  /* @tp_alloc@ */
635   ecptnc_pynew,                         /* @tp_new@ */
636   0,                                    /* @tp_free@ */
637   0                                     /* @tp_is_gc@ */
638 };
639
640 static PyGetSetDef ecpt_pygetset[] = {
641 #define GETSETNAME(op, name) ep##op##_##name
642   GET   (curve,         "P.curve -> elliptic curve containing P")
643   GET   (point,         "P.point -> standalone curve point")
644   GET   (x,             "P.x -> Cartesian x coordinate of P")
645   GET   (y,             "P.y -> Cartesian y coordinate of P")
646   GET   (_x,            "P._x -> internal x coordinate of P")
647   GET   (_y,            "P._y -> internal y coordinate of P")
648   GET   (_z,            "P._z -> internal z coordinate of P, or None")
649 #undef GETSETNAME
650   { 0 }
651 };
652
653 static PyMethodDef ecpt_pymethods[] = {
654 #define METHNAME(func) epmeth_##func
655   METH  (toraw,         "X.toraw() -> BIN")
656   METH  (dbl,           "X.dbl() -> X + X")
657   METH  (oncurvep,      "X.oncurvep() -> BOOL")
658 #undef METHNAME
659   { 0 }
660 };
661
662 static PyNumberMethods ecptcurve_pynumber = {
663   ecpt_pyadd,                           /* @nb_add@ */
664   ecpt_pysub,                           /* @nb_subtract@ */
665   ecpt_pymul,                           /* @nb_multiply@ */
666   0,                                    /* @nb_divide@ */
667   0,                                    /* @nb_remainder@ */
668   0,                                    /* @nb_divmod@ */
669   0,                                    /* @nb_power@ */
670   ecpt_pyneg,                           /* @nb_negative@ */
671   ecpt_pyid,                            /* @nb_positive@ */
672   0,                                    /* @nb_absolute@ */
673   0,                                    /* @nb_nonzero@ */
674   0,                                    /* @nb_invert@ */
675   0,                                    /* @nb_lshift@ */
676   0,                                    /* @nb_rshift@ */
677   0,                                    /* @nb_and@ */
678   0,                                    /* @nb_xor@ */
679   0,                                    /* @nb_or@ */
680   0,                                    /* @nb_coerce@ */
681   0,                                    /* @nb_int@ */
682   0,                                    /* @nb_long@ */
683   0,                                    /* @nb_float@ */
684   0,                                    /* @nb_oct@ */
685   0,                                    /* @nb_hex@ */
686
687   0,                                    /* @nb_inplace_add@ */
688   0,                                    /* @nb_inplace_subtract@ */
689   0,                                    /* @nb_inplace_multiply@ */
690   0,                                    /* @nb_inplace_divide@ */
691   0,                                    /* @nb_inplace_remainder@ */
692   0,                                    /* @nb_inplace_power@ */
693   0,                                    /* @nb_inplace_lshift@ */
694   0,                                    /* @nb_inplace_rshift@ */
695   0,                                    /* @nb_inplace_and@ */
696   0,                                    /* @nb_inplace_xor@ */
697   0,                                    /* @nb_inplace_or@ */
698
699   0,                                    /* @nb_floor_divide@ */
700   0,                                    /* @nb_true_divide@ */
701   0,                                    /* @nb_inplace_floor_divide@ */
702   0,                                    /* @nb_inplace_true_divide@ */
703 };
704
705 static PyTypeObject ecptcurve_pytype_skel = {
706   PyObject_HEAD_INIT(&PyType_Type) 0,   /* Header */
707   "catacomb.ECPtCurve",                 /* @tp_name@ */
708   sizeof(ecpt_pyobj),                   /* @tp_basicsize@ */
709   0,                                    /* @tp_itemsize@ */
710
711   ecpt_pydealloc,                       /* @tp_dealloc@ */
712   0,                                    /* @tp_print@ */
713   0,                                    /* @tp_getattr@ */
714   0,                                    /* @tp_setattr@ */
715   0,                                    /* @tp_compare@ */
716   0,                                    /* @tp_repr@ */
717   &ecptcurve_pynumber,                  /* @tp_as_number@ */
718   0,                                    /* @tp_as_sequence@ */
719   0,                                    /* @tp_as_mapping@ */
720   0,                                    /* @tp_hash@ */
721   0,                                    /* @tp_call@ */
722   0,                                    /* @tp_str@ */
723   0,                                    /* @tp_getattro@ */
724   0,                                    /* @tp_setattro@ */
725   0,                                    /* @tp_as_buffer@ */
726   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
727     Py_TPFLAGS_CHECKTYPES |
728     Py_TPFLAGS_BASETYPE,
729
730   /* @tp_doc@ */
731 "Elliptic curve points; abstract base class for points on given curves.",
732
733   0,                                    /* @tp_traverse@ */
734   0,                                    /* @tp_clear@ */
735   0,                                    /* @tp_richcompare@ */
736   0,                                    /* @tp_weaklistoffset@ */
737   0,                                    /* @tp_iter@ */
738   0,                                    /* @tp_iternexr@ */
739   ecpt_pymethods,                       /* @tp_methods@ */
740   0,                                    /* @tp_members@ */
741   ecpt_pygetset,                        /* @tp_getset@ */
742   0,                                    /* @tp_base@ */
743   0,                                    /* @tp_dict@ */
744   0,                                    /* @tp_descr_get@ */
745   0,                                    /* @tp_descr_set@ */
746   0,                                    /* @tp_dictoffset@ */
747   0,                                    /* @tp_init@ */
748   PyType_GenericAlloc,                  /* @tp_alloc@ */
749   abstract_pynew,                       /* @tp_new@ */
750   0,                                    /* @tp_free@ */
751   0                                     /* @tp_is_gc@ */
752 };
753
754 /*----- Elliptic curves themselves ----------------------------------------*/
755
756 static PyObject *eccurve_pyrichcompare(PyObject *x, PyObject *y, int op)
757 {
758   int b = ec_samep(ECCURVE_C(x), ECCURVE_C(y));
759   switch (op) {
760     case Py_EQ: break;
761     case Py_NE: b = !b;
762     default: TYERR("can't order elliptic curves");
763   }
764   return (getbool(b));
765 end:
766   return (0);
767 }
768
769 static PyObject *ecmmul_id(PyObject *me)
770   { ec p = EC_INIT; return (ecpt_pywrap(me, &p)); }
771
772 static int ecmmul_fill(void *pp, PyObject *me, PyObject *x, PyObject *m)
773 {
774   ec_mulfactor *f = pp;
775
776   if (getecpt(ECCURVE_C(me), &f->base, x) ||
777       (f->exp = getmp(m)) == 0)
778     return (-1);
779   f->base = *ECPT_P(x);
780   return (0);
781 }
782
783 static PyObject *ecmmul_exp(PyObject *me, void *pp, int n)
784 {
785   ec p = EC_INIT;
786   ec_immul(ECCURVE_C(me), &p, pp, n);
787   return (ecpt_pywrap(me, &p));
788 }
789
790 static void ecmmul_drop(void *pp)
791 {
792   ec_mulfactor *f = pp;
793   EC_DESTROY(&f->base);
794   MP_DROP(f->exp);
795 }
796
797 static PyObject *ecmeth_mmul(PyObject *me, PyObject *arg)
798 {
799   return (mexp_common(me, arg, sizeof(ec_mulfactor),
800                       ecmmul_id, ecmmul_fill, ecmmul_exp, ecmmul_drop));
801 }
802
803 static PyObject *meth__ECPtCurve_fromraw(PyObject *me, PyObject *arg)
804 {
805   char *p;
806   int len;
807   buf b;
808   PyObject *rc = 0;
809   ec_curve *cc;
810   ec pp = EC_INIT;
811
812   if (!PyArg_ParseTuple(arg, "Os#:fromraw", &me, &p, &len))
813     return (0);
814   buf_init(&b, p, len);
815   cc = ECCURVE_C(me);
816   if (ec_getraw(cc, &b, &pp))
817     SYNERR("bad point");
818   EC_IN(cc, &pp, &pp);
819   rc = Py_BuildValue("(NN)", ecpt_pywrap(me, &pp), bytestring_pywrapbuf(&b));
820 end:
821   return (rc);
822 }
823
824 static PyObject *meth__ECPt_frombuf(PyObject *me, PyObject *arg)
825 {
826   buf b;
827   char *p;
828   int sz;
829   PyObject *rc = 0;
830   ec pp = EC_INIT;
831
832   if (!PyArg_ParseTuple(arg, "Os#:frombuf", &me, &p, &sz)) goto end;
833   buf_init(&b, p, sz);
834   if (buf_getec(&b, &pp)) VALERR("malformed data");
835   rc = Py_BuildValue("(NN)", ecpt_pywrapout(me, &pp),
836                      bytestring_pywrapbuf(&b));
837 end:
838   return (rc);
839 }
840
841 static PyObject *meth__ECPt_parse(PyObject *me, PyObject *arg)
842 {
843   char *p;
844   qd_parse qd;
845   PyObject *rc = 0;
846   ec pp = EC_INIT;
847
848   if (!PyArg_ParseTuple(arg, "Os:parse", &me, &p)) goto end;
849   qd.p = p;
850   qd.e = 0;
851   if (!ec_ptparse(&qd, &pp)) SYNERR(qd.e);
852   rc = Py_BuildValue("(Ns)", ecpt_pywrapout(me, &pp), qd.p);
853 end:
854   return (rc);
855 }
856
857 static void eccurve_pydealloc(PyObject *me)
858 {
859   ec_destroycurve(ECCURVE_C(me));
860   Py_DECREF(ECCURVE_FOBJ(me));
861   PyType_Type.tp_dealloc(me);
862 }
863
864 static PyObject *ecmeth_find(PyObject *me, PyObject *arg)
865 {
866   PyObject *x;
867   mp *xx = 0;
868   ec p = EC_INIT;
869   PyObject *rc = 0;
870
871   if (!PyArg_ParseTuple(arg, "O:find", &x)) goto end;
872   if (FIELD_PYCHECK(x) && FE_F(x) == ECCURVE_C(me)->f)
873     xx = MP_COPY(FE_X(x));
874   else if ((xx = getmp(x)) == 0)
875     goto end;
876   else
877     xx = F_IN(ECCURVE_C(me)->f, xx, xx);
878   if (EC_FIND(ECCURVE_C(me), &p, xx) == 0)
879     VALERR("not on the curve");
880   rc = ecpt_pywrap(me, &p);
881 end:
882   if (xx) MP_DROP(xx);
883   return (rc);
884 }
885
886 static PyObject *ecmeth_rand(PyObject *me, PyObject *arg, PyObject *kw)
887 {
888   char *kwlist[] = { "rng", 0 };
889   grand *r = &rand_global;
890   ec p = EC_INIT;
891
892   if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:rand", kwlist,
893                                    convgrand, &r))
894     return (0);
895   ec_rand(ECCURVE_C(me), &p, r);
896   EC_IN(ECCURVE_C(me), &p, &p);
897   return (ecpt_pywrap(me, &p));
898 }
899
900 static PyObject *eccurve_dopywrap(PyTypeObject *ty,
901                                   PyObject *fobj, ec_curve *c)
902 {
903   eccurve_pyobj *cobj = newtype(ty, 0, c->ops->name);
904   cobj->c = c;
905   cobj->fobj = fobj;
906   cobj->ty.type.tp_basicsize = sizeof(ecpt_pyobj);
907   cobj->ty.type.tp_base = ecptcurve_pytype;
908   Py_INCREF(ecptcurve_pytype);
909   cobj->ty.type.tp_flags = (Py_TPFLAGS_DEFAULT |
910                             Py_TPFLAGS_BASETYPE |
911                             Py_TPFLAGS_CHECKTYPES |
912                             Py_TPFLAGS_HEAPTYPE);
913   cobj->ty.type.tp_alloc = PyType_GenericAlloc;
914   cobj->ty.type.tp_free = 0;
915   cobj->ty.type.tp_new = ecpt_pynew;
916   PyType_Ready(&cobj->ty.type);
917   return ((PyObject *)cobj);
918 }
919
920 PyObject *eccurve_pywrap(PyObject *fobj, ec_curve *c)
921 {
922   PyTypeObject *ty;
923
924   if (!fobj)
925     fobj = field_pywrap(c->f);
926   else
927     Py_INCREF(fobj);
928   assert(FIELD_F(fobj) == c->f);
929   if (strcmp(EC_NAME(c), "prime") == 0)
930     ty = ecprimecurve_pytype;
931   else if (strcmp(EC_NAME(c), "primeproj") == 0)
932     ty = ecprimeprojcurve_pytype;
933   else if (strcmp(EC_NAME(c), "bin") == 0)
934     ty = ecbincurve_pytype;
935   else if (strcmp(EC_NAME(c), "binproj") == 0)
936     ty = ecbinprojcurve_pytype;
937   else
938     abort();
939   return (eccurve_dopywrap(ty, fobj, c));
940 }
941
942 static PyObject *eccurve_pynew(PyTypeObject *ty,
943                                ec_curve *(*make)(field *, mp *, mp *),
944                                PyObject *arg, PyObject *kw)
945 {
946   PyObject *fobj;
947   PyObject *cobj = 0;
948   char *kwlist[] = { "field", "a", "b", 0 };
949   mp *aa = 0, *bb = 0;
950
951   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!OO", kwlist,
952                                    field_pytype, &fobj,
953                                    convmp, &aa, convmp, &bb))
954     goto end;
955   Py_INCREF(fobj);
956   cobj = eccurve_dopywrap(ty, fobj, make(FIELD_F(fobj), aa, bb));
957 end:
958   if (aa) MP_DROP(aa);
959   if (bb) MP_DROP(bb);
960   return (cobj);
961 }
962
963 static PyObject *meth__ECCurve_parse(PyObject *me, PyObject *arg)
964 {
965   char *p;
966   qd_parse qd;
967   ec_curve *c;
968   PyObject *rc = 0;
969
970   if (!PyArg_ParseTuple(arg, "Os", &me, &p))
971     goto end;
972   qd.p = p;
973   qd.e = 0;
974   if ((c = ec_curveparse(&qd)) == 0)
975     SYNERR(qd.e);
976   rc = eccurve_pywrap(0, c);
977 end:
978   return (rc);
979 }
980
981 static PyObject *ecget_name(PyObject *me, void *hunoz)
982   { return (PyString_FromString(EC_NAME(ECCURVE_C(me)))); }
983
984 static PyObject *ecget_a(PyObject *me, void *hunoz)
985   { return (fe_pywrap(ECCURVE_FOBJ(me), MP_COPY(ECCURVE_C(me)->a))); }
986
987 static PyObject *ecget_b(PyObject *me, void *hunoz) 
988   { return (fe_pywrap(ECCURVE_FOBJ(me), MP_COPY(ECCURVE_C(me)->b))); }
989
990 static PyObject *ecget_field(PyObject *me, void *hunoz)
991   { RETURN_OBJ(ECCURVE_FOBJ(me)); }
992
993 static PyObject *ecget_inf(PyObject *me, void *hunoz)
994   { ec inf = EC_INIT; return (ecpt_pywrap(me, &inf)); }
995
996 static PyGetSetDef eccurve_pygetset[] = {
997 #define GETSETNAME(op, name) ec##op##_##name
998   GET   (name,          "E.name -> name of this kind of curve")
999   GET   (a,             "E.a -> first parameter of curve")
1000   GET   (b,             "E.b -> second parameter of curve")
1001   GET   (field,         "E.field -> finite field containing this curve")
1002   GET   (inf,           "E.inf -> point at infinity of this curve")
1003 #undef GETSETNAME
1004   { 0 }
1005 };  
1006
1007 static PyMethodDef eccurve_pymethods[] = {
1008 #define METHNAME(name) ecmeth_##name
1009   METH  (mmul,          "\
1010 E.mmul([(P0, N0), (P1, N1), ...]) = N0 P0 + N1 P1 + ...")
1011   METH  (find,          "E.find(X) -> P")
1012   KWMETH(rand,          "E.rand(rng = rand) ->P")
1013 #undef METHNAME
1014   { 0 }
1015 };
1016
1017 static PyTypeObject eccurve_pytype_skel = {
1018   PyObject_HEAD_INIT(&PyType_Type) 0,   /* Header */
1019   "catacomb.ECCurve",                   /* @tp_name@ */
1020   sizeof(eccurve_pyobj),                /* @tp_basicsize@ */
1021   0,                                    /* @tp_itemsize@ */
1022
1023   eccurve_pydealloc,                    /* @tp_dealloc@ */
1024   0,                                    /* @tp_print@ */
1025   0,                                    /* @tp_getattr@ */
1026   0,                                    /* @tp_setattr@ */
1027   0,                                    /* @tp_compare@ */
1028   0,                                    /* @tp_repr@ */
1029   0,                                    /* @tp_as_number@ */
1030   0,                                    /* @tp_as_sequence@ */
1031   0,                                    /* @tp_as_mapping@ */
1032   0,                                    /* @tp_hash@ */
1033   0,                                    /* @tp_call@ */
1034   0,                                    /* @tp_str@ */
1035   0,                                    /* @tp_getattro@ */
1036   0,                                    /* @tp_setattro@ */
1037   0,                                    /* @tp_as_buffer@ */
1038   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
1039     Py_TPFLAGS_BASETYPE,
1040
1041   /* @tp_doc@ */
1042   "An elliptic curve.  Abstract class.",
1043
1044   0,                                    /* @tp_traverse@ */
1045   0,                                    /* @tp_clear@ */
1046   eccurve_pyrichcompare,                /* @tp_richcompare@ */
1047   0,                                    /* @tp_weaklistoffset@ */
1048   0,                                    /* @tp_iter@ */
1049   0,                                    /* @tp_iternexr@ */
1050   eccurve_pymethods,                    /* @tp_methods@ */
1051   0,                                    /* @tp_members@ */
1052   eccurve_pygetset,                     /* @tp_getset@ */
1053   0,                                    /* @tp_base@ */
1054   0,                                    /* @tp_dict@ */
1055   0,                                    /* @tp_descr_get@ */
1056   0,                                    /* @tp_descr_set@ */
1057   0,                                    /* @tp_dictoffset@ */
1058   0,                                    /* @tp_init@ */
1059   PyType_GenericAlloc,                  /* @tp_alloc@ */
1060   abstract_pynew,                       /* @tp_new@ */
1061   0,                                    /* @tp_free@ */
1062   0                                     /* @tp_is_gc@ */
1063 };
1064
1065 static PyObject *ecprimecurve_pynew(PyTypeObject *ty,
1066                                     PyObject *arg, PyObject *kw)
1067 {
1068   return (eccurve_pynew(ty, ec_prime, arg, kw));
1069 }
1070
1071 static PyTypeObject ecprimecurve_pytype_skel = {
1072   PyObject_HEAD_INIT(&PyType_Type) 0,   /* Header */
1073   "catacomb.ECPrimeCurve",              /* @tp_name@ */
1074   sizeof(eccurve_pyobj),                /* @tp_basicsize@ */
1075   0,                                    /* @tp_itemsize@ */
1076
1077   eccurve_pydealloc,                    /* @tp_dealloc@ */
1078   0,                                    /* @tp_print@ */
1079   0,                                    /* @tp_getattr@ */
1080   0,                                    /* @tp_setattr@ */
1081   0,                                    /* @tp_compare@ */
1082   0,                                    /* @tp_repr@ */
1083   0,                                    /* @tp_as_number@ */
1084   0,                                    /* @tp_as_sequence@ */
1085   0,                                    /* @tp_as_mapping@ */
1086   0,                                    /* @tp_hash@ */
1087   0,                                    /* @tp_call@ */
1088   0,                                    /* @tp_str@ */
1089   0,                                    /* @tp_getattro@ */
1090   0,                                    /* @tp_setattro@ */
1091   0,                                    /* @tp_as_buffer@ */
1092   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
1093     Py_TPFLAGS_BASETYPE,
1094
1095   /* @tp_doc@ */
1096   "An elliptic curve over a prime field.  Use ecprimeprojcurve.",
1097
1098   0,                                    /* @tp_traverse@ */
1099   0,                                    /* @tp_clear@ */
1100   eccurve_pyrichcompare,                /* @tp_richcompare@ */
1101   0,                                    /* @tp_weaklistoffset@ */
1102   0,                                    /* @tp_iter@ */
1103   0,                                    /* @tp_iternexr@ */
1104   0,                                    /* @tp_methods@ */
1105   0,                                    /* @tp_members@ */
1106   0,                                    /* @tp_getset@ */
1107   0,                                    /* @tp_base@ */
1108   0,                                    /* @tp_dict@ */
1109   0,                                    /* @tp_descr_get@ */
1110   0,                                    /* @tp_descr_set@ */
1111   0,                                    /* @tp_dictoffset@ */
1112   0,                                    /* @tp_init@ */
1113   PyType_GenericAlloc,                  /* @tp_alloc@ */
1114   ecprimecurve_pynew,                   /* @tp_new@ */
1115   0,                                    /* @tp_free@ */
1116   0                                     /* @tp_is_gc@ */
1117 };
1118
1119 static PyObject *ecprimeprojcurve_pynew(PyTypeObject *ty,
1120                                         PyObject *arg, PyObject *kw)
1121 {
1122   return (eccurve_pynew(ty, ec_primeproj, arg, kw));
1123 }
1124
1125 static PyTypeObject ecprimeprojcurve_pytype_skel = {
1126   PyObject_HEAD_INIT(&PyType_Type) 0,   /* Header */
1127   "catacomb.ECPrimeProjCurve",          /* @tp_name@ */
1128   sizeof(eccurve_pyobj),                /* @tp_basicsize@ */
1129   0,                                    /* @tp_itemsize@ */
1130
1131   eccurve_pydealloc,                    /* @tp_dealloc@ */
1132   0,                                    /* @tp_print@ */
1133   0,                                    /* @tp_getattr@ */
1134   0,                                    /* @tp_setattr@ */
1135   0,                                    /* @tp_compare@ */
1136   0,                                    /* @tp_repr@ */
1137   0,                                    /* @tp_as_number@ */
1138   0,                                    /* @tp_as_sequence@ */
1139   0,                                    /* @tp_as_mapping@ */
1140   0,                                    /* @tp_hash@ */
1141   0,                                    /* @tp_call@ */
1142   0,                                    /* @tp_str@ */
1143   0,                                    /* @tp_getattro@ */
1144   0,                                    /* @tp_setattro@ */
1145   0,                                    /* @tp_as_buffer@ */
1146   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
1147     Py_TPFLAGS_BASETYPE,
1148
1149   /* @tp_doc@ */
1150   "An elliptic curve over a prime field, using projective coordinates.",
1151
1152   0,                                    /* @tp_traverse@ */
1153   0,                                    /* @tp_clear@ */
1154   eccurve_pyrichcompare,                /* @tp_richcompare@ */
1155   0,                                    /* @tp_weaklistoffset@ */
1156   0,                                    /* @tp_iter@ */
1157   0,                                    /* @tp_iternexr@ */
1158   0,                                    /* @tp_methods@ */
1159   0,                                    /* @tp_members@ */
1160   0,                                    /* @tp_getset@ */
1161   0,                                    /* @tp_base@ */
1162   0,                                    /* @tp_dict@ */
1163   0,                                    /* @tp_descr_get@ */
1164   0,                                    /* @tp_descr_set@ */
1165   0,                                    /* @tp_dictoffset@ */
1166   0,                                    /* @tp_init@ */
1167   PyType_GenericAlloc,                  /* @tp_alloc@ */
1168   ecprimeprojcurve_pynew,               /* @tp_new@ */
1169   0,                                    /* @tp_free@ */
1170   0                                     /* @tp_is_gc@ */
1171 };
1172
1173 static PyObject *ecbincurve_pynew(PyTypeObject *ty,
1174                                   PyObject *arg, PyObject *kw)
1175 {
1176   return (eccurve_pynew(ty, ec_bin, arg, kw));
1177 }
1178
1179 static PyTypeObject ecbincurve_pytype_skel = {
1180   PyObject_HEAD_INIT(&PyType_Type) 0,   /* Header */
1181   "catacomb.ECBinCurve",                /* @tp_name@ */
1182   sizeof(eccurve_pyobj),                /* @tp_basicsize@ */
1183   0,                                    /* @tp_itemsize@ */
1184
1185   eccurve_pydealloc,                    /* @tp_dealloc@ */
1186   0,                                    /* @tp_print@ */
1187   0,                                    /* @tp_getattr@ */
1188   0,                                    /* @tp_setattr@ */
1189   0,                                    /* @tp_compare@ */
1190   0,                                    /* @tp_repr@ */
1191   0,                                    /* @tp_as_number@ */
1192   0,                                    /* @tp_as_sequence@ */
1193   0,                                    /* @tp_as_mapping@ */
1194   0,                                    /* @tp_hash@ */
1195   0,                                    /* @tp_call@ */
1196   0,                                    /* @tp_str@ */
1197   0,                                    /* @tp_getattro@ */
1198   0,                                    /* @tp_setattro@ */
1199   0,                                    /* @tp_as_buffer@ */
1200   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
1201     Py_TPFLAGS_BASETYPE,
1202
1203   /* @tp_doc@ */
1204   "An elliptic curve over a binary field.  Use ecbinprojcurve.",
1205
1206   0,                                    /* @tp_traverse@ */
1207   0,                                    /* @tp_clear@ */
1208   eccurve_pyrichcompare,                /* @tp_richcompare@ */
1209   0,                                    /* @tp_weaklistoffset@ */
1210   0,                                    /* @tp_iter@ */
1211   0,                                    /* @tp_iternexr@ */
1212   0,                                    /* @tp_methods@ */
1213   0,                                    /* @tp_members@ */
1214   0,                                    /* @tp_getset@ */
1215   0,                                    /* @tp_base@ */
1216   0,                                    /* @tp_dict@ */
1217   0,                                    /* @tp_descr_get@ */
1218   0,                                    /* @tp_descr_set@ */
1219   0,                                    /* @tp_dictoffset@ */
1220   0,                                    /* @tp_init@ */
1221   PyType_GenericAlloc,                  /* @tp_alloc@ */
1222   ecbincurve_pynew,                     /* @tp_new@ */
1223   0,                                    /* @tp_free@ */
1224   0                                     /* @tp_is_gc@ */
1225 };
1226
1227 static PyObject *ecbinprojcurve_pynew(PyTypeObject *ty,
1228                                       PyObject *arg, PyObject *kw)
1229 {
1230   return (eccurve_pynew(ty, ec_binproj, arg, kw));
1231 }
1232
1233 static PyTypeObject ecbinprojcurve_pytype_skel = {
1234   PyObject_HEAD_INIT(&PyType_Type) 0,   /* Header */
1235   "catacomb.ECBinProjCurve",            /* @tp_name@ */
1236   sizeof(eccurve_pyobj),                /* @tp_basicsize@ */
1237   0,                                    /* @tp_itemsize@ */
1238
1239   eccurve_pydealloc,                    /* @tp_dealloc@ */
1240   0,                                    /* @tp_print@ */
1241   0,                                    /* @tp_getattr@ */
1242   0,                                    /* @tp_setattr@ */
1243   0,                                    /* @tp_compare@ */
1244   0,                                    /* @tp_repr@ */
1245   0,                                    /* @tp_as_number@ */
1246   0,                                    /* @tp_as_sequence@ */
1247   0,                                    /* @tp_as_mapping@ */
1248   0,                                    /* @tp_hash@ */
1249   0,                                    /* @tp_call@ */
1250   0,                                    /* @tp_str@ */
1251   0,                                    /* @tp_getattro@ */
1252   0,                                    /* @tp_setattro@ */
1253   0,                                    /* @tp_as_buffer@ */
1254   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
1255     Py_TPFLAGS_BASETYPE,
1256
1257   /* @tp_doc@ */
1258   "An elliptic curve over a binary field, using projective coordinates.",
1259
1260   0,                                    /* @tp_traverse@ */
1261   0,                                    /* @tp_clear@ */
1262   eccurve_pyrichcompare,                /* @tp_richcompare@ */
1263   0,                                    /* @tp_weaklistoffset@ */
1264   0,                                    /* @tp_iter@ */
1265   0,                                    /* @tp_iternexr@ */
1266   0,                                    /* @tp_methods@ */
1267   0,                                    /* @tp_members@ */
1268   0,                                    /* @tp_getset@ */
1269   0,                                    /* @tp_base@ */
1270   0,                                    /* @tp_dict@ */
1271   0,                                    /* @tp_descr_get@ */
1272   0,                                    /* @tp_descr_set@ */
1273   0,                                    /* @tp_dictoffset@ */
1274   0,                                    /* @tp_init@ */
1275   PyType_GenericAlloc,                  /* @tp_alloc@ */
1276   ecbinprojcurve_pynew,                 /* @tp_new@ */
1277   0,                                    /* @tp_free@ */
1278   0                                     /* @tp_is_gc@ */
1279 };
1280
1281 /*----- Curve info --------------------------------------------------------*/
1282
1283 static int ncurves = -1;
1284
1285 void ecinfo_copy(ec_info *eic, const ec_info *ei)
1286 {
1287   eic->c = eccurve_copy(ei->c);
1288   EC_CREATE(&eic->g);
1289   EC_COPY(&eic->g, &ei->g);
1290   eic->r = MP_COPY(ei->r);
1291   eic->h = MP_COPY(ei->h);
1292 }
1293
1294 PyObject *ecinfo_pywrap(ec_info *ei)
1295 {
1296   ecinfo_pyobj *o;
1297
1298   o = PyObject_NEW(ecinfo_pyobj, ecinfo_pytype);
1299   o->ei = *ei;
1300   o->cobj = eccurve_pywrap(0, o->ei.c);
1301   Py_INCREF(o->cobj);
1302   return ((PyObject *)o);
1303 }
1304
1305 static void ecinfo_pydealloc(PyObject *me)
1306 {
1307   ec_info *ei = ECINFO_EI(me);
1308   EC_DESTROY(&ei->g);
1309   MP_DROP(ei->r);
1310   MP_DROP(ei->h);
1311   Py_DECREF(ECINFO_COBJ(me));
1312   FREEOBJ(me);
1313 }
1314
1315 static PyObject *ecinfo_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
1316 {
1317   ec_info ei = { 0 };
1318   PyObject *e, *g;
1319   char *kwlist[] = { "curve", "G", "r", "h", 0 };
1320   ecinfo_pyobj *rc = 0;
1321
1322   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O!O&O&:new", kwlist,
1323                                    eccurve_pytype, &e, ecpt_pytype, &g,
1324                                    convmp, &ei.r, convmp, &ei.h))
1325     goto end;
1326   if (ECPT_C(g) != ECCURVE_C(e) && !ec_samep(ECPT_C(g), ECCURVE_C(e)))
1327     TYERR("point not from this curve");
1328   ei.c = ECCURVE_C(e);
1329   EC_CREATE(&ei.g);
1330   EC_COPY(&ei.g, ECPT_P(g));
1331   rc = (ecinfo_pyobj *)ty->tp_alloc(ty, 0);
1332   rc->ei = ei;
1333   rc->cobj = e;
1334   Py_INCREF(rc->cobj);
1335   return ((PyObject *)rc);
1336
1337 end:
1338   mp_drop(ei.r);
1339   mp_drop(ei.h);
1340   return (0);
1341 }
1342
1343 static PyObject *meth__ECInfo_parse(PyObject *me, PyObject *arg)
1344 {
1345   char *p;
1346   qd_parse qd;
1347   ec_info ei;
1348   PyObject *rc = 0;
1349
1350   if (!PyArg_ParseTuple(arg, "Os:parse", &me, &p))
1351     goto end;
1352   qd.p = p;
1353   qd.e = 0;
1354   if (ec_infoparse(&qd, &ei))
1355     SYNERR(qd.e);
1356   rc = Py_BuildValue("(Ns)", ecinfo_pywrap(&ei), qd.p);
1357 end:
1358   return (rc);
1359 }
1360
1361 static PyObject *meth__ECInfo__curven(PyObject *me, PyObject *arg)
1362 {
1363   int i;
1364   ec_info ei;
1365   PyObject *rc = 0;
1366
1367   if (!PyArg_ParseTuple(arg, "Oi:_curven", &me, &i)) goto end;
1368   if (i < 0 || i >= ncurves) VALERR("curve index out of range");
1369   ec_infofromdata(&ei, ectab[i].data);
1370   rc = ecinfo_pywrap(&ei);
1371 end:
1372   return (rc);
1373 }
1374
1375 static PyObject *ecinfo_pyrichcompare(PyObject *x, PyObject *y, int op)
1376 {
1377   int b = ec_sameinfop(ECINFO_EI(x), ECINFO_EI(y));
1378   switch (op) {
1379     case Py_EQ: break;
1380     case Py_NE: b = !b;
1381     default: TYERR("can't order elliptic curve infos");
1382   }
1383   return (getbool(b));
1384 end:
1385   return (0);
1386 }
1387
1388 static PyObject *eimeth_check(PyObject *me, PyObject *arg, PyObject *kw)
1389 {
1390   char *kwlist[] = { "rng", 0 };
1391   grand *r = &rand_global;
1392   const char *p;
1393
1394   if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:check", kwlist,
1395                                    convgrand, &r))
1396     goto end;
1397   if ((p = ec_checkinfo(ECINFO_EI(me), r)) != 0)
1398     VALERR(p);
1399   RETURN_ME;
1400 end:
1401   return (0);
1402 }
1403
1404 static PyObject *eiget_curve(PyObject *me, void *hunoz)
1405   { RETURN_OBJ(ECINFO_COBJ(me)); }
1406
1407 static PyObject *eiget_G(PyObject *me, void *hunoz)
1408 {
1409   ec_info *ei = ECINFO_EI(me);
1410   ec p = EC_INIT;
1411   EC_IN(ei->c, &p, &ei->g);
1412   return (ecpt_pywrap(ECINFO_COBJ(me), &p));
1413 }
1414
1415 static PyObject *eiget_r(PyObject *me, void *hunoz)
1416   { return (mp_pywrap(MP_COPY(ECINFO_EI(me)->r))); }
1417
1418 static PyObject *eiget_h(PyObject *me, void *hunoz)
1419   { return (mp_pywrap(MP_COPY(ECINFO_EI(me)->h))); }
1420
1421 static PyGetSetDef ecinfo_pygetset[] = {
1422 #define GETSETNAME(op, name) ei##op##_##name
1423   GET   (curve,         "I.curve -> the elliptic curve")
1424   GET   (G,             "I.G -> generator point for the group")
1425   GET   (r,             "I.r -> order of the group (and hence of G")
1426   GET   (h,             "I.h -> cofactor of the group")
1427 #undef GETSETNAME
1428   { 0 }
1429 };
1430
1431 static PyMethodDef ecinfo_pymethods[] = {
1432 #define METHNAME(name) eimeth_##name
1433   KWMETH(check,         "I.check() -> None")
1434 #undef METHNAME
1435   { 0 }
1436 };
1437
1438 static PyTypeObject ecinfo_pytype_skel = {
1439   PyObject_HEAD_INIT(&PyType_Type) 0,   /* Header */
1440   "catacomb.ECInfo",                    /* @tp_name@ */
1441   sizeof(ecinfo_pyobj),                 /* @tp_basicsize@ */
1442   0,                                    /* @tp_itemsize@ */
1443
1444   ecinfo_pydealloc,                     /* @tp_dealloc@ */
1445   0,                                    /* @tp_print@ */
1446   0,                                    /* @tp_getattr@ */
1447   0,                                    /* @tp_setattr@ */
1448   0,                                    /* @tp_compare@ */
1449   0,                                    /* @tp_repr@ */
1450   0,                                    /* @tp_as_number@ */
1451   0,                                    /* @tp_as_sequence@ */
1452   0,                                    /* @tp_as_mapping@ */
1453   0,                                    /* @tp_hash@ */
1454   0,                                    /* @tp_call@ */
1455   0,                                    /* @tp_str@ */
1456   0,                                    /* @tp_getattro@ */
1457   0,                                    /* @tp_setattro@ */
1458   0,                                    /* @tp_as_buffer@ */
1459   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
1460     Py_TPFLAGS_BASETYPE,
1461
1462   /* @tp_doc@ */
1463   "Elliptic curve domain parameters.",
1464
1465   0,                                    /* @tp_traverse@ */
1466   0,                                    /* @tp_clear@ */
1467   ecinfo_pyrichcompare,                 /* @tp_richcompare@ */
1468   0,                                    /* @tp_weaklistoffset@ */
1469   0,                                    /* @tp_iter@ */
1470   0,                                    /* @tp_iternexr@ */
1471   ecinfo_pymethods,                     /* @tp_methods@ */
1472   0,                                    /* @tp_members@ */
1473   ecinfo_pygetset,                      /* @tp_getset@ */
1474   0,                                    /* @tp_base@ */
1475   0,                                    /* @tp_dict@ */
1476   0,                                    /* @tp_descr_get@ */
1477   0,                                    /* @tp_descr_set@ */
1478   0,                                    /* @tp_dictoffset@ */
1479   0,                                    /* @tp_init@ */
1480   PyType_GenericAlloc,                  /* @tp_alloc@ */
1481   ecinfo_pynew,                         /* @tp_new@ */
1482   0,                                    /* @tp_free@ */
1483   0                                     /* @tp_is_gc@ */
1484 };
1485
1486 /*----- Setup -------------------------------------------------------------*/
1487
1488 static PyMethodDef methods[] = {
1489 #define METHNAME(func) meth_##func
1490   METH  (_ECPt_frombuf,         "frombuf(E, STR) -> (P, REST)")
1491   METH  (_ECPtCurve_fromraw,    "fromraw(E, STR) -> (P, REST)")
1492   METH  (_ECPt_parse,           "parse(E, STR) -> (P, REST)")
1493   METH  (_ECCurve_parse,        "parse(STR) -> (E, REST)")
1494   METH  (_ECInfo_parse,         "parse(STR) -> (I, REST)")
1495   METH  (_ECInfo__curven,       "_curven(N) -> I")
1496 #undef METHNAME
1497   { 0 }
1498 };
1499
1500 void ec_pyinit(void)
1501 {
1502   INITTYPE(ecpt, root);
1503   INITTYPE(ecptcurve, ecpt);
1504   INITTYPE(eccurve, type);
1505   INITTYPE(ecprimecurve, eccurve);
1506   INITTYPE(ecprimeprojcurve, ecprimecurve);
1507   INITTYPE(ecbincurve, eccurve);
1508   INITTYPE(ecbinprojcurve, ecbincurve);
1509   INITTYPE(ecinfo, root);
1510   addmethods(methods);
1511 }
1512
1513 static PyObject *namedcurves(void)
1514 {
1515   int i, j;
1516   const char *p;
1517   PyObject *d, *c;
1518
1519   d = PyDict_New();
1520   for (i = 0; ectab[i].name; i++) {
1521     p = ectab[i].name;
1522     for (j = 0; j < i; j++) {
1523       if (ectab[i].data == ectab[j].data) {
1524         c = PyDict_GetItemString(d, (/*unconst*/ char *)ectab[j].name);
1525         Py_INCREF(c);
1526         goto found;
1527       }
1528     }
1529     c = PyInt_FromLong(i);
1530   found:
1531     PyDict_SetItemString(d, (/*unconst*/ char *)ectab[i].name, c);
1532     Py_DECREF(c);
1533   }
1534   ncurves = i;
1535   return (d);
1536 }
1537
1538 void ec_pyinsert(PyObject *mod)
1539 {
1540   INSERT("ECPt", ecpt_pytype);
1541   INSERT("ECPtCurve", ecptcurve_pytype);
1542   INSERT("ECCurve", eccurve_pytype);
1543   INSERT("ECPrimeCurve", ecprimecurve_pytype);
1544   INSERT("ECPrimeProjCurve", ecprimeprojcurve_pytype);
1545   INSERT("ECBinCurve", ecbincurve_pytype);
1546   INSERT("ECBinProjCurve", ecbinprojcurve_pytype);
1547   INSERT("ECInfo", ecinfo_pytype);
1548   INSERT("_eccurves", namedcurves());
1549 }
1550
1551 /*----- That's all, folks -------------------------------------------------*/