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