algorithms.py, rand.c: Support `Latin dances' stream ciphers.
[catacomb-python] / rand.c
diff --git a/rand.c b/rand.c
index 1c008b7..49aaa38 100644 (file)
--- a/rand.c
+++ b/rand.c
@@ -581,14 +581,17 @@ static PyTypeObject *gccrand_pytype, *gcrand_pytype;
 
 typedef grand *gcrand_func(const void *, size_t sz);
 typedef grand *gcirand_func(const void *, size_t sz, uint32);
+typedef grand *gcnrand_func(const void *, size_t sz, const void *);
 typedef struct gccrand_info {
   const char *name;
   const octet *keysz;
   unsigned f;
+  size_t noncesz;
   gcrand_func *func;
 } gccrand_info;
 
 #define RNGF_INT 1u
+#define RNGF_NONCE 2u
 
 typedef struct gccrand_pyobj {
   PyHeapTypeObject ty;
@@ -596,13 +599,13 @@ typedef struct gccrand_pyobj {
 } gccrand_pyobj;
 #define GCCRAND_INFO(o) (((gccrand_pyobj *)(o))->info)
 
-#define GCCRAND_DEF(name, ksz, func, f)                                        \
+#define GCCRAND_DEF(name, ksz, func, f, nsz)                           \
   static const gccrand_info func##_info =                              \
-    { name, ksz, f, (gcrand_func *)func };
+    { name, ksz, f, nsz, (gcrand_func *)func };
 RNGS(GCCRAND_DEF)
 
 static const gccrand_info *const gcrandtab[] = {
-#define GCCRAND_ENTRY(name, ksz, func, f) &func##_info,
+#define GCCRAND_ENTRY(name, ksz, func, f, nsz) &func##_info,
   RNGS(GCCRAND_ENTRY)
   0
 };
@@ -641,6 +644,25 @@ end:
   return (0);
 }
 
+static PyObject *gcnrand_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+{
+  const gccrand_info *info = GCCRAND_INFO(ty);
+  static char *kwlist[] = { "key", "nonce", 0 };
+  char *k, *n;
+  int ksz, nsz;
+
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#s#:new", kwlist,
+                                  &k, &ksz, &n, &nsz))
+    goto end;
+  if (keysz(ksz, info->keysz) != ksz) VALERR("bad key length");
+  if (nsz != info->noncesz) VALERR("bad nonce length");
+  return (grand_dopywrap(ty,
+                        ((gcnrand_func *)info->func)(k, ksz, n),
+                        f_freeme));
+end:
+  return (0);
+}
+
 static PyObject *gccrand_pywrap(const gccrand_info *info)
 {
   gccrand_pyobj *g = newtype(gccrand_pytype, 0, info->name);
@@ -653,10 +675,9 @@ static PyObject *gccrand_pywrap(const gccrand_info *info)
                            Py_TPFLAGS_HEAPTYPE);
   g->ty.ht_type.tp_alloc = PyType_GenericAlloc;
   g->ty.ht_type.tp_free = 0;
-  if (info->f & RNGF_INT)
-    g->ty.ht_type.tp_new = gcirand_pynew;
-  else
-    g->ty.ht_type.tp_new = gcrand_pynew;
+  if (info->f & RNGF_INT) g->ty.ht_type.tp_new = gcirand_pynew;
+  else if (info->f & RNGF_NONCE) g->ty.ht_type.tp_new = gcnrand_pynew;
+  else g->ty.ht_type.tp_new = gcrand_pynew;
   typeready(&g->ty.ht_type);
   return ((PyObject *)g);
 }