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