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