chiark / gitweb /
Merge remote-tracking branch 'origin/HEAD'
[catacomb-python] / rand.c
diff --git a/rand.c b/rand.c
index 6e1d05efcb4ae5edd6822cac0f74cbc5f2751f33..6fe78bc758990ac36022447731243d3cc1fd714e 100644 (file)
--- a/rand.c
+++ b/rand.c
@@ -90,20 +90,20 @@ static PyObject *grmeth_range(PyObject *me, PyObject *arg)
   if (!PyArg_ParseTuple(arg, "O:range", &m)) return (0);
   if (PyInt_Check(m)) {
     long mm = PyInt_AS_LONG(m);
-    if (mm < 0)
-      goto negative;
+    if (mm <= 0)
+      goto notpos;
     if (mm <= 0xffffffff)
       return (PyInt_FromLong(grand_range(GRAND_R(me), mm)));
   }
   if ((x = getmp(m)) == 0)
     goto end;
-  if (MP_NEGP(x))
-    goto negative;
+  if (!MP_POSP(x))
+    goto notpos;
   y = mprand_range(MP_NEW, x, GRAND_R(me), 0);
   MP_DROP(x);
   return (mp_pywrap(y));
-negative:
-  TYERR("range must be nonnegative");
+notpos:
+  VALERR("range must be strictly positive");
 end:
   if (x) MP_DROP(x);
   return (0);
@@ -112,12 +112,13 @@ end:
 static PyObject *grmeth_mp(PyObject *me, PyObject *arg, PyObject *kw)
 {
   size_t l;
-  mpw o;
+  mpw o = 0;
   char *kwlist[] = { "bits", "or", 0 };
 
   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|O&:mp", kwlist,
                                   convszt, &l, convmpw, &o))
     goto end;
+  if (l < MPW_BITS && (o >> l)) VALERR("or mask too large");
   return (mp_pywrap(mprand(MP_NEW, l, GRAND_R(me), o)));
 end:
   return (0);
@@ -172,7 +173,7 @@ end:
 static PyObject *grmeth_seedblock(PyObject *me, PyObject *arg)
 {
   char *p;
-  int n;
+  Py_ssize_t n;
   grand *r = GRAND_R(me);
   if (!PyArg_ParseTuple(arg, "s#:seedblock", &p, &n) ||
       checkop(r, GRAND_SEEDBLOCK, "seedblock"))
@@ -218,7 +219,7 @@ static PyObject *grmeth_mask(PyObject *me, PyObject *arg)
 {
   grand *r = GRAND_R(me);
   char *p, *q;
-  int sz;
+  Py_ssize_t sz;
   PyObject *rc;
 
   if (!PyArg_ParseTuple(arg, "s#:mask", &p, &sz)) return (0);
@@ -451,7 +452,7 @@ static PyObject *trmeth_stretch(PyObject *me, PyObject *arg)
 static PyObject *trmeth_add(PyObject *me, PyObject *arg)
 {
   grand *r = GRAND_R(me);
-  char *p; int n; unsigned goodbits;
+  char *p; Py_ssize_t n; unsigned goodbits;
   if (!PyArg_ParseTuple(arg, "s#O&:add", &p, &n, convuint, &goodbits))
     return (0);
   r->ops->misc(r, RAND_ADD, p, (size_t)n, goodbits);
@@ -461,7 +462,7 @@ static PyObject *trmeth_add(PyObject *me, PyObject *arg)
 static PyObject *trmeth_key(PyObject *me, PyObject *arg)
 {
   grand *r = GRAND_R(me);
-  char *p; int n;
+  char *p; Py_ssize_t n;
   if (!PyArg_ParseTuple(arg, "s#:key", &p, &n)) return (0);
   r->ops->misc(r, RAND_KEY, p, (size_t)n);
   RETURN_ME;
@@ -577,11 +578,17 @@ 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);
 typedef grand *gcnrand_func(const void *, size_t sz, const void *);
+typedef grand *gcshakerand_func(const void *, size_t,
+                               const void *, size_t,
+                               const void *, size_t);
+typedef grand *gcshafuncrand_func(const void *, size_t,
+                                 const void *, size_t);
+typedef grand *gckmacrand_func(const void *, size_t, const void *, size_t);
 typedef struct gccrand_info {
   const char *name;
   const octet *keysz;
@@ -590,8 +597,15 @@ typedef struct gccrand_info {
   gcrand_func *func;
 } gccrand_info;
 
-#define RNGF_INT 1u
-#define RNGF_NONCE 2u
+#define RNGF_MASK 255u
+
+enum {
+  RNG_PLAIN = 0,
+  RNG_SEAL,
+  RNG_LATIN,
+  RNG_SHAKE,
+  RNG_KMAC
+};
 
 typedef struct gccrand_pyobj {
   PyHeapTypeObject ty;
@@ -615,7 +629,7 @@ static PyObject *gcrand_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
   const gccrand_info *info = GCCRAND_INFO(ty);
   static char *kwlist[] = { "key", 0 };
   char *k;
-  int n;
+  Py_ssize_t n;
 
   if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", kwlist, &k, &n))
     goto end;
@@ -631,7 +645,7 @@ static PyObject *gcirand_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
   uint32 i = 0;
   static char *kwlist[] = { "key", "i", 0 };
   char *k;
-  int n;
+  Py_ssize_t n;
 
   if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#O&:new", kwlist,
                                   &k, &n, convu32, &i))
@@ -649,7 +663,7 @@ 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;
+  Py_ssize_t ksz, nsz;
 
   if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#s#:new", kwlist,
                                   &k, &ksz, &n, &nsz))
@@ -663,21 +677,56 @@ end:
   return (0);
 }
 
+static PyObject *gcshakyrand_pynew(PyTypeObject *ty,
+                                  PyObject *arg, PyObject *kw)
+{
+  const gccrand_info *info = GCCRAND_INFO(ty);
+  static char *kwlist_shake[] = { "key", "func", "perso", 0 };
+  static char *kwlist_func[] = { "key", "perso", 0 };
+  char *k, *f = 0, *p = 0;
+  Py_ssize_t ksz, fsz = 0, psz = 0;
+
+  if ((info->f&RNGF_MASK) == RNG_SHAKE
+       ? !PyArg_ParseTupleAndKeywords(arg, kw, "s#|s#s#:new", kwlist_shake,
+                                      &k, &ksz, &f, &fsz, &p, &psz)
+       : !PyArg_ParseTupleAndKeywords(arg, kw, "s#|s#:new", kwlist_func,
+                                      &k, &ksz, &p, &psz))
+    goto end;
+  if (keysz(ksz, info->keysz) != ksz) VALERR("bad key length");
+  return (grand_dopywrap(ty,
+                        (info->f&RNGF_MASK) == RNG_SHAKE
+                          ? ((gcshakerand_func *)info->func)(f, fsz,
+                                                             p, psz,
+                                                             k, ksz)
+                          : ((gcshafuncrand_func *)info->func)(p, psz,
+                                                               k, ksz),
+                        f_freeme));
+end:
+  return (0);
+}
+
 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);
+  switch (info->f&RNGF_MASK) {
+    case RNG_LATIN: g->ty.ht_type.tp_base = gclatinrand_pytype; break;
+    default: g->ty.ht_type.tp_base = gcrand_pytype; break;
+  }
+  Py_INCREF(g->ty.ht_type.tp_base);
   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;
-  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;
+  switch (info->f&RNGF_MASK) {
+    case RNG_LATIN: g->ty.ht_type.tp_new = gcnrand_pynew; break;
+    case RNG_SEAL: g->ty.ht_type.tp_new = gcirand_pynew; break;
+    case RNG_SHAKE: case RNG_KMAC:
+      g->ty.ht_type.tp_new = gcshakyrand_pynew; break;
+    default: g->ty.ht_type.tp_new = gcrand_pynew; break;
+  }
   typeready(&g->ty.ht_type);
   return ((PyObject *)g);
 }
@@ -687,6 +736,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")
@@ -695,6 +766,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@ */
@@ -791,6 +870,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)
@@ -1381,6 +1508,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);
@@ -1403,6 +1531,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);