diff options
Diffstat (limited to 'tinylfsr.c')
-rw-r--r-- | tinylfsr.c | 38 |
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; +} |