aboutsummaryrefslogtreecommitdiffstats
path: root/k12f1600.c
blob: 26d974babdd2866c4ce40d217a6f73390a93a511 (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
#include <linux/kernel.h>
#include <crypto/algapi.h>

enum poolinfo {
	POOL_BITS = 512,
	POOL_BYTES = POOL_BITS / 8
};

static const u64 keccak_round_constants[12] = {
	0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL, 0x8000000080008000ULL,
	0x000000000000808bULL, 0x0000000080000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL,
	0x000000000000008aULL, 0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL
};

static const int keccak_rotations[5][5] = {
	{ 0,  1,  62, 28, 27 }, { 36, 44, 6,  55, 20 }, { 3,  10, 43, 25, 39 },
	{ 41, 45, 15, 21, 8  }, { 18, 2,  61, 56, 14 }
};

static void keccak(u64 A[5][5])
{
	u64 B[5][5], C[5];
	int r, x, y;

#define N5(N, expr) N = 0, expr; N = 1, expr; N = 2, expr; N = 3, expr; N = 4, expr;

	for (r = 0; r < 12; ++r) {
		N5(x, C[x] = A[0][x] ^ A[1][x] ^ A[2][x] ^ A[3][x] ^ A[4][x]);
		N5(x, N5(y, A[y][x] ^= C[(x + 4) % 5] ^ rol64(C[(x + 1) % 5], 1)));
		N5(x, N5(y, B[(2 * x + 3 * y) % 5][y] = rol64(A[y][x], keccak_rotations[y][x])));
		N5(x, N5(y, A[y][x] = B[y][x] ^ (~B[y][(x + 1) % 5] & B[y][(x + 2) % 5])));
		A[0][0] ^= keccak_round_constants[r];
	}
}

static u64 state[5][5];
static int idx;

void mix_k12f1600(const void *in, int nbytes)
{
	const u8 *src = in;
	u8 *dst = (u8 *)state;

	while (nbytes) {
		size_t l = min_t(size_t, nbytes, sizeof(state) - POOL_BYTES - idx);
		if (!l) {
			keccak(state);
			idx = 0;
			continue;
		}
		crypto_xor(&dst[idx], src, l);
		nbytes -= l, src += l, idx += l;
	}
}