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