mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 1/4] lib: random: implement Xorshift* RNG
@ 2025-04-17  6:58 Ahmad Fatoum
  2025-04-17  6:58 ` [PATCH 2/4] clock: always seed Xorshift* from clocksource on startup Ahmad Fatoum
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Ahmad Fatoum @ 2025-04-17  6:58 UTC (permalink / raw)
  To: barebox; +Cc: Ahmad Fatoum

Xorshift is simpler, faster and better than the LCG we are currently
using. Add it in preparation alongside the LCG until consumers are
migrated.

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
 include/stdlib.h | 15 ++++++++
 lib/random.c     | 92 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 107 insertions(+)

diff --git a/include/stdlib.h b/include/stdlib.h
index 20bdc0491e3c..12a81cfc31a3 100644
--- a/include/stdlib.h
+++ b/include/stdlib.h
@@ -18,10 +18,25 @@ struct hwrng;
 
 /* fill a buffer with pseudo-random data */
 #if IN_PROPER
+void randbuf_r(u64 *x, void *buf, size_t len);
+void srand_xor(u64 entropy);
+void get_noncrypto_bytes(void *buf, size_t len);
 void get_random_bytes(void *buf, int len);
 int get_crypto_bytes(void *buf, int len);
 int hwrng_get_crypto_bytes(struct hwrng *rng, void *buf, int len);
 #else
+static inline void randbuf_r(u64 *x, void *buf, size_t len)
+{
+	BUG();
+}
+static inline void srand_xor(u64 entropy)
+{
+	BUG();
+}
+static inline void get_noncrypto_bytes(void *buf, size_t len)
+{
+	BUG();
+}
 static inline void get_random_bytes(void *buf, int len)
 {
 	BUG();
diff --git a/lib/random.c b/lib/random.c
index e83935d0e17c..fc4ecdfd3a1d 100644
--- a/lib/random.c
+++ b/lib/random.c
@@ -1,4 +1,15 @@
 // SPDX-License-Identifier: GPL-2.0-only
+/*
+ * The barebox random number generator provides mainly two APIs:
+ *
+ *   - get_noncrypto_bytes: Xorshift*
+ *     - https://en.wikipedia.org/wiki/Xorshift#xorshift*)
+ *     - https://forum.pjrc.com/index.php?threads/teensy-4-1-random-number-generator.61125/#post-243895
+ *
+ *   - get_crypto_bytes: Randomness directly from a HWRNG.
+ *     PRNG fallback only possible with debugging option
+ *     CONFIG_ALLOW_PRNG_FALLBACK set, which will emit a warning at runtime.
+ */
 
 #include <common.h>
 #include <stdlib.h>
@@ -21,6 +32,87 @@ void srand(unsigned int seed)
 	random_seed = seed;
 }
 
+static u64 prng_state = 1;
+
+/**
+ * rand_r - return next pseudo-random number depending only on input
+ *
+ * @x: RNG state
+ *
+ * This function runs the Xorshift* algorithm on the state input,
+ * updates the state and returns the next number in the PRNG
+ * sequence.
+ *
+ * Return: a 32 bit pseudo-random number
+ */
+static u32 rand_r(u64 *x)
+{
+	*x ^= *x >> 12;
+	*x ^= *x << 25;
+	*x ^= *x >> 27;
+
+	/*
+	 * Xorshift* fails only the MatrixRank test of BigCrush, however if the
+	 * generator is modified to return only the high 32 bits, then it passes
+	 * BigCrush with zero failures
+	 */
+	return (*x * 0x2545F4914F6CDD1DULL) >> 32;
+}
+
+/**
+ * randbuf_r - fills pseudo-random numbers into buffer depending only on input
+ *
+ * @x:   RNG state
+ * @buf: buffer to fill
+ * @len: size of buffer
+ *
+ * This function runs the Xorshift* algorithm on the state input,
+ * updates the state and fills the buffer with pseudo-random numbers.
+ *
+ * Only use this when you are using a fixed seed and the sequence
+ * should be reproducible (e.g. for NAND test).
+ */
+void randbuf_r(u64 *x, void *buf, size_t len)
+{
+	for (size_t i = 0; i < len; i += 4) {
+		u32 val = rand_r(x);
+		memcpy(buf + i, &val, min_t(size_t, 4, len - i));
+	}
+}
+
+/**
+ * srand_xor - Xor a 64-bit into the existing RNG state
+ *
+ * @entropy: additional 64-bit of entropy
+ *
+ * This function mixes 64-bit of entropy into the exising
+ * state by means of an Xor operation.
+ *
+ * Only use for independent entropy sources.
+ */
+void srand_xor(u64 entropy)
+{
+	prng_state ^= entropy;
+	/* Ensure prng_state is never zero */
+	prng_state += !prng_state;
+	rand_r(&prng_state);
+}
+
+/**
+ * get_noncrypto_bytes - get pseudo random numbers.
+ *
+ * @buf: buffer to fill
+ * @len: length of buffer
+ *
+ * This interface can be good enough to generate MAC address
+ * or use for NAND test. Use get_crypto_bytes for cryptographic
+ * applications.
+ */
+void get_noncrypto_bytes(void *buf, size_t len)
+{
+	randbuf_r(&prng_state, buf, len);
+}
+
 /**
  * get_random_bytes - get pseudo random numbers.
  * This interface can be good enough to generate MAC address
-- 
2.39.5




^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2025-04-22 10:07 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-04-17  6:58 [PATCH 1/4] lib: random: implement Xorshift* RNG Ahmad Fatoum
2025-04-17  6:58 ` [PATCH 2/4] clock: always seed Xorshift* from clocksource on startup Ahmad Fatoum
2025-04-17  6:58 ` [PATCH 3/4] random: replace all rand/srand API with Xorshift Ahmad Fatoum
2025-04-17  6:58 ` [PATCH 4/4] random: replace get_random_bytes with get_noncrypto_bytes Ahmad Fatoum
2025-04-22  8:54 ` [PATCH 1/4] lib: random: implement Xorshift* RNG Sascha Hauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox