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