chiark / gitweb /
Overhaul formatting.
[catacomb-python] / mp.c
1 /* -*-c-*-
2  *
3  * Multiprecision arithmetic
4  *
5  * (c) 2004 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This file is part of the Python interface to Catacomb.
11  *
12  * Catacomb/Python is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * Catacomb/Python is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with Catacomb/Python; if not, write to the Free Software Foundation,
24  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25  */
26
27 /*----- Header files ------------------------------------------------------*/
28
29 #include "catacomb-python.h"
30
31 /*----- General utilities -------------------------------------------------*/
32
33 PyTypeObject *mp_pytype = 0;
34 PyTypeObject *gf_pytype = 0;
35
36 mp *mp_frompylong(PyObject *obj)
37 {
38   unsigned long bits;
39   PyLongObject *l = (PyLongObject *)obj;
40   int sz;
41   size_t w;
42   mpd r = 0;
43   int b = 0;
44   int i;
45   mp *x;
46   mpw *p;
47
48   sz = l->ob_size;
49   if (sz < 0) sz = -sz;
50   assert(MPW_BITS >= SHIFT);
51   bits = (unsigned long)sz * SHIFT;
52   w = (bits + MPW_BITS - 1)/MPW_BITS;
53   x = mp_new(w, l->ob_size < 0 ? MP_NEG : 0);
54   p = x->v;
55   for (i = 0; i < sz; i++) {
56     r |= (mpd)l->ob_digit[i] << b;
57     b += SHIFT;
58     while (b >= MPW_BITS) {
59       *p++ = MPW(r);
60       r >>= MPW_BITS;
61       b -= MPW_BITS;
62     }
63   }
64   while (r) {
65     *p++ = MPW(r);
66     r >>= MPW_BITS;
67   }
68   x->vl = p;
69   MP_SHRINK(x);
70   return (x);
71 }
72
73 PyObject *mp_topylong(mp *x)
74 {
75   unsigned long bits = mp_bits(x);
76   int sz = (bits + SHIFT - 1)/SHIFT;
77   PyLongObject *l = _PyLong_New(sz);
78   mpd r = 0;
79   int b = 0;
80   mpw *p = x->v;
81   int i = 0;
82
83   assert(MPW_BITS >= SHIFT);
84   while (i < sz && p < x->vl) {
85     r |= (mpd)*p++ << b;
86     b += MPW_BITS;
87     while (i < sz && b >= SHIFT) {
88       l->ob_digit[i++] = r & MASK;
89       r >>= SHIFT;
90       b -= SHIFT;
91     }
92   }
93   while (i < sz && r) {
94     l->ob_digit[i++] = r & MASK;
95     r >>= SHIFT;
96   }
97   l->ob_size = (x->f & MP_NEG) ? -sz : sz;
98   return ((PyObject *)l);
99 }
100
101 mp *mp_frompyobject(PyObject *o, int radix)
102 {
103   mp *x;
104
105   if (PyString_Check(o)) {
106     mptext_stringctx sc;
107     mp *x;
108     sc.buf = PyString_AS_STRING(o);
109     sc.lim = sc.buf + PyString_GET_SIZE(o);
110     x = mp_read(MP_NEW, radix, &mptext_stringops, &sc);
111     if (!x) return (0);
112     if (sc.buf < sc.lim) { MP_DROP(x); return (0); }
113     return (x);
114   }
115   if ((x = tomp(o)) != 0)
116     return (x);
117   return (0);
118 }
119
120 PyObject *mp_topystring(mp *x, int radix, const char *xpre,
121                         const char *pre, const char *post)
122 {
123   int len = mptext_len(x, radix) + 1;
124   mptext_stringctx sc;
125   PyObject *o;
126   size_t xprelen = xpre ? strlen(xpre) : 0;
127   size_t prelen = pre ? strlen(pre) : 0;
128   size_t postlen = post ? strlen(post) : 0;
129   char *p;
130   MP_COPY(x);
131   o = PyString_FromStringAndSize(0, len + 1 + xprelen + prelen + postlen);
132   p = PyString_AS_STRING(o);
133   sc.buf = p;
134   if (xpre) { memcpy(sc.buf, xpre, xprelen); sc.buf += xprelen; }
135   if (MP_NEGP(x)) { *sc.buf++ = '-'; x = mp_neg(x, x); }
136   if (pre) { memcpy(sc.buf, pre, prelen); sc.buf += prelen; }
137   sc.lim = sc.buf + len;
138   mp_write(x, radix, &mptext_stringops, &sc);
139   if (post) { memcpy(sc.buf, post, postlen); sc.buf += postlen; }
140   MP_DROP(x);
141   _PyString_Resize(&o, sc.buf - p);
142   return (o);
143 }
144
145 static int good_radix_p(int r, int readp)
146 {
147   return ((r >= -255 && r <= -2) ||
148           (readp && r == 0) ||
149           (r >= 2 && r <= 62));
150 }
151
152 PyObject *mp_pywrap(mp *x)
153 {
154   mp_pyobj *z = PyObject_New(mp_pyobj, mp_pytype);
155   z->x = x;
156   return ((PyObject *)z);
157 }
158
159 PyObject *gf_pywrap(mp *x)
160 {
161   mp_pyobj *z = PyObject_New(mp_pyobj, gf_pytype);
162   z->x = x;
163   return ((PyObject *)z);
164 }
165
166 int mp_tolong_checked(mp *x, long *l)
167 {
168   static mp *longmin = 0, *longmax = 0;
169   int rc = -1;
170
171   if (!longmax) {
172     longmin = mp_fromlong(MP_NEW, LONG_MIN);
173     longmax = mp_fromlong(MP_NEW, LONG_MAX);
174   }
175   if (MP_CMP(x, <, longmin) || MP_CMP(x, >, longmax))
176     VALERR("mp out of range for int");
177   *l = mp_tolong(x);
178   rc = 0;
179 end:
180   return (rc);
181 }
182
183 /*----- Python interface --------------------------------------------------*/
184
185 static void mp_pydealloc(PyObject *o)
186 {
187   MP_DROP(MP_X(o));
188   FREEOBJ(o);
189 }
190
191 static PyObject *mp_pyrepr(PyObject *o)
192   { return mp_topystring(MP_X(o), 10, "MP(", 0, "L)"); }
193
194 static PyObject *mp_pystr(PyObject *o)
195   { return mp_topystring(MP_X(o), 10, 0, 0, 0); }
196
197 mp *tomp(PyObject *o)
198 {
199   PyObject *l;
200   mp *x;
201
202   if (!o)
203     return (0);
204   else if (MP_PYCHECK(o) || GF_PYCHECK(o))
205     return (MP_COPY(MP_X(o)));
206   else if (FE_PYCHECK(o))
207     return (F_OUT(FE_F(o), MP_NEW, FE_X(o)));
208   else if (PFILT_PYCHECK(o))
209     return (MP_COPY(PFILT_F(o)->m));
210   else if (ECPT_PYCHECK(o)) {
211     ec p = EC_INIT;
212     getecptout(&p, o);
213     x = MP_COPY(p.x);
214     EC_DESTROY(&p);
215     return (x);
216   } else if (GE_PYCHECK(o)) {
217     if ((x = G_TOINT(GE_G(o), MP_NEW, GE_X(o))) == 0)
218       return (0);
219     return (x);
220   } else if (PyInt_Check(o))
221     return (mp_fromlong(MP_NEW, PyInt_AS_LONG(o)));
222   else if ((l = PyNumber_Long(o)) != 0) {
223     x = mp_frompylong(l);
224     Py_DECREF(l);
225     return (x);
226   } else {
227     PyErr_Clear();
228     return (0);
229   }
230 }
231
232 mp *getmp(PyObject *o)
233 {
234   mp *x = 0;
235   if (!o) return (0);
236   if ((x = tomp(o)) == 0) {
237     PyErr_Format(PyExc_TypeError, "can't convert %.100s to mp",
238                  o->ob_type->tp_name);
239   }
240   return (x);
241 }
242
243 int convmp(PyObject *o, void *p)
244 {
245   mp *x;
246   if ((x = getmp(o)) == 0) return (0);
247   *(mp **)p = x;
248   return (1);
249 }
250
251 mp *getgf(PyObject *o)
252 {
253   mp *x = 0;
254   if (!o) return (0);
255   if ((x = tomp(o)) == 0) {
256     PyErr_Format(PyExc_TypeError, "can't convert %.100s to gf",
257                  o->ob_type->tp_name);
258   }
259   return (x);
260 }
261
262 int convgf(PyObject *o, void *p)
263 {
264   mp *x;
265   if ((x = getgf(o)) == 0) return (0);
266   *(mp **)p = x;
267   return (1);
268 }
269
270 static mp *implicitmp(PyObject *o)
271 {
272   if (!o ||
273       GF_PYCHECK(o) ||
274       ECPT_PYCHECK(o) ||
275       FE_PYCHECK(o) ||
276       GE_PYCHECK(o))
277     return (0);
278   return (tomp(o));
279 }
280
281 static mp *implicitgf(PyObject *o)
282 {
283   if (!o ||
284       MP_PYCHECK(o) ||
285       ECPT_PYCHECK(o) ||
286       FE_PYCHECK(o) ||
287       GE_PYCHECK(o))
288     return (0);
289   return (tomp(o));
290 }
291
292 static int mpbinop(PyObject *x, PyObject *y, mp **xx, mp **yy)
293 {
294   if ((*xx = implicitmp(x)) == 0)
295     return (-1);
296   if ((*yy = implicitmp(y)) == 0) {
297     MP_DROP(*xx);
298     return (-1);
299   }
300   return (0);
301 }
302
303 static int gfbinop(PyObject *x, PyObject *y, mp **xx, mp **yy)
304 {
305   if ((*xx = implicitgf(x)) == 0)
306     return (-1);
307   if ((*yy = implicitgf(y)) == 0) {
308     MP_DROP(*xx);
309     return (-1);
310   }
311   return (0);
312 }
313
314 #define gf_and mp_and
315 #define gf_or mp_or
316 #define gf_xor mp_xor
317 #define BINOP(pre, name)                                                \
318   static PyObject *pre##_py##name(PyObject *x, PyObject *y) {           \
319     mp *xx, *yy, *zz;                                                   \
320     if (pre##binop(x, y, &xx, &yy)) RETURN_NOTIMPL;                     \
321     zz = pre##_##name(MP_NEW, xx, yy);                                  \
322     MP_DROP(xx); MP_DROP(yy);                                           \
323     return (pre##_pywrap(zz));                                          \
324   }
325 BINOP(mp, add)
326 BINOP(mp, sub)
327 BINOP(mp, mul)
328 BINOP(mp, and2c)
329 BINOP(mp, or2c)
330 BINOP(mp, xor2c)
331 BINOP(gf, add)
332 BINOP(gf, sub)
333 BINOP(gf, mul)
334 BINOP(gf, and)
335 BINOP(gf, or)
336 BINOP(gf, xor)
337 #undef BINOP
338
339 static mp *mp_abs(mp *d, mp *x)
340 {
341   if (MP_NEGP(x))
342     return (mp_neg(d, x));
343   MP_COPY(x);
344   if (d) MP_DROP(d);
345   return (x);
346 }
347
348 #define UNOP(pre, name)                                                 \
349   static PyObject *pre##_py##name(PyObject *x)                          \
350     { return mp_pywrap(pre##_##name(MP_NEW, MP_X(x))); }
351 UNOP(mp, neg)
352 UNOP(mp, abs)
353 UNOP(mp, not2c)
354 #undef UNOP
355
356 static PyObject *mp_pyid(PyObject *x) { RETURN_OBJ(x); }
357
358 #define gf_lsr mp_lsr
359 #define SHIFTOP(pre, name, rname)                                       \
360   static PyObject *pre##_py##name(PyObject *x, PyObject *y) {           \
361     mp *xx, *yy;                                                        \
362     PyObject *z = 0;                                                    \
363     long n;                                                             \
364     if (pre##binop(x, y, &xx, &yy)) RETURN_NOTIMPL;                     \
365     if (mp_tolong_checked(yy, &n)) goto end;                            \
366     if (n < 0)                                                          \
367       z = pre##_pywrap(mp_##rname(MP_NEW, xx, -n));                     \
368     else                                                                \
369       z = pre##_pywrap(mp_##name(MP_NEW, xx, n));                       \
370   end:                                                                  \
371     MP_DROP(xx); MP_DROP(yy);                                           \
372     return (z);                                                         \
373   }
374 SHIFTOP(mp, lsl2c, lsr2c)
375 SHIFTOP(mp, lsr2c, lsl2c)
376 SHIFTOP(gf, lsl, lsr)
377 SHIFTOP(gf, lsr, lsl)
378 #undef SHIFTOP
379
380 #define DIVOP(pre, name, qq, rr, gather)                                \
381   static PyObject *pre##_py##name(PyObject *x, PyObject *y) {           \
382     mp *xx, *yy;                                                        \
383     PyObject *z = 0;                                                    \
384     INIT_##qq(q) INIT_##rr(r)                                           \
385     if (pre##binop(x, y, &xx, &yy)) RETURN_NOTIMPL;                     \
386     if (MP_ZEROP(yy))                                                   \
387       ZDIVERR("division by zero");                                      \
388     pre##_div(ARG_##qq(q), ARG_##rr(r), xx, yy);                        \
389     z = gather;                                                         \
390   end:                                                                  \
391     MP_DROP(xx); MP_DROP(yy);                                           \
392     return (z);                                                         \
393   }
394 #define INIT_YES(p) mp *p = MP_NEW;
395 #define INIT_NO(p)
396 #define ARG_YES(p) &p
397 #define ARG_NO(p) 0
398 DIVOP(mp, divmod, YES, YES,
399       Py_BuildValue("(NN)", mp_pywrap(q), mp_pywrap(r)))
400 DIVOP(mp, div, YES, NO, mp_pywrap(q))
401 DIVOP(mp, mod, NO, YES, mp_pywrap(r))
402 DIVOP(gf, divmod, YES, YES,
403       Py_BuildValue("(NN)", gf_pywrap(q), gf_pywrap(r)))
404 DIVOP(gf, div, YES, NO, gf_pywrap(q))
405 DIVOP(gf, mod, NO, YES, gf_pywrap(r))
406 #undef INIT_YES
407 #undef INIT_NO
408 #undef ARG_YES
409 #undef ARG_NO
410 #undef DIVOP
411
412 static mp *mp_modinv_checked(mp *d, mp *x, mp *p)
413 {
414   mp *g = MP_NEW;
415   mp_gcd(&g, 0, &d, p, x);
416   if (!MP_EQ(g, MP_ONE)) {
417     MP_DROP(g); MP_DROP(d);
418     PyErr_SetString(PyExc_ZeroDivisionError, "no modular inverse");
419     return (0);
420   }
421   MP_DROP(g); return (d);
422 }
423
424 static PyObject *mp_pyexp(PyObject *x, PyObject *y, PyObject *z)
425 {
426   mp *xx = 0, *yy = 0, *zz = 0;
427   mp *r = 0;
428   PyObject *rc = 0;
429
430   if ((xx = implicitmp(x)) == 0 || (yy = implicitmp(y)) == 0 ||
431       (z && z != Py_None && (zz = tomp(z)) == 0)) {
432     mp_drop(xx); mp_drop(yy); mp_drop(zz);
433     RETURN_NOTIMPL;
434   }
435   if (!z || z == Py_None) {
436     if (MP_NEGP(yy)) VALERR("negative exponent");
437     r = mp_exp(MP_NEW, xx, yy);
438   } else {
439     if (!MP_POSP(zz)) VALERR("modulus must be positive");
440     if (MP_NEGP(yy)) {
441       if ((xx = mp_modinv_checked(xx, xx, zz)) == 0) goto end;
442       yy = mp_neg(yy, yy);
443     }
444     if (MP_ODDP(zz)) {
445       mpmont mm;
446       mpmont_create(&mm, zz);
447       r = mpmont_exp(&mm, MP_NEW, xx, yy);
448       mpmont_destroy(&mm);
449     } else {
450       mpbarrett mb;
451       mpbarrett_create(&mb, zz);
452       r = mpbarrett_exp(&mb, MP_NEW, xx, yy);
453       mpbarrett_destroy(&mb);
454     }
455   }
456   rc = mp_pywrap(r);
457 end:
458   mp_drop(xx); mp_drop(yy); mp_drop(zz);
459   return (rc);
460 }
461
462 static mp *gf_modinv_checked(mp *d, mp *x, mp *p)
463 {
464   mp *g = MP_NEW;
465   gf_gcd(&g, 0, &d, p, x);
466   if (!MP_EQ(g, MP_ONE)) {
467     MP_DROP(g); MP_DROP(d);
468     PyErr_SetString(PyExc_ZeroDivisionError, "no modular inverse");
469     return (0);
470   }
471   MP_DROP(g); return (d);
472 }
473
474 #define BASEOP(name, radix, pre)                                        \
475   static PyObject *mp_py##name(PyObject *x)                             \
476     { return mp_topystring(MP_X(x), radix, 0, pre, 0); }
477 BASEOP(oct, 8, "0");
478 BASEOP(hex, 16, "0x");
479 #undef BASEOP
480
481 static int mp_pynonzerop(PyObject *x) { return !MP_ZEROP(MP_X(x)); }
482
483 static PyObject *mp_pyint(PyObject *x)
484 {
485   long l;
486   if (mp_tolong_checked(MP_X(x), &l)) return (0);
487   return (PyInt_FromLong(l));
488 }
489 static PyObject *mp_pylong(PyObject *x)
490   { return (mp_topylong(MP_X(x))); }
491 static PyObject *mp_pyfloat(PyObject *x)
492 {
493   PyObject *l = mp_topylong(MP_X(x));
494   double f = PyLong_AsDouble(l);
495   Py_DECREF(l);
496   return (PyFloat_FromDouble(f));
497 }
498
499 #define COERCE(pre, PRE)                                                \
500   static int pre##_pycoerce(PyObject **x, PyObject **y)                 \
501   {                                                                     \
502     mp *z;                                                              \
503                                                                         \
504     if (PRE##_PYCHECK(*y)) {                                            \
505       Py_INCREF(*x); Py_INCREF(*y);                                     \
506       return (0);                                                       \
507     }                                                                   \
508     if ((z = tomp(*y)) != 0) {                                          \
509       Py_INCREF(*x);                                                    \
510       *y = pre##_pywrap(z);                                             \
511       return (0);                                                       \
512     }                                                                   \
513     return (1);                                                         \
514   }
515 COERCE(mp, MP)
516 COERCE(gf, GF)
517 #undef COERCE
518
519 static int mp_pycompare(PyObject *x, PyObject *y)
520   { return mp_cmp(MP_X(x), MP_X(y)); }
521
522 static PyObject *mp_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
523 {
524   PyObject *x;
525   mp *z;
526   mp_pyobj *zz = 0;
527   int radix = 0;
528   char *kwlist[] = { "x", "radix", 0 };
529
530   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O|i:new", kwlist, &x, &radix))
531     goto end;
532   if (MP_PYCHECK(x)) RETURN_OBJ(x);
533   if (!good_radix_p(radix, 1)) VALERR("bad radix");
534   if ((z = mp_frompyobject(x, radix)) == 0) {
535     PyErr_Format(PyExc_TypeError, "can't convert %.100s to mp",
536                  x->ob_type->tp_name);
537     goto end;
538   }
539   zz = (mp_pyobj *)ty->tp_alloc(ty, 0);
540   zz->x = z;
541 end:
542   return ((PyObject *)zz);
543 }
544
545 static long mp_pyhash(PyObject *me)
546 {
547   long h;
548   PyObject *l = mp_topylong(MP_X(me)); h = PyObject_Hash(l);
549   Py_DECREF(l); return (h);
550 }
551
552 static PyObject *mpmeth_jacobi(PyObject *me, PyObject *arg)
553 {
554   mp *y = 0;
555   PyObject *z = 0;
556
557   if (!PyArg_ParseTuple(arg, "O&:jacobi", convmp, &y)) goto end;
558   z = PyInt_FromLong(mp_jacobi(y, MP_X(me)));
559 end:
560   if (y) MP_DROP(y);
561   return (z);
562 }
563
564 #define BITOP(pre, name, c)                                             \
565   static PyObject *pre##meth_##name(PyObject *me, PyObject *arg)        \
566   {                                                                     \
567     unsigned long i;                                                    \
568     if (!PyArg_ParseTuple(arg, "O&:" #name, convulong, &i)) return (0); \
569     return (pre##_pywrap(mp_##name##c(MP_NEW, MP_X(me), i)));           \
570   }
571 BITOP(mp, setbit, 2c);
572 BITOP(mp, clearbit, 2c);
573 BITOP(gf, setbit, );
574 BITOP(gf, clearbit, );
575 #undef BITOP
576
577 static PyObject *mpmeth_testbit(PyObject *me, PyObject *arg)
578 {
579   unsigned long i;
580   if (!PyArg_ParseTuple(arg, "O&:testbit", convulong, &i)) return (0);
581   return (getbool(mp_testbit2c(MP_X(me), i)));
582 }
583
584 static PyObject *gfmeth_testbit(PyObject *me, PyObject *arg)
585 {
586   unsigned long i;
587   if (!PyArg_ParseTuple(arg, "O&:testbit", convulong, &i)) return (0);
588   return (getbool(mp_testbit(MP_X(me), i)));
589 }
590
591 static PyObject *mpmeth_odd(PyObject *me, PyObject *arg)
592 {
593   mp *t;
594   size_t s;
595
596   if (!PyArg_ParseTuple(arg, ":odd")) return (0);
597   t = mp_odd(MP_NEW, MP_X(me), &s);
598   return (Py_BuildValue("(lN)", (long)s, mp_pywrap(t)));
599 }
600
601 static PyObject *mpmeth_sqr(PyObject *me, PyObject *arg)
602 {
603   if (!PyArg_ParseTuple(arg, ":sqr")) return (0);
604   return (mp_pywrap(mp_sqr(MP_NEW, MP_X(me))));
605 }
606
607 static PyObject *mpmeth_sqrt(PyObject *me, PyObject *arg)
608 {
609   if (!PyArg_ParseTuple(arg, ":sqrt")) return (0);
610   if (MP_NEGP(MP_X(me))) VALERR("negative root");
611   return (mp_pywrap(mp_sqrt(MP_NEW, MP_X(me))));
612 end:
613   return (0);
614 }
615
616 static PyObject *mpmeth_gcd(PyObject *me, PyObject *arg)
617 {
618   mp *y = 0, *zz = MP_NEW;
619   PyObject *z = 0;
620
621   if (!PyArg_ParseTuple(arg, "O&:gcd", convmp, &y)) goto end;
622   mp_gcd(&zz, 0, 0, MP_X(me), y);
623   z = mp_pywrap(zz);
624 end:
625   if (y) MP_DROP(y);
626   return (z);
627 }
628
629 static PyObject *mpmeth_gcdx(PyObject *me, PyObject *arg)
630 {
631   PyObject *z = 0;
632   mp *yy = 0, *zz = MP_NEW, *uu = MP_NEW, *vv = MP_NEW;
633
634   if (!PyArg_ParseTuple(arg, "O&:gcdx", convmp, &yy)) goto end;
635   mp_gcd(&zz, &uu, &vv, MP_X(me), yy);
636   z = Py_BuildValue("(NNN)",
637                     mp_pywrap(zz), mp_pywrap(uu), mp_pywrap(vv));
638 end:
639   if (yy) MP_DROP(yy);
640   return (z);
641 }
642
643 static PyObject *mpmeth_modinv(PyObject *me, PyObject *arg)
644 {
645   PyObject *z = 0;
646   mp *yy = 0, *zz = MP_NEW;
647
648   if (!PyArg_ParseTuple(arg, "O&:modinv", convmp, &yy) ||
649       (zz = mp_modinv_checked(MP_NEW, yy, MP_X(me))) == 0)
650     goto end;
651   z = mp_pywrap(zz);
652 end:
653   if (yy) MP_DROP(yy);
654   return (z);
655 }
656
657 static PyObject *mpmeth_tostring(PyObject *me, PyObject *arg, PyObject *kw)
658 {
659   int radix = 10;
660   char *kwlist[] = { "radix", 0 };
661   if (!PyArg_ParseTupleAndKeywords(arg, kw, "|i:tostring", kwlist, &radix))
662     goto end;
663   if (!good_radix_p(radix, 0)) VALERR("bad radix");
664   return (mp_topystring(MP_X(me), radix, 0, 0, 0));
665 end:
666   return (0);
667 }
668
669 static PyObject *mpmeth_modsqrt(PyObject *me, PyObject *arg)
670 {
671   PyObject *z = 0;
672   mp *yy = 0, *zz = MP_NEW;
673
674   if (!PyArg_ParseTuple(arg, "O&:modsqrt", convmp, &yy)) goto end;
675   if ((zz = mp_modsqrt(MP_NEW, yy, MP_X(me))) == 0)
676     VALERR("no modular square root");
677   z = mp_pywrap(zz);
678 end:
679   if (yy) MP_DROP(yy);
680   return (z);
681 }
682
683 #define STOREOP(name, c)                                                \
684   static PyObject *mpmeth_##name(PyObject *me,                          \
685                                  PyObject *arg, PyObject *kw)           \
686   {                                                                     \
687     long len = -1;                                                      \
688     char *kwlist[] = { "len", 0 };                                      \
689     PyObject *rc = 0;                                                   \
690                                                                         \
691     if (!PyArg_ParseTupleAndKeywords(arg, kw, "|l:" #name,              \
692                                     kwlist, &len))                      \
693       goto end;                                                         \
694     if (len < 0) {                                                      \
695       len = mp_octets##c(MP_X(me));                                     \
696       if (!len) len = 1;                                                \
697     }                                                                   \
698     rc = bytestring_pywrap(0, len);                                     \
699     mp_##name(MP_X(me), PyString_AS_STRING(rc), len);                   \
700   end:                                                                  \
701     return (rc);                                                        \
702   }
703 STOREOP(storel, )
704 STOREOP(storeb, )
705 STOREOP(storel2c, 2c)
706 STOREOP(storeb2c, 2c)
707 #undef STOREOP
708
709 #define BUFOP(ty, pyty)                                                 \
710   static PyObject *meth__##pyty##_frombuf(PyObject *me, PyObject *arg)  \
711   {                                                                     \
712     buf b;                                                              \
713     char *p;                                                            \
714     int sz;                                                             \
715     PyObject *rc = 0;                                                   \
716     mp *x;                                                              \
717                                                                         \
718     if (!PyArg_ParseTuple(arg, "Os#:frombuf", &me, &p, &sz)) goto end;  \
719     buf_init(&b, p, sz);                                                \
720     if ((x = buf_getmp(&b)) == 0) VALERR("malformed data");             \
721     rc = Py_BuildValue("(NN)", ty##_pywrap(x),                          \
722                        bytestring_pywrapbuf(&b));                       \
723   end:                                                                  \
724     return (rc);                                                        \
725   }
726 BUFOP(mp, MP)
727 BUFOP(gf, GF)
728 #undef BUFOP
729
730 static PyObject *mpmeth_tobuf(PyObject *me, PyObject *arg)
731 {
732   buf b;
733   PyObject *rc;
734   mp *x;
735   size_t n;
736
737   if (!PyArg_ParseTuple(arg, ":tobuf")) return (0);
738   x = MP_X(me);
739   n = mp_octets(x) + 3;
740   rc = bytestring_pywrap(0, n);
741   buf_init(&b, PyString_AS_STRING(rc), n);
742   buf_putmp(&b, x);
743   assert(BOK(&b));
744   _PyString_Resize(&rc, BLEN(&b));
745   return (rc);
746 }
747
748 static PyObject *mpmeth_primep(PyObject *me, PyObject *arg, PyObject *kw)
749 {
750   grand *r = &rand_global;
751   char *kwlist[] = { "rng", 0 };
752   PyObject *rc = 0;
753
754   if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&", kwlist, convgrand, &r))
755     goto end;
756   rc = getbool(pgen_primep(MP_X(me), r));
757 end:
758   return (rc);
759 }
760
761 static PyObject *mpget_nbits(PyObject *me, void *hunoz)
762   { return (PyInt_FromLong(mp_bits(MP_X(me)))); }
763
764 static PyObject *mpget_noctets(PyObject *me, void *hunoz)
765   { return (PyInt_FromLong(mp_octets(MP_X(me)))); }
766
767 static PyObject *mpget_noctets2c(PyObject *me, void *hunoz)
768   { return (PyInt_FromLong(mp_octets2c(MP_X(me)))); }
769
770 static PyGetSetDef mp_pygetset[] = {
771 #define GETSETNAME(op, func) mp##op##_##func
772   GET   (nbits,         "X.nbits -> bit length of X")
773   GET   (noctets,       "X.noctets -> octet length of X")
774   GET   (noctets2c,     "X.noctets2c -> two's complement octet length of X")
775 #undef GETSETNAME
776   { 0 }
777 };
778
779 static PyMethodDef mp_pymethods[] = {
780 #define METHNAME(func) mpmeth_##func
781   METH  (jacobi,        "X.jacobi(Y) -> Jacobi symbol (Y/X) (NB inversion!)")
782   METH  (setbit,        "X.setbit(N) -> X with bit N set")
783   METH  (clearbit,      "X.clearbit(N) -> X with bit N clear")
784   METH  (testbit,       "X.testbit(N) -> true/false if bit N set/clear in X")
785   METH  (odd,           "X.odd() -> S, T where X = 2^S T with T odd")
786   METH  (sqr,           "X.sqr() -> X^2")
787   METH  (sqrt,          "X.sqrt() -> largest integer <= sqrt(X)")
788   METH  (gcd,           "X.gcd(Y) -> gcd(X, Y)")
789   METH  (gcdx,
790          "X.gcdx(Y) -> (gcd(X, Y), U, V) with X U + Y V = gcd(X, Y)")
791   METH  (modinv,        "X.modinv(Y) -> multiplicative inverse of Y mod X")
792   METH  (modsqrt,       "X.modsqrt(Y) -> square root of Y mod X, if X prime")
793   KWMETH(primep,        "X.primep(rng = rand) -> true/false if X is prime")
794   KWMETH(tostring,      "X.tostring(radix = 10) -> STR")
795   KWMETH(storel,        "X.storel(len = -1) -> little-endian bytes")
796   KWMETH(storeb,        "X.storeb(len = -1) -> big-endian bytes")
797   KWMETH(storel2c,
798          "X.storel2c(len = -1) -> little-endian bytes, two's complement")
799   KWMETH(storeb2c,
800          "X.storeb2c(len = -1) -> big-endian bytes, two's complement")
801   METH  (tobuf,         "X.tobuf() -> buffer format")
802 #undef METHNAME
803   { 0 }
804 };
805
806 static PyNumberMethods mp_pynumber = {
807   mp_pyadd,                             /* @nb_add@ */
808   mp_pysub,                             /* @nb_subtract@ */
809   mp_pymul,                             /* @nb_multiply@ */
810   0,                                    /* @nb_divide@ */
811   mp_pymod,                             /* @nb_remainder@ */
812   mp_pydivmod,                          /* @nb_divmod@ */
813   mp_pyexp,                             /* @nb_power@ */
814   mp_pyneg,                             /* @nb_negative@ */
815   mp_pyid,                              /* @nb_positive@ */
816   mp_pyabs,                             /* @nb_absolute@ */
817   mp_pynonzerop,                        /* @nb_nonzero@ */
818   mp_pynot2c,                           /* @nb_invert@ */
819   mp_pylsl2c,                           /* @nb_lshift@ */
820   mp_pylsr2c,                           /* @nb_rshift@ */
821   mp_pyand2c,                           /* @nb_and@ */
822   mp_pyxor2c,                           /* @nb_xor@ */
823   mp_pyor2c,                            /* @nb_or@ */
824   mp_pycoerce,                          /* @nb_coerce@ */
825   mp_pyint,                             /* @nb_int@ */
826   mp_pylong,                            /* @nb_long@ */
827   mp_pyfloat,                           /* @nb_float@ */
828   mp_pyoct,                             /* @nb_oct@ */
829   mp_pyhex,                             /* @nb_hex@ */
830
831   0,                                    /* @nb_inplace_add@ */
832   0,                                    /* @nb_inplace_subtract@ */
833   0,                                    /* @nb_inplace_multiply@ */
834   0,                                    /* @nb_inplace_divide@ */
835   0,                                    /* @nb_inplace_remainder@ */
836   0,                                    /* @nb_inplace_power@ */
837   0,                                    /* @nb_inplace_lshift@ */
838   0,                                    /* @nb_inplace_rshift@ */
839   0,                                    /* @nb_inplace_and@ */
840   0,                                    /* @nb_inplace_xor@ */
841   0,                                    /* @nb_inplace_or@ */
842
843   mp_pydiv,                             /* @nb_floor_divide@ */
844   0,                                    /* @nb_true_divide@ */
845   0,                                    /* @nb_inplace_floor_divide@ */
846   0,                                    /* @nb_inplace_true_divide@ */
847 };
848
849 static PyTypeObject mp_pytype_skel = {
850   PyObject_HEAD_INIT(0) 0,              /* Header */
851   "catacomb.MP",                        /* @tp_name@ */
852   sizeof(mp_pyobj),                     /* @tp_basicsize@ */
853   0,                                    /* @tp_itemsize@ */
854
855   mp_pydealloc,                         /* @tp_dealloc@ */
856   0,                                    /* @tp_print@ */
857   0,                                    /* @tp_getattr@ */
858   0,                                    /* @tp_setattr@ */
859   mp_pycompare,                         /* @tp_compare@ */
860   mp_pyrepr,                            /* @tp_repr@ */
861   &mp_pynumber,                         /* @tp_as_number@ */
862   0,                                    /* @tp_as_sequence@ */
863   0,                                    /* @tp_as_mapping@ */
864   mp_pyhash,                            /* @tp_hash@ */
865   0,                                    /* @tp_call@ */
866   mp_pystr,                             /* @tp_str@ */
867   0,                                    /* @tp_getattro@ */
868   0,                                    /* @tp_setattro@ */
869   0,                                    /* @tp_as_buffer@ */
870   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
871     Py_TPFLAGS_CHECKTYPES |
872     Py_TPFLAGS_BASETYPE,
873
874   /* @tp_doc@ */
875 "Multiprecision integers, similar to `long' but more efficient and\n\
876 versatile.  Support all the standard arithmetic operations.\n\
877 \n\
878 Constructor mp(X, radix = R) attempts to convert X to an `mp'.  If\n\
879 X is a string, it's read in radix-R form, or we look for a prefix\n\
880 if R = 0.  Other acceptable things are ints and longs.\n\
881 \n\
882 Notes:\n\
883 \n\
884   * Use `//' for division.  MPs don't have `/' division.",
885
886   0,                                    /* @tp_traverse@ */
887   0,                                    /* @tp_clear@ */
888   0,                                    /* @tp_richcompare@ */
889   0,                                    /* @tp_weaklistoffset@ */
890   0,                                    /* @tp_iter@ */
891   0,                                    /* @tp_iternext@ */
892   mp_pymethods,                         /* @tp_methods@ */
893   0,                                    /* @tp_members@ */
894   mp_pygetset,                          /* @tp_getset@ */
895   0,                                    /* @tp_base@ */
896   0,                                    /* @tp_dict@ */
897   0,                                    /* @tp_descr_get@ */
898   0,                                    /* @tp_descr_set@ */
899   0,                                    /* @tp_dictoffset@ */
900   0,                                    /* @tp_init@ */
901   PyType_GenericAlloc,                  /* @tp_alloc@ */
902   mp_pynew,                             /* @tp_new@ */
903   0,                                    /* @tp_free@ */
904   0                                     /* @tp_is_gc@ */
905 };
906
907 static PyObject *meth__MP_fromstring(PyObject *me,
908                                      PyObject *arg, PyObject *kw)
909 {
910   int r = 0;
911   char *p;
912   int len;
913   PyObject *z = 0;
914   mp *zz;
915   mptext_stringctx sc;
916   char *kwlist[] = { "class", "x", "radix", 0 };
917
918   if (!PyArg_ParseTupleAndKeywords(arg, kw, "Os#|i:fromstring",
919                                    kwlist, &me, &p, &len, &r))
920     goto end;
921   if (!good_radix_p(r, 1)) VALERR("bad radix");
922   sc.buf = p; sc.lim = p + len;
923   if ((zz = mp_read(MP_NEW, r, &mptext_stringops, &sc)) == 0)
924     SYNERR("bad integer");
925   z = Py_BuildValue("(Ns#)", mp_pywrap(zz), sc.buf, (int)(sc.lim - sc.buf));
926 end:
927   return (z);
928 }
929
930 #define LOADOP(pre, py, name)                                           \
931   static PyObject *meth__##py##_##name(PyObject *me, PyObject *arg)     \
932   {                                                                     \
933     char *p;                                                            \
934     int len;                                                            \
935     if (!PyArg_ParseTuple(arg, "Os#:" #name, &me, &p, &len)) return (0); \
936     return (pre##_pywrap(mp_##name(MP_NEW, p, len)));                   \
937   }
938 LOADOP(mp, MP, loadl)
939 LOADOP(mp, MP, loadb)
940 LOADOP(mp, MP, loadl2c)
941 LOADOP(mp, MP, loadb2c)
942 LOADOP(gf, GF, loadl)
943 LOADOP(gf, GF, loadb)
944 #undef LOADOP
945
946 /*----- Products of small integers ----------------------------------------*/
947
948 typedef struct mpmul_pyobj {
949   PyObject_HEAD
950   int livep;
951   mpmul mm;
952 } mpmul_pyobj;
953
954 #define MPMUL_LIVEP(o) (((mpmul_pyobj *)(o))->livep)
955 #define MPMUL_PY(o) (&((mpmul_pyobj *)(o))->mm)
956
957 static void mpmul_pydealloc(PyObject *me)
958 {
959   if (MPMUL_LIVEP(me))
960     mp_drop(mpmul_done(MPMUL_PY(me)));
961   FREEOBJ(me);
962 }
963
964 static PyObject *mmmeth_factor(PyObject *me, PyObject *arg)
965 {
966   PyObject *q, *i;
967   mp *x;
968
969   if (!MPMUL_LIVEP(me)) VALERR("MPMul object invalid");
970   if (PyTuple_Size(arg) != 1)
971     i = PyObject_GetIter(arg);
972   else {
973     if ((q = PyTuple_GetItem(arg, 0)) == 0) goto end;
974     if ((i = PyObject_GetIter(q)) == 0) {
975       PyErr_Clear(); /* that's ok */
976       i = PyObject_GetIter(arg);
977     }
978   }
979   if (!i) goto end;
980   while ((q = PyIter_Next(i)) != 0) {
981     x = getmp(q); Py_DECREF(q); if (!x) {
982       Py_DECREF(i);
983       goto end;
984     }
985     mpmul_add(MPMUL_PY(me), x);
986     MP_DROP(x);
987   }
988   Py_DECREF(i);
989   RETURN_ME;
990 end:
991   return (0);
992 }
993
994 static PyObject *mmmeth_done(PyObject *me, PyObject *arg)
995 {
996   mp *x;
997
998   if (!PyArg_ParseTuple(arg, ":done")) goto end;
999   if (!MPMUL_LIVEP(me)) VALERR("MPMul object invalid");
1000   x = mpmul_done(MPMUL_PY(me));
1001   MPMUL_LIVEP(me) = 0;
1002   return (mp_pywrap(x));
1003 end:
1004   return (0);
1005 }
1006
1007 static PyObject *mpmul_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
1008 {
1009   mpmul_pyobj *mm;
1010
1011   if (kw) TYERR("keyword arguments not allowed here");
1012   mm = (mpmul_pyobj *)ty->tp_alloc(ty, 0);
1013   mpmul_init(&mm->mm);
1014   mm->livep = 1;
1015   if (mmmeth_factor((PyObject *)mm, arg) == 0) {
1016     Py_DECREF(mm);
1017     goto end;
1018   }
1019   return ((PyObject *)mm);
1020 end:
1021   return (0);
1022 }
1023
1024 static PyObject *mmget_livep(PyObject *me, void *hunoz)
1025   { return (getbool(MPMUL_LIVEP(me))); }
1026
1027 static PyGetSetDef mpmul_pygetset[] = {
1028 #define GETSETNAME(op, name) mm##op##_##name
1029   GET   (livep,                 "MM.livep -> flag: object still valid?")
1030 #undef GETSETNAME
1031   { 0 }
1032 };
1033
1034 static PyMethodDef mpmul_pymethods[] = {
1035 #define METHNAME(name) mmmeth_##name
1036   METH  (factor,                "MM.factor(ITERABLE) or MM.factor(I, ...)")
1037   METH  (done,                  "MM.done() -> PRODUCT")
1038 #undef METHNAME
1039   { 0 }
1040 };
1041
1042 static PyTypeObject *mpmul_pytype, mpmul_pytype_skel = {
1043   PyObject_HEAD_INIT(0) 0,              /* Header */
1044   "catacomb.MPMul",                     /* @tp_name@ */
1045   sizeof(mpmul_pyobj),                  /* @tp_basicsize@ */
1046   0,                                    /* @tp_itemsize@ */
1047
1048   mpmul_pydealloc,                      /* @tp_dealloc@ */
1049   0,                                    /* @tp_print@ */
1050   0,                                    /* @tp_getattr@ */
1051   0,                                    /* @tp_setattr@ */
1052   0,                                    /* @tp_compare@ */
1053   0,                                    /* @tp_repr@ */
1054   0,                                    /* @tp_as_number@ */
1055   0,                                    /* @tp_as_sequence@ */
1056   0,                                    /* @tp_as_mapping@ */
1057   0,                                    /* @tp_hash@ */
1058   0,                                    /* @tp_call@ */
1059   0,                                    /* @tp_str@ */
1060   0,                                    /* @tp_getattro@ */
1061   0,                                    /* @tp_setattro@ */
1062   0,                                    /* @tp_as_buffer@ */
1063   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
1064     Py_TPFLAGS_BASETYPE,
1065
1066   /* @tp_doc@ */
1067 "An object for multiplying many small integers.",
1068
1069   0,                                    /* @tp_traverse@ */
1070   0,                                    /* @tp_clear@ */
1071   0,                                    /* @tp_richcompare@ */
1072   0,                                    /* @tp_weaklistoffset@ */
1073   0,                                    /* @tp_iter@ */
1074   0,                                    /* @tp_iternext@ */
1075   mpmul_pymethods,                      /* @tp_methods@ */
1076   0,                                    /* @tp_members@ */
1077   mpmul_pygetset,                       /* @tp_getset@ */
1078   0,                                    /* @tp_base@ */
1079   0,                                    /* @tp_dict@ */
1080   0,                                    /* @tp_descr_get@ */
1081   0,                                    /* @tp_descr_set@ */
1082   0,                                    /* @tp_dictoffset@ */
1083   0,                                    /* @tp_init@ */
1084   PyType_GenericAlloc,                  /* @tp_alloc@ */
1085   mpmul_pynew,                          /* @tp_new@ */
1086   0,                                    /* @tp_free@ */
1087   0                                     /* @tp_is_gc@ */
1088 };
1089
1090 /*----- Montgomery reduction ----------------------------------------------*/
1091
1092 typedef struct mpmont_pyobj {
1093   PyObject_HEAD
1094   mpmont mm;
1095 } mpmont_pyobj;
1096
1097 #define MPMONT_PY(o) (&((mpmont_pyobj *)(o))->mm)
1098
1099 static PyObject *mmmeth_int(PyObject *me, PyObject *arg)
1100 {
1101   PyObject *z = 0;
1102   mp *yy = 0;
1103   mpmont *mm = MPMONT_PY(me);
1104
1105   if (!PyArg_ParseTuple(arg, "O&:in", convmp, &yy))
1106     goto end;
1107   mp_div(0, &yy, yy, mm->m);
1108   z = mp_pywrap(mpmont_mul(mm, MP_NEW, yy, mm->r2));
1109 end:
1110   if (yy) MP_DROP(yy);
1111   return (z);
1112 }
1113
1114 static PyObject *mmmeth_mul(PyObject *me, PyObject *arg)
1115 {
1116   PyObject *rc = 0;
1117   mp *yy = 0, *zz = 0;
1118
1119   if (!PyArg_ParseTuple(arg, "O&O&:mul", convmp, &yy, convmp, &zz))
1120     goto end;
1121   rc = mp_pywrap(mpmont_mul(MPMONT_PY(me), MP_NEW, yy, zz));
1122 end:
1123   if (yy) MP_DROP(yy); if (zz) MP_DROP(zz);
1124   return (rc);
1125 }
1126
1127 static PyObject *mmmeth_exp(PyObject *me, PyObject *arg)
1128 {
1129   PyObject *rc = 0;
1130   mp *yy = 0, *zz = 0;
1131
1132   if (!PyArg_ParseTuple(arg, "O&O&:exp", convmp, &yy, convmp, &zz))
1133     goto end;
1134   if (MP_NEGP(zz)) {
1135     if ((yy = mp_modinv_checked(yy, yy, MPMONT_PY(me)->m)) == 0) goto end;
1136     zz = mp_neg(zz, zz);
1137   }
1138   rc = mp_pywrap(mpmont_exp(MPMONT_PY(me), MP_NEW, yy, zz));
1139 end:
1140   if (yy) MP_DROP(yy); if (zz) MP_DROP(zz);
1141   return (rc);
1142 }
1143
1144 static PyObject *mmmeth_expr(PyObject *me, PyObject *arg)
1145 {
1146   PyObject *rc = 0;
1147   mp *yy = 0, *zz = 0;
1148
1149   if (!PyArg_ParseTuple(arg, "O&O&:expr", convmp, &yy, convmp, &zz))
1150     goto end;
1151   if (MP_NEGP(zz)) {
1152     yy = mpmont_reduce(MPMONT_PY(me), yy, yy);
1153     if ((yy = mp_modinv_checked(yy, yy, MPMONT_PY(me)->m)) == 0) goto end;
1154     yy = mpmont_mul(MPMONT_PY(me), yy, yy, MPMONT_PY(me)->r2);
1155     zz = mp_neg(zz, zz);
1156   }
1157   rc = mp_pywrap(mpmont_expr(MPMONT_PY(me), MP_NEW, yy, zz));
1158 end:
1159   if (yy) MP_DROP(yy); if (zz) MP_DROP(zz);
1160   return (rc);
1161 }
1162
1163 static PyObject *mm_mexpr_id(PyObject *me)
1164   { return mp_pywrap(MP_COPY(MPMONT_PY(me)->r)); }
1165
1166 static int mm_mexpr_fill(void *p, PyObject *me, PyObject *x, PyObject *y)
1167 {
1168   mp *xx = 0, *yy = 0;
1169   mp_expfactor *f = p;
1170   mpmont *mm = MPMONT_PY(me);
1171
1172   if ((xx = getmp(x)) == 0 || (yy = getmp(y)) == 0)
1173     goto fail;
1174   if (MP_NEGP(yy)) {
1175     xx = mpmont_reduce(mm, xx, xx);
1176     if ((xx = mp_modinv_checked(xx, xx, yy)) == 0)
1177       goto fail;
1178     xx = mpmont_mul(mm, xx, xx, mm->r2);
1179     yy = mp_neg(yy, yy);
1180   }
1181   f->base = xx;
1182   f->exp = yy;
1183   return (0);
1184
1185 fail:
1186   mp_drop(xx); mp_drop(yy);
1187   return (-1);
1188 }
1189
1190 static PyObject *mm_mexpr(PyObject *me, void *v, int n)
1191   { return mp_pywrap(mpmont_mexpr(MPMONT_PY(me), MP_NEW, v, n)); }
1192
1193 static void mp_mexp_drop(void *p)
1194 {
1195   mp_expfactor *f = p;
1196   mp_drop(f->base);
1197   mp_drop(f->exp);
1198 }
1199
1200 static PyObject *mmmeth_mexpr(PyObject *me, PyObject *arg)
1201 {
1202   return mexp_common(me, arg, sizeof(mp_expfactor),
1203                      mm_mexpr_id, mm_mexpr_fill, mm_mexpr, mp_mexp_drop);
1204 }
1205
1206 static PyObject *mp_mexp_id(PyObject *me)
1207   { return mp_pywrap(MP_ONE); }
1208
1209 static int mp_mexp_fill(void *p, PyObject *me, PyObject *x, PyObject *y)
1210 {
1211   mp *xx = 0, *yy = 0;
1212   mp_expfactor *f = p;
1213
1214   if ((xx = getmp(x)) == 0 || (yy = getmp(y)) == 0)
1215     goto fail;
1216   if (MP_NEGP(yy)) {
1217     if ((xx = mp_modinv_checked(xx, xx, yy)) == 0)
1218       goto fail;
1219     yy = mp_neg(yy, yy);
1220   }
1221   f->base = xx;
1222   f->exp = yy;
1223   return (0);
1224
1225 fail:
1226   mp_drop(xx); mp_drop(yy);
1227   return (-1);
1228 }
1229
1230 static PyObject *mm_mexp(PyObject *me, void *v, int n)
1231   { return mp_pywrap(mpmont_mexp(MPMONT_PY(me), MP_NEW, v, n)); }
1232
1233 static PyObject *mmmeth_mexp(PyObject *me, PyObject *arg)
1234 {
1235   return mexp_common(me, arg, sizeof(mp_expfactor),
1236                      mp_mexp_id, mp_mexp_fill, mm_mexp, mp_mexp_drop);
1237 }
1238
1239 #define mmmeth_ext mmmeth_reduce
1240 static PyObject *mmmeth_reduce(PyObject *me, PyObject *arg)
1241 {
1242   PyObject *z = 0;
1243   mp *yy = 0;
1244
1245   if (!PyArg_ParseTuple(arg, "O&", convmp, &yy)) goto end;
1246   z = mp_pywrap(mpmont_reduce(MPMONT_PY(me), MP_NEW, yy));
1247 end:
1248   return (z);
1249 }
1250
1251 static void mpmont_pydealloc(PyObject *me)
1252 {
1253   mpmont_destroy(MPMONT_PY(me));
1254   FREEOBJ(me);
1255 }
1256
1257 static PyObject *mpmont_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
1258 {
1259   mpmont_pyobj *mm = 0;
1260   char *kwlist[] = { "m", 0 };
1261   mp *xx = 0;
1262
1263   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:new", kwlist, convmp, &xx))
1264     goto end;
1265   if (!MP_POSP(xx) || !MP_ODDP(xx)) VALERR("m must be positive and odd");
1266   mm = (mpmont_pyobj *)ty->tp_alloc(ty, 0);
1267   mpmont_create(&mm->mm, xx);
1268 end:
1269   if (xx) MP_DROP(xx);
1270   return ((PyObject *)mm);
1271 }
1272
1273 static PyObject *mmget_m(PyObject *me, void *hunoz)
1274   { return (mp_pywrap(MP_COPY(MPMONT_PY(me)->m))); }
1275
1276 static PyObject *mmget_r(PyObject *me, void *hunoz)
1277   { return (mp_pywrap(MP_COPY(MPMONT_PY(me)->r))); }
1278
1279 static PyObject *mmget_r2(PyObject *me, void *hunoz)
1280   { return (mp_pywrap(MP_COPY(MPMONT_PY(me)->r2))); }
1281
1282 static PyGetSetDef mpmont_pygetset[] = {
1283 #define GETSETNAME(op, name) mm##op##_##name
1284   GET   (m,             "M.m -> modulus for reduction")
1285   GET   (r,             "M.r -> multiplicative identity")
1286   GET   (r2,            "M.r2 -> M.r^2, Montgomerization factor")
1287 #undef GETSETNAME
1288   { 0 }
1289 };
1290
1291 static PyMethodDef mpmont_pymethods[] = {
1292 #define METHNAME(name) mmmeth_##name
1293   METH  (int,           "M.out(X) -> XR")
1294   METH  (mul,           "M.mul(XR, YR) -> ZR where Z = X Y")
1295   METH  (expr,          "M.expr(XR, N) -> ZR where Z = X^N mod M.m")
1296   METH  (mexpr,         "\
1297 B.mexp([(XR0, N0), (XR1, N1), ...]) = ZR where Z = X0^N0 X1^N1 mod B.m\n\
1298 \t(the list may be flattened if this more convenient.)")
1299   METH  (reduce,        "M.reduce(XR) -> X")
1300   METH  (ext,           "M.ext(XR) -> X")
1301   METH  (exp,           "M.exp(X, N) -> X^N mod M.m")
1302   METH  (mexp,          "\
1303 B.mexp([(X0, N0), (X1, N1), ...]) = X0^N0 X1^N1 mod B.m\n\
1304 \t(the list may be flattened if this more convenient.)")
1305 #undef METHNAME
1306   { 0 }
1307 };
1308
1309 static PyTypeObject *mpmont_pytype, mpmont_pytype_skel = {
1310   PyObject_HEAD_INIT(0) 0,              /* Header */
1311   "catacomb.MPMont",                    /* @tp_name@ */
1312   sizeof(mpmont_pyobj),                 /* @tp_basicsize@ */
1313   0,                                    /* @tp_itemsize@ */
1314
1315   mpmont_pydealloc,                     /* @tp_dealloc@ */
1316   0,                                    /* @tp_print@ */
1317   0,                                    /* @tp_getattr@ */
1318   0,                                    /* @tp_setattr@ */
1319   0,                                    /* @tp_compare@ */
1320   0,                                    /* @tp_repr@ */
1321   0,                                    /* @tp_as_number@ */
1322   0,                                    /* @tp_as_sequence@ */
1323   0,                                    /* @tp_as_mapping@ */
1324   0,                                    /* @tp_hash@ */
1325   0,                                    /* @tp_call@ */
1326   0,                                    /* @tp_str@ */
1327   0,                                    /* @tp_getattro@ */
1328   0,                                    /* @tp_setattro@ */
1329   0,                                    /* @tp_as_buffer@ */
1330   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
1331     Py_TPFLAGS_BASETYPE,
1332
1333   /* @tp_doc@ */
1334 "A Montgomery reduction context.",
1335
1336   0,                                    /* @tp_traverse@ */
1337   0,                                    /* @tp_clear@ */
1338   0,                                    /* @tp_richcompare@ */
1339   0,                                    /* @tp_weaklistoffset@ */
1340   0,                                    /* @tp_iter@ */
1341   0,                                    /* @tp_iternext@ */
1342   mpmont_pymethods,                     /* @tp_methods@ */
1343   0,                                    /* @tp_members@ */
1344   mpmont_pygetset,                      /* @tp_getset@ */
1345   0,                                    /* @tp_base@ */
1346   0,                                    /* @tp_dict@ */
1347   0,                                    /* @tp_descr_get@ */
1348   0,                                    /* @tp_descr_set@ */
1349   0,                                    /* @tp_dictoffset@ */
1350   0,                                    /* @tp_init@ */
1351   PyType_GenericAlloc,                  /* @tp_alloc@ */
1352   mpmont_pynew,                         /* @tp_new@ */
1353   0,                                    /* @tp_free@ */
1354   0                                     /* @tp_is_gc@ */
1355 };
1356
1357 /*----- Barrett reduction -------------------------------------------------*/
1358
1359 typedef struct mpbarrett_pyobj {
1360   PyObject_HEAD
1361   mpbarrett mb;
1362 } mpbarrett_pyobj;
1363
1364 #define MPBARRETT_PY(o) (&((mpbarrett_pyobj *)(o))->mb)
1365
1366 static PyObject *mbmeth_exp(PyObject *me, PyObject *arg)
1367 {
1368   PyObject *rc = 0;
1369   mp *yy = 0, *zz = 0;
1370
1371   if (!PyArg_ParseTuple(arg, "O&O&:exp", convmp, &yy, convmp, &zz))
1372     goto end;
1373   if (MP_NEGP(zz)) {
1374     if ((yy = mp_modinv_checked(yy, yy, MPBARRETT_PY(me)->m)) == 0) goto end;
1375     zz = mp_neg(zz, zz);
1376   }
1377   rc = mp_pywrap(mpbarrett_exp(MPBARRETT_PY(me), MP_NEW, yy, zz));
1378 end:
1379   if (yy) MP_DROP(yy); if (zz) MP_DROP(zz);
1380   return (rc);
1381 }
1382
1383 static PyObject *mb_mexp(PyObject *me, void *v, int n)
1384   { return mp_pywrap(mpbarrett_mexp(MPBARRETT_PY(me), MP_NEW, v, n)); }
1385
1386 static PyObject *mbmeth_mexp(PyObject *me, PyObject *arg)
1387 {
1388   return mexp_common(me, arg, sizeof(mp_expfactor),
1389                      mp_mexp_id, mp_mexp_fill, mb_mexp, mp_mexp_drop);
1390 }
1391
1392 static PyObject *mbmeth_reduce(PyObject *me, PyObject *arg)
1393 {
1394   PyObject *z = 0;
1395   mp *yy = 0;
1396
1397   if (!PyArg_ParseTuple(arg, "O&:reduce", convmp, &yy))
1398     goto end;
1399   z = mp_pywrap(mpbarrett_reduce(MPBARRETT_PY(me), MP_NEW, yy));
1400 end:
1401   return (z);
1402 }
1403
1404 static void mpbarrett_pydealloc(PyObject *me)
1405 {
1406   mpbarrett_destroy(MPBARRETT_PY(me));
1407   FREEOBJ(me);
1408 }
1409
1410 static PyObject *mpbarrett_pynew(PyTypeObject *ty,
1411                                  PyObject *arg, PyObject *kw)
1412 {
1413   mpbarrett_pyobj *mb = 0;
1414   char *kwlist[] = { "m", 0 };
1415   mp *xx = 0;
1416
1417   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:new", kwlist, convmp, &xx))
1418     goto end;
1419   if (!MP_POSP(xx)) VALERR("m must be positive");
1420   mb = (mpbarrett_pyobj *)ty->tp_alloc(ty, 0);
1421   mpbarrett_create(&mb->mb, xx);
1422 end:
1423   if (xx) MP_DROP(xx);
1424   return ((PyObject *)mb);
1425 }
1426
1427 static PyObject *mbget_m(PyObject *me, void *hunoz)
1428   { return (mp_pywrap(MP_COPY(MPBARRETT_PY(me)->m))); }
1429
1430 static PyGetSetDef mpbarrett_pygetset[] = {
1431 #define GETSETNAME(op, name) mb##op##_##name
1432   GET   (m,             "B.m -> modulus for reduction")
1433 #undef GETSETNAME
1434   { 0 }
1435 };
1436
1437 static PyMethodDef mpbarrett_pymethods[] = {
1438 #define METHNAME(name) mbmeth_##name
1439   METH  (reduce,        "B.reduce(X) -> X mod B.m")
1440   METH  (exp,           "B.exp(X, N) -> X^N mod B.m")
1441   METH  (mexp,          "\
1442 B.mexp([(X0, N0), (X1, N1), ...]) = X0^N0 X1^N1 mod B.m\n\
1443 \t(the list may be flattened if this more convenient.)")
1444 #undef METHNAME
1445   { 0 }
1446 };
1447
1448 static PyTypeObject *mpbarrett_pytype, mpbarrett_pytype_skel = {
1449   PyObject_HEAD_INIT(0) 0,              /* Header */
1450   "catacomb.MPBarrett",                 /* @tp_name@ */
1451   sizeof(mpbarrett_pyobj),              /* @tp_basicsize@ */
1452   0,                                    /* @tp_itemsize@ */
1453
1454   mpbarrett_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 "A Barrett reduction context.",
1474
1475   0,                                    /* @tp_traverse@ */
1476   0,                                    /* @tp_clear@ */
1477   0,                                    /* @tp_richcompare@ */
1478   0,                                    /* @tp_weaklistoffset@ */
1479   0,                                    /* @tp_iter@ */
1480   0,                                    /* @tp_iternext@ */
1481   mpbarrett_pymethods,                  /* @tp_methods@ */
1482   0,                                    /* @tp_members@ */
1483   mpbarrett_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   mpbarrett_pynew,                      /* @tp_new@ */
1492   0,                                    /* @tp_free@ */
1493   0                                     /* @tp_is_gc@ */
1494 };
1495
1496 /*----- Nice prime reduction ----------------------------------------------*/
1497
1498 typedef struct mpreduce_pyobj {
1499   PyObject_HEAD
1500   mpreduce mr;
1501 } mpreduce_pyobj;
1502
1503 #define MPREDUCE_PY(o) (&((mpreduce_pyobj *)(o))->mr)
1504
1505 static PyObject *mrmeth_exp(PyObject *me, PyObject *arg)
1506 {
1507   PyObject *rc = 0;
1508   mp *yy = 0, *zz = 0;
1509
1510   if (!PyArg_ParseTuple(arg, "O&O&:exp", convmp, &yy, convmp, &zz))
1511     goto end;
1512   if (MP_NEGP(zz)) {
1513     if ((yy = mp_modinv_checked(yy, yy, MPREDUCE_PY(me)->p)) == 0) goto end;
1514     zz = mp_neg(zz, zz);
1515   }
1516   rc = mp_pywrap(mpreduce_exp(MPREDUCE_PY(me), MP_NEW, yy, zz));
1517 end:
1518   if (yy) MP_DROP(yy); if (zz) MP_DROP(zz);
1519   return (rc);
1520 }
1521
1522 static PyObject *mrmeth_reduce(PyObject *me, PyObject *arg)
1523 {
1524   PyObject *z = 0;
1525   mp *yy = 0;
1526
1527   if (!PyArg_ParseTuple(arg, "O&:reduce", convmp, &yy)) goto end;
1528   z = mp_pywrap(mpreduce_do(MPREDUCE_PY(me), MP_NEW, yy));
1529 end:
1530   return (z);
1531 }
1532
1533 static void mpreduce_pydealloc(PyObject *me)
1534 {
1535   mpreduce_destroy(MPREDUCE_PY(me));
1536   FREEOBJ(me);
1537 }
1538
1539 static PyObject *mpreduce_pynew(PyTypeObject *ty,
1540                                  PyObject *arg, PyObject *kw)
1541 {
1542   mpreduce_pyobj *mr = 0;
1543   mpreduce r;
1544   char *kwlist[] = { "m", 0 };
1545   mp *xx = 0;
1546
1547   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:new", kwlist, convmp, &xx))
1548     goto end;
1549   if (!MP_POSP(xx)) VALERR("m must be positive");
1550   if (mpreduce_create(&r, xx)) VALERR("bad modulus (must be 2^k - ...)");
1551   mr = (mpreduce_pyobj *)ty->tp_alloc(ty, 0);
1552   mr->mr = r;
1553 end:
1554   if (xx) MP_DROP(xx);
1555   return ((PyObject *)mr);
1556 }
1557
1558 static PyObject *mrget_m(PyObject *me, void *hunoz)
1559   { return (mp_pywrap(MP_COPY(MPREDUCE_PY(me)->p))); }
1560
1561 static PyGetSetDef mpreduce_pygetset[] = {
1562 #define GETSETNAME(op, name) mr##op##_##name
1563   GET   (m,             "R.m -> modulus for reduction")
1564 #undef GETSETNAME
1565   { 0 }
1566 };
1567
1568 static PyMethodDef mpreduce_pymethods[] = {
1569 #define METHNAME(name) mrmeth_##name
1570   METH  (reduce,        "R.reduce(X) -> X mod B.m")
1571   METH  (exp,           "R.exp(X, N) -> X^N mod B.m")
1572 #undef METHNAME
1573   { 0 }
1574 };
1575
1576 static PyTypeObject *mpreduce_pytype, mpreduce_pytype_skel = {
1577   PyObject_HEAD_INIT(0) 0,              /* Header */
1578   "catacomb.MPReduce",                  /* @tp_name@ */
1579   sizeof(mpreduce_pyobj),               /* @tp_basicsize@ */
1580   0,                                    /* @tp_itemsize@ */
1581
1582   mpreduce_pydealloc,                   /* @tp_dealloc@ */
1583   0,                                    /* @tp_print@ */
1584   0,                                    /* @tp_getattr@ */
1585   0,                                    /* @tp_setattr@ */
1586   0,                                    /* @tp_compare@ */
1587   0,                                    /* @tp_repr@ */
1588   0,                                    /* @tp_as_number@ */
1589   0,                                    /* @tp_as_sequence@ */
1590   0,                                    /* @tp_as_mapping@ */
1591   0,                                    /* @tp_hash@ */
1592   0,                                    /* @tp_call@ */
1593   0,                                    /* @tp_str@ */
1594   0,                                    /* @tp_getattro@ */
1595   0,                                    /* @tp_setattro@ */
1596   0,                                    /* @tp_as_buffer@ */
1597   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
1598     Py_TPFLAGS_BASETYPE,
1599
1600   /* @tp_doc@ */
1601 "A reduction context for reduction modulo primes of special form.",
1602
1603   0,                                    /* @tp_traverse@ */
1604   0,                                    /* @tp_clear@ */
1605   0,                                    /* @tp_richcompare@ */
1606   0,                                    /* @tp_weaklistoffset@ */
1607   0,                                    /* @tp_iter@ */
1608   0,                                    /* @tp_iternext@ */
1609   mpreduce_pymethods,                   /* @tp_methods@ */
1610   0,                                    /* @tp_members@ */
1611   mpreduce_pygetset,                    /* @tp_getset@ */
1612   0,                                    /* @tp_base@ */
1613   0,                                    /* @tp_dict@ */
1614   0,                                    /* @tp_descr_get@ */
1615   0,                                    /* @tp_descr_set@ */
1616   0,                                    /* @tp_dictoffset@ */
1617   0,                                    /* @tp_init@ */
1618   PyType_GenericAlloc,                  /* @tp_alloc@ */
1619   mpreduce_pynew,                       /* @tp_new@ */
1620   0,                                    /* @tp_free@ */
1621   0                                     /* @tp_is_gc@ */
1622 };
1623
1624 /*----- Chinese Remainder Theorem solution --------------------------------*/
1625
1626 typedef struct mpcrt_pyobj {
1627   PyObject_HEAD
1628   mpcrt c;
1629 } mpcrt_pyobj;
1630
1631 #define MPCRT_PY(o) (&((mpcrt_pyobj *)(o))->c)
1632
1633 static PyObject *mcmeth_solve(PyObject *me, PyObject *arg)
1634 {
1635   mpcrt *c = MPCRT_PY(me);
1636   PyObject *q = 0, *x, *z = 0;
1637   mp *xx;
1638   mp **v = 0;
1639   int i = 0, n = c->k;
1640
1641   Py_INCREF(me);
1642   if (PyTuple_Size(arg) == n)
1643     q = arg;
1644   else if (!PyArg_ParseTuple(arg, "O:solve", &q))
1645     goto end;
1646   Py_INCREF(q);
1647   if (!PySequence_Check(q)) TYERR("want a sequence of residues");
1648   if (PySequence_Size(q) != n) VALERR("residue count mismatch");
1649   v = xmalloc(n * sizeof(*v));
1650   for (i = 0; i < n; i++) {
1651     if ((x = PySequence_GetItem(q, i)) == 0) goto end;
1652     xx = getmp(x); Py_DECREF(x); if (!xx) goto end;
1653     v[i] = xx;
1654   }
1655   z = mp_pywrap(mpcrt_solve(c, MP_NEW, v));
1656 end:
1657   if (v) {
1658     n = i;
1659     for (i = 0; i < n; i++)
1660       MP_DROP(v[i]);
1661     xfree(v);
1662   }
1663   Py_DECREF(me);
1664   Py_XDECREF(q);
1665   return (z);
1666 }
1667
1668 static void mpcrt_pydealloc(PyObject *me)
1669 {
1670   mpcrt *c = MPCRT_PY(me);
1671   mpcrt_destroy(c);
1672   xfree(c->v);
1673 }
1674
1675 static PyObject *mpcrt_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
1676 {
1677   mpcrt_mod *v = 0;
1678   int n, i = 0;
1679   char *kwlist[] = { "mv", 0 };
1680   PyObject *q = 0, *x;
1681   mp *xx;
1682   mpcrt_pyobj *c = 0;
1683
1684   if (PyTuple_Size(arg) > 1)
1685     q = arg;
1686   else if (!PyArg_ParseTupleAndKeywords(arg, kw, "O:new", kwlist, &q))
1687     goto end;
1688   Py_INCREF(q);
1689   if (!PySequence_Check(q)) TYERR("want a sequence of moduli");
1690   n = PySequence_Size(q);
1691   if (PyErr_Occurred()) goto end;
1692   if (!n) VALERR("want at least one modulus");
1693   v = xmalloc(n * sizeof(*v));
1694   for (i = 0; i < n; i++) {
1695     if ((x = PySequence_GetItem(q, i)) == 0) goto end;
1696     xx = getmp(x); Py_DECREF(x); if (!xx) goto end;
1697     v[i].m = xx; v[i].n = 0; v[i].ni = 0; v[i].nni = 0;
1698   }
1699   c = (mpcrt_pyobj *)ty->tp_alloc(ty, 0);
1700   mpcrt_create(&c->c, v, n, 0);
1701   Py_DECREF(q);
1702   return ((PyObject *)c);
1703
1704 end:
1705   if (v) {
1706     n = i;
1707     for (i = 0; i < n; i++)
1708       MP_DROP(v[i].m);
1709     xfree(v);
1710   }
1711   Py_XDECREF(q);
1712   return (0);
1713 }
1714
1715 static PyObject *mcget_product(PyObject *me, void *hunoz)
1716   { return (mp_pywrap(MP_COPY(MPCRT_PY(me)->mb.m))); }
1717
1718 static PyObject *mcget_moduli(PyObject *me, void *hunoz)
1719 {
1720   int i;
1721   PyObject *q;
1722   mpcrt *c = MPCRT_PY(me);
1723
1724   if ((q = PyList_New(c->k)) == 0) return (0);
1725   for (i = 0; i < c->k; i++)
1726     PyList_SetItem(q, i, mp_pywrap(c->v[i].m));
1727   return (q);
1728 }
1729
1730 static PyGetSetDef mpcrt_pygetset[] = {
1731 #define GETSETNAME(op, name) mc##op##_##name
1732   GET   (product,       "C.product -> product of moduli")
1733   GET   (moduli,        "C.moduli -> list of individual moduli")
1734 #undef GETSETNAME
1735   { 0 }
1736 };
1737
1738 static PyMethodDef mpcrt_pymethods[] = {
1739 #define METHNAME(name) mcmeth_##name
1740   METH  (solve,         "C.solve([R0, R1]) -> X mod C.product")
1741 #undef METHNAME
1742   { 0 }
1743 };
1744
1745 static PyTypeObject *mpcrt_pytype, mpcrt_pytype_skel = {
1746   PyObject_HEAD_INIT(0) 0,              /* Header */
1747   "catacomb.MPCRT",                     /* @tp_name@ */
1748   sizeof(mpcrt_pyobj),                  /* @tp_basicsize@ */
1749   0,                                    /* @tp_itemsize@ */
1750
1751   mpcrt_pydealloc,                      /* @tp_dealloc@ */
1752   0,                                    /* @tp_print@ */
1753   0,                                    /* @tp_getattr@ */
1754   0,                                    /* @tp_setattr@ */
1755   0,                                    /* @tp_compare@ */
1756   0,                                    /* @tp_repr@ */
1757   0,                                    /* @tp_as_number@ */
1758   0,                                    /* @tp_as_sequence@ */
1759   0,                                    /* @tp_as_mapping@ */
1760   0,                                    /* @tp_hash@ */
1761   0,                                    /* @tp_call@ */
1762   0,                                    /* @tp_str@ */
1763   0,                                    /* @tp_getattro@ */
1764   0,                                    /* @tp_setattro@ */
1765   0,                                    /* @tp_as_buffer@ */
1766   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
1767     Py_TPFLAGS_BASETYPE,
1768
1769   /* @tp_doc@ */
1770 "A context for the solution of Chinese Remainder Theorem problems.",
1771
1772   0,                                    /* @tp_traverse@ */
1773   0,                                    /* @tp_clear@ */
1774   0,                                    /* @tp_richcompare@ */
1775   0,                                    /* @tp_weaklistoffset@ */
1776   0,                                    /* @tp_iter@ */
1777   0,                                    /* @tp_iternext@ */
1778   mpcrt_pymethods,                      /* @tp_methods@ */
1779   0,                                    /* @tp_members@ */
1780   mpcrt_pygetset,                       /* @tp_getset@ */
1781   0,                                    /* @tp_base@ */
1782   0,                                    /* @tp_dict@ */
1783   0,                                    /* @tp_descr_get@ */
1784   0,                                    /* @tp_descr_set@ */
1785   0,                                    /* @tp_dictoffset@ */
1786   0,                                    /* @tp_init@ */
1787   PyType_GenericAlloc,                  /* @tp_alloc@ */
1788   mpcrt_pynew,                          /* @tp_new@ */
1789   0,                                    /* @tp_free@ */
1790   0                                     /* @tp_is_gc@ */
1791 };
1792
1793 /*----- Binary polynomials ------------------------------------------------*/
1794
1795 static PyObject *gf_pyrepr(PyObject *o)
1796   { return mp_topystring(MP_X(o), 16, "GF(", "0x", "L)"); }
1797
1798 static PyObject *gf_pyrichcompare(PyObject *x, PyObject *y, int op)
1799 {
1800   mp *xx, *yy;
1801   int xl, yl;
1802   int b;
1803
1804   if (gfbinop(x, y, &xx, &yy)) RETURN_NOTIMPL;
1805   switch (op) {
1806     case Py_EQ: b = MP_EQ(xx, yy); break;
1807     case Py_NE: b = !MP_EQ(xx, yy); break;
1808     default:
1809       xl = mp_bits(xx);
1810       yl = mp_bits(yy);
1811       switch (op) {
1812         case Py_LT: b = xl < yl; break;
1813         case Py_LE: b = xl <= yl; break;
1814         case Py_GT: b = xl > yl; break;
1815         case Py_GE: b = xl >= yl; break;
1816         default: abort();
1817       }
1818       break;
1819   }
1820   MP_DROP(xx); MP_DROP(yy);
1821   return (getbool(b));
1822 }
1823
1824 static PyObject *gf_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
1825 {
1826   PyObject *x;
1827   mp *z;
1828   mp_pyobj *zz = 0;
1829   int radix = 0;
1830   char *kwlist[] = { "x", "radix", 0 };
1831
1832   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O|i:gf", kwlist, &x, &radix))
1833     goto end;
1834   if (GF_PYCHECK(x)) RETURN_OBJ(x);
1835   if (!good_radix_p(radix, 1)) VALERR("radix out of range");
1836   if ((z = mp_frompyobject(x, radix)) == 0) {
1837     PyErr_Format(PyExc_TypeError, "can't convert %.100s to gf",
1838                  x->ob_type->tp_name);
1839     goto end;
1840   }
1841   if (MP_NEGP(z)) {
1842     MP_DROP(z);
1843     VALERR("gf cannot be negative");
1844   }
1845   zz = (mp_pyobj *)ty->tp_alloc(ty, 0);
1846   zz->x = z;
1847 end:
1848   return ((PyObject *)zz);
1849 }
1850
1851 static long gf_pyhash(PyObject *me)
1852 {
1853   long i = mp_tolong(MP_X(me));
1854   i ^= 0xc7ecd67c; /* random perturbance */
1855   if (i == -1)
1856     i = -2;
1857   return (i);
1858 }
1859
1860 static PyObject *gf_pyexp(PyObject *x, PyObject *y, PyObject *z)
1861 {
1862   mp *xx = 0, *yy = 0, *zz = 0;
1863   mp *r = 0;
1864   PyObject *rc = 0;
1865
1866   if ((xx = tomp(x)) == 0 || (yy = tomp(y)) == 0 ||
1867       (z && z != Py_None && (zz = tomp(z)) == 0)) {
1868     mp_drop(xx); mp_drop(yy); mp_drop(zz);
1869     RETURN_NOTIMPL;
1870   }
1871   if (!z || z == Py_None) {
1872     if (MP_NEGP(yy)) VALERR("negative exponent");
1873     r = gf_exp(MP_NEW, xx, yy);
1874   } else {
1875     gfreduce gr;
1876     if (MP_ZEROP(zz)) ZDIVERR("zero modulus");
1877     if (MP_NEGP(yy)) {
1878       if ((xx = gf_modinv_checked(xx, xx, zz)) == 0) goto end;
1879       yy = mp_neg(yy, yy);
1880     }
1881     gfreduce_create(&gr, zz);
1882     r = gfreduce_exp(&gr, MP_NEW, xx, yy);
1883     gfreduce_destroy(&gr);
1884   }
1885   rc = gf_pywrap(r);
1886 end:
1887   mp_drop(xx); mp_drop(yy); mp_drop(zz);
1888   return (rc);
1889 }
1890
1891 static PyObject *gfmeth_sqr(PyObject *me, PyObject *arg)
1892 {
1893   if (!PyArg_ParseTuple(arg, ":sqr")) return (0);
1894   return (gf_pywrap(gf_sqr(MP_NEW, MP_X(me))));
1895 }
1896
1897 static PyObject *gfmeth_gcd(PyObject *me, PyObject *arg)
1898 {
1899   PyObject *z = 0;
1900   mp *yy = 0, *zz = MP_NEW;
1901
1902   if (!PyArg_ParseTuple(arg, "O&:gcd", convgf, &yy)) goto end;
1903   gf_gcd(&zz, 0, 0, MP_X(me), yy);
1904   z = gf_pywrap(zz);
1905 end:
1906   if (yy) MP_DROP(yy);
1907   return (z);
1908 }
1909
1910 static PyObject *gfmeth_gcdx(PyObject *me, PyObject *arg)
1911 {
1912   PyObject *z = 0;
1913   mp *yy = 0, *zz = MP_NEW, *uu = MP_NEW, *vv = MP_NEW;
1914
1915   if (!PyArg_ParseTuple(arg, "O&:gcdx", convgf, &yy))
1916     goto end;
1917   gf_gcd(&zz, &uu, &vv, MP_X(me), yy);
1918   z = Py_BuildValue("(NNN)",
1919                     gf_pywrap(zz), gf_pywrap(uu), gf_pywrap(vv));
1920 end:
1921   if (yy) MP_DROP(yy);
1922   return (z);
1923 }
1924
1925 static PyObject *gfmeth_modinv(PyObject *me, PyObject *arg)
1926 {
1927   PyObject *z = 0;
1928   mp *yy = 0, *zz = MP_NEW;
1929
1930   if (!PyArg_ParseTuple(arg, "O&:modinv", convgf, &yy) ||
1931       (zz = gf_modinv_checked(MP_NEW, yy, MP_X(me))) == 0)
1932     goto end;
1933   z = gf_pywrap(zz);
1934 end:
1935   if (yy) MP_DROP(yy);
1936   return (z);
1937 }
1938
1939 static PyObject *gfmeth_irreduciblep(PyObject *me, PyObject *arg)
1940 {
1941   if (!PyArg_ParseTuple(arg, ":irreduciblep")) return (0);
1942   return getbool(gf_irreduciblep(MP_X(me)));
1943 }
1944
1945 static PyObject *gfget_degree(PyObject *me, void *hunoz)
1946   { return (PyInt_FromLong(mp_bits(MP_X(me)) - 1)); }
1947
1948 static PyGetSetDef gf_pygetset[] = {
1949 #define GETSETNAME(op, name) gf##op##_##name
1950   GET   (degree,        "X.degree -> polynomial degree of X")
1951 #undef GETSETNAME
1952 #define GETSETNAME(op, name) mp##op##_##name
1953   GET   (nbits,         "X.nbits -> bit length of X")
1954   GET   (noctets,       "X.noctets -> octet length of X")
1955 #undef GETSETNAME
1956   { 0 }
1957 };
1958
1959 static PyMethodDef gf_pymethods[] = {
1960 #define METHNAME(func) gfmeth_##func
1961   METH  (setbit,        "X.setbit(N) -> X with bit N set")
1962   METH  (clearbit,      "X.clearbit(N) -> X with bit N clear")
1963   METH  (testbit,       "X.testbit(N) -> true/false if bit N set/clear in X")
1964   METH  (sqr,           "X.sqr() -> X^2")
1965   METH  (gcd,           "X.gcd(Y) -> gcd(X, Y)")
1966   METH  (gcdx,
1967          "X.gcdx(Y) -> (gcd(X, Y), U, V) with X U + Y V = gcd(X, Y)")
1968   METH  (modinv,        "X.modinv(Y) -> multiplicative inverse of Y mod X")
1969   METH  (irreduciblep,  "X.irreduciblep() -> true/false")
1970 #undef METHNAME
1971 #define METHNAME(func) mpmeth_##func
1972   KWMETH(tostring,      "X.tostring(radix = 10) -> STR")
1973   KWMETH(storel,        "X.storel(len = -1) -> little-endian bytes")
1974   KWMETH(storeb,        "X.storeb(len = -1) -> big-endian bytes")
1975   KWMETH(storel2c,
1976          "X.storel2c(len = -1) -> little-endian bytes, two's complement")
1977   KWMETH(storeb2c,
1978          "X.storeb2c(len = -1) -> big-endian bytes, two's complement")
1979   METH  (tobuf,         "X.tobuf() -> buffer format")
1980 #undef METHNAME
1981   { 0 }
1982 };
1983
1984 static PyNumberMethods gf_pynumber = {
1985   gf_pyadd,                             /* @nb_add@ */
1986   gf_pysub,                             /* @nb_subtract@ */
1987   gf_pymul,                             /* @nb_multiply@ */
1988   0,                                    /* @nb_divide@ */
1989   gf_pymod,                             /* @nb_remainder@ */
1990   gf_pydivmod,                          /* @nb_divmod@ */
1991   gf_pyexp,                             /* @nb_power@ */
1992   mp_pyid,                              /* @nb_negative@ */
1993   mp_pyid,                              /* @nb_positive@ */
1994   mp_pyid,                              /* @nb_absolute@ */
1995   mp_pynonzerop,                        /* @nb_nonzero@ */
1996   0 /* doesn't make any sense */,       /* @nb_invert@ */
1997   gf_pylsl,                             /* @nb_lshift@ */
1998   gf_pylsr,                             /* @nb_rshift@ */
1999   gf_pyand,                             /* @nb_and@ */
2000   gf_pyxor,                             /* @nb_xor@ */
2001   gf_pyor,                              /* @nb_or@ */
2002   gf_pycoerce,                          /* @nb_coerce@ */
2003   mp_pyint,                             /* @nb_int@ */
2004   mp_pylong,                            /* @nb_long@ */
2005   0 /* doesn't make any sense */,       /* @nb_float@ */
2006   mp_pyoct,                             /* @nb_oct@ */
2007   mp_pyhex,                             /* @nb_hex@ */
2008
2009   0,                                    /* @nb_inplace_add@ */
2010   0,                                    /* @nb_inplace_subtract@ */
2011   0,                                    /* @nb_inplace_multiply@ */
2012   0,                                    /* @nb_inplace_divide@ */
2013   0,                                    /* @nb_inplace_remainder@ */
2014   0,                                    /* @nb_inplace_power@ */
2015   0,                                    /* @nb_inplace_lshift@ */
2016   0,                                    /* @nb_inplace_rshift@ */
2017   0,                                    /* @nb_inplace_and@ */
2018   0,                                    /* @nb_inplace_xor@ */
2019   0,                                    /* @nb_inplace_or@ */
2020
2021   gf_pydiv,                             /* @nb_floor_divide@ */
2022   0,                                    /* @nb_true_divide@ */
2023   0,                                    /* @nb_inplace_floor_divide@ */
2024   0,                                    /* @nb_inplace_true_divide@ */
2025 };
2026
2027 static PyTypeObject gf_pytype_skel = {
2028   PyObject_HEAD_INIT(0) 0,              /* Header */
2029   "catacomb.GF",                        /* @tp_name@ */
2030   sizeof(mp_pyobj),                     /* @tp_basicsize@ */
2031   0,                                    /* @tp_itemsize@ */
2032
2033   mp_pydealloc,                         /* @tp_dealloc@ */
2034   0,                                    /* @tp_print@ */
2035   0,                                    /* @tp_getattr@ */
2036   0,                                    /* @tp_setattr@ */
2037   0,                                    /* @tp_compare@ */
2038   gf_pyrepr,                            /* @tp_repr@ */
2039   &gf_pynumber,                         /* @tp_as_number@ */
2040   0,                                    /* @tp_as_sequence@ */
2041   0,                                    /* @tp_as_mapping@ */
2042   gf_pyhash,                            /* @tp_hash@ */
2043   0,                                    /* @tp_call@ */
2044   mp_pyhex,                             /* @tp_str@ */
2045   0,                                    /* @tp_getattro@ */
2046   0,                                    /* @tp_setattro@ */
2047   0,                                    /* @tp_as_buffer@ */
2048   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
2049     Py_TPFLAGS_CHECKTYPES |
2050     Py_TPFLAGS_BASETYPE,
2051
2052   /* @tp_doc@ */
2053 "Binary polynomials.  Support almost all the standard arithmetic\n\
2054 operations.\n\
2055 \n\
2056 Constructor gf(X, radix = R) attempts to convert X to a `gf'.  If\n\
2057 X is a string, it's read in radix-R form, or we look for a prefix\n\
2058 if R = 0.  Other acceptable things are ints and longs.\n\
2059 \n\
2060 The name is hopelessly wrong from a technical point of view, but\n\
2061 but it's much easier to type than `p2' or `c2' or whatever.\n\
2062 \n\
2063 Notes:\n\
2064 \n\
2065   * Use `//' for division.  GFs don't have `/' division.",
2066
2067   0,                                    /* @tp_traverse@ */
2068   0,                                    /* @tp_clear@ */
2069   gf_pyrichcompare,                     /* @tp_richcompare@ */
2070   0,                                    /* @tp_weaklistoffset@ */
2071   0,                                    /* @tp_iter@ */
2072   0,                                    /* @tp_iternext@ */
2073   gf_pymethods,                         /* @tp_methods@ */
2074   0,                                    /* @tp_members@ */
2075   gf_pygetset,                          /* @tp_getset@ */
2076   0,                                    /* @tp_base@ */
2077   0,                                    /* @tp_dict@ */
2078   0,                                    /* @tp_descr_get@ */
2079   0,                                    /* @tp_descr_set@ */
2080   0,                                    /* @tp_dictoffset@ */
2081   0,                                    /* @tp_init@ */
2082   PyType_GenericAlloc,                  /* @tp_alloc@ */
2083   gf_pynew,                             /* @tp_new@ */
2084   0,                                    /* @tp_free@ */
2085   0                                     /* @tp_is_gc@ */
2086 };
2087
2088 static PyObject *meth__GF_fromstring(PyObject *me,
2089                                     PyObject *arg, PyObject *kw)
2090 {
2091   int r = 0;
2092   char *p;
2093   int len;
2094   PyObject *z = 0;
2095   mp *zz;
2096   mptext_stringctx sc;
2097   char *kwlist[] = { "class", "x", "radix", 0 };
2098
2099   if (!PyArg_ParseTupleAndKeywords(arg, kw, "Os#|i:fromstring",
2100                                    kwlist, &me, &p, &len, &r))
2101     goto end;
2102   if (!good_radix_p(r, 1)) VALERR("bad radix");
2103   sc.buf = p; sc.lim = p + len;
2104   if ((zz = mp_read(MP_NEW, r, &mptext_stringops, &sc)) == 0 ||
2105       MP_NEGP(zz)) {
2106     if (zz) MP_DROP(zz);
2107     SYNERR("bad binary polynomial");
2108   }
2109   z = Py_BuildValue("(Ns#)", gf_pywrap(zz), sc.buf, (int)(sc.lim - sc.buf));
2110 end:
2111   return (z);
2112 }
2113
2114 /*----- Sparse poly reduction ---------------------------------------------*/
2115
2116 typedef struct gfreduce_pyobj {
2117   PyObject_HEAD
2118   gfreduce mr;
2119 } gfreduce_pyobj;
2120
2121 #define GFREDUCE_PY(o) (&((gfreduce_pyobj *)(o))->mr)
2122
2123 static PyObject *grmeth_exp(PyObject *me, PyObject *arg)
2124 {
2125   PyObject *rc = 0;
2126   mp *yy = 0, *zz = 0;
2127
2128   if (!PyArg_ParseTuple(arg, "O&O&:exp", convgf, &yy, convgf, &zz))
2129     goto end;
2130   if (MP_NEGP(zz)) {
2131     if ((yy = gf_modinv_checked(yy, yy, GFREDUCE_PY(me)->p)) == 0) goto end;
2132     zz = mp_neg(zz, zz);
2133   }
2134   rc = gf_pywrap(gfreduce_exp(GFREDUCE_PY(me), MP_NEW, yy, zz));
2135 end:
2136   if (yy) MP_DROP(yy); if (zz) MP_DROP(zz);
2137   return (rc);
2138 }
2139
2140 static PyObject *grmeth_trace(PyObject *me, PyObject *arg)
2141 {
2142   PyObject *rc = 0;
2143   mp *xx = 0;
2144
2145   if (!PyArg_ParseTuple(arg, "O&:trace", convgf, &xx)) goto end;
2146   rc = PyInt_FromLong(gfreduce_trace(GFREDUCE_PY(me), xx));
2147 end:
2148   if (xx) MP_DROP(xx);
2149   return (rc);
2150 }
2151
2152 static PyObject *grmeth_halftrace(PyObject *me, PyObject *arg)
2153 {
2154   PyObject *rc = 0;
2155   mp *xx = 0;
2156
2157   if (!PyArg_ParseTuple(arg, "O&:halftrace", convgf, &xx)) goto end;
2158   rc = gf_pywrap(gfreduce_halftrace(GFREDUCE_PY(me), MP_NEW, xx));
2159 end:
2160   if (xx) MP_DROP(xx);
2161   return (rc);
2162 }
2163
2164 static PyObject *grmeth_sqrt(PyObject *me, PyObject *arg)
2165 {
2166   PyObject *rc = 0;
2167   mp *xx = 0, *yy;
2168
2169   if (!PyArg_ParseTuple(arg, "O&:sqrt", convgf, &xx)) goto end;
2170   if ((yy = gfreduce_sqrt(GFREDUCE_PY(me), MP_NEW, xx)) == 0)
2171     VALERR("no modular square root");
2172   rc = gf_pywrap(yy);
2173 end:
2174   if (xx) MP_DROP(xx);
2175   return (rc);
2176 }
2177
2178 static PyObject *grmeth_quadsolve(PyObject *me, PyObject *arg)
2179 {
2180   PyObject *rc = 0;
2181   mp *xx = 0, *yy;
2182
2183   if (!PyArg_ParseTuple(arg, "O&:quadsolve", convgf, &xx)) goto end;
2184   if ((yy = gfreduce_quadsolve(GFREDUCE_PY(me), MP_NEW, xx)) == 0)
2185     VALERR("no solution found");
2186   rc = gf_pywrap(yy);
2187 end:
2188   if (xx) MP_DROP(xx);
2189   return (rc);
2190 }
2191
2192 static PyObject *grmeth_reduce(PyObject *me, PyObject *arg)
2193 {
2194   PyObject *z = 0;
2195   mp *yy = 0;
2196
2197   if (!PyArg_ParseTuple(arg, "O&:reduce", convgf, &yy)) goto end;
2198   z = gf_pywrap(gfreduce_do(GFREDUCE_PY(me), MP_NEW, yy));
2199 end:
2200   return (z);
2201 }
2202
2203 static void gfreduce_pydealloc(PyObject *me)
2204 {
2205   gfreduce_destroy(GFREDUCE_PY(me));
2206   FREEOBJ(me);
2207 }
2208
2209 static PyObject *gfreduce_pynew(PyTypeObject *ty,
2210                                  PyObject *arg, PyObject *kw)
2211 {
2212   gfreduce_pyobj *mr = 0;
2213   gfreduce r;
2214   char *kwlist[] = { "m", 0 };
2215   mp *xx = 0;
2216
2217   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:new", kwlist, convgf, &xx))
2218     goto end;
2219   if (MP_ZEROP(xx)) ZDIVERR("modulus is zero!");
2220   gfreduce_create(&r, xx);
2221   mr = (gfreduce_pyobj *)ty->tp_alloc(ty, 0);
2222   mr->mr = r;
2223 end:
2224   if (xx) MP_DROP(xx);
2225   return ((PyObject *)mr);
2226 }
2227
2228 static PyObject *grget_m(PyObject *me, void *hunoz)
2229   { return (gf_pywrap(MP_COPY(GFREDUCE_PY(me)->p))); }
2230
2231 static PyGetSetDef gfreduce_pygetset[] = {
2232 #define GETSETNAME(op, name) gr##op##_##name
2233   GET   (m,             "R.m -> reduction polynomial")
2234 #undef GETSETNAME
2235   { 0 }
2236 };
2237
2238 static PyMethodDef gfreduce_pymethods[] = {
2239 #define METHNAME(name) grmeth_##name
2240   METH  (reduce,        "R.reduce(X) -> X mod B.m")
2241   METH  (trace,        "R.trace(X) -> Tr(X) = x + x^2 + ... + x^{2^{m - 1}}")
2242   METH  (halftrace,   "R.halftrace(X) -> x + x^{2^2} + ... + x^{2^{m - 1}}")
2243   METH  (sqrt,          "R.sqrt(X) -> Y where Y^2 = X mod R")
2244   METH  (quadsolve,     "R.quadsolve(X) -> Y where Y^2 + Y = X mod R")
2245   METH  (exp,           "R.exp(X, N) -> X^N mod B.m")
2246 #undef METHNAME
2247   { 0 }
2248 };
2249
2250 static PyTypeObject *gfreduce_pytype, gfreduce_pytype_skel = {
2251   PyObject_HEAD_INIT(0) 0,              /* Header */
2252   "catacomb.GFReduce",                  /* @tp_name@ */
2253   sizeof(gfreduce_pyobj),               /* @tp_basicsize@ */
2254   0,                                    /* @tp_itemsize@ */
2255
2256   gfreduce_pydealloc,                   /* @tp_dealloc@ */
2257   0,                                    /* @tp_print@ */
2258   0,                                    /* @tp_getattr@ */
2259   0,                                    /* @tp_setattr@ */
2260   0,                                    /* @tp_compare@ */
2261   0,                                    /* @tp_repr@ */
2262   0,                                    /* @tp_as_number@ */
2263   0,                                    /* @tp_as_sequence@ */
2264   0,                                    /* @tp_as_mapping@ */
2265   0,                                    /* @tp_hash@ */
2266   0,                                    /* @tp_call@ */
2267   0,                                    /* @tp_str@ */
2268   0,                                    /* @tp_getattro@ */
2269   0,                                    /* @tp_setattro@ */
2270   0,                                    /* @tp_as_buffer@ */
2271   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
2272     Py_TPFLAGS_BASETYPE,
2273
2274   /* @tp_doc@ */
2275 "A reduction context for reduction modulo sparse irreducible polynomials.",
2276
2277   0,                                    /* @tp_traverse@ */
2278   0,                                    /* @tp_clear@ */
2279   0,                                    /* @tp_richcompare@ */
2280   0,                                    /* @tp_weaklistoffset@ */
2281   0,                                    /* @tp_iter@ */
2282   0,                                    /* @tp_iternext@ */
2283   gfreduce_pymethods,                   /* @tp_methods@ */
2284   0,                                    /* @tp_members@ */
2285   gfreduce_pygetset,                    /* @tp_getset@ */
2286   0,                                    /* @tp_base@ */
2287   0,                                    /* @tp_dict@ */
2288   0,                                    /* @tp_descr_get@ */
2289   0,                                    /* @tp_descr_set@ */
2290   0,                                    /* @tp_dictoffset@ */
2291   0,                                    /* @tp_init@ */
2292   PyType_GenericAlloc,                  /* @tp_alloc@ */
2293   gfreduce_pynew,                       /* @tp_new@ */
2294   0,                                    /* @tp_free@ */
2295   0                                     /* @tp_is_gc@ */
2296 };
2297
2298 /*----- Normal/poly transformation ----------------------------------------*/
2299
2300 typedef struct gfn_pyobj {
2301   PyObject_HEAD
2302   mp *p;
2303   gfn ntop, pton;
2304 } gfn_pyobj;
2305
2306 static PyTypeObject *gfn_pytype, gfn_pytype_skel;
2307
2308 #define GFN_P(o) (((gfn_pyobj *)(o))->p)
2309 #define GFN_PTON(o) (&((gfn_pyobj *)(o))->pton)
2310 #define GFN_NTOP(o) (&((gfn_pyobj *)(o))->ntop)
2311
2312 static PyObject *gfn_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
2313 {
2314   mp *p = 0, *beta = 0;
2315   gfn_pyobj *gg = 0;
2316   char *kwlist[] = { "p", "beta", 0 };
2317
2318   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&:new", kwlist,
2319                                    convgf, &p, convgf, &beta))
2320     goto end;
2321   gg = PyObject_New(gfn_pyobj, ty);
2322   if (gfn_create(p, beta, &gg->ntop, &gg->pton)) {
2323     FREEOBJ(gg);
2324     gg = 0;
2325     VALERR("can't invert transformation matrix");
2326   }
2327   gg->p = MP_COPY(p);
2328 end:
2329   mp_drop(p);
2330   mp_drop(beta);
2331   return ((PyObject *)gg);
2332 }
2333
2334 static PyObject *gfnget_p(PyObject *me, void *hunoz)
2335   { return (gf_pywrap(MP_COPY(GFN_P(me)))); }
2336
2337 static PyObject *gfnget_beta(PyObject *me, void *hunoz)
2338 {
2339   gfn *n = GFN_NTOP(me);
2340   mp *x = n->r[n->n - 1];
2341   return (gf_pywrap(MP_COPY(x)));
2342 }
2343
2344 #define XFORMOP(name, NAME)                                             \
2345   static PyObject *gfnmeth_##name(PyObject *me, PyObject *arg)          \
2346   {                                                                     \
2347     mp *xx = 0;                                                         \
2348     mp *z = 0;                                                          \
2349                                                                         \
2350     if (!PyArg_ParseTuple(arg, "O&:" #name, convgf, &xx)) goto end;     \
2351     z = gfn_transform(GFN_##NAME(me), MP_NEW, xx);                      \
2352   end:                                                                  \
2353     mp_drop(xx);                                                        \
2354     if (!z) return (0);                                                 \
2355     return (mp_pywrap(z));                                              \
2356   }
2357 XFORMOP(pton, PTON)
2358 XFORMOP(ntop, NTOP)
2359 #undef XFORMOP
2360
2361 static void gfn_pydealloc(PyObject *me)
2362 {
2363   gfn_destroy(GFN_PTON(me));
2364   gfn_destroy(GFN_NTOP(me));
2365   FREEOBJ(me);
2366 }
2367
2368 static PyGetSetDef gfn_pygetset[] = {
2369 #define GETSETNAME(op, name) gfn##op##_##name
2370   GET   (p,             "X.p -> polynomial basis, as polynomial")
2371   GET   (beta,          "X.beta -> normal basis element, in poly form")
2372 #undef GETSETNAME
2373   { 0 }
2374 };
2375
2376 static PyMethodDef gfn_pymethods[] = {
2377 #define METHNAME(name) gfnmeth_##name
2378   METH  (pton,          "X.pton(A) -> normal-basis representation of A")
2379   METH  (ntop,          "X.ntop(A) -> polynomial-basis representation of A")
2380 #undef METHNAME
2381   { 0 }
2382 };
2383
2384 static PyTypeObject gfn_pytype_skel = {
2385   PyObject_HEAD_INIT(0) 0,              /* Header */
2386   "catacomb.GFN",                       /* @tp_name@ */
2387   sizeof(gfn_pyobj),                    /* @tp_basicsize@ */
2388   0,                                    /* @tp_itemsize@ */
2389
2390   gfn_pydealloc,                        /* @tp_dealloc@ */
2391   0,                                    /* @tp_print@ */
2392   0,                                    /* @tp_getattr@ */
2393   0,                                    /* @tp_setattr@ */
2394   0,                                    /* @tp_compare@ */
2395   0,                                    /* @tp_repr@ */
2396   0,                                    /* @tp_as_number@ */
2397   0,                                    /* @tp_as_sequence@ */
2398   0,                                    /* @tp_as_mapping@ */
2399   0,                                    /* @tp_hash@ */
2400   0,                                    /* @tp_call@ */
2401   0,                                    /* @tp_str@ */
2402   0,                                    /* @tp_getattro@ */
2403   0,                                    /* @tp_setattro@ */
2404   0,                                    /* @tp_as_buffer@ */
2405   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
2406     Py_TPFLAGS_BASETYPE,
2407
2408   /* @tp_doc@ */
2409 "An object for transforming elements of binary fields between polynomial\n\
2410 and normal basis representations.",
2411
2412   0,                                    /* @tp_traverse@ */
2413   0,                                    /* @tp_clear@ */
2414   0,                                    /* @tp_richcompare@ */
2415   0,                                    /* @tp_weaklistoffset@ */
2416   0,                                    /* @tp_iter@ */
2417   0,                                    /* @tp_iternext@ */
2418   gfn_pymethods,                        /* @tp_methods@ */
2419   0,                                    /* @tp_members@ */
2420   gfn_pygetset,                         /* @tp_getset@ */
2421   0,                                    /* @tp_base@ */
2422   0,                                    /* @tp_dict@ */
2423   0,                                    /* @tp_descr_get@ */
2424   0,                                    /* @tp_descr_set@ */
2425   0,                                    /* @tp_dictoffset@ */
2426   0,                                    /* @tp_init@ */
2427   PyType_GenericAlloc,                  /* @tp_alloc@ */
2428   gfn_pynew,                            /* @tp_new@ */
2429   0,                                    /* @tp_free@ */
2430   0                                     /* @tp_is_gc@ */
2431 };
2432
2433 /*----- Glue --------------------------------------------------------------*/
2434
2435 static PyMethodDef methods[] = {
2436 #define METHNAME(func) meth_##func
2437   KWMETH(_MP_fromstring,        "\
2438 fromstring(STR, radix = 0) -> (X, REST)\n\
2439 \n\
2440 Parse STR as a large integer, according to radix.  If radix is zero,\n\
2441 read a prefix from STR to decide radix: allow `0' for octal, `0x' for hex\n\
2442 or `R_' for other radix R.")
2443   KWMETH(_GF_fromstring,        "\
2444 fromstring(STR, radix = 0) -> (X, REST)\n\
2445 \n\
2446 Parse STR as a binary polynomial, according to radix.  If radix is zero,\n\
2447 read a prefix from STR to decide radix: allow `0' for octal, `0x' for hex\n\
2448 or `R_' for other radix R.")
2449   METH  (_MP_loadl,             "\
2450 loadl(STR) -> X: read little-endian bytes")
2451   METH  (_MP_loadb,             "\
2452 loadb(STR) -> X: read big-endian bytes")
2453   METH  (_MP_loadl2c,           "\
2454 loadl2c(STR) -> X: read little-endian bytes, two's complement")
2455   METH  (_MP_loadb2c,           "\
2456 loadb2c(STR) -> X: read big-endian bytes, two's complement")
2457   METH  (_MP_frombuf,           "\
2458 frombuf(STR) -> (X, REST): read buffer format")
2459   METH  (_GF_loadl,             "\
2460 loadl(STR) -> X: read little-endian bytes")
2461   METH  (_GF_loadb,             "\
2462 loadb(STR) -> X: read big-endian bytes")
2463   METH  (_GF_frombuf,           "\
2464 frombuf(STR) -> (X, REST): read buffer format")
2465 #undef METHNAME
2466   { 0 }
2467 };
2468
2469 void mp_pyinit(void)
2470 {
2471   INITTYPE(mp, root);
2472   INITTYPE(gf, root);
2473   INITTYPE(mpmul, root);
2474   INITTYPE(mpmont, root);
2475   INITTYPE(mpbarrett, root);
2476   INITTYPE(mpreduce, root);
2477   INITTYPE(mpcrt, root);
2478   INITTYPE(gfreduce, root);
2479   INITTYPE(gfn, root);
2480   addmethods(methods);
2481 }
2482
2483 void mp_pyinsert(PyObject *mod)
2484 {
2485   INSERT("MP", mp_pytype);
2486   INSERT("MPMul", mpmul_pytype);
2487   INSERT("MPMont", mpmont_pytype);
2488   INSERT("MPBarrett", mpbarrett_pytype);
2489   INSERT("MPReduce", mpreduce_pytype);
2490   INSERT("MPCRT", mpcrt_pytype);
2491   INSERT("GF", gf_pytype);
2492   INSERT("GFReduce", gfreduce_pytype);
2493   INSERT("GFN", gfn_pytype);
2494 }
2495
2496 /*----- That's all, folks -------------------------------------------------*/