Create keccak.c
This commit is contained in:
parent
0087b2e078
commit
6dfa612d24
|
@ -0,0 +1,430 @@
|
|||
/*
|
||||
* An implementation of the SHA3 (Keccak) hash function family.
|
||||
*
|
||||
* Algorithm specifications: http://keccak.noekeon.org/
|
||||
* NIST Announcement:
|
||||
* http://csrc.nist.gov/groups/ST/hash/sha-3/winner_sha-3.html
|
||||
*
|
||||
* Written in 2013 by Fabrizio Tarizzo <fabrizio@fabriziotarizzo.org>
|
||||
*
|
||||
* ===================================================================
|
||||
* The contents of this file are dedicated to the public domain. To
|
||||
* the extent that dedication to the public domain is not available,
|
||||
* everyone is granted a worldwide, perpetual, royalty-free,
|
||||
* non-exclusive license to exercise all rights associated with the
|
||||
* contents of this file for any purpose whatsoever.
|
||||
* No rights are reserved.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
* ===================================================================
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "common.h"
|
||||
#include "endianess.h"
|
||||
|
||||
FAKE_INIT(keccak)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint64_t state[25];
|
||||
|
||||
/* The buffer is as long as the state,
|
||||
* but only 'rate' bytes will be used.
|
||||
*/
|
||||
uint8_t buf[200];
|
||||
|
||||
/* When absorbing, this is the number of bytes in buf that
|
||||
* are coming from the message and outstanding.
|
||||
* When squeezing, this is the remaining number of bytes
|
||||
* that can be used as digest.
|
||||
*/
|
||||
unsigned valid_bytes;
|
||||
|
||||
/* All values in bytes */
|
||||
unsigned capacity;
|
||||
unsigned rate;
|
||||
|
||||
uint8_t squeezing;
|
||||
uint8_t padding;
|
||||
} keccak_state;
|
||||
|
||||
#undef ROL64
|
||||
#define ROL64(x,y) ((((x) << (y)) | (x) >> (64-(y))) & 0xFFFFFFFFFFFFFFFFULL)
|
||||
|
||||
static void keccak_function (uint64_t *state);
|
||||
|
||||
static void keccak_absorb_internal (keccak_state *self)
|
||||
{
|
||||
unsigned i,j;
|
||||
uint64_t d;
|
||||
|
||||
for (i=j=0; j < self->rate; ++i, j += 8) {
|
||||
d = LOAD_U64_LITTLE(self->buf + j);
|
||||
self->state[i] ^= d;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
keccak_squeeze_internal (keccak_state *self)
|
||||
{
|
||||
unsigned i, j;
|
||||
|
||||
for (i=j=0; j < self->rate; ++i, j += 8) {
|
||||
STORE_U64_LITTLE(self->buf+j, self->state[i]);
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYM int keccak_init (keccak_state **state,
|
||||
size_t capacity_bytes,
|
||||
uint8_t padding)
|
||||
{
|
||||
keccak_state *ks;
|
||||
|
||||
if (NULL == state) {
|
||||
return ERR_NULL;
|
||||
}
|
||||
|
||||
*state = ks = (keccak_state*) calloc(1, sizeof(keccak_state));
|
||||
if (NULL == ks)
|
||||
return ERR_MEMORY;
|
||||
|
||||
if (capacity_bytes >= 200)
|
||||
return ERR_DIGEST_SIZE;
|
||||
|
||||
ks->capacity = (unsigned)capacity_bytes;
|
||||
|
||||
ks->rate = 200 - ks->capacity;
|
||||
|
||||
ks->squeezing = 0;
|
||||
ks->padding = padding;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYM int keccak_destroy(keccak_state *state)
|
||||
{
|
||||
free(state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYM int keccak_absorb (keccak_state *self,
|
||||
const uint8_t *in,
|
||||
size_t length)
|
||||
{
|
||||
if (NULL==self || NULL==in)
|
||||
return ERR_NULL;
|
||||
|
||||
if (self->squeezing != 0)
|
||||
return ERR_UNKNOWN;
|
||||
|
||||
while (length > 0) {
|
||||
unsigned tc;
|
||||
unsigned left;
|
||||
|
||||
left = self->rate - self->valid_bytes;
|
||||
tc = (unsigned) MIN(length, left);
|
||||
memcpy(self->buf + self->valid_bytes, in, tc);
|
||||
|
||||
self->valid_bytes += tc;
|
||||
in += tc;
|
||||
length -= tc;
|
||||
|
||||
if (self->valid_bytes == self->rate) {
|
||||
keccak_absorb_internal (self);
|
||||
keccak_function (self->state);
|
||||
self->valid_bytes = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void keccak_finish (keccak_state *self)
|
||||
{
|
||||
assert(self->squeezing == 0);
|
||||
assert(self->valid_bytes < self->rate);
|
||||
|
||||
/* Padding */
|
||||
memset(self->buf + self->valid_bytes, 0, self->rate - self->valid_bytes);
|
||||
self->buf[self->valid_bytes] = self->padding;
|
||||
self->buf[self->rate-1] |= 0x80;
|
||||
|
||||
/* Final absorb */
|
||||
keccak_absorb_internal (self);
|
||||
keccak_function (self->state);
|
||||
|
||||
/* First squeeze */
|
||||
self->squeezing = 1;
|
||||
keccak_squeeze_internal (self);
|
||||
self->valid_bytes = self->rate;
|
||||
}
|
||||
|
||||
EXPORT_SYM int keccak_squeeze (keccak_state *self, uint8_t *out, size_t length)
|
||||
{
|
||||
if ((NULL == self) || (NULL == out))
|
||||
return ERR_NULL;
|
||||
|
||||
if (self->squeezing == 0) {
|
||||
keccak_finish (self);
|
||||
}
|
||||
|
||||
assert(self->squeezing == 1);
|
||||
assert(self->valid_bytes > 0);
|
||||
assert(self->valid_bytes <= self->rate);
|
||||
|
||||
while (length > 0) {
|
||||
unsigned tc;
|
||||
|
||||
tc = (unsigned)MIN(self->valid_bytes, length);
|
||||
memcpy(out, self->buf + (self->rate - self->valid_bytes), tc);
|
||||
|
||||
self->valid_bytes -= tc;
|
||||
out += tc;
|
||||
length -= tc;
|
||||
|
||||
if (self->valid_bytes == 0) {
|
||||
keccak_function (self->state);
|
||||
keccak_squeeze_internal (self);
|
||||
self->valid_bytes = self->rate;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYM int keccak_digest(keccak_state *state, uint8_t *digest, size_t len)
|
||||
{
|
||||
keccak_state tmp;
|
||||
|
||||
if ((NULL==state) || (NULL==digest))
|
||||
return ERR_NULL;
|
||||
|
||||
if (2*len != state->capacity)
|
||||
return ERR_UNKNOWN;
|
||||
|
||||
tmp = *state;
|
||||
return keccak_squeeze(&tmp, digest, len);
|
||||
}
|
||||
|
||||
EXPORT_SYM int keccak_copy(const keccak_state *src, keccak_state *dst)
|
||||
{
|
||||
if (NULL == src || NULL == dst) {
|
||||
return ERR_NULL;
|
||||
}
|
||||
|
||||
*dst = *src;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Keccak core function */
|
||||
|
||||
#define KECCAK_ROUNDS 24
|
||||
|
||||
#define ROT_01 36
|
||||
#define ROT_02 3
|
||||
#define ROT_03 41
|
||||
#define ROT_04 18
|
||||
#define ROT_05 1
|
||||
#define ROT_06 44
|
||||
#define ROT_07 10
|
||||
#define ROT_08 45
|
||||
#define ROT_09 2
|
||||
#define ROT_10 62
|
||||
#define ROT_11 6
|
||||
#define ROT_12 43
|
||||
#define ROT_13 15
|
||||
#define ROT_14 61
|
||||
#define ROT_15 28
|
||||
#define ROT_16 55
|
||||
#define ROT_17 25
|
||||
#define ROT_18 21
|
||||
#define ROT_19 56
|
||||
#define ROT_20 27
|
||||
#define ROT_21 20
|
||||
#define ROT_22 39
|
||||
#define ROT_23 8
|
||||
#define ROT_24 14
|
||||
|
||||
static const uint64_t roundconstants[KECCAK_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
|
||||
};
|
||||
|
||||
void keccak_function (uint64_t *state)
|
||||
{
|
||||
short i;
|
||||
|
||||
/* Temporary variables to avoid indexing overhead */
|
||||
uint64_t a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12;
|
||||
uint64_t a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24;
|
||||
|
||||
uint64_t b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12;
|
||||
uint64_t b13, b14, b15, b16, b17, b18, b19, b20, b21, b22, b23, b24;
|
||||
|
||||
uint64_t c0, c1, c2, c3, c4, d;
|
||||
|
||||
a0 = state[0];
|
||||
a1 = state[1];
|
||||
a2 = state[2];
|
||||
a3 = state[3];
|
||||
a4 = state[4];
|
||||
a5 = state[5];
|
||||
a6 = state[6];
|
||||
a7 = state[7];
|
||||
a8 = state[8];
|
||||
a9 = state[9];
|
||||
a10 = state[10];
|
||||
a11 = state[11];
|
||||
a12 = state[12];
|
||||
a13 = state[13];
|
||||
a14 = state[14];
|
||||
a15 = state[15];
|
||||
a16 = state[16];
|
||||
a17 = state[17];
|
||||
a18 = state[18];
|
||||
a19 = state[19];
|
||||
a20 = state[20];
|
||||
a21 = state[21];
|
||||
a22 = state[22];
|
||||
a23 = state[23];
|
||||
a24 = state[24];
|
||||
|
||||
for (i = 0; i < KECCAK_ROUNDS; ++i) {
|
||||
/*
|
||||
Uses temporary variables and loop unrolling to
|
||||
avoid array indexing and inner loops overhead
|
||||
*/
|
||||
|
||||
/* Prepare column parity for Theta step */
|
||||
c0 = a0 ^ a5 ^ a10 ^ a15 ^ a20;
|
||||
c1 = a1 ^ a6 ^ a11 ^ a16 ^ a21;
|
||||
c2 = a2 ^ a7 ^ a12 ^ a17 ^ a22;
|
||||
c3 = a3 ^ a8 ^ a13 ^ a18 ^ a23;
|
||||
c4 = a4 ^ a9 ^ a14 ^ a19 ^ a24;
|
||||
|
||||
/* Theta + Rho + Pi steps */
|
||||
d = c4 ^ ROL64(c1, 1);
|
||||
b0 = d ^ a0;
|
||||
b16 = ROL64(d ^ a5, ROT_01);
|
||||
b7 = ROL64(d ^ a10, ROT_02);
|
||||
b23 = ROL64(d ^ a15, ROT_03);
|
||||
b14 = ROL64(d ^ a20, ROT_04);
|
||||
|
||||
d = c0 ^ ROL64(c2, 1);
|
||||
b10 = ROL64(d ^ a1, ROT_05);
|
||||
b1 = ROL64(d ^ a6, ROT_06);
|
||||
b17 = ROL64(d ^ a11, ROT_07);
|
||||
b8 = ROL64(d ^ a16, ROT_08);
|
||||
b24 = ROL64(d ^ a21, ROT_09);
|
||||
|
||||
d = c1 ^ ROL64(c3, 1);
|
||||
b20 = ROL64(d ^ a2, ROT_10);
|
||||
b11 = ROL64(d ^ a7, ROT_11);
|
||||
b2 = ROL64(d ^ a12, ROT_12);
|
||||
b18 = ROL64(d ^ a17, ROT_13);
|
||||
b9 = ROL64(d ^ a22, ROT_14);
|
||||
|
||||
d = c2 ^ ROL64(c4, 1);
|
||||
b5 = ROL64(d ^ a3, ROT_15);
|
||||
b21 = ROL64(d ^ a8, ROT_16);
|
||||
b12 = ROL64(d ^ a13, ROT_17);
|
||||
b3 = ROL64(d ^ a18, ROT_18);
|
||||
b19 = ROL64(d ^ a23, ROT_19);
|
||||
|
||||
d = c3 ^ ROL64(c0, 1);
|
||||
b15 = ROL64(d ^ a4, ROT_20);
|
||||
b6 = ROL64(d ^ a9, ROT_21);
|
||||
b22 = ROL64(d ^ a14, ROT_22);
|
||||
b13 = ROL64(d ^ a19, ROT_23);
|
||||
b4 = ROL64(d ^ a24, ROT_24);
|
||||
|
||||
/* Chi + Iota steps */
|
||||
a0 = b0 ^ (~b1 & b2) ^ roundconstants[i];
|
||||
a1 = b1 ^ (~b2 & b3);
|
||||
a2 = b2 ^ (~b3 & b4);
|
||||
a3 = b3 ^ (~b4 & b0);
|
||||
a4 = b4 ^ (~b0 & b1);
|
||||
|
||||
a5 = b5 ^ (~b6 & b7);
|
||||
a6 = b6 ^ (~b7 & b8);
|
||||
a7 = b7 ^ (~b8 & b9);
|
||||
a8 = b8 ^ (~b9 & b5);
|
||||
a9 = b9 ^ (~b5 & b6);
|
||||
|
||||
a10 = b10 ^ (~b11 & b12);
|
||||
a11 = b11 ^ (~b12 & b13);
|
||||
a12 = b12 ^ (~b13 & b14);
|
||||
a13 = b13 ^ (~b14 & b10);
|
||||
a14 = b14 ^ (~b10 & b11);
|
||||
|
||||
a15 = b15 ^ (~b16 & b17);
|
||||
a16 = b16 ^ (~b17 & b18);
|
||||
a17 = b17 ^ (~b18 & b19);
|
||||
a18 = b18 ^ (~b19 & b15);
|
||||
a19 = b19 ^ (~b15 & b16);
|
||||
|
||||
a20 = b20 ^ (~b21 & b22);
|
||||
a21 = b21 ^ (~b22 & b23);
|
||||
a22 = b22 ^ (~b23 & b24);
|
||||
a23 = b23 ^ (~b24 & b20);
|
||||
a24 = b24 ^ (~b20 & b21);
|
||||
}
|
||||
|
||||
state[0] = a0;
|
||||
state[1] = a1;
|
||||
state[2] = a2;
|
||||
state[3] = a3;
|
||||
state[4] = a4;
|
||||
state[5] = a5;
|
||||
state[6] = a6;
|
||||
state[7] = a7;
|
||||
state[8] = a8;
|
||||
state[9] = a9;
|
||||
state[10] = a10;
|
||||
state[11] = a11;
|
||||
state[12] = a12;
|
||||
state[13] = a13;
|
||||
state[14] = a14;
|
||||
state[15] = a15;
|
||||
state[16] = a16;
|
||||
state[17] = a17;
|
||||
state[18] = a18;
|
||||
state[19] = a19;
|
||||
state[20] = a20;
|
||||
state[21] = a21;
|
||||
state[22] = a22;
|
||||
state[23] = a23;
|
||||
state[24] = a24;
|
||||
}
|
||||
|
Loading…
Reference in New Issue