@@@ py_buffer/freebin wip
[catacomb-python] / rand.c
diff --git a/rand.c b/rand.c
index 96a86d5..e72f450 100644 (file)
--- a/rand.c
+++ b/rand.c
@@ -65,7 +65,8 @@ PyObject *grand_pywrap(grand *r, unsigned f)
   else if (STRCMP(r->ops->name, ==, "sslprf")) ty = sslprf_pytype;
   else if (STRCMP(r->ops->name, ==, "tlsdx")) ty = tlsdx_pytype;
   else if (STRCMP(r->ops->name, ==, "tlsprf")) ty = tlsprf_pytype;
-  else if ((ob = PyDict_GetItemString(gccrands_dict, r->ops->name)) != 0)
+  else if ((ob = PyMapping_GetItemString
+                  (gccrands_dict, (/*unconst*/ char *)r->ops->name)) != 0)
     ty = (PyTypeObject *)ob;
   return (grand_dopywrap(ty, r, f));
 }
@@ -101,16 +102,14 @@ static PyObject *grmeth_range(PyObject *me, PyObject *arg)
   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)
-      goto notpos;
-    if (mm <= 0xffffffff)
+    long mm = PyInt_AsLong(m);
+    if (mm == -1 && PyErr_Occurred()) PyErr_Clear();
+    else if (mm <= 0) goto notpos;
+    else if (mm <= 0xffffffff)
       return (PyInt_FromLong(grand_range(GRAND_R(me), mm)));
   }
-  if ((x = getmp(m)) == 0)
-    goto end;
-  if (!MP_POSP(x))
-    goto notpos;
+  if ((x = getmp(m)) == 0) goto end;
+  if (!MP_POSP(x)) goto notpos;
   y = mprand_range(MP_NEW, x, GRAND_R(me), 0);
   MP_DROP(x);
   return (mp_pywrap(y));
@@ -145,7 +144,7 @@ static PyObject *grmeth_block(PyObject *me, PyObject *arg)
   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);
+  grand_fill(GRAND_R(me), BIN_PTR(rc), n);
 end:
   return (rc);
 }
@@ -185,13 +184,12 @@ end:
 
 static PyObject *grmeth_seedblock(PyObject *me, PyObject *arg)
 {
-  char *p;
-  Py_ssize_t n;
+  struct bin in;
   grand *r = GRAND_R(me);
-  if (!PyArg_ParseTuple(arg, "s#:seedblock", &p, &n) ||
+  if (!PyArg_ParseTuple(arg, "O&:seedblock", convbin, &in) ||
       grand_check(me) || checkop(r, GRAND_SEEDBLOCK, "seedblock"))
     goto end;
-  r->ops->misc(r, GRAND_SEEDBLOCK, p, (size_t)n);
+  r->ops->misc(r, GRAND_SEEDBLOCK, in.p, (size_t)in.sz);
   RETURN_ME;
 end:
   return (0);
@@ -231,16 +229,17 @@ end:
 static PyObject *grmeth_mask(PyObject *me, PyObject *arg)
 {
   grand *r = GRAND_R(me);
-  char *p, *q;
-  Py_ssize_t sz;
+  struct bin in;
+  const octet *p; size_t n;
+  octet *q;
   PyObject *rc;
 
-  if (!PyArg_ParseTuple(arg, "s#:mask", &p, &sz)) return (0);
+  if (!PyArg_ParseTuple(arg, "O&:mask", convbin, &in)) return (0);
   if (grand_check(me)) return (0);
-  rc = bytestring_pywrap(0, sz);
-  q = PyString_AS_STRING(rc);
-  GR_FILL(r, q, sz);
-  while (sz--) *q++ ^= *p++;
+  rc = bytestring_pywrap(0, in.sz);
+  q = (octet *)BIN_PTR(rc);
+  GR_FILL(r, q, in.sz);
+  p = in.p; n = in.sz; while (n--) *q++ ^= *p++;
   return (rc);
 }
 
@@ -252,7 +251,7 @@ static void grand_pydealloc(PyObject *me)
 }
 
 static PyObject *grget_name(PyObject *me, void *hunoz)
-  { return (grand_check(me) ? 0 : PyString_FromString(GRAND_R(me)->ops->name)); }
+  { return (grand_check(me) ? 0 : TEXT_FROMSTR(GRAND_R(me)->ops->name)); }
 
 static PyObject *grget_cryptop(PyObject *me, void *hunoz)
   { return (grand_check(me) ? 0 : getbool(GRAND_R(me)->ops->f & GRAND_CRYPTO)); }
@@ -283,7 +282,7 @@ static const PyMethodDef grand_pymethods[] = {
 };
 
 static const PyTypeObject grand_pytype_skel = {
-  PyObject_HEAD_INIT(0) 0,             /* Header */
+  PyVarObject_HEAD_INIT(0, 0)          /* Header */
   "GRand",                             /* @tp_name@ */
   sizeof(grand_pyobj),                 /* @tp_basicsize@ */
   0,                                   /* @tp_itemsize@ */
@@ -340,7 +339,7 @@ static PyObject *lcrand_pynew(PyTypeObject *me, PyObject *arg, PyObject *kw)
 }
 
 static const PyTypeObject lcrand_pytype_skel = {
-  PyObject_HEAD_INIT(0) 0,             /* Header */
+  PyVarObject_HEAD_INIT(0, 0)          /* Header */
   "LCRand",                            /* @tp_name@ */
   sizeof(grand_pyobj),                 /* @tp_basicsize@ */
   0,                                   /* @tp_itemsize@ */
@@ -397,7 +396,7 @@ static PyObject *fibrand_pynew(PyTypeObject *me, PyObject *arg, PyObject *kw)
 }
 
 static const PyTypeObject fibrand_pytype_skel = {
-  PyObject_HEAD_INIT(0) 0,             /* Header */
+  PyVarObject_HEAD_INIT(0, 0)          /* Header */
   "FibRand",                           /* @tp_name@ */
   sizeof(grand_pyobj),                 /* @tp_basicsize@ */
   0,                                   /* @tp_itemsize@ */
@@ -455,19 +454,19 @@ static PyObject *trmeth_stretch(PyObject *me)
 static PyObject *trmeth_add(PyObject *me, PyObject *arg)
 {
   grand *r = GRAND_R(me);
-  char *p; Py_ssize_t n; unsigned goodbits;
-  if (!PyArg_ParseTuple(arg, "s#O&:add", &p, &n, convuint, &goodbits))
+  struct bin in; unsigned goodbits;
+  if (!PyArg_ParseTuple(arg, "O&O&:add", convbin, &in, convuint, &goodbits))
     return (0);
-  r->ops->misc(r, RAND_ADD, p, (size_t)n, goodbits);
+  r->ops->misc(r, RAND_ADD, in.p, (size_t)in.sz, goodbits);
   RETURN_ME;
 }
 
 static PyObject *trmeth_key(PyObject *me, PyObject *arg)
 {
   grand *r = GRAND_R(me);
-  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);
+  struct bin k;
+  if (!PyArg_ParseTuple(arg, "O&:key", convbin, &k)) return (0);
+  r->ops->misc(r, RAND_KEY, k.p, (size_t)k.sz);
   RETURN_ME;
 }
 
@@ -527,7 +526,7 @@ static const PyGetSetDef truerand_pygetset[] = {
 };
 
 static const PyTypeObject truerand_pytype_skel = {
-  PyObject_HEAD_INIT(0) 0,             /* Header */
+  PyVarObject_HEAD_INIT(0, 0)          /* Header */
   "TrueRand",                          /* @tp_name@ */
   sizeof(grand_pyobj),                 /* @tp_basicsize@ */
   0,                                   /* @tp_itemsize@ */
@@ -626,13 +625,12 @@ static PyObject *gcrand_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
 {
   const gccrand_info *info = GCCRAND_INFO(ty);
   static const char *const kwlist[] = { "key", 0 };
-  char *k;
-  Py_ssize_t n;
+  struct bin k;
 
-  if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", KWLIST, &k, &n))
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:new", KWLIST,  convbin, &k))
     goto end;
-  if (keysz(n, info->keysz) != n) VALERR("bad key length");
-  return (grand_dopywrap(ty, info->func(k, n), f_freeme));
+  if (keysz(k.sz, info->keysz) != k.sz) VALERR("bad key length");
+  return (grand_dopywrap(ty, info->func(k.p, k.sz), f_freeme));
 end:
   return (0);
 }
@@ -642,15 +640,14 @@ static PyObject *gcirand_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
   const gccrand_info *info = GCCRAND_INFO(ty);
   uint32 i = 0;
   static const char *const kwlist[] = { "key", "i", 0 };
-  char *k;
-  Py_ssize_t n;
+  struct bin k;
 
-  if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#O&:new", KWLIST,
-                                  &k, &n, convu32, &i))
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|O&:new", KWLIST,
+                                  convbin, &k, convu32, &i))
     goto end;
-  if (keysz(n, info->keysz) != n) VALERR("bad key length");
+  if (keysz(k.sz, info->keysz) != k.sz) VALERR("bad key length");
   return (grand_dopywrap(ty,
-                        ((gcirand_func *)info->func)(k, n, i),
+                        ((gcirand_func *)info->func)(k.p, k.sz, i),
                         f_freeme));
 end:
   return (0);
@@ -660,16 +657,17 @@ static PyObject *gcnrand_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
 {
   const gccrand_info *info = GCCRAND_INFO(ty);
   static const char *const kwlist[] = { "key", "nonce", 0 };
-  char *k, *n;
-  Py_ssize_t ksz, nsz;
+  static const octet zn[24] = { 0 };
+  struct bin k, n;
 
-  if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#s#:new", KWLIST,
-                                  &k, &ksz, &n, &nsz))
+  n.p = zn; n.sz = info->noncesz; assert(info->noncesz <= sizeof(zn));
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|O&:new", KWLIST,
+                                  convbin, &k, convbin, &n))
     goto end;
-  if (keysz(ksz, info->keysz) != ksz) VALERR("bad key length");
-  if (nsz != info->noncesz) VALERR("bad nonce length");
+  if (keysz(k.sz, info->keysz) != k.sz) VALERR("bad key length");
+  if (n.sz != info->noncesz) VALERR("bad nonce length");
   return (grand_dopywrap(ty,
-                        ((gcnrand_func *)info->func)(k, ksz, n),
+                        ((gcnrand_func *)info->func)(k.p, k.sz, n.p),
                         f_freeme));
 end:
   return (0);
@@ -682,25 +680,25 @@ static PyObject *gcshakyrand_pynew(PyTypeObject *ty,
   static const char
     *const kwlist_shake[] = { "key", "func", "perso", 0 },
     *const kwlist_func[] = { "key", "perso", 0 };
-  char *k, *f = 0, *p = 0;
-  Py_ssize_t ksz, fsz = 0, psz = 0;
+  struct bin k, f = { 0, 0 }, p = { 0, 0 };
 
   if ((info->f&RNGF_MASK) == RNG_SHAKE
-       ? !PyArg_ParseTupleAndKeywords(arg, kw, "s#|s#s#:new",
+       ? !PyArg_ParseTupleAndKeywords(arg, kw, "O&|O&O&:new",
                                       (/*unconst*/ char **)kwlist_shake,
-                                      &k, &ksz, &f, &fsz, &p, &psz)
-       : !PyArg_ParseTupleAndKeywords(arg, kw, "s#|s#:new",
+                                      convbin, &k,
+                                      convbin, &f, convbin, &p)
+       : !PyArg_ParseTupleAndKeywords(arg, kw, "O&|O&:new",
                                       (/*unconst*/ char **)kwlist_func,
-                                      &k, &ksz, &p, &psz))
+                                      convbin, &k, convbin, &p))
     goto end;
-  if (keysz(ksz, info->keysz) != ksz) VALERR("bad key length");
+  if (keysz(k.sz, info->keysz) != k.sz) 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),
+                          ? ((gcshakerand_func *)info->func)(f.p, f.sz,
+                                                             p.p, p.sz,
+                                                             k.p, k.sz)
+                          : ((gcshafuncrand_func *)info->func)(p.p, p.sz,
+                                                               k.p, k.sz),
                         f_freeme));
 end:
   return (0);
@@ -733,7 +731,7 @@ static PyObject *gccrand_pywrap(const gccrand_info *info)
 }
 
 static PyObject *gccrget_name(PyObject *me, void *hunoz)
-  { return (PyString_FromString(GCCRAND_INFO(me)->name)); }
+  { return (TEXT_FROMSTR(GCCRAND_INFO(me)->name)); }
 static PyObject *gccrget_keysz(PyObject *me, void *hunoz)
   { return (keysz_pywrap(GCCRAND_INFO(me)->keysz)); }
 
@@ -775,7 +773,7 @@ static const PyMethodDef gclatinrand_pymethods[] = {
 };
 
 static const PyTypeObject gccrand_pytype_skel = {
-  PyObject_HEAD_INIT(0) 0,             /* Header */
+  PyVarObject_HEAD_INIT(0, 0)          /* Header */
   "GCCRand",                           /* @tp_name@ */
   sizeof(gccrand_pyobj),               /* @tp_basicsize@ */
   0,                                   /* @tp_itemsize@ */
@@ -823,7 +821,7 @@ static const PyTypeObject gccrand_pytype_skel = {
 };
 
 static const PyTypeObject gcrand_pytype_skel = {
-  PyObject_HEAD_INIT(0) 0,             /* Header */
+  PyVarObject_HEAD_INIT(0, 0)          /* Header */
   "GCRand",                            /* @tp_name@ */
   sizeof(grand_pyobj),                 /* @tp_basicsize@ */
   0,                                   /* @tp_itemsize@ */
@@ -871,7 +869,7 @@ static const PyTypeObject gcrand_pytype_skel = {
 };
 
 static const PyTypeObject gclatinrand_pytype_skel = {
-  PyObject_HEAD_INIT(0) 0,             /* Header */
+  PyVarObject_HEAD_INIT(0, 0)          /* Header */
   "GCLatinRand",                       /* @tp_name@ */
   sizeof(grand_pyobj),                 /* @tp_basicsize@ */
   0,                                   /* @tp_itemsize@ */
@@ -922,57 +920,56 @@ static const PyTypeObject gclatinrand_pytype_skel = {
 
 static PyObject *sslprf_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
 {
-  char *k, *s;
-  Py_ssize_t ksz, ssz;
+  struct bin k, s;
   const gchash *hco = &md5, *hci = &sha;
   PyObject *rc = 0;
   static const char *const kwlist[] = { "key", "seed", "ohash", "ihash", 0 };
 
-  if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#s#|O&O&:new", KWLIST,
-                                  &k, &ksz, &s, &ssz,
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&|O&O&:new", KWLIST,
+                                  convbin, &k, convbin, &s,
                                   convgchash, &hco, convgchash, &hci))
     goto end;
-  rc = grand_dopywrap(ty, sslprf_rand(hco, hci, k, ksz, s, ssz), f_freeme);
+  rc = grand_dopywrap(ty, sslprf_rand(hco, hci, k.p, k.sz, s.p, s.sz),
+                     f_freeme);
 end:
   return (rc);
 }
 
 static PyObject *tlsdx_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
 {
-  char *k, *s;
-  Py_ssize_t ksz, ssz;
+  struct bin k, s;
   const gcmac *mc = &sha_hmac;
   PyObject *rc = 0;
   static const char *const kwlist[] = { "key", "seed", "mac", 0 };
 
-  if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#s#|O&:new", KWLIST,
-                                  &k, &ksz, &s, &ssz,
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&|O&:new", KWLIST,
+                                  convbin, &k, convbin, &s,
                                   convgcmac, &mc))
     goto end;
-  rc = grand_dopywrap(ty, tlsdx_rand(mc, k, ksz, s, ssz), f_freeme);
+  rc = grand_dopywrap(ty, tlsdx_rand(mc, k.p, k.sz, s.p, s.sz), f_freeme);
 end:
   return (rc);
 }
 
 static PyObject *tlsprf_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
 {
-  char *k, *s;
-  Py_ssize_t ksz, ssz;
+  struct bin k, s;
   const gcmac *mcl = &md5_hmac, *mcr = &sha_hmac;
   PyObject *rc = 0;
   static const char *const kwlist[] = { "key", "seed", "lmac", "rmac", 0 };
 
-  if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#s#|O&O&:new", KWLIST,
-                                  &k, &ksz, &s, &ssz,
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&|O&O&:new", KWLIST,
+                                  convbin, &k, convbin, &s,
                                   convgcmac, &mcl, convgcmac, &mcr))
     goto end;
-  rc = grand_dopywrap(ty, tlsprf_rand(mcl, mcr, k, ksz, s, ssz), f_freeme);
+  rc = grand_dopywrap(ty, tlsprf_rand(mcl, mcr, k.p, k.sz, s.p, s.sz),
+                     f_freeme);
 end:
   return (rc);
 }
 
 static const PyTypeObject sslprf_pytype_skel = {
-  PyObject_HEAD_INIT(0) 0,             /* Header */
+  PyVarObject_HEAD_INIT(0, 0)          /* Header */
   "SSLRand",                           /* @tp_name@ */
   sizeof(grand_pyobj),                 /* @tp_basicsize@ */
   0,                                   /* @tp_itemsize@ */
@@ -1021,7 +1018,7 @@ static const PyTypeObject sslprf_pytype_skel = {
 };
 
 static const PyTypeObject tlsdx_pytype_skel = {
-  PyObject_HEAD_INIT(0) 0,             /* Header */
+  PyVarObject_HEAD_INIT(0, 0)          /* Header */
   "TLSDataExpansion",                  /* @tp_name@ */
   sizeof(grand_pyobj),                 /* @tp_basicsize@ */
   0,                                   /* @tp_itemsize@ */
@@ -1070,7 +1067,7 @@ static const PyTypeObject tlsdx_pytype_skel = {
 };
 
 static const PyTypeObject tlsprf_pytype_skel = {
-  PyObject_HEAD_INIT(0) 0,             /* Header */
+  PyVarObject_HEAD_INIT(0, 0)          /* Header */
   "TLSPRF",                            /* @tp_name@ */
   sizeof(grand_pyobj),                 /* @tp_basicsize@ */
   0,                                   /* @tp_itemsize@ */
@@ -1122,14 +1119,19 @@ static const PyTypeObject tlsprf_pytype_skel = {
 
 static PyObject *dsarand_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
 {
-  char *p;
-  Py_ssize_t sz;
+  struct bin in;
+  unsigned passes = 1;
+  grand *r;
   PyObject *rc = 0;
-  static const char *const kwlist[] = { "seed", 0 };
+  static const char *const kwlist[] = { "seed", "passes", 0 };
 
-  if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", KWLIST, &p, &sz))
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|O&:new", KWLIST,
+                                  convbin, &in, convuint, &passes))
     goto end;
-  rc = grand_dopywrap(ty, dsarand_create(p, sz), f_freeme);
+  if (!passes) VALERR("must be positive");
+  r = dsarand_create(in.p, in.sz);
+  if (passes != 1) r->ops->misc(r, DSARAND_PASSES, passes);
+  rc = grand_dopywrap(ty, r, f_freeme);
 end:
   return (rc);
 }
@@ -1139,19 +1141,42 @@ static PyObject *drget_seed(PyObject *me, void *hunoz)
   grand *r = GRAND_R(me);
   int n = r->ops->misc(r, DSARAND_SEEDSZ);
   PyObject *rc = bytestring_pywrap(0, n);
-  r->ops->misc(r, DSARAND_GETSEED, PyString_AS_STRING(rc));
+  r->ops->misc(r, DSARAND_GETSEED, BIN_PTR(rc));
+  return (rc);
+}
+
+static PyObject *drget_passes(PyObject *me, void *hunoz)
+{
+  grand *r = GRAND_R(me);
+  return (PyInt_FromLong(r->ops->misc(r, DSARAND_PASSES, 0)));
+}
+
+static int drset_passes(PyObject *me, PyObject *val, void *hunoz)
+{
+  grand *r = GRAND_R(me);
+  long n;
+  int rc = -1;
+
+  if (!val) NIERR("__del__");
+  n = PyInt_AsLong(val); if (n == -1 && PyErr_Occurred()) goto end;
+  if (n <= 0) VALERR("must be positive");
+  if (n > ULONG_MAX) VALERR("out of range");
+  r->ops->misc(r, DSARAND_PASSES, (unsigned)n);
+  rc = 0;
+end:
   return (rc);
 }
 
 static const PyGetSetDef dsarand_pygetset[] = {
 #define GETSETNAME(op, name) dr##op##_##name
   GET  (seed,          "R.seed -> current generator seed")
+  GETSET(passes,       "R.passes -> number of passes to create output")
 #undef GETSETNAME
   { 0 }
 };
 
 static const PyTypeObject dsarand_pytype_skel = {
-  PyObject_HEAD_INIT(0) 0,             /* Header */
+  PyVarObject_HEAD_INIT(0, 0)          /* Header */
   "DSARand",                           /* @tp_name@ */
   sizeof(grand_pyobj),                 /* @tp_basicsize@ */
   0,                                   /* @tp_itemsize@ */
@@ -1277,7 +1302,7 @@ static const PyGetSetDef bbs_pygetset[] = {
 };
 
 static const PyTypeObject bbs_pytype_skel = {
-  PyObject_HEAD_INIT(0) 0,             /* Header */
+  PyVarObject_HEAD_INIT(0, 0)          /* Header */
   "BlumBlumShub",                      /* @tp_name@ */
   sizeof(grand_pyobj),                 /* @tp_basicsize@ */
   0,                                   /* @tp_itemsize@ */
@@ -1439,7 +1464,7 @@ static const PyGetSetDef bbspriv_pygetset[] = {
 };
 
 static const PyTypeObject bbspriv_pytype_skel = {
-  PyObject_HEAD_INIT(0) 0,             /* Header */
+  PyVarObject_HEAD_INIT(0, 0)          /* Header */
   "BBSPriv",                           /* @tp_name@ */
   sizeof(bbspriv_pyobj),               /* @tp_basicsize@ */
   0,                                   /* @tp_itemsize@ */
@@ -1489,6 +1514,11 @@ static const PyTypeObject bbspriv_pytype_skel = {
 
 /*----- Global stuff ------------------------------------------------------*/
 
+static const struct nameval consts[] = {
+  CONST(RAND_IBITS),
+  { 0 }
+};
+
 void rand_pyinit(void)
 {
   INITTYPE(grand, root);
@@ -1508,8 +1538,10 @@ void rand_pyinit(void)
   rand_seed(RAND_GLOBAL, 160);
 }
 
-#define gccrand gccrand_info
-GEN(gccrands, crand)
+static const char *crand_namefn(const void *p)
+  { const gccrand_info *const *cls = p; return (*cls ? (*cls)->name : 0); }
+static PyObject *crand_valfn(const void *p)
+  { const gccrand_info *const *cls = p; return (gccrand_pywrap(*cls)); }
 
 void rand_pyinsert(PyObject *mod)
 {
@@ -1527,9 +1559,11 @@ void rand_pyinsert(PyObject *mod)
   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);
+  gccrands_dict = make_algtab(gcrandtab, sizeof(gccrand_info *),
+                             crand_namefn, crand_valfn);
+  INSERT("gccrands", gccrands_dict); Py_INCREF(gccrands_dict);
   INSERT("rand", rand_pyobj);
+  setconstants(mod, consts);
 }
 
 /*----- That's all, folks -------------------------------------------------*/