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