chiark / gitweb /
algorithms.c: Add basic support for Keccak[1600, n].
authorMark Wooding <mdw@distorted.org.uk>
Thu, 11 May 2017 09:42:15 +0000 (10:42 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Sun, 14 May 2017 03:29:20 +0000 (04:29 +0100)
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.

algorithms.c
catacomb-python.h

index 5703901fae129b68ea01e366884c6cbe94ff8e63..e4233fa74a799b89ac7c24f15989b624a4ba15d2 100644 (file)
@@ -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());
index d7e254355dfb79fcd42dca3caaba556b9a883a85..3b9d8f77337cb92c0efac7ee1993a9aaa09b626e 100644 (file)
@@ -69,6 +69,7 @@
 #include <catacomb/sha.h>
 #include <catacomb/sha-mgf.h>
 #include <catacomb/sha-hmac.h>
+#include <catacomb/keccak1600.h>
 
 #include <catacomb/mp.h>
 #include <catacomb/mpint.h>