From: Mark Wooding Date: Thu, 11 May 2017 09:42:15 +0000 (+0100) Subject: algorithms.c: Add basic support for Keccak[1600, n]. X-Git-Tag: 1.2.0~11 X-Git-Url: https://git.distorted.org.uk/~mdw/catacomb-python/commitdiff_plain/b35fdbe6fd7d9d46d5e195ae8cfd14d5729d3234 algorithms.c: Add basic support for Keccak[1600, n]. This takes the form of a simple object which encapsulates the Keccak[1600, n] state and allows mix and extract operations (which correspond to the I/O portions of absorb/squeeze and duplexing) and step, which actually invokes the permutation to advance the state. None of this keeps track of rate or capacity limits beyond the obvious memory-safety checks, so you can really screw yourself if you're not careful. --- diff --git a/algorithms.c b/algorithms.c index 5703901..e4233fa 100644 --- a/algorithms.c +++ b/algorithms.c @@ -1586,6 +1586,165 @@ 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; + + if (!convuint(val, &n)) return (-1); + k->n = n; + return (0); +} + +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@ */ +}; + /*----- Pseudorandom permutations -----------------------------------------*/ static PyTypeObject *gcprp_pytype, *gprp_pytype; @@ -1882,6 +2041,7 @@ void algorithms_pyinit(void) INITTYPE(poly1305cls, type); INITTYPE_META(poly1305key, type, poly1305cls); INITTYPE(poly1305hash, root); + INITTYPE(kxvik, root); INITTYPE(gcprp, type); INITTYPE(gprp, root); addmethods(methods); @@ -1915,6 +2075,7 @@ void algorithms_pyinsert(PyObject *mod) INSERT("Poly1305Class", poly1305cls_pytype); INSERT("poly1305", poly1305key_pytype); INSERT("Poly1305Hash", poly1305hash_pytype); + INSERT("Keccak1600", kxvik_pytype); INSERT("GCPRP", gcprp_pytype); INSERT("GPRP", gprp_pytype); INSERT("gcprps", gcprps()); diff --git a/catacomb-python.h b/catacomb-python.h index d7e2543..3b9d8f7 100644 --- a/catacomb-python.h +++ b/catacomb-python.h @@ -69,6 +69,7 @@ #include #include #include +#include #include #include