/* Based on the public domain implementation in crypto_hash/keccakc512/simple/ from * http://bench.cr.yp.to/supercop.html by Ronny Van Keer and the public domain "TweetFips202" * implementation from https://twitter.com/tweetfips202 by Gilles Van Assche, Daniel J. Bernstein, * and Peter Schwabe */ #include #include #include "fips202.h" #define NROUNDS 24 #define ROL(a, offset) ((a << offset) ^ (a >> (64-offset))) /************************************************* * Name: load64 * * Description: Load 8 bytes into uint64_t in little-endian order * * Arguments: - const uint8_t *x: pointer to input byte array * * Returns the loaded 64-bit unsigned integer **************************************************/ static uint64_t load64(const uint8_t x[8]) { unsigned int i; uint64_t r = 0; for(i=0;i<8;i++) r |= (uint64_t)x[i] << 8*i; return r; } /************************************************* * Name: store64 * * Description: Store a 64-bit integer to array of 8 bytes in little-endian order * * Arguments: - uint8_t *x: pointer to the output byte array (allocated) * - uint64_t u: input 64-bit unsigned integer **************************************************/ static void store64(uint8_t x[8], uint64_t u) { unsigned int i; for(i=0;i<8;i++) x[i] = u >> 8*i; } /* Keccak round constants */ static const uint64_t KeccakF_RoundConstants[NROUNDS] = { (uint64_t)0x0000000000000001ULL, (uint64_t)0x0000000000008082ULL, (uint64_t)0x800000000000808aULL, (uint64_t)0x8000000080008000ULL, (uint64_t)0x000000000000808bULL, (uint64_t)0x0000000080000001ULL, (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008009ULL, (uint64_t)0x000000000000008aULL, (uint64_t)0x0000000000000088ULL, (uint64_t)0x0000000080008009ULL, (uint64_t)0x000000008000000aULL, (uint64_t)0x000000008000808bULL, (uint64_t)0x800000000000008bULL, (uint64_t)0x8000000000008089ULL, (uint64_t)0x8000000000008003ULL, (uint64_t)0x8000000000008002ULL, (uint64_t)0x8000000000000080ULL, (uint64_t)0x000000000000800aULL, (uint64_t)0x800000008000000aULL, (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008080ULL, (uint64_t)0x0000000080000001ULL, (uint64_t)0x8000000080008008ULL }; /************************************************* * Name: KeccakF1600_StatePermute * * Description: The Keccak F1600 Permutation * * Arguments: - uint64_t *state: pointer to input/output Keccak state **************************************************/ static void KeccakF1600_StatePermute(uint64_t state[25]) { int round; uint64_t Aba, Abe, Abi, Abo, Abu; uint64_t Aga, Age, Agi, Ago, Agu; uint64_t Aka, Ake, Aki, Ako, Aku; uint64_t Ama, Ame, Ami, Amo, Amu; uint64_t Asa, Ase, Asi, Aso, Asu; uint64_t BCa, BCe, BCi, BCo, BCu; uint64_t Da, De, Di, Do, Du; uint64_t Eba, Ebe, Ebi, Ebo, Ebu; uint64_t Ega, Ege, Egi, Ego, Egu; uint64_t Eka, Eke, Eki, Eko, Eku; uint64_t Ema, Eme, Emi, Emo, Emu; uint64_t Esa, Ese, Esi, Eso, Esu; //copyFromState(A, state) Aba = state[ 0]; Abe = state[ 1]; Abi = state[ 2]; Abo = state[ 3]; Abu = state[ 4]; Aga = state[ 5]; Age = state[ 6]; Agi = state[ 7]; Ago = state[ 8]; Agu = state[ 9]; Aka = state[10]; Ake = state[11]; Aki = state[12]; Ako = state[13]; Aku = state[14]; Ama = state[15]; Ame = state[16]; Ami = state[17]; Amo = state[18]; Amu = state[19]; Asa = state[20]; Ase = state[21]; Asi = state[22]; Aso = state[23]; Asu = state[24]; for(round = 0; round < NROUNDS; round += 2) { // prepareTheta BCa = Aba^Aga^Aka^Ama^Asa; BCe = Abe^Age^Ake^Ame^Ase; BCi = Abi^Agi^Aki^Ami^Asi; BCo = Abo^Ago^Ako^Amo^Aso; BCu = Abu^Agu^Aku^Amu^Asu; //thetaRhoPiChiIotaPrepareTheta(round, A, E) Da = BCu^ROL(BCe, 1); De = BCa^ROL(BCi, 1); Di = BCe^ROL(BCo, 1); Do = BCi^ROL(BCu, 1); Du = BCo^ROL(BCa, 1); Aba ^= Da; BCa = Aba; Age ^= De; BCe = ROL(Age, 44); Aki ^= Di; BCi = ROL(Aki, 43); Amo ^= Do; BCo = ROL(Amo, 21); Asu ^= Du; BCu = ROL(Asu, 14); Eba = BCa ^((~BCe)& BCi ); Eba ^= (uint64_t)KeccakF_RoundConstants[round]; Ebe = BCe ^((~BCi)& BCo ); Ebi = BCi ^((~BCo)& BCu ); Ebo = BCo ^((~BCu)& BCa ); Ebu = BCu ^((~BCa)& BCe ); Abo ^= Do; BCa = ROL(Abo, 28); Agu ^= Du; BCe = ROL(Agu, 20); Aka ^= Da; BCi = ROL(Aka, 3); Ame ^= De; BCo = ROL(Ame, 45); Asi ^= Di; BCu = ROL(Asi, 61); Ega = BCa ^((~BCe)& BCi ); Ege = BCe ^((~BCi)& BCo ); Egi = BCi ^((~BCo)& BCu ); Ego = BCo ^((~BCu)& BCa ); Egu = BCu ^((~BCa)& BCe ); Abe ^= De; BCa = ROL(Abe, 1); Agi ^= Di; BCe = ROL(Agi, 6); Ako ^= Do; BCi = ROL(Ako, 25); Amu ^= Du; BCo = ROL(Amu, 8); Asa ^= Da; BCu = ROL(Asa, 18); Eka = BCa ^((~BCe)& BCi ); Eke = BCe ^((~BCi)& BCo ); Eki = BCi ^((~BCo)& BCu ); Eko = BCo ^((~BCu)& BCa ); Eku = BCu ^((~BCa)& BCe ); Abu ^= Du; BCa = ROL(Abu, 27); Aga ^= Da; BCe = ROL(Aga, 36); Ake ^= De; BCi = ROL(Ake, 10); Ami ^= Di; BCo = ROL(Ami, 15); Aso ^= Do; BCu = ROL(Aso, 56); Ema = BCa ^((~BCe)& BCi ); Eme = BCe ^((~BCi)& BCo ); Emi = BCi ^((~BCo)& BCu ); Emo = BCo ^((~BCu)& BCa ); Emu = BCu ^((~BCa)& BCe ); Abi ^= Di; BCa = ROL(Abi, 62); Ago ^= Do; BCe = ROL(Ago, 55); Aku ^= Du; BCi = ROL(Aku, 39); Ama ^= Da; BCo = ROL(Ama, 41); Ase ^= De; BCu = ROL(Ase, 2); Esa = BCa ^((~BCe)& BCi ); Ese = BCe ^((~BCi)& BCo ); Esi = BCi ^((~BCo)& BCu ); Eso = BCo ^((~BCu)& BCa ); Esu = BCu ^((~BCa)& BCe ); // prepareTheta BCa = Eba^Ega^Eka^Ema^Esa; BCe = Ebe^Ege^Eke^Eme^Ese; BCi = Ebi^Egi^Eki^Emi^Esi; BCo = Ebo^Ego^Eko^Emo^Eso; BCu = Ebu^Egu^Eku^Emu^Esu; //thetaRhoPiChiIotaPrepareTheta(round+1, E, A) Da = BCu^ROL(BCe, 1); De = BCa^ROL(BCi, 1); Di = BCe^ROL(BCo, 1); Do = BCi^ROL(BCu, 1); Du = BCo^ROL(BCa, 1); Eba ^= Da; BCa = Eba; Ege ^= De; BCe = ROL(Ege, 44); Eki ^= Di; BCi = ROL(Eki, 43); Emo ^= Do; BCo = ROL(Emo, 21); Esu ^= Du; BCu = ROL(Esu, 14); Aba = BCa ^((~BCe)& BCi ); Aba ^= (uint64_t)KeccakF_RoundConstants[round+1]; Abe = BCe ^((~BCi)& BCo ); Abi = BCi ^((~BCo)& BCu ); Abo = BCo ^((~BCu)& BCa ); Abu = BCu ^((~BCa)& BCe ); Ebo ^= Do; BCa = ROL(Ebo, 28); Egu ^= Du; BCe = ROL(Egu, 20); Eka ^= Da; BCi = ROL(Eka, 3); Eme ^= De; BCo = ROL(Eme, 45); Esi ^= Di; BCu = ROL(Esi, 61); Aga = BCa ^((~BCe)& BCi ); Age = BCe ^((~BCi)& BCo ); Agi = BCi ^((~BCo)& BCu ); Ago = BCo ^((~BCu)& BCa ); Agu = BCu ^((~BCa)& BCe ); Ebe ^= De; BCa = ROL(Ebe, 1); Egi ^= Di; BCe = ROL(Egi, 6); Eko ^= Do; BCi = ROL(Eko, 25); Emu ^= Du; BCo = ROL(Emu, 8); Esa ^= Da; BCu = ROL(Esa, 18); Aka = BCa ^((~BCe)& BCi ); Ake = BCe ^((~BCi)& BCo ); Aki = BCi ^((~BCo)& BCu ); Ako = BCo ^((~BCu)& BCa ); Aku = BCu ^((~BCa)& BCe ); Ebu ^= Du; BCa = ROL(Ebu, 27); Ega ^= Da; BCe = ROL(Ega, 36); Eke ^= De; BCi = ROL(Eke, 10); Emi ^= Di; BCo = ROL(Emi, 15); Eso ^= Do; BCu = ROL(Eso, 56); Ama = BCa ^((~BCe)& BCi ); Ame = BCe ^((~BCi)& BCo ); Ami = BCi ^((~BCo)& BCu ); Amo = BCo ^((~BCu)& BCa ); Amu = BCu ^((~BCa)& BCe ); Ebi ^= Di; BCa = ROL(Ebi, 62); Ego ^= Do; BCe = ROL(Ego, 55); Eku ^= Du; BCi = ROL(Eku, 39); Ema ^= Da; BCo = ROL(Ema, 41); Ese ^= De; BCu = ROL(Ese, 2); Asa = BCa ^((~BCe)& BCi ); Ase = BCe ^((~BCi)& BCo ); Asi = BCi ^((~BCo)& BCu ); Aso = BCo ^((~BCu)& BCa ); Asu = BCu ^((~BCa)& BCe ); } //copyToState(state, A) state[ 0] = Aba; state[ 1] = Abe; state[ 2] = Abi; state[ 3] = Abo; state[ 4] = Abu; state[ 5] = Aga; state[ 6] = Age; state[ 7] = Agi; state[ 8] = Ago; state[ 9] = Agu; state[10] = Aka; state[11] = Ake; state[12] = Aki; state[13] = Ako; state[14] = Aku; state[15] = Ama; state[16] = Ame; state[17] = Ami; state[18] = Amo; state[19] = Amu; state[20] = Asa; state[21] = Ase; state[22] = Asi; state[23] = Aso; state[24] = Asu; } /************************************************* * Name: keccak_init * * Description: Initializes the Keccak state. * * Arguments: - uint64_t *s: pointer to Keccak state **************************************************/ static void keccak_init(uint64_t s[25]) { unsigned int i; for(i=0;i<25;i++) s[i] = 0; } /************************************************* * Name: keccak_absorb * * Description: Absorb step of Keccak; incremental. * * Arguments: - uint64_t *s: pointer to Keccak state * - unsigned int pos: position in current block to be absorbed * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) * - const uint8_t *in: pointer to input to be absorbed into s * - size_t inlen: length of input in bytes * * Returns new position pos in current block **************************************************/ static unsigned int keccak_absorb(uint64_t s[25], unsigned int pos, unsigned int r, const uint8_t *in, size_t inlen) { unsigned int i; while(pos+inlen >= r) { for(i=pos;i> 8*(i%8); outlen -= i-pos; pos = i; } return pos; } /************************************************* * Name: keccak_absorb_once * * Description: Absorb step of Keccak; * non-incremental, starts by zeroeing the state. * * Arguments: - uint64_t *s: pointer to (uninitialized) output Keccak state * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) * - const uint8_t *in: pointer to input to be absorbed into s * - size_t inlen: length of input in bytes * - uint8_t p: domain-separation byte for different Keccak-derived functions **************************************************/ static void keccak_absorb_once(uint64_t s[25], unsigned int r, const uint8_t *in, size_t inlen, uint8_t p) { unsigned int i; for(i=0;i<25;i++) s[i] = 0; while(inlen >= r) { for(i=0;is); state->pos = 0; } /************************************************* * Name: shake128_absorb * * Description: Absorb step of the SHAKE128 XOF; incremental. * * Arguments: - keccak_state *state: pointer to (initialized) output Keccak state * - const uint8_t *in: pointer to input to be absorbed into s * - size_t inlen: length of input in bytes **************************************************/ void shake128_absorb(keccak_state *state, const uint8_t *in, size_t inlen) { state->pos = keccak_absorb(state->s, state->pos, SHAKE128_RATE, in, inlen); } /************************************************* * Name: shake128_finalize * * Description: Finalize absorb step of the SHAKE128 XOF. * * Arguments: - keccak_state *state: pointer to Keccak state **************************************************/ void shake128_finalize(keccak_state *state) { keccak_finalize(state->s, state->pos, SHAKE128_RATE, 0x1F); state->pos = SHAKE128_RATE; } /************************************************* * Name: shake128_squeeze * * Description: Squeeze step of SHAKE128 XOF. Squeezes arbitraily many * bytes. Can be called multiple times to keep squeezing. * * Arguments: - uint8_t *out: pointer to output blocks * - size_t outlen : number of bytes to be squeezed (written to output) * - keccak_state *s: pointer to input/output Keccak state **************************************************/ void shake128_squeeze(uint8_t *out, size_t outlen, keccak_state *state) { state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE128_RATE); } /************************************************* * Name: shake128_absorb_once * * Description: Initialize, absorb into and finalize SHAKE128 XOF; non-incremental. * * Arguments: - keccak_state *state: pointer to (uninitialized) output Keccak state * - const uint8_t *in: pointer to input to be absorbed into s * - size_t inlen: length of input in bytes **************************************************/ void shake128_absorb_once(keccak_state *state, const uint8_t *in, size_t inlen) { keccak_absorb_once(state->s, SHAKE128_RATE, in, inlen, 0x1F); state->pos = SHAKE128_RATE; } /************************************************* * Name: shake128_squeezeblocks * * Description: Squeeze step of SHAKE128 XOF. Squeezes full blocks of * SHAKE128_RATE bytes each. Can be called multiple times * to keep squeezing. Assumes new block has not yet been * started (state->pos = SHAKE128_RATE). * * Arguments: - uint8_t *out: pointer to output blocks * - size_t nblocks: number of blocks to be squeezed (written to output) * - keccak_state *s: pointer to input/output Keccak state **************************************************/ void shake128_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state) { keccak_squeezeblocks(out, nblocks, state->s, SHAKE128_RATE); } /************************************************* * Name: shake256_init * * Description: Initilizes Keccak state for use as SHAKE256 XOF * * Arguments: - keccak_state *state: pointer to (uninitialized) Keccak state **************************************************/ void shake256_init(keccak_state *state) { keccak_init(state->s); state->pos = 0; } /************************************************* * Name: shake256_absorb * * Description: Absorb step of the SHAKE256 XOF; incremental. * * Arguments: - keccak_state *state: pointer to (initialized) output Keccak state * - const uint8_t *in: pointer to input to be absorbed into s * - size_t inlen: length of input in bytes **************************************************/ void shake256_absorb(keccak_state *state, const uint8_t *in, size_t inlen) { state->pos = keccak_absorb(state->s, state->pos, SHAKE256_RATE, in, inlen); } /************************************************* * Name: shake256_finalize * * Description: Finalize absorb step of the SHAKE256 XOF. * * Arguments: - keccak_state *state: pointer to Keccak state **************************************************/ void shake256_finalize(keccak_state *state) { keccak_finalize(state->s, state->pos, SHAKE256_RATE, 0x1F); state->pos = SHAKE256_RATE; } /************************************************* * Name: shake256_squeeze * * Description: Squeeze step of SHAKE256 XOF. Squeezes arbitraily many * bytes. Can be called multiple times to keep squeezing. * * Arguments: - uint8_t *out: pointer to output blocks * - size_t outlen : number of bytes to be squeezed (written to output) * - keccak_state *s: pointer to input/output Keccak state **************************************************/ void shake256_squeeze(uint8_t *out, size_t outlen, keccak_state *state) { state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE256_RATE); } /************************************************* * Name: shake256_absorb_once * * Description: Initialize, absorb into and finalize SHAKE256 XOF; non-incremental. * * Arguments: - keccak_state *state: pointer to (uninitialized) output Keccak state * - const uint8_t *in: pointer to input to be absorbed into s * - size_t inlen: length of input in bytes **************************************************/ void shake256_absorb_once(keccak_state *state, const uint8_t *in, size_t inlen) { keccak_absorb_once(state->s, SHAKE256_RATE, in, inlen, 0x1F); state->pos = SHAKE256_RATE; } /************************************************* * Name: shake256_squeezeblocks * * Description: Squeeze step of SHAKE256 XOF. Squeezes full blocks of * SHAKE256_RATE bytes each. Can be called multiple times * to keep squeezing. Assumes next block has not yet been * started (state->pos = SHAKE256_RATE). * * Arguments: - uint8_t *out: pointer to output blocks * - size_t nblocks: number of blocks to be squeezed (written to output) * - keccak_state *s: pointer to input/output Keccak state **************************************************/ void shake256_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state) { keccak_squeezeblocks(out, nblocks, state->s, SHAKE256_RATE); } /************************************************* * Name: shake128 * * Description: SHAKE128 XOF with non-incremental API * * Arguments: - uint8_t *out: pointer to output * - size_t outlen: requested output length in bytes * - const uint8_t *in: pointer to input * - size_t inlen: length of input in bytes **************************************************/ void shake128(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) { size_t nblocks; keccak_state state; shake128_absorb_once(&state, in, inlen); nblocks = outlen/SHAKE128_RATE; shake128_squeezeblocks(out, nblocks, &state); outlen -= nblocks*SHAKE128_RATE; out += nblocks*SHAKE128_RATE; shake128_squeeze(out, outlen, &state); } /************************************************* * Name: shake256 * * Description: SHAKE256 XOF with non-incremental API * * Arguments: - uint8_t *out: pointer to output * - size_t outlen: requested output length in bytes * - const uint8_t *in: pointer to input * - size_t inlen: length of input in bytes **************************************************/ void shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) { size_t nblocks; keccak_state state; shake256_absorb_once(&state, in, inlen); nblocks = outlen/SHAKE256_RATE; shake256_squeezeblocks(out, nblocks, &state); outlen -= nblocks*SHAKE256_RATE; out += nblocks*SHAKE256_RATE; shake256_squeeze(out, outlen, &state); } /************************************************* * Name: sha3_256 * * Description: SHA3-256 with non-incremental API * * Arguments: - uint8_t *h: pointer to output (32 bytes) * - const uint8_t *in: pointer to input * - size_t inlen: length of input in bytes **************************************************/ void sha3_256(uint8_t h[32], const uint8_t *in, size_t inlen) { unsigned int i; uint64_t s[25]; keccak_absorb_once(s, SHA3_256_RATE, in, inlen, 0x06); KeccakF1600_StatePermute(s); for(i=0;i<4;i++) store64(h+8*i,s[i]); } /************************************************* * Name: sha3_512 * * Description: SHA3-512 with non-incremental API * * Arguments: - uint8_t *h: pointer to output (64 bytes) * - const uint8_t *in: pointer to input * - size_t inlen: length of input in bytes **************************************************/ void sha3_512(uint8_t h[64], const uint8_t *in, size_t inlen) { unsigned int i; uint64_t s[25]; keccak_absorb_once(s, SHA3_512_RATE, in, inlen, 0x06); KeccakF1600_StatePermute(s); for(i=0;i<8;i++) store64(h+8*i,s[i]); }