mail archive of the barebox mailing list
 help / color / mirror / Atom feed
From: Ahmad Fatoum <a.fatoum@pengutronix.de>
To: barebox@lists.infradead.org
Cc: Ahmad Fatoum <a.fatoum@pengutronix.de>
Subject: [PATCH 1/4] lib: random: implement Xorshift* RNG
Date: Thu, 17 Apr 2025 08:58:43 +0200	[thread overview]
Message-ID: <20250417065846.3562848-1-a.fatoum@pengutronix.de> (raw)

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




             reply	other threads:[~2025-04-17  7:06 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-04-17  6:58 Ahmad Fatoum [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250417065846.3562848-1-a.fatoum@pengutronix.de \
    --to=a.fatoum@pengutronix.de \
    --cc=barebox@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox