[hackers] [sbase] libutil: add random.c || Elie Le Vaillant

From: <git_AT_suckless.org>
Date: Thu, 19 Dec 2024 12:34:52 +0100 (CET)

commit 2677235ed7f86f26c817ca5eca7c730f2418638a
Author: Elie Le Vaillant <eolien55_AT_disroot.org>
AuthorDate: Fri Dec 6 10:37:35 2024 +0100
Commit: Roberto E. Vargas Caballero <k0ga_AT_shike2.com>
CommitDate: Thu Dec 19 12:28:05 2024 +0100

    libutil: add random.c
    
    Some programs need a good PRNG, such as shuf(1), or cron(1). This adds
    to libutil a random_uniform function which simply solves the problem of
    creating integers uniformly in a range. random_seed seeds the
    generator. arc4random would probably be a better PRNG than random, but
    it is less portable unfortunately.

diff --git a/Makefile b/Makefile
index e3b6936..8b2728c 100644
--- a/Makefile
+++ b/Makefile
_AT_@ -86,6 +86,7 @@ LIBUTILOBJ =\
         libutil/strsep.o\
         libutil/strnsubst.o\
         libutil/strtonum.o\
+ libutil/random.o\
         libutil/unescape.o\
         libutil/writeall.o
 
diff --git a/libutil/random.c b/libutil/random.c
new file mode 100644
index 0000000..48eeb79
--- /dev/null
+++ b/libutil/random.c
_AT_@ -0,0 +1,46 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <time.h>
+
+/*
+ * Uniformity is achieved by generating new random numbers until the one
+ * returned is outside the range [0, 2**32 % upper_bound). This
+ * guarantees the selected random number will be inside
+ * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
+ * after reduction modulo upper_bound.
+ *
+ * Copied off OpenBSD (original is arc4random_uniform)
+ */
+uint32_t
+random_uniform(uint32_t upper_bound)
+{
+ uint32_t r, min;
+
+ if (upper_bound < 2)
+ return 0;
+
+ /* 2**32 % x == (2**32 - x) % x */
+ min = -upper_bound % upper_bound;
+
+ /*
+ * This could theoretically loop forever but each retry has
+ * p > 0.5 (worst case, usually far better) of selecting a
+ * number inside the range we need, so it should rarely need
+ * to re-roll.
+ */
+ for (;;) {
+ r = random(); /* arc4random() is better, but we don't always have it */
+ if (r >= min)
+ break;
+ }
+
+ return r % upper_bound;
+}
+
+void
+random_seed(void)
+{
+ struct timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ srandom(ts.tv_nsec); /* not a good source of randomness, but eh */
+}
Received on Thu Dec 19 2024 - 12:34:52 CET

This archive was generated by hypermail 2.3.0 : Thu Dec 19 2024 - 12:36:44 CET