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