d7ab1bab |
1 | /* -*-c-*- |
2 | * |
3 | * $Id$ |
4 | * |
5 | * Abstract fields |
6 | * |
7 | * (c) 2004 Straylight/Edgeware |
8 | */ |
9 | |
10 | /*----- Licensing notice --------------------------------------------------* |
11 | * |
12 | * This file is part of the Python interface to Catacomb. |
13 | * |
14 | * Catacomb/Python is free software; you can redistribute it and/or modify |
15 | * it under the terms of the GNU General Public License as published by |
16 | * the Free Software Foundation; either version 2 of the License, or |
17 | * (at your option) any later version. |
18 | * |
19 | * Catacomb/Python is distributed in the hope that it will be useful, |
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
22 | * GNU General Public License for more details. |
23 | * |
24 | * You should have received a copy of the GNU General Public License |
25 | * along with Catacomb/Python; if not, write to the Free Software Foundation, |
26 | * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
27 | */ |
28 | |
29 | /*----- Header files ------------------------------------------------------*/ |
30 | |
31 | #include "catacomb-python.h" |
32 | |
33 | /*----- Various utilities -------------------------------------------------*/ |
34 | |
35 | PyTypeObject *field_pytype; |
36 | PyTypeObject *primefield_pytype; |
37 | PyTypeObject *niceprimefield_pytype; |
38 | PyTypeObject *binfield_pytype; |
39 | PyTypeObject *binpolyfield_pytype; |
40 | PyTypeObject *binnormfield_pytype; |
41 | PyTypeObject *fe_pytype; |
42 | |
43 | static PyObject *fe_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw) |
44 | { |
45 | PyObject *x; |
46 | mp *z; |
47 | char *kwlist[] = { "x", 0 }; |
48 | |
49 | if (!PyArg_ParseTupleAndKeywords(arg, kw, "O:fe", kwlist, &x)) |
50 | return (0); |
51 | if (FE_PYCHECK(x) && FE_F(x) == FIELD_F(ty)) RETURN_OBJ(x); |
52 | if ((z = getmp(x)) == 0) return (0); |
53 | z = F_IN(FIELD_F(ty), z, z); |
54 | return (fe_pywrap((PyObject *)ty, z)); |
55 | } |
56 | |
57 | static PyObject *field_dopywrap(PyTypeObject *ty, field *f) |
58 | { |
df9f8366 |
59 | field_pyobj *fobj = newtype(ty, 0, f->ops->name); |
d7ab1bab |
60 | fobj->f = f; |
df9f8366 |
61 | fobj->ty.type.tp_basicsize = sizeof(fe_pyobj); |
62 | fobj->ty.type.tp_base = fe_pytype; |
d7ab1bab |
63 | Py_INCREF(fe_pytype); |
df9f8366 |
64 | fobj->ty.type.tp_flags = (Py_TPFLAGS_DEFAULT | |
65 | Py_TPFLAGS_BASETYPE | |
66 | Py_TPFLAGS_CHECKTYPES | |
67 | Py_TPFLAGS_HEAPTYPE); |
68 | fobj->ty.type.tp_alloc = PyType_GenericAlloc; |
69 | fobj->ty.type.tp_free = 0; |
70 | fobj->ty.type.tp_new = fe_pynew; |
71 | PyType_Ready(&fobj->ty.type); |
d7ab1bab |
72 | return ((PyObject *)fobj); |
73 | } |
74 | |
75 | PyObject *field_pywrap(field *f) |
76 | { |
77 | PyTypeObject *ty; |
78 | |
79 | if (strcmp(F_NAME(f), "prime") == 0) ty = primefield_pytype; |
80 | else if (strcmp(F_NAME(f), "niceprime") == 0) ty = niceprimefield_pytype; |
81 | else if (strcmp(F_NAME(f), "binpoly") == 0) ty = binpolyfield_pytype; |
82 | else if (strcmp(F_NAME(f), "binnorm") == 0) ty = binnormfield_pytype; |
83 | else abort(); |
84 | return (field_dopywrap(ty, f)); |
85 | } |
86 | |
87 | field *field_copy(field *f) |
88 | { |
89 | if (strcmp(F_NAME(f), "prime") == 0) |
90 | f = field_prime(f->m); |
91 | else if (strcmp(F_NAME(f), "niceprime") == 0) |
92 | f = field_niceprime(f->m); |
93 | else if (strcmp(F_NAME(f), "binpoly") == 0) |
94 | f = field_binpoly(f->m); |
95 | else if (strcmp(F_NAME(f), "binnorm") == 0) { |
96 | fctx_binnorm *fc = (fctx_binnorm *)f; |
97 | f = field_binnorm(f->m, fc->ntop.r[fc->ntop.n - 1]); |
98 | } else |
99 | abort(); |
100 | return (f); |
101 | } |
102 | |
103 | PyObject *fe_pywrap(PyObject *fobj, mp *x) |
104 | { |
105 | fe_pyobj *z = PyObject_New(fe_pyobj, (PyTypeObject *)fobj); |
106 | z->f = FIELD_F(fobj); |
107 | Py_INCREF(fobj); |
108 | z->x = x; |
109 | return ((PyObject *)z); |
110 | } |
111 | |
112 | static mp *tofe(field *f, PyObject *o) |
113 | { |
114 | mp *x = 0, *y = 0; |
115 | |
116 | if (FE_PYCHECK(o)) { |
117 | if (FE_F(o) != f && !field_samep(FE_F(o), f)) return (0); |
118 | y = FE_X(o); |
119 | } |
120 | if ((x = tomp(o)) != 0) { |
121 | if (MP_ZEROP(x)) |
122 | y = f->zero; |
123 | else if (MP_EQ(x, MP_ONE)) |
124 | y = f->one; |
125 | } |
126 | if (x) MP_DROP(x); |
127 | if (y) MP_COPY(y); |
128 | return (y); |
129 | } |
130 | |
131 | mp *getfe(field *f, PyObject *o) |
132 | { |
133 | mp *x = 0; |
134 | if ((x = tofe(f, o)) == 0) { |
135 | PyErr_Format(PyExc_TypeError, "can't convert %.100s to fe", |
136 | o->ob_type->tp_name); |
137 | } |
138 | return (x); |
139 | } |
140 | |
141 | /*----- Field elements ----------------------------------------------------*/ |
142 | |
143 | static int febinop(PyObject *x, PyObject *y, |
144 | field **f, PyObject **fobj, mp **xx, mp **yy) |
145 | { |
146 | if (FE_PYCHECK(x)) *fobj = FE_FOBJ(x); |
147 | else if (FE_PYCHECK(y)) *fobj = FE_FOBJ(y); |
148 | else return (-1); |
149 | *f = FIELD_F(*fobj); |
150 | if ((*xx = tofe(*f, x)) == 0) |
151 | return (-1); |
152 | if ((*yy = tofe(*f, y)) == 0) { |
153 | MP_DROP(*xx); |
154 | return (-1); |
155 | } |
156 | return (0); |
157 | } |
158 | |
159 | #define BINOP(name) \ |
160 | static PyObject *fe_py##name(PyObject *x, PyObject *y) { \ |
161 | PyObject *fobj; \ |
162 | field *ff; \ |
163 | mp *xx, *yy, *zz; \ |
164 | if (febinop(x, y, &ff, &fobj, &xx, &yy)) RETURN_NOTIMPL; \ |
165 | zz = ff->ops->name(ff, MP_NEW, xx, yy); \ |
166 | MP_DROP(xx); MP_DROP(yy); \ |
167 | return (fe_pywrap(fobj, zz)); \ |
168 | } |
169 | BINOP(add) |
170 | BINOP(sub) |
171 | BINOP(mul) |
172 | #undef BINOP |
173 | |
174 | static PyObject *fe_pydiv(PyObject *x, PyObject *y) |
175 | { |
176 | PyObject *fobj; |
177 | field *ff; |
178 | mp *xx, *yy; |
179 | PyObject *z = 0; |
180 | if (febinop(x, y, &ff, &fobj, &xx, &yy)) RETURN_NOTIMPL; |
181 | if (F_ZEROP(ff, yy)) ZDIVERR("division by zero"); |
182 | yy = F_INV(ff, yy, yy); |
183 | z = fe_pywrap(fobj, F_MUL(ff, MP_NEW, xx, yy)); |
184 | end: |
185 | MP_DROP(xx); MP_DROP(yy); |
186 | return (z); |
187 | } |
188 | |
189 | static PyObject *fe_pyexp(PyObject *x, PyObject *y, PyObject *z) |
190 | { |
191 | field *ff; |
192 | mp *xx, *yy; |
193 | |
194 | if (z != Py_None || !FE_PYCHECK(x) || (yy = tomp(y)) == 0) |
195 | RETURN_NOTIMPL; |
196 | ff = FE_F(x); xx = FE_X(x); MP_COPY(xx); |
197 | if (MP_NEGP(yy) && F_ZEROP(ff, xx)) ZDIVERR("division by zero"); |
198 | z = fe_pywrap(FE_FOBJ(x), field_exp(ff, MP_NEW, xx, yy)); |
199 | end: |
200 | MP_DROP(xx); MP_DROP(yy); |
201 | return (z); |
202 | } |
203 | |
204 | static PyObject *fe_pyneg(PyObject *x) |
205 | { |
206 | return fe_pywrap(FE_FOBJ(x), FE_F(x)->ops->neg(FE_F(x), MP_NEW, FE_X(x))); |
207 | } |
208 | |
209 | static PyObject *fe_pyid(PyObject *x) { RETURN_OBJ(x); } |
210 | |
211 | static int fe_pynonzerop(PyObject *x) { return !F_ZEROP(FE_F(x), FE_X(x)); } |
212 | |
213 | static PyObject *fe_pyrichcompare(PyObject *x, PyObject *y, int op) |
214 | { |
215 | PyObject *fobj; |
216 | field *ff; |
217 | mp *xx, *yy; |
218 | int b; |
219 | PyObject *rc = 0; |
220 | |
221 | if (febinop(x, y, &ff, &fobj, &xx, &yy)) RETURN_NOTIMPL; |
222 | switch (op) { |
223 | case Py_EQ: b = MP_EQ(xx, yy); break; |
224 | case Py_NE: b = !MP_EQ(xx, yy); break; |
225 | default: TYERR("field elements are unordered"); |
226 | } |
227 | rc = getbool(b); |
228 | end: |
229 | MP_DROP(xx); MP_DROP(yy); |
230 | return (rc); |
231 | } |
232 | |
233 | static long fe_pyhash(PyObject *me) |
234 | { |
235 | long i = mp_tolong(FE_X(me)); |
236 | i ^= 0xdcf62d6c; /* random perturbance */ |
237 | if (i == -1) |
238 | i = -2; |
239 | return (i); |
240 | } |
241 | |
242 | static int fe_pycoerce(PyObject **x, PyObject **y) |
243 | { |
244 | mp *z; |
245 | |
246 | if (FE_PYCHECK(*y)) { |
247 | if (FE_F(*x) != FE_F(*y) && !field_samep(FE_F(*x), FE_F(*y))) |
248 | TYERR("field mismatch"); |
249 | Py_INCREF(*x); Py_INCREF(*y); |
250 | return (0); |
251 | } |
252 | if ((z = tofe(FE_F(*x), *y)) != 0) { |
253 | Py_INCREF(*x); |
254 | *y = fe_pywrap(FE_FOBJ(*x), z); |
255 | return (0); |
256 | } |
257 | return (1); |
258 | |
259 | end: |
260 | return (-1); |
261 | } |
262 | |
263 | static PyObject *fe_pyint(PyObject *x) |
264 | { |
265 | long l; |
266 | mp *xx = F_OUT(FE_F(x), MP_NEW, FE_X(x)); |
267 | if (mp_tolong_checked(xx, &l)) { MP_DROP(xx); return (0); } |
268 | MP_DROP(xx); |
269 | return (PyInt_FromLong(l)); |
270 | } |
271 | |
272 | static PyObject *fe_pylong(PyObject *x) |
273 | { |
274 | mp *xx = F_OUT(FE_F(x), MP_NEW, FE_X(x)); |
275 | PyObject *rc = (PyObject *)mp_topylong(xx); |
276 | MP_DROP(xx); |
277 | return (rc); |
278 | } |
279 | |
280 | #define BASEOP(name, radix, pre) \ |
281 | static PyObject *fe_py##name(PyObject *x) { \ |
282 | mp *xx = F_OUT(FE_F(x), MP_NEW, FE_X(x)); \ |
283 | PyObject *rc = mp_topystring(FE_X(x), radix, 0, pre, 0); \ |
284 | MP_DROP(xx); \ |
285 | return (rc); \ |
286 | } |
287 | BASEOP(oct, 8, "0"); |
288 | BASEOP(hex, 16, "0x"); |
289 | #undef BASEOP |
290 | |
291 | static void fe_pydealloc(PyObject *me) |
292 | { |
293 | Py_DECREF(FE_FOBJ(me)); |
294 | MP_DROP(FE_X(me)); |
3aa33042 |
295 | FREEOBJ(me); |
d7ab1bab |
296 | } |
297 | |
298 | #define UNOP(name, check) \ |
299 | static PyObject *femeth_##name(PyObject *me, PyObject *arg) { \ |
300 | field *f = FE_F(me); \ |
301 | mp *x = FE_X(me); \ |
302 | if (!PyArg_ParseTuple(arg, ":" #name)) return (0); \ |
303 | if (!f->ops->name) TYERR(#name " not supported for this field"); \ |
304 | check \ |
305 | x = f->ops->name(f, MP_NEW, x); \ |
306 | if (!x) RETURN_NONE; \ |
307 | return (fe_pywrap(FE_FOBJ(me), x)); \ |
308 | end: \ |
309 | return (0); \ |
310 | } |
311 | UNOP(inv, if (F_ZEROP(f, x)) ZDIVERR("division by zero"); ) |
312 | UNOP(sqr, ; ) |
313 | UNOP(sqrt, ; ) |
314 | UNOP(quadsolve, ; ) |
315 | UNOP(dbl, ; ) |
316 | UNOP(tpl, ; ) |
317 | UNOP(qdl, ; ) |
318 | UNOP(hlv, ; ) |
319 | #undef UNOP |
320 | |
321 | static PyObject *feget_field(PyObject *me, void *hunoz) |
322 | { RETURN_OBJ(FE_FOBJ(me)); } |
323 | |
324 | static PyObject *feget_value(PyObject *me, void *hunoz) |
325 | { |
326 | mp *x = F_OUT(FE_F(me), MP_NEW, FE_X(me)); |
327 | if (F_TYPE(FE_F(me)) == FTY_BINARY) |
328 | return (gf_pywrap(x)); |
329 | else |
330 | return (mp_pywrap(x)); |
331 | } |
332 | |
333 | static PyObject *feget__value(PyObject *me, void *hunoz) |
334 | { |
335 | mp *x = FE_X(me); |
336 | MP_COPY(x); |
337 | if (F_TYPE(FE_F(me)) == FTY_BINARY) |
338 | return (gf_pywrap(x)); |
339 | else |
340 | return (mp_pywrap(x)); |
341 | } |
342 | |
343 | static PyGetSetDef fe_pygetset[] = { |
344 | #define GETSETNAME(op, name) fe##op##_##name |
345 | GET (field, "X.field -> field containing X") |
346 | GET (value, "X.value -> `natural' integer representation of X") |
347 | GET (_value, "X._value -> internal integer representation of X") |
348 | #undef GETSETNAME |
349 | { 0 } |
350 | }; |
351 | |
352 | static PyMethodDef fe_pymethods[] = { |
353 | #define METHNAME(func) femeth_##func |
354 | METH (inv, "X.inv() -> X^{-1}") |
355 | METH (sqr, "X.sqr() -> X^2") |
356 | METH (sqrt, "X.sqrt() -> sqrt(X)") |
357 | METH (quadsolve, "X.quadsolve() -> Y where Y^2 + Y = X (binary only)") |
358 | METH (dbl, "X.dbl() -> 2 * X (prime only)") |
359 | METH (tpl, "X.tpl() -> 3 * X (prime only)") |
360 | METH (qdl, "X.qdl() -> 4 * X (prime only)") |
361 | METH (hlv, "X.hlv() -> X/2 (prime only)") |
362 | #undef METHNAME |
363 | { 0 } |
364 | }; |
365 | |
366 | static PyNumberMethods fe_pynumber = { |
367 | fe_pyadd, /* @nb_add@ */ |
368 | fe_pysub, /* @nb_subtract@ */ |
369 | fe_pymul, /* @nb_multiply@ */ |
370 | fe_pydiv, /* @nb_divide@ */ |
371 | 0, /* @nb_remainder@ */ |
372 | 0, /* @nb_divmod@ */ |
373 | fe_pyexp, /* @nb_power@ */ |
374 | fe_pyneg, /* @nb_negative@ */ |
375 | fe_pyid, /* @nb_positive@ */ |
376 | 0, /* @nb_absolute@ */ |
377 | fe_pynonzerop, /* @nb_nonzero@ */ |
378 | 0, /* @nb_invert@ */ |
379 | 0, /* @nb_lshift@ */ |
380 | 0, /* @nb_rshift@ */ |
381 | 0, /* @nb_and@ */ |
382 | 0, /* @nb_xor@ */ |
383 | 0, /* @nb_or@ */ |
384 | fe_pycoerce, /* @nb_coerce@ */ |
385 | fe_pyint, /* @nb_int@ */ |
386 | fe_pylong, /* @nb_long@ */ |
387 | 0 /* meaningless */, /* @nb_float@ */ |
388 | fe_pyoct, /* @nb_oct@ */ |
389 | fe_pyhex, /* @nb_hex@ */ |
390 | |
391 | 0, /* @nb_inplace_add@ */ |
392 | 0, /* @nb_inplace_subtract@ */ |
393 | 0, /* @nb_inplace_multiply@ */ |
394 | 0, /* @nb_inplace_divide@ */ |
395 | 0, /* @nb_inplace_remainder@ */ |
396 | 0, /* @nb_inplace_power@ */ |
397 | 0, /* @nb_inplace_lshift@ */ |
398 | 0, /* @nb_inplace_rshift@ */ |
399 | 0, /* @nb_inplace_and@ */ |
400 | 0, /* @nb_inplace_xor@ */ |
401 | 0, /* @nb_inplace_or@ */ |
402 | |
403 | 0, /* @nb_floor_divide@ */ |
404 | fe_pydiv, /* @nb_true_divide@ */ |
405 | 0, /* @nb_inplace_floor_divide@ */ |
406 | 0, /* @nb_inplace_true_divide@ */ |
407 | }; |
408 | |
409 | static PyTypeObject fe_pytype_skel = { |
6d4db0bf |
410 | PyObject_HEAD_INIT(0) 0, /* Header */ |
d7ab1bab |
411 | "catacomb.FE", /* @tp_name@ */ |
412 | sizeof(fe_pyobj), /* @tp_basicsize@ */ |
413 | 0, /* @tp_itemsize@ */ |
414 | |
415 | fe_pydealloc, /* @tp_dealloc@ */ |
416 | 0, /* @tp_print@ */ |
417 | 0, /* @tp_getattr@ */ |
418 | 0, /* @tp_setattr@ */ |
419 | 0, /* @tp_compare@ */ |
420 | 0, /* @tp_repr@ */ |
421 | &fe_pynumber, /* @tp_as_number@ */ |
422 | 0, /* @tp_as_sequence@ */ |
423 | 0, /* @tp_as_mapping@ */ |
424 | fe_pyhash, /* @tp_hash@ */ |
425 | 0, /* @tp_call@ */ |
426 | fe_pyhex, /* @tp_str@ */ |
427 | 0, /* @tp_getattro@ */ |
428 | 0, /* @tp_setattro@ */ |
429 | 0, /* @tp_as_buffer@ */ |
430 | Py_TPFLAGS_DEFAULT | /* @tp_flags@ */ |
431 | Py_TPFLAGS_CHECKTYPES | |
432 | Py_TPFLAGS_BASETYPE, |
433 | |
434 | /* @tp_doc@ */ |
435 | "Finite field elements, abstract base class.", |
436 | |
437 | 0, /* @tp_traverse@ */ |
438 | 0, /* @tp_clear@ */ |
439 | fe_pyrichcompare, /* @tp_richcompare@ */ |
440 | 0, /* @tp_weaklistoffset@ */ |
441 | 0, /* @tp_iter@ */ |
442 | 0, /* @tp_iternexr@ */ |
443 | fe_pymethods, /* @tp_methods@ */ |
444 | 0, /* @tp_members@ */ |
445 | fe_pygetset, /* @tp_getset@ */ |
446 | 0, /* @tp_base@ */ |
447 | 0, /* @tp_dict@ */ |
448 | 0, /* @tp_descr_get@ */ |
449 | 0, /* @tp_descr_set@ */ |
450 | 0, /* @tp_dictoffset@ */ |
451 | 0, /* @tp_init@ */ |
452 | PyType_GenericAlloc, /* @tp_alloc@ */ |
453 | abstract_pynew, /* @tp_new@ */ |
3aa33042 |
454 | 0, /* @tp_free@ */ |
d7ab1bab |
455 | 0 /* @tp_is_gc@ */ |
456 | }; |
457 | |
458 | /*----- Fields ------------------------------------------------------------*/ |
459 | |
460 | static PyObject *field_pyrichcompare(PyObject *x, PyObject *y, int op) |
461 | { |
462 | int b = field_samep(FIELD_F(x), FIELD_F(y)); |
463 | switch (op) { |
464 | case Py_EQ: break; |
465 | case Py_NE: b = !b; |
466 | default: TYERR("can't order fields"); |
467 | } |
468 | return (getbool(b)); |
469 | end: |
470 | return (0); |
471 | } |
472 | |
473 | static PyObject *fmeth_rand(PyObject *me, PyObject *arg, PyObject *kw) |
474 | { |
475 | char *kwlist[] = { "rng", 0 }; |
476 | grand *r = &rand_global; |
477 | |
478 | if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:rand", kwlist, |
479 | convgrand, &r)) |
480 | return (0); |
481 | return (fe_pywrap(me, F_RAND(FIELD_F(me), MP_NEW, r))); |
482 | } |
483 | |
484 | static PyObject *fmeth__adopt(PyObject *me, PyObject *arg) |
485 | { |
486 | mp *xx; |
487 | if (!PyArg_ParseTuple(arg, "O&:_adopt", convmp, &xx)) return (0); |
488 | return (fe_pywrap(me, xx)); |
489 | } |
490 | |
491 | static void field_pydealloc(PyObject *me) |
492 | { |
493 | F_DESTROY(FIELD_F(me)); |
494 | PyType_Type.tp_dealloc(me); |
495 | } |
496 | |
497 | static PyObject *fget_zero(PyObject *me, void *hunoz) |
498 | { return (fe_pywrap(me, MP_COPY(FIELD_F(me)->zero))); } |
499 | |
500 | static PyObject *fget_one(PyObject *me, void *hunoz) |
501 | { return (fe_pywrap(me, MP_COPY(FIELD_F(me)->one))); } |
502 | |
503 | static PyObject *fget_q(PyObject *me, void *hunoz) |
504 | { return (mp_pywrap(MP_COPY(FIELD_F(me)->q))); } |
505 | |
506 | static PyObject *fget_nbits(PyObject *me, void *hunoz) |
507 | { return (PyInt_FromLong(FIELD_F(me)->nbits)); } |
508 | |
509 | static PyObject *fget_noctets(PyObject *me, void *hunoz) |
510 | { return (PyInt_FromLong(FIELD_F(me)->noctets)); } |
511 | |
512 | static PyObject *fget_name(PyObject *me, void *hunoz) |
513 | { return (PyString_FromString(F_NAME(FIELD_F(me)))); } |
514 | |
515 | static PyObject *fget_type(PyObject *me, void *hunoz) |
516 | { return (PyInt_FromLong(F_TYPE(FIELD_F(me)))); } |
517 | |
518 | static PyGetSetDef field_pygetset[] = { |
519 | #define GETSETNAME(op, name) f##op##_##name |
520 | GET (zero, "F.zero -> field additive identity") |
521 | GET (one, "F.one -> field multiplicative identity") |
522 | GET (q, "F.q -> number of elements in field") |
523 | GET (nbits, "F.nbits -> bits needed to represent element") |
524 | GET (noctets, "F.noctets -> octetss needed to represent element") |
525 | GET (name, "F.name -> name of this kind of field") |
526 | GET (type, "F.type -> type code of this kind of field") |
527 | #undef GETSETNAME |
528 | { 0 } |
529 | }; |
530 | |
531 | static PyMethodDef field_pymethods[] = { |
532 | #define METHNAME(name) fmeth_##name |
533 | METH (_adopt, "F._adopt(X) -> FE") |
534 | KWMETH(rand, "F.rand(rng = rand) -> FE, uniformly distributed") |
535 | #undef METHNAME |
536 | { 0 } |
537 | }; |
538 | |
539 | static PyTypeObject field_pytype_skel = { |
6d4db0bf |
540 | PyObject_HEAD_INIT(0) 0, /* Header */ |
d7ab1bab |
541 | "catacomb.Field", /* @tp_name@ */ |
542 | sizeof(field_pyobj), /* @tp_basicsize@ */ |
543 | 0, /* @tp_itemsize@ */ |
544 | |
545 | field_pydealloc, /* @tp_dealloc@ */ |
546 | 0, /* @tp_print@ */ |
547 | 0, /* @tp_getattr@ */ |
548 | 0, /* @tp_setattr@ */ |
549 | 0, /* @tp_compare@ */ |
550 | 0, /* @tp_repr@ */ |
551 | 0, /* @tp_as_number@ */ |
552 | 0, /* @tp_as_sequence@ */ |
553 | 0, /* @tp_as_mapping@ */ |
554 | 0, /* @tp_hash@ */ |
555 | 0, /* @tp_call@ */ |
556 | 0, /* @tp_str@ */ |
557 | 0, /* @tp_getattro@ */ |
558 | 0, /* @tp_setattro@ */ |
559 | 0, /* @tp_as_buffer@ */ |
560 | Py_TPFLAGS_DEFAULT | /* @tp_flags@ */ |
561 | Py_TPFLAGS_BASETYPE, |
562 | |
563 | /* @tp_doc@ */ |
564 | "An abstract field. This is an abstract type.", |
565 | |
566 | 0, /* @tp_traverse@ */ |
567 | 0, /* @tp_clear@ */ |
568 | field_pyrichcompare, /* @tp_richcompare@ */ |
569 | 0, /* @tp_weaklistoffset@ */ |
570 | 0, /* @tp_iter@ */ |
571 | 0, /* @tp_iternexr@ */ |
572 | field_pymethods, /* @tp_methods@ */ |
573 | 0, /* @tp_members@ */ |
574 | field_pygetset, /* @tp_getset@ */ |
575 | 0, /* @tp_base@ */ |
576 | 0, /* @tp_dict@ */ |
577 | 0, /* @tp_descr_get@ */ |
578 | 0, /* @tp_descr_set@ */ |
579 | 0, /* @tp_dictoffset@ */ |
580 | 0, /* @tp_init@ */ |
581 | PyType_GenericAlloc, /* @tp_alloc@ */ |
582 | abstract_pynew, /* @tp_new@ */ |
3aa33042 |
583 | 0, /* @tp_free@ */ |
d7ab1bab |
584 | 0 /* @tp_is_gc@ */ |
585 | }; |
586 | |
587 | /*----- Prime fields ------------------------------------------------------*/ |
588 | |
589 | static PyObject *primefield_pynew(PyTypeObject *ty, |
590 | PyObject *arg, PyObject *kw) |
591 | { |
592 | mp *xx = 0; |
593 | field *f; |
594 | char *kwlist[] = { "p", 0 }; |
595 | |
596 | if (!PyArg_ParseTupleAndKeywords(arg, kw, "O:primefield", kwlist, |
597 | convmp, &xx)) |
598 | goto end; |
599 | if ((f = field_prime(xx)) == 0) |
600 | VALERR("bad prime for primefield"); |
601 | MP_DROP(xx); |
602 | return (field_dopywrap(ty, f)); |
603 | end: |
604 | mp_drop(xx); |
605 | return (0); |
606 | } |
607 | |
608 | static PyObject *pfget_p(PyObject *me, void *hunoz) |
609 | { return (mp_pywrap(MP_COPY(FIELD_F(me)->m))); } |
610 | |
611 | static PyGetSetDef primefield_pygetset[] = { |
612 | #define GETSETNAME(op, name) pf##op##_##name |
613 | GET (p, "F.p -> prime field characteristic") |
614 | #undef GETSETNAME |
615 | }; |
616 | |
617 | static PyTypeObject primefield_pytype_skel = { |
6d4db0bf |
618 | PyObject_HEAD_INIT(0) 0, /* Header */ |
d7ab1bab |
619 | "catacomb.PrimeField", /* @tp_name@ */ |
620 | sizeof(field_pyobj), /* @tp_basicsize@ */ |
621 | 0, /* @tp_itemsize@ */ |
622 | |
623 | field_pydealloc, /* @tp_dealloc@ */ |
624 | 0, /* @tp_print@ */ |
625 | 0, /* @tp_getattr@ */ |
626 | 0, /* @tp_setattr@ */ |
627 | 0, /* @tp_compare@ */ |
628 | 0, /* @tp_repr@ */ |
629 | 0, /* @tp_as_number@ */ |
630 | 0, /* @tp_as_sequence@ */ |
631 | 0, /* @tp_as_mapping@ */ |
632 | 0, /* @tp_hash@ */ |
633 | 0, /* @tp_call@ */ |
634 | 0, /* @tp_str@ */ |
635 | 0, /* @tp_getattro@ */ |
636 | 0, /* @tp_setattro@ */ |
637 | 0, /* @tp_as_buffer@ */ |
638 | Py_TPFLAGS_DEFAULT | /* @tp_flags@ */ |
639 | Py_TPFLAGS_BASETYPE, |
640 | |
641 | /* @tp_doc@ */ |
642 | "Prime fields.", |
643 | |
644 | 0, /* @tp_traverse@ */ |
645 | 0, /* @tp_clear@ */ |
646 | field_pyrichcompare, /* @tp_richcompare@ */ |
647 | 0, /* @tp_weaklistoffset@ */ |
648 | 0, /* @tp_iter@ */ |
649 | 0, /* @tp_iternexr@ */ |
650 | 0, /* @tp_methods@ */ |
651 | 0, /* @tp_members@ */ |
652 | primefield_pygetset, /* @tp_getset@ */ |
653 | 0, /* @tp_base@ */ |
654 | 0, /* @tp_dict@ */ |
655 | 0, /* @tp_descr_get@ */ |
656 | 0, /* @tp_descr_set@ */ |
657 | 0, /* @tp_dictoffset@ */ |
658 | 0, /* @tp_init@ */ |
659 | PyType_GenericAlloc, /* @tp_alloc@ */ |
660 | primefield_pynew, /* @tp_new@ */ |
3aa33042 |
661 | 0, /* @tp_free@ */ |
d7ab1bab |
662 | 0 /* @tp_is_gc@ */ |
663 | }; |
664 | |
665 | static PyObject *niceprimefield_pynew(PyTypeObject *ty, |
666 | PyObject *arg, PyObject *kw) |
667 | { |
668 | mp *xx = 0; |
669 | field *f; |
670 | char *kwlist[] = { "p", 0 }; |
671 | |
672 | if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:niceprimefield", |
673 | kwlist, convmp, &xx)) |
674 | goto end; |
675 | if ((f = field_niceprime(xx)) == 0) |
676 | VALERR("bad prime for niceprimefield"); |
677 | MP_DROP(xx); |
678 | return (field_dopywrap(ty, f)); |
679 | end: |
680 | mp_drop(xx); |
681 | return (0); |
682 | } |
683 | |
684 | static PyTypeObject niceprimefield_pytype_skel = { |
6d4db0bf |
685 | PyObject_HEAD_INIT(0) 0, /* Header */ |
d7ab1bab |
686 | "catacomb.NicePrimeField", /* @tp_name@ */ |
687 | sizeof(field_pyobj), /* @tp_basicsize@ */ |
688 | 0, /* @tp_itemsize@ */ |
689 | |
690 | field_pydealloc, /* @tp_dealloc@ */ |
691 | 0, /* @tp_print@ */ |
692 | 0, /* @tp_getattr@ */ |
693 | 0, /* @tp_setattr@ */ |
694 | 0, /* @tp_compare@ */ |
695 | 0, /* @tp_repr@ */ |
696 | 0, /* @tp_as_number@ */ |
697 | 0, /* @tp_as_sequence@ */ |
698 | 0, /* @tp_as_mapping@ */ |
699 | 0, /* @tp_hash@ */ |
700 | 0, /* @tp_call@ */ |
701 | 0, /* @tp_str@ */ |
702 | 0, /* @tp_getattro@ */ |
703 | 0, /* @tp_setattro@ */ |
704 | 0, /* @tp_as_buffer@ */ |
705 | Py_TPFLAGS_DEFAULT | /* @tp_flags@ */ |
706 | Py_TPFLAGS_BASETYPE, |
707 | |
708 | /* @tp_doc@ */ |
709 | "Nice prime fields.", |
710 | |
711 | 0, /* @tp_traverse@ */ |
712 | 0, /* @tp_clear@ */ |
713 | field_pyrichcompare, /* @tp_richcompare@ */ |
714 | 0, /* @tp_weaklistoffset@ */ |
715 | 0, /* @tp_iter@ */ |
716 | 0, /* @tp_iternexr@ */ |
717 | 0, /* @tp_methods@ */ |
718 | 0, /* @tp_members@ */ |
719 | 0, /* @tp_getset@ */ |
720 | 0, /* @tp_base@ */ |
721 | 0, /* @tp_dict@ */ |
722 | 0, /* @tp_descr_get@ */ |
723 | 0, /* @tp_descr_set@ */ |
724 | 0, /* @tp_dictoffset@ */ |
725 | 0, /* @tp_init@ */ |
726 | PyType_GenericAlloc, /* @tp_alloc@ */ |
727 | niceprimefield_pynew, /* @tp_new@ */ |
3aa33042 |
728 | 0, /* @tp_free@ */ |
d7ab1bab |
729 | 0 /* @tp_is_gc@ */ |
730 | }; |
731 | |
732 | /*----- Binary fields -----------------------------------------------------*/ |
733 | |
734 | static PyObject *bfget_m(PyObject *me, void *hunoz) |
735 | { return (PyInt_FromLong(FIELD_F(me)->nbits)); } |
736 | |
737 | static PyGetSetDef binfield_pygetset[] = { |
738 | #define GETSETNAME(op, name) bf##op##_##name |
739 | GET (m, "F.m -> field polynomial degree") |
740 | #undef GETSETNAME |
741 | { 0 } |
742 | }; |
743 | |
744 | static PyTypeObject binfield_pytype_skel = { |
6d4db0bf |
745 | PyObject_HEAD_INIT(0) 0, /* Header */ |
d7ab1bab |
746 | "catacomb.BinField", /* @tp_name@ */ |
747 | sizeof(field_pyobj), /* @tp_basicsize@ */ |
748 | 0, /* @tp_itemsize@ */ |
749 | |
750 | field_pydealloc, /* @tp_dealloc@ */ |
751 | 0, /* @tp_print@ */ |
752 | 0, /* @tp_getattr@ */ |
753 | 0, /* @tp_setattr@ */ |
754 | 0, /* @tp_compare@ */ |
755 | 0, /* @tp_repr@ */ |
756 | 0, /* @tp_as_number@ */ |
757 | 0, /* @tp_as_sequence@ */ |
758 | 0, /* @tp_as_mapping@ */ |
759 | 0, /* @tp_hash@ */ |
760 | 0, /* @tp_call@ */ |
761 | 0, /* @tp_str@ */ |
762 | 0, /* @tp_getattro@ */ |
763 | 0, /* @tp_setattro@ */ |
764 | 0, /* @tp_as_buffer@ */ |
765 | Py_TPFLAGS_DEFAULT | /* @tp_flags@ */ |
766 | Py_TPFLAGS_BASETYPE, |
767 | |
768 | /* @tp_doc@ */ |
769 | "Binary fields. Abstract class.", |
770 | |
771 | 0, /* @tp_traverse@ */ |
772 | 0, /* @tp_clear@ */ |
773 | field_pyrichcompare, /* @tp_richcompare@ */ |
774 | 0, /* @tp_weaklistoffset@ */ |
775 | 0, /* @tp_iter@ */ |
776 | 0, /* @tp_iternexr@ */ |
777 | 0, /* @tp_methods@ */ |
778 | 0, /* @tp_members@ */ |
779 | binfield_pygetset, /* @tp_getset@ */ |
780 | 0, /* @tp_base@ */ |
781 | 0, /* @tp_dict@ */ |
782 | 0, /* @tp_descr_get@ */ |
783 | 0, /* @tp_descr_set@ */ |
784 | 0, /* @tp_dictoffset@ */ |
785 | 0, /* @tp_init@ */ |
786 | PyType_GenericAlloc, /* @tp_alloc@ */ |
787 | abstract_pynew, /* @tp_new@ */ |
3aa33042 |
788 | 0, /* @tp_free@ */ |
d7ab1bab |
789 | 0 /* @tp_is_gc@ */ |
790 | }; |
791 | |
792 | static PyObject *binpolyfield_pynew(PyTypeObject *ty, |
793 | PyObject *arg, PyObject *kw) |
794 | { |
795 | mp *xx = 0; |
796 | field *f; |
797 | char *kwlist[] = { "p", 0 }; |
798 | |
799 | if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:binpolyfield", kwlist, |
800 | convgf, &xx)) |
801 | goto end; |
802 | if ((f = field_binpoly(xx)) == 0) VALERR("bad poly for binpolyfield"); |
803 | MP_DROP(xx); |
804 | return (field_dopywrap(ty, f)); |
805 | end: |
806 | mp_drop(xx); |
807 | return (0); |
808 | } |
809 | |
810 | static PyGetSetDef binpolyfield_pygetset[] = { |
811 | #define GETSETNAME(op, name) pf##op##_##name |
812 | GET (p, "F.p -> field polynomial") |
813 | #undef GETSETNAME |
814 | { 0 } |
815 | }; |
816 | |
817 | static PyTypeObject binpolyfield_pytype_skel = { |
6d4db0bf |
818 | PyObject_HEAD_INIT(0) 0, /* Header */ |
d7ab1bab |
819 | "catacomb.BinPolyField", /* @tp_name@ */ |
820 | sizeof(field_pyobj), /* @tp_basicsize@ */ |
821 | 0, /* @tp_itemsize@ */ |
822 | |
823 | field_pydealloc, /* @tp_dealloc@ */ |
824 | 0, /* @tp_print@ */ |
825 | 0, /* @tp_getattr@ */ |
826 | 0, /* @tp_setattr@ */ |
827 | 0, /* @tp_compare@ */ |
828 | 0, /* @tp_repr@ */ |
829 | 0, /* @tp_as_number@ */ |
830 | 0, /* @tp_as_sequence@ */ |
831 | 0, /* @tp_as_mapping@ */ |
832 | 0, /* @tp_hash@ */ |
833 | 0, /* @tp_call@ */ |
834 | 0, /* @tp_str@ */ |
835 | 0, /* @tp_getattro@ */ |
836 | 0, /* @tp_setattro@ */ |
837 | 0, /* @tp_as_buffer@ */ |
838 | Py_TPFLAGS_DEFAULT | /* @tp_flags@ */ |
839 | Py_TPFLAGS_BASETYPE, |
840 | |
841 | /* @tp_doc@ */ |
842 | "Binary fields with polynomial basis representation.", |
843 | |
844 | 0, /* @tp_traverse@ */ |
845 | 0, /* @tp_clear@ */ |
846 | field_pyrichcompare, /* @tp_richcompare@ */ |
847 | 0, /* @tp_weaklistoffset@ */ |
848 | 0, /* @tp_iter@ */ |
849 | 0, /* @tp_iternexr@ */ |
850 | 0, /* @tp_methods@ */ |
851 | 0, /* @tp_members@ */ |
852 | binpolyfield_pygetset, /* @tp_getset@ */ |
853 | 0, /* @tp_base@ */ |
854 | 0, /* @tp_dict@ */ |
855 | 0, /* @tp_descr_get@ */ |
856 | 0, /* @tp_descr_set@ */ |
857 | 0, /* @tp_dictoffset@ */ |
858 | 0, /* @tp_init@ */ |
859 | PyType_GenericAlloc, /* @tp_alloc@ */ |
860 | binpolyfield_pynew, /* @tp_new@ */ |
3aa33042 |
861 | 0, /* @tp_free@ */ |
d7ab1bab |
862 | 0 /* @tp_is_gc@ */ |
863 | }; |
864 | |
865 | static PyObject *binnormfield_pynew(PyTypeObject *ty, |
866 | PyObject *arg, PyObject *kw) |
867 | { |
868 | mp *xx = 0, *yy = 0; |
869 | field *f; |
870 | char *kwlist[] = { "p", "beta", 0 }; |
871 | |
872 | if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&:binnormfield", |
873 | kwlist, convgf, &xx, convgf, &yy)) |
874 | goto end; |
875 | if ((f = field_binnorm(xx, yy)) == 0) VALERR("bad args for binnormfield"); |
876 | MP_DROP(xx); MP_DROP(yy); |
877 | return (field_dopywrap(ty, f)); |
878 | end: |
879 | mp_drop(xx); mp_drop(yy); |
880 | return (0); |
881 | } |
882 | |
883 | static PyObject *bnfget_beta(PyObject *me, void *hunoz) |
884 | { |
885 | fctx_binnorm *fc = (fctx_binnorm *)FIELD_F(me); |
886 | return (gf_pywrap(MP_COPY(fc->ntop.r[fc->ntop.n - 1]))); |
887 | } |
888 | |
889 | static PyGetSetDef binnormfield_pygetset[] = { |
890 | #define GETSETNAME(op, name) pf##op##_##name |
891 | GET (p, "F.p -> field polynomial") |
892 | #undef GETSETNAME |
893 | #define GETSETNAME(op, name) bnf##op##_##name |
894 | GET (beta, "F.beta -> conversion factor") |
895 | #undef GETSETNAME |
896 | { 0 } |
897 | }; |
898 | |
899 | static PyTypeObject binnormfield_pytype_skel = { |
6d4db0bf |
900 | PyObject_HEAD_INIT(0) 0, /* Header */ |
d7ab1bab |
901 | "catacomb.BinNormField", /* @tp_name@ */ |
902 | sizeof(field_pyobj), /* @tp_basicsize@ */ |
903 | 0, /* @tp_itemsize@ */ |
904 | |
905 | field_pydealloc, /* @tp_dealloc@ */ |
906 | 0, /* @tp_print@ */ |
907 | 0, /* @tp_getattr@ */ |
908 | 0, /* @tp_setattr@ */ |
909 | 0, /* @tp_compare@ */ |
910 | 0, /* @tp_repr@ */ |
911 | 0, /* @tp_as_number@ */ |
912 | 0, /* @tp_as_sequence@ */ |
913 | 0, /* @tp_as_mapping@ */ |
914 | 0, /* @tp_hash@ */ |
915 | 0, /* @tp_call@ */ |
916 | 0, /* @tp_str@ */ |
917 | 0, /* @tp_getattro@ */ |
918 | 0, /* @tp_setattro@ */ |
919 | 0, /* @tp_as_buffer@ */ |
920 | Py_TPFLAGS_DEFAULT | /* @tp_flags@ */ |
921 | Py_TPFLAGS_BASETYPE, |
922 | |
923 | /* @tp_doc@ */ |
924 | "Binary fields with normal basis representation.", |
925 | |
926 | 0, /* @tp_traverse@ */ |
927 | 0, /* @tp_clear@ */ |
928 | field_pyrichcompare, /* @tp_richcompare@ */ |
929 | 0, /* @tp_weaklistoffset@ */ |
930 | 0, /* @tp_iter@ */ |
931 | 0, /* @tp_iternexr@ */ |
932 | 0, /* @tp_methods@ */ |
933 | 0, /* @tp_members@ */ |
934 | binnormfield_pygetset, /* @tp_getset@ */ |
935 | 0, /* @tp_base@ */ |
936 | 0, /* @tp_dict@ */ |
937 | 0, /* @tp_descr_get@ */ |
938 | 0, /* @tp_descr_set@ */ |
939 | 0, /* @tp_dictoffset@ */ |
940 | 0, /* @tp_init@ */ |
941 | PyType_GenericAlloc, /* @tp_alloc@ */ |
942 | binnormfield_pynew, /* @tp_new@ */ |
3aa33042 |
943 | 0, /* @tp_free@ */ |
d7ab1bab |
944 | 0 /* @tp_is_gc@ */ |
945 | }; |
946 | |
947 | /*----- Setup -------------------------------------------------------------*/ |
948 | |
949 | static PyObject *meth__Field_parse(PyObject *me, PyObject *arg) |
950 | { |
951 | field *f; |
952 | char *p; |
953 | PyObject *rc = 0; |
954 | qd_parse qd; |
955 | |
956 | if (!PyArg_ParseTuple(arg, "Os:parse", &me, &p)) |
957 | goto end; |
958 | qd.p = p; |
959 | qd.e = 0; |
960 | if ((f = field_parse(&qd)) == 0) |
961 | SYNERR(qd.e); |
962 | rc = Py_BuildValue("(Ns)", field_pywrap(f), qd.p); |
963 | end: |
964 | return (rc); |
965 | } |
966 | |
967 | static PyMethodDef methods[] = { |
968 | #define METHNAME(func) meth_##func |
969 | METH (_Field_parse, "parse(STR) -> F, REST") |
970 | #undef METHNAME |
971 | { 0 } |
972 | }; |
973 | |
974 | void field_pyinit(void) |
975 | { |
976 | INITTYPE(fe, root); |
977 | INITTYPE(field, type); |
978 | INITTYPE(primefield, field); |
979 | INITTYPE(niceprimefield, primefield); |
980 | INITTYPE(binfield, field); |
981 | INITTYPE(binpolyfield, binfield); |
982 | INITTYPE(binnormfield, binfield); |
983 | addmethods(methods); |
984 | } |
985 | |
986 | void field_pyinsert(PyObject *mod) |
987 | { |
988 | INSERT("FE", fe_pytype); |
989 | INSERT("Field", field_pytype); |
990 | INSERT("PrimeField", primefield_pytype); |
991 | INSERT("NicePrimeField", niceprimefield_pytype); |
992 | INSERT("BinField", binfield_pytype); |
993 | INSERT("BinPolyField", binpolyfield_pytype); |
994 | INSERT("BinNormField", binnormfield_pytype); |
995 | } |
996 | |
997 | /*----- That's all, folks -------------------------------------------------*/ |