+#define DEF_HDANCE(DANCE, HDANCE, dance, hdance) \
+ static PyObject *meth_##hdance##_prf(PyObject *me, PyObject *arg) \
+ { \
+ dance##_ctx dance; \
+ char *k, *n; \
+ Py_ssize_t ksz, nsz; \
+ PyObject *rc; \
+ if (!PyArg_ParseTuple(arg, "s#s#:" #hdance "_prf", \
+ &k, &ksz, &n, &nsz)) \
+ goto end; \
+ if (ksz != DANCE##_KEYSZ) VALERR("bad key length"); \
+ if (nsz != HDANCE##_INSZ) VALERR("bad input length"); \
+ rc = bytestring_pywrap(0, HSALSA20_OUTSZ); \
+ dance##_init(&dance, k, ksz, 0); \
+ hdance##_prf(&dance, n, PyString_AS_STRING(rc)); \
+ return (rc); \
+ end: \
+ return (0); \
+ }
+
+DEF_HDANCE(SALSA20, HSALSA20, salsa20, hsalsa20)
+DEF_HDANCE(SALSA20, HSALSA20, salsa20, hsalsa2012)
+DEF_HDANCE(SALSA20, HSALSA20, salsa20, hsalsa208)
+
+DEF_HDANCE(CHACHA, HCHACHA, chacha, hchacha20)
+DEF_HDANCE(CHACHA, HCHACHA, chacha, hchacha12)
+DEF_HDANCE(CHACHA, HCHACHA, chacha, hchacha8)
+
+/*----- Keccak-p[1600, n] -------------------------------------------------*/
+
+static PyTypeObject *kxvik_pytype;
+
+typedef struct kxvik_pyobj {
+ PyObject_HEAD
+ keccak1600_state s;
+ unsigned n;
+} kxvik_pyobj;
+
+static PyObject *kxvik_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+{
+ unsigned n = 24;
+ kxvik_pyobj *rc = 0;
+ char *kwlist[] = { "nround", 0 };
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:new", kwlist,
+ convuint, &n))
+ goto end;
+ rc = (kxvik_pyobj *)ty->tp_alloc(ty, 0);
+ rc->n = n;
+ keccak1600_init(&rc->s);
+end:
+ return ((PyObject *)rc);
+}
+
+static PyObject *kxvikmeth_mix(PyObject *me, PyObject *arg)
+{
+ kxvik_pyobj *k = (kxvik_pyobj *)me;
+ kludge64 t[25];
+ const octet *q;
+ octet buf[8];
+ unsigned i;
+ char *p; Py_ssize_t n;
+
+ if (!PyArg_ParseTuple(arg, "s#:mix", &p, &n)) goto end;
+ if (n > 200) VALERR("out of range");
+ q = (const octet *)p;
+ i = 0;
+ while (n > 8) { LOAD64_L_(t[i], q); i++; q += 8; n -= 8; }
+ if (n) {
+ memcpy(buf, q, n); memset(buf + n, 0, 8 - n);
+ LOAD64_L_(t[i], buf); i++;
+ }
+ keccak1600_mix(&k->s, t, i);
+ RETURN_ME;
+end:
+ return (0);
+}
+
+static PyObject *kxvikmeth_extract(PyObject *me, PyObject *arg)
+{
+ kxvik_pyobj *k = (kxvik_pyobj *)me;
+ PyObject *rc = 0;
+ kludge64 t[25];
+ octet *q, buf[8];
+ unsigned i;
+ unsigned n;
+
+ if (!PyArg_ParseTuple(arg, "O&:mix", convuint, &n)) goto end;
+ if (n > 200) VALERR("out of range");
+ rc = bytestring_pywrap(0, n);
+ q = (octet *)PyString_AS_STRING(rc);
+ keccak1600_extract(&k->s, t, (n + 7)/8);
+ i = 0;
+ while (n > 8) { STORE64_L_(q, t[i]); i++; q += 8; n -= 8; }
+ if (n) { STORE64_L_(buf, t[i]); memcpy(q, buf, n); }
+end:
+ return (rc);
+}
+
+static PyObject *kxvikmeth_step(PyObject *me, PyObject *arg)
+{
+ kxvik_pyobj *k = (kxvik_pyobj *)me;
+ if (!PyArg_ParseTuple(arg, ":step")) return (0);
+ keccak1600_p(&k->s, &k->s, k->n);
+ RETURN_ME;
+}
+
+static PyObject *kxvikget_nround(PyObject *me, void *hunoz)
+{
+ kxvik_pyobj *k = (kxvik_pyobj *)me;
+ return (PyInt_FromLong(k->n));
+}
+
+static int kxvikset_nround(PyObject *me, PyObject *val, void *hunoz)
+{
+ kxvik_pyobj *k = (kxvik_pyobj *)me;
+ unsigned n;
+ int rc = -1;
+
+ if (!val) NIERR("__del__");
+ if (!convuint(val, &n)) goto end;
+ k->n = n;
+ rc = 0;
+end:
+ return (rc);
+}
+
+static PyGetSetDef kxvik_pygetset[] = {
+#define GETSETNAME(op, name) kxvik##op##_##name
+ GETSET(nround, "KECCAK.nround -> number of rounds")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyMethodDef kxvik_pymethods[] = {
+#define METHNAME(func) kxvikmeth_##func
+ METH (mix, "KECCAK.mix(DATA)")
+ METH (extract, "KECCAK.extract(NOCTETS)")
+ METH (step, "KECCAK.step()")
+#undef METHNAME
+ { 0 }
+};
+
+static PyTypeObject kxvik_pytype_skel = {
+ PyObject_HEAD_INIT(0) 0, /* Header */
+ "Keccak1600", /* @tp_name@ */
+ sizeof(kxvik_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@ */
+"Keccak-p[1600, n] state.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternext@ */
+ kxvik_pymethods, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ kxvik_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@ */
+ kxvik_pynew, /* @tp_new@ */
+ 0, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyTypeObject *shake_pytype, *shake128_pytype, *shake256_pytype;
+
+typedef struct shake_pyobj {
+ PyObject_HEAD
+ int st;
+ shake_ctx h;
+} shake_pyobj;
+
+#define SHAKE_H(o) (&((shake_pyobj *)(o))->h)
+#define SHAKE_ST(o) (((shake_pyobj *)(o))->st)
+
+static PyObject *shake_dopynew(void (*initfn)(shake_ctx *,
+ const void *, size_t,
+ const void *, size_t),
+ PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+{
+ shake_pyobj *rc = 0;
+ char *p = 0, *f = 0;
+ Py_ssize_t psz = 0, fsz = 0;
+ char *kwlist[] = { "perso", "func", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|s#s#:new", kwlist,
+ &p, &psz, &f, &fsz))
+ goto end;
+ rc = (shake_pyobj *)ty->tp_alloc(ty, 0);
+ initfn(&rc->h, f, fsz, p, psz);
+ rc->st = 0;
+end:
+ return ((PyObject *)rc);
+}
+
+static PyObject *shake128_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+ { return (shake_dopynew(cshake128_init, ty, arg, kw)); }
+
+static PyObject *shake256_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+ { return (shake_dopynew(cshake256_init, ty, arg, kw)); }
+
+static int shake_check(PyObject *me, int st)
+{
+ if (SHAKE_ST(me) != st) VALERR("wrong state");
+ return (0);
+end:
+ return (-1);
+}
+
+static PyObject *shakemeth_hash(PyObject *me, PyObject *arg)
+{
+ char *p;
+ Py_ssize_t sz;
+ if (!PyArg_ParseTuple(arg, "s#:hash", &p, &sz)) return (0);
+ if (shake_check(me, 0)) return (0);
+ shake_hash(SHAKE_H(me), p, sz);
+ RETURN_ME;
+}
+
+#define SHAKEMETH_HASHU_(n, W, w) \
+ static PyObject *shakemeth_hashu##w(PyObject *me, PyObject *arg) \
+ { \
+ uint##n x; \
+ octet b[SZ_##W]; \
+ if (!PyArg_ParseTuple(arg, "O&:hashu" #w, convu##n, &x)) goto end; \
+ if (shake_check(me, 0)) goto end; \
+ STORE##W(b, x); shake_hash(SHAKE_H(me), b, sizeof(b)); \
+ RETURN_ME; \
+ end: \
+ return (0); \
+ }
+DOUINTCONV(SHAKEMETH_HASHU_)
+
+#define SHAKEMETH_HASHBUF_(n, W, w) \
+ static PyObject *shakemeth_hashbuf##w(PyObject *me, PyObject *arg) \
+ { \
+ char *p; \
+ Py_ssize_t sz; \
+ octet b[SZ_##W]; \
+ if (!PyArg_ParseTuple(arg, "s#:hashbuf" #w, &p, &sz)) goto end; \
+ if (sz > MASK##n) TYERR("string too long"); \
+ if (shake_check(me, 0)) goto end; \
+ STORE##W(b, sz); shake_hash(SHAKE_H(me), b, sizeof(b)); \
+ shake_hash(SHAKE_H(me), p, sz); \
+ RETURN_ME; \
+ end: \
+ return (0); \
+ }
+DOUINTCONV(SHAKEMETH_HASHBUF_)
+
+static PyObject *shakemeth_hashstrz(PyObject *me, PyObject *arg)
+{
+ char *p;
+ if (!PyArg_ParseTuple(arg, "s:hashstrz", &p)) return (0);
+ if (shake_check(me, 0)) return (0);
+ shake_hash(SHAKE_H(me), p, strlen(p) + 1);
+ RETURN_ME;
+}
+
+static PyObject *shakemeth_xof(PyObject *me, PyObject *arg)
+{
+ if (!PyArg_ParseTuple(arg, ":xof")) goto end;
+ if (shake_check(me, 0)) goto end;
+ shake_xof(SHAKE_H(me));
+ SHAKE_ST(me) = 1;
+ RETURN_ME;
+end:
+ return (0);
+}
+
+static PyObject *shakemeth_done(PyObject *me, PyObject *arg)
+{
+ PyObject *rc = 0;
+ size_t n;
+ if (!PyArg_ParseTuple(arg, "O&:done", convszt, &n)) goto end;
+ if (shake_check(me, 0)) goto end;
+ rc = bytestring_pywrap(0, n);
+ shake_done(SHAKE_H(me), PyString_AS_STRING(rc), n);
+ SHAKE_ST(me) = -1;
+end:
+ return (rc);
+}
+
+static PyObject *shakemeth_copy(PyObject *me, PyObject *arg)
+{
+ shake_pyobj *rc = 0;
+
+ if (!PyArg_ParseTuple(arg, ":copy")) goto end;
+ rc = PyObject_NEW(shake_pyobj, me->ob_type);
+ rc->h = *SHAKE_H(me);
+ rc->st = SHAKE_ST(me);
+end:
+ return ((PyObject *)me);
+}
+
+static PyObject *shakemeth_get(PyObject *me, PyObject *arg)
+{
+ PyObject *rc = 0;
+ size_t sz;
+
+ if (!PyArg_ParseTuple(arg, "O&:get", convszt, &sz)) goto end;
+ if (shake_check(me, 1)) goto end;
+ rc = bytestring_pywrap(0, sz);
+ shake_get(SHAKE_H(me), PyString_AS_STRING(rc), sz);
+end:
+ return (rc);
+}
+
+static PyObject *shakemeth_mask(PyObject *me, PyObject *arg)
+{
+ PyObject *rc = 0;
+ char *p; Py_ssize_t sz;
+
+ if (!PyArg_ParseTuple(arg, "s#:mask", &p, &sz)) goto end;
+ if (shake_check(me, 1)) goto end;
+ rc = bytestring_pywrap(0, sz);
+ shake_mask(SHAKE_H(me), p, PyString_AS_STRING(rc), sz);
+end:
+ return (rc);
+}
+
+static PyObject *shakeget_rate(PyObject *me, void *hunoz)
+ { return (PyInt_FromLong(SHAKE_H(me)->h.r)); }
+
+static PyObject *shakeget_buffered(PyObject *me, void *hunoz)
+ { return (PyInt_FromLong(SHAKE_H(me)->h.n)); }
+
+static PyObject *shakeget_state(PyObject *me, void *hunoz)
+{
+ int st = SHAKE_ST(me);
+ return (PyString_FromString(st == 0 ? "absorb" :
+ st == 1 ? "squeeze" : "dead"));
+}
+
+static PyGetSetDef shake_pygetset[] = {
+#define GETSETNAME(op, name) shake##op##_##name
+ GET (rate, "S.rate -> rate, in bytes")
+ GET (buffered, "S.buffered -> amount currently buffered")
+ GET (state, "S.state -> `absorb', `squeeze', `dead'")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyMethodDef shake_pymethods[] = {
+#define METHNAME(func) shakemeth_##func
+ METH (copy, "S.copy() -> SS")
+ METH (hash, "S.hash(M)")
+#define METHU_(n, W, w) METH(hashu##w, "S.hashu" #w "(WORD)")
+ DOUINTCONV(METHU_)
+#undef METHU_
+#define METHBUF_(n, W, w) METH(hashbuf##w, "S.hashbuf" #w "(BYTES)")
+ DOUINTCONV(METHBUF_)
+#undef METHBUF_
+ METH (hashstrz, "S.hashstrz(STRING)")
+ METH (xof, "S.xof()")
+ METH (done, "S.done(LEN) ->H")
+ METH (get, "S.get(LEN) -> H")
+ METH (mask, "S.mask(M) -> C")
+#undef METHNAME
+ { 0 }
+};
+
+static PyTypeObject shake_pytype_skel = {
+ PyObject_HEAD_INIT(0) 0, /* Header */
+ "Shake", /* @tp_name@ */
+ sizeof(shake_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@ */
+"SHAKE/cSHAKE base class.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternext@ */
+ shake_pymethods, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ shake_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@ */
+ 0, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyTypeObject shake128_pytype_skel = {
+ PyObject_HEAD_INIT(0) 0, /* Header */
+ "Shake128", /* @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@ */
+ 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@ */
+"SHAKE128/cSHAKE128 XOF.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternext@ */
+ 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@ */
+ shake128_pynew, /* @tp_new@ */
+ 0, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyTypeObject shake256_pytype_skel = {
+ PyObject_HEAD_INIT(0) 0, /* Header */
+ "Shake256", /* @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@ */
+ 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@ */
+"SHAKE256/cSHAKE256 XOF.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternext@ */
+ 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@ */
+ shake256_pynew, /* @tp_new@ */
+ 0, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- Pseudorandom permutations -----------------------------------------*/
+
+static PyTypeObject *gcprp_pytype, *gprp_pytype;
+
+typedef struct prpinfo {
+ const char *name;
+ const octet *keysz;
+ size_t ctxsz;
+ size_t blksz;
+ void (*init)(void *, const void *, size_t);
+ void (*eblk)(void *, const void *, void *);
+ void (*dblk)(void *, const void *, void *);
+} prpinfo;
+
+#define PRP_DEF(PRE, pre) \
+ static void pre##_prpinit(void *ctx, const void *k, size_t ksz) \
+ { pre##_init(ctx, k, ksz); } \
+ static void pre##_prpeblk(void *ctx, const void *in, void *out) \
+ { \
+ uint32 w[PRE##_BLKSZ/4]; BLKC_LOAD(PRE, w, in); \
+ pre##_eblk(ctx, w, w); BLKC_STORE(PRE, out, w); \
+ } \
+ static void pre##_prpdblk(void *ctx, const void *in, void *out) \
+ { \
+ uint32 w[PRE##_BLKSZ/4]; BLKC_LOAD(PRE, w, in); \
+ pre##_dblk(ctx, w, w); BLKC_STORE(PRE, out, w); \
+ } \
+ static const prpinfo pre##_prpinfo = { \
+ #pre, pre##_keysz, sizeof(pre##_ctx), PRE##_BLKSZ, \
+ pre##_prpinit, pre##_prpeblk, pre##_prpdblk \
+ };
+PRPS(PRP_DEF)
+
+static const struct prpinfo *const gprptab[] = {
+#define PRP_ENTRY(PRE, pre) &pre##_prpinfo,
+ PRPS(PRP_ENTRY)
+ 0
+};
+
+typedef struct gcprp_pyobj {
+ PyHeapTypeObject ty;
+ const prpinfo *prp;
+} gcprp_pyobj;
+#define GCPRP_PRP(o) (((gcprp_pyobj *)(o))->prp)
+
+typedef struct gprp_pyobj {
+ PyObject_HEAD
+ const prpinfo *prp;
+} gprp_pyobj;
+#define GPRP_PRP(o) (((gprp_pyobj *)(o))->prp)
+#define GPRP_CTX(o) (((gprp_pyobj *)(o)) + 1)
+
+typedef struct prp {
+ const prpinfo *prp;
+ void *ctx;
+} prp;
+
+static PyObject *gprp_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+{
+ char *kwlist[] = { "key", 0 };
+ char *k;
+ Py_ssize_t sz;
+ const prpinfo *prp = GCPRP_PRP(ty);
+ PyObject *me;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", kwlist, &k, &sz))
+ goto end;
+ if (keysz(sz, prp->keysz) != sz) VALERR("bad key length");
+ me = (PyObject *)ty->tp_alloc(ty, 0);
+ GPRP_PRP(me) = prp;
+ prp->init(GPRP_CTX(me), k, sz);
+ Py_INCREF(me);
+ return (me);
+end:
+ return (0);
+}
+
+static void gprp_pydealloc(PyObject *me)
+ { Py_DECREF(me->ob_type); FREEOBJ(me); }
+
+static PyObject *gcprp_pywrap(const prpinfo *prp)
+{
+ gcprp_pyobj *g = newtype(gcprp_pytype, 0, prp->name);
+ g->prp = prp;
+ g->ty.ht_type.tp_basicsize = sizeof(gprp_pyobj) + prp->ctxsz;
+ g->ty.ht_type.tp_base = gprp_pytype;
+ Py_INCREF(gprp_pytype);
+ g->ty.ht_type.tp_flags = (Py_TPFLAGS_DEFAULT |
+ Py_TPFLAGS_BASETYPE |
+ Py_TPFLAGS_HEAPTYPE);
+ g->ty.ht_type.tp_alloc = PyType_GenericAlloc;
+ g->ty.ht_type.tp_free = 0;
+ g->ty.ht_type.tp_new = gprp_pynew;
+ typeready(&g->ty.ht_type);
+ return ((PyObject *)g);
+}
+
+static PyObject *gcpget_name(PyObject *me, void *hunoz)
+ { return (PyString_FromString(GCPRP_PRP(me)->name)); }
+static PyObject *gcpget_keysz(PyObject *me, void *hunoz)
+ { return (keysz_pywrap(GCPRP_PRP(me)->keysz)); }
+static PyObject *gcpget_blksz(PyObject *me, void *hunoz)
+ { return (PyInt_FromLong(GCPRP_PRP(me)->blksz)); }
+
+static PyObject *gpmeth_encrypt(PyObject *me, PyObject *arg)
+{
+ char *p;
+ Py_ssize_t n;
+ PyObject *rc = 0;
+
+ if (!PyArg_ParseTuple(arg, "s#:encrypt", &p, &n)) goto end;
+ if (n != GPRP_PRP(me)->blksz) VALERR("incorrect block length");
+ rc = bytestring_pywrap(0, n);
+ GPRP_PRP(me)->eblk(GPRP_CTX(me), p, PyString_AS_STRING(rc));
+end:
+ return (rc);
+}
+
+static PyObject *gpmeth_decrypt(PyObject *me, PyObject *arg)
+{
+ char *p;
+ Py_ssize_t n;
+ PyObject *rc = 0;
+
+ if (!PyArg_ParseTuple(arg, "s#:decrypt", &p, &n)) goto end;
+ if (n != GPRP_PRP(me)->blksz) VALERR("incorrect block length");
+ rc = bytestring_pywrap(0, n);
+ GPRP_PRP(me)->dblk(GPRP_CTX(me), p, PyString_AS_STRING(rc));
+end:
+ return (rc);
+}
+
+static PyGetSetDef gcprp_pygetset[] = {
+#define GETSETNAME(op, name) gcp##op##_##name
+ GET (keysz, "CP.keysz -> acceptable key sizes")
+ GET (blksz, "CP.blksz -> block size")
+ GET (name, "CP.name -> name of this kind of PRP")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyMethodDef gprp_pymethods[] = {
+#define METHNAME(name) gpmeth_##name
+ METH (encrypt, "P.encrypt(PT) -> CT")
+ METH (decrypt, "P.decrypt(CT) -> PT")
+#undef METHNAME
+ { 0 }
+};
+
+static PyTypeObject gcprp_pytype_skel = {
+ PyObject_HEAD_INIT(0) 0, /* Header */
+ "GCPRP", /* @tp_name@ */
+ sizeof(gcprp_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@ */
+"Pseudorandom permutation metaclass.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternext@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ gcprp_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@ */
+ 0, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyTypeObject gprp_pytype_skel = {
+ PyObject_HEAD_INIT(0) 0, /* Header */
+ "GPRP", /* @tp_name@ */
+ sizeof(gprp_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ gprp_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 permutation, abstract base class.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternext@ */
+ gprp_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@ */
+ 0, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- Main code ---------------------------------------------------------*/
+
+static PyMethodDef methods[] = {
+#define METHNAME(func) meth_##func
+ METH (_KeySZ_fromdl, "\
+fromdl(N) -> M: convert integer discrete log field size to work factor")
+ METH (_KeySZ_fromschnorr, "\
+fromschnorr(N) -> M: convert Schnorr group order to work factor")
+ METH (_KeySZ_fromif, "\
+fromif(N) -> M: convert integer factorization problem size to work factor")
+ METH (_KeySZ_fromec, "\
+fromec(N) -> M: convert elliptic curve group order to work factor")
+ METH (_KeySZ_todl, "\
+todl(N) -> M: convert work factor to integer discrete log field size")
+ METH (_KeySZ_toschnorr, "\
+toschnorr(N) -> M: convert work factor to Schnorr group order")
+ METH (_KeySZ_toif, "\
+toif(N) -> M: convert work factor to integer factorization problem size")
+ METH (_KeySZ_toec, "\
+toec(N) -> M: convert work factor to elliptic curve group order")