--- /dev/null
+file py/python2.2-2.2.1/debian/python2.2/usr/bin/python2.2
+dir py/python2.2-2.2.1/builddir
+cd build/lib.linux-i686-2.2
+set env LD_LIBRARY_PATH=/home/mdw/src/catacomb/deb-build/.libs
--- /dev/null
+;;; -*-emacs-lisp-*-
+
+(setq skel-alist
+ (append
+ '((author . "Straylight/Edgeware")
+ (licence-text . "[[gpl]]")
+ (full-title . "the Python interface to Catacomb")
+ (program . "Catacomb/Python"))
+ skel-alist))
--- /dev/null
+include README Makefile MANIFEST MANIFEST.in
+include *.c *.h
+recursive-include catacomb *.py
--- /dev/null
+## Makefile
+
+PYTHON = python2.2
+prefix=/usr/local
+
+all: setup.py
+ $(PYTHON) setup.py build
+
+clean: setup.py
+ $(PYTHON) setup.py clean
+ rm -rf build
+
+dist: setup.py
+ $(PYTHON) setup.py sdist
+
+install: setup.py
+ $(PYTHON) setup.py install --prefix $(prefix)
+
+.PHONY: all clean dist
--- /dev/null
+Nothing much to say yet.
+
+Class hierarchy
+
+ bytestring
+
+ mp
+ mpmont
+ mpbarrett
+ mpreduce
+ mpcrt
+
+ gf
+ gfreduce
+ gfn
+
+ field
+ primefield
+ niceprimefield
+ binfield
+ binpolyfield
+ binnormfield
+ fe
+ [field objects]
+
+ eccurve
+ ecprimecurve
+ ecprimeprojcurve
+ ecbincurve
+ ecbinprojcurve
+ ecinfo
+ ecpt
+ [eccurve objects]
+
+ fginfo
+ dhinfo
+ bindhinfo
+
+ group
+ primegroup
+ bingroup
+ ecgroup
+ ge
+ [group objects]
+
+ grand
+ truerand
+
+ keysz
+ keyszany
+ keyszrange
+ keyszset
+
+ gccipher
+ gcipher
+ [gccipher objects]
+ gcmac
+ gmac
+ [gcmac objects]
+ gchash
+ ghash
+ [gchash objects]
+ gmhash
+ [gmac objects]
+
+ecinfo(curve = ecprimeprojcurve(),
+ G = ecprimeprojcurve()(),
+ r = 115792089210356248762697446949407573529996955224135760342422259061068512044369,
+ h = 1)
\ No newline at end of file
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id$
+ *
+ * Symmetric cryptography
+ *
+ * (c) 2004 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of the Python interface to Catacomb.
+ *
+ * Catacomb/Python is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb/Python is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Catacomb/Python; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "catacomb-python.h"
+#include "algorithms.h"
+
+/*----- Key sizes ---------------------------------------------------------*/
+
+PyTypeObject *keysz_pytype;
+PyTypeObject *keyszany_pytype, *keyszrange_pytype, *keyszset_pytype;
+PyObject *sha_pyobj, *has160_pyobj;
+
+PyObject *keysz_pywrap(const octet *k)
+{
+ switch (k[0]) {
+ case KSZ_ANY: {
+ keysz_pyobj *o = PyObject_New(keysz_pyobj, keyszany_pytype);
+ o->dfl = k[1];
+ return ((PyObject *)o);
+ } break;
+ case KSZ_RANGE: {
+ keyszrange_pyobj *o =
+ PyObject_New(keyszrange_pyobj, keyszrange_pytype);
+ o->dfl = k[1];
+ o->min = k[2];
+ o->max = k[3];
+ o->mod = k[4];
+ if (!o->mod) o->mod = 1;
+ return ((PyObject *)o);
+ } break;
+ case KSZ_SET: {
+ keyszset_pyobj *o =
+ PyObject_New(keyszset_pyobj, keyszset_pytype);
+ int i, n;
+ o->dfl = k[1];
+ for (i = 0; k[i + 1]; i++) ;
+ n = i; o->set = PyTuple_New(n);
+ for (i = 0; i < n; i++)
+ PyTuple_SET_ITEM(o->set, i, PyInt_FromLong(k[i + 1]));
+ return ((PyObject *)o);
+ } break;
+ default:
+ abort();
+ }
+}
+
+static PyObject *keyszany_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+{
+ char *kwlist[] = { "default", 0 };
+ int dfl;
+ keysz_pyobj *o;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "i:new", kwlist, &dfl))
+ goto end;
+ if (dfl < 0) VALERR("key size cannot be negative");
+ o = (keysz_pyobj *)ty->tp_alloc(ty, 0);
+ o->dfl = dfl;
+ return ((PyObject *)o);
+end:
+ return (0);
+}
+
+static PyObject *keyszrange_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+{
+ char *kwlist[] = { "default", "min", "max", "mod", 0 };
+ int dfl, min = 0, max = 0, mod = 1;
+ keyszrange_pyobj *o;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "i|iii:new", kwlist,
+ &dfl, &min, &max, &mod))
+ goto end;
+ if (dfl < 0 || min < 0 || max < 0)
+ VALERR("key size cannot be negative");
+ if (min > dfl || (max && dfl > max))
+ VALERR("bad key size bounds");
+ if (mod <= 0 || dfl % mod || min % mod || max % mod)
+ VALERR("bad key size modulus");
+ o = (keyszrange_pyobj *)ty->tp_alloc(ty, 0);
+ o->dfl = dfl;
+ o->min = min;
+ o->max = max;
+ o->mod = mod;
+ return ((PyObject *)o);
+end:
+ return (0);
+}
+
+static PyObject *keyszset_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+{
+ char *kwlist[] = { "default", "set", 0 };
+ int dfl, i, n, xx;
+ PyObject *set = 0;
+ PyObject *x = 0, *l = 0;
+ keyszset_pyobj *o = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "i|O:new", kwlist,
+ &dfl, &set))
+ goto end;
+ if (!set) set = PyTuple_New(0);
+ else Py_INCREF(set);
+ if (!PySequence_Check(set)) TYERR("want a sequence");
+ n = PySequence_Size(set);
+ l = PyList_New(0);
+ if (PyErr_Occurred()) goto end;
+ if (dfl < 0) VALERR("key size cannot be negative");
+ x = PyInt_FromLong(dfl);
+ PyList_Append(l, x);
+ Py_DECREF(x);
+ x = 0;
+ for (i = 0; i < n; i++) {
+ if ((x = PySequence_GetItem(set, i)) == 0) goto end;
+ xx = PyInt_AsLong(x);
+ if (PyErr_Occurred()) goto end;
+ if (xx == dfl) continue;
+ if (xx < 0) VALERR("key size cannot be negative");
+ PyList_Append(l, x);
+ Py_DECREF(x);
+ x = 0;
+ }
+ Py_DECREF(set);
+ if ((set = PySequence_Tuple(l)) == 0) goto end;
+ o = (keyszset_pyobj *)ty->tp_alloc(ty, 0);
+ o->dfl = dfl;
+ o->set = set;
+ Py_INCREF(set);
+end:
+ Py_XDECREF(set);
+ Py_XDECREF(l);
+ Py_XDECREF(x);
+ return ((PyObject *)o);
+}
+
+static PyObject *kaget_min(PyObject *me, void *hunoz)
+ { return (PyInt_FromLong(0)); }
+#define kaget_max kaget_min
+
+static PyObject *ksget_min(PyObject *me, void *hunoz)
+{
+ PyObject *set = ((keyszset_pyobj *)me)->set;
+ int i, n, y, x = -1;
+ n = PyTuple_Size(set);
+ for (i = 0; i < n; i++) {
+ y = PyInt_AsLong(PyTuple_GetItem(set, i));
+ if (x == -1 || y < x) x = y;
+ }
+ return (PyInt_FromLong(x));
+}
+
+static PyObject *ksget_max(PyObject *me, void *hunoz)
+{
+ PyObject *set = ((keyszset_pyobj *)me)->set;
+ int i, n, y, x = -1;
+ n = PyTuple_Size(set);
+ for (i = 0; i < n; i++) {
+ y = PyInt_AsLong(PyTuple_GetItem(set, i));
+ if (y > x) x = y;
+ }
+ return (PyInt_FromLong(x));
+}
+
+static PyMemberDef keysz_pymembers[] = {
+#define MEMBERSTRUCT keysz_pyobj
+#define default dfl /* ugh! */
+ MEMBER(default, T_INT, READONLY, "KSZ.default -> default key size")
+#undef default
+#undef MEMBERSTRUCT
+ { 0 }
+};
+
+static PyGetSetDef keyszany_pygetset[] = {
+#define GETSETNAME(op, name) ka##op##_##name
+ GET (min, "KSZ.min -> smallest allowed key size")
+ GET (max, "KSZ.min -> largest allowed key size")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyMemberDef keyszrange_pymembers[] = {
+#define MEMBERSTRUCT keyszrange_pyobj
+ MEMBER(min, T_INT, READONLY, "KSZ.min -> smallest allowed key size")
+ MEMBER(max, T_INT, READONLY, "KSZ.min -> largest allowed key size")
+ MEMBER(mod, T_INT, READONLY,
+ "KSZ.mod -> key size must be a multiple of this")
+#undef MEMBERSTRUCT
+ { 0 }
+};
+
+static PyGetSetDef keyszset_pygetset[] = {
+#define GETSETNAME(op, name) ks##op##_##name
+ GET (min, "KSZ.min -> smallest allowed key size")
+ GET (max, "KSZ.min -> largest allowed key size")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyMemberDef keyszset_pymembers[] = {
+#define MEMBERSTRUCT keyszset_pyobj
+ MEMBER(set, T_OBJECT, READONLY, "KSZ.set -> allowed key sizes")
+#undef MEMBERSTRUCT
+ { 0 }
+};
+
+static PyTypeObject keysz_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.KeySZ", /* @tp_name@ */
+ sizeof(keysz_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ _PyObject_Del, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Key size constraints.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ keysz_pymembers, /* @tp_members@ */
+ 0, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ abstract_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyTypeObject keyszany_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.KeySZAny", /* @tp_name@ */
+ sizeof(keysz_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ _PyObject_Del, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Key size constraints. This object imposes no constraints on size.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ keyszany_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ keyszany_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyTypeObject keyszrange_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.KeySZRange", /* @tp_name@ */
+ sizeof(keyszrange_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ _PyObject_Del, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Key size constraints. This object asserts minimum and maximum (if\n\
+sizes, and requires the key length to be a multiple of some value.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ keyszrange_pymembers, /* @tp_members@ */
+ 0, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ keyszrange_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyTypeObject keyszset_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.KeySZSet", /* @tp_name@ */
+ sizeof(keyszset_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ _PyObject_Del, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Key size constraints. This object requires the key to be one of a\n\
+few listed sizes.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ keyszset_pymembers, /* @tp_members@ */
+ keyszset_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ keyszset_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- Symmetric encryption ----------------------------------------------*/
+
+PyTypeObject *gccipher_pytype, *gcipher_pytype;
+
+CONVFUNC(gccipher, gccipher *, GCCIPHER_CC)
+CONVFUNC(gcipher, gcipher *, GCIPHER_C)
+
+PyObject *gcipher_pywrap(PyObject *cobj, gcipher *c, unsigned f)
+{
+ gcipher_pyobj *g;
+ if (!cobj) cobj = gccipher_pywrap((/*unconst*/ gccipher *)GC_CLASS(c));
+ else Py_INCREF(cobj);
+ g = PyObject_NEW(gcipher_pyobj, (PyTypeObject *)cobj);
+ g->c = c;
+ g->f = f;
+ return ((PyObject *)g);
+}
+
+static PyObject *gcipher_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+{
+ char *kwlist[] = { "k", 0 };
+ char *k;
+ int sz;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", kwlist, &k, &sz))
+ goto end;
+ if (keysz(sz, GCCIPHER_CC(ty)->keysz) != sz) VALERR("bad key length");
+ return (gcipher_pywrap((PyObject *)ty,
+ GC_INIT(GCCIPHER_CC(ty), k, sz),
+ f_freeme));
+end:
+ return (0);
+}
+
+PyObject *gccipher_pywrap(gccipher *cc)
+{
+ gccipher_pyobj *g = newtype(gccipher_pytype, 0);
+ g->cc = cc;
+ g->ty.tp_name = (/*unconst*/ char *)cc->name;
+ g->ty.tp_basicsize = sizeof(gcipher_pyobj);
+ g->ty.tp_base = gcipher_pytype;
+ Py_INCREF(gcipher_pytype);
+ g->ty.tp_flags = (Py_TPFLAGS_DEFAULT |
+ Py_TPFLAGS_BASETYPE |
+ Py_TPFLAGS_HEAPTYPE);
+ g->ty.tp_alloc = PyType_GenericAlloc;
+ g->ty.tp_free = _PyObject_Del;
+ g->ty.tp_new = gcipher_pynew;
+ PyType_Ready(&g->ty);
+ return ((PyObject *)g);
+}
+
+static void gcipher_pydealloc(PyObject *me)
+{
+ if (GCIPHER_F(me) & f_freeme)
+ GC_DESTROY(GCIPHER_C(me));
+ Py_DECREF(me->ob_type);
+ PyObject_DEL(me);
+}
+
+static PyObject *gccget_name(PyObject *me, void *hunoz)
+ { return (PyString_FromString(GCCIPHER_CC(me)->name)); }
+
+static PyObject *gccget_keysz(PyObject *me, void *hunoz)
+ { return (keysz_pywrap(GCCIPHER_CC(me)->keysz)); }
+
+static PyObject *gccget_blksz(PyObject *me, void *hunoz)
+ { return (PyInt_FromLong(GCCIPHER_CC(me)->blksz)); }
+
+static PyObject *gcmeth_encrypt(PyObject *me, PyObject *arg)
+{
+ char *p;
+ int sz;
+ PyObject *rc = 0;
+
+ if (!PyArg_ParseTuple(arg, "s#:encrypt", &p, &sz)) return (0);
+ rc = bytestring_pywrap(0, sz);
+ GC_ENCRYPT(GCIPHER_C(me), p, PyString_AS_STRING(rc), sz);
+ return (rc);
+}
+
+static PyObject *gcmeth_enczero(PyObject *me, PyObject *arg)
+{
+ char *p;
+ int sz;
+ PyObject *rc = 0;
+
+ if (!PyArg_ParseTuple(arg, "i:enczero", &sz)) return (0);
+ rc = bytestring_pywrap(0, sz);
+ p = PyString_AS_STRING(rc);
+ memset(p, 0, sz);
+ GC_ENCRYPT(GCIPHER_C(me), p, p, sz);
+ return (rc);
+}
+
+static PyObject *gcmeth_decrypt(PyObject *me, PyObject *arg)
+{
+ char *p;
+ int sz;
+ PyObject *rc = 0;
+
+ if (!PyArg_ParseTuple(arg, "s#:decrypt", &p, &sz)) return (0);
+ rc = bytestring_pywrap(0, sz);
+ GC_DECRYPT(GCIPHER_C(me), p, PyString_AS_STRING(rc), sz);
+ return (rc);
+}
+
+static PyObject *gcmeth_deczero(PyObject *me, PyObject *arg)
+{
+ char *p;
+ int sz;
+ PyObject *rc = 0;
+
+ if (!PyArg_ParseTuple(arg, "i:deczero", &sz)) return (0);
+ rc = bytestring_pywrap(0, sz);
+ p = PyString_AS_STRING(rc);
+ memset(p, 0, sz);
+ GC_DECRYPT(GCIPHER_C(me), p, p, sz);
+ return (rc);
+}
+
+static PyObject *gcmeth_setiv(PyObject *me, PyObject *arg)
+{
+ char *p;
+ int sz;
+
+ if (!PyArg_ParseTuple(arg, "s#:setiv", &p, &sz)) goto end;
+ if (!GC_CLASS(GCIPHER_C(me))->blksz) VALERR("not a block cipher mode");
+ if (sz != GC_CLASS(GCIPHER_C(me))->blksz) VALERR("bad IV length");
+ GC_SETIV(GCIPHER_C(me), p);
+ RETURN_ME;
+end:
+ return (0);
+}
+
+static PyObject *gcmeth_bdry(PyObject *me, PyObject *arg)
+{
+ if (!PyArg_ParseTuple(arg, ":bdry")) goto end;
+ if (!GC_CLASS(GCIPHER_C(me))->blksz) VALERR("not a block cipher mode");
+ GC_BDRY(GCIPHER_C(me));
+ RETURN_ME;
+end:
+ return (0);
+}
+
+static PyGetSetDef gccipher_pygetset[] = {
+#define GETSETNAME(op, name) gcc##op##_##name
+ GET (keysz, "CC.keysz -> acceptable key sizes")
+ GET (blksz, "CC.blksz -> block size, or zero")
+ GET (name, "CC.name -> name of this kind of cipher")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyMethodDef gcipher_pymethods[] = {
+#define METHNAME(name) gcmeth_##name
+ METH (encrypt, "C.encrypt(PT) -> CT")
+ METH (enczero, "C.enczero(N) -> CT")
+ METH (decrypt, "C.decrypt(CT) -> PT")
+ METH (deczero, "C.deczero(N) -> PT")
+ METH (setiv, "C.setiv(IV)")
+ METH (bdry, "C.bdry()")
+#undef METHNAME
+ { 0 }
+};
+
+static PyTypeObject gccipher_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.GCCipher", /* @tp_name@ */
+ sizeof(gccipher_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ 0, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Symmetric cipher metaclass.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ gccipher_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ abstract_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyTypeObject gcipher_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.GCipher", /* @tp_name@ */
+ sizeof(gcipher_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ gcipher_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Symmetric cipher, abstract base class.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ gcipher_pymethods, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ 0, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ abstract_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- Hash functions ----------------------------------------------------*/
+
+PyTypeObject *gchash_pytype, *ghash_pytype;
+
+CONVFUNC(gchash, gchash *, GCHASH_CH)
+CONVFUNC(ghash, ghash *, GHASH_H)
+
+static PyObject *ghash_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+{
+ char *kwlist[] = { 0 };
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, ":new", kwlist))
+ goto end;
+ return (ghash_pywrap((PyObject *)ty, GH_INIT(GCHASH_CH(ty)), f_freeme));
+end:
+ return (0);
+}
+
+PyObject *gchash_pywrap(gchash *ch)
+{
+ gchash_pyobj *g = newtype(gchash_pytype, 0);
+ g->ch = ch;
+ g->ty.tp_name = (/*unconst*/ char *)ch->name;
+ g->ty.tp_basicsize = sizeof(ghash_pyobj);
+ g->ty.tp_base = ghash_pytype;
+ Py_INCREF(ghash_pytype);
+ g->ty.tp_flags = (Py_TPFLAGS_DEFAULT |
+ Py_TPFLAGS_BASETYPE |
+ Py_TPFLAGS_HEAPTYPE);
+ g->ty.tp_alloc = PyType_GenericAlloc;
+ g->ty.tp_free = _PyObject_Del;
+ g->ty.tp_new = ghash_pynew;
+ PyType_Ready(&g->ty);
+ return ((PyObject *)g);
+}
+
+PyObject *ghash_pywrap(PyObject *cobj, ghash *h, unsigned f)
+{
+ ghash_pyobj *g;
+ if (!cobj) cobj = gchash_pywrap((/*unconst*/ gchash *)GH_CLASS(h));
+ else Py_INCREF(cobj);
+ g = PyObject_NEW(ghash_pyobj, (PyTypeObject *)cobj);
+ g->h = h;
+ g->f = f;
+ return ((PyObject *)g);
+}
+
+static void ghash_pydealloc(PyObject *me)
+{
+ if (GHASH_F(me) & f_freeme)
+ GH_DESTROY(GHASH_H(me));
+ Py_DECREF(me->ob_type);
+ PyObject_DEL(me);
+}
+
+static PyObject *gchget_name(PyObject *me, void *hunoz)
+ { return (PyString_FromString(GCHASH_CH(me)->name)); }
+
+static PyObject *gchget_hashsz(PyObject *me, void *hunoz)
+ { return (PyInt_FromLong(GCHASH_CH(me)->hashsz)); }
+
+static PyObject *gchget_bufsz(PyObject *me, void *hunoz)
+ { return (PyInt_FromLong(GCHASH_CH(me)->bufsz)); }
+
+static PyObject *ghmeth_hash(PyObject *me, PyObject *arg)
+{
+ char *p;
+ int sz;
+ if (!PyArg_ParseTuple(arg, "s#:hash", &p, &sz)) return (0);
+ GH_HASH(GHASH_H(me), p, sz);
+ RETURN_ME;
+}
+
+static PyObject *ghmeth_done(PyObject *me, PyObject *arg)
+{
+ ghash *g;
+ PyObject *rc;
+ if (!PyArg_ParseTuple(arg, ":done")) return (0);
+ g = GH_COPY(GHASH_H(me));
+ rc = bytestring_pywrap(0, g->ops->c->hashsz);
+ GH_DONE(g, PyString_AS_STRING(rc));
+ GH_DESTROY(g);
+ return (rc);
+}
+
+static PyGetSetDef gchash_pygetset[] = {
+#define GETSETNAME(op, name) gch##op##_##name
+ GET (bufsz, "CH.bufsz -> hash buffer size, or zero")
+ GET (hashsz, "CH.blksz -> hash output size")
+ GET (name, "CH.name -> name of this kind of hash")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyMethodDef ghash_pymethods[] = {
+#define METHNAME(name) ghmeth_##name
+ METH (hash, "H.hash(M)")
+ METH (done, "H.done() -> HASH")
+#undef METHNAME
+ { 0 }
+};
+
+static PyTypeObject gchash_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.GCHash", /* @tp_name@ */
+ sizeof(gchash_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ 0, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Hash function metaclass.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ gchash_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ abstract_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyTypeObject ghash_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.GHash", /* @tp_name@ */
+ sizeof(ghash_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ ghash_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Hash function, abstract base class.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ ghash_pymethods, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ 0, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ abstract_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- Message authentication --------------------------------------------*/
+
+PyTypeObject *gcmac_pytype, *gmac_pytype, *gmhash_pytype;
+
+CONVFUNC(gcmac, gcmac *, GCMAC_CM)
+CONVFUNC(gmac, gmac *, GMAC_M)
+CONVFUNC(gmhash, ghash *, GHASH_H)
+
+static PyObject *gmac_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+{
+ char *kwlist[] = { "k", 0 };
+ char *k;
+ int sz;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", kwlist, &k, &sz))
+ goto end;
+ if (keysz(sz, GCMAC_CM(ty)->keysz) != sz) VALERR("bad key length");
+ return (gmac_pywrap((PyObject *)ty,
+ GM_KEY(GCMAC_CM(ty), k, sz),
+ f_freeme));
+end:
+ return (0);
+}
+
+static PyObject *gmhash_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+{
+ char *kwlist[] = { 0 };
+ ghash_pyobj *g;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, ":new", kwlist)) return (0);
+ g = PyObject_NEW(ghash_pyobj, ty);
+ g->h = GM_INIT(GMAC_M(ty));
+ g->f = f_freeme;
+ Py_INCREF(ty);
+ return ((PyObject *)g);
+}
+
+PyObject *gcmac_pywrap(gcmac *cm)
+{
+ gcmac_pyobj *g = newtype(gcmac_pytype, 0);
+ g->cm = cm;
+ g->ty.tp_name = (/*unconst*/ char *)cm->name;
+ g->ty.tp_basicsize = sizeof(gmac_pyobj);
+ g->ty.tp_base = gmac_pytype;
+ Py_INCREF(gmac_pytype);
+ g->ty.tp_flags = (Py_TPFLAGS_DEFAULT |
+ Py_TPFLAGS_BASETYPE |
+ Py_TPFLAGS_HEAPTYPE);
+ g->ty.tp_alloc = PyType_GenericAlloc;
+ g->ty.tp_free = _PyObject_Del;
+ g->ty.tp_new = gmac_pynew;
+ PyType_Ready(&g->ty);
+ return ((PyObject *)g);
+}
+
+PyObject *gmac_pywrap(PyObject *cobj, gmac *m, unsigned f)
+{
+ gmac_pyobj *g;
+ if (!cobj) cobj = gcmac_pywrap((/*unconst*/ gcmac *)GM_CLASS(m));
+ else Py_INCREF(cobj);
+ g = newtype((PyTypeObject *)cobj, 0);
+ g->nameobj = PyString_FromFormat("%s(keyed)", m->ops->c->name);
+ g->ty.tp_name = PyString_AS_STRING(g->nameobj);
+ g->ty.tp_base = gmhash_pytype;
+ Py_INCREF(gmac_pytype);
+ g->ty.tp_flags = (Py_TPFLAGS_DEFAULT |
+ Py_TPFLAGS_BASETYPE |
+ Py_TPFLAGS_HEAPTYPE);
+ g->ty.tp_alloc = PyType_GenericAlloc;
+ g->ty.tp_free = _PyObject_Del;
+ g->ty.tp_new = gmhash_pynew;
+ PyType_Ready(&g->ty);
+ g->m = m;
+ g->f = f;
+ return ((PyObject *)g);
+}
+
+static void gmac_pydealloc(PyObject *me)
+{
+ if (GMAC_F(me) & f_freeme)
+ GM_DESTROY(GMAC_M(me));
+ Py_DECREF(me->ob_type);
+ Py_DECREF(GMAC_NAMEOBJ(me));
+ PyType_Type.tp_dealloc(me);
+}
+
+static PyObject *gcmget_name(PyObject *me, void *hunoz)
+ { return (PyString_FromString(GCMAC_CM(me)->name)); }
+
+static PyObject *gcmget_keysz(PyObject *me, void *hunoz)
+ { return (keysz_pywrap(GCMAC_CM(me)->keysz)); }
+
+static PyObject *gcmget_tagsz(PyObject *me, void *hunoz)
+ { return (PyInt_FromLong(GCMAC_CM(me)->hashsz)); }
+
+static PyGetSetDef gcmac_pygetset[] = {
+#define GETSETNAME(op, name) gcm##op##_##name
+ GET (keysz, "CM.keysz -> acceptable key sizes")
+ GET (tagsz, "CM.tagsz -> MAC output size")
+ GET (name, "CM.name -> name of this kind of MAC")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyTypeObject gcmac_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.GCMAC", /* @tp_name@ */
+ sizeof(gchash_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ 0, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Message authentication code metametaclass.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ gcmac_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ abstract_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyTypeObject gmac_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.GMAC", /* @tp_name@ */
+ sizeof(gmac_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ gmac_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Message authentication code metaclass, abstract base class.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ 0, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ abstract_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyTypeObject gmhash_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.GMACHash", /* @tp_name@ */
+ sizeof(ghash_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ ghash_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Message authentication code, abstract base class.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ 0, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ abstract_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- Main code ---------------------------------------------------------*/
+
+void algorithms_pyinit(void)
+{
+ INITTYPE(keysz, root);
+ INITTYPE(keyszany, keysz);
+ INITTYPE(keyszrange, keysz);
+ INITTYPE(keyszset, keysz);
+ INITTYPE(gccipher, type);
+ INITTYPE(gcipher, root);
+ INITTYPE(gchash, type);
+ INITTYPE(ghash, root);
+ INITTYPE(gcmac, type);
+ INITTYPE(gmac, type);
+ INITTYPE(gmhash, ghash);
+}
+
+#define GEN(func, base) \
+ static PyObject *func(void) \
+ { \
+ PyObject *d = PyDict_New(); \
+ PyObject *o; \
+ int i; \
+ \
+ for (i = 0; g##base##tab[i]; i++) { \
+ o = gc##base##_pywrap((/*unconst*/ gc##base *)g##base##tab[i]); \
+ PyDict_SetItemString(d, \
+ (/*unconst*/ char *)g##base##tab[i]->name, \
+ o); \
+ Py_DECREF(o); \
+ } \
+ return (d); \
+ }
+GEN(gcciphers, cipher)
+GEN(gchashes, hash)
+GEN(gcmacs, mac)
+
+void algorithms_pyinsert(PyObject *mod)
+{
+ PyObject *d;
+ INSERT("KeySZ", keysz_pytype);
+ INSERT("KeySZAny", keyszany_pytype);
+ INSERT("KeySZRange", keyszrange_pytype);
+ INSERT("KeySZSet", keyszset_pytype);
+ INSERT("GCCipher", gccipher_pytype);
+ INSERT("GCipher", gcipher_pytype);
+ INSERT("gcciphers", gcciphers());
+ INSERT("GCHash", gchash_pytype);
+ INSERT("GHash", ghash_pytype);
+ INSERT("gchashes", d = gchashes());
+ sha_pyobj = PyDict_GetItemString(d, "sha"); Py_INCREF(sha_pyobj);
+ has160_pyobj = PyDict_GetItemString(d, "has160"); Py_INCREF(has160_pyobj);
+ INSERT("GCMAC", gcmac_pytype);
+ INSERT("GMAC", gmac_pytype);
+ INSERT("GMACHash", gmhash_pytype);
+ INSERT("gcmacs", gcmacs());
+}
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+/* algorithms.h [generated] */
+
+#include <catacomb/des.h>
+#include <catacomb/des-ecb.h>
+#include <catacomb/des-cbc.h>
+#include <catacomb/des-cfb.h>
+#include <catacomb/des-ofb.h>
+#include <catacomb/des-counter.h>
+#include <catacomb/desx.h>
+#include <catacomb/desx-ecb.h>
+#include <catacomb/desx-cbc.h>
+#include <catacomb/desx-cfb.h>
+#include <catacomb/desx-ofb.h>
+#include <catacomb/desx-counter.h>
+#include <catacomb/des3.h>
+#include <catacomb/des3-ecb.h>
+#include <catacomb/des3-cbc.h>
+#include <catacomb/des3-cfb.h>
+#include <catacomb/des3-ofb.h>
+#include <catacomb/des3-counter.h>
+#include <catacomb/mars.h>
+#include <catacomb/mars-ecb.h>
+#include <catacomb/mars-cbc.h>
+#include <catacomb/mars-cfb.h>
+#include <catacomb/mars-ofb.h>
+#include <catacomb/mars-counter.h>
+#include <catacomb/idea.h>
+#include <catacomb/idea-ecb.h>
+#include <catacomb/idea-cbc.h>
+#include <catacomb/idea-cfb.h>
+#include <catacomb/idea-ofb.h>
+#include <catacomb/idea-counter.h>
+#include <catacomb/safer.h>
+#include <catacomb/safer-ecb.h>
+#include <catacomb/safer-cbc.h>
+#include <catacomb/safer-cfb.h>
+#include <catacomb/safer-ofb.h>
+#include <catacomb/safer-counter.h>
+#include <catacomb/safersk.h>
+#include <catacomb/safersk-ecb.h>
+#include <catacomb/safersk-cbc.h>
+#include <catacomb/safersk-cfb.h>
+#include <catacomb/safersk-ofb.h>
+#include <catacomb/safersk-counter.h>
+#include <catacomb/blowfish.h>
+#include <catacomb/blowfish-ecb.h>
+#include <catacomb/blowfish-cbc.h>
+#include <catacomb/blowfish-cfb.h>
+#include <catacomb/blowfish-ofb.h>
+#include <catacomb/blowfish-counter.h>
+#include <catacomb/twofish.h>
+#include <catacomb/twofish-ecb.h>
+#include <catacomb/twofish-cbc.h>
+#include <catacomb/twofish-cfb.h>
+#include <catacomb/twofish-ofb.h>
+#include <catacomb/twofish-counter.h>
+#include <catacomb/tea.h>
+#include <catacomb/tea-ecb.h>
+#include <catacomb/tea-cbc.h>
+#include <catacomb/tea-cfb.h>
+#include <catacomb/tea-ofb.h>
+#include <catacomb/tea-counter.h>
+#include <catacomb/xtea.h>
+#include <catacomb/xtea-ecb.h>
+#include <catacomb/xtea-cbc.h>
+#include <catacomb/xtea-cfb.h>
+#include <catacomb/xtea-ofb.h>
+#include <catacomb/xtea-counter.h>
+#include <catacomb/rc2.h>
+#include <catacomb/rc2-ecb.h>
+#include <catacomb/rc2-cbc.h>
+#include <catacomb/rc2-cfb.h>
+#include <catacomb/rc2-ofb.h>
+#include <catacomb/rc2-counter.h>
+#include <catacomb/rc5.h>
+#include <catacomb/rc5-ecb.h>
+#include <catacomb/rc5-cbc.h>
+#include <catacomb/rc5-cfb.h>
+#include <catacomb/rc5-ofb.h>
+#include <catacomb/rc5-counter.h>
+#include <catacomb/skipjack.h>
+#include <catacomb/skipjack-ecb.h>
+#include <catacomb/skipjack-cbc.h>
+#include <catacomb/skipjack-cfb.h>
+#include <catacomb/skipjack-ofb.h>
+#include <catacomb/skipjack-counter.h>
+#include <catacomb/cast128.h>
+#include <catacomb/cast128-ecb.h>
+#include <catacomb/cast128-cbc.h>
+#include <catacomb/cast128-cfb.h>
+#include <catacomb/cast128-ofb.h>
+#include <catacomb/cast128-counter.h>
+#include <catacomb/cast256.h>
+#include <catacomb/cast256-ecb.h>
+#include <catacomb/cast256-cbc.h>
+#include <catacomb/cast256-cfb.h>
+#include <catacomb/cast256-ofb.h>
+#include <catacomb/cast256-counter.h>
+#include <catacomb/square.h>
+#include <catacomb/square-ecb.h>
+#include <catacomb/square-cbc.h>
+#include <catacomb/square-cfb.h>
+#include <catacomb/square-ofb.h>
+#include <catacomb/square-counter.h>
+#include <catacomb/rijndael.h>
+#include <catacomb/rijndael-ecb.h>
+#include <catacomb/rijndael-cbc.h>
+#include <catacomb/rijndael-cfb.h>
+#include <catacomb/rijndael-ofb.h>
+#include <catacomb/rijndael-counter.h>
+#include <catacomb/rijndael192.h>
+#include <catacomb/rijndael192-ecb.h>
+#include <catacomb/rijndael192-cbc.h>
+#include <catacomb/rijndael192-cfb.h>
+#include <catacomb/rijndael192-ofb.h>
+#include <catacomb/rijndael192-counter.h>
+#include <catacomb/rijndael256.h>
+#include <catacomb/rijndael256-ecb.h>
+#include <catacomb/rijndael256-cbc.h>
+#include <catacomb/rijndael256-cfb.h>
+#include <catacomb/rijndael256-ofb.h>
+#include <catacomb/rijndael256-counter.h>
+#include <catacomb/serpent.h>
+#include <catacomb/serpent-ecb.h>
+#include <catacomb/serpent-cbc.h>
+#include <catacomb/serpent-cfb.h>
+#include <catacomb/serpent-ofb.h>
+#include <catacomb/serpent-counter.h>
+#include <catacomb/noekeon.h>
+#include <catacomb/noekeon-ecb.h>
+#include <catacomb/noekeon-cbc.h>
+#include <catacomb/noekeon-cfb.h>
+#include <catacomb/noekeon-ofb.h>
+#include <catacomb/noekeon-counter.h>
+#include <catacomb/rc4.h>
+#include <catacomb/seal.h>
+
+#include <catacomb/md2.h>
+#include <catacomb/md2-mgf.h>
+#include <catacomb/md2-hmac.h>
+#include <catacomb/md4.h>
+#include <catacomb/md4-mgf.h>
+#include <catacomb/md4-hmac.h>
+#include <catacomb/md5.h>
+#include <catacomb/md5-mgf.h>
+#include <catacomb/md5-hmac.h>
+#include <catacomb/tiger.h>
+#include <catacomb/tiger-mgf.h>
+#include <catacomb/tiger-hmac.h>
+#include <catacomb/has160.h>
+#include <catacomb/has160-mgf.h>
+#include <catacomb/has160-hmac.h>
+#include <catacomb/sha.h>
+#include <catacomb/sha-mgf.h>
+#include <catacomb/sha-hmac.h>
+#include <catacomb/sha224.h>
+#include <catacomb/sha224-mgf.h>
+#include <catacomb/sha224-hmac.h>
+#include <catacomb/sha256.h>
+#include <catacomb/sha256-mgf.h>
+#include <catacomb/sha256-hmac.h>
+#include <catacomb/sha384.h>
+#include <catacomb/sha384-mgf.h>
+#include <catacomb/sha384-hmac.h>
+#include <catacomb/sha512.h>
+#include <catacomb/sha512-mgf.h>
+#include <catacomb/sha512-hmac.h>
+#include <catacomb/rmd128.h>
+#include <catacomb/rmd128-mgf.h>
+#include <catacomb/rmd128-hmac.h>
+#include <catacomb/rmd160.h>
+#include <catacomb/rmd160-mgf.h>
+#include <catacomb/rmd160-hmac.h>
+#include <catacomb/rmd256.h>
+#include <catacomb/rmd256-mgf.h>
+#include <catacomb/rmd256-hmac.h>
+#include <catacomb/rmd320.h>
+#include <catacomb/rmd320-mgf.h>
+#include <catacomb/rmd320-hmac.h>
+#include <catacomb/whirlpool.h>
+#include <catacomb/whirlpool-mgf.h>
+#include <catacomb/whirlpool-hmac.h>
+#include <catacomb/whirlpool256.h>
+#include <catacomb/whirlpool256-mgf.h>
+#include <catacomb/whirlpool256-hmac.h>
+
+#define PRPS(DO) \
+ DO(DES, des) \
+ DO(DESX, desx) \
+ DO(DES3, des3) \
+ DO(MARS, mars) \
+ DO(IDEA, idea) \
+ DO(SAFER, safer) \
+ DO(SAFERSK, safersk) \
+ DO(BLOWFISH, blowfish) \
+ DO(TWOFISH, twofish) \
+ DO(TEA, tea) \
+ DO(XTEA, xtea) \
+ DO(RC2, rc2) \
+ DO(RC5, rc5) \
+ DO(SKIPJACK, skipjack) \
+ DO(CAST128, cast128) \
+ DO(CAST256, cast256) \
+ DO(SQUARE, square) \
+ DO(RIJNDAEL, rijndael) \
+ DO(RIJNDAEL192, rijndael192) \
+ DO(RIJNDAEL256, rijndael256) \
+ DO(SERPENT, serpent) \
+ DO(NOEKEON, noekeon) \
+ /* end */
+
+#define RNGS(DO) \
+ DO("des-ofb", des_ofbrand) \
+ DO("des-counter", des_counterrand) \
+ DO("desx-ofb", desx_ofbrand) \
+ DO("desx-counter", desx_counterrand) \
+ DO("des3-ofb", des3_ofbrand) \
+ DO("des3-counter", des3_counterrand) \
+ DO("mars-ofb", mars_ofbrand) \
+ DO("mars-counter", mars_counterrand) \
+ DO("idea-ofb", idea_ofbrand) \
+ DO("idea-counter", idea_counterrand) \
+ DO("safer-ofb", safer_ofbrand) \
+ DO("safer-counter", safer_counterrand) \
+ DO("safersk-ofb", safersk_ofbrand) \
+ DO("safersk-counter", safersk_counterrand) \
+ DO("blowfish-ofb", blowfish_ofbrand) \
+ DO("blowfish-counter", blowfish_counterrand) \
+ DO("twofish-ofb", twofish_ofbrand) \
+ DO("twofish-counter", twofish_counterrand) \
+ DO("tea-ofb", tea_ofbrand) \
+ DO("tea-counter", tea_counterrand) \
+ DO("xtea-ofb", xtea_ofbrand) \
+ DO("xtea-counter", xtea_counterrand) \
+ DO("rc2-ofb", rc2_ofbrand) \
+ DO("rc2-counter", rc2_counterrand) \
+ DO("rc5-ofb", rc5_ofbrand) \
+ DO("rc5-counter", rc5_counterrand) \
+ DO("skipjack-ofb", skipjack_ofbrand) \
+ DO("skipjack-counter", skipjack_counterrand) \
+ DO("cast128-ofb", cast128_ofbrand) \
+ DO("cast128-counter", cast128_counterrand) \
+ DO("cast256-ofb", cast256_ofbrand) \
+ DO("cast256-counter", cast256_counterrand) \
+ DO("square-ofb", square_ofbrand) \
+ DO("square-counter", square_counterrand) \
+ DO("rijndael-ofb", rijndael_ofbrand) \
+ DO("rijndael-counter", rijndael_counterrand) \
+ DO("rijndael192-ofb", rijndael192_ofbrand) \
+ DO("rijndael192-counter", rijndael192_counterrand) \
+ DO("rijndael256-ofb", rijndael256_ofbrand) \
+ DO("rijndael256-counter", rijndael256_counterrand) \
+ DO("serpent-ofb", serpent_ofbrand) \
+ DO("serpent-counter", serpent_counterrand) \
+ DO("noekeon-ofb", noekeon_ofbrand) \
+ DO("noekeon-counter", noekeon_counterrand) \
+ DO("md2-mgf", md2_mgfrand) \
+ DO("md4-mgf", md4_mgfrand) \
+ DO("md5-mgf", md5_mgfrand) \
+ DO("tiger-mgf", tiger_mgfrand) \
+ DO("has160-mgf", has160_mgfrand) \
+ DO("sha-mgf", sha_mgfrand) \
+ DO("sha224-mgf", sha224_mgfrand) \
+ DO("sha256-mgf", sha256_mgfrand) \
+ DO("sha384-mgf", sha384_mgfrand) \
+ DO("sha512-mgf", sha512_mgfrand) \
+ DO("rmd128-mgf", rmd128_mgfrand) \
+ DO("rmd160-mgf", rmd160_mgfrand) \
+ DO("rmd256-mgf", rmd256_mgfrand) \
+ DO("rmd320-mgf", rmd320_mgfrand) \
+ DO("whirlpool-mgf", whirlpool_mgfrand) \
+ DO("whirlpool256-mgf", whirlpool256_mgfrand) \
+ DO("rc4", rc4_rand) \
+ DO("seal", seal_randkludge) \
+ /* end */
+
--- /dev/null
+## -*-python-*-
+
+def cross(*seq):
+ if not len(seq):
+ return [(),]
+ x = seq[0]
+ if type(x) is not tuple and type(x) is not list:
+ x = x,
+ r = []
+ for i in x:
+ for j in cross(*seq[1:]):
+ r.append((i,) + j)
+ return r
+
+prps = '''
+des desx des3 mars
+idea safer safersk
+blowfish twofish
+tea xtea
+rc2 rc5
+skipjack
+cast128 cast256
+square rijndael rijndael192 rijndael256
+serpent noekeon
+'''.split()
+pmodes = '''
+ecb cbc cfb ofb counter
+'''.split()
+streamciphers = '''
+rc4 seal
+'''.split()
+hashes = '''
+md2 md4 md5 tiger has160
+sha sha224 sha256 sha384 sha512
+rmd128 rmd160 rmd256 rmd320
+whirlpool whirlpool256
+'''.split()
+hmodes = '''
+mgf hmac
+'''.split()
+
+print '/* algorithms.h [generated] */'
+print
+
+for i in prps:
+ print '#include <catacomb/%s.h>' % i
+ for j in pmodes:
+ print '#include <catacomb/%s-%s.h>' % (i, j)
+for i in streamciphers:
+ print '#include <catacomb/%s.h>' % i
+print
+for i in hashes:
+ print '#include <catacomb/%s.h>' % i
+ for j in hmodes:
+ print '#include <catacomb/%s-%s.h>' % (i, j)
+print
+
+print '#define PRPS(DO) \\'
+for i in prps:
+ print ' DO(%s, %s) \\' % (i.upper(), i)
+print ' /* end */'
+print
+
+print '#define RNGS(DO) \\'
+for i in (cross(prps, ['ofb', 'counter']) +
+ cross(hashes, 'mgf')):
+ print ' DO("%(prim)s-%(mode)s", %(prim)s_%(mode)srand) \\' % \
+ {'prim': i[0], 'mode': i[1]}
+print ' DO("rc4", rc4_rand) \\'
+print ' DO("seal", seal_randkludge) \\'
+print ' /* end */'
+print
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id$
+ *
+ * Byte strings
+ *
+ * (c) 2004 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of the Python interface to Catacomb.
+ *
+ * Catacomb/Python is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb/Python is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Catacomb/Python; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "catacomb-python.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+PyTypeObject *bytestring_pytype;
+
+PyObject *bytestring_pywrap(const void *p, size_t n)
+{
+ PyStringObject *x = PyObject_NewVar(PyStringObject, bytestring_pytype, n);
+ if (p) memcpy(x->ob_sval, p, n);
+ x->ob_sval[n] = 0;
+#ifdef CACHE_HASH
+ x->ob_shash = -1;
+#endif
+#ifdef INTERN_STRINGS
+ x->ob_sinterned = NULL;
+#endif
+ return ((PyObject *)x);
+}
+
+PyObject *bytestring_pywrapbuf(buf *b)
+ { return bytestring_pywrap(BCUR(b), BLEFT(b)); }
+
+#define BINOP(name, op) \
+ static PyObject *bytestring_py##name(PyObject *x, PyObject *y) { \
+ const void *xv, *yv; \
+ const unsigned char *xp, *yp; \
+ unsigned char *zp; \
+ int xsz, ysz; \
+ int i; \
+ PyObject *rc = 0; \
+ if (PyObject_AsReadBuffer(x, &xv, &xsz) || \
+ PyObject_AsReadBuffer(y, &yv, &ysz)) \
+ goto end; \
+ if (xsz != ysz) VALERR("length mismatch"); \
+ rc = bytestring_pywrap(0, xsz); \
+ xp = xv; yp = yv; zp = (unsigned char *)PyString_AS_STRING(rc); \
+ for (i = xsz; i > 0; i--) *zp++ = *xp++ op *yp++; \
+ end: \
+ return (rc); \
+ }
+BINOP(and, &)
+BINOP(or, |)
+BINOP(xor, ^)
+
+#define UNOP(name, op) \
+ static PyObject *bytestring_py##name(PyObject *x) { \
+ const void *xv; \
+ const unsigned char *xp; \
+ unsigned char *zp; \
+ int xsz; \
+ int i; \
+ PyObject *rc = 0; \
+ if (PyObject_AsReadBuffer(x, &xv, &xsz)) goto end; \
+ rc = bytestring_pywrap(0, xsz); \
+ xp = xv; zp = (unsigned char *)PyString_AS_STRING(rc); \
+ for (i = xsz; i > 0; i--) *zp++ = op *xp++; \
+ end: \
+ return (rc); \
+ }
+UNOP(not, ~)
+
+static PyNumberMethods bytestring_pynumber = {
+ 0, /* @nb_add@ */
+ 0, /* @nb_subtract@ */
+ 0, /* @nb_multiply@ */
+ 0, /* @nb_divide@ */
+ 0, /* @nb_remainder@ */
+ 0, /* @nb_divmod@ */
+ 0, /* @nb_power@ */
+ 0, /* @nb_negative@ */
+ 0, /* @nb_positive@ */
+ 0, /* @nb_absolute@ */
+ 0, /* @nb_nonzero@ */
+ bytestring_pynot, /* @nb_invert@ */
+ 0, /* @nb_lshift@ */
+ 0, /* @nb_rshift@ */
+ bytestring_pyand, /* @nb_and@ */
+ bytestring_pyxor, /* @nb_xor@ */
+ bytestring_pyor, /* @nb_or@ */
+ 0, /* @nb_coerce@ */
+ 0, /* @nb_int@ */
+ 0, /* @nb_long@ */
+ 0, /* @nb_float@ */
+ 0, /* @nb_oct@ */
+ 0, /* @nb_hex@ */
+};
+
+static PyBufferProcs bytestring_pybuffer;
+
+static PyTypeObject bytestring_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.ByteString", /* @tp_name@ */
+ 0, /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ 0, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ &bytestring_pynumber, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ &bytestring_pybuffer, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_CHECKTYPES |
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Byte string class.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ 0, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ 0, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- Initialization ----------------------------------------------------*/
+
+#define string_pytype &PyString_Type
+void bytestring_pyinit(void)
+{
+ INITTYPE(bytestring, string);
+}
+
+void bytestring_pyinsert(PyObject *mod)
+{
+ INSERT("ByteString", bytestring_pytype);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id$
+ *
+ * Definitions for Catacomb bindings
+ *
+ * (c) 2004 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of the Python interface to Catacomb.
+ *
+ * Catacomb/Python is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb/Python is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Catacomb/Python; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef CATACOMB_PYTHON_H
+#define CATACOMB_PYTHON_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <Python.h>
+#include <longintrepr.h>
+#include <structmember.h>
+
+#include <mLib/darray.h>
+#include <mLib/dstr.h>
+#include <mLib/macros.h>
+
+#include <catacomb/buf.h>
+
+#include <catacomb/grand.h>
+#include <catacomb/rand.h>
+#include <catacomb/noise.h>
+#include <catacomb/bbs.h>
+#include <catacomb/mprand.h>
+#include <catacomb/lcrand.h>
+#include <catacomb/fibrand.h>
+#include <catacomb/dsarand.h>
+#include <catacomb/sslprf.h>
+#include <catacomb/tlsprf.h>
+
+#include <catacomb/gcipher.h>
+#include <catacomb/ghash.h>
+#include <catacomb/gmac.h>
+#include <catacomb/md5.h>
+#include <catacomb/md5-hmac.h>
+#include <catacomb/sha.h>
+#include <catacomb/sha-mgf.h>
+#include <catacomb/sha-hmac.h>
+
+#include <catacomb/mp.h>
+#include <catacomb/mpint.h>
+#include <catacomb/mpmul.h>
+#include <catacomb/mpcrt.h>
+#include <catacomb/mpmont.h>
+#include <catacomb/mpbarrett.h>
+#include <catacomb/mpreduce.h>
+
+#include <catacomb/pgen.h>
+#include <catacomb/pfilt.h>
+#include <catacomb/strongprime.h>
+#include <catacomb/limlee.h>
+#include <catacomb/dh.h>
+#include <catacomb/ptab.h>
+#include <catacomb/bintab.h>
+#include <catacomb/dsa.h>
+
+#include <catacomb/gf.h>
+#include <catacomb/gfreduce.h>
+#include <catacomb/gfn.h>
+
+#include <catacomb/field.h>
+#include <catacomb/field-guts.h>
+
+#include <catacomb/ec.h>
+#include <catacomb/ec-raw.h>
+#include <catacomb/ectab.h>
+
+#include <catacomb/group.h>
+#include <catacomb/group-guts.h>
+
+#include <catacomb/gdsa.h>
+#include <catacomb/gkcdsa.h>
+#include <catacomb/rsa.h>
+
+#include <catacomb/key.h>
+#include <catacomb/passphrase.h>
+#include <catacomb/pixie.h>
+
+/*----- Utility macros ----------------------------------------------------*/
+
+#define RETURN_OBJ(obj) do { Py_INCREF(obj); return (obj); } while (0)
+#define RETURN_NONE RETURN_OBJ(Py_None)
+#define RETURN_NOTIMPL RETURN_OBJ(Py_NotImplemented)
+#define RETURN_TRUE RETURN_OBJ(Py_True)
+#define RETURN_FALSE RETURN_OBJ(Py_False)
+#define RETURN_ME RETURN_OBJ(me)
+
+#define EXCERR(exc, str) do { \
+ PyErr_SetString(exc, str); \
+ goto end; \
+} while (0)
+#define VALERR(str) EXCERR(PyExc_ValueError, str)
+#define TYERR(str) EXCERR(PyExc_TypeError, str)
+#define ZDIVERR(str) EXCERR(PyExc_ZeroDivisionError, str)
+#define SYNERR(str) EXCERR(PyExc_SyntaxError, str)
+#define SYSERR(str) EXCERR(PyExc_SystemError, str)
+#define OSERR(name) do { \
+ PyErr_SetFromErrnoWithFilename(PyExc_OSError, name); \
+ goto end; \
+} while (0)
+#define PGENERR do { pgenerr(); goto end; } while (0)
+
+#define CONVFUNC(ty, cty, ext) \
+ int conv##ty(PyObject *o, void *p) \
+ { \
+ if (!PyObject_TypeCheck(o, ty##_pytype)) \
+ TYERR("wanted a " #ty); \
+ *(cty *)p = ext(o); \
+ return (1); \
+ end: \
+ return (0); \
+ }
+
+#define root_pytype 0
+#define type_pytype &PyType_Type
+#define INITTYPE(ty, base) do { \
+ ty##_pytype_skel.tp_base = base##_pytype; \
+ ty##_pytype = inittype(&ty##_pytype_skel); \
+} while (0)
+
+#define INSERT(name, ob) do { \
+ PyObject *_o = (PyObject *)(ob); \
+ Py_INCREF(_o); \
+ PyModule_AddObject(mod, name, _o); \
+} while (0)
+
+#define METH(func, doc) \
+ { #func, METHNAME(func), METH_VARARGS, doc },
+#define KWMETH(func, doc) \
+ { #func, (PyCFunction)METHNAME(func), \
+ METH_VARARGS | METH_KEYWORDS, doc },
+
+#define GET(func, doc) \
+ { #func, GETSETNAME(get, func), 0, doc },
+#define GETSET(func, doc) \
+ { #func, GETSETNAME(get, func), GETSETNAME(set, func), doc },
+
+#define MEMBER(name, ty, f, doc) \
+ { #name, ty, offsetof(MEMBERSTRUCT, name), f, doc },
+
+#define MODULES(DO) \
+ DO(bytestring) \
+ DO(rand) DO(algorithms) DO(pubkey) DO(pgen) \
+ DO(mp) DO(field) DO(ec) DO(group) \
+ DO(passphrase)
+#define DOMODINIT(m) m##_pyinit();
+#define DOMODINSERT(m) m##_pyinsert(mod);
+#define INIT_MODULES do { MODULES(DOMODINIT) } while (0)
+#define INSERT_MODULES do { MODULES(DOMODINSERT) } while (0)
+
+#define DO(m) \
+ extern void m##_pyinit(void); \
+ extern void m##_pyinsert(PyObject *);
+MODULES(DO)
+#undef DO
+
+/*----- Bytestrings -------------------------------------------------------*/
+
+PyTypeObject *bytestring_pyobj;
+PyObject *bytestring_pywrap(const void *, size_t);
+PyObject *bytestring_pywrapbuf(buf *);
+
+/*----- Multiprecision arithmetic -----------------------------------------*/
+
+typedef struct mp_pyobj {
+ PyObject_HEAD
+ mp *x;
+} mp_pyobj;
+
+extern PyTypeObject *mp_pytype;
+extern PyTypeObject *gf_pytype;
+#define MP_X(o) (((mp_pyobj *)(o))->x)
+#define MP_PYCHECK(o) PyObject_TypeCheck((o), mp_pytype)
+#define GF_PYCHECK(o) PyObject_TypeCheck((o), gf_pytype)
+
+extern mp *mp_frompylong(PyLongObject *);
+extern PyLongObject *mp_topylong(mp *);
+extern mp *tomp(PyObject *);
+extern mp *getmp(PyObject *);
+extern int convmp(PyObject *, void *);
+extern mp *getgf(PyObject *);
+extern int convgf(PyObject *, void *);
+extern PyObject *mp_pywrap(mp *);
+extern PyObject *gf_pywrap(mp *);
+extern mp *mp_frompyobject(PyObject *, int);
+extern PyObject *mp_topystring(mp *, int,
+ const char *, const char *, const char *);
+extern int mp_tolong_checked(mp *, long *);
+
+/*----- Abstract fields ---------------------------------------------------*/
+
+typedef struct field_pyobj {
+ PyTypeObject ty;
+ field *f;
+} field_pyobj;
+
+extern PyTypeObject *fe_pytype;
+#define FE_PYCHECK(o) PyObject_TypeCheck((o), fe_pytype)
+#define FE_F(o) (((fe_pyobj *)(o))->f)
+#define FE_FOBJ(o) ((PyObject *)(o)->ob_type)
+#define FE_X(o) (((fe_pyobj *)(o))->x)
+extern PyObject *fe_pywrap(PyObject *, mp *);
+extern mp *getfe(field *, PyObject *);
+
+typedef struct fe_pyobj {
+ PyObject_HEAD
+ field *f;
+ PyObject *fobj; /* to keep it alive */
+ mp *x;
+} fe_pyobj;
+
+extern PyTypeObject *field_pytype;
+extern PyTypeObject *primefield_pytype;
+extern PyTypeObject *niceprimefield_pytype;
+extern PyTypeObject *binfield_pytype;
+extern PyTypeObject *binpolyfield_pytype;
+extern PyTypeObject *binnormfield_pytype;
+#define FIELD_PYCHECK(o) PyObject_TypeCheck((o), field_pytype)
+#define FIELD_F(o) (((field_pyobj *)(o))->f)
+extern PyObject *field_pywrap(field *);
+extern field *field_copy(field *);
+
+/*----- Elliptic curves ---------------------------------------------------*/
+
+typedef struct ecpt_pyobj {
+ PyObject_HEAD
+ ec_curve *c;
+ ec p;
+} ecpt_pyobj;
+
+extern PyTypeObject *ecpt_pytype, *ecptcurve_pytype;
+#define ECPT_PYCHECK(o) PyObject_TypeCheck((o), ecpt_pytype)
+#define ECPTCURVE_PYCHECK(o) PyObject_TypeCheck((o), ecptcurve_pytype)
+#define ECPT_C(o) (((ecpt_pyobj *)(o))->c)
+#define ECPT_COBJ(o) ((PyObject *)(o)->ob_type)
+#define ECPT_FOBJ(o) ECCURVE_FOBJ(ECPT_COBJ((o)))
+#define ECPT_P(o) (&((ecpt_pyobj *)(o))->p)
+extern PyObject *ecpt_pywrap(PyObject *, ec *);
+extern PyObject *ecpt_pywrapout(void *, ec *);
+extern int toecpt(ec_curve *, ec *, PyObject *);
+extern int getecpt(ec_curve *, ec *, PyObject *);
+extern void getecptout(ec *, PyObject *);
+extern int convec(PyObject *, void *);
+
+typedef struct eccurve_pyobj {
+ PyTypeObject ty;
+ ec_curve *c;
+ PyObject *fobj;
+} eccurve_pyobj;
+
+extern PyTypeObject *eccurve_pytype;
+extern PyTypeObject *ecprimecurve_pytype;
+extern PyTypeObject *ecprimeprojcurve_pytype;
+extern PyTypeObject *ecbincurve_pytype;
+extern PyTypeObject *ecbinprojcurve_pytype;
+#define ECCURVE_PYCHECK(o) PyObject_TypeCheck((o), eccurve_pytype)
+#define ECCURVE_C(o) (((eccurve_pyobj *)(o))->c)
+#define ECCURVE_FOBJ(o) (((eccurve_pyobj *)(o))->fobj)
+extern PyObject *eccurve_pywrap(PyObject *, ec_curve *);
+extern ec_curve *eccurve_copy(ec_curve *);
+
+typedef struct ecinfo_pyobj {
+ PyObject_HEAD
+ ec_info ei;
+ PyObject *cobj;
+} ecinfo_pyobj;
+
+extern PyTypeObject *ecinfo_pytype;
+#define ECINFO_PYCHECK(o) PyObject_TypeCheck((o), ecinfo_pytype)
+#define ECINFO_EI(o) (&((ecinfo_pyobj *)(o))->ei)
+#define ECINFO_COBJ(o) (((ecinfo_pyobj *)(o))->cobj)
+extern void ecinfo_copy(ec_info *, const ec_info *);
+extern PyObject *ecinfo_pywrap(ec_info *);
+
+/*----- Cyclic groups -----------------------------------------------------*/
+
+typedef struct fginfo_pyobj {
+ PyObject_HEAD
+ gprime_param dp;
+} fginfo_pyobj;
+
+PyTypeObject *fginfo_pytype, *dhinfo_pytype, *bindhinfo_pytype;
+#define FGINFO_DP(fg) (&((fginfo_pyobj *)(fg))->dp)
+PyObject *fginfo_pywrap(gprime_param *, PyTypeObject *);
+
+typedef struct ge_pyobj {
+ PyObject_HEAD
+ ge *x;
+ group *g;
+} ge_pyobj;
+
+extern PyTypeObject *ge_pytype;
+#define GE_PYCHECK(o) PyObject_TypeCheck((o), ge_pytype)
+#define GE_X(o) (((ge_pyobj *)(o))->x)
+#define GE_G(o) (((ge_pyobj *)(o))->g)
+#define GE_GOBJ(o) ((PyObject *)(group_pyobj *)(o)->ob_type)
+extern PyObject *ge_pywrap(PyObject *, ge *);
+
+typedef struct group_pyobj {
+ PyTypeObject ty;
+ group *g;
+} group_pyobj;
+
+extern PyTypeObject *group_pytype;
+extern PyTypeObject *primegroup_pytype, *bingroup_pytype, *ecgroup_pytype;
+#define GROUP_G(o) (((group_pyobj *)(o))->g)
+extern PyObject *group_pywrap(group *);
+extern group *group_copy(group *);
+
+/*----- Random number generators ------------------------------------------*/
+
+#define f_freeme 1u
+
+typedef struct grand_pyobj {
+ PyObject_HEAD
+ unsigned f;
+ grand *r;
+} grand_pyobj;
+
+extern PyTypeObject *grand_pytype, *truerand_pytype;
+extern PyTypeObject *lcrand_pytype,* fibrand_pytype;
+extern PyTypeObject *dsarand_pytype, *bbs_pytype;
+extern PyObject *rand_pyobj;
+#define GRAND_PYCHECK(o) PyObject_TypeCheck((o), grand_pytype)
+#define GRAND_F(o) (((grand_pyobj *)(o))->f)
+#define GRAND_R(o) (((grand_pyobj *)(o))->r)
+extern PyObject *grand_pywrap(grand *, unsigned);
+extern int convgrand(PyObject *, void *);
+
+/*----- Key sizes ---------------------------------------------------------*/
+
+typedef struct keysz_pyobj {
+ PyObject_HEAD
+ int dfl;
+} keysz_pyobj;
+
+typedef struct keyszrange_pyobj {
+ PyObject_HEAD
+ int dfl;
+ int min, max, mod;
+} keyszrange_pyobj;
+
+typedef struct keyszset_pyobj {
+ PyObject_HEAD
+ int dfl;
+ PyObject *set;
+} keyszset_pyobj;
+
+#define KEYSZ_PYCHECK(o) PyObject_TypeCheck((o), keysz_pytype)
+extern PyObject *keysz_pywrap(const octet *);
+
+/*----- Symmetric cryptography --------------------------------------------*/
+
+typedef struct gccipher_pyobj {
+ PyTypeObject ty;
+ gccipher *cc;
+} gccipher_pyobj;
+
+extern PyTypeObject *gccipher_pytype;
+#define GCCIPHER_PYCHECK(o) PyObject_TypeCheck((o), gccipher_pytype)
+#define GCCIPHER_CC(o) (((gccipher_pyobj *)(o))->cc)
+#define GCCIPHER_F(o) (((gccipher_pyobj *)(o))->f)
+extern PyObject *gccipher_pywrap(gccipher *);
+extern int convgccipher(PyObject *, void *);
+extern int convgcipher(PyObject *, void *);
+
+typedef struct gcipher_pyobj {
+ PyObject_HEAD
+ unsigned f;
+ gcipher *c;
+} gcipher_pyobj;
+
+extern PyTypeObject *gcipher_pytype;
+#define GCIPHER_PYCHECK(o) PyObject_TypeCheck((o), gcipher_pytype)
+#define GCIPHER_C(o) (((gcipher_pyobj *)(o))->c)
+#define GCIPHER_F(o) (((gcipher_pyobj *)(o))->f)
+extern PyObject *gcipher_pywrap(PyObject *, gcipher *, unsigned);
+extern int convgcipher(PyObject *, void *);
+
+typedef struct gchash_pyobj {
+ PyTypeObject ty;
+ gchash *ch;
+} gchash_pyobj;
+
+extern PyTypeObject *gchash_pytype;
+#define GCHASH_PYCHECK(o) PyObject_TypeCheck((o), gchash_pytype)
+#define GCHASH_CH(o) (((gchash_pyobj *)(o))->ch)
+#define GCHASH_F(o) (((gchash_pyobj *)(o))->f)
+extern PyObject *gchash_pywrap(gchash *);
+extern int convgchash(PyObject *, void *);
+
+typedef struct ghash_pyobj {
+ PyObject_HEAD
+ unsigned f;
+ ghash *h;
+} ghash_pyobj;
+
+extern PyTypeObject *ghash_pytype, *gmhash_pytype;
+extern PyObject *sha_pyobj, *has160_pyobj;
+#define GHASH_PYCHECK(o) PyObject_TypeCheck((o), ghash_pytype)
+#define GHASH_H(o) (((ghash_pyobj *)(o))->h)
+#define GHASH_F(o) (((ghash_pyobj *)(o))->f)
+extern PyObject *ghash_pywrap(PyObject *, ghash *, unsigned);
+extern int convghash(PyObject *, void *);
+extern int convgmhash(PyObject *, void *);
+
+typedef struct gcmac_pyobj {
+ PyTypeObject ty;
+ gcmac *cm;
+} gcmac_pyobj;
+
+extern PyTypeObject *gcmac_pytype;
+#define GCMAC_PYCHECK(o) PyObject_TypeCheck((o), gcmac_pytype)
+#define GCMAC_CM(o) (((gcmac_pyobj *)(o))->cm)
+#define GCMAC_F(o) (((gcmac_pyobj *)(o))->f)
+extern PyObject *gcmac_pywrap(gcmac *);
+extern int convgcmac(PyObject *, void *);
+
+typedef struct gmac_pyobj {
+ PyTypeObject ty;
+ unsigned f;
+ gmac *m;
+ PyObject *nameobj;
+} gmac_pyobj;
+
+extern PyTypeObject *gmac_pytype;
+#define GMAC_PYCHECK(o) PyObject_TypeCheck((o), gmac_pytype)
+#define GMAC_M(o) (((gmac_pyobj *)(o))->m)
+#define GMAC_NAMEOBJ(o) (((gmac_pyobj *)(o))->nameobj)
+#define GMAC_F(o) (((gmac_pyobj *)(o))->f)
+extern PyObject *gmac_pywrap(PyObject *, gmac *, unsigned);
+extern int convgmac(PyObject *, void *);
+
+/*----- Public key crypto -------------------------------------------------*/
+
+/*----- Key generation ----------------------------------------------------*/
+
+typedef struct pfilt_pyobj {
+ PyObject_HEAD
+ pfilt f;
+ int st;
+} pfilt_pyobj;
+
+extern PyTypeObject *pfilt_pytype;
+#define PFILT_PYCHECK(o) PyObject_TypeCheck(o, pfilt_pytype)
+#define PFILT_F(o) (&((pfilt_pyobj *)(o))->f)
+#define PFILT_ST(o) (((pfilt_pyobj *)(o))->st)
+
+typedef struct { pgen_proc *proc; void *ctx; } pgev;
+#define PGEV_HEAD PyObject_HEAD pgev pg;
+
+typedef struct pgev_pyobj {
+ PGEV_HEAD
+} pgev_pyobj;
+
+extern PyTypeObject *pgev_pytype;
+#define PGEV_PYCHECK(o) PyObject_TypeCheck(o, pgev_pytype)
+#define PGEV_PG(o) (&((pgev_pyobj *)(o))->pg)
+
+extern int convpgev(PyObject *, void *);
+extern void droppgev(pgev *);
+extern void pgenerr(void);
+
+/*----- Core utility functions --------------------------------------------*/
+
+extern PyObject *mexp_common(PyObject *, PyObject *, size_t,
+ PyObject *(*id)(PyObject *),
+ int (*fill)(void *, PyObject *,
+ PyObject *, PyObject *),
+ PyObject *(*exp)(PyObject *, void *, int),
+ void (*drop)(void *));
+
+extern int convulong(PyObject *, void *);
+extern int convu32(PyObject *, void *);
+extern int convmpw(PyObject *, void *);
+extern int convuint(PyObject *, void *);
+extern int convszt(PyObject *, void *);
+extern int convbool(PyObject *, void *);
+extern PyObject *abstract_pynew(PyTypeObject *, PyObject *, PyObject *);
+extern PyObject *getbool(int);
+extern PyObject *getu32(uint32);
+extern void *newtype(PyTypeObject *, const PyTypeObject *);
+extern PyTypeObject *inittype(PyTypeObject *);
+extern void addmethods(const PyMethodDef *);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id$
+ *
+ * Where the fun begins
+ *
+ * (c) 2004 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of the Python interface to Catacomb.
+ *
+ * Catacomb/Python is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb/Python is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Catacomb/Python; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "catacomb-python.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+static void setconstants(PyObject *mod)
+{
+ static const struct { const char *name; unsigned long value; } consts[] = {
+#define C(x) { #x, x }
+ C(FTY_PRIME), C(FTY_BINARY),
+ C(PGEN_PASS), C(PGEN_FAIL), C(PGEN_BEGIN), C(PGEN_TRY), C(PGEN_DONE),
+ C(PGEN_ABORT),
+ C(MPW_MAX),
+ C(PMODE_READ), C(PMODE_VERIFY),
+#undef C
+ { 0 }
+ };
+ int i;
+ PyObject *x;
+
+ for (i = 0; consts[i].name; i++) {
+ if (consts[i].value > LONG_MAX)
+ x = PyLong_FromUnsignedLong(consts[i].value);
+ else
+ x = PyInt_FromLong(consts[i].value);
+ PyModule_AddObject(mod, (/*unconst*/ char *)consts[i].name, x);
+ }
+}
+
+PyObject *getu32(uint32 w)
+{
+ if (w <= 0x7fffffff)
+ return (PyInt_FromLong(w));
+ else
+ return (PyLong_FromUnsignedLong(w));
+}
+
+PyObject *getbool(int b)
+{
+ if (b) RETURN_TRUE;
+ else RETURN_FALSE;
+}
+
+PyObject *abstract_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+{
+ PyErr_SetString(PyExc_TypeError, "can't instantiate this class");
+ return (0);
+}
+
+int convulong(PyObject *o, void *pp)
+{
+ long i;
+ unsigned long *p = pp;
+ PyObject *t;
+
+ if (PyInt_Check(o)) {
+ i = PyInt_AS_LONG(o);
+ if (i < 0) TYERR("must be nonnegative");
+ *p = i;
+ } else {
+ if ((t = PyNumber_Long(o)) == 0) goto end;
+ *p = PyLong_AsUnsignedLong(t);
+ Py_DECREF(t);
+ if (PyErr_Occurred()) goto end;
+ }
+ return (1);
+end:
+ return (0);
+}
+
+int convu32(PyObject *o, void *pp)
+{
+ unsigned long u;
+ uint32 *p = pp;
+
+ if (!convulong(o, &u)) goto end;
+ if (u > 0xffffffff) TYERR("out of range");
+ *p = u;
+ return (1);
+end:
+ return (0);
+}
+
+int convuint(PyObject *o, void *pp)
+{
+ unsigned long u;
+ unsigned *p = pp;
+
+ if (!convulong(o, &u)) goto end;
+ if (u > UINT_MAX) TYERR("out of range");
+ *p = u;
+ return (1);
+end:
+ return (0);
+}
+
+int convmpw(PyObject *o, void *pp)
+{
+ unsigned long u;
+ unsigned *p = pp;
+
+ if (!convulong(o, &u)) goto end;
+ if (u > MPW_MAX) TYERR("out of range");
+ *p = u;
+ return (1);
+end:
+ return (0);
+}
+
+int convszt(PyObject *o, void *pp)
+{
+ unsigned long u;
+ size_t *p = pp;
+
+ if (!convulong(o, &u)) goto end;
+ if (u > ~(size_t)0) TYERR("out of range");
+ *p = u;
+ return (1);
+end:
+ return (0);
+}
+
+int convbool(PyObject *o, void *pp)
+{
+ *(int *)pp = PyObject_IsTrue(o);
+ return (1);
+}
+
+PyObject *mexp_common(PyObject *me, PyObject *arg,
+ size_t efsz,
+ PyObject *(*id)(PyObject *),
+ int (*fill)(void *, PyObject *,
+ PyObject *, PyObject *),
+ PyObject *(*exp)(PyObject *, void *, int),
+ void (*drop)(void *))
+{
+ int i = 0, j, n, flat;
+ PyObject *qq, *x, *y, *z = 0;
+ char *v = 0, *vv;
+
+ if (PyTuple_Size(arg) == 1)
+ arg = PyTuple_GetItem(arg, 0);
+ Py_INCREF(arg);
+ if (!PySequence_Check(arg)) TYERR("not a sequence");
+ n = PySequence_Size(arg); if (!n) { z = id(me); goto end; }
+ x = PySequence_GetItem(arg, 0);
+ if (PySequence_Check(x))
+ flat = 0;
+ else {
+ if (n % 2) VALERR("must have even number of arguments");
+ n /= 2;
+ flat = 1;
+ }
+ Py_DECREF(x);
+
+ v = xmalloc(n * efsz);
+ for (i = j = 0, vv = v; i < n; i++, vv += efsz) {
+ if (flat) {
+ x = PySequence_GetItem(arg, j++);
+ y = PySequence_GetItem(arg, j++);
+ } else {
+ qq = PySequence_GetItem(arg, j++);
+ if (!qq) goto end;
+ if (!PySequence_Check(qq) || PySequence_Size(qq) != 2) {
+ Py_DECREF(qq);
+ TYERR("want a sequence of pairs");
+ }
+ x = PySequence_GetItem(qq, 0);
+ y = PySequence_GetItem(qq, 1);
+ Py_DECREF(qq);
+ }
+ if (!x || !y) goto end;
+ if (fill(vv, me, x, y)) {
+ Py_DECREF(x);
+ Py_DECREF(y);
+ if (!PyErr_Occurred())
+ PyErr_SetString(PyExc_TypeError, "type mismatch");
+ goto end;
+ }
+ Py_DECREF(x);
+ Py_DECREF(y);
+ }
+ z = exp(me, v, n);
+
+end:
+ if (v) {
+ for (j = 0, vv = v; j < i; j++, vv += efsz)
+ drop(vv);
+ xfree(v);
+ }
+ Py_DECREF(arg);
+ return (z);
+}
+
+DA_DECL(method_v, PyMethodDef);
+static method_v global_pymethods = DA_INIT;
+void addmethods(const PyMethodDef *m)
+{
+ size_t n;
+
+ for (n = 0; m[n].ml_name; n++);
+ DA_ENSURE(&global_pymethods, n);
+ memcpy(DA(&global_pymethods) + DA_LEN(&global_pymethods),
+ m, n * sizeof(*m));
+ DA_EXTEND(&global_pymethods, n);
+}
+
+static const PyTypeObject emptytype = { 0 };
+
+void *newtype(PyTypeObject *metaty, const PyTypeObject *skel)
+{
+ PyTypeObject *ty = (PyTypeObject *)_PyObject_GC_Malloc(metaty, 0);
+ if (!skel) skel = &emptytype;
+ memcpy(ty, skel, sizeof(*skel));
+ if (ty->tp_base) Py_INCREF(ty->tp_base);
+ PyObject_INIT(ty, metaty);
+ Py_INCREF(metaty);
+ return (ty);
+}
+
+static PyObject *smallprimes(void)
+{
+ PyObject *v = PyList_New(NPRIME);
+ int i;
+
+ for (i = 0; i < NPRIME; i++)
+ PyList_SetItem(v, i, PyInt_FromLong(primetab[i]));
+ return (v);
+}
+
+PyTypeObject *inittype(PyTypeObject *tyskel)
+{
+ PyTypeObject *ty = newtype(&PyType_Type, tyskel);
+ ty->tp_flags |= Py_TPFLAGS_HEAPTYPE;
+ PyType_Ready(ty);
+ return (ty);
+}
+
+void init_base(void) {
+ static const PyMethodDef mzero = { 0 };
+ PyObject *mod;
+ INIT_MODULES;
+ DA_PUSH(&global_pymethods, mzero);
+ mod = Py_InitModule("catacomb._base", DA(&global_pymethods));
+ INSERT_MODULES;
+ INSERT("smallprimes", smallprimes());
+ setconstants(mod);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+# -*-python-*-
+#
+# $Id$
+#
+# Setup for Catacomb/Python bindings
+#
+# (c) 2004 Straylight/Edgeware
+#
+
+#----- Licensing notice -----------------------------------------------------
+#
+# This file is part of the Python interface to Catacomb.
+#
+# Catacomb/Python is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# Catacomb/Python is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Catacomb/Python; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+import _base
+import types as _types
+from binascii import hexlify as _hexify, unhexlify as _unhexify
+
+def _init():
+ d = globals()
+ b = _base.__dict__;
+ for i in b:
+ if i[0] != '_':
+ d[i] = b[i];
+ for i in ['MP', 'GF', 'Field',
+ 'ECPt', 'ECPtCurve', 'ECCurve', 'ECInfo',
+ 'DHInfo', 'BinDHInfo', 'RSAPriv', 'PrimeFilter', 'RabinMiller',
+ 'Group', 'GE']:
+ c = d[i]
+ pre = '_' + i + '_'
+ plen = len(pre)
+ for j in b:
+ if j[:plen] == pre:
+ setattr(c, j[plen:], classmethod(b[j]))
+ for i in [gcciphers, gchashes, gcmacs]:
+ for j in i:
+ c = i[j]
+ d[c.name.replace('-', '_')] = c
+_init()
+
+def _augment(c, cc):
+ for i in cc.__dict__:
+ a = cc.__dict__[i]
+ if type(a) is _types.MethodType:
+ a = a.im_func
+ elif type(a) not in (_types.FunctionType, staticmethod, classmethod):
+ continue
+ setattr(c, i, a)
+
+class _tmp:
+ def fromhex(x):
+ return ByteString(_unhexify(x))
+ fromhex = staticmethod(fromhex)
+ def __hex__(me):
+ return _hexify(me)
+ def __repr__(me):
+ return 'bytes(%r)' % hex(me)
+_augment(ByteString, _tmp)
+bytes = ByteString.fromhex
+
+class _tmp:
+ def negp(x): return x < 0
+ def posp(x): return x > 0
+ def zerop(x): return x == 0
+ def oddp(x): return x.testbit(0)
+ def evenp(x): return not x.testbit(0)
+ def mont(x): return MPMont(x)
+ def barrett(x): return MPBarrett(x)
+ def reduce(x): return MPReduce(x)
+ def factorial(x):
+ 'factorial(X) -> X!'
+ if x < 0: raise ValueError, 'factorial argument must be > 0'
+ return MP.product(xrange(1, x + 1))
+ factorial = staticmethod(factorial)
+_augment(MP, _tmp)
+
+def _checkend(r):
+ x, rest = r
+ if rest != '':
+ raise SyntaxError, 'junk at end of string'
+ return x
+
+class _tmp:
+ def reduce(x): return GReduce(x)
+_augment(GF, _tmp)
+
+class _tmp:
+ def fromstring(str): return _checkend(Field.parse(str))
+ fromstring = staticmethod(fromstring)
+_augment(Field, _tmp)
+
+class _tmp:
+ def __repr__(me): return '%s(%sL)' % (type(me).__name__, me.p)
+ def ec(me, a, b): return ECPrimeProjCurve(me, a, b)
+_augment(PrimeField, _tmp)
+
+class _tmp:
+ def __repr__(me): return '%s(%sL)' % (type(me).__name__, hex(me.p))
+ def ec(me, a, b): return ECBinProjCurve(me, a, b)
+_augment(BinField, _tmp)
+
+class _tmp:
+ def __str__(me): return str(me.value)
+ def __repr__(me): return '%s(%s)' % (repr(me.field), repr(me.value))
+_augment(FE, _tmp)
+
+class _groupmap (object):
+ def __init__(me, map, nth):
+ me.map = map
+ me.nth = nth
+ me.i = [None] * (max(map.values()) + 1)
+ def __repr__(me):
+ return '{%s}' % ', '.join(['%r: %r' % (k, me[k]) for k in me])
+ def __contains__(me, k):
+ return k in me.map
+ def __getitem__(me, k):
+ i = me.map[k]
+ if me.i[i] is None:
+ me.i[i] = me.nth(i)
+ return me.i[i]
+ def __setitem__(me, k, v):
+ raise TypeError, "immutable object"
+ def __iter__(me):
+ return iter(me.map)
+eccurves = _groupmap(_base._eccurves, ECInfo._curven)
+primegroups = _groupmap(_base._pgroups, DHInfo._groupn)
+bingroups = _groupmap(_base._bingroups, BinDHInfo._groupn)
+
+class _tmp:
+ def __repr__(me):
+ return '%s(%r, %s, %s)' % (type(me).__name__, me.field, me.a, me.b)
+ def frombuf(me, s):
+ return ecpt.frombuf(me, s)
+ def fromraw(me, s):
+ return ecpt.fromraw(me, s)
+ def pt(me, *args):
+ return ECPt(me, *args)
+_augment(ECCurve, _tmp)
+
+class _tmp:
+ def __repr__(me):
+ if not me: return 'ECPt()'
+ return 'ECPt(%s, %s)' % (me.ix, me.iy)
+ def __str__(me):
+ if not me: return 'inf'
+ return '(%s, %s)' % (me.ix, me.iy)
+_augment(ECPt, _tmp)
+
+class _tmp:
+ def __repr__(me):
+ return 'ECInfo(curve = %r, G = %r, r = %s, h = %s)' % \
+ (me.curve, me.G, me.r, me.h)
+ def group(me):
+ return ECGroup(me)
+_augment(ECInfo, _tmp)
+
+class _tmp:
+ def __repr__(me):
+ if not me: return '%r()' % (me.curve)
+ return '%r(%s, %s)' % (me.curve, me.x, me.y)
+ def __str__(me):
+ if not me: return 'inf'
+ return '(%s, %s)' % (me.x, me.y)
+_augment(ECPtCurve, _tmp)
+
+class _tmp:
+ def __repr__(me): return 'KeySZAny(%d)' % me.default
+ def check(me, sz): return True
+ def best(me, sz): return sz
+_augment(KeySZAny, _tmp)
+
+class _tmp:
+ def __repr__(me):
+ return 'KeySZRange(%d, %d, %d, %d)' % \
+ (me.default, me.min, me.max, me.mod)
+ def check(me, sz): return me.min <= sz <= me.max and sz % me.mod == 0
+ def best(me, sz):
+ if sz < me.min: raise ValueError, 'key too small'
+ elif sz > me.max: return me.max
+ else: return sz - (sz % me.mod)
+_augment(KeySZRange, _tmp)
+
+class _tmp:
+ def __repr__(me): return 'KeySZSet(%d, %s)' % (me.default, me.set)
+ def check(me, sz): return sz in me.set
+ def best(me, sz):
+ found = -1
+ for i in me.set:
+ if found < i <= sz: found = i
+ if found < 0: raise ValueError, 'key too small'
+ return found
+_augment(KeySZSet, _tmp)
+
+class _tmp:
+ def __repr__(me):
+ return '%s(p = %s, r = %s, g = %s)' % \
+ (type(me).__name__, me.p, me.r, me.g)
+_augment(FGInfo, _tmp)
+
+class _tmp:
+ def group(me): return PrimeGroup(me)
+_augment(DHInfo, _tmp)
+
+class _tmp:
+ def group(me): return BinGroup(me)
+_augment(BinDHInfo, _tmp)
+
+class _tmp:
+ def __repr__(me):
+ return '%s(%r)' % (type(me).__name__, me.info)
+_augment(Group, _tmp)
+
+class _tmp:
+ def __repr__(me):
+ return '%r(%r)' % (me.group, str(me))
+_augment(GE, _tmp)
+
+class PKCS1Crypt(object):
+ def __init__(me, ep = '', rng = rand):
+ me.ep = ep
+ me.rng = rng
+ def encode(me, msg, nbits):
+ return _base._p1crypt_encode(msg, nbits, me.ep, me.rng)
+ def decode(me, ct, nbits):
+ return _base._p1crypt_decode(ct, nbits, me.ep, me.rng)
+
+class PKCS1Sig(object):
+ def __init__(me, ep = '', rng = rand):
+ me.ep = ep
+ me.rng = rng
+ def encode(me, msg, nbits):
+ return _base._p1sig_encode(msg, nbits, me.ep, me.rng)
+ def decode(me, msg, sig, nbits):
+ return _base._p1sig_decode(msg, sig, nbits, me.ep, me.rng)
+
+class OAEP(object):
+ def __init__(me, mgf = sha_mgf, hash = sha, ep = '', rng = rand):
+ me.mgf = mgf
+ me.hash = hash
+ me.ep = ep
+ me.rng = rng
+ def encode(me, msg, nbits):
+ return _base._oaep_encode(msg, nbits, me.mgf, me.hash, me.ep, me.rng)
+ def decode(me, ct, nbits):
+ return _base._oaep_decode(ct, nbits, me.mgf, me.hash, me.ep, me.rng)
+
+class PSS(object):
+ def __init__(me, mgf = sha_mgf, hash = sha, saltsz = None, rng = rand):
+ me.mgf = mgf
+ me.hash = hash
+ if saltsz is None:
+ saltsz = hash.hashsz
+ me.saltsz = saltsz
+ me.rng = rng
+ def encode(me, msg, nbits):
+ return _base._pss_encode(msg, nbits, me.mgf, me.hash, me.saltsz, me.rng)
+ def decode(me, msg, sig, nbits):
+ return _base._pss_decode(msg, sig, nbits,
+ me.mgf, me.hash, me.saltsz, me.rng)
+
+class _tmp:
+ def encrypt(me, msg, enc):
+ return me.pubop(enc.encode(msg, me.n.nbits))
+ def verify(me, msg, sig, enc):
+ if msg is None: return enc.decode(msg, me.pubop(sig), me.n.nbits)
+ try:
+ x = enc.decode(msg, me.pubop(sig), me.n.nbits)
+ return x is None or x == msg
+ except ValueError:
+ return False
+_augment(RSAPub, _tmp)
+
+class _tmp:
+ def decrypt(me, ct, enc): return enc.decode(me.privop(ct), me.n.nbits)
+ def sign(me, msg, enc): return me.privop(enc.encode(msg, me.n.nbits))
+_augment(RSAPriv, _tmp)
+
+
+class SophieGermainStepJump (object):
+ def pg_begin(me, ev):
+ me.lf = PrimeFilter(ev.x)
+ me.hf = me.lf.muladd(2, 1)
+ return me.cont(ev)
+ def pg_try(me, ev):
+ me.step()
+ return me.cont(ev)
+ def cont(me, ev):
+ while me.lf.status == PGEN_FAIL or me.hf.status == PGEN_FAIL:
+ me.step()
+ if me.lf.status == PGEN_ABORT or me.hf.status == PGEN_ABORT:
+ return PGEN_ABORT
+ ev.x = me.lf.x
+ if me.lf.status == PGEN_DONE and me.hf.status == PGEN_DONE:
+ return PGEN_DONE
+ return PGEN_TRY
+ def pg_done(me, ev):
+ del me.lf
+ del me.hf
+
+class SophieGermainStepper (SophieGermainStepJump):
+ def __init__(me, step):
+ me.lstep = step;
+ me.hstep = 2 * step
+ def step(me):
+ me.lf.step(me.lstep)
+ me.hf.step(me.hstep)
+
+class SophieGermainJumper (SophieGermainStepJump):
+ def __init__(me, jump):
+ me.ljump = PrimeFilter(jump);
+ me.hjump = me.ljump.muladd(2, 0)
+ def step(me):
+ me.lf.jump(me.ljump)
+ me.hf.jump(me.hjump)
+ def pg_done(me, ev):
+ del me.ljump
+ del me.hjump
+ SophieGermainStepJump.pg_done(me, ev)
+
+class SophieGermainTester (object):
+ def __init__(me):
+ pass
+ def pg_begin(me, ev):
+ me.lr = RabinMiller(ev.x)
+ me.hr = RabinMiller(2 * ev.x + 1)
+ def pg_try(me, ev):
+ lst = me.lr.test(ev.rng.range(me.lr.x))
+ if lst != PGEN_PASS and lst != PGEN_DONE:
+ return lst
+ rst = me.hr.test(ev.rng.range(me.hr.x))
+ if rst != PGEN_PASS and rst != PGEN_DONE:
+ return rst
+ if lst == PGEN_DONE and rst == PGEN_DONE:
+ return PGEN_DONE
+ return PGEN_PASS
+ def pg_done(me, ev):
+ del me.lr
+ del me.hr
+
+class PrimeGenEventHandler (object):
+ def pg_begin(me, ev):
+ return me.pg_try(ev)
+ def pg_done(me, ev):
+ return PGEN_DONE
+ def pg_abort(me, ev):
+ return PGEN_TRY
+ def pg_fail(me, ev):
+ return PGEN_TRY
+ def pg_pass(me, ev):
+ return PGEN_TRY
+
+class PrimitiveStepper (PrimeGenEventHandler):
+ def __init__(me):
+ pass
+ def pg_try(me, ev):
+ ev.x = me.i.next()
+ return PGEN_TRY
+ def pg_begin(me, ev):
+ me.i = iter(smallprimes)
+ return me.pg_try(ev)
+
+class PrimitiveTester (PrimeGenEventHandler):
+ def __init__(me, mod, hh = [], exp = None):
+ me.mod = MPMont(mod)
+ me.exp = exp
+ me.hh = hh
+ def pg_try(me, ev):
+ x = ev.x
+ if me.exp is not None:
+ x = me.mod.exp(x, me.exp)
+ if x == 1: return PGEN_FAIL
+ for h in me.hh:
+ if me.mod.exp(x, h) == 1: return PGEN_FAIL
+ ev.x = x
+ return PGEN_DONE
+
+class SimulStepper (PrimeGenEventHandler):
+ def __init__(me, mul = 2, add = 1, step = 2):
+ me.step = step
+ me.mul = mul
+ me.add = add
+ def _stepfn(me, step):
+ if step <= 0:
+ raise ValueError, 'step must be positive'
+ if step <= MPW_MAX:
+ return lambda f: f.step(step)
+ j = PrimeFilter(step)
+ return lambda f: f.jump(j)
+ def pg_begin(me, ev):
+ x = ev.x
+ me.lf = PrimeFilter(x)
+ me.hf = PrimeFilter(x * me.mul + me.add)
+ me.lstep = me._stepfn(me.step)
+ me.hstep = me._stepfn(me.step * me.mul)
+ SimulStepper._cont(me, ev)
+ def pg_try(me, ev):
+ me._step()
+ me._cont(ev)
+ def _step(me):
+ me.lstep(me.lf)
+ me.hstep(me.hf)
+ def _cont(me, ev):
+ while me.lf.status == PGEN_FAIL or me.hf.status == PGEN_FAIL:
+ me._step()
+ if me.lf.status == PGEN_ABORT or me.hf.status == PGEN_ABORT:
+ return PGEN_ABORT
+ ev.x = me.lf.x
+ if me.lf.status == PGEN_DONE and me.hf.status == PGEN_DONE:
+ return PGEN_DONE
+ return PGEN_TRY
+ def pg_done(me, ev):
+ del me.lf
+ del me.hf
+ del me.lstep
+ del me.hstep
+
+class SimulTester (PrimeGenEventHandler):
+ def __init__(me, mul = 2, add = 1):
+ me.mul = mul
+ me.add = add
+ def pg_begin(me, ev):
+ x = ev.x
+ me.lr = RabinMiller(x)
+ me.hr = RabinMiller(x * me.mul + me.add)
+ def pg_try(me, ev):
+ lst = me.lr.test(ev.rng.range(me.lr.x))
+ if lst != PGEN_PASS and lst != PGEN_DONE:
+ return lst
+ rst = me.hr.test(ev.rng.range(me.hr.x))
+ if rst != PGEN_PASS and rst != PGEN_DONE:
+ return rst
+ if lst == PGEN_DONE and rst == PGEN_DONE:
+ return PGEN_DONE
+ return PGEN_PASS
+ def pg_done(me, ev):
+ del me.lr
+ del me.hr
+
+def sgprime(start, step = 2, name = 'p', event = pgen_nullev, nsteps = 0):
+ start = MP(start)
+ return pgen(start, name, SimulStepper(step = step), SimulTester(), event,
+ nsteps, RabinMiller.iters(start.nbits))
+
+def findprimitive(mod, hh = [], exp = None, name = 'g', event = pgen_nullev):
+ return pgen(0, name, PrimitiveStepper(), PrimitiveTester(mod, hh, exp),
+ event, 0, 1)
+
+def kcdsaprime(pbits, qbits, rng = rand,
+ event = pgen_nullev, name = 'p', nsteps = 0):
+ hbits = pbits - qbits
+ h = pgen(rng.mp(hbits, 1), name + ' [h]',
+ PrimeGenStepper(2), PrimeGenTester(),
+ event, nsteps, RabinMiller.iters(hbits))
+ q = pgen(rng.mp(qbits, 1), name, SimulStepper(2 * h, 1, 2),
+ SimulTester(2 * h, 1), event, nsteps, RabinMiller.iters(qbits))
+ p = 2 * q * h + 1
+ return p, q, h
+
+#----- That's all, folks ----------------------------------------------------
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id$
+ *
+ * Elliptic curves
+ *
+ * (c) 2004 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of the Python interface to Catacomb.
+ *
+ * Catacomb/Python is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb/Python is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Catacomb/Python; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "catacomb-python.h"
+
+/*----- Utility functions -------------------------------------------------*/
+
+PyTypeObject *ecpt_pytype;
+PyTypeObject *ecptcurve_pytype;
+PyTypeObject *eccurve_pytype;
+PyTypeObject *ecprimecurve_pytype;
+PyTypeObject *ecprimeprojcurve_pytype;
+PyTypeObject *ecbincurve_pytype;
+PyTypeObject *ecbinprojcurve_pytype;
+PyTypeObject *ecinfo_pytype;
+
+ec_curve *eccurve_copy(ec_curve *c)
+{
+ field *f;
+ mp *a, *b;
+
+ if ((f = field_copy(c->f)) == 0)
+ return (0);
+ a = F_OUT(f, MP_NEW, c->a);
+ b = F_OUT(f, MP_NEW, c->b);
+ if (strcmp(EC_NAME(c), "prime") == 0)
+ c = ec_prime(f, a, b);
+ else if (strcmp(EC_NAME(c), "primeproj") == 0)
+ c = ec_primeproj(f, a, b);
+ else if (strcmp(EC_NAME(c), "bin") == 0)
+ c = ec_bin(f, a, b);
+ else if (strcmp(EC_NAME(c), "binproj") == 0)
+ c = ec_binproj(f, a, b);
+ else
+ c = 0;
+ MP_DROP(a);
+ MP_DROP(b);
+ if (!c) F_DESTROY(f);
+ return (c);
+}
+
+static PyObject *ecpt_dopywrap(PyObject *cobj, ec_curve *c, ec *p)
+{
+ ecpt_pyobj *z = PyObject_New(ecpt_pyobj, (PyTypeObject *)cobj);
+ z->p = *p;
+ z->c = c;
+ Py_INCREF(cobj);
+ return ((PyObject *)z);
+}
+
+PyObject *ecpt_pywrap(PyObject *cobj, ec *p)
+ { return (ecpt_dopywrap(cobj, ECCURVE_C(cobj), p)); }
+
+PyObject *ecpt_pywrapout(void *cobj, ec *p)
+{
+ ec_curve *c;
+
+ if (!PyType_IsSubtype(cobj, ecptcurve_pytype))
+ c = 0;
+ else {
+ c = ECCURVE_C(cobj);
+ EC_IN(ECCURVE_C(cobj), p, p);
+ }
+ return (ecpt_dopywrap(cobj, c, p));
+}
+
+int toecpt(ec_curve *c, ec *d, PyObject *p)
+{
+ if (ECPTCURVE_PYCHECK(p)) {
+ if (ECPT_C(p) != c && !ec_samep(ECPT_C(p), c))
+ return (-1);
+ EC_COPY(d, ECPT_P(p));
+ } else if (ECPT_PYCHECK(p))
+ EC_IN(c, d, ECPT_P(p));
+ else
+ return (-1);
+ return (0);
+}
+
+int getecpt(ec_curve *c, ec *d, PyObject *p)
+{
+ if (toecpt(c, d, p)) {
+ PyErr_Format(PyExc_TypeError, "can't convert %.100s to ecpt",
+ p->ob_type->tp_name);
+ return (-1);
+ }
+ return (0);
+}
+
+void getecptout(ec *d, PyObject *p)
+{
+ if (ECPTCURVE_PYCHECK(p))
+ EC_OUT(ECPT_C(p), d, ECPT_P(p));
+ else {
+ assert(ECPT_PYCHECK(p));
+ EC_COPY(d, ECPT_P(p));
+ }
+}
+
+int convecpt(PyObject *o, void *p)
+{
+ if (!ECPT_PYCHECK(o))
+ TYERR("want elliptic curve point");
+ getecptout(p, o);
+ return (1);
+end:
+ return (0);
+}
+
+/*----- Curve points ------------------------------------------------------*/
+
+static int ecbinop(PyObject *x, PyObject *y,
+ ec_curve **c, PyObject **cobj, ec *xx, ec *yy)
+{
+ if (ECPTCURVE_PYCHECK(x)) *cobj = ECPT_COBJ(x);
+ else if (ECPTCURVE_PYCHECK(y)) *cobj = ECPT_COBJ(y);
+ else return (-1);
+ *c = ECCURVE_C(*cobj);
+ if (toecpt(*c, xx, x) || toecpt(*c, yy, y)) return (-1);
+ return (0);
+}
+
+#define BINOP(name) \
+ static PyObject *ecpt_py##name(PyObject *x, PyObject *y) { \
+ ec xx = EC_INIT, yy = EC_INIT, zz = EC_INIT; \
+ PyObject *cobj; \
+ ec_curve *c; \
+ if (ecbinop(x, y, &c, &cobj, &xx, &yy)) RETURN_NOTIMPL; \
+ c->ops->name(c, &zz, &xx, &yy); \
+ EC_DESTROY(&xx); EC_DESTROY(&yy); \
+ return (ecpt_pywrap(ECPT_COBJ(x), &zz)); \
+ }
+BINOP(add)
+BINOP(sub)
+#undef BINOP
+
+#define UNOP(name) \
+ static PyObject *ecpt_py##name(PyObject *x) { \
+ ec zz = EC_INIT; \
+ ec_curve *c = ECPT_C(x); \
+ c->ops->name(c, &zz, ECPT_P(x)); \
+ return (ecpt_pywrap(ECPT_COBJ(x), &zz)); \
+ }
+UNOP(neg)
+#undef UNOP
+
+static PyObject *ecpt_pyid(PyObject *x) { RETURN_OBJ(x); }
+
+static int ecpt_pynonzerop(PyObject *x) { return (!EC_ATINF(ECPT_P(x))); }
+
+static void ecpt_pydealloc(PyObject *x)
+{
+ EC_DESTROY(ECPT_P(x));
+ Py_DECREF(ECPT_COBJ(x));
+ PyObject_DEL(x);
+}
+
+static PyObject *ecpt_pymul(PyObject *x, PyObject *y)
+{
+ mp *xx;
+ ec zz = EC_INIT;
+
+ if (ECPT_PYCHECK(x)) { PyObject *t; t = x; x = y; y = t; }
+ if (!ECPT_PYCHECK(y) || (xx = tomp(x)) == 0) RETURN_NOTIMPL;
+ ec_imul(ECPT_C(y), &zz, ECPT_P(y), xx);
+ return (ecpt_pywrap(ECPT_COBJ(y), &zz));
+}
+
+static long ecpt_pyhash(PyObject *me)
+{
+ long i;
+ ec p = EC_INIT;
+
+ EC_OUT(ECPT_C(me), &p, ECPT_P(me));
+ i = 0xe0fdd039; /* random perturbance */
+ if (p.x) i ^= mp_tolong(p.x);
+ if (p.y) i ^= mp_tolong(p.y);
+ if (i == -1) i = -2;
+ EC_DESTROY(&p);
+ return (i);
+}
+
+static PyObject *ecpt_pyrichcompare(PyObject *x, PyObject *y, int op)
+{
+ ec_curve *c;
+ PyObject *cobj;
+ ec p = EC_INIT, q = EC_INIT;
+ int b;
+ PyObject *rc = 0;
+
+ if (ecbinop(x, y, &c, &cobj, &p, &q)) RETURN_NOTIMPL;
+ EC_OUT(c, &p, &p);
+ EC_OUT(c, &q, &q);
+ switch (op) {
+ case Py_EQ: b = EC_EQ(&p, &q); break;
+ case Py_NE: b = !EC_EQ(&p, &q); break;
+ default: TYERR("elliptic curve points are unordered");
+ }
+ rc = getbool(b);
+end:
+ EC_DESTROY(&p);
+ EC_DESTROY(&q);
+ return (rc);
+}
+
+static PyObject *epmeth_oncurvep(PyObject *me, PyObject *arg)
+{
+ if (!PyArg_ParseTuple(arg, ":oncurvep")) return (0);
+ return (getbool(!ec_check(ECPT_C(me), ECPT_P(me))));
+}
+
+static PyObject *epmeth_dbl(PyObject *me, PyObject *arg)
+{
+ ec p = EC_INIT;
+ if (!PyArg_ParseTuple(arg, ":dbl")) return (0);
+ EC_DBL(ECPT_C(me), &p, ECPT_P(me));
+ return (ecpt_pywrap(ECPT_COBJ(me), &p));
+}
+
+static PyObject *epmeth_tobuf(PyObject *me, PyObject *arg)
+{
+ buf b;
+ ec p = EC_INIT;
+ PyObject *rc;
+ size_t n;
+
+ if (!PyArg_ParseTuple(arg, ":tobuf")) return (0);
+ getecptout(&p, me);
+ if (EC_ATINF(&p))
+ n = 2;
+ else
+ n = mp_octets(p.x) + mp_octets(p.y) + 4;
+ rc = bytestring_pywrap(0, n);
+ buf_init(&b, PyString_AS_STRING(rc), n);
+ buf_putec(&b, &p);
+ assert(BOK(&b));
+ _PyString_Resize(&rc, BLEN(&b));
+ EC_DESTROY(&p);
+ return (rc);
+}
+
+static PyObject *epmeth_toraw(PyObject *me, PyObject *arg)
+{
+ buf b;
+ PyObject *rc;
+ char *p;
+ ec_curve *c = ECPT_C(me);
+ ec pp = EC_INIT;
+ int len;
+
+ if (!PyArg_ParseTuple(arg, ":toraw")) return (0);
+ len = c->f->noctets * 2 + 1;
+ rc = bytestring_pywrap(0, len);
+ p = PyString_AS_STRING(rc);
+ buf_init(&b, p, len);
+ EC_OUT(c, &pp, ECPT_P(me));
+ ec_putraw(c, &b, &pp);
+ EC_DESTROY(&pp);
+ _PyString_Resize(&rc, BLEN(&b));
+ return (rc);
+}
+
+static PyObject *epget_curve(PyObject *me, void *hunoz)
+ { RETURN_OBJ(ECPT_COBJ(me)); }
+
+static PyObject *epncget_ix(PyObject *me, void *hunoz)
+{
+ ec p = EC_INIT;
+ PyObject *rc;
+ if (EC_ATINF(ECPT_P(me))) RETURN_NONE;
+ getecptout(&p, me);
+ rc = mp_pywrap(MP_COPY(p.x));
+ EC_DESTROY(&p);
+ return (rc);
+}
+
+static PyObject *epncget_iy(PyObject *me, void *hunoz)
+{
+ ec p = EC_INIT;
+ PyObject *rc;
+ if (EC_ATINF(ECPT_P(me))) RETURN_NONE;
+ getecptout(&p, me);
+ rc = mp_pywrap(MP_COPY(p.y));
+ EC_DESTROY(&p);
+ return (rc);
+}
+
+static PyObject *epncget_point(PyObject *me, void *hunoz)
+ { RETURN_ME; }
+
+static PyObject *epget_point(PyObject *me, void *hunoz)
+{
+ ec p = EC_INIT;
+ getecptout(&p, me);
+ return (ecpt_pywrapout(ecpt_pytype, &p));
+}
+
+static PyObject *epget_x(PyObject *me, void *hunoz)
+{
+ ec_curve *c = ECPT_C(me);
+ ec *pp = ECPT_P(me);
+ PyObject *fobj = ECPT_FOBJ(me);
+ ec p = EC_INIT;
+ PyObject *rc;
+
+ if (EC_ATINF(pp)) RETURN_NONE;
+ EC_OUT(c, &p, pp);
+ rc = fe_pywrap(fobj, F_IN(c->f, MP_NEW, p.x));
+ EC_DESTROY(&p);
+ return (rc);
+}
+
+static PyObject *epget_y(PyObject *me, void *hunoz)
+{
+ ec_curve *c = ECPT_C(me);
+ ec *pp = ECPT_P(me);
+ PyObject *fobj = ECPT_FOBJ(me);
+ ec p = EC_INIT;
+ PyObject *rc;
+
+ if (EC_ATINF(pp)) RETURN_NONE;
+ EC_OUT(c, &p, pp);
+ rc = fe_pywrap(fobj, F_IN(c->f, MP_NEW, p.y));
+ EC_DESTROY(&p);
+ return (rc);
+}
+
+static PyObject *epget__x(PyObject *me, void *hunoz)
+{
+ if (EC_ATINF(ECPT_P(me))) RETURN_NONE;
+ return (fe_pywrap(ECPT_FOBJ(me), MP_COPY(ECPT_P(me)->x)));
+}
+
+static PyObject *epget__y(PyObject *me, void *hunoz)
+{
+ if (EC_ATINF(ECPT_P(me))) RETURN_NONE;
+ return (fe_pywrap(ECPT_FOBJ(me), MP_COPY(ECPT_P(me)->y)));
+}
+
+static PyObject *epget__z(PyObject *me, void *hunoz)
+{
+ if (EC_ATINF(ECPT_P(me)) || !ECPT_P(me)->z) RETURN_NONE;
+ return (fe_pywrap(ECPT_FOBJ(me), MP_COPY(ECPT_P(me)->z)));
+}
+
+static mp *coord_in(field *f, PyObject *x)
+{
+ mp *xx;
+ if (FE_PYCHECK(x) && FE_F(x) == f)
+ return (MP_COPY(FE_X(x)));
+ else if ((xx = getmp(x)) == 0)
+ return (0);
+ else
+ return (F_IN(f, xx, xx));
+}
+
+static int ecptxl_3(ec_curve *c, ec *p,
+ PyObject *x, PyObject *y, PyObject *z)
+{
+ int rc = -1;
+
+ if (!x || !y || !z) TYERR("missing argument");
+ if (!c) VALERR("internal form with no curve!");
+ if ((p->x == coord_in(c->f, x)) == 0 ||
+ (p->y == coord_in(c->f, y)) == 0 ||
+ (z != Py_None && (p->z = coord_in(c->f, z))) == 0)
+ goto end;
+ if (!p->z) p->z = MP_COPY(c->f->one); /* just in case */
+ rc = 0;
+end:
+ return (rc);
+}
+
+static int ecptxl_2(ec_curve *c, ec *p, PyObject *x, PyObject *y)
+{
+ int rc = -1;
+
+ if (!x || !y) TYERR("missing argument");
+ if ((p->x = getmp(x)) == 0 ||
+ (p->y = getmp(y)) == 0)
+ goto end;
+ if (c) EC_IN(c, p, p);
+ rc = 0;
+end:
+ return (rc);
+}
+
+static int ecptxl_1(ec_curve *c, ec *p, PyObject *x)
+{
+ int rc = -1;
+ PyObject *y = 0, *z = 0, *t = 0;
+ mp *xx = 0;
+ const void *q;
+ int n;
+ qd_parse qd;
+
+ Py_XINCREF(x);
+ if (!x || x == Py_None)
+ /*cool*/;
+ else if (ECPT_PYCHECK(x)) {
+ getecptout(p, x);
+ goto fix;
+ } else if (PyString_Check(x)) {
+ if (PyObject_AsReadBuffer(x, &q, 0))
+ goto end;
+ qd.p = q;
+ qd.e = 0;
+ if (!ec_ptparse(&qd, p))
+ SYNERR(qd.e);
+ goto fix;
+ } else if (c && (xx = tomp(x)) != 0) {
+ xx = F_IN(c->f, xx, xx);
+ if (!EC_FIND(c, p, xx)) VALERR("not on the curve");
+ } else if (PySequence_Check(x)) {
+ t = x; x = 0;
+ n = PySequence_Size(t);
+ if (n != 2 && (n != 3 || !c))
+ TYERR("want sequence of two or three items");
+ if ((x = PySequence_GetItem(t, 0)) == 0 ||
+ (y = PySequence_GetItem(t, 1)) == 0 ||
+ (n == 3 && (z = PySequence_GetItem(t, 2)) == 0))
+ goto end;
+ rc = (n == 2) ? ecptxl_2(c, p, x, y) : ecptxl_3(c, p, x, y, z);
+ } else
+ TYERR("can't convert to curve point");
+ goto ok;
+
+fix:
+ if (c) EC_IN(c, p, p);
+ok:
+ rc = 0;
+end:
+ Py_XDECREF(x); Py_XDECREF(y); Py_XDECREF(z); Py_XDECREF(t);
+ mp_drop(xx);
+ return (rc);
+}
+
+static int ecptxl(ec_curve *c, ec *p, PyObject *x, PyObject *y, PyObject *z)
+{
+ if (z)
+ return (ecptxl_3(c, p, x, y, z));
+ else if (y)
+ return (ecptxl_2(c, p, x, y));
+ else
+ return (ecptxl_1(c, p, x));
+}
+
+static int ecpt_fromobjects(PyObject *cc, ec *p,
+ PyObject *x, PyObject *y, PyObject *z)
+{
+ ec_curve *c = 0;
+
+ if (cc && PyType_IsSubtype((PyTypeObject *)cc, ecptcurve_pytype))
+ c = ECCURVE_C(cc);
+ return (ecptxl(c, p, x, y, z));
+}
+
+static PyObject *ecptnc_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+{
+ PyObject *x = 0, *y = 0, *z = 0;
+ ec p = EC_INIT;
+ char *kwlist[] = { "x", "y", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|OO:new", kwlist, &x, &y) ||
+ ecptxl(0, &p, x, y, z))
+ goto end;
+ return (ecpt_pywrapout(ty, &p));
+end:
+ EC_DESTROY(&p);
+ return (0);
+}
+
+static PyObject *ecpt_pyint(PyObject *me)
+{
+ ec p = EC_INIT;
+ long l;
+ PyObject *rc = 0;
+ if (EC_ATINF(ECPT_P(me))) VALERR("point at infinity");
+ getecptout(&p, me);
+ if (mp_tolong_checked(p.x, &l)) goto end;
+ rc = PyInt_FromLong(l);
+end:
+ EC_DESTROY(&p);
+ return (rc);
+}
+
+static PyObject *ecpt_pylong(PyObject *me)
+{
+ ec p = EC_INIT;
+ PyObject *rc = 0;
+ if (EC_ATINF(ECPT_P(me))) VALERR("point at infinity");
+ getecptout(&p, me);
+ rc = (PyObject *)mp_topylong(p.x);
+end:
+ EC_DESTROY(&p);
+ return (rc);
+}
+
+static PyObject *ecpt_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+{
+ PyObject *x = 0, *y = 0, *z = 0;
+ ec p = EC_INIT;
+ char *kwlist[] = { "x", "y", "z", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|OOO:new", kwlist,
+ &x, &y, &z) ||
+ ecptxl(ECCURVE_C(ty), &p, x, y, z))
+ goto end;
+ return (ecpt_pywrap((PyObject *)ty, &p));
+end:
+ EC_DESTROY(&p);
+ return (0);
+}
+
+static PyGetSetDef ecptnc_pygetset[] = {
+#define GETSETNAME(op, name) epnc##op##_##name
+ GET (ix, "P.ix -> integer x coordinate of P")
+ GET (iy, "P.iy -> integer y coordinate of P")
+ GET (point, "P.point -> standalone curve point (no-op)")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyMethodDef ecptnc_pymethods[] = {
+#define METHNAME(func) epmeth_##func
+ METH (tobuf, "X.tobuf() -> BIN")
+#undef METHNAME
+ { 0 }
+};
+
+static PyNumberMethods ecpt_pynumber = {
+ 0, /* @nb_add@ */
+ 0, /* @nb_subtract@ */
+ 0, /* @nb_multiply@ */
+ 0, /* @nb_divide@ */
+ 0, /* @nb_remainder@ */
+ 0, /* @nb_divmod@ */
+ 0, /* @nb_power@ */
+ 0, /* @nb_negative@ */
+ 0, /* @nb_positive@ */
+ 0, /* @nb_absolute@ */
+ ecpt_pynonzerop, /* @nb_nonzero@ */
+ 0, /* @nb_invert@ */
+ 0, /* @nb_lshift@ */
+ 0, /* @nb_rshift@ */
+ 0, /* @nb_and@ */
+ 0, /* @nb_xor@ */
+ 0, /* @nb_or@ */
+ 0, /* @nb_coerce@ */
+ ecpt_pyint, /* @nb_int@ */
+ ecpt_pylong, /* @nb_long@ */
+ 0, /* @nb_float@ */
+ 0, /* @nb_oct@ */
+ 0, /* @nb_hex@ */
+
+ 0, /* @nb_inplace_add@ */
+ 0, /* @nb_inplace_subtract@ */
+ 0, /* @nb_inplace_multiply@ */
+ 0, /* @nb_inplace_divide@ */
+ 0, /* @nb_inplace_remainder@ */
+ 0, /* @nb_inplace_power@ */
+ 0, /* @nb_inplace_lshift@ */
+ 0, /* @nb_inplace_rshift@ */
+ 0, /* @nb_inplace_and@ */
+ 0, /* @nb_inplace_xor@ */
+ 0, /* @nb_inplace_or@ */
+
+ 0, /* @nb_floor_divide@ */
+ 0, /* @nb_true_divide@ */
+ 0, /* @nb_inplace_floor_divide@ */
+ 0, /* @nb_inplace_true_divide@ */
+};
+
+static PyTypeObject ecpt_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.ECPt", /* @tp_name@ */
+ sizeof(ecpt_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ ecpt_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ &ecpt_pynumber, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ ecpt_pyhash, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_CHECKTYPES |
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Elliptic curve points, not associated with any curve.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ ecpt_pyrichcompare, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ ecptnc_pymethods, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ ecptnc_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ ecptnc_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyGetSetDef ecpt_pygetset[] = {
+#define GETSETNAME(op, name) ep##op##_##name
+ GET (curve, "P.curve -> elliptic curve containing P")
+ GET (point, "P.point -> standalone curve point")
+ GET (x, "P.x -> Cartesian x coordinate of P")
+ GET (y, "P.y -> Cartesian y coordinate of P")
+ GET (_x, "P._x -> internal x coordinate of P")
+ GET (_y, "P._y -> internal y coordinate of P")
+ GET (_z, "P._z -> internal z coordinate of P, or None")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyMethodDef ecpt_pymethods[] = {
+#define METHNAME(func) epmeth_##func
+ METH (toraw, "X.toraw() -> BIN")
+ METH (dbl, "X.dbl() -> X + X")
+#undef METHNAME
+ { 0 }
+};
+
+static PyNumberMethods ecptcurve_pynumber = {
+ ecpt_pyadd, /* @nb_add@ */
+ ecpt_pysub, /* @nb_subtract@ */
+ ecpt_pymul, /* @nb_multiply@ */
+ 0, /* @nb_divide@ */
+ 0, /* @nb_remainder@ */
+ 0, /* @nb_divmod@ */
+ 0, /* @nb_power@ */
+ ecpt_pyneg, /* @nb_negative@ */
+ ecpt_pyid, /* @nb_positive@ */
+ 0, /* @nb_absolute@ */
+ 0, /* @nb_nonzero@ */
+ 0, /* @nb_invert@ */
+ 0, /* @nb_lshift@ */
+ 0, /* @nb_rshift@ */
+ 0, /* @nb_and@ */
+ 0, /* @nb_xor@ */
+ 0, /* @nb_or@ */
+ 0, /* @nb_coerce@ */
+ 0, /* @nb_int@ */
+ 0, /* @nb_long@ */
+ 0, /* @nb_float@ */
+ 0, /* @nb_oct@ */
+ 0, /* @nb_hex@ */
+
+ 0, /* @nb_inplace_add@ */
+ 0, /* @nb_inplace_subtract@ */
+ 0, /* @nb_inplace_multiply@ */
+ 0, /* @nb_inplace_divide@ */
+ 0, /* @nb_inplace_remainder@ */
+ 0, /* @nb_inplace_power@ */
+ 0, /* @nb_inplace_lshift@ */
+ 0, /* @nb_inplace_rshift@ */
+ 0, /* @nb_inplace_and@ */
+ 0, /* @nb_inplace_xor@ */
+ 0, /* @nb_inplace_or@ */
+
+ 0, /* @nb_floor_divide@ */
+ 0, /* @nb_true_divide@ */
+ 0, /* @nb_inplace_floor_divide@ */
+ 0, /* @nb_inplace_true_divide@ */
+};
+
+static PyTypeObject ecptcurve_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.ECPtCurve", /* @tp_name@ */
+ sizeof(ecpt_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ ecpt_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ &ecptcurve_pynumber, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_CHECKTYPES |
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Elliptic curve points; abstract base class for points on given curves.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ ecpt_pymethods, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ ecpt_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ abstract_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- Elliptic curves themselves ----------------------------------------*/
+
+static PyObject *eccurve_pyrichcompare(PyObject *x, PyObject *y, int op)
+{
+ int b = ec_samep(ECCURVE_C(x), ECCURVE_C(y));
+ switch (op) {
+ case Py_EQ: break;
+ case Py_NE: b = !b;
+ default: TYERR("can't order elliptic curves");
+ }
+ return (getbool(b));
+end:
+ return (0);
+}
+
+static PyObject *ecmmul_id(PyObject *me)
+ { ec p = EC_INIT; return (ecpt_pywrap(me, &p)); }
+
+static int ecmmul_fill(void *pp, PyObject *me, PyObject *x, PyObject *m)
+{
+ ec_mulfactor *f = pp;
+
+ if (getecpt(ECCURVE_C(me), &f->base, x) ||
+ (f->exp = getmp(m)) == 0)
+ return (-1);
+ f->base = *ECPT_P(x);
+ return (0);
+}
+
+static PyObject *ecmmul_exp(PyObject *me, void *pp, int n)
+{
+ ec p = EC_INIT;
+ ec_immul(ECCURVE_C(me), &p, pp, n);
+ return (ecpt_pywrap(me, &p));
+}
+
+static void ecmmul_drop(void *pp)
+{
+ ec_mulfactor *f = pp;
+ EC_DESTROY(&f->base);
+ MP_DROP(f->exp);
+}
+
+static PyObject *ecmeth_mmul(PyObject *me, PyObject *arg)
+{
+ return (mexp_common(me, arg, sizeof(ec_mulfactor),
+ ecmmul_id, ecmmul_fill, ecmmul_exp, ecmmul_drop));
+}
+
+static PyObject *meth__ECPtCurve_fromraw(PyObject *me, PyObject *arg)
+{
+ char *p;
+ int len;
+ buf b;
+ PyObject *rc = 0;
+ ec_curve *cc;
+ ec pp = EC_INIT;
+
+ if (!PyArg_ParseTuple(arg, "Os#:fromraw", &me, &p, &len))
+ return (0);
+ buf_init(&b, p, len);
+ cc = ECCURVE_C(me);
+ if (ec_getraw(cc, &b, &pp))
+ SYNERR("bad point");
+ EC_IN(cc, &pp, &pp);
+ rc = Py_BuildValue("(NN)", ecpt_pywrap(me, &pp), bytestring_pywrapbuf(&b));
+end:
+ return (rc);
+}
+
+static PyObject *meth__ECPt_frombuf(PyObject *me, PyObject *arg)
+{
+ buf b;
+ char *p;
+ int sz;
+ PyObject *rc = 0;
+ ec pp = EC_INIT;
+
+ if (!PyArg_ParseTuple(arg, "Os#:frombuf", &me, &p, &sz)) goto end;
+ buf_init(&b, p, sz);
+ if (buf_getec(&b, &pp)) VALERR("malformed data");
+ rc = Py_BuildValue("(NN)", ecpt_pywrapout(me, &pp),
+ bytestring_pywrapbuf(&b));
+end:
+ return (rc);
+}
+
+static PyObject *meth__ECPt_parse(PyObject *me, PyObject *arg)
+{
+ char *p;
+ qd_parse qd;
+ PyObject *rc = 0;
+ ec pp = EC_INIT;
+
+ if (!PyArg_ParseTuple(arg, "Os:parse", &me, &p)) goto end;
+ qd.p = p;
+ qd.e = 0;
+ if (!ec_ptparse(&qd, &pp)) SYNERR(qd.e);
+ rc = Py_BuildValue("(Ns)", ecpt_pywrapout(me, &pp), qd.p);
+end:
+ return (rc);
+}
+
+static void eccurve_pydealloc(PyObject *me)
+{
+ ec_destroycurve(ECCURVE_C(me));
+ Py_DECREF(ECCURVE_FOBJ(me));
+ PyType_Type.tp_dealloc(me);
+}
+
+static PyObject *ecmeth_find(PyObject *me, PyObject *arg)
+{
+ PyObject *x;
+ mp *xx = 0;
+ ec p = EC_INIT;
+ PyObject *rc = 0;
+
+ if (!PyArg_ParseTuple(arg, "O:find", &x)) goto end;
+ if (FIELD_PYCHECK(x) && FE_F(x) == ECCURVE_C(me)->f)
+ xx = MP_COPY(FE_X(x));
+ else if ((xx = getmp(x)) == 0)
+ goto end;
+ else
+ xx = F_IN(ECCURVE_C(me)->f, xx, xx);
+ if (EC_FIND(ECCURVE_C(me), &p, xx) == 0)
+ VALERR("not on the curve");
+ rc = ecpt_pywrap(me, &p);
+end:
+ if (xx) MP_DROP(xx);
+ return (rc);
+}
+
+static PyObject *ecmeth_rand(PyObject *me, PyObject *arg, PyObject *kw)
+{
+ char *kwlist[] = { "rng", 0 };
+ grand *r = &rand_global;
+ ec p = EC_INIT;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:rand", kwlist,
+ convgrand, &r))
+ return (0);
+ ec_rand(ECCURVE_C(me), &p, r);
+ EC_IN(ECCURVE_C(me), &p, &p);
+ return (ecpt_pywrap(me, &p));
+}
+
+static PyObject *eccurve_dopywrap(PyTypeObject *ty,
+ PyObject *fobj, ec_curve *c)
+{
+ eccurve_pyobj *cobj = newtype(ty, 0);
+ cobj->c = c;
+ cobj->fobj = fobj;
+ cobj->ty.tp_name = (/*unconst*/ char *)c->ops->name;
+ cobj->ty.tp_basicsize = sizeof(ecpt_pyobj);
+ cobj->ty.tp_base = ecptcurve_pytype;
+ Py_INCREF(ecptcurve_pytype);
+ cobj->ty.tp_flags = (Py_TPFLAGS_DEFAULT |
+ Py_TPFLAGS_BASETYPE |
+ Py_TPFLAGS_CHECKTYPES |
+ Py_TPFLAGS_HEAPTYPE);
+ cobj->ty.tp_alloc = PyType_GenericAlloc;
+ cobj->ty.tp_free =_PyObject_Del;
+ cobj->ty.tp_new = ecpt_pynew;
+ PyType_Ready(&cobj->ty);
+ return ((PyObject *)cobj);
+}
+
+PyObject *eccurve_pywrap(PyObject *fobj, ec_curve *c)
+{
+ PyTypeObject *ty;
+
+ if (!fobj)
+ fobj = field_pywrap(c->f);
+ else
+ Py_INCREF(fobj);
+ assert(FIELD_F(fobj) == c->f);
+ if (strcmp(EC_NAME(c), "prime") == 0)
+ ty = ecprimecurve_pytype;
+ else if (strcmp(EC_NAME(c), "primeproj") == 0)
+ ty = ecprimeprojcurve_pytype;
+ else if (strcmp(EC_NAME(c), "bin") == 0)
+ ty = ecbincurve_pytype;
+ else if (strcmp(EC_NAME(c), "binproj") == 0)
+ ty = ecbinprojcurve_pytype;
+ else
+ abort();
+ return (eccurve_dopywrap(ty, fobj, c));
+}
+
+static PyObject *eccurve_pynew(PyTypeObject *ty,
+ ec_curve *(*make)(field *, mp *, mp *),
+ PyObject *arg, PyObject *kw)
+{
+ PyObject *fobj;
+ PyObject *cobj = 0;
+ char *kwlist[] = { "field", "a", "b", 0 };
+ mp *aa = 0, *bb = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!OO", kwlist,
+ field_pytype, &fobj,
+ convmp, &aa, convmp, &bb))
+ goto end;
+ Py_INCREF(fobj);
+ cobj = eccurve_dopywrap(ty, fobj, make(FIELD_F(fobj), aa, bb));
+end:
+ if (aa) MP_DROP(aa);
+ if (bb) MP_DROP(bb);
+ return (cobj);
+}
+
+static PyObject *meth__ECCurve_parse(PyObject *me, PyObject *arg)
+{
+ char *p;
+ qd_parse qd;
+ ec_curve *c;
+ PyObject *rc = 0;
+
+ if (!PyArg_ParseTuple(arg, "Os", &me, &p))
+ goto end;
+ qd.p = p;
+ qd.e = 0;
+ if ((c = ec_curveparse(&qd)) == 0)
+ SYNERR(qd.e);
+ rc = eccurve_pywrap(0, c);
+end:
+ return (rc);
+}
+
+static PyObject *ecget_name(PyObject *me, void *hunoz)
+ { return (PyString_FromString(EC_NAME(ECCURVE_C(me)))); }
+
+static PyObject *ecget_a(PyObject *me, void *hunoz)
+ { return (fe_pywrap(ECCURVE_FOBJ(me), MP_COPY(ECCURVE_C(me)->a))); }
+
+static PyObject *ecget_b(PyObject *me, void *hunoz)
+ { return (fe_pywrap(ECCURVE_FOBJ(me), MP_COPY(ECCURVE_C(me)->b))); }
+
+static PyObject *ecget_field(PyObject *me, void *hunoz)
+ { RETURN_OBJ(ECCURVE_FOBJ(me)); }
+
+static PyObject *ecget_inf(PyObject *me, void *hunoz)
+ { ec inf = EC_INIT; return (ecpt_pywrap(me, &inf)); }
+
+static PyGetSetDef eccurve_pygetset[] = {
+#define GETSETNAME(op, name) ec##op##_##name
+ GET (name, "E.name -> name of this kind of curve")
+ GET (a, "E.a -> first parameter of curve")
+ GET (b, "E.b -> second parameter of curve")
+ GET (field, "E.field -> finite field containing this curve")
+ GET (inf, "E.inf -> point at infinity of this curve")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyMethodDef eccurve_pymethods[] = {
+#define METHNAME(name) ecmeth_##name
+ METH (mmul, "\
+E.mmul([(P0, N0), (P1, N1), ...]) = N0 P0 + N1 P1 + ...")
+ METH (find, "E.find(X) -> P")
+ KWMETH(rand, "E.rand(rng = rand) ->P")
+#undef METHNAME
+ { 0 }
+};
+
+static PyTypeObject eccurve_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.ECCurve", /* @tp_name@ */
+ sizeof(eccurve_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ eccurve_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+ "An elliptic curve. Abstract class.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ eccurve_pyrichcompare, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ eccurve_pymethods, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ eccurve_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ abstract_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyObject *ecprimecurve_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+{
+ return (eccurve_pynew(ty, ec_prime, arg, kw));
+}
+
+static PyTypeObject ecprimecurve_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.ECPrimeCurve", /* @tp_name@ */
+ sizeof(eccurve_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ eccurve_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+ "An elliptic curve over a prime field. Use ecprimeprojcurve.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ eccurve_pyrichcompare, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ 0, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ ecprimecurve_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyObject *ecprimeprojcurve_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+{
+ return (eccurve_pynew(ty, ec_primeproj, arg, kw));
+}
+
+static PyTypeObject ecprimeprojcurve_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.ECPrimeProjCurve", /* @tp_name@ */
+ sizeof(eccurve_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ eccurve_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+ "An elliptic curve over a prime field, using projective coordinates.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ eccurve_pyrichcompare, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ 0, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ ecprimeprojcurve_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyObject *ecbincurve_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+{
+ return (eccurve_pynew(ty, ec_bin, arg, kw));
+}
+
+static PyTypeObject ecbincurve_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.ECBinCurve", /* @tp_name@ */
+ sizeof(eccurve_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ eccurve_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+ "An elliptic curve over a binary field. Use ecbinprojcurve.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ eccurve_pyrichcompare, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ 0, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ ecbincurve_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyObject *ecbinprojcurve_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+{
+ return (eccurve_pynew(ty, ec_binproj, arg, kw));
+}
+
+static PyTypeObject ecbinprojcurve_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.ECBinProjCurve", /* @tp_name@ */
+ sizeof(eccurve_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ eccurve_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+ "An elliptic curve over a binary field, using projective coordinates.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ eccurve_pyrichcompare, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ 0, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ ecbinprojcurve_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- Curve info --------------------------------------------------------*/
+
+static int ncurves = -1;
+
+void ecinfo_copy(ec_info *eic, const ec_info *ei)
+{
+ eic->c = eccurve_copy(ei->c);
+ EC_CREATE(&eic->g);
+ EC_COPY(&eic->g, &ei->g);
+ eic->r = MP_COPY(ei->r);
+ eic->h = MP_COPY(ei->h);
+}
+
+PyObject *ecinfo_pywrap(ec_info *ei)
+{
+ ecinfo_pyobj *o;
+
+ o = PyObject_NEW(ecinfo_pyobj, ecinfo_pytype);
+ o->ei = *ei;
+ o->cobj = eccurve_pywrap(0, o->ei.c);
+ Py_INCREF(o->cobj);
+ return ((PyObject *)o);
+}
+
+static void ecinfo_pydealloc(PyObject *me)
+{
+ ec_info *ei = ECINFO_EI(me);
+ EC_DESTROY(&ei->g);
+ MP_DROP(ei->r);
+ MP_DROP(ei->h);
+ Py_DECREF(ECINFO_COBJ(me));
+ PyObject_DEL(me);
+}
+
+static PyObject *ecinfo_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+{
+ ec_info ei = { 0 };
+ PyObject *e, *g;
+ char *kwlist[] = { "curve", "G", "r", "h", 0 };
+ ecinfo_pyobj *rc = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O!O&O&:new", kwlist,
+ eccurve_pytype, &e, ecpt_pytype, &g,
+ convmp, &ei.r, convmp, &ei.h))
+ goto end;
+ if (ECPT_C(g) != ECCURVE_C(e) && !ec_samep(ECPT_C(g), ECCURVE_C(e)))
+ TYERR("point not from this curve");
+ ei.c = ECCURVE_C(e);
+ EC_CREATE(&ei.g);
+ EC_COPY(&ei.g, ECPT_P(g));
+ rc = (ecinfo_pyobj *)ty->tp_alloc(ty, 0);
+ rc->ei = ei;
+ rc->cobj = e;
+ Py_INCREF(rc->cobj);
+ return ((PyObject *)rc);
+
+end:
+ mp_drop(ei.r);
+ mp_drop(ei.h);
+ return (0);
+}
+
+static PyObject *meth__ECInfo_parse(PyObject *me, PyObject *arg)
+{
+ char *p;
+ qd_parse qd;
+ ec_info ei;
+ PyObject *rc = 0;
+
+ if (!PyArg_ParseTuple(arg, "Os:parse", &me, &p))
+ goto end;
+ qd.p = p;
+ qd.e = 0;
+ if (ec_infoparse(&qd, &ei))
+ SYNERR(qd.e);
+ rc = Py_BuildValue("(Ns)", ecinfo_pywrap(&ei), qd.p);
+end:
+ return (rc);
+}
+
+static PyObject *meth__ECInfo__curven(PyObject *me, PyObject *arg)
+{
+ int i;
+ ec_info ei;
+ PyObject *rc = 0;
+
+ if (!PyArg_ParseTuple(arg, "Oi:_curven", &me, &i)) goto end;
+ if (i < 0 || i >= ncurves) VALERR("curve index out of range");
+ ec_infofromdata(&ei, ectab[i].data);
+ rc = ecinfo_pywrap(&ei);
+end:
+ return (rc);
+}
+
+static PyObject *ecinfo_pyrichcompare(PyObject *x, PyObject *y, int op)
+{
+ int b = ec_sameinfop(ECINFO_EI(x), ECINFO_EI(y));
+ switch (op) {
+ case Py_EQ: break;
+ case Py_NE: b = !b;
+ default: TYERR("can't order elliptic curve infos");
+ }
+ return (getbool(b));
+end:
+ return (0);
+}
+
+static PyObject *eimeth_check(PyObject *me, PyObject *arg, PyObject *kw)
+{
+ char *kwlist[] = { "rng", 0 };
+ grand *r = &rand_global;
+ const char *p;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:check", kwlist,
+ convgrand, &r))
+ goto end;
+ if ((p = ec_checkinfo(ECINFO_EI(me), r)) != 0)
+ VALERR(p);
+ RETURN_ME;
+end:
+ return (0);
+}
+
+static PyObject *eiget_curve(PyObject *me, void *hunoz)
+ { RETURN_OBJ(ECINFO_COBJ(me)); }
+
+static PyObject *eiget_G(PyObject *me, void *hunoz)
+{
+ ec_info *ei = ECINFO_EI(me);
+ ec p = EC_INIT;
+ EC_IN(ei->c, &p, &ei->g);
+ return (ecpt_pywrap(ECINFO_COBJ(me), &p));
+}
+
+static PyObject *eiget_r(PyObject *me, void *hunoz)
+ { return (mp_pywrap(MP_COPY(ECINFO_EI(me)->r))); }
+
+static PyObject *eiget_h(PyObject *me, void *hunoz)
+ { return (mp_pywrap(MP_COPY(ECINFO_EI(me)->h))); }
+
+static PyGetSetDef ecinfo_pygetset[] = {
+#define GETSETNAME(op, name) ei##op##_##name
+ GET (curve, "I.curve -> the elliptic curve")
+ GET (G, "I.G -> generator point for the group")
+ GET (r, "I.r -> order of the group (and hence of G")
+ GET (h, "I.h -> cofactor of the group")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyMethodDef ecinfo_pymethods[] = {
+#define METHNAME(name) eimeth_##name
+ KWMETH(check, "I.check() -> None")
+#undef METHNAME
+ { 0 }
+};
+
+static PyTypeObject ecinfo_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.ECInfo", /* @tp_name@ */
+ sizeof(ecinfo_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ ecinfo_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+ "Elliptic curve domain parameters.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ ecinfo_pyrichcompare, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ ecinfo_pymethods, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ ecinfo_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ ecinfo_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- Setup -------------------------------------------------------------*/
+
+static PyMethodDef methods[] = {
+#define METHNAME(func) meth_##func
+ METH (_ECPt_frombuf, "frombuf(E, STR) -> (P, REST)")
+ METH (_ECPtCurve_fromraw, "fromraw(E, STR) -> (P, REST)")
+ METH (_ECPt_parse, "parse(E, STR) -> (P, REST)")
+ METH (_ECCurve_parse, "parse(STR) -> (E, REST)")
+ METH (_ECInfo_parse, "parse(STR) -> (I, REST)")
+ METH (_ECInfo__curven, "_curven(N) -> I")
+#undef METHNAME
+ { 0 }
+};
+
+void ec_pyinit(void)
+{
+ INITTYPE(ecpt, root);
+ INITTYPE(ecptcurve, ecpt);
+ INITTYPE(eccurve, type);
+ INITTYPE(ecprimecurve, eccurve);
+ INITTYPE(ecprimeprojcurve, ecprimecurve);
+ INITTYPE(ecbincurve, eccurve);
+ INITTYPE(ecbinprojcurve, ecbincurve);
+ INITTYPE(ecinfo, root);
+ addmethods(methods);
+}
+
+static PyObject *namedcurves(void)
+{
+ int i, j;
+ const char *p;
+ PyObject *d, *c;
+
+ d = PyDict_New();
+ for (i = 0; ectab[i].name; i++) {
+ p = ectab[i].name;
+ for (j = 0; j < i; j++) {
+ if (ectab[i].data == ectab[j].data) {
+ c = PyDict_GetItemString(d, (/*unconst*/ char *)ectab[j].name);
+ Py_INCREF(c);
+ goto found;
+ }
+ }
+ c = PyInt_FromLong(i);
+ found:
+ PyDict_SetItemString(d, (/*unconst*/ char *)ectab[i].name, c);
+ Py_DECREF(c);
+ }
+ ncurves = i;
+ return (d);
+}
+
+void ec_pyinsert(PyObject *mod)
+{
+ INSERT("ECPt", ecpt_pytype);
+ INSERT("ECPtCurve", ecptcurve_pytype);
+ INSERT("ECCurve", eccurve_pytype);
+ INSERT("ECPrimeCurve", ecprimecurve_pytype);
+ INSERT("ECPrimeProjCurve", ecprimeprojcurve_pytype);
+ INSERT("ECBinCurve", ecbincurve_pytype);
+ INSERT("ECBinProjCurve", ecbinprojcurve_pytype);
+ INSERT("ECInfo", ecinfo_pytype);
+ INSERT("_eccurves", namedcurves());
+}
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id$
+ *
+ * Abstract fields
+ *
+ * (c) 2004 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of the Python interface to Catacomb.
+ *
+ * Catacomb/Python is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb/Python is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Catacomb/Python; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "catacomb-python.h"
+
+/*----- Various utilities -------------------------------------------------*/
+
+PyTypeObject *field_pytype;
+PyTypeObject *primefield_pytype;
+PyTypeObject *niceprimefield_pytype;
+PyTypeObject *binfield_pytype;
+PyTypeObject *binpolyfield_pytype;
+PyTypeObject *binnormfield_pytype;
+PyTypeObject *fe_pytype;
+
+static PyObject *fe_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+{
+ PyObject *x;
+ mp *z;
+ char *kwlist[] = { "x", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O:fe", kwlist, &x))
+ return (0);
+ if (FE_PYCHECK(x) && FE_F(x) == FIELD_F(ty)) RETURN_OBJ(x);
+ if ((z = getmp(x)) == 0) return (0);
+ z = F_IN(FIELD_F(ty), z, z);
+ return (fe_pywrap((PyObject *)ty, z));
+}
+
+static PyObject *field_dopywrap(PyTypeObject *ty, field *f)
+{
+ field_pyobj *fobj = newtype(ty, 0);
+ fobj->f = f;
+ fobj->ty.tp_name = (/*unconst*/ char *)f->ops->name;
+ fobj->ty.tp_basicsize = sizeof(fe_pyobj);
+ fobj->ty.tp_base = fe_pytype;
+ Py_INCREF(fe_pytype);
+ fobj->ty.tp_flags = (Py_TPFLAGS_DEFAULT |
+ Py_TPFLAGS_BASETYPE |
+ Py_TPFLAGS_CHECKTYPES |
+ Py_TPFLAGS_HEAPTYPE);
+ fobj->ty.tp_alloc = PyType_GenericAlloc;
+ fobj->ty.tp_free = _PyObject_Del;
+ fobj->ty.tp_new = fe_pynew;
+ PyType_Ready(&fobj->ty);
+ return ((PyObject *)fobj);
+}
+
+PyObject *field_pywrap(field *f)
+{
+ PyTypeObject *ty;
+
+ if (strcmp(F_NAME(f), "prime") == 0) ty = primefield_pytype;
+ else if (strcmp(F_NAME(f), "niceprime") == 0) ty = niceprimefield_pytype;
+ else if (strcmp(F_NAME(f), "binpoly") == 0) ty = binpolyfield_pytype;
+ else if (strcmp(F_NAME(f), "binnorm") == 0) ty = binnormfield_pytype;
+ else abort();
+ return (field_dopywrap(ty, f));
+}
+
+field *field_copy(field *f)
+{
+ if (strcmp(F_NAME(f), "prime") == 0)
+ f = field_prime(f->m);
+ else if (strcmp(F_NAME(f), "niceprime") == 0)
+ f = field_niceprime(f->m);
+ else if (strcmp(F_NAME(f), "binpoly") == 0)
+ f = field_binpoly(f->m);
+ else if (strcmp(F_NAME(f), "binnorm") == 0) {
+ fctx_binnorm *fc = (fctx_binnorm *)f;
+ f = field_binnorm(f->m, fc->ntop.r[fc->ntop.n - 1]);
+ } else
+ abort();
+ return (f);
+}
+
+PyObject *fe_pywrap(PyObject *fobj, mp *x)
+{
+ fe_pyobj *z = PyObject_New(fe_pyobj, (PyTypeObject *)fobj);
+ z->f = FIELD_F(fobj);
+ Py_INCREF(fobj);
+ z->x = x;
+ return ((PyObject *)z);
+}
+
+static mp *tofe(field *f, PyObject *o)
+{
+ mp *x = 0, *y = 0;
+
+ if (FE_PYCHECK(o)) {
+ if (FE_F(o) != f && !field_samep(FE_F(o), f)) return (0);
+ y = FE_X(o);
+ }
+ if ((x = tomp(o)) != 0) {
+ if (MP_ZEROP(x))
+ y = f->zero;
+ else if (MP_EQ(x, MP_ONE))
+ y = f->one;
+ }
+ if (x) MP_DROP(x);
+ if (y) MP_COPY(y);
+ return (y);
+}
+
+mp *getfe(field *f, PyObject *o)
+{
+ mp *x = 0;
+ if ((x = tofe(f, o)) == 0) {
+ PyErr_Format(PyExc_TypeError, "can't convert %.100s to fe",
+ o->ob_type->tp_name);
+ }
+ return (x);
+}
+
+/*----- Field elements ----------------------------------------------------*/
+
+static int febinop(PyObject *x, PyObject *y,
+ field **f, PyObject **fobj, mp **xx, mp **yy)
+{
+ if (FE_PYCHECK(x)) *fobj = FE_FOBJ(x);
+ else if (FE_PYCHECK(y)) *fobj = FE_FOBJ(y);
+ else return (-1);
+ *f = FIELD_F(*fobj);
+ if ((*xx = tofe(*f, x)) == 0)
+ return (-1);
+ if ((*yy = tofe(*f, y)) == 0) {
+ MP_DROP(*xx);
+ return (-1);
+ }
+ return (0);
+}
+
+#define BINOP(name) \
+ static PyObject *fe_py##name(PyObject *x, PyObject *y) { \
+ PyObject *fobj; \
+ field *ff; \
+ mp *xx, *yy, *zz; \
+ if (febinop(x, y, &ff, &fobj, &xx, &yy)) RETURN_NOTIMPL; \
+ zz = ff->ops->name(ff, MP_NEW, xx, yy); \
+ MP_DROP(xx); MP_DROP(yy); \
+ return (fe_pywrap(fobj, zz)); \
+ }
+BINOP(add)
+BINOP(sub)
+BINOP(mul)
+#undef BINOP
+
+static PyObject *fe_pydiv(PyObject *x, PyObject *y)
+{
+ PyObject *fobj;
+ field *ff;
+ mp *xx, *yy;
+ PyObject *z = 0;
+ if (febinop(x, y, &ff, &fobj, &xx, &yy)) RETURN_NOTIMPL;
+ if (F_ZEROP(ff, yy)) ZDIVERR("division by zero");
+ yy = F_INV(ff, yy, yy);
+ z = fe_pywrap(fobj, F_MUL(ff, MP_NEW, xx, yy));
+end:
+ MP_DROP(xx); MP_DROP(yy);
+ return (z);
+}
+
+static PyObject *fe_pyexp(PyObject *x, PyObject *y, PyObject *z)
+{
+ field *ff;
+ mp *xx, *yy;
+
+ if (z != Py_None || !FE_PYCHECK(x) || (yy = tomp(y)) == 0)
+ RETURN_NOTIMPL;
+ ff = FE_F(x); xx = FE_X(x); MP_COPY(xx);
+ if (MP_NEGP(yy) && F_ZEROP(ff, xx)) ZDIVERR("division by zero");
+ z = fe_pywrap(FE_FOBJ(x), field_exp(ff, MP_NEW, xx, yy));
+end:
+ MP_DROP(xx); MP_DROP(yy);
+ return (z);
+}
+
+static PyObject *fe_pyneg(PyObject *x)
+{
+ return fe_pywrap(FE_FOBJ(x), FE_F(x)->ops->neg(FE_F(x), MP_NEW, FE_X(x)));
+}
+
+static PyObject *fe_pyid(PyObject *x) { RETURN_OBJ(x); }
+
+static int fe_pynonzerop(PyObject *x) { return !F_ZEROP(FE_F(x), FE_X(x)); }
+
+static PyObject *fe_pyrichcompare(PyObject *x, PyObject *y, int op)
+{
+ PyObject *fobj;
+ field *ff;
+ mp *xx, *yy;
+ int b;
+ PyObject *rc = 0;
+
+ if (febinop(x, y, &ff, &fobj, &xx, &yy)) RETURN_NOTIMPL;
+ switch (op) {
+ case Py_EQ: b = MP_EQ(xx, yy); break;
+ case Py_NE: b = !MP_EQ(xx, yy); break;
+ default: TYERR("field elements are unordered");
+ }
+ rc = getbool(b);
+end:
+ MP_DROP(xx); MP_DROP(yy);
+ return (rc);
+}
+
+static long fe_pyhash(PyObject *me)
+{
+ long i = mp_tolong(FE_X(me));
+ i ^= 0xdcf62d6c; /* random perturbance */
+ if (i == -1)
+ i = -2;
+ return (i);
+}
+
+static int fe_pycoerce(PyObject **x, PyObject **y)
+{
+ mp *z;
+
+ if (FE_PYCHECK(*y)) {
+ if (FE_F(*x) != FE_F(*y) && !field_samep(FE_F(*x), FE_F(*y)))
+ TYERR("field mismatch");
+ Py_INCREF(*x); Py_INCREF(*y);
+ return (0);
+ }
+ if ((z = tofe(FE_F(*x), *y)) != 0) {
+ Py_INCREF(*x);
+ *y = fe_pywrap(FE_FOBJ(*x), z);
+ return (0);
+ }
+ return (1);
+
+end:
+ return (-1);
+}
+
+static PyObject *fe_pyint(PyObject *x)
+{
+ long l;
+ mp *xx = F_OUT(FE_F(x), MP_NEW, FE_X(x));
+ if (mp_tolong_checked(xx, &l)) { MP_DROP(xx); return (0); }
+ MP_DROP(xx);
+ return (PyInt_FromLong(l));
+}
+
+static PyObject *fe_pylong(PyObject *x)
+{
+ mp *xx = F_OUT(FE_F(x), MP_NEW, FE_X(x));
+ PyObject *rc = (PyObject *)mp_topylong(xx);
+ MP_DROP(xx);
+ return (rc);
+}
+
+#define BASEOP(name, radix, pre) \
+ static PyObject *fe_py##name(PyObject *x) { \
+ mp *xx = F_OUT(FE_F(x), MP_NEW, FE_X(x)); \
+ PyObject *rc = mp_topystring(FE_X(x), radix, 0, pre, 0); \
+ MP_DROP(xx); \
+ return (rc); \
+ }
+BASEOP(oct, 8, "0");
+BASEOP(hex, 16, "0x");
+#undef BASEOP
+
+static void fe_pydealloc(PyObject *me)
+{
+ Py_DECREF(FE_FOBJ(me));
+ MP_DROP(FE_X(me));
+ PyObject_DEL(me);
+}
+
+#define UNOP(name, check) \
+ static PyObject *femeth_##name(PyObject *me, PyObject *arg) { \
+ field *f = FE_F(me); \
+ mp *x = FE_X(me); \
+ if (!PyArg_ParseTuple(arg, ":" #name)) return (0); \
+ if (!f->ops->name) TYERR(#name " not supported for this field"); \
+ check \
+ x = f->ops->name(f, MP_NEW, x); \
+ if (!x) RETURN_NONE; \
+ return (fe_pywrap(FE_FOBJ(me), x)); \
+ end: \
+ return (0); \
+ }
+UNOP(inv, if (F_ZEROP(f, x)) ZDIVERR("division by zero"); )
+UNOP(sqr, ; )
+UNOP(sqrt, ; )
+UNOP(quadsolve, ; )
+UNOP(dbl, ; )
+UNOP(tpl, ; )
+UNOP(qdl, ; )
+UNOP(hlv, ; )
+#undef UNOP
+
+static PyObject *feget_field(PyObject *me, void *hunoz)
+ { RETURN_OBJ(FE_FOBJ(me)); }
+
+static PyObject *feget_value(PyObject *me, void *hunoz)
+{
+ mp *x = F_OUT(FE_F(me), MP_NEW, FE_X(me));
+ if (F_TYPE(FE_F(me)) == FTY_BINARY)
+ return (gf_pywrap(x));
+ else
+ return (mp_pywrap(x));
+}
+
+static PyObject *feget__value(PyObject *me, void *hunoz)
+{
+ mp *x = FE_X(me);
+ MP_COPY(x);
+ if (F_TYPE(FE_F(me)) == FTY_BINARY)
+ return (gf_pywrap(x));
+ else
+ return (mp_pywrap(x));
+}
+
+static PyGetSetDef fe_pygetset[] = {
+#define GETSETNAME(op, name) fe##op##_##name
+ GET (field, "X.field -> field containing X")
+ GET (value, "X.value -> `natural' integer representation of X")
+ GET (_value, "X._value -> internal integer representation of X")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyMethodDef fe_pymethods[] = {
+#define METHNAME(func) femeth_##func
+ METH (inv, "X.inv() -> X^{-1}")
+ METH (sqr, "X.sqr() -> X^2")
+ METH (sqrt, "X.sqrt() -> sqrt(X)")
+ METH (quadsolve, "X.quadsolve() -> Y where Y^2 + Y = X (binary only)")
+ METH (dbl, "X.dbl() -> 2 * X (prime only)")
+ METH (tpl, "X.tpl() -> 3 * X (prime only)")
+ METH (qdl, "X.qdl() -> 4 * X (prime only)")
+ METH (hlv, "X.hlv() -> X/2 (prime only)")
+#undef METHNAME
+ { 0 }
+};
+
+static PyNumberMethods fe_pynumber = {
+ fe_pyadd, /* @nb_add@ */
+ fe_pysub, /* @nb_subtract@ */
+ fe_pymul, /* @nb_multiply@ */
+ fe_pydiv, /* @nb_divide@ */
+ 0, /* @nb_remainder@ */
+ 0, /* @nb_divmod@ */
+ fe_pyexp, /* @nb_power@ */
+ fe_pyneg, /* @nb_negative@ */
+ fe_pyid, /* @nb_positive@ */
+ 0, /* @nb_absolute@ */
+ fe_pynonzerop, /* @nb_nonzero@ */
+ 0, /* @nb_invert@ */
+ 0, /* @nb_lshift@ */
+ 0, /* @nb_rshift@ */
+ 0, /* @nb_and@ */
+ 0, /* @nb_xor@ */
+ 0, /* @nb_or@ */
+ fe_pycoerce, /* @nb_coerce@ */
+ fe_pyint, /* @nb_int@ */
+ fe_pylong, /* @nb_long@ */
+ 0 /* meaningless */, /* @nb_float@ */
+ fe_pyoct, /* @nb_oct@ */
+ fe_pyhex, /* @nb_hex@ */
+
+ 0, /* @nb_inplace_add@ */
+ 0, /* @nb_inplace_subtract@ */
+ 0, /* @nb_inplace_multiply@ */
+ 0, /* @nb_inplace_divide@ */
+ 0, /* @nb_inplace_remainder@ */
+ 0, /* @nb_inplace_power@ */
+ 0, /* @nb_inplace_lshift@ */
+ 0, /* @nb_inplace_rshift@ */
+ 0, /* @nb_inplace_and@ */
+ 0, /* @nb_inplace_xor@ */
+ 0, /* @nb_inplace_or@ */
+
+ 0, /* @nb_floor_divide@ */
+ fe_pydiv, /* @nb_true_divide@ */
+ 0, /* @nb_inplace_floor_divide@ */
+ 0, /* @nb_inplace_true_divide@ */
+};
+
+static PyTypeObject fe_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.FE", /* @tp_name@ */
+ sizeof(fe_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ fe_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ &fe_pynumber, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ fe_pyhash, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ fe_pyhex, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_CHECKTYPES |
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Finite field elements, abstract base class.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ fe_pyrichcompare, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ fe_pymethods, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ fe_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ abstract_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- Fields ------------------------------------------------------------*/
+
+static PyObject *field_pyrichcompare(PyObject *x, PyObject *y, int op)
+{
+ int b = field_samep(FIELD_F(x), FIELD_F(y));
+ switch (op) {
+ case Py_EQ: break;
+ case Py_NE: b = !b;
+ default: TYERR("can't order fields");
+ }
+ return (getbool(b));
+end:
+ return (0);
+}
+
+static PyObject *fmeth_rand(PyObject *me, PyObject *arg, PyObject *kw)
+{
+ char *kwlist[] = { "rng", 0 };
+ grand *r = &rand_global;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:rand", kwlist,
+ convgrand, &r))
+ return (0);
+ return (fe_pywrap(me, F_RAND(FIELD_F(me), MP_NEW, r)));
+}
+
+static PyObject *fmeth__adopt(PyObject *me, PyObject *arg)
+{
+ mp *xx;
+ if (!PyArg_ParseTuple(arg, "O&:_adopt", convmp, &xx)) return (0);
+ return (fe_pywrap(me, xx));
+}
+
+static void field_pydealloc(PyObject *me)
+{
+ F_DESTROY(FIELD_F(me));
+ PyType_Type.tp_dealloc(me);
+}
+
+static PyObject *fget_zero(PyObject *me, void *hunoz)
+ { return (fe_pywrap(me, MP_COPY(FIELD_F(me)->zero))); }
+
+static PyObject *fget_one(PyObject *me, void *hunoz)
+ { return (fe_pywrap(me, MP_COPY(FIELD_F(me)->one))); }
+
+static PyObject *fget_q(PyObject *me, void *hunoz)
+ { return (mp_pywrap(MP_COPY(FIELD_F(me)->q))); }
+
+static PyObject *fget_nbits(PyObject *me, void *hunoz)
+ { return (PyInt_FromLong(FIELD_F(me)->nbits)); }
+
+static PyObject *fget_noctets(PyObject *me, void *hunoz)
+ { return (PyInt_FromLong(FIELD_F(me)->noctets)); }
+
+static PyObject *fget_name(PyObject *me, void *hunoz)
+ { return (PyString_FromString(F_NAME(FIELD_F(me)))); }
+
+static PyObject *fget_type(PyObject *me, void *hunoz)
+ { return (PyInt_FromLong(F_TYPE(FIELD_F(me)))); }
+
+static PyGetSetDef field_pygetset[] = {
+#define GETSETNAME(op, name) f##op##_##name
+ GET (zero, "F.zero -> field additive identity")
+ GET (one, "F.one -> field multiplicative identity")
+ GET (q, "F.q -> number of elements in field")
+ GET (nbits, "F.nbits -> bits needed to represent element")
+ GET (noctets, "F.noctets -> octetss needed to represent element")
+ GET (name, "F.name -> name of this kind of field")
+ GET (type, "F.type -> type code of this kind of field")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyMethodDef field_pymethods[] = {
+#define METHNAME(name) fmeth_##name
+ METH (_adopt, "F._adopt(X) -> FE")
+ KWMETH(rand, "F.rand(rng = rand) -> FE, uniformly distributed")
+#undef METHNAME
+ { 0 }
+};
+
+static PyTypeObject field_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.Field", /* @tp_name@ */
+ sizeof(field_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ field_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"An abstract field. This is an abstract type.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ field_pyrichcompare, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ field_pymethods, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ field_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ abstract_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- Prime fields ------------------------------------------------------*/
+
+static PyObject *primefield_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+{
+ mp *xx = 0;
+ field *f;
+ char *kwlist[] = { "p", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O:primefield", kwlist,
+ convmp, &xx))
+ goto end;
+ if ((f = field_prime(xx)) == 0)
+ VALERR("bad prime for primefield");
+ MP_DROP(xx);
+ return (field_dopywrap(ty, f));
+end:
+ mp_drop(xx);
+ return (0);
+}
+
+static PyObject *pfget_p(PyObject *me, void *hunoz)
+ { return (mp_pywrap(MP_COPY(FIELD_F(me)->m))); }
+
+static PyGetSetDef primefield_pygetset[] = {
+#define GETSETNAME(op, name) pf##op##_##name
+ GET (p, "F.p -> prime field characteristic")
+#undef GETSETNAME
+};
+
+static PyTypeObject primefield_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.PrimeField", /* @tp_name@ */
+ sizeof(field_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ field_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+ "Prime fields.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ field_pyrichcompare, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ primefield_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ primefield_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyObject *niceprimefield_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+{
+ mp *xx = 0;
+ field *f;
+ char *kwlist[] = { "p", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:niceprimefield",
+ kwlist, convmp, &xx))
+ goto end;
+ if ((f = field_niceprime(xx)) == 0)
+ VALERR("bad prime for niceprimefield");
+ MP_DROP(xx);
+ return (field_dopywrap(ty, f));
+end:
+ mp_drop(xx);
+ return (0);
+}
+
+static PyTypeObject niceprimefield_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.NicePrimeField", /* @tp_name@ */
+ sizeof(field_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ field_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+ "Nice prime fields.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ field_pyrichcompare, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ 0, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ niceprimefield_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- Binary fields -----------------------------------------------------*/
+
+static PyObject *bfget_m(PyObject *me, void *hunoz)
+ { return (PyInt_FromLong(FIELD_F(me)->nbits)); }
+
+static PyGetSetDef binfield_pygetset[] = {
+#define GETSETNAME(op, name) bf##op##_##name
+ GET (m, "F.m -> field polynomial degree")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyTypeObject binfield_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.BinField", /* @tp_name@ */
+ sizeof(field_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ field_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+ "Binary fields. Abstract class.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ field_pyrichcompare, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ binfield_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ abstract_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyObject *binpolyfield_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+{
+ mp *xx = 0;
+ field *f;
+ char *kwlist[] = { "p", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:binpolyfield", kwlist,
+ convgf, &xx))
+ goto end;
+ if ((f = field_binpoly(xx)) == 0) VALERR("bad poly for binpolyfield");
+ MP_DROP(xx);
+ return (field_dopywrap(ty, f));
+end:
+ mp_drop(xx);
+ return (0);
+}
+
+static PyGetSetDef binpolyfield_pygetset[] = {
+#define GETSETNAME(op, name) pf##op##_##name
+ GET (p, "F.p -> field polynomial")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyTypeObject binpolyfield_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.BinPolyField", /* @tp_name@ */
+ sizeof(field_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ field_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+ "Binary fields with polynomial basis representation.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ field_pyrichcompare, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ binpolyfield_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ binpolyfield_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyObject *binnormfield_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+{
+ mp *xx = 0, *yy = 0;
+ field *f;
+ char *kwlist[] = { "p", "beta", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&:binnormfield",
+ kwlist, convgf, &xx, convgf, &yy))
+ goto end;
+ if ((f = field_binnorm(xx, yy)) == 0) VALERR("bad args for binnormfield");
+ MP_DROP(xx); MP_DROP(yy);
+ return (field_dopywrap(ty, f));
+end:
+ mp_drop(xx); mp_drop(yy);
+ return (0);
+}
+
+static PyObject *bnfget_beta(PyObject *me, void *hunoz)
+{
+ fctx_binnorm *fc = (fctx_binnorm *)FIELD_F(me);
+ return (gf_pywrap(MP_COPY(fc->ntop.r[fc->ntop.n - 1])));
+}
+
+static PyGetSetDef binnormfield_pygetset[] = {
+#define GETSETNAME(op, name) pf##op##_##name
+ GET (p, "F.p -> field polynomial")
+#undef GETSETNAME
+#define GETSETNAME(op, name) bnf##op##_##name
+ GET (beta, "F.beta -> conversion factor")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyTypeObject binnormfield_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.BinNormField", /* @tp_name@ */
+ sizeof(field_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ field_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+ "Binary fields with normal basis representation.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ field_pyrichcompare, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ binnormfield_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ binnormfield_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- Setup -------------------------------------------------------------*/
+
+static PyObject *meth__Field_parse(PyObject *me, PyObject *arg)
+{
+ field *f;
+ char *p;
+ PyObject *rc = 0;
+ qd_parse qd;
+
+ if (!PyArg_ParseTuple(arg, "Os:parse", &me, &p))
+ goto end;
+ qd.p = p;
+ qd.e = 0;
+ if ((f = field_parse(&qd)) == 0)
+ SYNERR(qd.e);
+ rc = Py_BuildValue("(Ns)", field_pywrap(f), qd.p);
+end:
+ return (rc);
+}
+
+static PyMethodDef methods[] = {
+#define METHNAME(func) meth_##func
+ METH (_Field_parse, "parse(STR) -> F, REST")
+#undef METHNAME
+ { 0 }
+};
+
+void field_pyinit(void)
+{
+ INITTYPE(fe, root);
+ INITTYPE(field, type);
+ INITTYPE(primefield, field);
+ INITTYPE(niceprimefield, primefield);
+ INITTYPE(binfield, field);
+ INITTYPE(binpolyfield, binfield);
+ INITTYPE(binnormfield, binfield);
+ addmethods(methods);
+}
+
+void field_pyinsert(PyObject *mod)
+{
+ INSERT("FE", fe_pytype);
+ INSERT("Field", field_pytype);
+ INSERT("PrimeField", primefield_pytype);
+ INSERT("NicePrimeField", niceprimefield_pytype);
+ INSERT("BinField", binfield_pytype);
+ INSERT("BinPolyField", binpolyfield_pytype);
+ INSERT("BinNormField", binnormfield_pytype);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id$
+ *
+ * Binary polynomial arithmetic
+ *
+ * (c) 2004 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of the Python interface to Catacomb.
+ *
+ * Catacomb/Python is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb/Python is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Catacomb/Python; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log$
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "catacomb-python.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+PyTypeObject *gf_pytype;
+
+PyObject *gf_pywrap(mp *x)
+{
+ mp_pyobj *z = PyObject_New(mp_pyobj, mp_pytype);
+ z->x = x;
+ return ((PyObject *)z);
+}
+
+mp *getgf(PyObject *o)
+{
+ mp *x = 0;
+ if ((x = tomp(o)) == 0) {
+ PyErr_Format(PyExc_TypeError, "can't convert %.100s to gf",
+ o->ob_type->tp_name);
+ }
+ return (x);
+}
+
+
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id$
+ *
+ * Abstract group inteface
+ *
+ * (c) 2004 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of the Python interface to Catacomb.
+ *
+ * Catacomb/Python is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb/Python is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Catacomb/Python; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "catacomb-python.h"
+
+/*----- DH and binary group infos -----------------------------------------*/
+
+PyObject *fginfo_pywrap(gprime_param *dp, PyTypeObject *ty)
+{
+ fginfo_pyobj *z = PyObject_New(fginfo_pyobj, ty);
+ z->dp.p = MP_COPY(dp->p);
+ z->dp.q = MP_COPY(dp->q);
+ z->dp.g = MP_COPY(dp->g);
+ return ((PyObject *)z);
+}
+
+static PyObject *fginfo_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+{
+ char *kwlist[] = { "p", "r", "g", 0 };
+ gprime_param dp = { 0 };
+ fginfo_pyobj *z = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&O&:new", kwlist,
+ convmp, &dp.p,
+ convmp, &dp.q,
+ &convmp, dp.g))
+ goto end;
+ z = PyObject_New(fginfo_pyobj, ty);
+ z->dp = dp;
+ return ((PyObject *)z);
+end:
+ mp_drop(dp.p);
+ mp_drop(dp.q);
+ mp_drop(dp.g);
+ return (0);
+}
+
+static PyObject *figet_r(PyObject *me, void *hunoz)
+ { return mp_pywrap(FGINFO_DP(me)->q); }
+
+static PyObject *diget_p(PyObject *me, void *hunoz)
+ { return mp_pywrap(FGINFO_DP(me)->p); }
+
+static PyObject *diget_g(PyObject *me, void *hunoz)
+ { return mp_pywrap(FGINFO_DP(me)->g); }
+
+static PyObject *biget_p(PyObject *me, void *hunoz)
+ { return gf_pywrap(FGINFO_DP(me)->p); }
+
+static PyObject *biget_m(PyObject *me, void *hunoz)
+ { return PyInt_FromLong(mp_octets(FGINFO_DP(me)->p) - 1); }
+
+static PyObject *biget_g(PyObject *me, void *hunoz)
+ { return gf_pywrap(FGINFO_DP(me)->g); }
+
+static void fginfo_pydealloc(PyObject *me)
+{
+ mp_drop(FGINFO_DP(me)->p);
+ mp_drop(FGINFO_DP(me)->q);
+ mp_drop(FGINFO_DP(me)->g);
+ _PyObject_Del(me);
+}
+
+static PyObject *meth__DHInfo_generate(PyObject *me,
+ PyObject *arg, PyObject *kw)
+{
+ dh_param dp;
+ unsigned ql = 0, pl;
+ unsigned steps = 0;
+ grand *r = &rand_global;
+ pgev evt = { 0 };
+ char *kwlist[] =
+ { "class", "pbits", "qbits", "event", "rng", "nsteps", 0 };
+ PyObject *rc = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO&|O&O&O&O&:generate", kwlist,
+ &me, convuint, &pl, convuint, &ql,
+ convpgev, &evt, convgrand, &r,
+ convuint, &steps))
+ goto end;
+ if (dh_gen(&dp, ql, pl, steps, r, evt.proc, evt.ctx))
+ PGENERR;
+ rc = fginfo_pywrap(&dp, dhinfo_pytype);
+end:
+ droppgev(&evt);
+ return (rc);
+}
+
+static PyObject *meth__DHInfo_genlimlee(PyObject *me,
+ PyObject *arg, PyObject *kw)
+{
+ dh_param dp;
+ unsigned ql, pl;
+ unsigned steps = 0;
+ grand *r = &rand_global;
+ pgev oe = { 0 }, ie = { 0 };
+ int subgroupp = 1;
+ unsigned f = 0;
+ char *kwlist[] = { "class", "pbits", "qbits", "event", "ievent",
+ "rng", "nsteps", "subgroupp", 0 };
+ size_t i, nf;
+ mp **v = 0;
+ PyObject *rc = 0, *vec = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw,
+ "OO&O&|O&O&O&O&O&:genlimlee", kwlist,
+ &me, convuint, &pl, convuint, &ql,
+ convpgev, &oe, convpgev, &ie,
+ convgrand, &r, convuint, &steps,
+ convbool, &subgroupp))
+ goto end;
+ if (subgroupp) f |= DH_SUBGROUP;
+ if (dh_limlee(&dp, ql, pl, f, steps, r,
+ oe.proc, oe.ctx, ie.proc, ie.ctx, &nf, &v))
+ PGENERR;
+ vec = PyList_New(nf);
+ for (i = 0; i < nf; i++)
+ PyList_SetItem(vec, i, mp_pywrap(v[i]));
+ xfree(v);
+ rc = Py_BuildValue("(NN)", fginfo_pywrap(&dp, dhinfo_pytype), vec);
+end:
+ droppgev(&oe); droppgev(&ie);
+ return (rc);
+}
+
+static PyObject *meth__DHInfo_gendsa(PyObject *me,
+ PyObject *arg, PyObject *kw)
+{
+ dsa_param dp;
+ unsigned ql, pl;
+ unsigned steps = 0;
+ dsa_seed ds;
+ char *k;
+ int ksz;
+ pgev evt = { 0 };
+ char *kwlist[] =
+ { "class", "pbits", "qbits", "seed", "event", "nsteps", 0 };
+ PyObject *rc = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO&O&s#|O&O&:generate", kwlist,
+ &me, convuint, &pl, convuint, &ql,
+ &k, &ksz, convpgev, &evt,
+ convuint, &steps))
+ goto end;
+ if (dsa_gen(&dp, ql, pl, steps, k, ksz, &ds, evt.proc, evt.ctx))
+ PGENERR;
+ rc = Py_BuildValue("(NNl)", fginfo_pywrap(&dp, dhinfo_pytype),
+ bytestring_pywrap(ds.p, ds.sz), (long)ds.count);
+ xfree(ds.p);
+end:
+ droppgev(&evt);
+ return (rc);
+}
+
+static int npgroups = -1, nbingroups = -1;
+
+static PyObject *namedgroups(const pentry *pp, int *ne)
+{
+ int i, j;
+ const char *p;
+ PyObject *d, *c;
+
+ d = PyDict_New();
+ for (i = 0; pp[i].name; i++) {
+ p = pp[i].name;
+ for (j = 0; j < i; j++) {
+ if (pp[i].data == pp[j].data) {
+ c = PyDict_GetItemString(d, (/*unconst*/ char *)pp[j].name);
+ Py_INCREF(c);
+ goto found;
+ }
+ }
+ c = PyInt_FromLong(i);
+ found:
+ PyDict_SetItemString(d, (/*unconst*/ char *)pp[i].name, c);
+ Py_DECREF(c);
+ }
+ *ne = i;
+ return (d);
+}
+
+static PyObject *meth__groupn(PyObject *me, PyObject *arg,
+ PyTypeObject *ty, const pentry *pp, int ne)
+{
+ int i;
+ gprime_param gp;
+ PyObject *rc = 0;
+
+ if (!PyArg_ParseTuple(arg, "Oi:_groupn", &me, &i)) goto end;
+ if (i < 0 || i >= ne) VALERR("group index out of range");
+ dh_infofromdata(&gp, pp[i].data);
+ rc = fginfo_pywrap(&gp, ty);
+end:
+ return (rc);
+}
+
+static PyObject *meth__DHInfo__groupn(PyObject *me, PyObject *arg)
+ { return (meth__groupn(me, arg, dhinfo_pytype, ptab, npgroups)); }
+
+static PyObject *meth__BinDHInfo__groupn(PyObject *me, PyObject *arg)
+ { return (meth__groupn(me, arg, bindhinfo_pytype, bintab, nbingroups)); }
+
+static PyObject *meth__parse(PyObject *me, PyObject *arg, PyTypeObject *ty,
+ int (*parse)(qd_parse *, gprime_param *))
+{
+ qd_parse qd;
+ char *p;
+ gprime_param gp;
+ PyObject *rc = 0;
+
+ if (!PyArg_ParseTuple(arg, "Os:parse", &me, &p)) goto end;
+ qd.p = p;
+ qd.e = 0;
+ if (parse(&qd, &gp)) SYNERR(qd.e);
+ rc = fginfo_pywrap(&gp, ty);
+end:
+ return (rc);
+}
+
+static PyObject *meth__DHInfo_parse(PyObject *me, PyObject *arg)
+ { return (meth__parse(me, arg, dhinfo_pytype, dh_parse)); }
+
+static PyObject *meth__BinDHInfo_parse(PyObject *me, PyObject *arg)
+ { return (meth__parse(me, arg, bindhinfo_pytype, dhbin_parse)); }
+
+static PyGetSetDef fginfo_pygetset[] = {
+#define GETSETNAME(op, name) fi##op##_##name
+ GET (r, "I.r -> group order")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyGetSetDef dhinfo_pygetset[] = {
+#define GETSETNAME(op, name) di##op##_##name
+ GET (p, "I.p -> prime")
+ GET (g, "I.g -> generator")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyGetSetDef bindhinfo_pygetset[] = {
+#define GETSETNAME(op, name) bi##op##_##name
+ GET (p, "I.p -> irreducible polynomial")
+ GET (m, "I.m -> degree of polynomial")
+ GET (g, "I.g -> generator")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyTypeObject fginfo_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.FGInfo", /* @tp_name@ */
+ sizeof(fginfo_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ fginfo_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+ "Abstract base class for field-group information objects.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ fginfo_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ abstract_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyTypeObject dhinfo_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.DHInfo", /* @tp_name@ */
+ sizeof(fginfo_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ fginfo_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+ "Standard (integer) Diffie-Hellman group information.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ dhinfo_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ fginfo_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyTypeObject bindhinfo_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.BinDHInfo", /* @tp_name@ */
+ sizeof(fginfo_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ fginfo_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+ "Binary-field Diffie-Hellman group information.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ bindhinfo_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ fginfo_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- General utilities -------------------------------------------------*/
+
+PyTypeObject *ge_pytype, *group_pytype;
+PyTypeObject *primegroup_pytype, *bingroup_pytype, *ecgroup_pytype;
+
+group *group_copy(group *g)
+{
+ if (strcmp(G_NAME(g), "prime") == 0) {
+ gctx_prime *gc = (gctx_prime *)g;
+ gprime_param gp;
+ gp.g = G_TOINT(g, MP_NEW, g->g);
+ gp.p = gc->mm.m;
+ gp.q = gc->g.r;
+ g = group_prime(&gp);
+ MP_DROP(gp.g);
+ } else if (strcmp(G_NAME(g), "bin") == 0) {
+ gctx_bin *gc = (gctx_bin *)g;
+ gbin_param gb;
+ gb.g = G_TOINT(g, MP_NEW, g->g);
+ gb.p = gc->r.p;
+ gb.q = gc->g.r;
+ g = group_binary(&gb);
+ MP_DROP(gb.g);
+ } else if (strcmp(G_NAME(g), "ec") == 0) {
+ gctx_ec *gc = (gctx_ec *)g;
+ ec_info ei;
+ if ((ei.c = eccurve_copy(gc->ei.c)) == 0)
+ return (0);
+ EC_CREATE(&ei.g);
+ EC_COPY(&ei.g, &gc->ei.g);
+ ei.r = MP_COPY(gc->ei.r);
+ ei.h = MP_COPY(gc->ei.h);
+ g = group_ec(&ei);
+ } else
+ g = 0;
+ return (g);
+}
+
+PyObject *ge_pywrap(PyObject *gobj, ge *x)
+{
+ ge_pyobj *z = PyObject_New(ge_pyobj, (PyTypeObject *)gobj);
+ z->x = x;
+ z->g = GROUP_G(gobj);
+ Py_INCREF(gobj);
+ return ((PyObject *)z);
+}
+
+static PyObject *ge_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+{
+ char *kwlist[] = { "x", 0 };
+ PyObject *x;
+ group *g;
+ ec p = EC_INIT;
+ mp *y = 0;
+ ge *xx = 0;
+ mptext_stringctx sc;
+
+ g = GROUP_G(ty);
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O:new", kwlist, &x)) goto end;
+ xx = G_CREATE(g);
+ if (ECPT_PYCHECK(x)) {
+ getecptout(&p, x);
+ if (G_FROMEC(g, xx, &p))
+ TYERR("can't convert from elliptic curve point");
+ EC_DESTROY(&p);
+ } else if ((y = tomp(x)) != 0) {
+ if (G_FROMINT(g, xx, y))
+ TYERR("can't convert from integer");
+ MP_DROP(y);
+ } else if (PyString_Check(x)) {
+ sc.buf = PyString_AS_STRING(x);
+ sc.lim = sc.buf + PyString_GET_SIZE(x);
+ if (G_READ(g, xx, &mptext_stringops, &sc) || sc.buf < sc.lim)
+ SYNERR("malformed group element string");
+ } else
+ TYERR("can't convert to group element");
+ return (ge_pywrap((PyObject *)ty, xx));
+end:
+ mp_drop(y);
+ EC_DESTROY(&p);
+ if (xx) G_DESTROY(g, xx);
+ return (0);
+}
+
+static PyObject *group_dopywrap(PyTypeObject *ty, group *g)
+{
+ group_pyobj *gobj = newtype(ty, 0);
+ gobj->g = g;
+ gobj->ty.tp_name = (/*unconst*/ char *)g->ops->name;
+ gobj->ty.tp_basicsize = sizeof(ge_pyobj);
+ gobj->ty.tp_base = ge_pytype;
+ Py_INCREF(group_pytype);
+ gobj->ty.tp_flags = (Py_TPFLAGS_DEFAULT |
+ Py_TPFLAGS_BASETYPE |
+ Py_TPFLAGS_CHECKTYPES |
+ Py_TPFLAGS_HEAPTYPE);
+ gobj->ty.tp_alloc = PyType_GenericAlloc;
+ gobj->ty.tp_free =_PyObject_Del;
+ gobj->ty.tp_new = ge_pynew;
+ PyType_Ready(&gobj->ty);
+ return ((PyObject *)gobj);
+}
+
+PyObject *group_pywrap(group *g)
+{
+ PyTypeObject *ty;
+
+ if (strcmp(G_NAME(g), "prime") == 0) ty = primegroup_pytype;
+ else if (strcmp(G_NAME(g), "bin") == 0) ty = bingroup_pytype;
+ else if (strcmp(G_NAME(g), "ec") == 0) ty = ecgroup_pytype;
+ else abort();
+ return (group_dopywrap(ty, g));
+}
+
+/*----- Group elements ----------------------------------------------------*/
+
+#define BINOP(name) \
+ static PyObject *ge_py##name(PyObject *x, PyObject *y) \
+ { \
+ ge *z; \
+ group *g; \
+ if (!GE_PYCHECK(x) || !GE_PYCHECK(y) || \
+ (GE_G(x) != GE_G(y) && !group_samep(GE_G(x), GE_G(y)))) \
+ RETURN_NOTIMPL; \
+ g = GE_G(x); \
+ z = G_CREATE(g); \
+ g->ops->name(g, z, GE_X(x), GE_X(y)); \
+ return (ge_pywrap(GE_GOBJ(x), z)); \
+ }
+BINOP(mul)
+BINOP(div)
+#undef BINOP
+
+#define UNOP(name) \
+ static PyObject *gemeth_##name(PyObject *me, PyObject *arg) \
+ { \
+ group *g; \
+ ge *z; \
+ if (!PyArg_ParseTuple(arg, ":" #name)) return (0); \
+ g = GE_G(me); \
+ z = G_CREATE(g); \
+ g->ops->name(g, z, GE_X(me)); \
+ return (ge_pywrap(GE_GOBJ(me), z)); \
+ }
+UNOP(sqr)
+UNOP(inv)
+#undef UNOP
+
+static PyObject *ge_pyexp(PyObject *x, PyObject *n, PyObject *m)
+{
+ mp *nn;
+ ge *z;
+
+ if (m != Py_None || !GE_PYCHECK(x) || (nn = getmp(n)) == 0)
+ RETURN_NOTIMPL;
+ z = G_CREATE(GE_G(x));
+ G_EXP(GE_G(x), z, GE_X(x), nn);
+ MP_DROP(nn);
+ return (ge_pywrap(GE_GOBJ(x), z));
+}
+
+static void ge_pydealloc(PyObject *me)
+{
+ G_DESTROY(GE_G(me), GE_X(me));
+ Py_DECREF(GE_GOBJ(me));
+ PyObject_DEL(me);
+}
+
+static void group_pydealloc(PyObject *me)
+{
+ G_DESTROYGROUP(GROUP_G(me));
+ PyType_Type.tp_dealloc(me);
+}
+
+static PyObject *gmexp_id(PyObject *me)
+{
+ group *g = GROUP_G(me); ge *x = G_CREATE(g);
+ G_COPY(g, x, g->i); return (ge_pywrap(me, x));
+}
+
+static int gmexp_fill(void *pp, PyObject *me, PyObject *x, PyObject *m)
+{
+ group_expfactor *f = pp;
+
+ if (!GE_PYCHECK(x) || GE_G(x) != GROUP_G(me) || (f->exp = getmp(m)) == 0)
+ return (-1);
+ f->base = GE_X(x);
+ return (0);
+}
+
+static PyObject *ge_pyrichcompare(PyObject *x, PyObject *y, int op)
+{
+ int b;
+ PyObject *rc = 0;
+
+ if (!GE_PYCHECK(x) || !GE_PYCHECK(y) ||
+ (GE_G(x) != GE_G(y) && !group_samep(GE_G(x), GE_G(y))))
+ RETURN_NOTIMPL;
+ switch (op) {
+ case Py_EQ: b = G_EQ(GE_G(x), GE_X(x), GE_X(y)); break;
+ case Py_NE: b = !G_EQ(GE_G(x), GE_X(x), GE_X(y)); break;
+ default: TYERR("group elements are unordered");
+ }
+ rc = getbool(b);
+end:
+ return (rc);
+}
+
+static PyObject *gemeth_check(PyObject *me, PyObject *arg)
+{
+ if (!PyArg_ParseTuple(arg, ":check")) goto end;
+ if (group_check(GE_G(me), GE_X(me))) VALERR("bad group element");
+ RETURN_OBJ(me);
+end:
+ return (0);
+}
+
+static int ge_pynonzerop(PyObject *x)
+ { return (!G_IDENTP(GE_G(x), GE_X(x))); }
+
+static PyObject *ge_pystr(PyObject *me)
+{
+ dstr d = DSTR_INIT;
+ PyObject *rc;
+
+ group_writedstr(GE_G(me), GE_X(me), &d);
+ rc = PyString_FromStringAndSize(d.buf, d.len);
+ DDESTROY(&d);
+ return (rc);
+}
+
+static PyObject *ge_pylong(PyObject *me)
+{
+ mp *x = 0;
+ PyObject *rc = 0;
+
+ if ((x = G_TOINT(GE_G(me), MP_NEW, GE_X(me))) == 0)
+ TYERR("can't convert to integer");
+ rc = (PyObject *)mp_topylong(x);
+end:
+ mp_drop(x);
+ return (rc);
+}
+
+static PyObject *ge_pyint(PyObject *me)
+{
+ mp *x = 0;
+ PyObject *rc = 0;
+ long l;
+
+ if ((x = G_TOINT(GE_G(me), MP_NEW, GE_X(me))) == 0)
+ TYERR("can't convert to integer");
+ if (mp_tolong_checked(x, &l)) goto end;
+ rc = PyInt_FromLong(l);
+end:
+ mp_drop(x);
+ return (rc);
+}
+
+static PyObject *gemeth_toint(PyObject *me, PyObject *arg)
+{
+ mp *x;
+
+ if (!PyArg_ParseTuple(arg, ":toint")) goto end;
+ if ((x = G_TOINT(GE_G(me), MP_NEW, GE_X(me))) == 0)
+ TYERR("can't convert to integer");
+ return (mp_pywrap(x));
+end:
+ return (0);
+}
+
+static PyObject *gemeth_toec(PyObject *me, PyObject *arg, PyObject *kw)
+{
+ char *kwlist[] = { "curve", 0 };
+ PyTypeObject *cty = ecpt_pytype;
+ ec p = EC_INIT;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O:toec", kwlist,
+ &cty)) goto end;
+ if (!PyType_Check(cty) || !PyType_IsSubtype(cty, ecpt_pytype))
+ TYERR("want subtype of catacomb.ECPt");
+ if (G_TOEC(GE_G(me), &p, GE_X(me)))
+ TYERR("can't convert to ec point");
+ return (ecpt_pywrapout(cty, &p));
+end:
+ return (0);
+}
+
+static PyObject *gemeth_tobuf(PyObject *me, PyObject *arg)
+{
+ buf b;
+ PyObject *rc;
+ size_t n;
+
+ if (!PyArg_ParseTuple(arg, ":tobuf")) return (0);
+ n = GE_G(me)->noctets + 4;
+ rc = bytestring_pywrap(0, n);
+ buf_init(&b, PyString_AS_STRING(rc), n);
+ G_TOBUF(GE_G(me), &b, GE_X(me));
+ assert(BOK(&b));
+ _PyString_Resize(&rc, BLEN(&b));
+ return (rc);
+}
+
+static PyObject *gemeth_toraw(PyObject *me, PyObject *arg)
+{
+ buf b;
+ PyObject *rc;
+ size_t n;
+
+ if (!PyArg_ParseTuple(arg, ":toraw")) return (0);
+ n = GE_G(me)->noctets;
+ rc = bytestring_pywrap(0, n);
+ buf_init(&b, PyString_AS_STRING(rc), n);
+ G_TORAW(GE_G(me), &b, GE_X(me));
+ assert(BOK(&b));
+ _PyString_Resize(&rc, BLEN(&b));
+ return (rc);
+}
+
+static PyObject *gmexp_exp(PyObject *me, void *pp, int n)
+{
+ ge *z = G_CREATE(GROUP_G(me));
+ G_MEXP(GROUP_G(me), z, pp, n);
+ return (ge_pywrap(me, z));
+}
+
+static void gmexp_drop(void *pp)
+{
+ group_expfactor *f = pp;
+ MP_DROP(f->exp);
+}
+
+static PyObject *gmeth_mexp(PyObject *me, PyObject *arg)
+{
+ return (mexp_common(me, arg, sizeof(group_expfactor),
+ gmexp_id, gmexp_fill, gmexp_exp, gmexp_drop));
+}
+
+static PyObject *gmeth_check(PyObject *me, PyObject *arg, PyObject *kw)
+{
+ char *kwlist[] = { "rng", 0 };
+ grand *r = &rand_global;
+ const char *p;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:check", kwlist,
+ convgrand, &r))
+ goto end;
+ if ((p = G_CHECK(GROUP_G(me), r)) != 0)
+ VALERR(p);
+ RETURN_OBJ(me);
+end:
+ return (0);
+}
+
+static PyObject *group_pyrichcompare(PyObject *x, PyObject *y, int op)
+{
+ int b = group_samep(GROUP_G(x), GROUP_G(y));
+ switch (op) {
+ case Py_EQ: break;
+ case Py_NE: b = !b;
+ default: TYERR("can't order groups");
+ }
+ return (getbool(b));
+end:
+ return (0);
+}
+
+static PyObject *meth__GE_frombuf(PyObject *me, PyObject *arg)
+{
+ buf b;
+ char *p;
+ int n;
+ group *g;
+ ge *x = 0;
+
+ if (!PyArg_ParseTuple(arg, "Os#:frombuf", &me, &p, &n))
+ return (0);
+ g = GROUP_G(me);
+ buf_init(&b, p, n);
+ x = G_CREATE(g);
+ if (G_FROMBUF(g, &b, x))
+ VALERR("invalid data");
+ return (Py_BuildValue("(NN)", ge_pywrap(me, x), bytestring_pywrapbuf(&b)));
+end:
+ if (x) G_DESTROY(g, x);
+ return (0);
+}
+
+static PyObject *meth__GE_fromraw(PyObject *me, PyObject *arg)
+{
+ buf b;
+ char *p;
+ int n;
+ group *g;
+ ge *x = 0;
+
+ if (!PyArg_ParseTuple(arg, "Os#:fromraw", &me, &p, &n))
+ return (0);
+ g = GROUP_G(me);
+ buf_init(&b, p, n);
+ x = G_CREATE(g);
+ if (G_FROMRAW(g, &b, x))
+ VALERR("invalid data");
+ return (Py_BuildValue("(NN)", ge_pywrap(me, x), bytestring_pywrapbuf(&b)));
+end:
+ if (x) G_DESTROY(g, x);
+ return (0);
+}
+
+static PyObject *meth__GE_fromstring(PyObject *me, PyObject *arg)
+{
+ mptext_stringctx sc;
+ char *p;
+ int n;
+ group *g;
+ ge *x = 0;
+
+ if (!PyArg_ParseTuple(arg, "Os#:fromstring", &me, &p, &n))
+ return (0);
+ sc.buf = p;
+ sc.lim = sc.buf + n;
+ g = GROUP_G(me);
+ x = G_CREATE(g);
+ if (G_READ(g, x, &mptext_stringops, &sc))
+ SYNERR("bad group element string");
+ return (Py_BuildValue("(Ns#)", ge_pywrap(me, x),
+ sc.buf, (int)(sc.lim - sc.buf)));
+end:
+ if (x) G_DESTROY(g, x);
+ return (0);
+}
+
+static PyObject *meth__Group_parse(PyObject *me, PyObject *arg)
+{
+ char *p;
+ qd_parse qd;
+ group *g;
+
+ if (!PyArg_ParseTuple(arg, "Os:parse", &me, &p))
+ goto end;
+ qd.p = p;
+ qd.e = 0;
+ if ((g = group_parse(&qd)) == 0)
+ SYNERR(qd.e);
+ return (group_pywrap(g));
+end:
+ return (0);
+}
+
+static PyObject *geget_group(PyObject *me, void *hunoz)
+ { RETURN_OBJ(GE_GOBJ(me)); }
+
+static PyObject *gget_nbits(PyObject *me, void *hunoz)
+ { return (PyInt_FromLong(GROUP_G(me)->nbits)); }
+
+static PyObject *gget_noctets(PyObject *me, void *hunoz)
+ { return (PyInt_FromLong(GROUP_G(me)->noctets)); }
+
+static PyObject *gget_i(PyObject *me, void *hunoz)
+{
+ group *g = GROUP_G(me); ge *x = G_CREATE(g);
+ G_COPY(g, x, g->i); return (ge_pywrap(me, x));
+}
+
+static PyObject *gget_g(PyObject *me, void *hunoz)
+{
+ group *g = GROUP_G(me); ge *x = G_CREATE(g);
+ G_COPY(g, x, g->g); return (ge_pywrap(me, x));
+}
+
+static PyObject *gget_r(PyObject *me, void *hunoz)
+ { return (mp_pywrap(MP_COPY(GROUP_G(me)->r))); }
+
+static PyObject *gget_h(PyObject *me, void *hunoz)
+ { return (mp_pywrap(MP_COPY(GROUP_G(me)->h))); }
+
+static PyGetSetDef ge_pygetset[] = {
+#define GETSETNAME(op, name) ge##op##_##name
+ GET (group, "X.group -> group containing X")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyMethodDef ge_pymethods[] = {
+#define METHNAME(name) gemeth_##name
+ METH (inv, "X.inv() -> inverse element of X")
+ METH (sqr, "X.sqr() -> X^2 = X * X")
+ METH (check, "X.check() -> check X really belongs to its group")
+ METH (toint, "X.toint() -> X converted to an integer")
+ KWMETH(toec, "\
+X.toec(curve = ecpt) -> X converted to elliptic curve point")
+ METH (tobuf, "X.tobuf() -> X in buffer representation")
+ METH (toraw, "X.toraw() -> X in raw representation")
+#undef METHNAME
+ { 0 }
+};
+
+static PyNumberMethods ge_pynumber = {
+ 0, /* @nb_add@ */
+ 0, /* @nb_subtract@ */
+ ge_pymul, /* @nb_multiply@ */
+ ge_pydiv, /* @nb_divide@ */
+ 0, /* @nb_remainder@ */
+ 0, /* @nb_divmod@ */
+ ge_pyexp, /* @nb_power@ */
+ 0, /* @nb_negative@ */
+ 0, /* @nb_positive@ */
+ 0, /* @nb_absolute@ */
+ ge_pynonzerop, /* @nb_nonzero@ */
+ 0, /* @nb_invert@ */
+ 0, /* @nb_lshift@ */
+ 0, /* @nb_rshift@ */
+ 0, /* @nb_and@ */
+ 0, /* @nb_xor@ */
+ 0, /* @nb_or@ */
+ 0, /* @nb_coerce@ */
+ ge_pyint, /* @nb_int@ */
+ ge_pylong, /* @nb_long@ */
+ 0 /* meaningless */, /* @nb_float@ */
+ 0, /* @nb_oct@ */
+ 0, /* @nb_hex@ */
+
+ 0, /* @nb_inplace_add@ */
+ 0, /* @nb_inplace_subtract@ */
+ 0, /* @nb_inplace_multiply@ */
+ 0, /* @nb_inplace_divide@ */
+ 0, /* @nb_inplace_remainder@ */
+ 0, /* @nb_inplace_power@ */
+ 0, /* @nb_inplace_lshift@ */
+ 0, /* @nb_inplace_rshift@ */
+ 0, /* @nb_inplace_and@ */
+ 0, /* @nb_inplace_xor@ */
+ 0, /* @nb_inplace_or@ */
+
+ 0, /* @nb_floor_divide@ */
+ ge_pydiv, /* @nb_true_divide@ */
+ 0, /* @nb_inplace_floor_divide@ */
+ 0, /* @nb_inplace_true_divide@ */
+};
+
+static PyTypeObject ge_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.GE", /* @tp_name@ */
+ sizeof(ge_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ ge_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ &ge_pynumber, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ ge_pystr, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_CHECKTYPES |
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Group elements, abstract base class.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ ge_pyrichcompare, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ ge_pymethods, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ ge_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ abstract_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyGetSetDef group_pygetset[] = {
+#define GETSETNAME(op, name) g##op##_##name
+ GET (noctets, "G.noctets -> size in octets of element")
+ GET (nbits, "G.nbits -> size in bits of element")
+ GET (i, "G.i -> group identity")
+ GET (g, "G.g -> group generator")
+ GET (r, "G.r -> group order")
+ GET (h, "G.h -> group cofactor")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyMethodDef group_pymethods[] = {
+#define METHNAME(name) gmeth_##name
+ METH (mexp, "\
+G.mexp([(X0, N0), (X1, N1), ...]) -> X0^N0 X1^N1 ...")
+ KWMETH(check, "G.check(rand = random): check group is good")
+#undef METHNAME
+ { 0 }
+};
+
+static PyTypeObject group_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.Group", /* @tp_name@ */
+ sizeof(group_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ group_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Abstract base class for groups.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ group_pyrichcompare, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ group_pymethods, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ group_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ abstract_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyObject *pgget_info(PyObject *me, void *hunoz)
+{
+ gprime_param dp;
+ gctx_prime *gg = (gctx_prime *)GROUP_G(me);
+ dp.p = MP_COPY(gg->mm.m);
+ dp.q = MP_COPY(gg->g.r);
+ dp.g = mpmont_reduce(&gg->mm, MP_NEW, gg->gen);
+ return (fginfo_pywrap(&dp, dhinfo_pytype));
+}
+
+static PyGetSetDef primegroup_pygetset[] = {
+#define GETSETNAME(op, name) pg##op##_##name
+ GET (info, "G.info -> information about the group")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyObject *primegroup_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+{
+ PyObject *i;
+ char *kwlist[] = { "info", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!:new", kwlist,
+ dhinfo_pytype, &i))
+ return (0);
+ return (group_dopywrap(ty, group_prime(FGINFO_DP(i))));
+}
+
+static PyTypeObject primegroup_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.PrimeGroup", /* @tp_name@ */
+ sizeof(group_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ group_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Subgroups of prime fields.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ primegroup_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ primegroup_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyObject *bgget_info(PyObject *me, void *hunoz)
+{
+ gbin_param dp;
+ gctx_bin *gg = (gctx_bin *)GROUP_G(me);
+ dp.p = MP_COPY(gg->r.p);
+ dp.q = MP_COPY(gg->g.r);
+ dp.g = MP_COPY(gg->gen);
+ return (fginfo_pywrap(&dp, bindhinfo_pytype));
+}
+
+static PyGetSetDef bingroup_pygetset[] = {
+#define GETSETNAME(op, name) bg##op##_##name
+ GET (info, "G.info -> information about the group")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyObject *bingroup_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+{
+ PyObject *i;
+ char *kwlist[] = { "info", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!:new", kwlist,
+ bindhinfo_pytype, &i))
+ return (0);
+ return (group_dopywrap(ty, group_binary(FGINFO_DP(i))));
+}
+
+static PyTypeObject bingroup_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.BinGroup", /* @tp_name@ */
+ sizeof(group_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ group_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Subgroups of binary fields.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ bingroup_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ bingroup_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyObject *egget_info(PyObject *me, void *hunoz)
+{
+ ec_info ei;
+ gctx_ec *gg = (gctx_ec *)GROUP_G(me);
+
+ ecinfo_copy(&ei, &gg->ei);
+ return (ecinfo_pywrap(&ei));
+}
+
+static PyGetSetDef ecgroup_pygetset[] = {
+#define GETSETNAME(op, name) eg##op##_##name
+ GET (info, "G.info -> information about the group")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyObject *ecgroup_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+{
+ PyObject *i;
+ ec_info ei;
+ char *kwlist[] = { "info", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!:new", kwlist,
+ ecinfo_pytype, &i))
+ return (0);
+ ecinfo_copy(&ei, ECINFO_EI(i));
+ return (group_dopywrap(ty, group_ec(&ei)));
+}
+
+static PyTypeObject ecgroup_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.ECGroup", /* @tp_name@ */
+ sizeof(group_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ group_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Elliptic curve groups.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ ecgroup_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ ecgroup_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- Global stuff ------------------------------------------------------*/
+
+static PyMethodDef methods[] = {
+#define METHNAME(name) meth_##name
+ METH (_GE_frombuf, "frombuf(BUF) -> X, REST")
+ METH (_GE_fromraw, "fromraw(BUF) -> X, REST")
+ METH (_GE_fromstring, "fromstring(STR) -> X, REST")
+ METH (_Group_parse, "parse(STR) -> G, REST")
+ METH (_DHInfo_parse, "parse(STR) -> D, REST")
+ METH (_BinDHInfo_parse, "parse(STR) -> D, REST")
+ METH (_DHInfo__groupn, 0)
+ METH (_BinDHInfo__groupn, 0)
+ KWMETH(_DHInfo_generate, "\
+generate(PBITS, [qbits = 0, event = pgen_nullev,
+ rng = rand, nsteps = 0]) -> D")
+ KWMETH(_DHInfo_genlimlee, "\
+genlimlee(PBITS, QBITS, [event = pgen_nullev, ievent = pgen_nullev,\n\
+ rng = rand, nsteps = 0, subgroupp = True]) -> (D, [Q, ...])")
+ KWMETH(_DHInfo_gendsa, "\
+gendsa(PBITS, QBITS, SEED, [event = pgen_nullev, nsteps = 0])\n\
+ -> (D, SEED, COUNT)")
+#undef METHNAME
+ { 0 }
+};
+
+void group_pyinit(void)
+{
+ INITTYPE(fginfo, root);
+ INITTYPE(dhinfo, fginfo);
+ INITTYPE(bindhinfo, dhinfo);
+ INITTYPE(ge, root);
+ INITTYPE(group, type);
+ INITTYPE(primegroup, group);
+ INITTYPE(bingroup, group);
+ INITTYPE(ecgroup, group);
+ addmethods(methods);
+}
+
+void group_pyinsert(PyObject *mod)
+{
+ INSERT("FGInfo", fginfo_pytype);
+ INSERT("DHInfo", dhinfo_pytype);
+ INSERT("BinDHInfo", bindhinfo_pytype);
+ INSERT("GE", ge_pytype);
+ INSERT("Group", group_pytype);
+ INSERT("PrimeGroup", primegroup_pytype);
+ INSERT("BinGroup", bingroup_pytype);
+ INSERT("ECGroup", ecgroup_pytype);
+ INSERT("_pgroups", namedgroups(ptab, &npgroups));
+ INSERT("_bingroups", namedgroups(bintab, &nbingroups));
+}
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id$
+ *
+ * Key files and data
+ *
+ * (c) 2005 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of the Python interface to Catacomb.
+ *
+ * Catacomb/Python is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb/Python is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Catacomb/Python; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "catacomb-python.h"
+
+/*----- Key files ---------------------------------------------------------*/
+
+static PyObject *keyfile_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+{
+
+}
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id$
+ *
+ * Multiprecision arithmetic
+ *
+ * (c) 2004 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of the Python interface to Catacomb.
+ *
+ * Catacomb/Python is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb/Python is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Catacomb/Python; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "catacomb-python.h"
+
+/*----- General utilities -------------------------------------------------*/
+
+PyTypeObject *mp_pytype = 0;
+PyTypeObject *gf_pytype = 0;
+
+mp *mp_frompylong(PyLongObject *l)
+{
+ unsigned long bits;
+ int sz;
+ size_t w;
+ mpd r = 0;
+ int b = 0;
+ int i;
+ mp *x;
+ mpw *p;
+
+ sz = l->ob_size;
+ if (sz < 0) sz = -sz;
+ assert(MPW_BITS >= SHIFT);
+ bits = (unsigned long)sz * SHIFT;
+ w = (bits + MPW_BITS - 1)/MPW_BITS;
+ x = mp_new(w, l->ob_size < 0 ? MP_NEG : 0);
+ p = x->v;
+ for (i = 0; i < sz; i++) {
+ r |= (mpd)l->ob_digit[i] << b;
+ b += SHIFT;
+ while (b >= MPW_BITS) {
+ *p++ = MPW(r);
+ r >>= MPW_BITS;
+ b -= MPW_BITS;
+ }
+ }
+ while (r) {
+ *p++ = MPW(r);
+ r >>= MPW_BITS;
+ }
+ x->vl = p;
+ MP_SHRINK(x);
+ return (x);
+}
+
+PyLongObject *mp_topylong(mp *x)
+{
+ unsigned long bits = mp_bits(x);
+ int sz = (bits + SHIFT - 1)/SHIFT;
+ PyLongObject *l = _PyLong_New(sz);
+ mpd r = 0;
+ int b = 0;
+ mpw *p = x->v;
+ int i = 0;
+
+ assert(MPW_BITS >= SHIFT);
+ while (i < sz && p < x->vl) {
+ r |= *p << b;
+ b += MPW_BITS;
+ while (i < sz && b >= SHIFT) {
+ l->ob_digit[i++] = r & MASK;
+ r >>= SHIFT;
+ b -= SHIFT;
+ }
+ }
+ while (i < sz && r) {
+ l->ob_digit[i++] = r & MASK;
+ r >>= SHIFT;
+ }
+ l->ob_size = (x->f & MP_NEG) ? -sz : sz;
+ return (l);
+}
+
+mp *mp_frompyobject(PyObject *o, int radix)
+{
+ mp *x;
+
+ if ((x = tomp(o)) != 0)
+ return (x);
+ if (PyString_Check(o)) {
+ mptext_stringctx sc;
+ mp *x;
+ sc.buf = PyString_AS_STRING(o);
+ sc.lim = sc.buf + PyString_GET_SIZE(o);
+ x = mp_read(MP_NEW, radix, &mptext_stringops, &sc);
+ if (!x) return (0);
+ if (sc.buf < sc.lim) { MP_DROP(x); return (0); }
+ return (x);
+ }
+ return (0);
+}
+
+PyObject *mp_topystring(mp *x, int radix, const char *xpre,
+ const char *pre, const char *post)
+{
+ int len = mptext_len(x, radix) + 1;
+ mptext_stringctx sc;
+ PyObject *o;
+ size_t xprelen = xpre ? strlen(xpre) : 0;
+ size_t prelen = pre ? strlen(pre) : 0;
+ size_t postlen = post ? strlen(post) : 0;
+ char *p;
+ MP_COPY(x);
+ o = PyString_FromStringAndSize(0, len + 1 + xprelen + prelen + postlen);
+ p = PyString_AS_STRING(o);
+ sc.buf = p;
+ if (xpre) { memcpy(sc.buf, xpre, xprelen); sc.buf += xprelen; }
+ if (MP_NEGP(x)) { *sc.buf++ = '-'; x = mp_neg(x, x); }
+ if (pre) { memcpy(sc.buf, pre, prelen); sc.buf += prelen; }
+ sc.lim = sc.buf + len;
+ mp_write(x, radix, &mptext_stringops, &sc);
+ if (post) { memcpy(sc.buf, post, postlen); sc.buf += postlen; }
+ MP_DROP(x);
+ _PyString_Resize(&o, sc.buf - p);
+ return (o);
+}
+
+PyObject *mp_pywrap(mp *x)
+{
+ mp_pyobj *z = PyObject_New(mp_pyobj, mp_pytype);
+ z->x = x;
+ return ((PyObject *)z);
+}
+
+PyObject *gf_pywrap(mp *x)
+{
+ mp_pyobj *z = PyObject_New(mp_pyobj, gf_pytype);
+ z->x = x;
+ return ((PyObject *)z);
+}
+
+int mp_tolong_checked(mp *x, long *l)
+{
+ static mp *longmin = 0, *longmax = 0;
+ int rc = -1;
+
+ if (!longmax) {
+ longmin = mp_fromlong(MP_NEW, LONG_MIN);
+ longmax = mp_fromlong(MP_NEW, LONG_MAX);
+ }
+ if (MP_CMP(x, <, longmin) || MP_CMP(x, >, longmax))
+ VALERR("mp out of range for int");
+ *l = mp_tolong(x);
+ rc = 0;
+end:
+ return (rc);
+}
+
+/*----- Python interface --------------------------------------------------*/
+
+static void mp_pydealloc(PyObject *o)
+{
+ MP_DROP(MP_X(o));
+ PyObject_DEL(o);
+}
+
+static PyObject *mp_pyrepr(PyObject *o)
+ { return mp_topystring(MP_X(o), 10, "MP(", 0, "L)"); }
+
+static PyObject *mp_pystr(PyObject *o)
+ { return mp_topystring(MP_X(o), 10, 0, 0, 0); }
+
+mp *tomp(PyObject *o)
+{
+ PyObject *l;
+ mp *x;
+
+ if (!o)
+ return (0);
+ else if (MP_PYCHECK(o) || GF_PYCHECK(o))
+ return (MP_COPY(MP_X(o)));
+ else if (FE_PYCHECK(o))
+ return (F_OUT(FE_F(o), MP_NEW, FE_X(o)));
+ else if (PFILT_PYCHECK(o))
+ return (MP_COPY(PFILT_F(o)->m));
+ else if (ECPT_PYCHECK(o)) {
+ ec p = EC_INIT;
+ getecptout(&p, o);
+ x = MP_COPY(p.x);
+ EC_DESTROY(&p);
+ return (x);
+ } else if (GE_PYCHECK(o)) {
+ if ((x = G_TOINT(GE_G(o), MP_NEW, GE_X(o))) == 0)
+ return (0);
+ return (x);
+ } else if (PyInt_Check(o))
+ return (mp_fromlong(MP_NEW, PyInt_AS_LONG(o)));
+ else if ((l = PyNumber_Long(o)) != 0) {
+ x = mp_frompylong((PyLongObject *)l);
+ Py_DECREF(l);
+ return (x);
+ } else {
+ PyErr_Clear();
+ return (0);
+ }
+}
+
+mp *getmp(PyObject *o)
+{
+ mp *x = 0;
+ if (!o) return (0);
+ if ((x = tomp(o)) == 0) {
+ PyErr_Format(PyExc_TypeError, "can't convert %.100s to mp",
+ o->ob_type->tp_name);
+ }
+ return (x);
+}
+
+int convmp(PyObject *o, void *p)
+{
+ mp *x;
+ if ((x = getmp(o)) == 0) return (0);
+ *(mp **)p = x;
+ return (1);
+}
+
+mp *getgf(PyObject *o)
+{
+ mp *x = 0;
+ if (!o) return (0);
+ if ((x = tomp(o)) == 0) {
+ PyErr_Format(PyExc_TypeError, "can't convert %.100s to gf",
+ o->ob_type->tp_name);
+ }
+ return (x);
+}
+
+int convgf(PyObject *o, void *p)
+{
+ mp *x;
+ if ((x = getgf(o)) == 0) return (0);
+ *(mp **)p = x;
+ return (1);
+}
+
+static int mpbinop(PyObject *x, PyObject *y, mp **xx, mp **yy)
+{
+ if ((*xx = tomp(x)) == 0)
+ return (-1);
+ if ((*yy = tomp(y)) == 0) {
+ MP_DROP(*xx);
+ return (-1);
+ }
+ return (0);
+}
+
+#define gf_and mp_and
+#define gf_or mp_or
+#define gf_xor mp_xor
+#define BINOP(pre, name) \
+ static PyObject *pre##_py##name(PyObject *x, PyObject *y) { \
+ mp *xx, *yy, *zz; \
+ if (mpbinop(x, y, &xx, &yy)) RETURN_NOTIMPL; \
+ zz = pre##_##name(MP_NEW, xx, yy); \
+ MP_DROP(xx); MP_DROP(yy); \
+ return (pre##_pywrap(zz)); \
+ }
+BINOP(mp, add)
+BINOP(mp, sub)
+BINOP(mp, mul)
+BINOP(mp, and2c)
+BINOP(mp, or2c)
+BINOP(mp, xor2c)
+BINOP(gf, add)
+BINOP(gf, sub)
+BINOP(gf, mul)
+BINOP(gf, and)
+BINOP(gf, or)
+BINOP(gf, xor)
+#undef BINOP
+
+static mp *mp_abs(mp *d, mp *x)
+{
+ if (MP_NEGP(x))
+ return (mp_neg(d, x));
+ MP_COPY(x);
+ if (d) MP_DROP(d);
+ return (x);
+}
+
+#define UNOP(pre, name) \
+ static PyObject *pre##_py##name(PyObject *x) \
+ { return mp_pywrap(pre##_##name(MP_NEW, MP_X(x))); }
+UNOP(mp, neg)
+UNOP(mp, abs)
+UNOP(mp, not2c)
+#undef UNOP
+
+static PyObject *mp_pyid(PyObject *x) { RETURN_OBJ(x); }
+
+#define gf_lsr mp_lsr
+#define SHIFTOP(pre, name, rname) \
+ static PyObject *pre##_py##name(PyObject *x, PyObject *y) { \
+ mp *xx, *yy; \
+ PyObject *z = 0; \
+ long n; \
+ if (mpbinop(x, y, &xx, &yy)) RETURN_NOTIMPL; \
+ if (mp_tolong_checked(yy, &n)) goto end; \
+ if (n < 0) \
+ z = pre##_pywrap(mp_##rname(MP_NEW, xx, -n)); \
+ else \
+ z = pre##_pywrap(mp_##name(MP_NEW, xx, n)); \
+ end: \
+ MP_DROP(xx); MP_DROP(yy); \
+ return (z); \
+ }
+SHIFTOP(mp, lsl2c, lsr2c)
+SHIFTOP(mp, lsr2c, lsl2c)
+SHIFTOP(gf, lsl, lsr)
+SHIFTOP(gf, lsr, lsl)
+#undef SHIFTOP
+
+#define DIVOP(pre, name, qq, rr, gather) \
+ static PyObject *pre##_py##name(PyObject *x, PyObject *y) { \
+ mp *xx, *yy; \
+ PyObject *z = 0; \
+ INIT_##qq(q) INIT_##rr(r) \
+ if (mpbinop(x, y, &xx, &yy)) RETURN_NOTIMPL; \
+ if (MP_ZEROP(yy)) \
+ ZDIVERR("division by zero"); \
+ pre##_div(ARG_##qq(q), ARG_##rr(r), xx, yy); \
+ z = gather; \
+ end: \
+ MP_DROP(xx); MP_DROP(yy); \
+ return (z); \
+ }
+#define INIT_YES(p) mp *p = MP_NEW;
+#define INIT_NO(p)
+#define ARG_YES(p) &p
+#define ARG_NO(p) 0
+DIVOP(mp, divmod, YES, YES,
+ Py_BuildValue("(NN)", mp_pywrap(q), mp_pywrap(r)))
+DIVOP(mp, div, YES, NO, mp_pywrap(q))
+DIVOP(mp, mod, NO, YES, mp_pywrap(r))
+DIVOP(gf, divmod, YES, YES,
+ Py_BuildValue("(NN)", gf_pywrap(q), gf_pywrap(r)))
+DIVOP(gf, div, YES, NO, gf_pywrap(q))
+DIVOP(gf, mod, NO, YES, gf_pywrap(r))
+#undef INIT_YES
+#undef INIT_NO
+#undef ARG_YES
+#undef ARG_NO
+#undef DIVOP
+
+static mp *mp_modinv_checked(mp *d, mp *x, mp *p)
+{
+ mp *g = MP_NEW;
+ mp_gcd(&g, 0, &d, p, x);
+ if (!MP_EQ(g, MP_ONE)) {
+ MP_DROP(g); MP_DROP(d);
+ PyErr_SetString(PyExc_ZeroDivisionError, "no modular inverse");
+ return (0);
+ }
+ MP_DROP(g); return (d);
+}
+
+static PyObject *mp_pyexp(PyObject *x, PyObject *y, PyObject *z)
+{
+ mp *xx = 0, *yy = 0, *zz = 0;
+ mp *r = 0;
+ PyObject *rc = 0;
+
+ if ((xx = tomp(x)) == 0 || (yy = tomp(y)) == 0 ||
+ (z && z != Py_None && (zz = tomp(z)) == 0)) {
+ mp_drop(xx); mp_drop(yy); mp_drop(zz);
+ RETURN_NOTIMPL;
+ }
+ if (!z || z == Py_None) {
+ if (MP_NEGP(yy)) VALERR("negative exponent");
+ r = mp_exp(MP_NEW, xx, yy);
+ } else {
+ if (!MP_POSP(zz)) VALERR("modulus must be positive");
+ if (MP_NEGP(yy)) {
+ if ((xx = mp_modinv_checked(xx, xx, zz)) == 0) goto end;
+ yy = mp_neg(yy, yy);
+ }
+ if (MP_ODDP(zz)) {
+ mpmont mm;
+ mpmont_create(&mm, zz);
+ r = mpmont_exp(&mm, MP_NEW, xx, yy);
+ mpmont_destroy(&mm);
+ } else {
+ mpbarrett mb;
+ mpbarrett_create(&mb, zz);
+ r = mpbarrett_exp(&mb, MP_NEW, xx, yy);
+ mpbarrett_destroy(&mb);
+ }
+ }
+ rc = mp_pywrap(r);
+end:
+ mp_drop(xx); mp_drop(yy); mp_drop(zz);
+ return (rc);
+}
+
+static mp *gf_modinv_checked(mp *d, mp *x, mp *p)
+{
+ mp *g = MP_NEW;
+ gf_gcd(&g, 0, &d, p, x);
+ if (!MP_EQ(g, MP_ONE)) {
+ MP_DROP(g); MP_DROP(d);
+ PyErr_SetString(PyExc_ZeroDivisionError, "no modular inverse");
+ return (0);
+ }
+ MP_DROP(g); return (d);
+}
+
+#define BASEOP(name, radix, pre) \
+ static PyObject *mp_py##name(PyObject *x) \
+ { return mp_topystring(MP_X(x), radix, 0, pre, 0); }
+BASEOP(oct, 8, "0");
+BASEOP(hex, 16, "0x");
+#undef BASEOP
+
+static int mp_pynonzerop(PyObject *x) { return !MP_ZEROP(MP_X(x)); }
+
+static PyObject *mp_pyint(PyObject *x)
+{
+ long l;
+ if (mp_tolong_checked(MP_X(x), &l)) return (0);
+ return (PyInt_FromLong(l));
+}
+static PyObject *mp_pylong(PyObject *x)
+ { return (PyObject *)mp_topylong(MP_X(x)); }
+static PyObject *mp_pyfloat(PyObject *x)
+{
+ PyObject *l = (PyObject *)mp_topylong(MP_X(x));
+ double f = PyLong_AsDouble(l);
+ Py_DECREF(l);
+ return (PyFloat_FromDouble(f));
+}
+
+#define COERCE(pre, PRE) \
+ static int pre##_pycoerce(PyObject **x, PyObject **y) \
+ { \
+ mp *z; \
+ \
+ if (PRE##_PYCHECK(*y)) { \
+ Py_INCREF(*x); Py_INCREF(*y); \
+ return (0); \
+ } \
+ if ((z = tomp(*y)) != 0) { \
+ Py_INCREF(*x); \
+ *y = pre##_pywrap(z); \
+ return (0); \
+ } \
+ return (1); \
+ }
+COERCE(mp, MP)
+COERCE(gf, GF)
+#undef COERCE
+
+static int mp_pycompare(PyObject *x, PyObject *y)
+ { return mp_cmp(MP_X(x), MP_X(y)); }
+
+static PyObject *mp_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+{
+ PyObject *x;
+ mp *z;
+ mp_pyobj *zz = 0;
+ int radix = 0;
+ char *kwlist[] = { "x", "radix", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O|i:mp", kwlist, &x, &radix))
+ goto end;
+ if (MP_PYCHECK(x)) RETURN_OBJ(x);
+ if (radix < -255 || radix > 62) VALERR("radix out of range");
+ if ((z = mp_frompyobject(x, radix)) == 0) {
+ PyErr_Format(PyExc_TypeError, "can't convert %.100s to mp",
+ x->ob_type->tp_name);
+ goto end;
+ }
+ zz = (mp_pyobj *)ty->tp_alloc(ty, 0);
+ zz->x = z;
+end:
+ return ((PyObject *)zz);
+}
+
+static long mp_pyhash(PyObject *me)
+{
+ long i = mp_tolong(MP_X(me));
+ if (i == -1)
+ i = -2;
+ return (i);
+}
+
+static PyObject *mpmeth_jacobi(PyObject *me, PyObject *arg)
+{
+ mp *y = 0;
+ PyObject *z = 0;
+
+ if (!PyArg_ParseTuple(arg, "O&:jacobi", convmp, &y)) goto end;
+ z = PyInt_FromLong(mp_jacobi(y, MP_X(me)));
+end:
+ if (y) MP_DROP(y);
+ return (z);
+}
+
+#define BITOP(pre, name, c) \
+ static PyObject *pre##meth_##name(PyObject *me, PyObject *arg) \
+ { \
+ int i; \
+ if (!PyArg_ParseTuple(arg, "i:" #name, &i)) return (0); \
+ return (pre##_pywrap(mp_##name##c(MP_NEW, MP_X(me), i))); \
+ }
+BITOP(mp, setbit, 2c);
+BITOP(mp, clearbit, 2c);
+BITOP(gf, setbit, );
+BITOP(gf, clearbit, );
+#undef BITOP
+
+static PyObject *mpmeth_testbit(PyObject *me, PyObject *arg)
+{
+ int i;
+ if (!PyArg_ParseTuple(arg, "i:testbit", &i)) return (0);
+ return (getbool(mp_testbit2c(MP_X(me), i)));
+}
+
+static PyObject *gfmeth_testbit(PyObject *me, PyObject *arg)
+{
+ int i;
+ if (!PyArg_ParseTuple(arg, "i:testbit", &i)) return (0);
+ return (getbool(mp_testbit(MP_X(me), i)));
+}
+
+static PyObject *mpmeth_odd(PyObject *me, PyObject *arg)
+{
+ mp *t;
+ size_t s;
+
+ if (!PyArg_ParseTuple(arg, ":odd")) return (0);
+ t = mp_odd(MP_NEW, MP_X(me), &s);
+ return (Py_BuildValue("(lN)", (long)s, mp_pywrap(t)));
+}
+
+static PyObject *mpmeth_sqr(PyObject *me, PyObject *arg)
+{
+ if (!PyArg_ParseTuple(arg, ":sqr")) return (0);
+ return (mp_pywrap(mp_sqr(MP_NEW, MP_X(me))));
+}
+
+static PyObject *mpmeth_sqrt(PyObject *me, PyObject *arg)
+{
+ if (!PyArg_ParseTuple(arg, ":sqrt")) return (0);
+ if (MP_NEGP(MP_X(me))) VALERR("negative root");
+ return (mp_pywrap(mp_sqrt(MP_NEW, MP_X(me))));
+end:
+ return (0);
+}
+
+static PyObject *mpmeth_gcd(PyObject *me, PyObject *arg)
+{
+ mp *y = 0, *zz = MP_NEW;
+ PyObject *z = 0;
+
+ if (!PyArg_ParseTuple(arg, "O&:gcd", convmp, &y)) goto end;
+ mp_gcd(&zz, 0, 0, MP_X(me), y);
+ z = mp_pywrap(zz);
+end:
+ if (y) MP_DROP(y);
+ return (z);
+}
+
+static PyObject *mpmeth_gcdx(PyObject *me, PyObject *arg)
+{
+ PyObject *z = 0;
+ mp *yy = 0, *zz = MP_NEW, *uu = MP_NEW, *vv = MP_NEW;
+
+ if (!PyArg_ParseTuple(arg, "O&:gcdx", convmp, &yy)) goto end;
+ mp_gcd(&zz, &uu, &vv, MP_X(me), yy);
+ z = Py_BuildValue("(NNN)",
+ mp_pywrap(zz), mp_pywrap(uu), mp_pywrap(vv));
+end:
+ if (yy) MP_DROP(yy);
+ return (z);
+}
+
+static PyObject *mpmeth_modinv(PyObject *me, PyObject *arg)
+{
+ PyObject *z = 0;
+ mp *yy = 0, *zz = MP_NEW;
+
+ if (!PyArg_ParseTuple(arg, "O&:modinv", convmp, &yy) ||
+ (zz = mp_modinv_checked(MP_NEW, yy, MP_X(me))) == 0)
+ goto end;
+ z = mp_pywrap(zz);
+end:
+ if (yy) MP_DROP(yy);
+ return (z);
+}
+
+static PyObject *mpmeth_tostring(PyObject *me, PyObject *arg, PyObject *kw)
+{
+ int radix = 10;
+ char *kwlist[] = { "radix", 0 };
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|i:tostring", kwlist, &radix))
+ goto end;
+ if (radix < -255 || radix > 62 || radix == -1 || radix == 0 || radix == 1)
+ VALERR("bad radix");
+ return (mp_topystring(MP_X(me), radix, 0, 0, 0));
+end:
+ return (0);
+}
+
+static PyObject *mpmeth_modsqrt(PyObject *me, PyObject *arg)
+{
+ PyObject *z = 0;
+ mp *yy = 0, *zz = MP_NEW;
+
+ if (!PyArg_ParseTuple(arg, "O&:modsqrt", convmp, &yy)) goto end;
+ if ((zz = mp_modsqrt(MP_NEW, yy, MP_X(me))) == 0)
+ VALERR("no modular square root");
+ z = mp_pywrap(zz);
+end:
+ if (yy) MP_DROP(yy);
+ return (z);
+}
+
+#define STOREOP(name, c) \
+ static PyObject *mpmeth_##name(PyObject *me, \
+ PyObject *arg, PyObject *kw) \
+ { \
+ long len = -1; \
+ char *kwlist[] = { "len", 0 }; \
+ PyObject *rc = 0; \
+ \
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|l:" #name, \
+ kwlist, &len)) \
+ goto end; \
+ if (len < 0) { \
+ len = mp_octets##c(MP_X(me)); \
+ if (!len) len = 1; \
+ } \
+ rc = bytestring_pywrap(0, len); \
+ mp_##name(MP_X(me), PyString_AS_STRING(rc), len); \
+ end: \
+ return (rc); \
+ }
+STOREOP(storel, )
+STOREOP(storeb, )
+STOREOP(storel2c, 2c)
+STOREOP(storeb2c, 2c)
+#undef STOREOP
+
+#define BUFOP(ty, pyty) \
+ static PyObject *meth__##pyty##_frombuf(PyObject *me, PyObject *arg) \
+ { \
+ buf b; \
+ char *p; \
+ int sz; \
+ PyObject *rc = 0; \
+ mp *x; \
+ \
+ if (!PyArg_ParseTuple(arg, "Os#:frombuf", &me, &p, &sz)) goto end; \
+ buf_init(&b, p, sz); \
+ if ((x = buf_getmp(&b)) == 0) VALERR("malformed data"); \
+ rc = Py_BuildValue("(NN)", ty##_pywrap(x), \
+ bytestring_pywrapbuf(&b)); \
+ end: \
+ return (rc); \
+ }
+BUFOP(mp, MP)
+BUFOP(gf, GF)
+#undef BUFOP
+
+static PyObject *mpmeth_tobuf(PyObject *me, PyObject *arg)
+{
+ buf b;
+ PyObject *rc;
+ mp *x;
+ size_t n;
+
+ if (!PyArg_ParseTuple(arg, ":tobuf")) return (0);
+ x = MP_X(me);
+ n = mp_octets(x) + 3;
+ rc = bytestring_pywrap(0, n);
+ buf_init(&b, PyString_AS_STRING(rc), n);
+ buf_putmp(&b, x);
+ assert(BOK(&b));
+ _PyString_Resize(&rc, BLEN(&b));
+ return (rc);
+}
+
+static PyObject *mpmeth_primep(PyObject *me, PyObject *arg, PyObject *kw)
+{
+ grand *r = &rand_global;
+ char *kwlist[] = { "rng", 0 };
+ PyObject *rc = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&", kwlist, convgrand, &r))
+ goto end;
+ rc = getbool(pgen_primep(MP_X(me), r));
+end:
+ return (rc);
+}
+
+static PyObject *mpget_nbits(PyObject *me, void *hunoz)
+ { return (PyInt_FromLong(mp_bits(MP_X(me)))); }
+
+static PyObject *mpget_noctets(PyObject *me, void *hunoz)
+ { return (PyInt_FromLong(mp_octets(MP_X(me)))); }
+
+static PyObject *mpget_noctets2c(PyObject *me, void *hunoz)
+ { return (PyInt_FromLong(mp_octets2c(MP_X(me)))); }
+
+static PyGetSetDef mp_pygetset[] = {
+#define GETSETNAME(op, func) mp##op##_##func
+ GET (nbits, "X.nbits -> bit length of X")
+ GET (noctets, "X.noctets -> octet length of X")
+ GET (noctets2c, "X.noctets2c -> two's complement octet length of X")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyMethodDef mp_pymethods[] = {
+#define METHNAME(func) mpmeth_##func
+ METH (jacobi, "X.jacobi(Y) -> Jacobi symbol (Y/X) (NB inversion!)")
+ METH (setbit, "X.setbit(N) -> X with bit N set")
+ METH (clearbit, "X.clearbit(N) -> X with bit N clear")
+ METH (testbit, "X.testbit(N) -> true/false if bit N set/clear in X")
+ METH (odd, "X.odd() -> S, T where X = 2^S T with T odd")
+ METH (sqr, "X.sqr() -> X^2")
+ METH (sqrt, "X.sqrt() -> largest integer <= sqrt(X)")
+ METH (gcd, "X.gcd(Y) -> gcd(X, Y)")
+ METH (gcdx,
+ "X.gcdx(Y) -> (gcd(X, Y), U, V) with X U + Y V = gcd(X, Y)")
+ METH (modinv, "X.modinv(Y) -> multiplicative inverse of Y mod X")
+ METH (modsqrt, "X.modsqrt(Y) -> square root of Y mod X, if X prime")
+ KWMETH(primep, "X.primep(rng = rand) -> true/false if X is prime")
+ KWMETH(tostring, "X.tostring(radix = 10) -> STR")
+ KWMETH(storel, "X.storel(len = -1) -> little-endian bytes")
+ KWMETH(storeb, "X.storeb(len = -1) -> big-endian bytes")
+ KWMETH(storel2c,
+ "X.storel2c(len = -1) -> little-endian bytes, two's complement")
+ KWMETH(storeb2c,
+ "X.storeb2c(len = -1) -> big-endian bytes, two's complement")
+ METH (tobuf, "X.tobuf() -> buffer format")
+#undef METHNAME
+ { 0 }
+};
+
+static PyNumberMethods mp_pynumber = {
+ mp_pyadd, /* @nb_add@ */
+ mp_pysub, /* @nb_subtract@ */
+ mp_pymul, /* @nb_multiply@ */
+ 0, /* @nb_divide@ */
+ mp_pymod, /* @nb_remainder@ */
+ mp_pydivmod, /* @nb_divmod@ */
+ mp_pyexp, /* @nb_power@ */
+ mp_pyneg, /* @nb_negative@ */
+ mp_pyid, /* @nb_positive@ */
+ mp_pyabs, /* @nb_absolute@ */
+ mp_pynonzerop, /* @nb_nonzero@ */
+ mp_pynot2c, /* @nb_invert@ */
+ mp_pylsl2c, /* @nb_lshift@ */
+ mp_pylsr2c, /* @nb_rshift@ */
+ mp_pyand2c, /* @nb_and@ */
+ mp_pyxor2c, /* @nb_xor@ */
+ mp_pyor2c, /* @nb_or@ */
+ mp_pycoerce, /* @nb_coerce@ */
+ mp_pyint, /* @nb_int@ */
+ mp_pylong, /* @nb_long@ */
+ mp_pyfloat, /* @nb_float@ */
+ mp_pyoct, /* @nb_oct@ */
+ mp_pyhex, /* @nb_hex@ */
+
+ 0, /* @nb_inplace_add@ */
+ 0, /* @nb_inplace_subtract@ */
+ 0, /* @nb_inplace_multiply@ */
+ 0, /* @nb_inplace_divide@ */
+ 0, /* @nb_inplace_remainder@ */
+ 0, /* @nb_inplace_power@ */
+ 0, /* @nb_inplace_lshift@ */
+ 0, /* @nb_inplace_rshift@ */
+ 0, /* @nb_inplace_and@ */
+ 0, /* @nb_inplace_xor@ */
+ 0, /* @nb_inplace_or@ */
+
+ mp_pydiv, /* @nb_floor_divide@ */
+ 0, /* @nb_true_divide@ */
+ 0, /* @nb_inplace_floor_divide@ */
+ 0, /* @nb_inplace_true_divide@ */
+};
+
+static PyTypeObject mp_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.MP", /* @tp_name@ */
+ sizeof(mp_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ mp_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ mp_pycompare, /* @tp_compare@ */
+ mp_pyrepr, /* @tp_repr@ */
+ &mp_pynumber, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ mp_pyhash, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ mp_pystr, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_CHECKTYPES |
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Multiprecision integers, similar to `long' but more efficient and\n\
+versatile. Support all the standard arithmetic operations.\n\
+\n\
+Constructor mp(X, radix = R) attempts to convert X to an `mp'. If\n\
+X is a string, it's read in radix-R form, or we look for a prefix\n\
+if R = 0. Other acceptable things are ints and longs.\n\
+\n\
+Notes:\n\
+\n\
+ * Use `//' for division. MPs don't have `/' division.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ mp_pymethods, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ mp_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ mp_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyObject *meth__MP_fromstring(PyObject *me,
+ PyObject *arg, PyObject *kw)
+{
+ int r = 0;
+ char *p;
+ int len;
+ PyObject *z = 0;
+ mp *zz;
+ mptext_stringctx sc;
+ char *kwlist[] = { "class", "x", "radix", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "Os#|i:fromstring",
+ kwlist, &me, &p, &len, &r))
+ goto end;
+ if (r < -255 || r > 62) VALERR("radix out of range");
+ sc.buf = p; sc.lim = p + len;
+ if ((zz = mp_read(MP_NEW, r, &mptext_stringops, &sc)) == 0)
+ SYNERR("bad integer");
+ z = Py_BuildValue("(Ns#)", mp_pywrap(zz), sc.buf, (int)(sc.lim - sc.buf));
+end:
+ return (z);
+}
+
+static PyObject *meth__MP_product(PyObject *me, PyObject *arg)
+{
+ mpmul m;
+ PyObject *q, *i;
+ mp *x;
+
+ if (PyTuple_Size(arg) != 2) {
+ i = PyObject_GetIter(arg);
+ PyIter_Next(i);
+ } else {
+ if ((q = PyTuple_GetItem(arg, 1)) == 0) return (0);
+ if ((i = PyObject_GetIter(q)) == 0) {
+ PyErr_Clear(); /* that's ok */
+ i = PyObject_GetIter(arg);
+ }
+ }
+ if (!i) return (0);
+ mpmul_init(&m);
+ while ((q = PyIter_Next(i)) != 0) {
+ x = getmp(q); Py_DECREF(q); if (!x) {
+ MP_DROP(mpmul_done(&m));
+ Py_DECREF(i);
+ return (0);
+ }
+ mpmul_add(&m, x);
+ MP_DROP(x);
+ }
+ x = mpmul_done(&m);
+ Py_DECREF(i);
+ return (mp_pywrap(x));
+}
+
+#define LOADOP(pre, py, name) \
+ static PyObject *meth__##py##_##name(PyObject *me, PyObject *arg) \
+ { \
+ char *p; \
+ int len; \
+ if (!PyArg_ParseTuple(arg, "Os#:" #name, &me, &p, &len)) return (0); \
+ return (pre##_pywrap(mp_##name(MP_NEW, p, len))); \
+ }
+LOADOP(mp, MP, loadl)
+LOADOP(mp, MP, loadb)
+LOADOP(mp, MP, loadl2c)
+LOADOP(mp, MP, loadb2c)
+LOADOP(gf, GF, loadl)
+LOADOP(gf, GF, loadb)
+#undef LOADOP
+
+/*----- Montgomery reduction ----------------------------------------------*/
+
+typedef struct mpmont_pyobj {
+ PyObject_HEAD
+ mpmont mm;
+} mpmont_pyobj;
+
+#define MPMONT_PY(o) (&((mpmont_pyobj *)(o))->mm)
+
+static PyObject *mmmeth_int(PyObject *me, PyObject *arg)
+{
+ PyObject *z = 0;
+ mp *yy = 0;
+ mpmont *mm = MPMONT_PY(me);
+
+ if (!PyArg_ParseTuple(arg, "O&:in", convmp, &yy))
+ goto end;
+ mp_div(0, &yy, yy, mm->m);
+ z = mp_pywrap(mpmont_mul(mm, MP_NEW, yy, mm->r2));
+end:
+ if (yy) MP_DROP(yy);
+ return (z);
+}
+
+static PyObject *mmmeth_mul(PyObject *me, PyObject *arg)
+{
+ PyObject *rc = 0;
+ mp *yy = 0, *zz = 0;
+
+ if (!PyArg_ParseTuple(arg, "O&O&:mul", convmp, &yy, convmp, &zz))
+ goto end;
+ rc = mp_pywrap(mpmont_mul(MPMONT_PY(me), MP_NEW, yy, zz));
+end:
+ if (yy) MP_DROP(yy); if (zz) MP_DROP(zz);
+ return (rc);
+}
+
+static PyObject *mmmeth_exp(PyObject *me, PyObject *arg)
+{
+ PyObject *rc = 0;
+ mp *yy = 0, *zz = 0;
+
+ if (!PyArg_ParseTuple(arg, "O&O&:exp", convmp, &yy, convmp, &zz))
+ goto end;
+ if (MP_NEGP(zz)) {
+ if ((yy = mp_modinv_checked(yy, yy, MPMONT_PY(me)->m)) == 0) goto end;
+ zz = mp_neg(zz, zz);
+ }
+ rc = mp_pywrap(mpmont_exp(MPMONT_PY(me), MP_NEW, yy, zz));
+end:
+ if (yy) MP_DROP(yy); if (zz) MP_DROP(zz);
+ return (rc);
+}
+
+static PyObject *mmmeth_expr(PyObject *me, PyObject *arg)
+{
+ PyObject *rc = 0;
+ mp *yy = 0, *zz = 0;
+
+ if (!PyArg_ParseTuple(arg, "O&O&:expr", convmp, &yy, convmp, &zz))
+ goto end;
+ if (MP_NEGP(zz)) {
+ yy = mpmont_reduce(MPMONT_PY(me), yy, yy);
+ if ((yy = mp_modinv_checked(yy, yy, MPMONT_PY(me)->m)) == 0) goto end;
+ yy = mpmont_mul(MPMONT_PY(me), yy, yy, MPMONT_PY(me)->r2);
+ zz = mp_neg(zz, zz);
+ }
+ rc = mp_pywrap(mpmont_expr(MPMONT_PY(me), MP_NEW, yy, zz));
+end:
+ if (yy) MP_DROP(yy); if (zz) MP_DROP(zz);
+ return (rc);
+}
+
+static PyObject *mm_mexpr_id(PyObject *me)
+ { return mp_pywrap(MP_COPY(MPMONT_PY(me)->r)); }
+
+static int mm_mexpr_fill(void *p, PyObject *me, PyObject *x, PyObject *y)
+{
+ mp *xx = 0, *yy = 0;
+ mp_expfactor *f = p;
+ mpmont *mm = MPMONT_PY(me);
+
+ if ((xx = getmp(x)) == 0 || (yy = getmp(y)) == 0)
+ goto fail;
+ if (MP_NEGP(yy)) {
+ xx = mpmont_reduce(mm, xx, xx);
+ if ((xx = mp_modinv_checked(xx, xx, yy)) == 0)
+ goto fail;
+ xx = mpmont_mul(mm, xx, xx, mm->r2);
+ yy = mp_neg(yy, yy);
+ }
+ f->base = xx;
+ f->exp = yy;
+ return (0);
+
+fail:
+ mp_drop(xx); mp_drop(yy);
+ return (-1);
+}
+
+static PyObject *mm_mexpr(PyObject *me, void *v, int n)
+ { return mp_pywrap(mpmont_mexpr(MPMONT_PY(me), MP_NEW, v, n)); }
+
+static void mp_mexp_drop(void *p)
+{
+ mp_expfactor *f = p;
+ mp_drop(f->base);
+ mp_drop(f->exp);
+}
+
+static PyObject *mmmeth_mexpr(PyObject *me, PyObject *arg)
+{
+ return mexp_common(me, arg, sizeof(mp_expfactor),
+ mm_mexpr_id, mm_mexpr_fill, mm_mexpr, mp_mexp_drop);
+}
+
+static PyObject *mp_mexp_id(PyObject *me)
+ { return mp_pywrap(MP_ONE); }
+
+static int mp_mexp_fill(void *p, PyObject *me, PyObject *x, PyObject *y)
+{
+ mp *xx = 0, *yy = 0;
+ mp_expfactor *f = p;
+
+ if ((xx = getmp(x)) == 0 || (yy = getmp(y)) == 0)
+ goto fail;
+ if (MP_NEGP(yy)) {
+ if ((xx = mp_modinv_checked(xx, xx, yy)) == 0)
+ goto fail;
+ yy = mp_neg(yy, yy);
+ }
+ f->base = xx;
+ f->exp = yy;
+ return (0);
+
+fail:
+ mp_drop(xx); mp_drop(yy);
+ return (-1);
+}
+
+static PyObject *mm_mexp(PyObject *me, void *v, int n)
+ { return mp_pywrap(mpmont_mexp(MPMONT_PY(me), MP_NEW, v, n)); }
+
+static PyObject *mmmeth_mexp(PyObject *me, PyObject *arg)
+{
+ return mexp_common(me, arg, sizeof(mp_expfactor),
+ mp_mexp_id, mp_mexp_fill, mm_mexp, mp_mexp_drop);
+}
+
+#define mmmeth_ext mmmeth_reduce
+static PyObject *mmmeth_reduce(PyObject *me, PyObject *arg)
+{
+ PyObject *z = 0;
+ mp *yy = 0;
+
+ if (!PyArg_ParseTuple(arg, "O&", convmp, &yy)) goto end;
+ z = mp_pywrap(mpmont_reduce(MPMONT_PY(me), MP_NEW, yy));
+end:
+ return (z);
+}
+
+static void mpmont_pydealloc(PyObject *me)
+{
+ mpmont_destroy(MPMONT_PY(me));
+ PyObject_DEL(me);
+}
+
+static PyObject *mpmont_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+{
+ mpmont_pyobj *mm = 0;
+ char *kwlist[] = { "m", 0 };
+ mp *xx = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:new", kwlist, convmp, &xx))
+ goto end;
+ if (!MP_POSP(xx) || !MP_ODDP(xx)) VALERR("m must be positive and odd");
+ mm = (mpmont_pyobj *)ty->tp_alloc(ty, 0);
+ mpmont_create(&mm->mm, xx);
+end:
+ if (xx) MP_DROP(xx);
+ return ((PyObject *)mm);
+}
+
+static PyObject *mmget_m(PyObject *me, void *hunoz)
+ { return (mp_pywrap(MP_COPY(MPMONT_PY(me)->m))); }
+
+static PyObject *mmget_r(PyObject *me, void *hunoz)
+ { return (mp_pywrap(MP_COPY(MPMONT_PY(me)->r))); }
+
+static PyObject *mmget_r2(PyObject *me, void *hunoz)
+ { return (mp_pywrap(MP_COPY(MPMONT_PY(me)->r2))); }
+
+static PyGetSetDef mpmont_pygetset[] = {
+#define GETSETNAME(op, name) mm##op##_##name
+ GET (m, "M.m -> modulus for reduction")
+ GET (r, "M.r -> multiplicative identity")
+ GET (r2, "M.r2 -> M.r^2, Montgomerization factor")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyMethodDef mpmont_pymethods[] = {
+#define METHNAME(name) mmmeth_##name
+ METH (int, "M.out(X) -> XR")
+ METH (mul, "M.mul(XR, YR) -> ZR where Z = X Y")
+ METH (expr, "M.expr(XR, N) -> ZR where Z = X^N mod M.m")
+ METH (mexpr, "\
+B.mexp([(XR0, N0), (XR1, N1), ...]) = ZR where Z = X0^N0 X1^N1 mod B.m\n\
+\t(the list may be flattened if this more convenient.)")
+ METH (reduce, "M.reduce(XR) -> X")
+ METH (ext, "M.ext(XR) -> X")
+ METH (exp, "M.exp(X, N) -> X^N mod M.m")
+ METH (mexp, "\
+B.mexp([(X0, N0), (X1, N1), ...]) = X0^N0 X1^N1 mod B.m\n\
+\t(the list may be flattened if this more convenient.)")
+#undef METHNAME
+ { 0 }
+};
+
+static PyTypeObject *mpmont_pytype, mpmont_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.MPMont", /* @tp_name@ */
+ sizeof(mpmont_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ mpmont_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"A Montgomery reduction context.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ mpmont_pymethods, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ mpmont_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ mpmont_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- Barrett reduction -------------------------------------------------*/
+
+typedef struct mpbarrett_pyobj {
+ PyObject_HEAD
+ mpbarrett mb;
+} mpbarrett_pyobj;
+
+#define MPBARRETT_PY(o) (&((mpbarrett_pyobj *)(o))->mb)
+
+static PyObject *mbmeth_exp(PyObject *me, PyObject *arg)
+{
+ PyObject *rc = 0;
+ mp *yy = 0, *zz = 0;
+
+ if (!PyArg_ParseTuple(arg, "O&O&:exp", convmp, &yy, convmp, &zz))
+ goto end;
+ if (MP_NEGP(zz)) {
+ if ((yy = mp_modinv_checked(yy, yy, MPBARRETT_PY(me)->m)) == 0) goto end;
+ zz = mp_neg(zz, zz);
+ }
+ rc = mp_pywrap(mpbarrett_exp(MPBARRETT_PY(me), MP_NEW, yy, zz));
+end:
+ if (yy) MP_DROP(yy); if (zz) MP_DROP(zz);
+ return (rc);
+}
+
+static PyObject *mb_mexp(PyObject *me, void *v, int n)
+ { return mp_pywrap(mpbarrett_mexp(MPBARRETT_PY(me), MP_NEW, v, n)); }
+
+static PyObject *mbmeth_mexp(PyObject *me, PyObject *arg)
+{
+ return mexp_common(me, arg, sizeof(mp_expfactor),
+ mp_mexp_id, mp_mexp_fill, mb_mexp, mp_mexp_drop);
+}
+
+static PyObject *mbmeth_reduce(PyObject *me, PyObject *arg)
+{
+ PyObject *z = 0;
+ mp *yy = 0;
+
+ if (!PyArg_ParseTuple(arg, "O&:reduce", convmp, &yy))
+ goto end;
+ z = mp_pywrap(mpbarrett_reduce(MPBARRETT_PY(me), MP_NEW, yy));
+end:
+ return (z);
+}
+
+static void mpbarrett_pydealloc(PyObject *me)
+{
+ mpbarrett_destroy(MPBARRETT_PY(me));
+ PyObject_DEL(me);
+}
+
+static PyObject *mpbarrett_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+{
+ mpbarrett_pyobj *mb = 0;
+ char *kwlist[] = { "m", 0 };
+ mp *xx = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:new", kwlist, convmp, &xx))
+ goto end;
+ if (!MP_POSP(xx)) VALERR("m must be positive");
+ mb = (mpbarrett_pyobj *)ty->tp_alloc(ty, 0);
+ mpbarrett_create(&mb->mb, xx);
+end:
+ if (xx) MP_DROP(xx);
+ return ((PyObject *)mb);
+}
+
+static PyObject *mbget_m(PyObject *me, void *hunoz)
+ { return (mp_pywrap(MP_COPY(MPBARRETT_PY(me)->m))); }
+
+static PyGetSetDef mpbarrett_pygetset[] = {
+#define GETSETNAME(op, name) mb##op##_##name
+ GET (m, "B.m -> modulus for reduction")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyMethodDef mpbarrett_pymethods[] = {
+#define METHNAME(name) mbmeth_##name
+ METH (reduce, "B.reduce(X) -> X mod B.m")
+ METH (exp, "B.exp(X, N) -> X^N mod B.m")
+ METH (mexp, "\
+B.mexp([(X0, N0), (X1, N1), ...]) = X0^N0 X1^N1 mod B.m\n\
+\t(the list may be flattened if this more convenient.)")
+#undef METHNAME
+ { 0 }
+};
+
+static PyTypeObject *mpbarrett_pytype, mpbarrett_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.MPBarrett", /* @tp_name@ */
+ sizeof(mpbarrett_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ mpbarrett_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"A Barrett reduction context.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ mpbarrett_pymethods, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ mpbarrett_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ mpbarrett_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- Nice prime reduction ----------------------------------------------*/
+
+typedef struct mpreduce_pyobj {
+ PyObject_HEAD
+ mpreduce mr;
+} mpreduce_pyobj;
+
+#define MPREDUCE_PY(o) (&((mpreduce_pyobj *)(o))->mr)
+
+static PyObject *mrmeth_exp(PyObject *me, PyObject *arg)
+{
+ PyObject *rc = 0;
+ mp *yy = 0, *zz = 0;
+
+ if (!PyArg_ParseTuple(arg, "O&O&:exp", convmp, &yy, convmp, &zz))
+ goto end;
+ if (MP_NEGP(zz)) {
+ if ((yy = mp_modinv_checked(yy, yy, MPREDUCE_PY(me)->p)) == 0) goto end;
+ zz = mp_neg(zz, zz);
+ }
+ rc = mp_pywrap(mpreduce_exp(MPREDUCE_PY(me), MP_NEW, yy, zz));
+end:
+ if (yy) MP_DROP(yy); if (zz) MP_DROP(zz);
+ return (rc);
+}
+
+static PyObject *mrmeth_reduce(PyObject *me, PyObject *arg)
+{
+ PyObject *z = 0;
+ mp *yy = 0;
+
+ if (!PyArg_ParseTuple(arg, "O&:reduce", convmp, &yy)) goto end;
+ z = mp_pywrap(mpreduce_do(MPREDUCE_PY(me), MP_NEW, yy));
+end:
+ return (z);
+}
+
+static void mpreduce_pydealloc(PyObject *me)
+{
+ mpreduce_destroy(MPREDUCE_PY(me));
+ PyObject_DEL(me);
+}
+
+static PyObject *mpreduce_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+{
+ mpreduce_pyobj *mr = 0;
+ mpreduce r;
+ char *kwlist[] = { "m", 0 };
+ mp *xx = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:new", kwlist, convmp, &xx))
+ goto end;
+ if (!MP_POSP(xx)) VALERR("m must be positive");
+ if (mpreduce_create(&r, xx)) VALERR("bad modulus (must be 2^k - ...)");
+ mr = (mpreduce_pyobj *)ty->tp_alloc(ty, 0);
+ mr->mr = r;
+end:
+ if (xx) MP_DROP(xx);
+ return ((PyObject *)mr);
+}
+
+static PyObject *mrget_m(PyObject *me, void *hunoz)
+ { return (mp_pywrap(MP_COPY(MPREDUCE_PY(me)->p))); }
+
+static PyGetSetDef mpreduce_pygetset[] = {
+#define GETSETNAME(op, name) mr##op##_##name
+ GET (m, "R.m -> modulus for reduction")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyMethodDef mpreduce_pymethods[] = {
+#define METHNAME(name) mrmeth_##name
+ METH (reduce, "R.reduce(X) -> X mod B.m")
+ METH (exp, "R.exp(X, N) -> X^N mod B.m")
+#undef METHNAME
+ { 0 }
+};
+
+static PyTypeObject *mpreduce_pytype, mpreduce_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.MPReduce", /* @tp_name@ */
+ sizeof(mpreduce_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ mpreduce_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"A reduction context for reduction modulo primes of special form.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ mpreduce_pymethods, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ mpreduce_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ mpreduce_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- Chinese Remainder Theorem solution --------------------------------*/
+
+typedef struct mpcrt_pyobj {
+ PyObject_HEAD
+ mpcrt c;
+} mpcrt_pyobj;
+
+#define MPCRT_PY(o) (&((mpcrt_pyobj *)(o))->c)
+
+static PyObject *mcmeth_solve(PyObject *me, PyObject *arg)
+{
+ mpcrt *c = MPCRT_PY(me);
+ PyObject *q = 0, *x, *z = 0;
+ mp *xx;
+ mp **v = 0;
+ int i = 0, n = c->k;
+
+ Py_INCREF(me);
+ if (PyTuple_Size(arg) == n)
+ q = arg;
+ else if (!PyArg_ParseTuple(arg, "O:solve", &q))
+ goto end;
+ Py_INCREF(q);
+ if (!PySequence_Check(q)) TYERR("want a sequence of residues");
+ if (PySequence_Size(q) != n) VALERR("residue count mismatch");
+ v = xmalloc(n * sizeof(*v));
+ for (i = 0; i < n; i++) {
+ if ((x = PySequence_GetItem(q, i)) == 0) goto end;
+ xx = getmp(x); Py_DECREF(x); if (!xx) goto end;
+ v[i] = xx;
+ }
+ z = mp_pywrap(mpcrt_solve(c, MP_NEW, v));
+end:
+ if (v) {
+ n = i;
+ for (i = 0; i < n; i++)
+ MP_DROP(v[i]);
+ xfree(v);
+ }
+ Py_DECREF(me);
+ Py_XDECREF(q);
+ return (z);
+}
+
+static void mpcrt_pydealloc(PyObject *me)
+{
+ mpcrt *c = MPCRT_PY(me);
+ mpcrt_destroy(c);
+ xfree(c->v);
+}
+
+static PyObject *mpcrt_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+{
+ mpcrt_mod *v = 0;
+ int n, i = 0;
+ char *kwlist[] = { "mv", 0 };
+ PyObject *q = 0, *x;
+ mp *xx;
+ mpcrt_pyobj *c = 0;
+
+ if (PyTuple_Size(arg) > 1)
+ q = arg;
+ else if (!PyArg_ParseTupleAndKeywords(arg, kw, "O:new", kwlist, &q))
+ goto end;
+ Py_INCREF(q);
+ if (!PySequence_Check(q)) TYERR("want a sequence of moduli");
+ n = PySequence_Size(q);
+ if (PyErr_Occurred()) goto end;
+ if (!n) VALERR("want at least one modulus");
+ v = xmalloc(n * sizeof(*v));
+ for (i = 0; i < n; i++) {
+ if ((x = PySequence_GetItem(q, i)) == 0) goto end;
+ xx = getmp(x); Py_DECREF(x); if (!xx) goto end;
+ v[i].m = xx; v[i].n = 0; v[i].ni = 0; v[i].nni = 0;
+ }
+ c = (mpcrt_pyobj *)ty->tp_alloc(ty, 0);
+ mpcrt_create(&c->c, v, n, 0);
+ Py_DECREF(q);
+ return ((PyObject *)c);
+
+end:
+ if (v) {
+ n = i;
+ for (i = 0; i < n; i++)
+ MP_DROP(v[i].m);
+ xfree(v);
+ }
+ Py_XDECREF(q);
+ return (0);
+}
+
+static PyObject *mcget_product(PyObject *me, void *hunoz)
+ { return (mp_pywrap(MP_COPY(MPCRT_PY(me)->mb.m))); }
+
+static PyObject *mcget_moduli(PyObject *me, void *hunoz)
+{
+ int i;
+ PyObject *q;
+ mpcrt *c = MPCRT_PY(me);
+
+ if ((q = PyList_New(c->k)) == 0) return (0);
+ for (i = 0; i < c->k; i++)
+ PyList_SetItem(q, i, mp_pywrap(c->v[i].m));
+ return (q);
+}
+
+static PyGetSetDef mpcrt_pygetset[] = {
+#define GETSETNAME(op, name) mc##op##_##name
+ GET (product, "C.product -> product of moduli")
+ GET (moduli, "C.moduli -> list of individual moduli")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyMethodDef mpcrt_pymethods[] = {
+#define METHNAME(name) mcmeth_##name
+ METH (solve, "C.solve([R0, R1]) -> X mod C.product")
+#undef METHNAME
+ { 0 }
+};
+
+static PyTypeObject *mpcrt_pytype, mpcrt_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.MPCRT", /* @tp_name@ */
+ sizeof(mpcrt_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ mpcrt_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"A context for the solution of Chinese Remainder Theorem problems.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ mpcrt_pymethods, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ mpcrt_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ mpcrt_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- Binary polynomials ------------------------------------------------*/
+
+static PyObject *gf_pyrepr(PyObject *o)
+ { return mp_topystring(MP_X(o), 16, "GF(", "0x", "L)"); }
+
+static PyObject *gf_pyrichcompare(PyObject *x, PyObject *y, int op)
+{
+ mp *xx, *yy;
+ int xl, yl;
+ int b;
+
+ if (mpbinop(x, y, &xx, &yy)) RETURN_NOTIMPL;
+ switch (op) {
+ case Py_EQ: b = MP_EQ(xx, yy); break;
+ case Py_NE: b = !MP_EQ(xx, yy); break;
+ default:
+ xl = mp_bits(xx);
+ yl = mp_bits(yy);
+ switch (op) {
+ case Py_LT: b = xl < yl; break;
+ case Py_LE: b = xl <= yl; break;
+ case Py_GT: b = xl > yl; break;
+ case Py_GE: b = xl >= yl; break;
+ default: abort();
+ }
+ break;
+ }
+ MP_DROP(xx); MP_DROP(yy);
+ return (getbool(b));
+}
+
+static PyObject *gf_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+{
+ PyObject *x;
+ mp *z;
+ mp_pyobj *zz = 0;
+ int radix = 0;
+ char *kwlist[] = { "x", "radix", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O|i:gf", kwlist, &x, &radix))
+ goto end;
+ if (GF_PYCHECK(x)) RETURN_OBJ(x);
+ if (radix < -255 || radix > 62) VALERR("radix out of range");
+ if ((z = mp_frompyobject(x, radix)) == 0) {
+ PyErr_Format(PyExc_TypeError, "can't convert %.100s to gf",
+ x->ob_type->tp_name);
+ goto end;
+ }
+ if (MP_NEGP(z)) {
+ MP_DROP(z);
+ VALERR("gf cannot be negative");
+ }
+ zz = (mp_pyobj *)ty->tp_alloc(ty, 0);
+ zz->x = z;
+end:
+ return ((PyObject *)zz);
+}
+
+static long gf_pyhash(PyObject *me)
+{
+ long i = mp_tolong(MP_X(me));
+ i ^= 0xc7ecd67c; /* random perturbance */
+ if (i == -1)
+ i = -2;
+ return (i);
+}
+
+static PyObject *gf_pyexp(PyObject *x, PyObject *y, PyObject *z)
+{
+ mp *xx = 0, *yy = 0, *zz = 0;
+ mp *r = 0;
+ PyObject *rc = 0;
+
+ if ((xx = tomp(x)) == 0 || (yy = tomp(y)) == 0 ||
+ (z && z != Py_None && (zz = tomp(z)) == 0)) {
+ mp_drop(xx); mp_drop(yy); mp_drop(zz);
+ RETURN_NOTIMPL;
+ }
+ if (!z || z == Py_None) {
+ if (MP_NEGP(yy)) VALERR("negative exponent");
+ r = gf_exp(MP_NEW, xx, yy);
+ } else {
+ gfreduce gr;
+ if (MP_ZEROP(zz)) ZDIVERR("zero modulus");
+ if (MP_NEGP(yy)) {
+ if ((xx = gf_modinv_checked(xx, xx, zz)) == 0) goto end;
+ yy = mp_neg(yy, yy);
+ }
+ gfreduce_create(&gr, zz);
+ r = gfreduce_exp(&gr, MP_NEW, xx, yy);
+ gfreduce_destroy(&gr);
+ }
+ rc = gf_pywrap(r);
+end:
+ mp_drop(xx); mp_drop(yy); mp_drop(zz);
+ return (rc);
+}
+
+static PyObject *gfmeth_sqr(PyObject *me, PyObject *arg)
+{
+ if (!PyArg_ParseTuple(arg, ":sqr")) return (0);
+ return (gf_pywrap(gf_sqr(MP_NEW, MP_X(me))));
+}
+
+static PyObject *gfmeth_gcd(PyObject *me, PyObject *arg)
+{
+ PyObject *z = 0;
+ mp *yy = 0, *zz = MP_NEW;
+
+ if (!PyArg_ParseTuple(arg, "O&:gcd", convgf, &yy)) goto end;
+ gf_gcd(&zz, 0, 0, MP_X(me), yy);
+ z = gf_pywrap(zz);
+end:
+ if (yy) MP_DROP(yy);
+ return (z);
+}
+
+static PyObject *gfmeth_gcdx(PyObject *me, PyObject *arg)
+{
+ PyObject *z = 0;
+ mp *yy = 0, *zz = MP_NEW, *uu = MP_NEW, *vv = MP_NEW;
+
+ if (!PyArg_ParseTuple(arg, "O&:gcdx", convgf, &yy))
+ goto end;
+ gf_gcd(&zz, &uu, &vv, MP_X(me), yy);
+ z = Py_BuildValue("(NNN)",
+ gf_pywrap(zz), gf_pywrap(uu), gf_pywrap(vv));
+end:
+ if (yy) MP_DROP(yy);
+ return (z);
+}
+
+static PyObject *gfmeth_modinv(PyObject *me, PyObject *arg)
+{
+ PyObject *z = 0;
+ mp *yy = 0, *zz = MP_NEW;
+
+ if (!PyArg_ParseTuple(arg, "O&:modinv", convgf, &yy) ||
+ (zz = gf_modinv_checked(MP_NEW, yy, MP_X(me))) == 0)
+ goto end;
+ z = gf_pywrap(zz);
+end:
+ if (yy) MP_DROP(yy);
+ return (z);
+}
+
+static PyObject *gfmeth_irreduciblep(PyObject *me, PyObject *arg)
+{
+ if (!PyArg_ParseTuple(arg, ":irreduciblep")) return (0);
+ return getbool(gf_irreduciblep(MP_X(me)));
+}
+
+static PyObject *gfget_degree(PyObject *me, void *hunoz)
+ { return (PyInt_FromLong(mp_bits(MP_X(me)) - 1)); }
+
+static PyGetSetDef gf_pygetset[] = {
+#define GETSETNAME(op, name) gf##op##_##name
+ GET (degree, "X.degree -> polynomial degree of X")
+#undef GETSETNAME
+#define GETSETNAME(op, name) mp##op##_##name
+ GET (nbits, "X.nbits -> bit length of X")
+ GET (noctets, "X.noctets -> octet length of X")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyMethodDef gf_pymethods[] = {
+#define METHNAME(func) gfmeth_##func
+ METH (setbit, "X.setbit(N) -> X with bit N set")
+ METH (clearbit, "X.clearbit(N) -> X with bit N clear")
+ METH (testbit, "X.testbit(N) -> true/false if bit N set/clear in X")
+ METH (sqr, "X.sqr() -> X^2")
+ METH (gcd, "X.gcd(Y) -> gcd(X, Y)")
+ METH (gcdx,
+ "X.gcdx(Y) -> (gcd(X, Y), U, V) with X U + Y V = gcd(X, Y)")
+ METH (modinv, "X.modinv(Y) -> multiplicative inverse of Y mod X")
+ METH (irreduciblep, "X.irreduciblep() -> true/false")
+#undef METHNAME
+#define METHNAME(func) mpmeth_##func
+ KWMETH(tostring, "X.tostring(radix = 10) -> STR")
+ KWMETH(storel, "X.storel(len = -1) -> little-endian bytes")
+ KWMETH(storeb, "X.storeb(len = -1) -> big-endian bytes")
+ KWMETH(storel2c,
+ "X.storel2c(len = -1) -> little-endian bytes, two's complement")
+ KWMETH(storeb2c,
+ "X.storeb2c(len = -1) -> big-endian bytes, two's complement")
+ METH (tobuf, "X.tobuf() -> buffer format")
+#undef METHNAME
+ { 0 }
+};
+
+static PyNumberMethods gf_pynumber = {
+ gf_pyadd, /* @nb_add@ */
+ gf_pysub, /* @nb_subtract@ */
+ gf_pymul, /* @nb_multiply@ */
+ 0, /* @nb_divide@ */
+ gf_pymod, /* @nb_remainder@ */
+ gf_pydivmod, /* @nb_divmod@ */
+ gf_pyexp, /* @nb_power@ */
+ mp_pyid, /* @nb_negative@ */
+ mp_pyid, /* @nb_positive@ */
+ mp_pyid, /* @nb_absolute@ */
+ mp_pynonzerop, /* @nb_nonzero@ */
+ 0 /* doesn't make any sense */, /* @nb_invert@ */
+ gf_pylsl, /* @nb_lshift@ */
+ gf_pylsr, /* @nb_rshift@ */
+ gf_pyand, /* @nb_and@ */
+ gf_pyxor, /* @nb_xor@ */
+ gf_pyor, /* @nb_or@ */
+ gf_pycoerce, /* @nb_coerce@ */
+ mp_pyint, /* @nb_int@ */
+ mp_pylong, /* @nb_long@ */
+ 0 /* doesn't make any sense */, /* @nb_float@ */
+ mp_pyoct, /* @nb_oct@ */
+ mp_pyhex, /* @nb_hex@ */
+
+ 0, /* @nb_inplace_add@ */
+ 0, /* @nb_inplace_subtract@ */
+ 0, /* @nb_inplace_multiply@ */
+ 0, /* @nb_inplace_divide@ */
+ 0, /* @nb_inplace_remainder@ */
+ 0, /* @nb_inplace_power@ */
+ 0, /* @nb_inplace_lshift@ */
+ 0, /* @nb_inplace_rshift@ */
+ 0, /* @nb_inplace_and@ */
+ 0, /* @nb_inplace_xor@ */
+ 0, /* @nb_inplace_or@ */
+
+ gf_pydiv, /* @nb_floor_divide@ */
+ 0, /* @nb_true_divide@ */
+ 0, /* @nb_inplace_floor_divide@ */
+ 0, /* @nb_inplace_true_divide@ */
+};
+
+static PyTypeObject gf_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.GF", /* @tp_name@ */
+ sizeof(mp_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ mp_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ gf_pyrepr, /* @tp_repr@ */
+ &gf_pynumber, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ gf_pyhash, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ mp_pyhex, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_CHECKTYPES |
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Binary polynomials. Support almost all the standard arithmetic\n\
+operations.\n\
+\n\
+Constructor gf(X, radix = R) attempts to convert X to a `gf'. If\n\
+X is a string, it's read in radix-R form, or we look for a prefix\n\
+if R = 0. Other acceptable things are ints and longs.\n\
+\n\
+The name is hopelessly wrong from a technical point of view, but\n\
+but it's much easier to type than `p2' or `c2' or whatever.\n\
+\n\
+Notes:\n\
+\n\
+ * Use `//' for division. GFs don't have `/' division.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ gf_pyrichcompare, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ gf_pymethods, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ gf_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ gf_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyObject *meth__GF_fromstring(PyObject *me,
+ PyObject *arg, PyObject *kw)
+{
+ int r = 0;
+ char *p;
+ int len;
+ PyObject *z = 0;
+ mp *zz;
+ mptext_stringctx sc;
+ char *kwlist[] = { "class", "x", "radix", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "Os#|i:fromstring",
+ kwlist, &me, &p, &len, &r))
+ goto end;
+ if (r < -255 || r > 62) VALERR("radix out of range");
+ sc.buf = p; sc.lim = p + len;
+ if ((zz = mp_read(MP_NEW, r, &mptext_stringops, &sc)) == 0 || MP_NEGP(zz))
+ z = Py_BuildValue("(Os#)", Py_None, p, len);
+ else
+ z = Py_BuildValue("(Ns#)", gf_pywrap(zz),
+ sc.buf, (int)(sc.lim - sc.buf));
+end:
+ return (z);
+}
+
+/*----- Sparse poly reduction ---------------------------------------------*/
+
+typedef struct gfreduce_pyobj {
+ PyObject_HEAD
+ gfreduce mr;
+} gfreduce_pyobj;
+
+#define GFREDUCE_PY(o) (&((gfreduce_pyobj *)(o))->mr)
+
+static PyObject *grmeth_exp(PyObject *me, PyObject *arg)
+{
+ PyObject *rc = 0;
+ mp *yy = 0, *zz = 0;
+
+ if (!PyArg_ParseTuple(arg, "O&O&:exp", convgf, &yy, convgf, &zz))
+ goto end;
+ if (MP_NEGP(zz)) {
+ if ((yy = gf_modinv_checked(yy, yy, GFREDUCE_PY(me)->p)) == 0) goto end;
+ zz = mp_neg(zz, zz);
+ }
+ rc = gf_pywrap(gfreduce_exp(GFREDUCE_PY(me), MP_NEW, yy, zz));
+end:
+ if (yy) MP_DROP(yy); if (zz) MP_DROP(zz);
+ return (rc);
+}
+
+static PyObject *grmeth_reduce(PyObject *me, PyObject *arg)
+{
+ PyObject *z = 0;
+ mp *yy = 0;
+
+ if (!PyArg_ParseTuple(arg, "O&:reduce", convgf, &yy)) goto end;
+ z = gf_pywrap(gfreduce_do(GFREDUCE_PY(me), MP_NEW, yy));
+end:
+ return (z);
+}
+
+static void gfreduce_pydealloc(PyObject *me)
+{
+ gfreduce_destroy(GFREDUCE_PY(me));
+ PyObject_DEL(me);
+}
+
+static PyObject *gfreduce_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+{
+ gfreduce_pyobj *mr = 0;
+ gfreduce r;
+ char *kwlist[] = { "m", 0 };
+ mp *xx = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:new", kwlist, convgf, &xx))
+ goto end;
+ if (MP_ZEROP(xx)) ZDIVERR("modulus is zero!");
+ gfreduce_create(&r, xx);
+ mr = (gfreduce_pyobj *)ty->tp_alloc(ty, 0);
+ mr->mr = r;
+end:
+ if (xx) MP_DROP(xx);
+ return ((PyObject *)mr);
+}
+
+static PyObject *grget_m(PyObject *me, void *hunoz)
+ { return (gf_pywrap(MP_COPY(GFREDUCE_PY(me)->p))); }
+
+static PyGetSetDef gfreduce_pygetset[] = {
+#define GETSETNAME(op, name) gr##op##_##name
+ GET (m, "R.m -> reduction polynomial")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyMethodDef gfreduce_pymethods[] = {
+#define METHNAME(name) grmeth_##name
+ METH (reduce, "R.reduce(X) -> X mod B.m")
+ METH (exp, "R.exp(X, N) -> X^N mod B.m")
+#undef METHNAME
+ { 0 }
+};
+
+static PyTypeObject *gfreduce_pytype, gfreduce_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.GFReduce", /* @tp_name@ */
+ sizeof(gfreduce_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ gfreduce_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"A reduction context for reduction modulo sparse irreducible polynomials.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ gfreduce_pymethods, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ gfreduce_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ gfreduce_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- Normal/poly transformation ----------------------------------------*/
+
+typedef struct gfn_pyobj {
+ PyObject_HEAD
+ mp *p;
+ gfn ntop, pton;
+} gfn_pyobj;
+
+static PyTypeObject *gfn_pytype, gfn_pytype_skel;
+
+#define GFN_P(o) (((gfn_pyobj *)(o))->p)
+#define GFN_PTON(o) (&((gfn_pyobj *)(o))->pton)
+#define GFN_NTOP(o) (&((gfn_pyobj *)(o))->ntop)
+
+static PyObject *gfn_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+{
+ mp *p = 0, *beta = 0;
+ gfn_pyobj *gg = 0;
+ char *kwlist[] = { "p", "beta", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&:new", kwlist,
+ convgf, &p, convgf, &beta))
+ goto end;
+ gg = PyObject_New(gfn_pyobj, ty);
+ if (gfn_create(p, beta, &gg->ntop, &gg->pton)) {
+ PyObject_DEL(gg);
+ gg = 0;
+ VALERR("can't invert transformation matrix");
+ }
+ gg->p = MP_COPY(p);
+end:
+ mp_drop(p);
+ mp_drop(beta);
+ return ((PyObject *)gg);
+}
+
+static PyObject *gfnget_p(PyObject *me, void *hunoz)
+ { return (gf_pywrap(MP_COPY(GFN_P(me)))); }
+
+static PyObject *gfnget_beta(PyObject *me, void *hunoz)
+{
+ gfn *n = GFN_NTOP(me);
+ mp *x = n->r[n->n - 1];
+ return (gf_pywrap(MP_COPY(x)));
+}
+
+#define XFORMOP(name, NAME) \
+ static PyObject *gfnmeth_##name(PyObject *me, PyObject *arg) \
+ { \
+ mp *xx = 0; \
+ mp *z = 0; \
+ \
+ if (!PyArg_ParseTuple(arg, "O&:" #name, convgf, &xx)) goto end; \
+ z = gfn_transform(GFN_##NAME(me), MP_NEW, xx); \
+ end: \
+ mp_drop(xx); \
+ if (!z) return (0); \
+ return (mp_pywrap(z)); \
+ }
+XFORMOP(pton, PTON)
+XFORMOP(ntop, NTOP)
+#undef XFORMOP
+
+static void gfn_pydealloc(PyObject *me)
+{
+ gfn_destroy(GFN_PTON(me));
+ gfn_destroy(GFN_NTOP(me));
+ PyObject_DEL(me);
+}
+
+static PyGetSetDef gfn_pygetset[] = {
+#define GETSETNAME(op, name) gfn##op##_##name
+ GET (p, "X.p -> polynomial basis, as polynomial")
+ GET (beta, "X.beta -> normal basis element, in poly form")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyMethodDef gfn_pymethods[] = {
+#define METHNAME(name) gfnmeth_##name
+ METH (pton, "X.pton(A) -> normal-basis representation of A")
+ METH (ntop, "X.ntop(A) -> polynomial-basis representation of A")
+#undef METHNAME
+ { 0 }
+};
+
+static PyTypeObject gfn_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.GFN", /* @tp_name@ */
+ sizeof(gfn_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ gfn_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"An object for transforming elements of binary fields between polynomial\n\
+and normal basis representations.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ gfn_pymethods, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ gfn_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ gfn_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- Glue --------------------------------------------------------------*/
+
+static PyMethodDef methods[] = {
+#define METHNAME(func) meth_##func
+ KWMETH(_MP_fromstring, "\
+fromstring(STR, radix = 0) -> (X, REST)\n\
+\n\
+Parse STR as a large integer, according to radix. If radix is zero,\n\
+read a prefix from STR to decide radix: allow `0' for octal, `0x' for hex\n\
+or `R_' for other radix R.")
+ KWMETH(_GF_fromstring, "\
+fromstring(STR, radix = 0) -> (X, REST)\n\
+\n\
+Parse STR as a binary polynomial, according to radix. If radix is zero,\n\
+read a prefix from STR to decide radix: allow `0' for octal, `0x' for hex\n\
+or `R_' for other radix R.")
+ METH (_MP_loadl, "\
+loadl(STR) -> X: read little-endian bytes")
+ METH (_MP_loadb, "\
+loadb(STR) -> X: read big-endian bytes")
+ METH (_MP_loadl2c, "\
+loadl2c(STR) -> X: read little-endian bytes, two's complement")
+ METH (_MP_loadb2c, "\
+loadb2c(STR) -> X: read big-endian bytes, two's complement")
+ METH (_MP_frombuf, "\
+frombuf(STR) -> (X, REST): read buffer format")
+ METH (_MP_product, "\
+product(ITER) -> X: product of things iterated over")
+ METH (_GF_loadl, "\
+loadl(STR) -> X: read little-endian bytes")
+ METH (_GF_loadb, "\
+loadb(STR) -> X: read big-endian bytes")
+ METH (_GF_frombuf, "\
+frombuf(STR) -> (X, REST): read buffer format")
+#undef METHNAME
+ { 0 }
+};
+
+void mp_pyinit(void)
+{
+ INITTYPE(mp, root);
+ INITTYPE(gf, root);
+ INITTYPE(mpmont, root);
+ INITTYPE(mpbarrett, root);
+ INITTYPE(mpreduce, root);
+ INITTYPE(mpcrt, root);
+ INITTYPE(gfreduce, root);
+ INITTYPE(gfn, root);
+ addmethods(methods);
+}
+
+void mp_pyinsert(PyObject *mod)
+{
+ INSERT("MP", mp_pytype);
+ INSERT("MPMont", mpmont_pytype);
+ INSERT("MPBarrett", mpbarrett_pytype);
+ INSERT("MPReduce", mpreduce_pytype);
+ INSERT("MPCRT", mpcrt_pytype);
+ INSERT("GF", gf_pytype);
+ INSERT("GFReduce", gfreduce_pytype);
+ INSERT("GFN", gfn_pytype);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id$
+ *
+ * Reading and writing passphrases
+ *
+ * (c) 2005 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of the Python interface to Catacomb.
+ *
+ * Catacomb/Python is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb/Python is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Catacomb/Python; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "catacomb-python.h"
+
+/*----- Pixie stuff -------------------------------------------------------*/
+
+typedef struct pixie_pyobj {
+ PyObject_HEAD
+ int fd;
+} pixie_pyobj;
+
+static PyTypeObject *pixie_pytype;
+#define PIXIE_PYCHECK(o) PyObject_TypeCheck((o), pixie_pytype)
+#define PIXIE_FD(o) (((pixie_pyobj *)(o))->fd)
+
+static int convpixie(PyObject *o, void *p)
+{
+ if (!PIXIE_PYCHECK(o))
+ TYERR("want pixie");
+ *(int *)p = PIXIE_FD(o);
+ return (1);
+end:
+ return (0);
+}
+
+static PyObject *pixie_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+{
+ pixie_pyobj *rc = 0;
+ char *kwlist[] = { "socket", 0 };
+ char *sock = 0;
+ int fd;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|s:new", kwlist, &sock))
+ goto end;
+ if ((fd = pixie_open(sock)) < 0)
+ OSERR(sock);
+ rc = (pixie_pyobj *)ty->tp_alloc(ty, 0);
+ rc->fd = fd;
+end:
+ return ((PyObject *)rc);
+}
+
+static void pixie_pydealloc(PyObject *me)
+{
+ close(PIXIE_FD(me));
+ PyObject_DEL(me);
+
+}
+
+static PyObject *pixmeth_read(PyObject *me, PyObject *arg, PyObject *kw)
+{
+ unsigned mode = PMODE_READ;
+ char *tag;
+ char *kwlist[] = { "tag", "mode", 0 };
+ PyObject *rc = 0;
+ int r;
+ char buf[1024];
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s|O&:read", kwlist,
+ &tag, convuint, &mode))
+ goto end;
+ r = pixie_read(PIXIE_FD(me), tag, mode, buf, sizeof(buf));
+ if (r < 0)
+ OSERR(0);
+ else if (r > 0)
+ RETURN_NONE;
+ else
+ rc = PyString_FromString(buf);
+end:
+ return (rc);
+}
+
+static PyObject *pixmeth_set(PyObject *me, PyObject *arg)
+{
+ char *tag;
+ char *phrase;
+
+ if (!PyArg_ParseTuple(arg, "ss:set", &tag, &phrase))
+ return (0);
+ pixie_set(PIXIE_FD(me), tag, phrase);
+ RETURN_ME;
+}
+
+static PyObject *pixmeth_cancel(PyObject *me, PyObject *arg)
+{
+ char *tag;
+
+ if (!PyArg_ParseTuple(arg, "s:cancel", &tag))
+ return (0);
+ pixie_cancel(PIXIE_FD(me), tag);
+ RETURN_ME;
+}
+
+static PyMethodDef pixie_pymethods[] = {
+#define METHNAME(name) pixmeth_##name
+ KWMETH(read, "P.read(TAG, [mode = PMODE_READ]) -> STRING")
+ METH (set, "P.set(TAG, PHRASE)")
+ METH (cancel, "P.cancel(TAG)")
+#undef METHNAME
+ { 0 }
+};
+
+static PyTypeObject pixie_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.Pixie", /* @tp_name@ */
+ sizeof(pixie_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ pixie_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Passphrase pixie connection.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ pixie_pymethods, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ 0, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ pixie_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- Main code ---------------------------------------------------------*/
+
+static PyObject *meth_ppread(PyObject *me, PyObject *arg, PyObject *kw)
+{
+ char *tag;
+ unsigned f = PMODE_READ;
+ PyObject *rc = 0;
+ char *kwlist[] = { "tag", "mode", 0 };
+ char buf[1024];
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s|O&:ppread", kwlist,
+ &tag, convuint, &f))
+ goto end;
+ if (passphrase_read(tag, f, buf, sizeof(buf)))
+ SYSERR("passphrase read failed");
+ rc = PyString_FromString(buf);
+end:
+ return (rc);
+}
+
+static PyObject *meth_ppcancel(PyObject *me, PyObject *arg)
+{
+ char *tag;
+
+ if (!PyArg_ParseTuple(arg, "s:ppcancel", &tag))
+ return (0);
+ passphrase_cancel(tag);
+ RETURN_NONE;
+}
+
+static PyObject *meth_getpass(PyObject *me, PyObject *arg)
+{
+ char *prompt;
+ char buf[1024];
+ PyObject *rc = 0;
+
+ if (!PyArg_ParseTuple(arg, "s:getpass", &prompt))
+ goto end;
+ if (pixie_getpass(prompt, buf, sizeof(buf)))
+ OSERR(0);
+ rc = PyString_FromString(buf);
+end:
+ return (rc);
+}
+
+static PyMethodDef methods[] = {
+#define METHNAME(name) meth_##name
+ KWMETH(ppread, "ppread(TAG, [mode = PMODE_READ]) -> STRING")
+ METH (ppcancel, "ppcancel(TAG)")
+ METH (getpass, "getpass(PROMPT) -> STRING")
+#undef METHNAME
+ { 0 }
+};
+
+void passphrase_pyinit(void)
+{
+ INITTYPE(pixie, root);
+ addmethods(methods);
+}
+
+void passphrase_pyinsert(PyObject *mod)
+{
+ INSERT("Pixie", pixie_pytype);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id$
+ *
+ * Prime number generation
+ *
+ * (c) 2005 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of the Python interface to Catacomb.
+ *
+ * Catacomb/Python is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb/Python is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Catacomb/Python; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "catacomb-python.h"
+
+/*----- Filters -----------------------------------------------------------*/
+
+PyTypeObject *pfilt_pytype;
+
+static PyObject *pfilt_pywrap(pfilt *f)
+{
+ pfilt_pyobj *o = 0;
+ o = PyObject_New(pfilt_pyobj, pfilt_pytype);
+ o->f = *f;
+ o->st = pfilt_step(f, 0);
+ return ((PyObject *)o);
+}
+
+static PyObject *pfilt_pymake(PyTypeObject *ty, PyObject *xobj)
+{
+ mp *x = 0;
+ pfilt_pyobj *o = 0;
+
+ if (PFILT_PYCHECK(xobj)) RETURN_OBJ(xobj);
+ if ((x = getmp(xobj)) == 0) goto end;
+ o = (pfilt_pyobj *)ty->tp_alloc(ty, 0);
+ o->st = pfilt_create(&o->f, x);
+end:
+ mp_drop(x);
+ return ((PyObject *)o);
+}
+
+static PyObject *pfilt_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+{
+ char *kwlist[] = { "x", 0 };
+ PyObject *xobj;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O:new", kwlist, &xobj))
+ return (0);
+ return (pfilt_pymake(ty, xobj));
+}
+
+static void pfilt_pydealloc(PyObject *me)
+ { pfilt_destroy(PFILT_F(me)); PyObject_DEL(me); }
+
+static PyObject *pfmeth_step(PyObject *me, PyObject *arg)
+{
+ mpw x;
+
+ if (!PyArg_ParseTuple(arg, "O&:step", convmpw, &x)) return (0);
+ PFILT_ST(me) = pfilt_step(PFILT_F(me), x);
+ RETURN_ME;
+}
+
+static PyObject *pfmeth_muladd(PyObject *me, PyObject *arg)
+{
+ mpw m, a;
+ pfilt_pyobj *o = 0;
+
+ if (!PyArg_ParseTuple(arg, "O&O&:muladd", convmpw, &m, convmpw, &a))
+ return (0);
+ o = PyObject_New(pfilt_pyobj, pfilt_pytype);
+ o->st = pfilt_muladd(&o->f, PFILT_F(me), m, a);
+ return ((PyObject *)o);
+}
+
+static CONVFUNC(pfilt, pfilt *, PFILT_F)
+
+static PyObject *pfmeth_jump(PyObject *me, PyObject *arg)
+{
+ pfilt *f;
+
+ if (!PyArg_ParseTuple(arg, "O&:jump", convpfilt, &f)) return (0);
+ PFILT_ST(me) = pfilt_jump(PFILT_F(me), f);
+ RETURN_ME;
+}
+
+static PyObject *meth__PrimeFilter_smallfactor(PyObject *me, PyObject *arg)
+{
+ mp *x = 0;
+ PyObject *rc = 0;
+
+ if (!PyArg_ParseTuple(arg, "OO&:smallfactor", &me, convmp, &x)) goto end;
+ rc = PyInt_FromLong(pfilt_smallfactor(x));
+end:
+ mp_drop(x);
+ return (rc);
+}
+
+static int pfilt_pynonzerop(PyObject *me)
+ { return (PFILT_ST(me) != PGEN_FAIL); }
+
+static PyObject *pfilt_pyint(PyObject *me)
+{
+ long l;
+ PyObject *rc = 0;
+
+ if (mp_tolong_checked(PFILT_F(me)->m, &l)) goto end;
+ rc = PyInt_FromLong(l);
+end:
+ return (rc);
+}
+
+static PyObject *pfilt_pylong(PyObject *me)
+ { return ((PyObject *)mp_topylong(PFILT_F(me)->m)); }
+
+static PyObject *pfget_x(PyObject *me, void *hunoz)
+ { return (mp_pywrap(MP_COPY(PFILT_F(me)->m))); }
+
+static PyObject *pfget_status(PyObject *me, void *hunoz)
+ { return (PyInt_FromLong(PFILT_ST(me))); }
+
+static PyGetSetDef pfilt_pygetset[] = {
+#define GETSETNAME(op, name) pf##op##_##name
+ GET (x, "F.x -> current position of filter")
+ GET (status, "F.status -> primality status of filter")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyMethodDef pfilt_pymethods[] = {
+#define METHNAME(name) pfmeth_##name
+ METH (step, "F.step(N)")
+ METH (muladd, "F.muladd(M, A)")
+ METH (jump, "F.jump(FF)")
+#undef METHNAME
+ { 0 }
+};
+
+static PyNumberMethods pfilt_pynumber = {
+ 0, /* @nb_add@ */
+ 0, /* @nb_subtract@ */
+ 0, /* @nb_multiply@ */
+ 0, /* @nb_divide@ */
+ 0, /* @nb_remainder@ */
+ 0, /* @nb_divmod@ */
+ 0, /* @nb_power@ */
+ 0, /* @nb_negative@ */
+ 0, /* @nb_positive@ */
+ 0, /* @nb_absolute@ */
+ pfilt_pynonzerop, /* @nb_nonzero@ */
+ 0, /* @nb_invert@ */
+ 0, /* @nb_lshift@ */
+ 0, /* @nb_rshift@ */
+ 0, /* @nb_and@ */
+ 0, /* @nb_xor@ */
+ 0, /* @nb_or@ */
+ 0, /* @nb_coerce@ */
+ pfilt_pyint, /* @nb_int@ */
+ pfilt_pylong, /* @nb_long@ */
+ 0, /* @nb_float@ */
+ 0, /* @nb_oct@ */
+ 0, /* @nb_hex@ */
+
+ 0, /* @nb_inplace_add@ */
+ 0, /* @nb_inplace_subtract@ */
+ 0, /* @nb_inplace_multiply@ */
+ 0, /* @nb_inplace_divide@ */
+ 0, /* @nb_inplace_remainder@ */
+ 0, /* @nb_inplace_power@ */
+ 0, /* @nb_inplace_lshift@ */
+ 0, /* @nb_inplace_rshift@ */
+ 0, /* @nb_inplace_and@ */
+ 0, /* @nb_inplace_xor@ */
+ 0, /* @nb_inplace_or@ */
+
+ 0, /* @nb_floor_divide@ */
+ 0, /* @nb_true_divide@ */
+ 0, /* @nb_inplace_floor_divide@ */
+ 0, /* @nb_inplace_true_divide@ */
+};
+
+static PyTypeObject pfilt_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.PrimeFilter", /* @tp_name@ */
+ sizeof(pfilt_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ pfilt_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ &pfilt_pynumber, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Small-primes filter.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ pfilt_pymethods, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ pfilt_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ pfilt_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- Rabin-Miller testing ----------------------------------------------*/
+
+typedef struct rabin_pyobj {
+ PyObject_HEAD
+ rabin r;
+} rabin_pyobj;
+
+static PyTypeObject *rabin_pytype;
+#define RABIN_R(o) (&((rabin_pyobj *)(o))->r)
+
+static PyObject *rabin_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+{
+ mp *x = 0;
+ rabin_pyobj *o = 0;
+ char *kwlist[] = { "x", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:new", kwlist, convmp, &x))
+ goto end;
+ if (!MP_POSP(x) || MP_EVENP(x)) VALERR("must be positive and odd");
+ o = (rabin_pyobj *)ty->tp_alloc(ty, 0);
+ rabin_create(&o->r, x);
+end:
+ return ((PyObject *)o);
+}
+
+static void rabin_pydealloc(PyObject *me)
+{
+ rabin_destroy(RABIN_R(me));
+ PyObject_DEL(me);
+}
+
+static PyObject *rmeth_test(PyObject *me, PyObject *arg)
+{
+ mp *w = 0;
+ PyObject *rc = 0;
+
+ if (!PyArg_ParseTuple(arg, "O&:test", convmp, &w)) goto end;
+ rc = PyInt_FromLong(rabin_test(RABIN_R(me), w));
+end:
+ mp_drop(w);
+ return (rc);
+}
+
+static PyObject *rmeth_rtest(PyObject *me, PyObject *arg)
+{
+ mp *w = 0;
+ PyObject *rc = 0;
+
+ if (!PyArg_ParseTuple(arg, "O&:rtest", convmp, &w)) goto end;
+ rc = PyInt_FromLong(rabin_rtest(RABIN_R(me), w));
+end:
+ mp_drop(w);
+ return (rc);
+}
+
+static PyObject *rget_niters(PyObject *me, void *hunoz)
+ { return (PyInt_FromLong(rabin_iters(mp_bits(RABIN_R(me)->mm.m)))); }
+
+static PyObject *rget_x(PyObject *me, void *hunoz)
+ { return (mp_pywrap(MP_COPY(RABIN_R(me)->mm.m))); }
+
+static PyObject *meth__RabinMiller_iters(PyObject *me, PyObject *arg)
+{
+ unsigned n;
+
+ if (!PyArg_ParseTuple(arg, "OO&:iters", &me, convuint, &n)) return (0);
+ return (PyInt_FromLong(rabin_iters(n)));
+}
+
+static PyGetSetDef rabin_pygetset[] = {
+#define GETSETNAME(op, name) r##op##_##name
+ GET (x, "R.x -> number under test")
+ GET (niters, "R.niters -> suggested number of tests")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyMethodDef rabin_pymethods[] = {
+#define METHNAME(name) rmeth_##name
+ METH (test, "R.test(W) -> PGST")
+ METH (rtest, "R.rtest(W) -> PGST")
+#undef METHNAME
+ { 0 }
+};
+
+static PyTypeObject rabin_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.RabinMiller", /* @tp_name@ */
+ sizeof(rabin_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ rabin_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Rabin-Miller strong primality test.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ rabin_pymethods, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ rabin_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ rabin_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- Events ------------------------------------------------------------*/
+
+typedef struct pgevent_pyobj {
+ PyObject_HEAD
+ pgen_event *ev;
+} pgevent_pyobj;
+
+static PyTypeObject *pgevent_pytype;
+#define PGEVENT_EV(o) (((pgevent_pyobj *)(o))->ev)
+
+static PyObject *pgevent_pywrap(pgen_event *ev)
+{
+ pgevent_pyobj *o = PyObject_New(pgevent_pyobj, pgevent_pytype);
+ o->ev = ev;
+ return ((PyObject *)o);
+}
+
+static CONVFUNC(pgevent, pgen_event *, PGEVENT_EV)
+
+static void pgevent_kill(PyObject *me) { PGEVENT_EV(me) = 0; }
+static void pgevent_pydealloc(PyObject *me) { PyObject_DEL(me); }
+
+#define PGEVENT_CHECK(me) do { \
+ if (!PGEVENT_EV(me)) { \
+ PyErr_SetString(PyExc_ValueError, "event object is dead"); \
+ return (0); \
+ } \
+} while (0)
+
+static PyObject *peget_name(PyObject *me, void *hunoz)
+ { PGEVENT_CHECK(me); return (PyString_FromString(PGEVENT_EV(me)->name)); }
+
+static PyObject *peget_x(PyObject *me, void *hunoz)
+ { PGEVENT_CHECK(me); return (mp_pywrap(MP_COPY(PGEVENT_EV(me)->m))); }
+
+static PyObject *peget_steps(PyObject *me, void *hunoz)
+ { PGEVENT_CHECK(me); return (PyInt_FromLong(PGEVENT_EV(me)->steps)); }
+
+static PyObject *peget_tests(PyObject *me, void *hunoz)
+ { PGEVENT_CHECK(me); return (PyInt_FromLong(PGEVENT_EV(me)->tests)); }
+
+static PyObject *peget_rng(PyObject *me, void *hunoz)
+ { PGEVENT_CHECK(me); return (grand_pywrap(PGEVENT_EV(me)->r, 0)); }
+
+static int peset_x(PyObject *me, PyObject *xobj, void *hunoz)
+{
+ mp *x = 0;
+ pgen_event *ev = PGEVENT_EV(me);
+ int rc = -1;
+ PGEVENT_CHECK(me);
+ if ((x = getmp(xobj)) == 0) goto end;
+ mp_drop(ev->m);
+ ev->m = MP_COPY(x);
+ rc = 0;
+end:
+ mp_drop(x);
+ return (rc);
+}
+
+static PyGetSetDef pgevent_pygetset[] = {
+#define GETSETNAME(op, name) pe##op##_##name
+ GET (name, "EV.name -> value being generated")
+ GETSET(x, "EV.x -> value under test")
+ GET (steps, "EV.steps -> number of steps left")
+ GET (tests, "EV.tests -> tests before passing")
+ GET (rng, "EV.rng -> (noncrypto) random number generator")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyTypeObject pgevent_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.PrimeGenEvent", /* @tp_name@ */
+ sizeof(pgevent_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ pgevent_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Prime-generation event.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ pgevent_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ abstract_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- Event handlers ----------------------------------------------------*/
+
+PyTypeObject *pgev_pytype;
+
+typedef struct pgstep_pyobj {
+ PGEV_HEAD
+ pgen_filterctx f;
+} pgstep_pyobj;
+
+static PyTypeObject *pgstep_pytype;
+#define PGSTEP_STEP(o) (((pgstep_pyobj *)(o))->f.step)
+
+typedef struct pgjump_pyobj {
+ PGEV_HEAD
+ PyObject *fobj;
+ pgen_jumpctx j;
+} pgjump_pyobj;
+
+static PyTypeObject *pgjump_pytype;
+#define PGJUMP_FOBJ(o) (((pgjump_pyobj *)(o))->fobj)
+#define PGJUMP_J(o) (&((pgjump_pyobj *)(o))->j)
+
+typedef struct pgtest_pyobj {
+ PGEV_HEAD
+ rabin r;
+} pgtest_pyobj;
+
+static PyTypeObject *pgtest_pytype;
+
+static int pgev_python(int rq, pgen_event *ev, void *p)
+{
+ PyObject *py = p;
+ PyObject *pyev = 0;
+ PyObject *rc = 0;
+ int st = PGEN_ABORT;
+ long l;
+ char *meth[] = {
+ "pg_abort", "pg_done", "pg_begin", "pg_try", "pg_fail", "pg_pass"
+ };
+
+ Py_INCREF(py);
+ rq++;
+ if (rq > N(meth)) SYSERR("event code out of range");
+ pyev = pgevent_pywrap(ev);
+ if ((rc = PyObject_CallMethod(py, meth[rq], "(O)", pyev)) == 0)
+ goto end;
+ if (rc == Py_None)
+ st = PGEN_TRY;
+ else if ((l = PyInt_AsLong(rc)) == -1 && PyErr_Occurred())
+ goto end;
+ else if (l < PGEN_ABORT || l > PGEN_PASS)
+ VALERR("return code out of range");
+ else
+ st = l;
+end:
+ if (pyev) {
+ pgevent_kill(pyev);
+ Py_DECREF(pyev);
+ }
+ Py_XDECREF(rc);
+ Py_DECREF(py);
+ return (st);
+}
+
+static PyObject *pgev_pywrap(const pgev *pg)
+{
+ pgev_pyobj *o;
+
+ o = PyObject_New(pgev_pyobj, pgev_pytype);
+ o->pg = *pg;
+ return ((PyObject *)o);
+}
+
+int convpgev(PyObject *o, void *p)
+{
+ pgev *pg = p;
+
+ if (PGEV_PYCHECK(o))
+ *pg = *PGEV_PG(o);
+ else {
+ pg->proc = pgev_python;
+ pg->ctx = o;
+ Py_INCREF(o);
+ }
+ return (1);
+}
+
+void droppgev(pgev *p)
+{
+ if (p->proc == pgev_python) {
+ PyObject *py = p->ctx;
+ Py_DECREF(py);
+ }
+}
+
+static PyObject *pgmeth_common(PyObject *me, PyObject *arg, int rq)
+{
+ pgen_event *ev;
+ pgev *pg = PGEV_PG(me);
+ PyObject *rc = 0;
+
+ if (!PyArg_ParseTuple(arg, "O&", convpgevent, &ev)) goto end;
+ rc = PyInt_FromLong(!pg->proc ? rq : pg->proc(rq, ev, pg->ctx));
+end:
+ return (rc);
+}
+
+#define PGMETH(lc, uc) \
+ static PyObject *pgmeth_pg_##lc(PyObject *me, PyObject *arg) \
+ { return pgmeth_common(me, arg, PGEN_##uc); }
+PGMETH(abort, ABORT)
+PGMETH(done, DONE)
+PGMETH(begin, BEGIN)
+PGMETH(try, TRY)
+PGMETH(pass, PASS)
+PGMETH(fail, FAIL)
+#undef PGMETH
+
+static PyObject *pgev_stdev(pgen_proc *proc)
+ { pgev pg; pg.proc = proc; pg.ctx = 0; return (pgev_pywrap(&pg)); }
+
+static PyMethodDef pgev_pymethods[] = {
+#define METHNAME(name) pgmeth_##name
+ METH (pg_abort, "E.pg_abort() -> PGRC -- prime generation aborted")
+ METH (pg_done, "E.pg_done() -> PGRC -- prime generation finished")
+ METH (pg_begin, "E.pg_begin() -> PGRC -- commence stepping/testing")
+ METH (pg_try, "E.pg_try() -> PGRC -- found new candidate")
+ METH (pg_pass, "E.pg_pass() -> PGRC -- passed primality test")
+ METH (pg_fail, "E.pg_fail() -> PGRC -- failed primality test")
+#undef METHNAME
+ { 0 }
+};
+
+static PyTypeObject pgev_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.PrimeGenBuiltinHandler", /* @tp_name@ */
+ sizeof(pgev_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ _PyObject_Del, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Built-in prime-generation event handler, base class.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ pgev_pymethods, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ 0, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ abstract_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyObject *pgstep_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+{
+ mpw s;
+ pgstep_pyobj *rc = 0;
+ char *kwlist[] = { "step", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:new", kwlist, convmpw, &s))
+ goto end;
+ rc = (pgstep_pyobj *)ty->tp_alloc(ty, 0);
+ rc->f.step = s;
+ rc->pg.proc = pgen_filter;
+ rc->pg.ctx = &rc->f;
+end:
+ return ((PyObject *)rc);
+}
+
+static PyObject *psget_step(PyObject *me, void *hunoz)
+ { return (PyInt_FromLong(PGSTEP_STEP(me))); }
+
+static PyGetSetDef pgstep_pygetset[] = {
+#define GETSETNAME(op, name) ps##op##_##name
+ GET (step, "S.step -> step size for the stepper")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyTypeObject pgstep_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.PrimeGenStepper", /* @tp_name@ */
+ sizeof(pgstep_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ 0, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+ "Simple prime-number stepper with small-factors filter.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ pgstep_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ pgstep_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyObject *pgjump_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+{
+ PyObject *o, *fobj;
+ pgjump_pyobj *rc = 0;
+ char *kwlist[] = { "jump", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O:new", kwlist, &o) ||
+ (fobj = pfilt_pymake(pfilt_pytype, o)) == 0)
+ goto end;
+ rc = (pgjump_pyobj *)ty->tp_alloc(ty, 0);
+ rc->fobj = fobj;
+ rc->j.j = PFILT_F(fobj);
+ rc->pg.proc = pgen_jump;
+ rc->pg.ctx = &rc->j;
+end:
+ return ((PyObject *)rc);
+}
+
+static void pgjump_pydealloc(PyObject *me)
+{
+ Py_DECREF(PGJUMP_FOBJ(me));
+ _PyObject_Del(me);
+}
+
+static PyObject *pjget_jump(PyObject *me, void *hunoz)
+ { RETURN_OBJ(PGJUMP_FOBJ(me)); }
+
+static PyGetSetDef pgjump_pygetset[] = {
+#define GETSETNAME(op, name) pj##op##_##name
+ GET (jump, "S.jump -> jump size for the stepper")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyTypeObject pgjump_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.PrimeGenJumper", /* @tp_name@ */
+ sizeof(pgjump_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ pgjump_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Stepper for larger steps, with small-factors filter.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ pgjump_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ pgjump_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyObject *pgtest_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+{
+ pgtest_pyobj *rc = 0;
+ char *kwlist[] = { 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, ":new", kwlist)) goto end;
+ rc = (pgtest_pyobj *)ty->tp_alloc(ty, 0);
+ rc->pg.proc = pgen_test;
+ rc->pg.ctx = &rc->r;
+end:
+ return ((PyObject *)rc);
+}
+
+static PyTypeObject pgtest_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.PrimeGenTester", /* @tp_name@ */
+ sizeof(pgtest_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ 0, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Rabin-Miller tester.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ 0, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ pgtest_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- Prime generation functions ----------------------------------------*/
+
+void pgenerr(void)
+{
+ if (!PyErr_Occurred())
+ PyErr_SetString(PyExc_ValueError, "prime generation failed");
+}
+
+static PyObject *meth_pgen(PyObject *me, PyObject *arg, PyObject *kw)
+{
+ mp *x = 0;
+ mp *r = 0;
+ PyObject *rc = 0;
+ char *p = "p";
+ pgen_filterctx fc = { 2 };
+ rabin tc;
+ pgev step = { 0 }, test = { 0 }, evt = { 0 };
+ unsigned nsteps = 0, ntests = 0;
+ char *kwlist[] = { "start", "name", "stepper", "tester", "event",
+ "nsteps", "ntests", 0 };
+
+ step.proc = pgen_filter; step.ctx = &fc;
+ test.proc = pgen_test; test.ctx = &tc;
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|sO&O&O&O&O&:pgen", kwlist,
+ convmp, &x, &p, convpgev, &step,
+ convpgev, &test, convpgev, &evt,
+ convuint, &nsteps, convuint, &ntests))
+ goto end;
+ if (!ntests) ntests = rabin_iters(mp_bits(x));
+ if ((r = pgen(p, MP_NEW, x, evt.proc, evt.ctx,
+ nsteps, step.proc, step.ctx,
+ ntests, test.proc, test.ctx)) == 0)
+ PGENERR;
+ if (PyErr_Occurred()) goto end;
+ rc = mp_pywrap(r);
+ r = 0;
+end:
+ mp_drop(r); mp_drop(x);
+ droppgev(&step); droppgev(&test); droppgev(&evt);
+ return (rc);
+}
+
+static PyObject *meth_strongprime_setup(PyObject *me,
+ PyObject *arg, PyObject *kw)
+{
+ mp *x = 0;
+ pfilt f;
+ grand *r = &rand_global;
+ unsigned nbits;
+ char *name = "p";
+ unsigned n = 0;
+ pgev evt = { 0 };
+ PyObject *rc = 0;
+ char *kwlist[] = { "nbits", "name", "event", "rng", "nsteps", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|sO&O&O&", kwlist,
+ convuint, &nbits, &name,
+ convpgev, &evt, convgrand, &r,
+ convuint, &n))
+ goto end;
+ if ((x = strongprime_setup(name, MP_NEW, &f, nbits,
+ r, n, evt.proc, evt.ctx)) == 0)
+ PGENERR;
+ rc = Py_BuildValue("(NN)", mp_pywrap(x), pfilt_pywrap(&f));
+ x = 0;
+end:
+ mp_drop(x);
+ droppgev(&evt);
+ return (rc);
+}
+
+static PyObject *meth_strongprime(PyObject *me, PyObject *arg, PyObject *kw)
+{
+ mp *x = 0;
+ grand *r = &rand_global;
+ unsigned nbits;
+ char *name = "p";
+ unsigned n = 0;
+ pgev evt = { 0 };
+ PyObject *rc = 0;
+ char *kwlist[] = { "nbits", "name", "event", "rng", "nsteps", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|sO&O&O&", kwlist,
+ convuint, &nbits, &name,
+ convpgev, &evt, convgrand, &r,
+ convuint, &n))
+ goto end;
+ if ((x = strongprime(name, MP_NEW, nbits,
+ r, n, evt.proc, evt.ctx)) == 0)
+ PGENERR;
+ rc = mp_pywrap(x);
+ x = 0;
+end:
+ mp_drop(x);
+ droppgev(&evt);
+ return (rc);
+}
+
+static PyObject *meth_limlee(PyObject *me, PyObject *arg, PyObject *kw)
+{
+ char *p = "p";
+ pgev ie = { 0 }, oe = { 0 };
+ unsigned ql, pl;
+ grand *r = &rand_global;
+ unsigned on = 0;
+ size_t i, nf = 0;
+ PyObject *rc = 0, *vec;
+ char *kwlist[] = { "pbits", "qbits", "name", "event", "ievent",
+ "rng", "nsteps", 0 };
+ mp *x = 0, **v = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&|sO&O&O&O&:limlee", kwlist,
+ convuint, &pl, convuint, &ql,
+ &p, convpgev, &oe, convpgev, &ie,
+ convgrand, &r, convuint, &on))
+ goto end;
+ if ((x = limlee(p, MP_NEW, MP_NEW, ql, pl, r, on,
+ oe.proc, oe.ctx, ie.proc, ie.ctx, &nf, &v)) == 0)
+ PGENERR;
+ vec = PyList_New(nf);
+ for (i = 0; i < nf; i++)
+ PyList_SetItem(vec, i, mp_pywrap(v[i]));
+ xfree(v);
+ rc = Py_BuildValue("(NN)", mp_pywrap(x), vec);
+end:
+ droppgev(&oe); droppgev(&ie);
+ return (rc);
+}
+
+/*----- Global stuff ------------------------------------------------------*/
+
+static PyMethodDef methods[] = {
+#define METHNAME(name) meth_##name
+ METH (_PrimeFilter_smallfactor, "smallfactor(X) -> PGRC")
+ METH (_RabinMiller_iters, "iters(NBITS) -> NITERS")
+ KWMETH(pgen, "\
+pgen(START, [name = 'p', stepper = PrimeGenStepper(2),\n\
+ tester = PrimeGenTester(), event = pgen_nullev,\n\
+ nsteps = 0, ntests = RabinMiller.iters(START.nbits)]) -> P")
+ KWMETH(strongprime_setup, "\
+strongprime_setup(NBITS, [name = 'p', event = pgen_nullev,\n\
+ rng = rand, nsteps = 0]) -> (START, JUMP)")
+ KWMETH(strongprime, "\
+strongprime_setup(NBITS, [name = 'p', event = pgen_nullev,\n\
+ rng = rand, nsteps = 0]) -> P")
+ KWMETH(limlee, "\
+limlee(PBITS, QBITS, [name = 'p', event = pgen_nullev,\n\
+ ievent = pgen_nullev, rng = rand, nsteps = 0]) -> (P, [Q, ...])")
+#undef METHNAME
+ { 0 }
+};
+
+void pgen_pyinit(void)
+{
+ INITTYPE(pfilt, root);
+ INITTYPE(rabin, root);
+ INITTYPE(pgevent, root);
+ INITTYPE(pgev, root);
+ INITTYPE(pgstep, pgev);
+ INITTYPE(pgjump, pgev);
+ INITTYPE(pgtest, pgev);
+ addmethods(methods);
+}
+
+static PyObject *obj;
+
+void pgen_pyinsert(PyObject *mod)
+{
+ INSERT("PrimeFilter", pfilt_pytype);
+ INSERT("RabinMiller", rabin_pytype);
+ INSERT("PrimeGenEvent", pgevent_pytype);
+ INSERT("PrimeGenBuiltinHandler", pgev_pytype);
+ INSERT("PrimeGenStepper", pgstep_pytype);
+ INSERT("PrimeGenJumper", pgjump_pytype);
+ INSERT("PrimeGenTester", pgtest_pytype);
+ INSERT("pgen_nullev", obj = pgev_stdev(0));
+ INSERT("pgen_stdev", pgev_stdev(pgen_ev));
+ INSERT("pgen_spinev", pgev_stdev(pgen_evspin));
+ INSERT("pgen_subev", pgev_stdev(pgen_subev));
+}
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id$
+ *
+ * Public-key cryptography
+ *
+ * (c) 2004 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of the Python interface to Catacomb.
+ *
+ * Catacomb/Python is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb/Python is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Catacomb/Python; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "catacomb-python.h"
+
+/*----- DSA and similar ---------------------------------------------------*/
+
+typedef struct dsa_pyobj {
+ PyObject_HEAD
+ PyObject *G, *u, *p, *rng, *hash;
+ gdsa d;
+} dsa_pyobj;
+
+static PyTypeObject *dsapub_pytype, *dsapriv_pytype;
+static PyTypeObject *kcdsapub_pytype, *kcdsapriv_pytype;
+#define DSA_D(o) (&((dsa_pyobj *)(o))->d)
+#define DSA_G(o) (((dsa_pyobj *)(o))->G)
+#define DSA_U(o) (((dsa_pyobj *)(o))->u)
+#define DSA_P(o) (((dsa_pyobj *)(o))->p)
+#define DSA_RNG(o) (((dsa_pyobj *)(o))->rng)
+#define DSA_HASH(o) (((dsa_pyobj *)(o))->hash)
+
+static void dsa_pydealloc(PyObject *me)
+{
+ dsa_pyobj *g = (dsa_pyobj *)me;
+ Py_DECREF(g->G); Py_DECREF(g->u); Py_DECREF(g->p);
+ Py_DECREF(g->rng); Py_DECREF(g->hash);
+ PyObject_DEL(me);
+}
+
+static PyObject *dsa_setup(PyTypeObject *ty, PyObject *G, PyObject *u,
+ PyObject *p, PyObject *rng, PyObject *hash)
+{
+ dsa_pyobj *g;
+
+ g = PyObject_New(dsa_pyobj, ty);
+ if (GROUP_G(G) != GE_G(p) && !group_samep(GROUP_G(G), GE_G(p)))
+ TYERR("public key not from group");
+ if (!u) {
+ g->d.u = 0;
+ u = Py_None;
+ } else if ((g->d.u = getmp(u)) == 0)
+ goto end;
+ g->d.g = GROUP_G(G);
+ g->d.p = GE_X(p);
+ g->d.r = GRAND_R(rng);
+ g->d.h = GCHASH_CH(hash);
+ g->G = G; Py_INCREF(G); g->u = u; Py_INCREF(u); g->p = p; Py_INCREF(p);
+ rng = g->rng; Py_INCREF(rng); g->hash = hash; Py_INCREF(hash);
+ return ((PyObject *)g);
+end:
+ PyObject_DEL(g);
+ return (0);
+}
+
+static PyObject *dsapub_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+{
+ PyObject *G, *p, *u = 0, *rng = rand_pyobj, *hash = sha_pyobj;
+ PyObject *rc = 0;
+ char *kwlist[] = { "G", "p", "u", "hash", "rng", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O!O!|OO!:new", kwlist,
+ group_pytype, &G,
+ ge_pytype, &p,
+ &u,
+ gchash_pytype, &hash,
+ grand_pytype, &rng) ||
+ (rc = dsa_setup(dsapub_pytype, G, u, p, rng, hash)) == 0)
+ goto end;
+end:
+ return (rc);
+}
+
+static PyObject *dsameth_beginhash(PyObject *me, PyObject *arg)
+{
+ if (!PyArg_ParseTuple(arg, ":beginhash")) return (0);
+ return (ghash_pywrap(DSA_HASH(me), gdsa_beginhash(DSA_D(me)), f_freeme));
+}
+
+static PyObject *dsameth_endhash(PyObject *me, PyObject *arg)
+{
+ ghash *h;
+ PyObject *rc;
+ if (!PyArg_ParseTuple(arg, "O&:endhash", convghash, &h)) return (0);
+ gdsa_endhash(DSA_D(me), h);
+ h = GH_COPY(h);
+ rc = bytestring_pywrap(0, GH_CLASS(h)->hashsz);
+ GH_DONE(h, PyString_AS_STRING(rc));
+ GH_DESTROY(h);
+ return (rc);
+}
+
+static PyObject *dsameth_sign(PyObject *me, PyObject *arg, PyObject *kw)
+{
+ gdsa_sig s = GDSA_SIG_INIT;
+ char *p;
+ int n;
+ mp *k = 0;
+ PyObject *rc = 0;
+ char *kwlist[] = { "msg", "k", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#|O&:sign", kwlist,
+ &p, &n, convmp, &k))
+ goto end;
+ if (n != DSA_D(me)->h->hashsz)
+ VALERR("bad message length (doesn't match hash size)");
+ gdsa_sign(DSA_D(me), &s, p, k);
+ rc = Py_BuildValue("(NN)", mp_pywrap(s.r), mp_pywrap(s.s));
+end:
+ mp_drop(k);
+ return (rc);
+}
+
+static PyObject *dsameth_verify(PyObject *me, PyObject *arg)
+{
+ char *p;
+ int n;
+ gdsa_sig s = GDSA_SIG_INIT;
+ PyObject *rc = 0;
+
+ if (!PyArg_ParseTuple(arg, "s#(O&O&):verify",
+ &p, &n, convmp, &s.r, convmp, &s.s))
+ goto end;
+ if (n != DSA_D(me)->h->hashsz)
+ VALERR("bad message length (doesn't match hash size)");
+ rc = getbool(gdsa_verify(DSA_D(me), &s, p));
+end:
+ mp_drop(s.r);
+ mp_drop(s.s);
+ return (rc);
+}
+
+static PyObject *dsapriv_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+{
+ PyObject *G, *p, *u = Py_None, *rng = rand_pyobj, *hash = sha_pyobj;
+ PyObject *rc = 0;
+ char *kwlist[] = { "G", "p", "u", "hash", "rng", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O!|O!OO!:new", kwlist,
+ group_pytype, &G,
+ ge_pytype, &p,
+ &u,
+ gchash_pytype, &hash,
+ grand_pytype, &rng) ||
+ (rc = dsa_setup(dsapriv_pytype, G, p, u, rng, hash)) == 0)
+ goto end;
+end:
+ return (rc);
+}
+
+static PyMethodDef dsapub_pymethods[] = {
+#define METHNAME(name) dsameth_##name
+ METH (beginhash, "D.beginhash() -> hash object")
+ METH (endhash, "D.endhash(H) -> BYTES")
+ METH (verify, "D.verify(MSG, (R, S)) -> true/false")
+#undef METHNAME
+ { 0 }
+};
+
+static PyMethodDef dsapriv_pymethods[] = {
+#define METHNAME(name) dsameth_##name
+ KWMETH(sign, "D.sign(MSG, k = K) -> R, S")
+#undef METHNAME
+ { 0 }
+};
+
+static PyMemberDef dsapub_pymembers[] = {
+#define MEMBERSTRUCT dsa_pyobj
+ MEMBER(G, T_OBJECT, READONLY, "D.G -> group to work in")
+ MEMBER(p, T_OBJECT, READONLY, "D.p -> public key (group element")
+ MEMBER(rng, T_OBJECT, READONLY, "D.rng -> random number generator")
+ MEMBER(hash, T_OBJECT, READONLY, "D.hash -> hash class")
+#undef MEMBERSTRUCT
+ { 0 }
+};
+
+static PyMemberDef dsapriv_pymembers[] = {
+#define MEMBERSTRUCT dsa_pyobj
+ MEMBER(u, T_OBJECT, READONLY, "D.u -> private key (exponent)")
+#undef MEMBERSTRUCT
+ { 0 }
+};
+
+static PyTypeObject dsapub_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.DSAPub", /* @tp_name@ */
+ sizeof(dsa_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ dsa_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"DSA public key information.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ dsapub_pymethods, /* @tp_methods@ */
+ dsapub_pymembers, /* @tp_members@ */
+ 0, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ dsapub_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyTypeObject dsapriv_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.DSAPriv", /* @tp_name@ */
+ sizeof(dsa_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ 0, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"DSA private key information.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ dsapriv_pymethods, /* @tp_methods@ */
+ dsapriv_pymembers, /* @tp_members@ */
+ 0, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ dsapriv_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyObject *kcdsapub_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+{
+ PyObject *G, *p, *u = 0, *rng = rand_pyobj, *hash = has160_pyobj;
+ PyObject *rc = 0;
+ char *kwlist[] = { "G", "p", "u", "hash", "rng", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O!O!|OO!:new", kwlist,
+ group_pytype, &G,
+ ge_pytype, &p,
+ &u,
+ gchash_pytype, &hash,
+ grand_pytype, &rng) ||
+ (rc = dsa_setup(kcdsapub_pytype, G, p, u, rng, hash)) == 0)
+ goto end;
+end:
+ return (rc);
+}
+
+static PyObject *kcdsapriv_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+{
+ PyObject *G, *p, *u = Py_None, *rng = rand_pyobj, *hash = has160_pyobj;
+ PyObject *rc = 0;
+ char *kwlist[] = { "G", "p", "u", "hash", "rng", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O!|O!OO!:new", kwlist,
+ group_pytype, &G,
+ ge_pytype, &p,
+ &u,
+ gchash_pytype, &hash,
+ grand_pytype, &rng) ||
+ (rc = dsa_setup(kcdsapriv_pytype, G, p, u, rng, hash)) == 0)
+ goto end;
+end:
+ return (rc);
+}
+
+static PyObject *kcdsameth_beginhash(PyObject *me, PyObject *arg)
+{
+ if (!PyArg_ParseTuple(arg, ":beginhash")) return (0);
+ return (ghash_pywrap(DSA_HASH(me), gkcdsa_beginhash(DSA_D(me)), f_freeme));
+}
+
+static PyObject *kcdsameth_endhash(PyObject *me, PyObject *arg)
+{
+ ghash *h;
+ PyObject *rc;
+ if (!PyArg_ParseTuple(arg, "O&:endhash", convghash, &h)) return (0);
+ gkcdsa_endhash(DSA_D(me), h);
+ h = GH_COPY(h);
+ rc = bytestring_pywrap(0, GH_CLASS(h)->hashsz);
+ GH_DONE(h, PyString_AS_STRING(rc));
+ GH_DESTROY(h);
+ return (rc);
+}
+
+static PyObject *kcdsameth_sign(PyObject *me, PyObject *arg, PyObject *kw)
+{
+ gkcdsa_sig s = GKCDSA_SIG_INIT;
+ char *p;
+ int n;
+ mp *k = 0;
+ PyObject *r = 0, *rc = 0;
+ char *kwlist[] = { "msg", "k", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#|O&:sign", kwlist,
+ &p, &n, convmp, &k))
+ goto end;
+ if (n != DSA_D(me)->h->hashsz)
+ VALERR("bad message length (doesn't match hash size)");
+ r = bytestring_pywrap(0, DSA_D(me)->h->hashsz);
+ s.r = PyString_AS_STRING(r);
+ gkcdsa_sign(DSA_D(me), &s, p, k);
+ rc = Py_BuildValue("(NN)", r, mp_pywrap(s.s));
+end:
+ Py_XDECREF(r);
+ mp_drop(k);
+ return (rc);
+}
+
+static PyObject *kcdsameth_verify(PyObject *me, PyObject *arg)
+{
+ char *p;
+ int n, rn;
+ gkcdsa_sig s = GKCDSA_SIG_INIT;
+ PyObject *rc = 0;
+
+ if (!PyArg_ParseTuple(arg, "s#(s#O&):verify",
+ &p, &n, &s.r, &rn, convmp, &s.s))
+ goto end;
+ if (n != DSA_D(me)->h->hashsz)
+ VALERR("bad message length (doesn't match hash size)");
+ if (rn != DSA_D(me)->h->hashsz)
+ VALERR("bad signature `r' length (doesn't match hash size)");
+ rc = getbool(gkcdsa_verify(DSA_D(me), &s, p));
+end:
+ mp_drop(s.s);
+ return (rc);
+}
+
+static PyMethodDef kcdsapub_pymethods[] = {
+#define METHNAME(name) kcdsameth_##name
+ METH (beginhash, "D.beginhash() -> hash object")
+ METH (endhash, "D.endhash(H) -> BYTES")
+ METH (verify, "D.verify(MSG, (R, S)) -> true/false")
+#undef METHNAME
+ { 0 }
+};
+
+static PyMethodDef kcdsapriv_pymethods[] = {
+#define METHNAME(name) kcdsameth_##name
+ KWMETH(sign, "D.sign(MSG, k = K) -> R, S")
+#undef METHNAME
+ { 0 }
+};
+
+static PyTypeObject kcdsapub_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.KCDSAPub", /* @tp_name@ */
+ sizeof(dsa_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ dsa_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"KCDSA public key information.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ kcdsapub_pymethods, /* @tp_methods@ */
+ dsapub_pymembers, /* @tp_members@ */
+ 0, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ kcdsapub_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyTypeObject kcdsapriv_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.KCDSAPriv", /* @tp_name@ */
+ sizeof(dsa_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ 0, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"KCDSA private key information.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ kcdsapriv_pymethods, /* @tp_methods@ */
+ dsapriv_pymembers, /* @tp_members@ */
+ 0, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ kcdsapriv_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- RSA ---------------------------------------------------------------*/
+
+typedef struct rsapub_pyobj {
+ PyObject_HEAD
+ rsa_pub pub;
+ rsa_pubctx pubctx;
+} rsapub_pyobj;
+
+#define RSA_PUB(o) (&((rsapub_pyobj *)(o))->pub)
+#define RSA_PUBCTX(o) (&((rsapub_pyobj *)(o))->pubctx)
+
+typedef struct rsapriv_pyobj {
+ PyObject_HEAD
+ rsa_pub pub;
+ rsa_pubctx pubctx;
+ rsa_priv priv;
+ rsa_privctx privctx;
+ PyObject *rng;
+} rsapriv_pyobj;
+
+#define RSA_PRIV(o) (&((rsapriv_pyobj *)(o))->priv)
+#define RSA_PRIVCTX(o) (&((rsapriv_pyobj *)(o))->privctx)
+#define RSA_RNG(o) (((rsapriv_pyobj *)(o))->rng)
+
+static PyTypeObject *rsapub_pytype, *rsapriv_pytype;
+
+static PyObject *rsapub_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+{
+ rsa_pub rp = { 0 };
+ rsapub_pyobj *o;
+ char *kwlist[] = { "n", "e", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&:new", kwlist,
+ convmp, &rp.n, convmp, &rp.e))
+ goto end;
+ o = (rsapub_pyobj *)ty->tp_alloc(ty, 0);
+ o->pub = rp;
+ rsa_pubcreate(&o->pubctx, &o->pub);
+ return ((PyObject *)o);
+end:
+ rsa_pubfree(&rp);
+ return (0);
+}
+
+static void rsapub_pydealloc(PyObject *me)
+{
+ rsa_pubdestroy(RSA_PUBCTX(me));
+ rsa_pubfree(RSA_PUB(me));
+ PyObject_DEL(me);
+}
+
+static PyObject *rsaget_n(PyObject *me, void *hunoz)
+ { return mp_pywrap(MP_COPY(RSA_PUB(me)->n)); }
+
+static PyObject *rsaget_e(PyObject *me, void *hunoz)
+ { return mp_pywrap(MP_COPY(RSA_PUB(me)->e)); }
+
+static PyObject *rsameth_pubop(PyObject *me, PyObject *arg)
+{
+ mp *x = 0;
+ PyObject *rc = 0;
+
+ if (!PyArg_ParseTuple(arg, "O&:pubop", convmp, &x)) goto end;
+ rc = mp_pywrap(rsa_pubop(RSA_PUBCTX(me), MP_NEW, x));
+end:
+ mp_drop(x);
+ return (rc);
+}
+
+static PyObject *rsapriv_dopywrap(PyTypeObject *ty,
+ rsa_priv *rp, PyObject *rng)
+{
+ rsapriv_pyobj *o;
+
+ o = (rsapriv_pyobj *)ty->tp_alloc(ty, 0);
+ o->priv = *rp;
+ o->pub.n = rp->n;
+ o->pub.e = rp->e;
+ rsa_privcreate(&o->privctx, &o->priv, &rand_global);
+ rsa_pubcreate(&o->pubctx, &o->pub);
+ if (!rng) {
+ rng = Py_None;
+ Py_INCREF(rng);
+ }
+ o->rng = rng;
+ return ((PyObject *)o);
+}
+
+PyObject *rsapriv_pywrap(rsa_priv *rp)
+ { return rsapriv_dopywrap(rsapriv_pytype, rp, 0); }
+
+static PyObject *rsapriv_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+{
+ rsa_priv rp = { 0 };
+ PyObject *rng = Py_None;
+ char *kwlist[] =
+ { "n", "e", "d", "p", "q", "dp", "dq", "q_inv", "rng", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&O&O&O&O&O&O&O&O:new", kwlist,
+ convmp, &rp.n, convmp, &rp.e,
+ convmp, &rp.d,
+ convmp, &rp.p, convmp, &rp.q,
+ convmp, &rp.dp, convmp, &rp.dq,
+ convmp, &rp.q_inv,
+ &rng))
+ goto end;
+ if (rsa_recover(&rp)) VALERR("couldn't construct private key");
+ if (rng != Py_None && !GRAND_PYCHECK(rng))
+ TYERR("not a random number source");
+ Py_INCREF(rng);
+ return (rsapriv_dopywrap(ty, &rp, rng));
+end:
+ rsa_privfree(&rp);
+ return (0);
+}
+
+static void rsapriv_pydealloc(PyObject *me)
+{
+ RSA_PRIVCTX(me)->r = &rand_global;
+ rsa_privdestroy(RSA_PRIVCTX(me));
+ rsa_privfree(RSA_PRIV(me));
+ Py_DECREF(RSA_RNG(me));
+ PyObject_DEL(me);
+}
+
+static PyObject *rsaget_d(PyObject *me, void *hunoz)
+ { return mp_pywrap(MP_COPY(RSA_PRIV(me)->d)); }
+
+static PyObject *rsaget_p(PyObject *me, void *hunoz)
+ { return mp_pywrap(MP_COPY(RSA_PRIV(me)->p)); }
+
+static PyObject *rsaget_q(PyObject *me, void *hunoz)
+ { return mp_pywrap(MP_COPY(RSA_PRIV(me)->q)); }
+
+static PyObject *rsaget_dp(PyObject *me, void *hunoz)
+ { return mp_pywrap(MP_COPY(RSA_PRIV(me)->dp)); }
+
+static PyObject *rsaget_dq(PyObject *me, void *hunoz)
+ { return mp_pywrap(MP_COPY(RSA_PRIV(me)->dq)); }
+
+static PyObject *rsaget_q_inv(PyObject *me, void *hunoz)
+ { return mp_pywrap(MP_COPY(RSA_PRIV(me)->q_inv)); }
+
+static PyObject *rsaget_rng(PyObject *me, void *hunoz)
+ { RETURN_OBJ(RSA_RNG(me)); }
+
+static int rsaset_rng(PyObject *me, PyObject *val, void *hunoz)
+{
+ int rc = -1;
+ if (val != Py_None && !GRAND_PYCHECK(val))
+ TYERR("expected grand or None");
+ Py_DECREF(RSA_RNG(me));
+ RSA_RNG(me) = val;
+ Py_INCREF(val);
+ rc = 0;
+end:
+ return (rc);
+}
+
+static PyObject *rsameth_privop(PyObject *me, PyObject *arg, PyObject *kw)
+{
+ PyObject *rng = RSA_RNG(me);
+ mp *x = 0;
+ PyObject *rc = 0;
+ char *kwlist[] = { "x", "rng", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|O:privop", kwlist,
+ convmp, &x, &rng))
+ goto end;
+ if (rng != Py_None && !GRAND_PYCHECK(rng))
+ TYERR("not a random number source");
+ RSA_PRIVCTX(me)->r = (rng == Py_None) ? 0 : GRAND_R(rng);
+ rc = mp_pywrap(rsa_privop(RSA_PRIVCTX(me), MP_NEW, x));
+end:
+ mp_drop(x);
+ return (rc);
+}
+
+static PyObject *meth__RSAPriv_generate(PyObject *me,
+ PyObject *arg, PyObject *kw)
+{
+ grand *r = &rand_global;
+ unsigned nbits;
+ unsigned n = 0;
+ rsa_priv rp;
+ pgev evt = { 0 };
+ char *kwlist[] = { "class", "nbits", "event", "rng", "nsteps", 0 };
+ PyObject *rc = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO&|O&O&O&:generate", kwlist,
+ &me, convuint, &nbits, convpgev, &evt,
+ convgrand, &r, convuint, &n))
+ goto end;
+ if (rsa_gen(&rp, nbits, r, n, evt.proc, evt.ctx))
+ PGENERR;
+ rc = rsapriv_pywrap(&rp);
+end:
+ droppgev(&evt);
+ return (rc);
+}
+
+static PyGetSetDef rsapub_pygetset[] = {
+#define GETSETNAME(op, name) rsa##op##_##name
+ GET (n, "R.n -> N")
+ GET (e, "R.e -> E")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyMethodDef rsapub_pymethods[] = {
+#define METHNAME(name) rsameth_##name
+ METH (pubop, "R.pubop(X) -> X^E (mod N)")
+#undef METHNAME
+ { 0 }
+};
+
+static PyGetSetDef rsapriv_pygetset[] = {
+#define GETSETNAME(op, name) rsa##op##_##name
+ GET (d, "R.d -> D")
+ GET (p, "R.p -> P")
+ GET (q, "R.q -> Q")
+ GET (dp, "R.dp -> D mod (P - 1)")
+ GET (dq, "R.dq -> D mod (Q - 1)")
+ GET (q_inv, "R.q_inv -> Q^{-1} mod P")
+ GETSET(rng, "R.rng -> random number source for blinding")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyMethodDef rsapriv_pymethods[] = {
+#define METHNAME(name) rsameth_##name
+ KWMETH(privop, "R.privop(X, rng = None) -> X^D (mod N)")
+#undef METHNAME
+ { 0 }
+};
+
+static PyTypeObject rsapub_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.RSAPub", /* @tp_name@ */
+ sizeof(rsapub_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ rsapub_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"RSA public key information.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ rsapub_pymethods, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ rsapub_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ rsapub_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyTypeObject rsapriv_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.RSAPriv", /* @tp_name@ */
+ sizeof(rsapriv_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ rsapriv_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"RSA private key information.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ rsapriv_pymethods, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ rsapriv_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ rsapriv_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- RSA padding schemes -----------------------------------------------*/
+
+static PyObject *meth__p1crypt_encode(PyObject *me,
+ PyObject *arg, PyObject *kw)
+{
+ pkcs1 p1;
+ char *m, *ep;
+ int msz, epsz;
+ unsigned long nbits;
+ PyObject *rc = 0;
+ octet *b = 0;
+ size_t sz;
+ mp *x;
+ char *kwlist[] = { "msg", "nbits", "ep", "rng", 0 };
+
+ p1.r = &rand_global; ep = 0; epsz = 0;
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#O&|s#O&:encode", kwlist,
+ &m, &msz, convulong, &nbits,
+ &ep, &epsz, convgrand, &p1.r))
+ goto end;
+ sz = (nbits + 7)/8;
+ p1.ep = ep; p1.epsz = epsz;
+ if (epsz + msz + 11 > sz) VALERR("buffer underflow");
+ b = xmalloc(sz);
+ x = pkcs1_cryptencode(MP_NEW, m, msz, b, sz, nbits, &p1);
+ rc = mp_pywrap(x);
+end:
+ xfree(b);
+ return (rc);
+}
+
+static PyObject *meth__p1crypt_decode(PyObject *me,
+ PyObject *arg, PyObject *kw)
+{
+ pkcs1 p1;
+ char *ep;
+ int epsz;
+ unsigned long nbits;
+ int n;
+ PyObject *rc = 0;
+ octet *b = 0;
+ size_t sz;
+ mp *x = 0;
+ char *kwlist[] = { "ct", "nbits", "ep", "rng", 0 };
+
+ p1.r = &rand_global; ep = 0; epsz = 0;
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&|s#O&:decode", kwlist,
+ convmp, &x, convulong, &nbits,
+ &ep, &epsz, convgrand, &p1.r))
+ goto end;
+ sz = (nbits + 7)/8;
+ p1.ep = ep; p1.epsz = epsz;
+ if (epsz + 11 > sz) VALERR("buffer underflow");
+ b = xmalloc(sz);
+ if ((n = pkcs1_cryptdecode(x, b, sz, nbits, &p1)) < 0)
+ VALERR("decryption failed");
+ rc = bytestring_pywrap(b, n);
+end:
+ mp_drop(x);
+ xfree(b);
+ return (rc);
+}
+
+static PyObject *meth__p1sig_encode(PyObject *me,
+ PyObject *arg, PyObject *kw)
+{
+ pkcs1 p1;
+ char *m, *ep;
+ int msz, epsz;
+ unsigned long nbits;
+ PyObject *rc = 0;
+ octet *b = 0;
+ size_t sz;
+ mp *x;
+ char *kwlist[] = { "msg", "nbits", "ep", "rng", 0 };
+
+ p1.r = &rand_global; ep = 0; epsz = 0;
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#O&|s#O&:encode", kwlist,
+ &m, &msz, convulong, &nbits,
+ &ep, &epsz, convgrand, &p1.r))
+ goto end;
+ sz = (nbits + 7)/8;
+ p1.ep = ep; p1.epsz = epsz;
+ if (epsz + msz + 11 > sz) VALERR("buffer underflow");
+ b = xmalloc(sz);
+ x = pkcs1_sigencode(MP_NEW, m, msz, b, sz, nbits, &p1);
+ rc = mp_pywrap(x);
+end:
+ xfree(b);
+ return (rc);
+}
+
+static PyObject *meth__p1sig_decode(PyObject *me,
+ PyObject *arg, PyObject *kw)
+{
+ pkcs1 p1;
+ char *ep;
+ int epsz;
+ unsigned long nbits;
+ int n;
+ PyObject *hukairz;
+ PyObject *rc = 0;
+ octet *b = 0;
+ size_t sz;
+ mp *x = 0;
+ char *kwlist[] = { "msg", "sig", "nbits", "ep", "rng", 0 };
+
+ p1.r = &rand_global; ep = 0; epsz = 0;
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO&O&|s#O&:decode", kwlist,
+ &hukairz, convmp, &x, convulong, &nbits,
+ &ep, &epsz, convgrand, &p1.r))
+ goto end;
+ sz = (nbits + 7)/8;
+ p1.ep = ep; p1.epsz = epsz;
+ if (epsz + 10 > sz) VALERR("buffer underflow");
+ b = xmalloc(sz);
+ if ((n = pkcs1_sigdecode(x, 0, 0, b, sz, nbits, &p1)) < 0)
+ VALERR("verification failed");
+ rc = bytestring_pywrap(b, n);
+end:
+ mp_drop(x);
+ xfree(b);
+ return (rc);
+}
+
+static PyObject *meth__oaep_encode(PyObject *me,
+ PyObject *arg, PyObject *kw)
+{
+ oaep o;
+ char *m, *ep;
+ int msz, epsz;
+ unsigned long nbits;
+ PyObject *rc = 0;
+ octet *b = 0;
+ size_t sz;
+ mp *x;
+ char *kwlist[] = { "msg", "nbits", "mgf", "hash", "ep", "rng", 0 };
+
+ o.r = &rand_global; o.cc = &sha_mgf; o.ch = &sha; ep = 0; epsz = 0;
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#O&|O&O&s#O&:encode", kwlist,
+ &m, &msz, convulong, &nbits,
+ convgccipher, &o.cc,
+ convgchash, &o.ch,
+ &ep, &epsz,
+ convgrand, &o.r))
+ goto end;
+ sz = (nbits + 7)/8;
+ o.ep = ep; o.epsz = epsz;
+ if (2 * o.ch->hashsz + 2 + msz > sz) VALERR("buffer underflow");
+ b = xmalloc(sz);
+ x = oaep_encode(MP_NEW, m, msz, b, sz, nbits, &o);
+ rc = mp_pywrap(x);
+end:
+ xfree(b);
+ return (rc);
+}
+
+static PyObject *meth__oaep_decode(PyObject *me,
+ PyObject *arg, PyObject *kw)
+{
+ oaep o;
+ char *ep;
+ int epsz;
+ unsigned long nbits;
+ int n;
+ PyObject *rc = 0;
+ octet *b = 0;
+ size_t sz;
+ mp *x = 0;
+ char *kwlist[] = { "ct", "nbits", "mgf", "hash", "ep", "rng", 0 };
+
+ o.r = &rand_global; o.cc = &sha_mgf; o.ch = &sha; ep = 0; epsz = 0;
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&|O&O&s#O&:decode", kwlist,
+ convmp, &x, convulong, &nbits,
+ convgccipher, &o.cc,
+ convgchash, &o.ch,
+ &ep, &epsz,
+ convgrand, &o.r))
+ goto end;
+ sz = (nbits + 7)/8;
+ o.ep = ep; o.epsz = epsz;
+ if (2 * o.ch->hashsz > sz) VALERR("buffer underflow");
+ b = xmalloc(sz);
+ if ((n = oaep_decode(x, b, sz, nbits, &o)) < 0)
+ VALERR("decryption failed");
+ rc = bytestring_pywrap(b, n);
+end:
+ mp_drop(x);
+ xfree(b);
+ return (rc);
+}
+
+static PyObject *meth__pss_encode(PyObject *me,
+ PyObject *arg, PyObject *kw)
+{
+ pss p;
+ char *m;
+ int msz;
+ unsigned long nbits;
+ PyObject *rc = 0;
+ octet *b = 0;
+ size_t sz;
+ mp *x = 0;
+ char *kwlist[] = { "msg", "nbits", "mgf", "hash", "saltsz", "rng", 0 };
+
+ p.cc = &sha_mgf; p.ch = &sha; p.r = &rand_global; p.ssz = (size_t)-1;
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#O&|O&O&O&O&:encode", kwlist,
+ &m, &msz, convulong, &nbits,
+ convgccipher, &p.cc,
+ convgchash, &p.ch,
+ convszt, &p.ssz,
+ convgrand, &p.r))
+ goto end;
+ sz = (nbits + 7)/8;
+ if (p.ssz == (size_t)-1) p.ssz = p.ch->hashsz;
+ if (p.ch->hashsz + p.ssz + 2 > sz) VALERR("buffer underflow");
+ b = xmalloc(sz);
+ x = pss_encode(MP_NEW, m, msz, b, sz, nbits, &p);
+ rc = mp_pywrap(x);
+end:
+ xfree(b);
+ return (rc);
+}
+
+static PyObject *meth__pss_decode(PyObject *me,
+ PyObject *arg, PyObject *kw)
+{
+ pss p;
+ char *m;
+ int msz;
+ unsigned long nbits;
+ PyObject *rc = 0;
+ octet *b = 0;
+ size_t sz;
+ int n;
+ mp *x = 0;
+ char *kwlist[] =
+ { "msg", "sig", "nbits", "mgf", "hash", "saltsz", "rng", 0 };
+
+ p.cc = &sha_mgf; p.ch = &sha; p.r = &rand_global; p.ssz = (size_t)-1;
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#O&O&|O&O&O&O&:decode", kwlist,
+ &m, &msz, convmp, &x, convulong, &nbits,
+ convgccipher, &p.cc,
+ convgchash, &p.ch,
+ convszt, &p.ssz,
+ convgrand, &p.r))
+ goto end;
+ sz = (nbits + 7)/8;
+ if (p.ssz == (size_t)-1) p.ssz = p.ch->hashsz;
+ if (p.ch->hashsz + p.ssz + 2 > sz) VALERR("buffer underflow");
+ b = xmalloc(sz);
+ if ((n = pss_decode(x, m, msz, b, sz, nbits, &p)) < 0)
+ VALERR("verification failed");
+ rc = Py_None; Py_INCREF(rc);
+end:
+ mp_drop(x);
+ xfree(b);
+ return (rc);
+}
+
+/*----- Global stuff ------------------------------------------------------*/
+
+static PyMethodDef methods[] = {
+#define METHNAME(name) meth_##name
+ KWMETH(_p1crypt_encode, 0)
+ KWMETH(_p1crypt_decode, 0)
+ KWMETH(_p1sig_encode, 0)
+ KWMETH(_p1sig_decode, 0)
+ KWMETH(_oaep_encode, 0)
+ KWMETH(_oaep_decode, 0)
+ KWMETH(_pss_encode, 0)
+ KWMETH(_pss_decode, 0)
+ KWMETH(_RSAPriv_generate, "\
+generate(NBITS, [event = pgen_nullev, rng = rand, nsteps = 0]) -> R")
+#undef METHNAME
+ { 0 }
+};
+
+void pubkey_pyinit(void)
+{
+ INITTYPE(dsapub, root);
+ INITTYPE(dsapriv, dsapub);
+ INITTYPE(kcdsapub, root);
+ INITTYPE(kcdsapriv, kcdsapub);
+ INITTYPE(rsapub, root);
+ INITTYPE(rsapriv, rsapub);
+ addmethods(methods);
+}
+
+void pubkey_pyinsert(PyObject *mod)
+{
+ INSERT("DSAPub", dsapub_pytype);
+ INSERT("DSAPriv", dsapriv_pytype);
+ INSERT("KCDSAPub", kcdsapub_pytype);
+ INSERT("KCDSAPriv", kcdsapriv_pytype);
+ INSERT("RSAPub", rsapub_pytype);
+ INSERT("RSAPriv", rsapriv_pytype);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+#! /usr/bin/python2.2
+
+import catacomb as C
+import gdbm, struct
+from sys import argv, exit, stdin, stdout, stderr
+from getopt import getopt, GetoptError
+from os import environ
+from fnmatch import fnmatch
+
+file = '%s/.pwsafe' % environ['HOME']
+
+class DecryptError (Exception):
+ pass
+
+class Crypto (object):
+ def __init__(me, c, h, m, ck, mk):
+ me.c = c(ck)
+ me.m = m(mk)
+ me.h = h
+ def encrypt(me, pt):
+ if me.c.__class__.blksz:
+ iv = C.rand.block(me.c.__class__.blksz)
+ me.c.setiv(iv)
+ else:
+ iv = ''
+ y = iv + me.c.encrypt(pt)
+ t = me.m().hash(y).done()
+ return t + y
+ def decrypt(me, ct):
+ t = ct[:me.m.__class__.tagsz]
+ y = ct[me.m.__class__.tagsz:]
+ if t != me.m().hash(y).done():
+ raise DecryptError
+ iv = y[:me.c.__class__.blksz]
+ if me.c.__class__.blksz: me.c.setiv(iv)
+ return me.c.decrypt(y[me.c.__class__.blksz:])
+
+class PPK (Crypto):
+ def __init__(me, pp, c, h, m, salt = None):
+ if not salt: salt = C.rand.block(h.hashsz)
+ tag = '%s\0%s' % (pp, salt)
+ Crypto.__init__(me, c, h, m,
+ h().hash('cipher:' + tag).done(),
+ h().hash('mac:' + tag).done())
+ me.salt = salt
+
+class Buffer (object):
+ def __init__(me, s):
+ me.str = s
+ me.i = 0
+ def get(me, n):
+ i = me.i
+ if n + i > len(me.str):
+ raise IndexError, 'buffer underflow'
+ me.i += n
+ return me.str[i:i + n]
+ def getbyte(me):
+ return ord(me.get(1))
+ def unpack(me, fmt):
+ return struct.unpack(fmt, me.get(struct.calcsize(fmt)))
+ def getstring(me):
+ return me.get(me.unpack('>H')[0])
+ def checkend(me):
+ if me.i != len(me.str):
+ raise ValueError, 'junk at end of buffer'
+
+def wrapstr(s):
+ return struct.pack('>H', len(s)) + s
+
+class PWIter (object):
+ def __init__(me, pw):
+ me.pw = pw
+ me.k = me.pw.db.firstkey()
+ def next(me):
+ k = me.k
+ while True:
+ if k is None:
+ raise StopIteration
+ if k[0] == '$':
+ break
+ k = me.pw.db.nextkey(k)
+ me.k = me.pw.db.nextkey(k)
+ return me.pw.unpack(me.pw.db[k])[0]
+class PW (object):
+ def __init__(me, file, mode = 'r'):
+ me.db = gdbm.open(file, mode)
+ c = C.gcciphers[me.db['cipher']]
+ h = C.gchashes[me.db['hash']]
+ m = C.gcmacs[me.db['mac']]
+ tag = me.db['tag']
+ ppk = PPK(C.ppread(tag), c, h, m, me.db['salt'])
+ try:
+ buf = Buffer(ppk.decrypt(me.db['key']))
+ except DecryptError:
+ C.ppcancel(tag)
+ raise
+ me.ck = buf.getstring()
+ me.mk = buf.getstring()
+ buf.checkend()
+ me.k = Crypto(c, h, m, me.ck, me.mk)
+ me.magic = me.k.decrypt(me.db['magic'])
+ def keyxform(me, key):
+ return '$' + me.k.h().hash(me.magic).hash(key).done()
+ def changepp(me):
+ tag = me.db['tag']
+ C.ppcancel(tag)
+ ppk = PPK(C.ppread(tag, C.PMODE_VERIFY),
+ me.k.c.__class__, me.k.h, me.k.m.__class__)
+ me.db['key'] = ppk.encrypt(wrapstr(me.ck) + wrapstr(me.mk))
+ me.db['salt'] = ppk.salt
+ def pack(me, key, value):
+ w = wrapstr(key) + wrapstr(value)
+ pl = (len(w) + 255) & ~255
+ w += '\0' * (pl - len(w))
+ return me.k.encrypt(w)
+ def unpack(me, p):
+ buf = Buffer(me.k.decrypt(p))
+ key = buf.getstring()
+ value = buf.getstring()
+ return key, value
+ def __getitem__(me, key):
+ return me.unpack(me.db[me.keyxform(key)])[1]
+ def __setitem__(me, key, value):
+ me.db[me.keyxform(key)] = me.pack(key, value)
+ def __delitem__(me, key):
+ del me.db[me.keyxform(key)]
+ def __iter__(me):
+ return PWIter(me)
+
+def cmd_create(av):
+ cipher = 'blowfish-cbc'
+ hash = 'rmd160'
+ mac = None
+ try:
+ opts, args = getopt(av, 'c:h:m:', ['cipher=', 'mac=', 'hash='])
+ except GetoptError:
+ return 1
+ for o, a in opts:
+ if o in ('-c', '--cipher'):
+ cipher = a
+ elif o in ('-m', '--mac'):
+ mac = a
+ elif o in ('-h', '--hash'):
+ hash = a
+ else:
+ raise 'Barf!'
+ if len(args) > 2:
+ return 1
+ if len(args) >= 1:
+ tag = args[0]
+ else:
+ tag = 'pwsafe'
+ db = gdbm.open(file, 'n', 0600)
+ pp = C.ppread(tag, C.PMODE_VERIFY)
+ if not mac: mac = hash + '-hmac'
+ c = C.gcciphers[cipher]
+ h = C.gchashes[hash]
+ m = C.gcmacs[mac]
+ ppk = PPK(pp, c, h, m)
+ ck = C.rand.block(c.keysz.default)
+ mk = C.rand.block(m.keysz.default)
+ k = Crypto(c, h, m, ck, mk)
+ db['tag'] = tag
+ db['salt'] = ppk.salt
+ db['cipher'] = cipher
+ db['hash'] = hash
+ db['mac'] = mac
+ db['key'] = ppk.encrypt(wrapstr(ck) + wrapstr(mk))
+ db['magic'] = k.encrypt(C.rand.block(h.hashsz))
+
+def cmd_changepp(av):
+ if len(av) != 0:
+ return 1
+ pw = PW(file, 'w')
+ pw.changepp()
+
+def cmd_find(av):
+ if len(av) != 1:
+ return 1
+ pw = PW(file)
+ print pw[av[0]]
+
+def cmd_store(av):
+ if len(av) < 1 or len(av) > 2:
+ return 1
+ tag = av[0]
+ if len(av) < 2:
+ pp = C.getpass("Enter passphrase `%s': " % tag)
+ vpp = C.getpass("Confirm passphrase `%s': " % tag)
+ if pp != vpp:
+ raise ValueError, "passphrases don't match"
+ elif av[1] == '-':
+ pp = stdin.readline()
+ else:
+ pp = av[1]
+ pw = PW(file, 'w')
+ pw[av[0]] = pp
+
+def cmd_copy(av):
+ if len(av) < 1 or len(av) > 2:
+ return 1
+ pw_in = PW(file)
+ pw_out = PW(av[0], 'w')
+ if len(av) >= 3:
+ pat = av[1]
+ else:
+ pat = None
+ for k in pw_in:
+ if pat is None or fnmatch(k, pat):
+ pw_out[k] = pw_in[k]
+
+def cmd_list(av):
+ if len(av) > 1:
+ return 1
+ pw = PW(file)
+ if len(av) >= 1:
+ pat = av[0]
+ else:
+ pat = None
+ for k in pw:
+ if pat is None or fnmatch(k, pat):
+ print k
+
+def cmd_topixie(av):
+ if len(av) < 1 or len(av) > 2:
+ return 1
+ pw = PW(file)
+ tag = av[0]
+ if len(av) >= 2:
+ pptag = av[1]
+ else:
+ pptag = av[0]
+ C.Pixie().set(pptag, pw[tag])
+
+def asciip(s):
+ for ch in s:
+ if ch < ' ' or ch > '~': return False
+ return True
+def present(s):
+ if asciip(s): return s
+ return C.ByteString(s)
+def cmd_dump(av):
+ db = gdbm.open(file, 'r')
+ k = db.firstkey()
+ while True:
+ if k is None: break
+ print '%r: %r' % (present(k), present(db[k]))
+ k = db.nextkey(k)
+
+commands = { 'create': [cmd_create,
+ '[-c CIPHER] [-h HASH] [-m MAC] [PP-TAG]'],
+ 'find' : [cmd_find, 'LABEL'],
+ 'store' : [cmd_store, 'LABEL [VALUE]'],
+ 'list' : [cmd_list, '[GLOB-PATTERN]'],
+ 'changepp' : [cmd_changepp, ''],
+ 'copy' : [cmd_copy, 'DEST-FILE [GLOB-PATTERN]'],
+ 'to-pixie' : [cmd_topixie, 'TAG [PIXIE-TAG]'],
+ 'dump' : [cmd_dump, '']}
+
+def version():
+ print 'pwsafe 1.0.0'
+def usage(fp):
+ print >>fp, 'Usage: pwsafe COMMAND [ARGS...]'
+def help():
+ version()
+ print
+ usage(stdout)
+ print '''
+Maintains passwords or other short secrets securely.
+
+Options:
+
+-h, --help Show this help text.
+-v, --version Show program version number.
+-u, --usage Show short usage message.
+
+Commands provided:
+'''
+ for c in commands:
+ print '%s %s' % (c, commands[c][1])
+
+try:
+ opts, argv = getopt(argv[1:],
+ 'hvuf:',
+ ['help', 'version', 'usage', 'file='])
+except GetoptError:
+ usage(stderr)
+ exit(1)
+for o, a in opts:
+ if o in ('-h', '--help'):
+ help()
+ exit(0)
+ elif o in ('-v', '--version'):
+ version()
+ exit(0)
+ elif o in ('-u', '--usage'):
+ usage(stdout)
+ exit(0)
+ elif o in ('-f', '--file'):
+ file = a
+ else:
+ raise 'Barf!'
+if len(argv) < 1:
+ usage(stderr)
+ exit(1)
+
+if argv[0] in commands:
+ c = argv[0]
+ argv = argv[1:]
+else:
+ c = 'find'
+if commands[c][0](argv):
+ print >>stderr, 'Usage: pwsafe %s %s' % (c, commands[c][1])
+ exit(1)
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id$
+ *
+ * Random-number generators
+ *
+ * (c) 2004 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of the Python interface to Catacomb.
+ *
+ * Catacomb/Python is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb/Python is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Catacomb/Python; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "catacomb-python.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+PyTypeObject *grand_pytype, *truerand_pytype;
+PyTypeObject *lcrand_pytype, *fibrand_pytype;
+PyTypeObject *dsarand_pytype, *bbs_pytype, *bbspriv_pytype;
+PyTypeObject *sslprf_pytype, *tlsdx_pytype, *tlsprf_pytype;
+PyObject *rand_pyobj;
+
+static PyObject *grand_dopywrap(PyTypeObject *ty, grand *r, unsigned f)
+{
+ grand_pyobj *g;
+
+ g = (grand_pyobj *)ty->tp_alloc(ty, 0);
+ g->r = r;
+ g->f = f;
+ return ((PyObject *)g);
+}
+
+PyObject *grand_pywrap(grand *r, unsigned f)
+{
+ PyTypeObject *ty = grand_pytype;
+
+ if (strcmp(r->ops->name, "rand") == 0) ty = truerand_pytype;
+ else if (strcmp(r->ops->name, "lcrand") == 0) ty = lcrand_pytype;
+ else if (strcmp(r->ops->name, "fibrand") == 0) ty = fibrand_pytype;
+ else if (strcmp(r->ops->name, "dsarand") == 0) ty = dsarand_pytype;
+ else if (strcmp(r->ops->name, "bbs") == 0) ty = bbs_pytype;
+ return (grand_dopywrap(ty, r, f));
+}
+
+CONVFUNC(grand, grand *, GRAND_R)
+
+static PyObject *grmeth_byte(PyObject *me, PyObject *arg)
+{
+ if (!PyArg_ParseTuple(arg, ":byte")) return (0);
+ return (PyInt_FromLong(grand_byte(GRAND_R(me))));
+}
+
+static PyObject *grmeth_word(PyObject *me, PyObject *arg)
+{
+ if (!PyArg_ParseTuple(arg, ":word")) return (0);
+ return (getu32(grand_word(GRAND_R(me))));
+}
+
+static PyObject *grmeth_range(PyObject *me, PyObject *arg)
+{
+ PyObject *m;
+ mp *x = 0;
+ mp *y = 0;
+
+ if (!PyArg_ParseTuple(arg, "O:range", &m)) return (0);
+ if (PyInt_Check(m)) {
+ long mm = PyInt_AS_LONG(m);
+ if (mm < 0)
+ goto negative;
+ if (mm <= 0xffffffff)
+ return (PyInt_FromLong(grand_range(GRAND_R(me), mm)));
+ }
+ if ((x = getmp(m)) == 0)
+ goto end;
+ if (MP_NEGP(x))
+ goto negative;
+ y = mprand_range(MP_NEW, x, GRAND_R(me), 0);
+ MP_DROP(x);
+ return (mp_pywrap(y));
+negative:
+ TYERR("range must be nonnegative");
+end:
+ if (x) MP_DROP(x);
+ return (0);
+}
+
+static PyObject *grmeth_mp(PyObject *me, PyObject *arg, PyObject *kw)
+{
+ size_t l;
+ mpw o;
+ char *kwlist[] = { "bits", "or", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|O&:mp", kwlist,
+ convszt, &l, convmpw, &o))
+ goto end;
+ return (mp_pywrap(mprand(MP_NEW, l, GRAND_R(me), o)));
+end:
+ return (0);
+}
+
+static PyObject *grmeth_block(PyObject *me, PyObject *arg)
+{
+ unsigned long n;
+ PyObject *rc = 0;
+
+ if (!PyArg_ParseTuple(arg, "O&:block", convulong, &n)) goto end;
+ rc = bytestring_pywrap(0, n);
+ grand_fill(GRAND_R(me), PyString_AS_STRING(rc), n);
+end:
+ return (rc);
+}
+
+static int checkop(grand *r, unsigned op, const char *what)
+{
+ if (r->ops->misc(r, GRAND_CHECK, op))
+ return (0);
+ PyErr_Format(PyExc_TypeError, "operation %s not supported", what);
+ return (-1);
+}
+
+static PyObject *grmeth_seedint(PyObject *me, PyObject *arg)
+{
+ int i;
+ grand *r = GRAND_R(me);
+ if (!PyArg_ParseTuple(arg, "i:seedint", &i) ||
+ checkop(r, GRAND_SEEDINT, "seedint"))
+ goto end;
+ r->ops->misc(r, GRAND_SEEDINT, i);
+ RETURN_ME;
+end:
+ return (0);
+}
+
+static PyObject *grmeth_seedword(PyObject *me, PyObject *arg)
+{
+ uint32 u;
+ grand *r = GRAND_R(me);
+ if (!PyArg_ParseTuple(arg, "O&:seedword", convu32, &u) ||
+ checkop(r, GRAND_SEEDUINT32, "seedword"))
+ goto end;
+ r->ops->misc(r, GRAND_SEEDUINT32, u);
+ RETURN_ME;
+end:
+ return (0);
+}
+
+static PyObject *grmeth_seedblock(PyObject *me, PyObject *arg)
+{
+ char *p;
+ int n;
+ grand *r = GRAND_R(me);
+ if (!PyArg_ParseTuple(arg, "s#:seedblock", &p, &n) ||
+ checkop(r, GRAND_SEEDBLOCK, "seedblock"))
+ goto end;
+ r->ops->misc(r, GRAND_SEEDBLOCK, p, (size_t)n);
+ RETURN_ME;
+end:
+ return (0);
+}
+
+static PyObject *grmeth_seedmp(PyObject *me, PyObject *arg)
+{
+ PyObject *x;
+ mp *xx;
+ grand *r = GRAND_R(me);
+ if (!PyArg_ParseTuple(arg, "O:seedmp", &x) ||
+ checkop(r, GRAND_SEEDMP, "seedmp") ||
+ (xx = getmp(x)) == 0)
+ goto end;
+ r->ops->misc(r, GRAND_SEEDMP, xx);
+ MP_DROP(xx);
+ RETURN_ME;
+end:
+ return (0);
+}
+
+static PyObject *grmeth_seedrand(PyObject *me, PyObject *arg, PyObject *kw)
+{
+ char *kwlist[] = { "rng", 0 };
+ grand *r = GRAND_R(me);
+ grand *rr = &rand_global;
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:seedrand", kwlist,
+ convgrand, &rr) ||
+ checkop(r, GRAND_SEEDRAND, "seedrand"))
+ goto end;
+ r->ops->misc(r, GRAND_SEEDRAND, rr);
+ RETURN_ME;
+end:
+ return (0);
+}
+
+static PyObject *grmeth_mask(PyObject *me, PyObject *arg)
+{
+ grand *r = GRAND_R(me);
+ char *p, *q;
+ int sz;
+ PyObject *rc;
+
+ if (!PyArg_ParseTuple(arg, "s#:mask", &p, &sz)) return (0);
+ rc = bytestring_pywrap(0, sz);
+ q = PyString_AS_STRING(rc);
+ GR_FILL(r, q, sz);
+ while (sz--) *q++ ^= *p++;
+ return (rc);
+}
+
+static void grand_pydealloc(PyObject *me)
+{
+ grand_pyobj *g = (grand_pyobj *)me;
+ if (g->f & f_freeme)
+ GR_DESTROY(g->r);
+ PyObject_DEL(me);
+}
+
+static PyObject *grget_name(PyObject *me, void *hunoz)
+ { return (PyString_FromString(GRAND_R(me)->ops->name)); }
+
+static PyObject *grget_cryptop(PyObject *me, void *hunoz)
+ { return (getbool(GRAND_R(me)->ops->f & GRAND_CRYPTO)); }
+
+static PyGetSetDef grand_pygetset[] = {
+#define GETSETNAME(op, name) gr##op##_##name
+ GET (name, "R.name -> name of this kind of generator")
+ GET (cryptop, "R.cryptop -> flag: cryptographically strong?")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyMethodDef grand_pymethods[] = {
+#define METHNAME(name) grmeth_##name
+ METH (byte, "R.byte() -> BYTE")
+ METH (word, "R.word() -> WORD")
+ METH (block, "R.block(N) -> STRING")
+ KWMETH(mp, "R.mp(bits, or = 0) -> MP")
+ METH (range, "R.range(MAX) -> INT")
+ METH (mask, "R.mask(STR) -> STR")
+ METH (seedint, "R.seedint(I)")
+ METH (seedword, "R.seedword(I)")
+ METH (seedblock, "R.seedblock(BYTES)")
+ METH (seedmp, "R.seedmp(X)")
+ KWMETH(seedrand, "R.seedrand(RR)")
+#undef METHNAME
+ { 0 }
+};
+
+static PyTypeObject grand_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.GRand", /* @tp_name@ */
+ sizeof(grand_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ grand_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Generic random number source.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ grand_pymethods, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ grand_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ abstract_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyObject *lcrand_pynew(PyTypeObject *me, PyObject *arg, PyObject *kw)
+{
+ uint32 n = 0;
+ char *kwlist[] = { "seed", 0 };
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:new", kwlist, convu32, &n))
+ return (0);
+ return (grand_dopywrap(lcrand_pytype, lcrand_create(n), f_freeme));
+}
+
+static PyTypeObject lcrand_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.LCRand", /* @tp_name@ */
+ sizeof(grand_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ grand_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Linear congruential generator.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ 0, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ lcrand_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyObject *fibrand_pynew(PyTypeObject *me, PyObject *arg, PyObject *kw)
+{
+ uint32 n = 0;
+ char *kwlist[] = { "seed", 0 };
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:new", kwlist, convu32, &n))
+ return (0);
+ return (grand_dopywrap(fibrand_pytype, fibrand_create(n), f_freeme));
+}
+
+static PyTypeObject fibrand_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.FibRand", /* @tp_name@ */
+ sizeof(grand_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ grand_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Fibonacci generator.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ 0, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ fibrand_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- True random generator ---------------------------------------------*/
+
+static PyObject *trmeth_gate(PyObject *me, PyObject *arg)
+{
+ grand *r = GRAND_R(me);
+ if (!PyArg_ParseTuple(arg, ":gate")) return (0);
+ r->ops->misc(r, RAND_GATE);
+ RETURN_ME;
+}
+
+static PyObject *trmeth_stretch(PyObject *me, PyObject *arg)
+{
+ grand *r = GRAND_R(me);
+ if (!PyArg_ParseTuple(arg, ":stretch")) return (0);
+ r->ops->misc(r, RAND_STRETCH);
+ RETURN_ME;
+}
+
+static PyObject *trmeth_key(PyObject *me, PyObject *arg)
+{
+ grand *r = GRAND_R(me);
+ char *p; int n;
+ if (!PyArg_ParseTuple(arg, "s#:key", &p, &n)) return (0);
+ r->ops->misc(r, RAND_KEY, p, n);
+ RETURN_ME;
+}
+
+static PyObject *trmeth_seed(PyObject *me, PyObject *arg)
+{
+ grand *r = GRAND_R(me);
+ unsigned u;
+ if (!PyArg_ParseTuple(arg, "O&:seed", convuint, &u)) return (0);
+ if (u > RAND_IBITS) VALERR("pointlessly large");
+ r->ops->misc(r, RAND_SEED, u);
+ RETURN_ME;
+end:
+ return (0);
+}
+
+static PyObject *trmeth_timer(PyObject *me, PyObject *arg)
+{
+ grand *r = GRAND_R(me);
+ if (!PyArg_ParseTuple(arg, ":timer")) return (0);
+ r->ops->misc(r, RAND_TIMER);
+ RETURN_ME;
+}
+
+static PyObject *truerand_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+{
+ char *kwlist[] = { 0 };
+ grand *r;
+ PyObject *rc = 0;
+ if (PyArg_ParseTupleAndKeywords(arg, kw, ":new", kwlist)) goto end;
+ r = rand_create();
+ r->ops->misc(r, RAND_NOISESRC, &noise_source);
+ r->ops->misc(r, RAND_SEED, 160);
+ rc = grand_dopywrap(ty, r, f_freeme);
+end:
+ return (rc);
+}
+
+static PyMethodDef truerand_pymethods[] = {
+#define METHNAME(name) trmeth_##name
+ METH (gate, "R.gate()")
+ METH (stretch, "R.stretch()")
+ METH (key, "R.key(BYTES)")
+ METH (seed, "R.seed(NBITS)")
+ METH (timer, "R.timer()")
+#undef METHNAME
+ { 0 }
+};
+
+static PyObject *trget_goodbits(PyObject *me, void *hunoz)
+{
+ grand *r = GRAND_R(me);
+ return (PyInt_FromLong(r->ops->misc(r, RAND_GOODBITS)));
+}
+
+static PyGetSetDef truerand_pygetset[] = {
+#define GETSETNAME(op, name) tr##op##_##name
+ GET (goodbits, "R.goodbits -> good bits of entropy remaining")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyTypeObject truerand_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.TrueRand", /* @tp_name@ */
+ sizeof(grand_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ grand_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"True random number source.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ truerand_pymethods, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ truerand_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ truerand_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- SSL and TLS generators --------------------------------------------*/
+
+static PyObject *sslprf_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+{
+ char *k, *s;
+ int ksz, ssz;
+ const gchash *hco = &md5, *hci = &sha;
+ PyObject *rc = 0;
+ char *kwlist[] = { "key", "seed", "ohash", "ihash", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#s#|O&O&:new", kwlist,
+ &k, &ksz, &s, &ssz,
+ convgchash, &hco, convgchash, &hci))
+ goto end;
+ rc = grand_dopywrap(ty, sslprf_rand(hco, hci, k, ksz, s, ssz), f_freeme);
+end:
+ return (rc);
+}
+
+static PyObject *tlsdx_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+{
+ char *k, *s;
+ int ksz, ssz;
+ const gcmac *mc = &sha_hmac;
+ PyObject *rc = 0;
+ char *kwlist[] = { "key", "seed", "mac", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#s#|O&:new", kwlist,
+ &k, &ksz, &s, &ssz,
+ convgcmac, &mc))
+ goto end;
+ rc = grand_dopywrap(ty, tlsdx_rand(mc, k, ksz, s, ssz), f_freeme);
+end:
+ return (rc);
+}
+
+static PyObject *tlsprf_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+{
+ char *k, *s;
+ int ksz, ssz;
+ const gcmac *mcl = &md5_hmac, *mcr = &sha_hmac;
+ PyObject *rc = 0;
+ char *kwlist[] = { "key", "seed", "lmac", "rmac", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#s#|O&O&:new", kwlist,
+ &k, &ksz, &s, &ssz,
+ convgcmac, &mcl, convgcmac, &mcr))
+ goto end;
+ rc = grand_dopywrap(ty, tlsprf_rand(mcl, mcr, k, ksz, s, ssz), f_freeme);
+end:
+ return (rc);
+}
+
+static PyTypeObject sslprf_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.SSLRand", /* @tp_name@ */
+ sizeof(grand_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ grand_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Random number generator for SSL master secret.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ 0, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ sslprf_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyTypeObject tlsdx_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.TLSDataExpansion", /* @tp_name@ */
+ sizeof(grand_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ grand_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"TLS data expansion function.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ 0, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ tlsdx_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyTypeObject tlsprf_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.TLSPRF", /* @tp_name@ */
+ sizeof(grand_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ grand_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"TLS pseudorandom function.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ 0, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ tlsprf_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- DSA generator -----------------------------------------------------*/
+
+static PyObject *dsarand_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+{
+ char *p;
+ int sz;
+ PyObject *rc = 0;
+ char *kwlist[] = { "seed", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", kwlist, &p, &sz))
+ goto end;
+ rc = grand_dopywrap(ty, dsarand_create(p, sz), f_freeme);
+end:
+ return (0);
+}
+
+static PyObject *drget_seed(PyObject *me, void *hunoz)
+{
+ grand *r = GRAND_R(me);
+ int n = r->ops->misc(r, DSARAND_SEEDSZ);
+ PyObject *rc = bytestring_pywrap(0, n);
+ r->ops->misc(r, DSARAND_GETSEED, PyString_AS_STRING(rc));
+ return (rc);
+}
+
+static PyGetSetDef dsarand_pygetset[] = {
+#define GETSETNAME(op, name) dr##op##_##name
+ GET (seed, "R.seed -> current generator seed")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyTypeObject dsarand_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.DSARand", /* @tp_name@ */
+ sizeof(grand_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ grand_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Pseudorandom number generator for constructing DSA parameters.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ dsarand_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ dsarand_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- Blum-Blum-Shub generator ------------------------------------------*/
+
+static PyObject *bbs_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+{
+ mp *n = 0, *x = MP_TWO;
+ PyObject *rc = 0;
+ char *kwlist[] = { "n", "x", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|O&:new", kwlist,
+ convmp, &n, convmp, &x))
+ goto end;
+ rc = grand_dopywrap(ty, bbs_rand(n, x), f_freeme);
+end:
+ mp_drop(n);
+ mp_drop(x);
+ return (rc);
+}
+
+static PyObject *bbsmeth_step(PyObject *me, PyObject *arg)
+{
+ grand *r = GRAND_R(me); if (!PyArg_ParseTuple(arg, ":step")) return (0);
+ r->ops->misc(r, BBS_STEP); RETURN_ME;
+}
+
+static PyObject *bbsmeth_bits(PyObject *me, PyObject *arg)
+{
+ grand *r = GRAND_R(me); unsigned n; uint32 w;
+ if (!PyArg_ParseTuple(arg, "O&:bits", convuint, &n)) goto end;
+ if (n > 32) VALERR("can't get more than 32 bits");
+ r->ops->misc(r, BBS_BITS, n, &w); return (getu32(w));
+end:
+ return (0);
+}
+
+static PyObject *bbsmeth_wrap(PyObject *me, PyObject *arg)
+{
+ grand *r = GRAND_R(me); if (!PyArg_ParseTuple(arg, ":wrap")) return (0);
+ r->ops->misc(r, BBS_WRAP); RETURN_ME;
+}
+
+static PyObject *bbsget_n(PyObject *me, void *hunoz)
+{
+ mp *x = MP_NEW; grand *r = GRAND_R(me);
+ r->ops->misc(r, BBS_MOD, &x); return (mp_pywrap(x));
+}
+
+static PyObject *bbsget_x(PyObject *me, void *hunoz)
+{
+ mp *x = MP_NEW; grand *r = GRAND_R(me);
+ r->ops->misc(r, BBS_STATE, &x); return (mp_pywrap(x));
+}
+
+static int bbsset_x(PyObject *me, PyObject *val, void *hunoz)
+{
+ mp *x = 0; grand *r = GRAND_R(me); int rc = -1;
+ if ((x = getmp(val)) == 0) goto end; r->ops->misc(r, BBS_SET, x); rc = 0;
+ end: mp_drop(x); return (rc);
+}
+
+static PyObject *bbsget_stepsz(PyObject *me, void *hunoz)
+{
+ grand *r = GRAND_R(me);
+ return (PyInt_FromLong(r->ops->misc(r, BBS_STEPSZ)));
+}
+
+static PyMethodDef bbs_pymethods[] = {
+#define METHNAME(name) bbsmeth_##name
+ METH (step, "R.step(): steps the generator (not useful)")
+ METH (bits, "R.bits(N) -> W: returns N bits (<= 32) from the generator")
+ METH (wrap, "R.wrap(): flushes unused bits in internal buffer")
+#undef METHNAME
+ { 0 }
+};
+
+static PyGetSetDef bbs_pygetset[] = {
+#define GETSETNAME(op, name) bbs##op##_##name
+ GET (n, "R.n -> Blum modulus")
+ GETSET(x, "R.x -> current seed value")
+ GET (stepsz, "R.stepsz -> number of bits generated per step")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyTypeObject bbs_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.BlumBlumShub", /* @tp_name@ */
+ sizeof(grand_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ grand_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Blum-Blum-Shub strong pseudorandom number generator.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ bbs_pymethods, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ bbs_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ bbs_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+typedef struct bbspriv_pyobj {
+ grand_pyobj gr;
+ bbs_priv bp;
+} bbspriv_pyobj;
+
+#define BBSPRIV_BP(o) (&((bbspriv_pyobj *)(o))->bp)
+
+static PyObject *bbspriv_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+{
+ mp *p = 0, *q = 0, *n = 0, *x = MP_TWO;
+ bbspriv_pyobj *rc = 0;
+ char *kwlist[] = { "n", "p", "q", "seed", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&O&O&O&:new", kwlist,
+ convmp, &n, convmp, &p, convmp, &q,
+ convmp, &x))
+ goto end;
+ if (!n + !p + !q > 1) VALERR("must specify at least two of n, p, q");
+ if (!n) n = mp_mul(MP_NEW, p, q);
+ else if (!p) mp_div(&p, 0, n, q);
+ else if (!q) mp_div(&q, 0, n, p);
+ rc = (bbspriv_pyobj *)ty->tp_alloc(ty, 0);
+ rc->gr.r = bbs_rand(n, x);
+ rc->gr.f = f_freeme;
+ rc->bp.p = MP_COPY(p);
+ rc->bp.q = MP_COPY(q);
+ rc->bp.n = MP_COPY(n);
+end:
+ mp_drop(p); mp_drop(q); mp_drop(n); mp_drop(x);
+ return ((PyObject *)rc);
+}
+
+static PyObject *meth__BBSPriv_generate(PyObject *me,
+ PyObject *arg, PyObject *kw)
+{
+ bbs_priv bp = { 0 };
+ mp *x = MP_TWO;
+ pgev evt = { 0 };
+ unsigned nbits, n = 0;
+ grand *r = &rand_global;
+ char *kwlist[] = { "class", "nbits", "event", "rng", "nsteps", "seed", 0 };
+ bbspriv_pyobj *rc = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO&|O&O&O&O&:generate", kwlist,
+ &me, convuint, &nbits, convpgev, &evt,
+ convgrand, &r, convuint, &n, convmp, &x))
+ goto end;
+ if (bbs_gen(&bp, nbits, r, n, evt.proc, evt.ctx))
+ VALERR("prime genration failed");
+ rc = PyObject_New(bbspriv_pyobj, bbspriv_pytype);
+ rc->gr.r = bbs_rand(bp.n, x);
+ rc->gr.f = f_freeme;
+ rc->bp.p = MP_COPY(bp.p);
+ rc->bp.q = MP_COPY(bp.q);
+ rc->bp.n = MP_COPY(bp.n);
+end:
+ mp_drop(bp.p); mp_drop(bp.q); mp_drop(bp.n); mp_drop(x);
+ return ((PyObject *)rc);
+}
+
+static void bbspriv_pydealloc(PyObject *me)
+{
+ bbs_priv *bp = BBSPRIV_BP(me);
+ mp_drop(bp->n);
+ mp_drop(bp->p);
+ mp_drop(bp->q);
+ grand_pydealloc(me);
+}
+
+static PyObject *bpmeth_ff(PyObject *me, PyObject *arg)
+{
+ mp *n = 0; grand *r = GRAND_R(me); bbs_priv *bp = BBSPRIV_BP(me);
+ if (!PyArg_ParseTuple(arg, "O&:ff", convmp, &n)) return (0);
+ r->ops->misc(r, BBS_FF, bp, n); RETURN_ME;
+}
+
+static PyObject *bpmeth_rew(PyObject *me, PyObject *arg)
+{
+ mp *n = 0; grand *r = GRAND_R(me); bbs_priv *bp = BBSPRIV_BP(me);
+ if (!PyArg_ParseTuple(arg, "O&:rew", convmp, &n)) return (0);
+ r->ops->misc(r, BBS_REW, bp, n); RETURN_ME;
+}
+
+static PyObject *bpget_n(PyObject *me, void *hunoz)
+ { return (mp_pywrap(MP_COPY(BBSPRIV_BP(me)->n))); }
+
+static PyObject *bpget_p(PyObject *me, void *hunoz)
+ { return (mp_pywrap(MP_COPY(BBSPRIV_BP(me)->p))); }
+
+static PyObject *bpget_q(PyObject *me, void *hunoz)
+ { return (mp_pywrap(MP_COPY(BBSPRIV_BP(me)->q))); }
+
+static PyMethodDef bbspriv_pymethods[] = {
+#define METHNAME(name) bpmeth_##name
+ METH (ff, "R.ff(N): fast-forward N places")
+ METH (rew, "R.rew(N): rewind N places")
+#undef METHNAME
+ { 0 }
+};
+
+static PyGetSetDef bbspriv_pygetset[] = {
+#define GETSETNAME(op, name) bp##op##_##name
+ GET (n, "R.n -> Blum modulus")
+ GET (p, "R.p -> one of the factors of the modulus")
+ GET (q, "R.q -> one of the factors of the modulus")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyTypeObject bbspriv_pytype_skel = {
+ PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */
+ "catacomb.BBSPriv", /* @tp_name@ */
+ sizeof(bbspriv_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ bbspriv_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+"Blum-Blum-Shub strong pseudorandom generator, with private key.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ bbspriv_pymethods, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ bbspriv_pygetset, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ 0, /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ bbspriv_pynew, /* @tp_new@ */
+ _PyObject_Del, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- Global stuff ------------------------------------------------------*/
+
+static PyMethodDef methods[] = {
+#define METHNAME(name) meth_##name
+ KWMETH(_BBSPriv_generate, "\
+generate(NBITS, [event = pgen_nullev, rng = rand, nsteps = 0, seed = 2])")
+#undef METHNAME
+ { 0 }
+};
+
+void rand_pyinit(void)
+{
+ INITTYPE(grand, root);
+ INITTYPE(truerand, grand);
+ INITTYPE(fibrand, grand);
+ INITTYPE(lcrand, grand);
+ INITTYPE(dsarand, grand);
+ INITTYPE(bbs, grand);
+ INITTYPE(bbspriv, bbs);
+ INITTYPE(sslprf, grand);
+ INITTYPE(tlsdx, grand);
+ INITTYPE(tlsprf, grand);
+ rand_noisesrc(RAND_GLOBAL, &noise_source);
+ rand_seed(RAND_GLOBAL, 160);
+ addmethods(methods);
+}
+
+void rand_pyinsert(PyObject *mod)
+{
+ INSERT("GRand", grand_pytype);
+ INSERT("TrueRand", truerand_pytype);
+ INSERT("LCRand", lcrand_pytype);
+ INSERT("FibRand", fibrand_pytype);
+ INSERT("SSLRand", sslprf_pytype);
+ INSERT("TLSDataExpansion", tlsdx_pytype);
+ INSERT("TLSPRF", tlsprf_pytype);
+ INSERT("DSARand", dsarand_pytype);
+ INSERT("BlumBlumShub", bbs_pytype);
+ INSERT("BBSPriv", bbspriv_pytype);
+ rand_pyobj = grand_pywrap(&rand_global, 0); Py_INCREF(rand_pyobj);
+ INSERT("rand", rand_pyobj);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+#! /usr/bin/python
+
+from distutils.core import setup, Extension
+from os import *
+from os import _exit
+from errno import *
+import sys
+from sys import stdin, stdout, stderr
+
+def progoutput(cmd):
+ p = popen(cmd)
+ out = p.readline()
+ if p.read() != '': raise 'extra junk from %s' % cmd
+ p.close()
+ return out.rstrip('\n')
+
+incdirs = []
+libdirs = []
+libs = []
+
+def libconfig(lib, ver):
+ config = lib + '-config'
+ if system('%s --check %s' % (config, ver)):
+ raise '%s version %s not found' % (lib, ver)
+ version = progoutput('%s --version' % config)
+ for i in progoutput('%s --cflags' % config).split():
+ if i[:2] == '-I': incdirs.append(i[2:])
+ else: raise 'strange cflags item %s' % i
+ for i in progoutput('%s --libs' % config).split():
+ if i[:2] == '-L': libdirs.append(i[2:])
+ elif i[:2] == '-l': libs.append(i[2:])
+ else: raise 'strange libs item %s' % i
+
+def uniquify(l):
+ u = {}
+ o = []
+ for i in l:
+ if i not in u:
+ o.append(i)
+ u[i] = 1
+ return o
+
+cflags = []
+libs = []
+libconfig('mLib', '2.0.3')
+libconfig('catacomb', '2.1.0')
+
+class SubprocessFailure (Exception):
+ def __init__(me, file, rc):
+ me.args = (file, rc)
+ me.file = file
+ me.rc = rc
+ def __str__(me):
+ if WIFEXITED(me.rc):
+ return '%s failed (rc = %d)' % (me.file, WEXITSTATUS(me.rc))
+ elif WIFSIGNALED(me.rc):
+ return '%s died (signal %d)' % (me.file, WTERMSIG(me.rc))
+ else:
+ return '%s died inexplicably' % (me.file)
+
+for g in ['algorithms.h']:
+ if type(g) == tuple:
+ fin, fout = g
+ else:
+ root, ext = path.splitext(g)
+ fin = root + '.py'
+ fout = g
+ stin = stat(fin)
+ try:
+ stout = stat(fout)
+ updatep = stin.st_mtime > stout.st_mtime
+ except OSError, err:
+ if err.errno == ENOENT:
+ updatep = True
+ else:
+ raise
+ if updatep:
+ kid = fork()
+ print 'running %s to create %s' % (fin, fout)
+ fnew = fout + '.new'
+ if kid == 0:
+ try:
+ out = file(fnew, 'w')
+ dup2(out.fileno(), stdout.fileno())
+ out.close()
+ execl(sys.executable, sys.executable, fin)
+ except:
+ stderr.write('error running %s -> %s: %s\n' %
+ (fin, fout, sys.exc_info()[1]))
+ _exit(127)
+ _, rc = waitpid(kid, 0)
+ if rc:
+ raise SubprocessFailure, (fin, rc)
+ rename(fnew, fout)
+
+cat = Extension('catacomb._base',
+ ['catacomb.c', 'bytestring.c',
+ 'rand.c', 'algorithms.c', 'pubkey.c', 'pgen.c',
+ 'mp.c', 'field.c', 'ec.c', 'group.c', 'passphrase.c'],
+ ##extra_compile_args = ['-O0'],
+ include_dirs = uniquify(incdirs),
+ library_dirs = uniquify(libdirs),
+ libraries = uniquify(libs))
+
+setup(name = 'Catacomb',
+ version = '2.1.0',
+ description = 'Interface to Catacomb cryptographic library',
+ url = 'http://tux.nsict.org/~mdw/Catacomb-2.1.0',
+ author = 'Straylight/Edgeware',
+ author_email = 'mdw@nsict.org',
+ license = 'GNU General Public License',
+ packages = ['catacomb'],
+ scripts = ['pwsafe'],
+ ext_modules = [cat])