*.py: Upgrade old-fashioned `raise' syntax.
[catacomb-python] / pgen.c
CommitLineData
d7ab1bab 1/* -*-c-*-
2 *
d7ab1bab 3 * Prime number generation
4 *
5 * (c) 2005 Straylight/Edgeware
6 */
7
b2687a0a 8/*----- Licensing notice --------------------------------------------------*
d7ab1bab 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.
b2687a0a 16 *
d7ab1bab 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.
b2687a0a 21 *
d7ab1bab 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/*----- Filters -----------------------------------------------------------*/
32
33PyTypeObject *pfilt_pytype;
34
35static PyObject *pfilt_pywrap(pfilt *f)
36{
37 pfilt_pyobj *o = 0;
38 o = PyObject_New(pfilt_pyobj, pfilt_pytype);
39 o->f = *f;
40 o->st = pfilt_step(f, 0);
b2687a0a 41 return ((PyObject *)o);
d7ab1bab 42}
43
44static PyObject *pfilt_pymake(PyTypeObject *ty, PyObject *xobj)
45{
46 mp *x = 0;
47 pfilt_pyobj *o = 0;
48
49 if (PFILT_PYCHECK(xobj)) RETURN_OBJ(xobj);
50 if ((x = getmp(xobj)) == 0) goto end;
51 o = (pfilt_pyobj *)ty->tp_alloc(ty, 0);
52 o->st = pfilt_create(&o->f, x);
53end:
54 mp_drop(x);
55 return ((PyObject *)o);
56}
57
58static PyObject *pfilt_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
59{
827f89d7 60 static const char *const kwlist[] = { "x", 0 };
d7ab1bab 61 PyObject *xobj;
62
827f89d7 63 if (!PyArg_ParseTupleAndKeywords(arg, kw, "O:new", KWLIST, &xobj))
d7ab1bab 64 return (0);
65 return (pfilt_pymake(ty, xobj));
66}
67
68static void pfilt_pydealloc(PyObject *me)
3aa33042 69 { pfilt_destroy(PFILT_F(me)); FREEOBJ(me); }
d7ab1bab 70
71static PyObject *pfmeth_step(PyObject *me, PyObject *arg)
72{
73 mpw x;
74
75 if (!PyArg_ParseTuple(arg, "O&:step", convmpw, &x)) return (0);
76 PFILT_ST(me) = pfilt_step(PFILT_F(me), x);
77 RETURN_ME;
78}
79
80static PyObject *pfmeth_muladd(PyObject *me, PyObject *arg)
81{
82 mpw m, a;
83 pfilt_pyobj *o = 0;
84
85 if (!PyArg_ParseTuple(arg, "O&O&:muladd", convmpw, &m, convmpw, &a))
86 return (0);
87 o = PyObject_New(pfilt_pyobj, pfilt_pytype);
88 o->st = pfilt_muladd(&o->f, PFILT_F(me), m, a);
89 return ((PyObject *)o);
90}
91
92static CONVFUNC(pfilt, pfilt *, PFILT_F)
93
94static PyObject *pfmeth_jump(PyObject *me, PyObject *arg)
95{
96 pfilt *f;
97
98 if (!PyArg_ParseTuple(arg, "O&:jump", convpfilt, &f)) return (0);
99 PFILT_ST(me) = pfilt_jump(PFILT_F(me), f);
100 RETURN_ME;
101}
102
a157093f 103static PyObject *pfmeth_smallfactor(PyObject *me, PyObject *arg)
d7ab1bab 104{
105 mp *x = 0;
106 PyObject *rc = 0;
107
a157093f 108 if (!PyArg_ParseTuple(arg, "O&:smallfactor", convmp, &x)) goto end;
d7ab1bab 109 rc = PyInt_FromLong(pfilt_smallfactor(x));
110end:
111 mp_drop(x);
112 return (rc);
113}
114
115static int pfilt_pynonzerop(PyObject *me)
116 { return (PFILT_ST(me) != PGEN_FAIL); }
117
118static PyObject *pfilt_pyint(PyObject *me)
119{
120 long l;
121 PyObject *rc = 0;
122
bc243788
MW
123 if (!mp_tolong_checked(PFILT_F(me)->m, &l, 0)) rc = PyInt_FromLong(l);
124 else rc = mp_topylong(PFILT_F(me)->m);
d7ab1bab 125 return (rc);
126}
127
128static PyObject *pfilt_pylong(PyObject *me)
f368b46e 129 { return (mp_topylong(PFILT_F(me)->m)); }
d7ab1bab 130
131static PyObject *pfget_x(PyObject *me, void *hunoz)
132 { return (mp_pywrap(MP_COPY(PFILT_F(me)->m))); }
133
134static PyObject *pfget_status(PyObject *me, void *hunoz)
135 { return (PyInt_FromLong(PFILT_ST(me))); }
136
c90f712e 137static const PyGetSetDef pfilt_pygetset[] = {
d7ab1bab 138#define GETSETNAME(op, name) pf##op##_##name
139 GET (x, "F.x -> current position of filter")
140 GET (status, "F.status -> primality status of filter")
141#undef GETSETNAME
142 { 0 }
143};
144
c90f712e 145static const PyMethodDef pfilt_pymethods[] = {
d7ab1bab 146#define METHNAME(name) pfmeth_##name
147 METH (step, "F.step(N)")
148 METH (muladd, "F.muladd(M, A)")
149 METH (jump, "F.jump(FF)")
a157093f 150 SMTH (smallfactor, "smallfactor(X) -> PGST")
d7ab1bab 151#undef METHNAME
152 { 0 }
153};
154
c90f712e 155static const PyNumberMethods pfilt_pynumber = {
d7ab1bab 156 0, /* @nb_add@ */
157 0, /* @nb_subtract@ */
158 0, /* @nb_multiply@ */
159 0, /* @nb_divide@ */
160 0, /* @nb_remainder@ */
161 0, /* @nb_divmod@ */
162 0, /* @nb_power@ */
163 0, /* @nb_negative@ */
164 0, /* @nb_positive@ */
165 0, /* @nb_absolute@ */
166 pfilt_pynonzerop, /* @nb_nonzero@ */
167 0, /* @nb_invert@ */
168 0, /* @nb_lshift@ */
169 0, /* @nb_rshift@ */
170 0, /* @nb_and@ */
171 0, /* @nb_xor@ */
172 0, /* @nb_or@ */
173 0, /* @nb_coerce@ */
174 pfilt_pyint, /* @nb_int@ */
175 pfilt_pylong, /* @nb_long@ */
176 0, /* @nb_float@ */
177 0, /* @nb_oct@ */
178 0, /* @nb_hex@ */
179
180 0, /* @nb_inplace_add@ */
181 0, /* @nb_inplace_subtract@ */
182 0, /* @nb_inplace_multiply@ */
183 0, /* @nb_inplace_divide@ */
184 0, /* @nb_inplace_remainder@ */
185 0, /* @nb_inplace_power@ */
186 0, /* @nb_inplace_lshift@ */
187 0, /* @nb_inplace_rshift@ */
188 0, /* @nb_inplace_and@ */
189 0, /* @nb_inplace_xor@ */
190 0, /* @nb_inplace_or@ */
191
192 0, /* @nb_floor_divide@ */
193 0, /* @nb_true_divide@ */
194 0, /* @nb_inplace_floor_divide@ */
195 0, /* @nb_inplace_true_divide@ */
196};
197
c263b05c 198static const PyTypeObject pfilt_pytype_skel = {
591bf41b 199 PyVarObject_HEAD_INIT(0, 0) /* Header */
c461c9b3 200 "PrimeFilter", /* @tp_name@ */
d7ab1bab 201 sizeof(pfilt_pyobj), /* @tp_basicsize@ */
202 0, /* @tp_itemsize@ */
203
204 pfilt_pydealloc, /* @tp_dealloc@ */
205 0, /* @tp_print@ */
206 0, /* @tp_getattr@ */
207 0, /* @tp_setattr@ */
208 0, /* @tp_compare@ */
209 0, /* @tp_repr@ */
c90f712e 210 PYNUMBER(pfilt), /* @tp_as_number@ */
d7ab1bab 211 0, /* @tp_as_sequence@ */
212 0, /* @tp_as_mapping@ */
213 0, /* @tp_hash@ */
214 0, /* @tp_call@ */
215 0, /* @tp_str@ */
216 0, /* @tp_getattro@ */
217 0, /* @tp_setattro@ */
218 0, /* @tp_as_buffer@ */
219 Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
220 Py_TPFLAGS_BASETYPE,
221
222 /* @tp_doc@ */
d96c882e 223 "PrimeFilter(X): small-primes filter.",
d7ab1bab 224
225 0, /* @tp_traverse@ */
226 0, /* @tp_clear@ */
227 0, /* @tp_richcompare@ */
228 0, /* @tp_weaklistoffset@ */
229 0, /* @tp_iter@ */
963a6148 230 0, /* @tp_iternext@ */
c90f712e 231 PYMETHODS(pfilt), /* @tp_methods@ */
d7ab1bab 232 0, /* @tp_members@ */
c90f712e 233 PYGETSET(pfilt), /* @tp_getset@ */
d7ab1bab 234 0, /* @tp_base@ */
235 0, /* @tp_dict@ */
236 0, /* @tp_descr_get@ */
237 0, /* @tp_descr_set@ */
238 0, /* @tp_dictoffset@ */
239 0, /* @tp_init@ */
240 PyType_GenericAlloc, /* @tp_alloc@ */
241 pfilt_pynew, /* @tp_new@ */
3aa33042 242 0, /* @tp_free@ */
d7ab1bab 243 0 /* @tp_is_gc@ */
244};
245
246/*----- Rabin-Miller testing ----------------------------------------------*/
247
248typedef struct rabin_pyobj {
249 PyObject_HEAD
250 rabin r;
251} rabin_pyobj;
252
253static PyTypeObject *rabin_pytype;
254#define RABIN_R(o) (&((rabin_pyobj *)(o))->r)
255
256static PyObject *rabin_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
257{
258 mp *x = 0;
259 rabin_pyobj *o = 0;
827f89d7 260 static const char *const kwlist[] = { "x", 0 };
d7ab1bab 261
827f89d7 262 if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:new", KWLIST, convmp, &x))
d7ab1bab 263 goto end;
264 if (!MP_POSP(x) || MP_EVENP(x)) VALERR("must be positive and odd");
265 o = (rabin_pyobj *)ty->tp_alloc(ty, 0);
266 rabin_create(&o->r, x);
267end:
268 return ((PyObject *)o);
269}
270
271static void rabin_pydealloc(PyObject *me)
272{
273 rabin_destroy(RABIN_R(me));
3aa33042 274 FREEOBJ(me);
d7ab1bab 275}
276
277static PyObject *rmeth_test(PyObject *me, PyObject *arg)
278{
279 mp *w = 0;
280 PyObject *rc = 0;
281
282 if (!PyArg_ParseTuple(arg, "O&:test", convmp, &w)) goto end;
283 rc = PyInt_FromLong(rabin_test(RABIN_R(me), w));
284end:
285 mp_drop(w);
286 return (rc);
287}
288
289static PyObject *rmeth_rtest(PyObject *me, PyObject *arg)
290{
291 mp *w = 0;
292 PyObject *rc = 0;
293
294 if (!PyArg_ParseTuple(arg, "O&:rtest", convmp, &w)) goto end;
295 rc = PyInt_FromLong(rabin_rtest(RABIN_R(me), w));
296end:
297 mp_drop(w);
298 return (rc);
299}
300
301static PyObject *rget_niters(PyObject *me, void *hunoz)
302 { return (PyInt_FromLong(rabin_iters(mp_bits(RABIN_R(me)->mm.m)))); }
303
304static PyObject *rget_x(PyObject *me, void *hunoz)
305 { return (mp_pywrap(MP_COPY(RABIN_R(me)->mm.m))); }
306
a157093f 307static PyObject *rmeth_iters(PyObject *me, PyObject *arg)
d7ab1bab 308{
309 unsigned n;
310
a157093f 311 if (!PyArg_ParseTuple(arg, "O&:iters", convuint, &n)) return (0);
d7ab1bab 312 return (PyInt_FromLong(rabin_iters(n)));
313}
314
c90f712e 315static const PyGetSetDef rabin_pygetset[] = {
d7ab1bab 316#define GETSETNAME(op, name) r##op##_##name
317 GET (x, "R.x -> number under test")
318 GET (niters, "R.niters -> suggested number of tests")
319#undef GETSETNAME
320 { 0 }
321};
322
c90f712e 323static const PyMethodDef rabin_pymethods[] = {
d7ab1bab 324#define METHNAME(name) rmeth_##name
325 METH (test, "R.test(W) -> PGST")
326 METH (rtest, "R.rtest(W) -> PGST")
a157093f 327 SMTH (iters, "iters(NBITS) -> NITERS")
d7ab1bab 328#undef METHNAME
329 { 0 }
330};
331
c263b05c 332static const PyTypeObject rabin_pytype_skel = {
591bf41b 333 PyVarObject_HEAD_INIT(0, 0) /* Header */
c461c9b3 334 "RabinMiller", /* @tp_name@ */
d7ab1bab 335 sizeof(rabin_pyobj), /* @tp_basicsize@ */
336 0, /* @tp_itemsize@ */
337
338 rabin_pydealloc, /* @tp_dealloc@ */
339 0, /* @tp_print@ */
340 0, /* @tp_getattr@ */
341 0, /* @tp_setattr@ */
342 0, /* @tp_compare@ */
343 0, /* @tp_repr@ */
344 0, /* @tp_as_number@ */
345 0, /* @tp_as_sequence@ */
346 0, /* @tp_as_mapping@ */
347 0, /* @tp_hash@ */
348 0, /* @tp_call@ */
349 0, /* @tp_str@ */
350 0, /* @tp_getattro@ */
351 0, /* @tp_setattro@ */
352 0, /* @tp_as_buffer@ */
353 Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
354 Py_TPFLAGS_BASETYPE,
355
356 /* @tp_doc@ */
d96c882e 357 "RabinMiller(X): Rabin-Miller strong primality test.",
d7ab1bab 358
359 0, /* @tp_traverse@ */
360 0, /* @tp_clear@ */
361 0, /* @tp_richcompare@ */
362 0, /* @tp_weaklistoffset@ */
363 0, /* @tp_iter@ */
963a6148 364 0, /* @tp_iternext@ */
c90f712e 365 PYMETHODS(rabin), /* @tp_methods@ */
d7ab1bab 366 0, /* @tp_members@ */
c90f712e 367 PYGETSET(rabin), /* @tp_getset@ */
d7ab1bab 368 0, /* @tp_base@ */
369 0, /* @tp_dict@ */
370 0, /* @tp_descr_get@ */
371 0, /* @tp_descr_set@ */
372 0, /* @tp_dictoffset@ */
373 0, /* @tp_init@ */
374 PyType_GenericAlloc, /* @tp_alloc@ */
375 rabin_pynew, /* @tp_new@ */
3aa33042 376 0, /* @tp_free@ */
d7ab1bab 377 0 /* @tp_is_gc@ */
378};
379
380/*----- Events ------------------------------------------------------------*/
381
382typedef struct pgevent_pyobj {
383 PyObject_HEAD
d65d80d7 384 PyObject *r;
d7ab1bab 385 pgen_event *ev;
386} pgevent_pyobj;
387
388static PyTypeObject *pgevent_pytype;
389#define PGEVENT_EV(o) (((pgevent_pyobj *)(o))->ev)
390
391static PyObject *pgevent_pywrap(pgen_event *ev)
392{
393 pgevent_pyobj *o = PyObject_New(pgevent_pyobj, pgevent_pytype);
d65d80d7 394 o->ev = ev; o->r = 0;
d7ab1bab 395 return ((PyObject *)o);
396}
397
398static CONVFUNC(pgevent, pgen_event *, PGEVENT_EV)
399
d65d80d7
MW
400static void pgevent_kill(PyObject *me)
401{
402 pgevent_pyobj *ev = (pgevent_pyobj *)me;
403
404 ev->ev = 0;
405 if (ev->r) GRAND_R(ev->r) = 0;
406}
407
408static void pgevent_pydealloc(PyObject *me)
409{
410 pgevent_pyobj *ev = (pgevent_pyobj *)me;
19a4c416 411 Py_XDECREF(ev->r); FREEOBJ(me);
d65d80d7 412}
d7ab1bab 413
414#define PGEVENT_CHECK(me) do { \
415 if (!PGEVENT_EV(me)) { \
d65d80d7 416 PyErr_SetString(PyExc_ValueError, "event object is no longer valid"); \
d7ab1bab 417 return (0); \
418 } \
419} while (0)
420
421static PyObject *peget_name(PyObject *me, void *hunoz)
2135a6d3 422 { PGEVENT_CHECK(me); return (TEXT_FROMSTR(PGEVENT_EV(me)->name)); }
d7ab1bab 423
424static PyObject *peget_x(PyObject *me, void *hunoz)
425 { PGEVENT_CHECK(me); return (mp_pywrap(MP_COPY(PGEVENT_EV(me)->m))); }
426
427static PyObject *peget_steps(PyObject *me, void *hunoz)
428 { PGEVENT_CHECK(me); return (PyInt_FromLong(PGEVENT_EV(me)->steps)); }
429
430static PyObject *peget_tests(PyObject *me, void *hunoz)
431 { PGEVENT_CHECK(me); return (PyInt_FromLong(PGEVENT_EV(me)->tests)); }
432
433static PyObject *peget_rng(PyObject *me, void *hunoz)
d65d80d7
MW
434{
435 pgevent_pyobj *ev = (pgevent_pyobj *)me;
436
437 PGEVENT_CHECK(me);
438 if (!ev->r) ev->r = grand_pywrap(ev->ev->r, 0);
439 Py_INCREF(ev->r); return ((PyObject *)ev->r);
440}
d7ab1bab 441
442static int peset_x(PyObject *me, PyObject *xobj, void *hunoz)
443{
444 mp *x = 0;
445 pgen_event *ev = PGEVENT_EV(me);
446 int rc = -1;
03e1fedf 447 if (!xobj) NIERR("__del__");
d7ab1bab 448 PGEVENT_CHECK(me);
449 if ((x = getmp(xobj)) == 0) goto end;
450 mp_drop(ev->m);
451 ev->m = MP_COPY(x);
452 rc = 0;
453end:
454 mp_drop(x);
455 return (rc);
456}
457
c90f712e 458static const PyGetSetDef pgevent_pygetset[] = {
d7ab1bab 459#define GETSETNAME(op, name) pe##op##_##name
460 GET (name, "EV.name -> value being generated")
461 GETSET(x, "EV.x -> value under test")
462 GET (steps, "EV.steps -> number of steps left")
463 GET (tests, "EV.tests -> tests before passing")
464 GET (rng, "EV.rng -> (noncrypto) random number generator")
465#undef GETSETNAME
466 { 0 }
467};
468
c263b05c 469static const PyTypeObject pgevent_pytype_skel = {
591bf41b 470 PyVarObject_HEAD_INIT(0, 0) /* Header */
c461c9b3 471 "PrimeGenEvent", /* @tp_name@ */
d7ab1bab 472 sizeof(pgevent_pyobj), /* @tp_basicsize@ */
473 0, /* @tp_itemsize@ */
474
475 pgevent_pydealloc, /* @tp_dealloc@ */
476 0, /* @tp_print@ */
477 0, /* @tp_getattr@ */
478 0, /* @tp_setattr@ */
479 0, /* @tp_compare@ */
480 0, /* @tp_repr@ */
481 0, /* @tp_as_number@ */
482 0, /* @tp_as_sequence@ */
483 0, /* @tp_as_mapping@ */
484 0, /* @tp_hash@ */
485 0, /* @tp_call@ */
486 0, /* @tp_str@ */
487 0, /* @tp_getattro@ */
488 0, /* @tp_setattro@ */
489 0, /* @tp_as_buffer@ */
490 Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
491 Py_TPFLAGS_BASETYPE,
492
493 /* @tp_doc@ */
d96c882e 494 "Prime-generation event.",
d7ab1bab 495
496 0, /* @tp_traverse@ */
497 0, /* @tp_clear@ */
498 0, /* @tp_richcompare@ */
499 0, /* @tp_weaklistoffset@ */
500 0, /* @tp_iter@ */
963a6148 501 0, /* @tp_iternext@ */
d7ab1bab 502 0, /* @tp_methods@ */
503 0, /* @tp_members@ */
c90f712e 504 PYGETSET(pgevent), /* @tp_getset@ */
d7ab1bab 505 0, /* @tp_base@ */
506 0, /* @tp_dict@ */
507 0, /* @tp_descr_get@ */
508 0, /* @tp_descr_set@ */
509 0, /* @tp_dictoffset@ */
510 0, /* @tp_init@ */
511 PyType_GenericAlloc, /* @tp_alloc@ */
512 abstract_pynew, /* @tp_new@ */
3aa33042 513 0, /* @tp_free@ */
d7ab1bab 514 0 /* @tp_is_gc@ */
515};
516
517/*----- Event handlers ----------------------------------------------------*/
518
519PyTypeObject *pgev_pytype;
520
521typedef struct pgstep_pyobj {
522 PGEV_HEAD
523 pgen_filterctx f;
524} pgstep_pyobj;
525
526static PyTypeObject *pgstep_pytype;
527#define PGSTEP_STEP(o) (((pgstep_pyobj *)(o))->f.step)
528
529typedef struct pgjump_pyobj {
530 PGEV_HEAD
531 PyObject *fobj;
532 pgen_jumpctx j;
533} pgjump_pyobj;
534
535static PyTypeObject *pgjump_pytype;
536#define PGJUMP_FOBJ(o) (((pgjump_pyobj *)(o))->fobj)
537#define PGJUMP_J(o) (&((pgjump_pyobj *)(o))->j)
538
539typedef struct pgtest_pyobj {
540 PGEV_HEAD
541 rabin r;
542} pgtest_pyobj;
543
544static PyTypeObject *pgtest_pytype;
545
546static int pgev_python(int rq, pgen_event *ev, void *p)
547{
930d78e3 548 pypgev *pg = p;
d7ab1bab 549 PyObject *pyev = 0;
550 PyObject *rc = 0;
551 int st = PGEN_ABORT;
552 long l;
827f89d7
MW
553 static const char *const meth[] =
554 { "pg_abort", "pg_done", "pg_begin", "pg_try", "pg_fail", "pg_pass" };
d7ab1bab 555
d7ab1bab 556 rq++;
557 if (rq > N(meth)) SYSERR("event code out of range");
558 pyev = pgevent_pywrap(ev);
7f38dc76 559 if ((rc = PyObject_CallMethod(pg->obj, (/*unconst*/ char *)meth[rq],
827f89d7 560 "(O)", pyev)) == 0)
d7ab1bab 561 goto end;
562 if (rc == Py_None)
563 st = PGEN_TRY;
564 else if ((l = PyInt_AsLong(rc)) == -1 && PyErr_Occurred())
565 goto end;
566 else if (l < PGEN_ABORT || l > PGEN_PASS)
567 VALERR("return code out of range");
b2687a0a 568 else
d7ab1bab 569 st = l;
570end:
930d78e3
MW
571 if (PyErr_Occurred())
572 stash_exception(pg->exc, "exception from `pgen' handler");
d7ab1bab 573 if (pyev) {
574 pgevent_kill(pyev);
575 Py_DECREF(pyev);
576 }
577 Py_XDECREF(rc);
d7ab1bab 578 return (st);
579}
580
581static PyObject *pgev_pywrap(const pgev *pg)
582{
583 pgev_pyobj *o;
584
585 o = PyObject_New(pgev_pyobj, pgev_pytype);
586 o->pg = *pg;
587 return ((PyObject *)o);
588}
589
590int convpgev(PyObject *o, void *p)
591{
930d78e3 592 pypgev *pg = p;
d7ab1bab 593
594 if (PGEV_PYCHECK(o))
930d78e3 595 pg->ev = *PGEV_PG(o);
d7ab1bab 596 else {
930d78e3
MW
597 pg->ev.proc = pgev_python;
598 pg->ev.ctx = pg;
599 pg->obj = o; Py_INCREF(o);
d7ab1bab 600 }
601 return (1);
602}
603
930d78e3 604void droppgev(pypgev *pg)
d7ab1bab 605{
930d78e3
MW
606 if (pg->ev.proc == pgev_python)
607 { assert(pg->ev.ctx == pg); Py_DECREF(pg->obj); }
d7ab1bab 608}
609
610static PyObject *pgmeth_common(PyObject *me, PyObject *arg, int rq)
611{
612 pgen_event *ev;
613 pgev *pg = PGEV_PG(me);
614 PyObject *rc = 0;
615
616 if (!PyArg_ParseTuple(arg, "O&", convpgevent, &ev)) goto end;
617 rc = PyInt_FromLong(!pg->proc ? rq : pg->proc(rq, ev, pg->ctx));
618end:
619 return (rc);
620}
621
622#define PGMETH(lc, uc) \
623 static PyObject *pgmeth_pg_##lc(PyObject *me, PyObject *arg) \
624 { return pgmeth_common(me, arg, PGEN_##uc); }
625PGMETH(abort, ABORT)
626PGMETH(done, DONE)
627PGMETH(begin, BEGIN)
628PGMETH(try, TRY)
629PGMETH(pass, PASS)
630PGMETH(fail, FAIL)
631#undef PGMETH
632
633static PyObject *pgev_stdev(pgen_proc *proc)
634 { pgev pg; pg.proc = proc; pg.ctx = 0; return (pgev_pywrap(&pg)); }
635
c90f712e 636static const PyMethodDef pgev_pymethods[] = {
d7ab1bab 637#define METHNAME(name) pgmeth_##name
fb23e96c
MW
638 METH (pg_abort, "E.pg_abort(EV) -> PGST -- prime generation aborted")
639 METH (pg_done, "E.pg_done(EV) -> PGST -- prime generation finished")
640 METH (pg_begin, "E.pg_begin(EV) -> PGST -- commence stepping/testing")
641 METH (pg_try, "E.pg_try(EV) -> PGST -- found new candidate")
642 METH (pg_pass, "E.pg_pass(EV) -> PGST -- passed primality test")
643 METH (pg_fail, "E.pg_fail(EV) -> PGST -- failed primality test")
d7ab1bab 644#undef METHNAME
645 { 0 }
646};
647
c263b05c 648static const PyTypeObject pgev_pytype_skel = {
591bf41b 649 PyVarObject_HEAD_INIT(0, 0) /* Header */
c461c9b3 650 "PrimeGenBuiltinHandler", /* @tp_name@ */
d7ab1bab 651 sizeof(pgev_pyobj), /* @tp_basicsize@ */
652 0, /* @tp_itemsize@ */
653
3aa33042 654 0, /* @tp_dealloc@ */
d7ab1bab 655 0, /* @tp_print@ */
656 0, /* @tp_getattr@ */
657 0, /* @tp_setattr@ */
658 0, /* @tp_compare@ */
659 0, /* @tp_repr@ */
660 0, /* @tp_as_number@ */
661 0, /* @tp_as_sequence@ */
662 0, /* @tp_as_mapping@ */
663 0, /* @tp_hash@ */
664 0, /* @tp_call@ */
665 0, /* @tp_str@ */
666 0, /* @tp_getattro@ */
667 0, /* @tp_setattro@ */
668 0, /* @tp_as_buffer@ */
669 Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
670 Py_TPFLAGS_BASETYPE,
671
672 /* @tp_doc@ */
d96c882e 673 "Built-in prime-generation event handler, base class.",
d7ab1bab 674
675 0, /* @tp_traverse@ */
676 0, /* @tp_clear@ */
677 0, /* @tp_richcompare@ */
678 0, /* @tp_weaklistoffset@ */
679 0, /* @tp_iter@ */
963a6148 680 0, /* @tp_iternext@ */
c90f712e 681 PYMETHODS(pgev), /* @tp_methods@ */
d7ab1bab 682 0, /* @tp_members@ */
683 0, /* @tp_getset@ */
684 0, /* @tp_base@ */
685 0, /* @tp_dict@ */
686 0, /* @tp_descr_get@ */
687 0, /* @tp_descr_set@ */
688 0, /* @tp_dictoffset@ */
689 0, /* @tp_init@ */
690 PyType_GenericAlloc, /* @tp_alloc@ */
691 abstract_pynew, /* @tp_new@ */
3aa33042 692 0, /* @tp_free@ */
d7ab1bab 693 0 /* @tp_is_gc@ */
694};
695
696static PyObject *pgstep_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
697{
698 mpw s;
699 pgstep_pyobj *rc = 0;
827f89d7 700 static const char *const kwlist[] = { "step", 0 };
d7ab1bab 701
827f89d7 702 if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:new", KWLIST, convmpw, &s))
d7ab1bab 703 goto end;
704 rc = (pgstep_pyobj *)ty->tp_alloc(ty, 0);
705 rc->f.step = s;
706 rc->pg.proc = pgen_filter;
707 rc->pg.ctx = &rc->f;
708end:
709 return ((PyObject *)rc);
710}
711
712static PyObject *psget_step(PyObject *me, void *hunoz)
713 { return (PyInt_FromLong(PGSTEP_STEP(me))); }
714
c90f712e 715static const PyGetSetDef pgstep_pygetset[] = {
d7ab1bab 716#define GETSETNAME(op, name) ps##op##_##name
b2687a0a 717 GET (step, "S.step -> step size for the stepper")
d7ab1bab 718#undef GETSETNAME
719 { 0 }
720};
721
c263b05c 722static const PyTypeObject pgstep_pytype_skel = {
591bf41b 723 PyVarObject_HEAD_INIT(0, 0) /* Header */
c461c9b3 724 "PrimeGenStepper", /* @tp_name@ */
d7ab1bab 725 sizeof(pgstep_pyobj), /* @tp_basicsize@ */
726 0, /* @tp_itemsize@ */
727
728 0, /* @tp_dealloc@ */
729 0, /* @tp_print@ */
730 0, /* @tp_getattr@ */
731 0, /* @tp_setattr@ */
732 0, /* @tp_compare@ */
733 0, /* @tp_repr@ */
734 0, /* @tp_as_number@ */
735 0, /* @tp_as_sequence@ */
736 0, /* @tp_as_mapping@ */
737 0, /* @tp_hash@ */
738 0, /* @tp_call@ */
739 0, /* @tp_str@ */
740 0, /* @tp_getattro@ */
741 0, /* @tp_setattro@ */
742 0, /* @tp_as_buffer@ */
743 Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
744 Py_TPFLAGS_BASETYPE,
745
746 /* @tp_doc@ */
d96c882e 747 "PrimeGenStepper(STEP): simple stepper with small-factors filter.",
d7ab1bab 748
749 0, /* @tp_traverse@ */
750 0, /* @tp_clear@ */
751 0, /* @tp_richcompare@ */
752 0, /* @tp_weaklistoffset@ */
753 0, /* @tp_iter@ */
963a6148 754 0, /* @tp_iternext@ */
d7ab1bab 755 0, /* @tp_methods@ */
756 0, /* @tp_members@ */
c90f712e 757 PYGETSET(pgstep), /* @tp_getset@ */
d7ab1bab 758 0, /* @tp_base@ */
759 0, /* @tp_dict@ */
760 0, /* @tp_descr_get@ */
761 0, /* @tp_descr_set@ */
762 0, /* @tp_dictoffset@ */
763 0, /* @tp_init@ */
764 PyType_GenericAlloc, /* @tp_alloc@ */
765 pgstep_pynew, /* @tp_new@ */
3aa33042 766 0, /* @tp_free@ */
d7ab1bab 767 0 /* @tp_is_gc@ */
768};
769
770static PyObject *pgjump_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
771{
772 PyObject *o, *fobj;
773 pgjump_pyobj *rc = 0;
827f89d7 774 static const char *const kwlist[] = { "jump", 0 };
d7ab1bab 775
827f89d7 776 if (!PyArg_ParseTupleAndKeywords(arg, kw, "O:new", KWLIST, &o) ||
d7ab1bab 777 (fobj = pfilt_pymake(pfilt_pytype, o)) == 0)
778 goto end;
779 rc = (pgjump_pyobj *)ty->tp_alloc(ty, 0);
780 rc->fobj = fobj;
781 rc->j.j = PFILT_F(fobj);
782 rc->pg.proc = pgen_jump;
783 rc->pg.ctx = &rc->j;
784end:
785 return ((PyObject *)rc);
786}
787
788static void pgjump_pydealloc(PyObject *me)
789{
790 Py_DECREF(PGJUMP_FOBJ(me));
3aa33042 791 FREEOBJ(me);
d7ab1bab 792}
793
794static PyObject *pjget_jump(PyObject *me, void *hunoz)
795 { RETURN_OBJ(PGJUMP_FOBJ(me)); }
796
c90f712e 797static const PyGetSetDef pgjump_pygetset[] = {
d7ab1bab 798#define GETSETNAME(op, name) pj##op##_##name
b2687a0a 799 GET (jump, "S.jump -> jump size for the stepper")
d7ab1bab 800#undef GETSETNAME
801 { 0 }
802};
803
c263b05c 804static const PyTypeObject pgjump_pytype_skel = {
591bf41b 805 PyVarObject_HEAD_INIT(0, 0) /* Header */
c461c9b3 806 "PrimeGenJumper", /* @tp_name@ */
d7ab1bab 807 sizeof(pgjump_pyobj), /* @tp_basicsize@ */
808 0, /* @tp_itemsize@ */
809
810 pgjump_pydealloc, /* @tp_dealloc@ */
811 0, /* @tp_print@ */
812 0, /* @tp_getattr@ */
813 0, /* @tp_setattr@ */
814 0, /* @tp_compare@ */
815 0, /* @tp_repr@ */
816 0, /* @tp_as_number@ */
817 0, /* @tp_as_sequence@ */
818 0, /* @tp_as_mapping@ */
819 0, /* @tp_hash@ */
820 0, /* @tp_call@ */
821 0, /* @tp_str@ */
822 0, /* @tp_getattro@ */
823 0, /* @tp_setattro@ */
824 0, /* @tp_as_buffer@ */
825 Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
826 Py_TPFLAGS_BASETYPE,
827
828 /* @tp_doc@ */
d96c882e
MW
829 "PrimeGenJumper(JUMP): "
830 "stepper for larger steps with small-factors filter.",
d7ab1bab 831
832 0, /* @tp_traverse@ */
833 0, /* @tp_clear@ */
834 0, /* @tp_richcompare@ */
835 0, /* @tp_weaklistoffset@ */
836 0, /* @tp_iter@ */
963a6148 837 0, /* @tp_iternext@ */
d7ab1bab 838 0, /* @tp_methods@ */
839 0, /* @tp_members@ */
c90f712e 840 PYGETSET(pgjump), /* @tp_getset@ */
d7ab1bab 841 0, /* @tp_base@ */
842 0, /* @tp_dict@ */
843 0, /* @tp_descr_get@ */
844 0, /* @tp_descr_set@ */
845 0, /* @tp_dictoffset@ */
846 0, /* @tp_init@ */
847 PyType_GenericAlloc, /* @tp_alloc@ */
848 pgjump_pynew, /* @tp_new@ */
3aa33042 849 0, /* @tp_free@ */
d7ab1bab 850 0 /* @tp_is_gc@ */
851};
852
853static PyObject *pgtest_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
854{
855 pgtest_pyobj *rc = 0;
827f89d7 856 static const char *const kwlist[] = { 0 };
d7ab1bab 857
827f89d7 858 if (!PyArg_ParseTupleAndKeywords(arg, kw, ":new", KWLIST)) goto end;
d7ab1bab 859 rc = (pgtest_pyobj *)ty->tp_alloc(ty, 0);
860 rc->pg.proc = pgen_test;
861 rc->pg.ctx = &rc->r;
862end:
863 return ((PyObject *)rc);
864}
865
c263b05c 866static const PyTypeObject pgtest_pytype_skel = {
591bf41b 867 PyVarObject_HEAD_INIT(0, 0) /* Header */
c461c9b3 868 "PrimeGenTester", /* @tp_name@ */
d7ab1bab 869 sizeof(pgtest_pyobj), /* @tp_basicsize@ */
870 0, /* @tp_itemsize@ */
871
872 0, /* @tp_dealloc@ */
873 0, /* @tp_print@ */
874 0, /* @tp_getattr@ */
875 0, /* @tp_setattr@ */
876 0, /* @tp_compare@ */
877 0, /* @tp_repr@ */
878 0, /* @tp_as_number@ */
879 0, /* @tp_as_sequence@ */
880 0, /* @tp_as_mapping@ */
881 0, /* @tp_hash@ */
882 0, /* @tp_call@ */
883 0, /* @tp_str@ */
884 0, /* @tp_getattro@ */
885 0, /* @tp_setattro@ */
886 0, /* @tp_as_buffer@ */
887 Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
888 Py_TPFLAGS_BASETYPE,
889
890 /* @tp_doc@ */
d96c882e 891 "PrimeGenTester(): Rabin-Miller tester.",
d7ab1bab 892
893 0, /* @tp_traverse@ */
894 0, /* @tp_clear@ */
895 0, /* @tp_richcompare@ */
896 0, /* @tp_weaklistoffset@ */
897 0, /* @tp_iter@ */
963a6148 898 0, /* @tp_iternext@ */
d7ab1bab 899 0, /* @tp_methods@ */
900 0, /* @tp_members@ */
901 0, /* @tp_getset@ */
902 0, /* @tp_base@ */
903 0, /* @tp_dict@ */
904 0, /* @tp_descr_get@ */
905 0, /* @tp_descr_set@ */
906 0, /* @tp_dictoffset@ */
907 0, /* @tp_init@ */
908 PyType_GenericAlloc, /* @tp_alloc@ */
909 pgtest_pynew, /* @tp_new@ */
3aa33042 910 0, /* @tp_free@ */
d7ab1bab 911 0 /* @tp_is_gc@ */
912};
913
914/*----- Prime generation functions ----------------------------------------*/
915
930d78e3 916void pgenerr(struct excinfo *exc)
d7ab1bab 917{
930d78e3
MW
918 if (exc->ty) RESTORE_EXCINFO(exc);
919 else PyErr_SetString(PyExc_ValueError, "prime generation failed");
d7ab1bab 920}
921
922static PyObject *meth_pgen(PyObject *me, PyObject *arg, PyObject *kw)
923{
924 mp *x = 0;
925 mp *r = 0;
926 PyObject *rc = 0;
927 char *p = "p";
928 pgen_filterctx fc = { 2 };
929 rabin tc;
930d78e3
MW
930 struct excinfo exc = EXCINFO_INIT;
931 pypgev step = { { 0 } }, test = { { 0 } }, evt = { { 0 } };
d7ab1bab 932 unsigned nsteps = 0, ntests = 0;
827f89d7
MW
933 static const char *const kwlist[] =
934 { "start", "name", "stepper", "tester", "event", "nsteps", "ntests", 0 };
d7ab1bab 935
930d78e3
MW
936 step.exc = &exc; step.ev.proc = pgen_filter; step.ev.ctx = &fc;
937 test.exc = &exc; test.ev.proc = pgen_test; test.ev.ctx = &tc;
938 evt.exc = &exc;
827f89d7 939 if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|sO&O&O&O&O&:pgen", KWLIST,
d7ab1bab 940 convmp, &x, &p, convpgev, &step,
941 convpgev, &test, convpgev, &evt,
942 convuint, &nsteps, convuint, &ntests))
943 goto end;
944 if (!ntests) ntests = rabin_iters(mp_bits(x));
930d78e3
MW
945 if ((r = pgen(p, MP_NEW, x, evt.ev.proc, evt.ev.ctx,
946 nsteps, step.ev.proc, step.ev.ctx,
947 ntests, test.ev.proc, test.ev.ctx)) == 0)
948 PGENERR(&exc);
949 rc = mp_pywrap(r); r = 0;
d7ab1bab 950end:
951 mp_drop(r); mp_drop(x);
952 droppgev(&step); droppgev(&test); droppgev(&evt);
b2687a0a 953 return (rc);
d7ab1bab 954}
955
956static PyObject *meth_strongprime_setup(PyObject *me,
957 PyObject *arg, PyObject *kw)
958{
959 mp *x = 0;
960 pfilt f;
961 grand *r = &rand_global;
962 unsigned nbits;
963 char *name = "p";
964 unsigned n = 0;
930d78e3
MW
965 struct excinfo exc = EXCINFO_INIT;
966 pypgev evt = { { 0 } };
d7ab1bab 967 PyObject *rc = 0;
827f89d7
MW
968 static const char *const kwlist[] =
969 { "nbits", "name", "event", "rng", "nsteps", 0 };
d7ab1bab 970
930d78e3 971 evt.exc = &exc;
827f89d7 972 if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|sO&O&O&", KWLIST,
d7ab1bab 973 convuint, &nbits, &name,
974 convpgev, &evt, convgrand, &r,
975 convuint, &n))
976 goto end;
977 if ((x = strongprime_setup(name, MP_NEW, &f, nbits,
930d78e3
MW
978 r, n, evt.ev.proc, evt.ev.ctx)) == 0)
979 PGENERR(&exc);
d7ab1bab 980 rc = Py_BuildValue("(NN)", mp_pywrap(x), pfilt_pywrap(&f));
981 x = 0;
982end:
983 mp_drop(x);
984 droppgev(&evt);
985 return (rc);
986}
987
988static PyObject *meth_strongprime(PyObject *me, PyObject *arg, PyObject *kw)
989{
990 mp *x = 0;
991 grand *r = &rand_global;
992 unsigned nbits;
993 char *name = "p";
994 unsigned n = 0;
930d78e3
MW
995 struct excinfo exc = EXCINFO_INIT;
996 pypgev evt = { { 0 } };
d7ab1bab 997 PyObject *rc = 0;
827f89d7
MW
998 static const char *const kwlist[] =
999 { "nbits", "name", "event", "rng", "nsteps", 0 };
d7ab1bab 1000
930d78e3 1001 evt.exc = &exc;
827f89d7 1002 if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|sO&O&O&", KWLIST,
d7ab1bab 1003 convuint, &nbits, &name,
1004 convpgev, &evt, convgrand, &r,
1005 convuint, &n))
1006 goto end;
1007 if ((x = strongprime(name, MP_NEW, nbits,
930d78e3
MW
1008 r, n, evt.ev.proc, evt.ev.ctx)) == 0)
1009 PGENERR(&exc);
d7ab1bab 1010 rc = mp_pywrap(x);
1011 x = 0;
1012end:
1013 mp_drop(x);
1014 droppgev(&evt);
1015 return (rc);
1016}
1017
1018static PyObject *meth_limlee(PyObject *me, PyObject *arg, PyObject *kw)
1019{
1020 char *p = "p";
930d78e3
MW
1021 struct excinfo exc = EXCINFO_INIT;
1022 pypgev ie = { { 0 } }, oe = { { 0 } };
d7ab1bab 1023 unsigned ql, pl;
1024 grand *r = &rand_global;
1025 unsigned on = 0;
1026 size_t i, nf = 0;
1027 PyObject *rc = 0, *vec;
827f89d7
MW
1028 static const char *const kwlist[] =
1029 { "pbits", "qbits", "name", "event", "ievent", "rng", "nsteps", 0 };
d7ab1bab 1030 mp *x = 0, **v = 0;
1031
930d78e3 1032 ie.exc = oe.exc = &exc;
827f89d7 1033 if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&|sO&O&O&O&:limlee", KWLIST,
d7ab1bab 1034 convuint, &pl, convuint, &ql,
1035 &p, convpgev, &oe, convpgev, &ie,
1036 convgrand, &r, convuint, &on))
1037 goto end;
1038 if ((x = limlee(p, MP_NEW, MP_NEW, ql, pl, r, on,
930d78e3
MW
1039 oe.ev.proc, oe.ev.ctx, ie.ev.proc, ie.ev.ctx,
1040 &nf, &v)) == 0)
1041 PGENERR(&exc);;
d7ab1bab 1042 vec = PyList_New(nf);
1043 for (i = 0; i < nf; i++)
c51a597d 1044 PyList_SET_ITEM(vec, i, mp_pywrap(v[i]));
d7ab1bab 1045 xfree(v);
1046 rc = Py_BuildValue("(NN)", mp_pywrap(x), vec);
1047end:
1048 droppgev(&oe); droppgev(&ie);
1049 return (rc);
1050}
1051
1052/*----- Global stuff ------------------------------------------------------*/
1053
810542b0
MW
1054static const struct nameval consts[] = {
1055 CONST(PGEN_PASS), CONST(PGEN_FAIL), CONST(PGEN_BEGIN), CONST(PGEN_TRY),
1056 CONST(PGEN_DONE), CONST(PGEN_ABORT),
1057 { 0 }
1058};
1059
c90f712e 1060static const PyMethodDef methods[] = {
d7ab1bab 1061#define METHNAME(name) meth_##name
d96c882e
MW
1062 KWMETH(pgen,
1063 "pgen(START, [name = 'p'], [stepper = PrimeGenStepper(2)],\n"
1064 " [tester = PrimeGenTester()], [event = pgen_nullev],\n"
1065 " [nsteps = 0], [ntests = RabinMiller.iters(START.nbits)]) -> P")
1066 KWMETH(strongprime_setup,
1067 "strongprime_setup(NBITS, [name = 'p'], [event = pgen_nullev],\n"
1068 " [rng = rand], [nsteps = 0]) -> (START, JUMP)")
1069 KWMETH(strongprime,
1070 "strongprime(NBITS, [name = 'p'], [event = pgen_nullev],\n"
1071 " [rng = rand], [nsteps = 0]) -> P")
1072 KWMETH(limlee,
1073 "limlee(PBITS, QBITS, [name = 'p'], [event = pgen_nullev],\n"
1074 " [ievent = pgen_nullev], [rng = rand], [nsteps = 0]) "
1075 "-> (P, [Q, ...])")
d7ab1bab 1076#undef METHNAME
1077 { 0 }
1078};
1079
1080void pgen_pyinit(void)
1081{
1082 INITTYPE(pfilt, root);
1083 INITTYPE(rabin, root);
1084 INITTYPE(pgevent, root);
1085 INITTYPE(pgev, root);
1086 INITTYPE(pgstep, pgev);
1087 INITTYPE(pgjump, pgev);
1088 INITTYPE(pgtest, pgev);
1089 addmethods(methods);
1090}
1091
1092static PyObject *obj;
1093
1094void pgen_pyinsert(PyObject *mod)
1095{
1096 INSERT("PrimeFilter", pfilt_pytype);
1097 INSERT("RabinMiller", rabin_pytype);
1098 INSERT("PrimeGenEvent", pgevent_pytype);
1099 INSERT("PrimeGenBuiltinHandler", pgev_pytype);
1100 INSERT("PrimeGenStepper", pgstep_pytype);
1101 INSERT("PrimeGenJumper", pgjump_pytype);
1102 INSERT("PrimeGenTester", pgtest_pytype);
1103 INSERT("pgen_nullev", obj = pgev_stdev(0));
1104 INSERT("pgen_stdev", pgev_stdev(pgen_ev));
1105 INSERT("pgen_spinev", pgev_stdev(pgen_evspin));
1106 INSERT("pgen_subev", pgev_stdev(pgen_subev));
810542b0 1107 setconstants(mod, consts);
d7ab1bab 1108}
1109
1110/*----- That's all, folks -------------------------------------------------*/