aboutsummaryrefslogtreecommitdiffstats
path: root/tinylfsr.c
diff options
context:
space:
mode:
Diffstat (limited to 'tinylfsr.c')
-rw-r--r--tinylfsr.c38
1 files changed, 38 insertions, 0 deletions
diff --git a/tinylfsr.c b/tinylfsr.c
new file mode 100644
index 0000000..fcea1a0
--- /dev/null
+++ b/tinylfsr.c
@@ -0,0 +1,38 @@
+#include <linux/kernel.h>
+
+enum poolinfo {
+ POOL_WORDS = 128,
+ POOL_WORDMASK = POOL_WORDS - 1,
+ POOL_BITS = POOL_WORDS * sizeof(u32) * 8,
+};
+
+static u32 input_pool_data[POOL_WORDS];
+
+static struct {
+ u16 add_ptr;
+} input_pool = { 0 };
+
+void mix_tinylfsr(const void *in, int nbytes)
+{
+ unsigned long i = input_pool.add_ptr, next;
+ const u8 *src = in;
+
+ /* Mix one byte at a time to simplify size handling and churn faster. */
+ while (nbytes--) {
+ /* The simplest possible max period LFSR.
+ * This is morally equivalent to evaluating
+ * the input as a polynomial at x^32.
+ *
+ * It can be evaluated in parallel, since i+0
+ * only depends on i+0 and i+1. Thus i+0 depends
+ * on i+0,i+1, i+1 depends on i+1 and i+2,
+ * so we can absorb up to 126 bytes in parallel
+ * if necessary.
+ */
+ next = (i + 1) & POOL_WORDMASK;
+ input_pool_data[i] = *src++ ^ rol32(input_pool_data[i], 9) ^
+ (input_pool_data[next] << 15) ^ (input_pool_data[next] >> 24);
+ i = next;
+ }
+ input_pool.add_ptr = i;
+}