aboutsummaryrefslogtreecommitdiffstats
path: root/original.c
blob: 32be34884908b0c8f5a495295c0a8c6057d0cb18 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <linux/kernel.h>

enum poolinfo {
	POOL_WORDS = 128,
	POOL_WORDMASK = POOL_WORDS - 1,
	POOL_BITS = POOL_WORDS * sizeof(u32) * 8,

	/* x^128 + x^104 + x^76 + x^51 +x^25 + x + 1 */
	POOL_TAP1 = 104,
	POOL_TAP2 = 76,
	POOL_TAP3 = 51,
	POOL_TAP4 = 25,
	POOL_TAP5 = 1,
};

static u32 input_pool_data[POOL_WORDS];

static struct {
	u16 add_ptr;
	u16 input_rotate;
} input_pool = { 0 };

static const u32 twist_table[8] = {
	0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158,
	0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278
};

void mix_original(const void *in, int nbytes)
{
	unsigned long i;
	int input_rotate;
	const u8 *bytes = in;
	u32 w;

	input_rotate = input_pool.input_rotate;
	i = input_pool.add_ptr;

	/* mix one byte at a time to simplify size handling and churn faster */
	while (nbytes--) {
		w = rol32(*bytes++, input_rotate);
		i = (i - 1) & POOL_WORDMASK;

		/* XOR in the various taps */
		w ^= input_pool_data[i];
		w ^= input_pool_data[(i + POOL_TAP1) & POOL_WORDMASK];
		w ^= input_pool_data[(i + POOL_TAP2) & POOL_WORDMASK];
		w ^= input_pool_data[(i + POOL_TAP3) & POOL_WORDMASK];
		w ^= input_pool_data[(i + POOL_TAP4) & POOL_WORDMASK];
		w ^= input_pool_data[(i + POOL_TAP5) & POOL_WORDMASK];

		/* Mix the result back in with a twist */
		input_pool_data[i] = (w >> 3) ^ twist_table[w & 7];

		/*
		 * Normally, we add 7 bits of rotation to the pool.
		 * At the beginning of the pool, add an extra 7 bits
		 * rotation, so that successive passes spread the
		 * input bits across the pool evenly.
		 */
		input_rotate = (input_rotate + (i ? 7 : 14)) & 31;
	}

	input_pool.input_rotate = input_rotate;
	input_pool.add_ptr = i;
}