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