+/*----- Generic random number generator interface -------------------------*/
+
+static void gdestroy(grand *r)
+{
+ gctx *g = (r == &rand_global ? &pool : (gctx *)r);
+ if (g != &pool)
+ DESTROY(g);
+}
+
+static int gmisc(grand *r, unsigned op, ...)
+{
+ gctx *g = (r == &rand_global ? &pool : (gctx *)r);
+ va_list ap;
+ int rc = 0;
+ va_start(ap, op);
+
+ switch (op) {
+ case GRAND_CHECK:
+ switch (va_arg(ap, unsigned)) {
+ case GRAND_CHECK:
+ case GRAND_SEEDINT:
+ case GRAND_SEEDUINT32:
+ case GRAND_SEEDBLOCK:
+ case GRAND_SEEDRAND:
+ case RAND_GATE:
+ case RAND_STRETCH:
+ case RAND_KEY:
+ case RAND_NOISESRC:
+ rc = 1;
+ break;
+ default:
+ rc = 0;
+ break;
+ }
+ break;
+ case GRAND_SEEDINT: {
+ unsigned u = va_arg(ap, unsigned);
+ rand_add(&g->p, &u, sizeof(u), sizeof(u));
+ } break;
+ case GRAND_SEEDUINT32: {
+ uint32 i = va_arg(ap, uint32);
+ rand_add(&g->p, &i, sizeof(i), 4);
+ } break;
+ case GRAND_SEEDBLOCK: {
+ const void *p = va_arg(ap, const void *);
+ size_t sz = va_arg(ap, size_t);
+ rand_add(&g->p, p, sz, sz);
+ } break;
+ case GRAND_SEEDRAND: {
+ grand *rr = va_arg(ap, grand *);
+ octet buf[16];
+ rr->ops->fill(rr, buf, sizeof(buf));
+ rand_add(&g->p, buf, sizeof(buf), 8);
+ } break;
+ case RAND_GATE:
+ rand_gate(&g->p);
+ break;
+ case RAND_STRETCH:
+ rand_stretch(&g->p);
+ break;
+ case RAND_KEY: {
+ const void *k = va_arg(ap, const void *);
+ size_t sz = va_arg(ap, size_t);
+ rand_key(&g->p, k, sz);
+ } break;
+ case RAND_NOISESRC:
+ rand_noisesrc(&g->p, va_arg(ap, const rand_source *));
+ break;
+ default:
+ GRAND_BADOP;
+ break;
+ }
+
+ va_end(ap);
+ return (rc);
+}
+
+static octet gbyte(grand *r)
+{
+ gctx *g = (r == &rand_global ? &pool : (gctx *)r);
+ octet o;
+ rand_getgood(&g->p, &o, 1);
+ return (o);
+}
+
+static uint32 gword(grand *r)
+{
+ gctx *g = (r == &rand_global ? &pool : (gctx *)r);
+ octet b[4];
+ rand_getgood(&g->p, &b, sizeof(b));
+ return (LOAD32(b));
+}
+
+static void gfill(grand *r, void *p, size_t sz)
+{
+ gctx *g = (r == &rand_global ? &pool : (gctx *)r);
+ rand_getgood(&g->p, p, sz);
+}
+
+static const grand_ops gops = {
+ "rand",
+ 0,
+ gmisc, gdestroy,
+ gword, gbyte, gword, grand_range, gfill
+};
+
+grand rand_global = { &gops };
+
+/* --- @rand_create@ --- *
+ *
+ * Arguments: ---
+ *
+ * Returns: Pointer to a generic generator.
+ *
+ * Use: Constructs a generic generator interface over a Catacomb
+ * entropy pool generator.
+ */
+
+grand *rand_create(void)
+{
+ gctx *g = CREATE(gctx);
+ g->r.ops = &gops;
+ rand_init(&g->p);
+ return (&g->r);
+}
+