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