about summary refs log tree commit diff
path: root/src/librandom
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2014-09-18 18:55:44 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2014-09-18 18:55:44 +0000
commit3534b428629be185e096be99e3bd5fdfe32d5544 (patch)
tree210ef3198ed66bc7f7b7bf6a85e4579f455e5a36 /src/librandom
downloadskalibs-3534b428629be185e096be99e3bd5fdfe32d5544.tar.gz
skalibs-3534b428629be185e096be99e3bd5fdfe32d5544.tar.xz
skalibs-3534b428629be185e096be99e3bd5fdfe32d5544.zip
initial commit with rc for skalibs-2.0.0.0
Diffstat (limited to 'src/librandom')
-rw-r--r--src/librandom/badrandom_char.c13
-rw-r--r--src/librandom/badrandom_finish.c12
-rw-r--r--src/librandom/badrandom_here.c40
-rw-r--r--src/librandom/badrandom_init.c10
-rw-r--r--src/librandom/badrandom_int.c12
-rw-r--r--src/librandom/badrandom_string.c12
-rw-r--r--src/librandom/goodrandom_char.c13
-rw-r--r--src/librandom/goodrandom_finish.c12
-rw-r--r--src/librandom/goodrandom_here.c40
-rw-r--r--src/librandom/goodrandom_init.c10
-rw-r--r--src/librandom/goodrandom_int.c12
-rw-r--r--src/librandom/goodrandom_string.c12
-rw-r--r--src/librandom/random-internal.h20
-rw-r--r--src/librandom/random_mask2.c35
-rw-r--r--src/librandom/random_name.c13
-rw-r--r--src/librandom/random_sauniquename.c25
-rw-r--r--src/librandom/random_unsort.c17
-rw-r--r--src/librandom/randomegd_open.c20
-rw-r--r--src/librandom/randomegd_readb.c27
-rw-r--r--src/librandom/randomegd_readnb.c28
-rw-r--r--src/librandom/rrandom_add.c13
-rw-r--r--src/librandom/rrandom_finish.c14
-rw-r--r--src/librandom/rrandom_name.c13
-rw-r--r--src/librandom/rrandom_read.c21
-rw-r--r--src/librandom/rrandom_readint.c24
-rw-r--r--src/librandom/surf.c54
-rw-r--r--src/librandom/surf_autoinit.c10
-rw-r--r--src/librandom/surf_here.c8
-rw-r--r--src/librandom/surf_init.c10
-rw-r--r--src/librandom/surf_makeseed.c35
-rw-r--r--src/librandom/surf_sinit.c13
-rw-r--r--src/librandom/unidevrandom.c38
-rw-r--r--src/librandom/unidevurandom.c38
-rw-r--r--src/librandom/unihasegd.c38
-rw-r--r--src/librandom/unirandom_finish.c12
-rw-r--r--src/librandom/unirandom_init.c12
-rw-r--r--src/librandom/unirandom_readb.c10
-rw-r--r--src/librandom/unirandom_readnb.c10
-rw-r--r--src/librandom/unirandom_register.c16
-rw-r--r--src/librandom/unirandomdev.c50
-rw-r--r--src/librandom/unirandomegd.c37
-rw-r--r--src/librandom/unisurf.c23
-rw-r--r--src/librandom/unisurf_init.c18
43 files changed, 900 insertions, 0 deletions
diff --git a/src/librandom/badrandom_char.c b/src/librandom/badrandom_char.c
new file mode 100644
index 0000000..c0ca1de
--- /dev/null
+++ b/src/librandom/badrandom_char.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include "random-internal.h"
+#include <skalibs/random.h>
+
+unsigned char badrandom_char (void)
+{
+  unsigned char x ;
+  badrandom_string((char *)&x, 1) ;
+  return x ;
+}
diff --git a/src/librandom/badrandom_finish.c b/src/librandom/badrandom_finish.c
new file mode 100644
index 0000000..e0791ee
--- /dev/null
+++ b/src/librandom/badrandom_finish.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/rrandom.h>
+#include "random-internal.h"
+#include <skalibs/random.h>
+
+void badrandom_finish (void)
+{
+  rrandom_finish(&badrandom_here) ;
+}
diff --git a/src/librandom/badrandom_here.c b/src/librandom/badrandom_here.c
new file mode 100644
index 0000000..c7d2992
--- /dev/null
+++ b/src/librandom/badrandom_here.c
@@ -0,0 +1,40 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/sysdeps.h>
+#include <skalibs/config.h>
+#include <skalibs/unisurf.h>
+#include "random-internal.h"
+
+#ifdef SKALIBS_EGD
+
+# include <skalibs/unirandomegd.h>
+
+# ifdef SKALIBS_HASDEVURANDOM
+
+# include <skalibs/unirandomdev.h>
+
+rrandom badrandom_here = { { { UNIRANDOM_REGISTER_DEVURANDOM(), 3 }, { UNIRANDOM_REGISTER_HASEGD(), 3 }, { UNIRANDOM_REGISTER_SURF(), 3 } }, 3 } ;
+
+# else
+
+rrandom badrandom_here = { { { UNIRANDOM_REGISTER_HASEGD(), 3 }, { UNIRANDOM_REGISTER_SURF(), 3 }, { UNIRANDOM_ZERO, 3 } }, 2 } ;
+
+# endif
+
+#else
+
+# ifdef SKALIBS_HASDEVURANDOM
+
+# include <skalibs/unirandomdev.h>
+
+rrandom badrandom_here = { { { UNIRANDOM_REGISTER_DEVURANDOM(), 3 }, { UNIRANDOM_REGISTER_SURF(), 3 }, { UNIRANDOM_ZERO, 3 } }, 2 } ;
+
+# else
+
+rrandom badrandom_here = { { { UNIRANDOM_REGISTER_SURF(), 3 }, { UNIRANDOM_ZERO, 3 }, { UNIRANDOM_ZERO, 3 } }, 1 } ;
+
+# endif
+
+#endif
diff --git a/src/librandom/badrandom_init.c b/src/librandom/badrandom_init.c
new file mode 100644
index 0000000..a6eb7e3
--- /dev/null
+++ b/src/librandom/badrandom_init.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/random.h>
+
+int badrandom_init (void)
+{
+  return 1 ;
+}
diff --git a/src/librandom/badrandom_int.c b/src/librandom/badrandom_int.c
new file mode 100644
index 0000000..ae12db5
--- /dev/null
+++ b/src/librandom/badrandom_int.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/rrandom.h>
+#include "random-internal.h"
+#include <skalibs/random.h>
+
+unsigned int badrandom_int (unsigned int n)
+{
+  return rrandom_readint(&badrandom_here, n, &unirandom_readnb) ;
+}
diff --git a/src/librandom/badrandom_string.c b/src/librandom/badrandom_string.c
new file mode 100644
index 0000000..ec20f5b
--- /dev/null
+++ b/src/librandom/badrandom_string.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/rrandom.h>
+#include "random-internal.h"
+#include <skalibs/random.h>
+
+unsigned int badrandom_string (char *s, unsigned int n)
+{
+  return rrandom_readnb(&badrandom_here, s, n) ;
+}
diff --git a/src/librandom/goodrandom_char.c b/src/librandom/goodrandom_char.c
new file mode 100644
index 0000000..8fbf5e8
--- /dev/null
+++ b/src/librandom/goodrandom_char.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include "random-internal.h"
+#include <skalibs/random.h>
+
+unsigned char goodrandom_char (void)
+{
+  unsigned char x ;
+  goodrandom_string((char *)&x, 1) ;
+  return x ;
+}
diff --git a/src/librandom/goodrandom_finish.c b/src/librandom/goodrandom_finish.c
new file mode 100644
index 0000000..a764030
--- /dev/null
+++ b/src/librandom/goodrandom_finish.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include "random-internal.h"
+#include <skalibs/rrandom.h>
+#include <skalibs/random.h>
+
+void goodrandom_finish (void)
+{
+  rrandom_finish(&goodrandom_here) ;
+}
diff --git a/src/librandom/goodrandom_here.c b/src/librandom/goodrandom_here.c
new file mode 100644
index 0000000..8275ab2
--- /dev/null
+++ b/src/librandom/goodrandom_here.c
@@ -0,0 +1,40 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/sysdeps.h>
+#include <skalibs/config.h>
+#include <skalibs/unisurf.h>
+#include "random-internal.h"
+
+#ifdef SKALIBS_EGD
+
+# include <skalibs/unirandomegd.h>
+
+# ifdef SKALIBS_HASDEVRANDOM
+
+# include <skalibs/unirandomdev.h>
+
+rrandom goodrandom_here = { { { UNIRANDOM_REGISTER_DEVRANDOM(), 3 }, { UNIRANDOM_REGISTER_HASEGD(), 3 }, { UNIRANDOM_REGISTER_SURF(), 3 } }, 3 } ;
+
+# else
+
+rrandom goodrandom_here = { { { UNIRANDOM_REGISTER_HASEGD(), 3 }, { UNIRANDOM_REGISTER_SURF(), 3 }, { UNIRANDOM_ZERO, 3 } }, 2 } ;
+
+# endif
+
+#else
+
+# ifdef SKALIBS_HASDEVRANDOM
+
+# include <skalibs/unirandomdev.h>
+
+rrandom goodrandom_here = { { { UNIRANDOM_REGISTER_DEVRANDOM(), 3 }, { UNIRANDOM_REGISTER_SURF(), 3 }, { UNIRANDOM_ZERO, 3 } }, 2 } ;
+
+# else
+
+rrandom goodrandom_here = { { { UNIRANDOM_REGISTER_SURF(), 3 }, { UNIRANDOM_ZERO, 3 }, { UNIRANDOM_ZERO, 3 } }, 1 } ;
+
+# endif
+
+#endif
diff --git a/src/librandom/goodrandom_init.c b/src/librandom/goodrandom_init.c
new file mode 100644
index 0000000..dea6225
--- /dev/null
+++ b/src/librandom/goodrandom_init.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/random.h>
+
+int goodrandom_init (void)
+{
+  return 1 ;
+}
diff --git a/src/librandom/goodrandom_int.c b/src/librandom/goodrandom_int.c
new file mode 100644
index 0000000..11ef2e1
--- /dev/null
+++ b/src/librandom/goodrandom_int.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/rrandom.h>
+#include "random-internal.h"
+#include <skalibs/random.h>
+
+unsigned int goodrandom_int (unsigned int n)
+{
+  return rrandom_readint(&goodrandom_here, n, &unirandom_readb) ;
+}
diff --git a/src/librandom/goodrandom_string.c b/src/librandom/goodrandom_string.c
new file mode 100644
index 0000000..556c41c
--- /dev/null
+++ b/src/librandom/goodrandom_string.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/rrandom.h>
+#include "random-internal.h"
+#include <skalibs/random.h>
+
+unsigned int goodrandom_string (char *s, unsigned int n)
+{
+  return rrandom_readb(&goodrandom_here, s, n) ;
+}
diff --git a/src/librandom/random-internal.h b/src/librandom/random-internal.h
new file mode 100644
index 0000000..37b534e
--- /dev/null
+++ b/src/librandom/random-internal.h
@@ -0,0 +1,20 @@
+/* ISC license. */
+
+#ifndef RANDOM_INTERNAL_H
+#define RANDOM_INTERNAL_H
+
+#include <skalibs/gccattributes.h>
+#include <skalibs/surf.h>
+#include <skalibs/unirandom.h>
+#include <skalibs/rrandom.h>
+
+extern void unirandom_register (unirandom_ref, int (*) (union unirandominfo *), int (*) (union unirandominfo *), unsigned int (*) (union unirandominfo *, char *, unsigned int), unsigned int (*) (union unirandominfo *, char *, unsigned int)) ;
+
+extern unsigned int random_mask2 (unsigned int) gccattr_const ;
+extern unsigned int random_nchars (unsigned int) gccattr_const ;
+
+extern SURFSchedule surf_here ;
+extern rrandom goodrandom_here ;
+extern rrandom badrandom_here ;
+
+#endif
diff --git a/src/librandom/random_mask2.c b/src/librandom/random_mask2.c
new file mode 100644
index 0000000..ab8c8e7
--- /dev/null
+++ b/src/librandom/random_mask2.c
@@ -0,0 +1,35 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+#include "random-internal.h"
+
+unsigned int random_mask2 (register unsigned int n)
+{
+  for (;;)
+  {
+    register unsigned int m = n | (n >> 1) ;
+    if (m == n) return n ;
+    n = m ;
+  }
+}
+
+unsigned int random_nchars (register unsigned int n)
+{
+  return n <= 0xff ? 1 :
+#if SKALIBS_SIZEOFUINT == 2
+  2
+#else
+         n <= 0xffff ? 2 :
+         n <= 0xffffffUL ? 3 :
+# if SKALIBS_SIZEOFUINT == 4
+  4
+# else
+         n <= 0xffffffffUL ? 4 :
+         n <= 0xffffffffffULL ? 5 :
+         n <= 0xffffffffffffULL ? 6 :
+         n <= 0xffffffffffffffULL ? 7 :
+  8
+# endif
+#endif
+ ;
+}
diff --git a/src/librandom/random_name.c b/src/librandom/random_name.c
new file mode 100644
index 0000000..8736699
--- /dev/null
+++ b/src/librandom/random_name.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include "random-internal.h"
+#include <skalibs/random.h>
+
+int random_name (char *s, unsigned int n)
+{
+  register unsigned int r = rrandom_name(&badrandom_here, s, n, 1) ;
+  if (r < n) return -1 ;
+  return n ;
+}
diff --git a/src/librandom/random_sauniquename.c b/src/librandom/random_sauniquename.c
new file mode 100644
index 0000000..7c902ef
--- /dev/null
+++ b/src/librandom/random_sauniquename.c
@@ -0,0 +1,25 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/stralloc.h>
+#include <skalibs/skamisc.h>
+#include <skalibs/random.h>
+
+int random_sauniquename (stralloc *sa, unsigned int n)
+{
+  unsigned int base = sa->len ;
+  int wasnull = !sa->s ;
+  register int r ;
+  if (sauniquename(sa) == -1) return -1 ;
+  if (!stralloc_readyplus(sa, n+1)) goto err ;
+  stralloc_catb(sa, ":", 1) ;
+  r = random_name(sa->s + sa->len, n) ;
+  if (r == -1) goto err ;
+  sa->len += r ;
+  return r ;
+
+err:
+  if (wasnull) stralloc_free(sa) ; else sa->len = base ;
+  return -1 ;
+}
diff --git a/src/librandom/random_unsort.c b/src/librandom/random_unsort.c
new file mode 100644
index 0000000..289ef96
--- /dev/null
+++ b/src/librandom/random_unsort.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/random.h>
+
+void random_unsort (char *s, unsigned int n, unsigned int chunksize)
+{
+  char tmp[chunksize] ;
+  while (n--)
+  {
+    register unsigned int i = badrandom_int(n+1) ;
+    byte_copy(tmp, chunksize, s + i * chunksize) ;
+    byte_copy(s + i * chunksize, chunksize, s + n * chunksize) ;
+    byte_copy(s + n * chunksize, chunksize, tmp) ;
+  }
+}
diff --git a/src/librandom/randomegd_open.c b/src/librandom/randomegd_open.c
new file mode 100644
index 0000000..7c43f0d
--- /dev/null
+++ b/src/librandom/randomegd_open.c
@@ -0,0 +1,20 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/webipc.h>
+#include <skalibs/randomegd.h>
+
+int randomegd_open (char const *path)
+{
+  int s = ipc_stream() ;
+  if (s < 0) return -1 ;
+  if (ipc_connect(s, path) == -1)
+  {
+    register int e = errno ;
+    fd_close(s) ;
+    errno = e ;
+    return -1 ;
+  }
+  return s ;
+}
diff --git a/src/librandom/randomegd_readb.c b/src/librandom/randomegd_readb.c
new file mode 100644
index 0000000..614f7a8
--- /dev/null
+++ b/src/librandom/randomegd_readb.c
@@ -0,0 +1,27 @@
+/* ISC license. */
+
+#include <skalibs/allreadwrite.h>
+#include <skalibs/randomegd.h>
+
+unsigned int randomegd_readb (int s, char *x, unsigned int n)
+{
+  unsigned int w = 0 ;
+  unsigned int i = 0 ;
+  for (; i < (n / 255) ; i++)
+  {
+    char const c[2] = { 0x02, 0xFF } ;
+    register unsigned int wtmp ;
+    if (allwrite(s, c, 2) < 2) return w ;
+    wtmp = allread(s, x + w, 255) ;
+    w += wtmp ;
+    if (wtmp < 255) return w ;
+  }
+  if (w < n)
+  {
+    char c[2] = "\002" ;
+    c[1] = n - w ;
+    if (allwrite(s, c, 2) < 2) return w ;
+    w += allread(s, x + w, c[1]) ;
+  }
+  return w ;
+}
diff --git a/src/librandom/randomegd_readnb.c b/src/librandom/randomegd_readnb.c
new file mode 100644
index 0000000..29165c4
--- /dev/null
+++ b/src/librandom/randomegd_readnb.c
@@ -0,0 +1,28 @@
+/* ISC license. */
+
+#include <skalibs/allreadwrite.h>
+#include <skalibs/randomegd.h>
+
+unsigned int randomegd_readnb (int s, char *x, unsigned int n)
+{
+  unsigned int w = 0 ;
+  while ((n - w) >= 255)
+  {
+    char c[2] = { 0x01, 0xFF } ;
+    register unsigned char wtmp ;
+    if (allwrite(s, c, 2) < 2) return w ;
+    if (sanitize_read(fd_read(s, c+1, 1)) < 1) return w ;
+    wtmp = allread(s, x + w, c[1]) ;
+    w += wtmp ;
+    if ((wtmp < (unsigned char)c[1]) || ((unsigned char)c[1] < 0xFF)) return w ;
+  }
+  if (w < n)
+  {
+    char c[2] = "\001" ;
+    c[1] = n - w ;
+    if (allwrite(s, c, 2) < 2) return w ;
+    if (sanitize_read(fd_read(s, c+1, 1)) < 1) return w ;
+    w += allread(s, x + w, c[1]) ;
+  }
+  return w ;
+}
diff --git a/src/librandom/rrandom_add.c b/src/librandom/rrandom_add.c
new file mode 100644
index 0000000..c22a43c
--- /dev/null
+++ b/src/librandom/rrandom_add.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/unirandom.h>
+#include <skalibs/rrandom.h>
+
+int rrandom_add (rrandom_ref z, int (*f) (unirandom_ref))
+{
+  if (z->n >= 3) return (errno = EBUSY, 0) ;
+  if (!(*f)(&z->tries[z->n].it)) return 0 ;
+  z->tries[z->n++].ok = 3 ;
+  return 1 ;
+}
diff --git a/src/librandom/rrandom_finish.c b/src/librandom/rrandom_finish.c
new file mode 100644
index 0000000..a3cb24b
--- /dev/null
+++ b/src/librandom/rrandom_finish.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <skalibs/unirandom.h>
+#include <skalibs/rrandom.h>
+
+int rrandom_finish (rrandom_ref z)
+{
+  rrandom zero = RRANDOM_ZERO ;
+  unsigned int i = z->n ;
+  int e = 1 ;
+  while (i--) e &= unirandom_finish(&z->tries[i].it) ;
+  if (e) *z = zero ;
+  return e ;
+}
diff --git a/src/librandom/rrandom_name.c b/src/librandom/rrandom_name.c
new file mode 100644
index 0000000..5e77e83
--- /dev/null
+++ b/src/librandom/rrandom_name.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <skalibs/unirandom.h>
+#include <skalibs/rrandom.h>
+
+unsigned int rrandom_name (rrandom_ref z, char *s, unsigned int n, int nb)
+{
+  static char const *oklist = "ABCDEFGHIJKLMNOPQRSTUVWXYZghijklmnopqrstuvwxyz-_0123456789abcdef" ;
+  register unsigned int r = rrandom_read(z, s, n, nb ? &unirandom_readnb : &unirandom_readb) ;
+  register unsigned int i = 0 ;
+  for (; i < r ; i++) s[i] = oklist[s[i] & 63] ;
+  return r ;
+}
diff --git a/src/librandom/rrandom_read.c b/src/librandom/rrandom_read.c
new file mode 100644
index 0000000..57ff920
--- /dev/null
+++ b/src/librandom/rrandom_read.c
@@ -0,0 +1,21 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/error.h>
+#include <skalibs/unirandom.h>
+#include <skalibs/rrandom.h>
+
+unsigned int rrandom_read (rrandom_ref z, char *s, unsigned int n, unsigned int (*f) (unirandom_ref, char *, unsigned int))
+{
+  unsigned int i = 0 ;
+  for (; i < 3 ; i++)
+  {
+    int r ;
+    if (!z->tries[i].ok) continue ;
+    r = sanitize_read((*f)(&z->tries[i].it, s, n)) ;
+    if (r > 0) return r ;
+    z->tries[i].ok = error_temp(errno) ? z->tries[i].ok - 1 : 0 ;
+  }
+  return (errno = ENOENT, 0) ;
+}
diff --git a/src/librandom/rrandom_readint.c b/src/librandom/rrandom_readint.c
new file mode 100644
index 0000000..e4f677c
--- /dev/null
+++ b/src/librandom/rrandom_readint.c
@@ -0,0 +1,24 @@
+/* ISC license. */
+
+#include <skalibs/uint.h>
+#include <skalibs/unirandom.h>
+#include "random-internal.h"
+#include <skalibs/rrandom.h>
+
+unsigned int rrandom_readint (rrandom_ref z, unsigned int n, unsigned int (*f) (unirandom_ref, char *, unsigned int))
+{
+  if (!n) return 0 ;
+  else
+  {
+    unsigned int i = n, nchars = random_nchars(n), m = random_mask2(n-1) ;
+    char tmp[UINT_PACK] ;
+    while (i >= n)
+    {
+      if (rrandom_read(z, tmp, nchars, f) < nchars) return 0 ;
+      byte_zero(tmp + nchars, UINT_PACK - nchars) ;
+      uint_unpack(tmp, &i) ;
+      i &= m ;
+    }
+    return i ;
+  }
+}
diff --git a/src/librandom/surf.c b/src/librandom/surf.c
new file mode 100644
index 0000000..1687df9
--- /dev/null
+++ b/src/librandom/surf.c
@@ -0,0 +1,54 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/surf.h>
+
+#define ROTATE(x, b) (((x) << (b)) | ((x) >> (32 - (b))))
+#define MUSH(i, b) x = t[i] += (((x ^ ctx->seed[i]) + sum) ^ ROTATE(x, b))
+
+static void surfit (SURFSchedule_ref ctx)
+{
+  uint32 t[12] ;
+  uint32 z[8] ;
+  uint32 x ;
+  uint32 sum = 0 ;
+  unsigned int i = 0, loop = 0 ; ;
+
+  if (!++ctx->in[0] && !++ctx->in[1] && !++ctx->in[2]) ++ctx->in[3] ;
+  for (; i < 12 ; i++) t[i] = ctx->in[i] ^ ctx->seed[12+i] ;
+  for (i = 0 ; i < 8 ; i++) z[i] = ctx->seed[24+i] ;
+  x = t[11] ;
+  for (; loop < 2 ; loop++)
+  {
+    for (i = 0 ; i < 16 ; i++)
+    {
+      sum += 0x9e3779b9 ;
+      MUSH(0, 5) ; MUSH(1, 7) ; MUSH(2, 9) ;  MUSH(3, 13) ;
+      MUSH(4, 5) ; MUSH(5, 7) ; MUSH(6, 9) ;  MUSH(7, 13) ;
+      MUSH(8, 5) ; MUSH(9, 7) ; MUSH(10, 9) ; MUSH(11, 13) ;
+    }
+    for (i = 0 ; i < 8 ; i++) z[i] ^= t[i+4] ;
+  }
+  for (i = 0 ; i < 8 ; i++) uint32_pack(ctx->out + (i<<2), z[i]) ;
+}
+
+void surf (SURFSchedule_ref ctx, char *s, unsigned int n)
+{
+  {
+    register unsigned int i = 32 - ctx->pos ;
+    if (n < i) i = n ;
+    byte_copy(s, i, ctx->out + ctx->pos) ;
+    s += i ; n -= i ; ctx->pos += i ;
+  }
+  while (n > 32)
+  {
+    surfit(ctx) ;
+    byte_copy(s, 32, ctx->out) ;
+    s += 32 ; n -= 32 ;
+  }
+  if (!n) return ;
+  surfit(ctx) ;
+  byte_copy(s, n, ctx->out) ;
+  ctx->pos = n ;
+}
diff --git a/src/librandom/surf_autoinit.c b/src/librandom/surf_autoinit.c
new file mode 100644
index 0000000..920612b
--- /dev/null
+++ b/src/librandom/surf_autoinit.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/surf.h>
+
+void surf_autoinit (SURFSchedule_ref ctx, char *s, unsigned int n)
+{
+  if (!ctx->in[0] && !ctx->in[1] && !ctx->in[2] && !ctx->in[3])
+    surf_init(ctx) ;
+  surf(ctx, s, n) ;
+}
diff --git a/src/librandom/surf_here.c b/src/librandom/surf_here.c
new file mode 100644
index 0000000..ebbdffb
--- /dev/null
+++ b/src/librandom/surf_here.c
@@ -0,0 +1,8 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/surf.h>
+#include "random-internal.h"
+
+SURFSchedule surf_here = SURFSCHEDULE_ZERO ;
diff --git a/src/librandom/surf_init.c b/src/librandom/surf_init.c
new file mode 100644
index 0000000..3662fa8
--- /dev/null
+++ b/src/librandom/surf_init.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/surf.h>
+
+void surf_init (SURFSchedule_ref ctx)
+{
+  char s[160] ;
+  surf_makeseed(s) ;
+  surf_sinit(ctx, s) ;
+}
diff --git a/src/librandom/surf_makeseed.c b/src/librandom/surf_makeseed.c
new file mode 100644
index 0000000..adae9a4
--- /dev/null
+++ b/src/librandom/surf_makeseed.c
@@ -0,0 +1,35 @@
+/* ISC license. */
+
+#include <unistd.h>
+#include <skalibs/uint32.h>
+#include <skalibs/tai.h>
+#include <skalibs/sha1.h>
+#include <skalibs/surf.h>
+
+void surf_makeseed (char *s)
+{
+  SHA1Schedule bak = SHA1_INIT() ;
+  {
+    tain_t now ;
+    char tmp[20 + TAIN_PACK] ;
+    uint32 x = getpid() ;
+    uint32_pack(tmp, x) ;
+    x = getppid() ;
+    uint32_pack(tmp + 4, x) ;
+    tain_now(&now) ;
+    tain_pack(tmp + 8, &now) ;
+    sha1_update(&bak, tmp, 8 + TAIN_PACK) ;
+    sha1_final(&bak, tmp) ;
+    sha1_init(&bak) ;
+    sha1_update(&bak, tmp, 20) ;
+  }  
+  {
+    char i = 0 ;
+    for (; i < 8 ; i++)
+    {
+      SHA1Schedule ctx = bak ;
+      sha1_update(&ctx, &i, 1) ;
+      sha1_final(&ctx, s + 20*i) ;
+    }
+  }
+}
diff --git a/src/librandom/surf_sinit.c b/src/librandom/surf_sinit.c
new file mode 100644
index 0000000..ae7f480
--- /dev/null
+++ b/src/librandom/surf_sinit.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/surf.h>
+
+void surf_sinit (SURFSchedule_ref ctx, char const *s)
+{
+  SURFSchedule zero = SURFSCHEDULE_ZERO ;
+  register unsigned int i = 4 ;
+  *ctx = zero ;
+  for (; i < 12 ; i++) uint32_unpack(s + (i<<2) - 16, ctx->in + i) ;
+  for (i = 0 ; i < 32 ; i++) uint32_unpack(s + 32 + (i<<2), ctx->seed + i) ;
+}
diff --git a/src/librandom/unidevrandom.c b/src/librandom/unidevrandom.c
new file mode 100644
index 0000000..fb7b6b8
--- /dev/null
+++ b/src/librandom/unidevrandom.c
@@ -0,0 +1,38 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+#include <skalibs/unirandomdev.h>
+#include <skalibs/unirandom.h>
+
+#ifdef SKALIBS_HASDEVRANDOM
+
+#include "random-internal.h"
+
+int unidevrandom_init (union unirandominfo *u)
+{
+  return unirandomdev_sinit(u, "/dev/random") ;
+}
+
+int unirandom_register_devrandom (unirandom *u)
+{
+  unirandom_register(u, &unidevrandom_init, &unirandomdev_finish, &unirandomdev_readb, &unirandomdev_readnb) ;
+  return 1 ;
+}
+
+#else
+
+#include <errno.h>
+
+int unidevrandom_init (union unirandominfo *u)
+{
+  (void)u ;
+  return (errno = ENOSYS, 0) ;
+}
+
+int unirandom_register_devrandom (unirandom *u)
+{
+  (void)u ;
+  return (errno = ENOSYS, 0) ;
+}
+
+#endif
diff --git a/src/librandom/unidevurandom.c b/src/librandom/unidevurandom.c
new file mode 100644
index 0000000..d601ea0
--- /dev/null
+++ b/src/librandom/unidevurandom.c
@@ -0,0 +1,38 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+#include <skalibs/unirandomdev.h>
+#include <skalibs/unirandom.h>
+
+#ifdef SKALIBS_HASDEVURANDOM
+
+#include "random-internal.h"
+
+int unidevurandom_init (union unirandominfo *u)
+{
+  return unirandomdev_sinit(u, "/dev/urandom") ;
+}
+
+int unirandom_register_devurandom (unirandom *u)
+{
+  unirandom_register(u, &unidevurandom_init, &unirandomdev_finish, &unirandomdev_readb, &unirandomdev_readnb) ;
+  return 1 ;
+}
+
+#else
+
+#include <errno.h>
+
+int unidevurandom_init (union unirandominfo *u)
+{
+  (void)u ;
+  return (errno = ENOSYS, 0) ;
+}
+
+int unirandom_register_devurandom (unirandom *u)
+{
+  (void)u ;
+  return (errno = ENOSYS, 0) ;
+}
+
+#endif
diff --git a/src/librandom/unihasegd.c b/src/librandom/unihasegd.c
new file mode 100644
index 0000000..ab263c7
--- /dev/null
+++ b/src/librandom/unihasegd.c
@@ -0,0 +1,38 @@
+/* ISC license. */
+
+#include <skalibs/config.h>
+#include <skalibs/unirandomegd.h>
+#include <skalibs/unirandom.h>
+
+#ifdef SKALIBS_EGD
+
+#include "random-internal.h"
+
+int unihasegd_init (union unirandominfo *u)
+{
+  return unirandomegd_sinit(u, SKALIBS_EGD) ;
+}
+
+int unirandom_register_hasegd (unirandom *u)
+{
+  unirandom_register(u, &unihasegd_init, &unirandomegd_finish, &unirandomegd_readb, &unirandomegd_readnb) ;
+  return 1 ;
+}
+
+#else
+
+#include <errno.h>
+
+int unihasegd_init (union unirandominfo *u)
+{
+  (void)u ;
+  return (errno = ENOSYS, 0) ;
+}
+
+int unirandom_register_hasegd (unirandom *u)
+{
+  (void)u ;
+  return (errno = ENOSYS, 0) ;
+}
+
+#endif
diff --git a/src/librandom/unirandom_finish.c b/src/librandom/unirandom_finish.c
new file mode 100644
index 0000000..14c4411
--- /dev/null
+++ b/src/librandom/unirandom_finish.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/unirandom.h>
+
+int unirandom_finish (unirandom_ref u)
+{
+  if (!u->initted) return 1 ;
+  if (!(*u->finish)(&u->data)) return 0 ;
+  u->initted = 0 ;
+  return 1 ;
+}
diff --git a/src/librandom/unirandom_init.c b/src/librandom/unirandom_init.c
new file mode 100644
index 0000000..711a4ac
--- /dev/null
+++ b/src/librandom/unirandom_init.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/unirandom.h>
+
+int unirandom_init (unirandom_ref u)
+{
+  if (u->initted) return 1 ;
+  if (!(*u->init)(&u->data)) return 0 ;
+  u->initted = 1 ;
+  return 1 ;
+}
diff --git a/src/librandom/unirandom_readb.c b/src/librandom/unirandom_readb.c
new file mode 100644
index 0000000..cbe45a6
--- /dev/null
+++ b/src/librandom/unirandom_readb.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/unirandom.h>
+
+unsigned int unirandom_readb (unirandom_ref u, char *s, unsigned int n)
+{
+  if (!u->initted && !unirandom_init(u)) return 0 ;
+  return (*u->readb)(&u->data, s, n) ;
+}
diff --git a/src/librandom/unirandom_readnb.c b/src/librandom/unirandom_readnb.c
new file mode 100644
index 0000000..f0cc38e
--- /dev/null
+++ b/src/librandom/unirandom_readnb.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/unirandom.h>
+
+unsigned int unirandom_readnb (unirandom_ref u, char *s, unsigned int n)
+{
+  if (!u->initted && !unirandom_init(u)) return 0 ;
+  return (*u->readnb)(&u->data, s, n) ;
+}
diff --git a/src/librandom/unirandom_register.c b/src/librandom/unirandom_register.c
new file mode 100644
index 0000000..35f7411
--- /dev/null
+++ b/src/librandom/unirandom_register.c
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/unirandom.h>
+#include "random-internal.h"
+
+void unirandom_register (unirandom_ref u, int (*init) (union unirandominfo *), int (*finish) (union unirandominfo *), unsigned int (*readb) (union unirandominfo *, char *, unsigned int), unsigned int (*readnb) (union unirandominfo *, char *, unsigned int))
+{
+  unirandom zero = UNIRANDOM_ZERO ;
+  *u = zero ;
+  u->init = init ;
+  u->finish = finish ;
+  u->readb = readb ;
+  u->readnb = readnb ;
+  u->initted = 0 ;
+}
diff --git a/src/librandom/unirandomdev.c b/src/librandom/unirandomdev.c
new file mode 100644
index 0000000..4a22514
--- /dev/null
+++ b/src/librandom/unirandomdev.c
@@ -0,0 +1,50 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/buffer.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/unirandom.h>
+#include <skalibs/unirandomdev.h>
+
+int unirandomdev_sinit (union unirandominfo *u, char const *file)
+{
+  register int fd = open_read(file) ;
+  if (fd < 0) return 0 ;
+  if (coe(fd) < 0)
+  {
+    register int e = errno ;
+    fd_close(fd) ;
+    errno = e ;
+    return 0 ;
+  }
+  buffer_init(&u->device.b, &buffer_read, fd, u->device.buf, RANDOMBUF_BUFSIZE) ;
+  u->device.nb = 1 ;
+  return 1 ;
+}
+
+int unirandomdev_finish (union unirandominfo *u)
+{
+  return fd_close(buffer_fd(&u->device.b)) < 0 ;
+}
+
+static unsigned int unirandomdev_read (union unirandominfo *u, char *s, unsigned int n, unsigned int h)
+{
+  unsigned int w = 0 ;
+  if (u->device.nb != h)
+  {
+    if ((h ? ndelay_on(buffer_fd(&u->device.b)) : ndelay_off(buffer_fd(&u->device.b))) < 0) return 0 ;
+    u->device.nb = h ;
+  }
+  buffer_getall(&u->device.b, s, n, &w) ;
+  return w ;
+}
+
+unsigned int unirandomdev_readb (union unirandominfo *u, char *s, unsigned int n)
+{
+  return unirandomdev_read(u, s, n, 0) ;
+}
+
+unsigned int unirandomdev_readnb (union unirandominfo *u, char *s, unsigned int n)
+{
+  return unirandomdev_read(u, s, n, 1) ;
+}
diff --git a/src/librandom/unirandomegd.c b/src/librandom/unirandomegd.c
new file mode 100644
index 0000000..a340f06
--- /dev/null
+++ b/src/librandom/unirandomegd.c
@@ -0,0 +1,37 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/randomegd.h>
+#include <skalibs/unirandom.h>
+#include <skalibs/unirandomegd.h>
+
+int unirandomegd_sinit (union unirandominfo *u, char const *path)
+{
+  register int s = randomegd_open(path) ;
+  if (s == -1) return 0 ;
+  if (coe(s) == -1)
+  {
+    register int e = errno ;
+    fd_close(s) ;
+    errno = e ;
+    return 0 ;
+  }
+  u->egd.fd = s ;
+  return 1 ;
+}
+
+int unirandomegd_finish (union unirandominfo *u)
+{
+  return !fd_close(u->egd.fd) ;
+}
+
+unsigned int unirandomegd_readb (union unirandominfo *u, char *s, unsigned int n)
+{
+  return randomegd_readb(u->egd.fd, s, n) ;
+}
+
+unsigned int unirandomegd_readnb (union unirandominfo *u, char *s, unsigned int n)
+{
+  return randomegd_readnb(u->egd.fd, s, n) ;
+}
diff --git a/src/librandom/unisurf.c b/src/librandom/unisurf.c
new file mode 100644
index 0000000..334d044
--- /dev/null
+++ b/src/librandom/unisurf.c
@@ -0,0 +1,23 @@
+/* ISC license. */
+
+#include <skalibs/surf.h>
+#include <skalibs/unirandom.h>
+#include <skalibs/unisurf.h>
+
+int unisurf_sinit (union unirandominfo *u, char const *s)
+{
+  surf_sinit(&u->surf_ctx, s) ;
+  return 1 ;
+}
+
+int unisurf_finish (union unirandominfo *u)
+{
+  (void)u ;
+  return 1 ;
+}
+
+unsigned int unisurf_read (union unirandominfo *u, char *s, unsigned int n)
+{
+  surf(&u->surf_ctx, s, n) ;
+  return n ;
+}
diff --git a/src/librandom/unisurf_init.c b/src/librandom/unisurf_init.c
new file mode 100644
index 0000000..d5a1f73
--- /dev/null
+++ b/src/librandom/unisurf_init.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#include <skalibs/surf.h>
+#include "random-internal.h"
+#include <skalibs/unirandom.h>
+#include <skalibs/unisurf.h>
+
+int unisurf_init (union unirandominfo *u)
+{
+  surf_init(&u->surf_ctx) ;
+  return 1 ;
+}
+
+int unirandom_register_surf (unirandom *u)
+{
+  unirandom_register(u, &unisurf_init, &unisurf_finish, &unisurf_read, &unisurf_read) ;
+  return 1 ;
+}