algorithms.c: Add missing guard for `del' to property `set' functions.
[catacomb-python] / rand.c
diff --git a/rand.c b/rand.c
index f163efa..5a323b0 100644 (file)
--- a/rand.c
+++ b/rand.c
@@ -69,15 +69,25 @@ PyObject *grand_pywrap(grand *r, unsigned f)
 
 CONVFUNC(grand, grand *, GRAND_R)
 
+static int grand_check(PyObject *me)
+{
+  if (!GRAND_R(me)) VALERR("random generator object is no longer valid");
+  return (0);
+end:
+  return (-1);
+}
+
 static PyObject *grmeth_byte(PyObject *me, PyObject *arg)
 {
   if (!PyArg_ParseTuple(arg, ":byte")) return (0);
+  if (grand_check(me)) return (0);
   return (PyInt_FromLong(grand_byte(GRAND_R(me))));
 }
 
 static PyObject *grmeth_word(PyObject *me, PyObject *arg)
 {
   if (!PyArg_ParseTuple(arg, ":word")) return (0);
+  if (grand_check(me)) return (0);
   return (getulong(grand_word(GRAND_R(me))));
 }
 
@@ -88,6 +98,7 @@ static PyObject *grmeth_range(PyObject *me, PyObject *arg)
   mp *y = 0;
 
   if (!PyArg_ParseTuple(arg, "O:range", &m)) return (0);
+  if (grand_check(me)) return (0);
   if (PyInt_Check(m)) {
     long mm = PyInt_AS_LONG(m);
     if (mm <= 0)
@@ -118,6 +129,7 @@ static PyObject *grmeth_mp(PyObject *me, PyObject *arg, PyObject *kw)
   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|O&:mp", kwlist,
                                   convszt, &l, convmpw, &o))
     goto end;
+  if (grand_check(me)) return (0);
   if (l < MPW_BITS && (o >> l)) VALERR("or mask too large");
   return (mp_pywrap(mprand(MP_NEW, l, GRAND_R(me), o)));
 end:
@@ -130,6 +142,7 @@ static PyObject *grmeth_block(PyObject *me, PyObject *arg)
   PyObject *rc = 0;
 
   if (!PyArg_ParseTuple(arg, "O&:block", convulong, &n)) goto end;
+  if (grand_check(me)) return (0);
   rc = bytestring_pywrap(0, n);
   grand_fill(GRAND_R(me), PyString_AS_STRING(rc), n);
 end:
@@ -138,8 +151,7 @@ end:
 
 static int checkop(grand *r, unsigned op, const char *what)
 {
-  if (r->ops->misc(r, GRAND_CHECK, op))
-    return (0);
+  if (r->ops->misc(r, GRAND_CHECK, op)) return (0);
   PyErr_Format(PyExc_TypeError, "operation %s not supported", what);
   return (-1);
 }
@@ -149,7 +161,7 @@ static PyObject *grmeth_seedint(PyObject *me, PyObject *arg)
   int i;
   grand *r = GRAND_R(me);
   if (!PyArg_ParseTuple(arg, "i:seedint", &i) ||
-      checkop(r, GRAND_SEEDINT, "seedint"))
+      grand_check(me) || checkop(r, GRAND_SEEDINT, "seedint"))
     goto end;
   r->ops->misc(r, GRAND_SEEDINT, i);
   RETURN_ME;
@@ -162,7 +174,7 @@ static PyObject *grmeth_seedword(PyObject *me, PyObject *arg)
   uint32 u;
   grand *r = GRAND_R(me);
   if (!PyArg_ParseTuple(arg, "O&:seedword", convu32, &u) ||
-      checkop(r, GRAND_SEEDUINT32, "seedword"))
+      grand_check(me) || checkop(r, GRAND_SEEDUINT32, "seedword"))
     goto end;
   r->ops->misc(r, GRAND_SEEDUINT32, u);
   RETURN_ME;
@@ -176,7 +188,7 @@ static PyObject *grmeth_seedblock(PyObject *me, PyObject *arg)
   Py_ssize_t n;
   grand *r = GRAND_R(me);
   if (!PyArg_ParseTuple(arg, "s#:seedblock", &p, &n) ||
-      checkop(r, GRAND_SEEDBLOCK, "seedblock"))
+      grand_check(me) || checkop(r, GRAND_SEEDBLOCK, "seedblock"))
     goto end;
   r->ops->misc(r, GRAND_SEEDBLOCK, p, (size_t)n);
   RETURN_ME;
@@ -190,7 +202,7 @@ static PyObject *grmeth_seedmp(PyObject *me, PyObject *arg)
   mp *xx;
   grand *r = GRAND_R(me);
   if (!PyArg_ParseTuple(arg, "O:seedmp", &x) ||
-      checkop(r, GRAND_SEEDMP, "seedmp") ||
+      grand_check(me) || checkop(r, GRAND_SEEDMP, "seedmp") ||
       (xx = getmp(x)) == 0)
     goto end;
   r->ops->misc(r, GRAND_SEEDMP, xx);
@@ -207,7 +219,7 @@ static PyObject *grmeth_seedrand(PyObject *me, PyObject *arg, PyObject *kw)
   grand *rr = &rand_global;
   if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:seedrand", kwlist,
                                   convgrand, &rr) ||
-      checkop(r, GRAND_SEEDRAND, "seedrand"))
+      grand_check(me) || checkop(r, GRAND_SEEDRAND, "seedrand"))
     goto end;
   r->ops->misc(r, GRAND_SEEDRAND, rr);
   RETURN_ME;
@@ -223,6 +235,7 @@ static PyObject *grmeth_mask(PyObject *me, PyObject *arg)
   PyObject *rc;
 
   if (!PyArg_ParseTuple(arg, "s#:mask", &p, &sz)) return (0);
+  if (grand_check(me)) return (0);
   rc = bytestring_pywrap(0, sz);
   q = PyString_AS_STRING(rc);
   GR_FILL(r, q, sz);
@@ -233,16 +246,15 @@ static PyObject *grmeth_mask(PyObject *me, PyObject *arg)
 static void grand_pydealloc(PyObject *me)
 {
   grand_pyobj *g = (grand_pyobj *)me;
-  if (g->f & f_freeme)
-    GR_DESTROY(g->r);
+  if ((g->f & f_freeme) && g->r) GR_DESTROY(g->r);
   FREEOBJ(me);
 }
 
 static PyObject *grget_name(PyObject *me, void *hunoz)
-  { return (PyString_FromString(GRAND_R(me)->ops->name)); }
+  { return (grand_check(me) ? 0 : PyString_FromString(GRAND_R(me)->ops->name)); }
 
 static PyObject *grget_cryptop(PyObject *me, void *hunoz)
-  { return (getbool(GRAND_R(me)->ops->f & GRAND_CRYPTO)); }
+  { return (grand_check(me) ? 0 : getbool(GRAND_R(me)->ops->f & GRAND_CRYPTO)); }
 
 static PyGetSetDef grand_pygetset[] = {
 #define GETSETNAME(op, name) gr##op##_##name
@@ -583,6 +595,12 @@ 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;
@@ -591,9 +609,15 @@ typedef struct gccrand_info {
   gcrand_func *func;
 } gccrand_info;
 
-#define RNGF_INT 1u
-#define RNGF_NONCE 2u
-#define RNGF_LATIN 4u
+#define RNGF_MASK 255u
+
+enum {
+  RNG_PLAIN = 0,
+  RNG_SEAL,
+  RNG_LATIN,
+  RNG_SHAKE,
+  RNG_KMAC
+};
 
 typedef struct gccrand_pyobj {
   PyHeapTypeObject ty;
@@ -665,22 +689,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 =
-    (info->f & RNGF_LATIN) ? gclatinrand_pytype : 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);
 }
@@ -1203,7 +1261,7 @@ static PyObject *bbsget_x(PyObject *me, void *hunoz)
 
 static int bbsset_x(PyObject *me, PyObject *val, void *hunoz)
 {
-  mp *x = 0; grand *r = GRAND_R(me); int rc = -1; if (!x) NIERR("__del__");
+  mp *x = 0; grand *r = GRAND_R(me); int rc = -1; if (!val) NIERR("__del__");
   if ((x = getmp(val)) == 0) goto end; r->ops->misc(r, BBS_SET, x); rc = 0;
   end: mp_drop(x); return (rc);
 }
@@ -1318,18 +1376,20 @@ static PyObject *meth__BBSPriv_generate(PyObject *me,
 {
   bbs_priv bp = { 0 };
   mp *x = MP_TWO;
-  pgev evt = { 0 };
+  struct excinfo exc = EXCINFO_INIT;
+  pypgev evt = { { 0 } };
   unsigned nbits, n = 0;
   grand *r = &rand_global;
   char *kwlist[] = { "class", "nbits", "event", "rng", "nsteps", "seed", 0 };
   bbspriv_pyobj *rc = 0;
 
+  evt.exc = &exc;
   if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO&|O&O&O&O&:generate", kwlist,
                                   &me, convuint, &nbits, convpgev, &evt,
                                   convgrand, &r, convuint, &n, convmp, &x))
     goto end;
-  if (bbs_gen(&bp, nbits, r, n, evt.proc, evt.ctx))
-    VALERR("prime genration failed");
+  if (bbs_gen(&bp, nbits, r, n, evt.ev.proc, evt.ev.ctx))
+    PGENERR(&exc);
   rc = PyObject_New(bbspriv_pyobj, bbspriv_pytype);
   rc->gr.r = bbs_rand(bp.n, x);
   rc->gr.f = f_freeme;
@@ -1443,7 +1503,8 @@ static PyTypeObject bbspriv_pytype_skel = {
 static PyMethodDef methods[] = {
 #define METHNAME(name) meth_##name
   KWMETH(_BBSPriv_generate,            "\
-generate(NBITS, [event = pgen_nullev, rng = rand, nsteps = 0, seed = 2])")
+generate(NBITS, [event = pgen_nullev], [rng = rand],\n\
+        [nsteps = 0], [seed = 2]) -> R")
 #undef METHNAME
   { 0 }
 };