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