#include <assert.h>
#include <string.h>
#include "sha3-nettle-impl.h"
#include "sha3-nettle-impl-le.h"
#include "sha3-nettle-impl-memxor.h"
int sha3_init(sha3_ctx_t *c, int mdlen)
{
memset(c, 0, offsetof (sha3_ctx_t, block));
c->mdlen = mdlen;
c->blksize = 200 - 2 * mdlen;
return 1;
}
int sha3_update(sha3_ctx_t *c, const void *data, size_t len)
{
c->index = _sha3_update (&c->state, c->blksize, c->block, c->index, len, data);
return 1;
}
int sha3_final(void *md, sha3_ctx_t *c)
{
_sha3_pad (&c->state, c->blksize, c->block, c->index);
_nettle_write_le64 (c->mdlen, md, c->state.a);
return 1;
}
void *sha3(const void *in, size_t inlen, void *md, int mdlen)
{
sha3_ctx_t sha3;
sha3_init(&sha3, mdlen);
sha3_update(&sha3, in, inlen);
sha3_final(md, &sha3);
return md;
}
static void
sha3_absorb (struct sha3_state *state, unsigned length, const uint8_t *data)
{
assert ( (length & 7) == 0);
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
{
uint64_t *p;
for (p = state->a; length > 0; p++, length -= 8, data += 8)
*p ^= LE_READ_UINT64 (data);
}
#else /* !WORDS_BIGENDIAN */
memxor (state->a, data, length);
#endif
sha3_permute (state);
}
unsigned
_sha3_update (struct sha3_state *state,
unsigned block_size, uint8_t *block,
unsigned pos,
size_t length, const uint8_t *data)
{
if (pos > 0)
{
unsigned left = block_size - pos;
if (length < left)
{
memcpy (block + pos, data, length);
return pos + length;
}
else
{
memcpy (block + pos, data, left);
data += left;
length -= left;
sha3_absorb (state, block_size, block);
}
}
for (; length >= block_size; length -= block_size, data += block_size)
sha3_absorb (state, block_size, data);
memcpy (block, data, length);
return length;
}
void
_sha3_pad (struct sha3_state *state,
unsigned block_size, uint8_t *block, unsigned pos)
{
assert (pos < block_size);
block[pos++] = 6;
memset (block + pos, 0, block_size - pos);
block[block_size - 1] |= 0x80;
sha3_absorb (state, block_size, block);
}
void
sha3_permute (struct sha3_state *state)
{
static const uint64_t rc[SHA3_ROUNDS] = {
0x0000000000000001ULL, 0X0000000000008082ULL,
0X800000000000808AULL, 0X8000000080008000ULL,
0X000000000000808BULL, 0X0000000080000001ULL,
0X8000000080008081ULL, 0X8000000000008009ULL,
0X000000000000008AULL, 0X0000000000000088ULL,
0X0000000080008009ULL, 0X000000008000000AULL,
0X000000008000808BULL, 0X800000000000008BULL,
0X8000000000008089ULL, 0X8000000000008003ULL,
0X8000000000008002ULL, 0X8000000000000080ULL,
0X000000000000800AULL, 0X800000008000000AULL,
0X8000000080008081ULL, 0X8000000000008080ULL,
0X0000000080000001ULL, 0X8000000080008008ULL,
};
/* Original permutation:
0,10,20, 5,15,
16, 1,11,21, 6,
7,17, 2,12,22,
23, 8,18, 3,13,
14,24, 9,19, 4
Rotation counts:
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,
*/
/* In-place implementation. Permutation done as a long sequence of
25 moves "following" the permutation.
T <-- 1
1 <-- 6
6 <-- 9
9 <-- 22
22 <-- 14
14 <-- 20
20 <-- 2
2 <-- 12
12 <-- 13
13 <-- 19
19 <-- 23
23 <-- 15
15 <-- 4
4 <-- 24
24 <-- 21
21 <-- 8
8 <-- 16
16 <-- 5
5 <-- 3
3 <-- 18
18 <-- 17
17 <-- 11
11 <-- 7
7 <-- 10
10 <-- T
*/
uint64_t C[5], D[5], T, X;
unsigned i, y;
#define A state->a
C[0] = A[0] ^ A[5+0] ^ A[10+0] ^ A[15+0] ^ A[20+0];
C[1] = A[1] ^ A[5+1] ^ A[10+1] ^ A[15+1] ^ A[20+1];
C[2] = A[2] ^ A[5+2] ^ A[10+2] ^ A[15+2] ^ A[20+2];
C[3] = A[3] ^ A[5+3] ^ A[10+3] ^ A[15+3] ^ A[20+3];
C[4] = A[4] ^ A[5+4] ^ A[10+4] ^ A[15+4] ^ A[20+4];
for (i = 0; i < SHA3_ROUNDS; i++)
{
D[0] = C[4] ^ ROTL64(1, C[1]);
D[1] = C[0] ^ ROTL64(1, C[2]);
D[2] = C[1] ^ ROTL64(1, C[3]);
D[3] = C[2] ^ ROTL64(1, C[4]);
D[4] = C[3] ^ ROTL64(1, C[0]);
A[0] ^= D[0];
X = A[ 1] ^ D[1]; T = ROTL64(1, X);
X = A[ 6] ^ D[1]; A[ 1] = ROTL64 (44, X);
X = A[ 9] ^ D[4]; A[ 6] = ROTL64 (20, X);
X = A[22] ^ D[2]; A[ 9] = ROTL64 (61, X);
X = A[14] ^ D[4]; A[22] = ROTL64 (39, X);
X = A[20] ^ D[0]; A[14] = ROTL64 (18, X);
X = A[ 2] ^ D[2]; A[20] = ROTL64 (62, X);
X = A[12] ^ D[2]; A[ 2] = ROTL64 (43, X);
X = A[13] ^ D[3]; A[12] = ROTL64 (25, X);
X = A[19] ^ D[4]; A[13] = ROTL64 ( 8, X);
X = A[23] ^ D[3]; A[19] = ROTL64 (56, X);
X = A[15] ^ D[0]; A[23] = ROTL64 (41, X);
X = A[ 4] ^ D[4]; A[15] = ROTL64 (27, X);
X = A[24] ^ D[4]; A[ 4] = ROTL64 (14, X);
X = A[21] ^ D[1]; A[24] = ROTL64 ( 2, X);
X = A[ 8] ^ D[3]; A[21] = ROTL64 (55, X); /* row 4 done */
X = A[16] ^ D[1]; A[ 8] = ROTL64 (45, X);
X = A[ 5] ^ D[0]; A[16] = ROTL64 (36, X);
X = A[ 3] ^ D[3]; A[ 5] = ROTL64 (28, X);
X = A[18] ^ D[3]; A[ 3] = ROTL64 (21, X); /* row 0 done */
X = A[17] ^ D[2]; A[18] = ROTL64 (15, X);
X = A[11] ^ D[1]; A[17] = ROTL64 (10, X); /* row 3 done */
X = A[ 7] ^ D[2]; A[11] = ROTL64 ( 6, X); /* row 1 done */
X = A[10] ^ D[0]; A[ 7] = ROTL64 ( 3, X);
A[10] = T; /* row 2 done */
D[0] = ~A[1] & A[2];
D[1] = ~A[2] & A[3];
D[2] = ~A[3] & A[4];
D[3] = ~A[4] & A[0];
D[4] = ~A[0] & A[1];
A[0] ^= D[0] ^ rc[i]; C[0] = A[0];
A[1] ^= D[1]; C[1] = A[1];
A[2] ^= D[2]; C[2] = A[2];
A[3] ^= D[3]; C[3] = A[3];
A[4] ^= D[4]; C[4] = A[4];
for (y = 5; y < 25; y+= 5)
{
D[0] = ~A[y+1] & A[y+2];
D[1] = ~A[y+2] & A[y+3];
D[2] = ~A[y+3] & A[y+4];
D[3] = ~A[y+4] & A[y+0];
D[4] = ~A[y+0] & A[y+1];
A[y+0] ^= D[0]; C[0] ^= A[y+0];
A[y+1] ^= D[1]; C[1] ^= A[y+1];
A[y+2] ^= D[2]; C[2] ^= A[y+2];
A[y+3] ^= D[3]; C[3] ^= A[y+3];
A[y+4] ^= D[4]; C[4] ^= A[y+4];
}
}
#undef A
}