rand.c, algorithms.py: Support random access protocol of Latin-dance PRFs.
authorMark Wooding <mdw@distorted.org.uk>
Mon, 12 Sep 2016 21:29:09 +0000 (22:29 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Mon, 12 Sep 2016 21:33:26 +0000 (22:33 +0100)
Add a new superclass for random bit generators based on Latin-dance
PRFs (Salsa20, ChaCha, etc.) which exposes the `seek'/`tell' random
access protocol to Python.

algorithms.py
rand.c

index 3ceb207..c2ab4ee 100644 (file)
@@ -85,7 +85,7 @@ for i in latindances:
   else:
     raise ValueError, 'failed to find root name for %s' % i
   print ('\t_("%(name)s", %(root)s_keysz, %(id)s_rand, ' +
-         'RNGF_NONCE, %(ROOT)s_NONCESZ) \\') % \
+         'RNGF_NONCE | RNGF_LATIN, %(ROOT)s_NONCESZ) \\') % \
       {'name': i, 'id': i.translate(None, '/'),
        'root': root, 'ROOT': root.upper()}
 print '\t/* end */'
diff --git a/rand.c b/rand.c
index 4fcb155..784fd93 100644 (file)
--- a/rand.c
+++ b/rand.c
@@ -578,7 +578,7 @@ static PyTypeObject truerand_pytype_skel = {
 
 /*----- Generators from symmetric encryption algorithms -------------------*/
 
-static PyTypeObject *gccrand_pytype, *gcrand_pytype;
+static PyTypeObject *gccrand_pytype, *gcrand_pytype, *gclatinrand_pytype;
 
 typedef grand *gcrand_func(const void *, size_t sz);
 typedef grand *gcirand_func(const void *, size_t sz, uint32);
@@ -593,6 +593,7 @@ typedef struct gccrand_info {
 
 #define RNGF_INT 1u
 #define RNGF_NONCE 2u
+#define RNGF_LATIN 4u
 
 typedef struct gccrand_pyobj {
   PyHeapTypeObject ty;
@@ -669,8 +670,9 @@ static PyObject *gccrand_pywrap(const gccrand_info *info)
   gccrand_pyobj *g = newtype(gccrand_pytype, 0, info->name);
   g->info = info;
   g->ty.ht_type.tp_basicsize = sizeof(grand_pyobj);
-  g->ty.ht_type.tp_base = gcrand_pytype;
-  Py_INCREF(gcrand_pytype);
+  g->ty.ht_type.tp_base =
+    (info->f & RNGF_LATIN) ? gclatinrand_pytype : gcrand_pytype;
+  Py_INCREF(g->ty.ht_type.tp_base);
   g->ty.ht_type.tp_flags = (Py_TPFLAGS_DEFAULT |
                            Py_TPFLAGS_BASETYPE |
                            Py_TPFLAGS_HEAPTYPE);
@@ -688,6 +690,28 @@ static PyObject *gccrget_name(PyObject *me, void *hunoz)
 static PyObject *gccrget_keysz(PyObject *me, void *hunoz)
   { return (keysz_pywrap(GCCRAND_INFO(me)->keysz)); }
 
+static PyObject *gclrmeth_tell(PyObject *me, PyObject *arg)
+{
+  grand *r = GRAND_R(me);
+  PyObject *rc = 0;
+  kludge64 off;
+
+  if (!PyArg_ParseTuple(arg, ":tell")) return (0);
+  r->ops->misc(r, SALSA20_TELLU64, &off);
+  rc = getk64(off);
+  return (rc);
+}
+
+static PyObject *gclrmeth_seek(PyObject *me, PyObject *arg)
+{
+  grand *r = GRAND_R(me);
+  kludge64 off;
+
+  if (!PyArg_ParseTuple(arg, "O&:seek", convk64, &off)) return (0);
+  r->ops->misc(r, SALSA20_SEEKU64, off);
+  RETURN_ME;
+}
+
 static PyGetSetDef gccrand_pygetset[] = {
 #define GETSETNAME(op, name) gccr##op##_##name
   GET  (keysz,                 "CR.keysz -> acceptable key sizes")
@@ -696,6 +720,14 @@ static PyGetSetDef gccrand_pygetset[] = {
   { 0 }
 };
 
+static PyMethodDef gclatinrand_pymethods[] = {
+#define METHNAME(name) gclrmeth_##name
+  METH (tell,          "R.tell() -> OFF")
+  METH (seek,          "R.seek(OFF)")
+#undef METHNAME
+  { 0 }
+};
+
 static PyTypeObject gccrand_pytype_skel = {
   PyObject_HEAD_INIT(0) 0,             /* Header */
   "GCCRand",                           /* @tp_name@ */
@@ -792,6 +824,54 @@ static PyTypeObject gcrand_pytype_skel = {
   0                                    /* @tp_is_gc@ */
 };
 
+static PyTypeObject gclatinrand_pytype_skel = {
+  PyObject_HEAD_INIT(0) 0,             /* Header */
+  "GCLatinRand",                       /* @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@ */
+"Abstract base class for symmetric crypto-based generators.",
+
+  0,                                   /* @tp_traverse@ */
+  0,                                   /* @tp_clear@ */
+  0,                                   /* @tp_richcompare@ */
+  0,                                   /* @tp_weaklistoffset@ */
+  0,                                   /* @tp_iter@ */
+  0,                                   /* @tp_iternext@ */
+  gclatinrand_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@ */
+};
+
 /*----- SSL and TLS generators --------------------------------------------*/
 
 static PyObject *sslprf_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
@@ -1382,6 +1462,7 @@ void rand_pyinit(void)
   INITTYPE(tlsprf, grand);
   INITTYPE(gccrand, type);
   INITTYPE(gcrand, grand);
+  INITTYPE(gclatinrand, gcrand);
   rand_noisesrc(RAND_GLOBAL, &noise_source);
   rand_seed(RAND_GLOBAL, 160);
   addmethods(methods);
@@ -1404,6 +1485,7 @@ void rand_pyinsert(PyObject *mod)
   INSERT("BBSPriv", bbspriv_pytype);
   INSERT("GCCRand", gccrand_pytype);
   INSERT("GCRand", gcrand_pytype);
+  INSERT("GCLatinRand", gclatinrand_pytype);
   rand_pyobj = grand_pywrap(&rand_global, 0); Py_INCREF(rand_pyobj);
   gccrands_dict = gccrands(); Py_INCREF(gccrands_dict);
   INSERT("gccrands", gccrands_dict);