[v2,2/7] support: Add pseudo-random number generator interface

Message ID 20180831204238.10626-3-adhemerval.zanella@linaro.org
State Dropped
Headers

Commit Message

Adhemerval Zanella Aug. 31, 2018, 8:42 p.m. UTC
  This is based on POSIX mrand48 and the interfaces provided is just
wrapping around common usages (buffer fill and uniform distribution).
Although better PNRGs exists, the already in place POSIXs one is
used for simplicity and a better de factor one is being discussed
for inclusion (arc4random based on AES-CTR). Ideally it would replace
the mrand48 usage for this interface.

Checked on x86_64-linux-gnu.

	* support/Makefile (libsupport-routines): Add support_random.
	(tests): Add tst-support_random.
	* support/support_random.c: New file.
	* support/support_random.h: Likewise.
---
 support/Makefile         |  3 +-
 support/support_random.c | 90 ++++++++++++++++++++++++++++++++++++++++
 support/support_random.h | 59 ++++++++++++++++++++++++++
 3 files changed, 151 insertions(+), 1 deletion(-)
 create mode 100644 support/support_random.c
 create mode 100644 support/support_random.h
  

Patch

diff --git a/support/Makefile b/support/Makefile
index 9063046c23..db46be606e 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -56,6 +56,7 @@  libsupport-routines = \
   support_openpty \
   support_quote_blob \
   support_record_failure \
+  support_random \
   support_run_diff \
   support_shared_allocate \
   support_test_compare_blob \
@@ -161,7 +162,7 @@  tests = \
   tst-support_record_failure \
   tst-test_compare \
   tst-test_compare_blob \
-  tst-xreadlink \
+  tst-xreadlink
 
 ifeq ($(run-built-tests),yes)
 tests-special = \
diff --git a/support/support_random.c b/support/support_random.c
new file mode 100644
index 0000000000..5feee1a213
--- /dev/null
+++ b/support/support_random.c
@@ -0,0 +1,90 @@ 
+/* Function for pseudo-random number generation.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <assert.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/random.h>
+
+#include <support/support_random.h>
+#include <support/check.h>
+#include <support/xunistd.h>
+
+void
+support_random_seed (support_random_state *state, uint32_t seed)
+{
+  unsigned short int seed16v[3] = { 0 };
+  memcpy (seed16v, &seed, sizeof (seed));
+  seed48_r (seed16v, state);
+}
+
+void
+support_random_rseed (support_random_state *state)
+{
+  unsigned short int buf[3];
+  size_t len = sizeof buf;
+
+  ssize_t ret = getrandom (buf, len, 0);
+  if (ret != len)
+    {
+      int fd = xopen ("/dev/urandom", O_RDONLY, 0);
+      uintptr_t pbuf = (uintptr_t) buf;
+      uintptr_t pend = pbuf + len;
+      while (pbuf < pend)
+	{
+	  ret = read (fd, buf, pend - pbuf);
+	  if (ret <= 0)
+	    FAIL_EXIT1 ("read %zu bytes from /dev/urandom failed: %m",
+			pend - pbuf);
+          pbuf += ret;
+	}
+      close (fd);
+    }
+
+  seed48_r (buf, state);
+}
+
+uint32_t
+support_random_u32 (support_random_state *state)
+{
+  long int rl;
+  mrand48_r (state, &rl);
+  return rl;
+}
+
+void
+support_random_buf (support_random_state *state, void *buf, size_t nbytes)
+{
+  size_t nw = nbytes / sizeof (uint32_t);
+  for (size_t i = 0; i < nw; i++)
+    {
+      uint32_t r = support_random_u32 (state);
+      memcpy (buf, &r, sizeof (uint32_t));
+      buf = (void*)((uintptr_t)buf + sizeof (uint32_t));
+    }
+
+  size_t nb = nbytes % sizeof (uint32_t);
+  if (nb != 0)
+    {
+      uint32_t r = support_random_u32 (state);
+      memcpy (buf, &r, nb);
+    }
+}
diff --git a/support/support_random.h b/support/support_random.h
new file mode 100644
index 0000000000..8224c2b774
--- /dev/null
+++ b/support/support_random.h
@@ -0,0 +1,59 @@ 
+/* Function for pseudo-random number generation.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef SUPPORT_MT_RAND_H
+#define SUPPORT_MT_RAND_H
+
+#include <stdint.h>
+#include <stdlib.h>
+
+typedef struct drand48_data support_random_state;
+
+void support_random_seed (support_random_state *state, uint32_t seed);
+void support_random_rseed (support_random_state *state);
+
+uint32_t support_random_u32 (support_random_state *state);
+void support_random_buf (support_random_state *state, void *buf,
+			 size_t nbytes);
+
+/* Scales the number NUMBER to the uniformly distributed closed internal
+   [min, max].  */
+static inline uint32_t
+support_random_uniform_distribution (support_random_state *state,
+				     uint32_t min, uint32_t max)
+{
+  uint32_t ret;
+  uint32_t range = max - min;
+  /* It assumes the input random number RANDOM range is as larger or equal
+     than the RANGE, so the result will either returned or downscaled.  */
+  if (range != UINT32_MAX)
+    {
+      uint32_t urange = range + 1;  /* range can be 0.  */
+      uint32_t scaling = UINT32_MAX / urange;
+      uint32_t past = urange * scaling;
+      do
+        ret = support_random_u32 (state);
+      while (ret >= past);
+      ret /= scaling;
+    }
+  else
+    ret = support_random_u32 (state);
+  return ret + min;
+}
+
+#endif