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