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