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