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