/*
 * Keccak implementation for SHA3 parameters.
 *
 * Copyright (c) 2012 Marko Kreen
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * Based on public-domain Keccak-inplace.c and Keccak-inplace32BI.c
 * implementations from Keccak reference code:
 *
 *     The Keccak sponge function, designed by Guido Bertoni, Joan Daemen,
 *     Michaël Peeters and Gilles Van Assche. For more information, feedback or
 *     questions, please refer to our website: http://keccak.noekeon.org/
 *
 *     Implementation by Ronny Van Keer and the designers,
 *     hereby denoted as "the implementer".
 *
 *     To the extent possible under law, the implementer has waived all copyright
 *     and related or neighboring rights to the source code in this file.
 *     http://creativecommons.org/publicdomain/zero/1.0/
 *
 * 32-bit word interlacing algorithm:
 *
 *     Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002
 */

#include <usual/crypto/keccak.h>
#include <usual/crypto/digest.h>
#include <usual/bits.h>
#include <usual/endian.h>
#include <limits.h>
#include <string.h>

/*
 * Decide whether to use 64- or 32-bit implementation.
 */
#if !defined(KECCAK_64BIT) && !defined(KECCAK_32BIT)
/* If neither is defined, try to autodetect */
#if (LONG_MAX > 0xFFFFFFFF) || (UINTPTR_MAX > 0xFFFFFFFF)
/* use 64-bit implementation if 'long' or 'uintptr_t' is 64-bit */
#define KECCAK_64BIT
#else
/* otherwise, use 32-bit implementation */
#define KECCAK_32BIT
#endif
#endif

/* For SHA3 variant of Keccak */
#define KECCAK_ROUNDS 24


#ifdef KECCAK_64BIT

/*
 * 64-bit implementation - one lane is one 64-bit word.
 */

/* round constants */
static const uint64_t RoundConstants64[KECCAK_ROUNDS] = {
	UINT64_C(0x0000000000000001), UINT64_C(0x0000000000008082),
	UINT64_C(0x800000000000808A), UINT64_C(0x8000000080008000),
	UINT64_C(0x000000000000808B), UINT64_C(0x0000000080000001),
	UINT64_C(0x8000000080008081), UINT64_C(0x8000000000008009),
	UINT64_C(0x000000000000008A), UINT64_C(0x0000000000000088),
	UINT64_C(0x0000000080008009), UINT64_C(0x000000008000000A),
	UINT64_C(0x000000008000808B), UINT64_C(0x800000000000008B),
	UINT64_C(0x8000000000008089), UINT64_C(0x8000000000008003),
	UINT64_C(0x8000000000008002), UINT64_C(0x8000000000000080),
	UINT64_C(0x000000000000800A), UINT64_C(0x800000008000000A),
	UINT64_C(0x8000000080008081), UINT64_C(0x8000000000008080),
	UINT64_C(0x0000000080000001), UINT64_C(0x8000000080008008),
};

static void keccak_f(struct KeccakContext *ctx)
{
	uint64_t *state = ctx->u.state64;
	uint64_t Ba, Be, Bi, Bo, Bu;
	uint64_t Ca, Ce, Ci, Co, Cu;
	uint64_t Da, De, Di, Do, Du;
	int i;

#define Aba state[ 0]
#define Abe state[ 1]
#define Abi state[ 2]
#define Abo state[ 3]
#define Abu state[ 4]
#define Aga state[ 5]
#define Age state[ 6]
#define Agi state[ 7]
#define Ago state[ 8]
#define Agu state[ 9]
#define Aka state[10]
#define Ake state[11]
#define Aki state[12]
#define Ako state[13]
#define Aku state[14]
#define Ama state[15]
#define Ame state[16]
#define Ami state[17]
#define Amo state[18]
#define Amu state[19]
#define Asa state[20]
#define Ase state[21]
#define Asi state[22]
#define Aso state[23]
#define Asu state[24]

	for (i = 0; i < KECCAK_ROUNDS; i += 4) {
		/* Code for 4 rounds */
		Ca = Aba^Aga^Aka^Ama^Asa;
		Ce = Abe^Age^Ake^Ame^Ase;
		Ci = Abi^Agi^Aki^Ami^Asi;
		Co = Abo^Ago^Ako^Amo^Aso;
		Cu = Abu^Agu^Aku^Amu^Asu;
		Da = Cu^rol64(Ce, 1);
		De = Ca^rol64(Ci, 1);
		Di = Ce^rol64(Co, 1);
		Do = Ci^rol64(Cu, 1);
		Du = Co^rol64(Ca, 1);

		Ba = (Aba^Da);
		Be = rol64((Age^De), 44);
		Bi = rol64((Aki^Di), 43);
		Bo = rol64((Amo^Do), 21);
		Bu = rol64((Asu^Du), 14);
		Aba =   Ba ^((~Be)&  Bi );
		Aba ^= RoundConstants64[i+0];
		Age =   Be ^((~Bi)&  Bo );
		Aki =   Bi ^((~Bo)&  Bu );
		Amo =   Bo ^((~Bu)&  Ba );
		Asu =   Bu ^((~Ba)&  Be );

		Bi = rol64((Aka^Da), 3);
		Bo = rol64((Ame^De), 45);
		Bu = rol64((Asi^Di), 61);
		Ba = rol64((Abo^Do), 28);
		Be = rol64((Agu^Du), 20);
		Aka =   Ba ^((~Be)&  Bi );
		Ame =   Be ^((~Bi)&  Bo );
		Asi =   Bi ^((~Bo)&  Bu );
		Abo =   Bo ^((~Bu)&  Ba );
		Agu =   Bu ^((~Ba)&  Be );

		Bu = rol64((Asa^Da), 18);
		Ba = rol64((Abe^De), 1);
		Be = rol64((Agi^Di), 6);
		Bi = rol64((Ako^Do), 25);
		Bo = rol64((Amu^Du), 8);
		Asa =   Ba ^((~Be)&  Bi );
		Abe =   Be ^((~Bi)&  Bo );
		Agi =   Bi ^((~Bo)&  Bu );
		Ako =   Bo ^((~Bu)&  Ba );
		Amu =   Bu ^((~Ba)&  Be );

		Be = rol64((Aga^Da), 36);
		Bi = rol64((Ake^De), 10);
		Bo = rol64((Ami^Di), 15);
		Bu = rol64((Aso^Do), 56);
		Ba = rol64((Abu^Du), 27);
		Aga =   Ba ^((~Be)&  Bi );
		Ake =   Be ^((~Bi)&  Bo );
		Ami =   Bi ^((~Bo)&  Bu );
		Aso =   Bo ^((~Bu)&  Ba );
		Abu =   Bu ^((~Ba)&  Be );

		Bo = rol64((Ama^Da), 41);
		Bu = rol64((Ase^De), 2);
		Ba = rol64((Abi^Di), 62);
		Be = rol64((Ago^Do), 55);
		Bi = rol64((Aku^Du), 39);
		Ama =   Ba ^((~Be)&  Bi );
		Ase =   Be ^((~Bi)&  Bo );
		Abi =   Bi ^((~Bo)&  Bu );
		Ago =   Bo ^((~Bu)&  Ba );
		Aku =   Bu ^((~Ba)&  Be );

		Ca = Aba^Aka^Asa^Aga^Ama;
		Ce = Age^Ame^Abe^Ake^Ase;
		Ci = Aki^Asi^Agi^Ami^Abi;
		Co = Amo^Abo^Ako^Aso^Ago;
		Cu = Asu^Agu^Amu^Abu^Aku;
		Da = Cu^rol64(Ce, 1);
		De = Ca^rol64(Ci, 1);
		Di = Ce^rol64(Co, 1);
		Do = Ci^rol64(Cu, 1);
		Du = Co^rol64(Ca, 1);

		Ba = (Aba^Da);
		Be = rol64((Ame^De), 44);
		Bi = rol64((Agi^Di), 43);
		Bo = rol64((Aso^Do), 21);
		Bu = rol64((Aku^Du), 14);
		Aba =   Ba ^((~Be)&  Bi );
		Aba ^= RoundConstants64[i+1];
		Ame =   Be ^((~Bi)&  Bo );
		Agi =   Bi ^((~Bo)&  Bu );
		Aso =   Bo ^((~Bu)&  Ba );
		Aku =   Bu ^((~Ba)&  Be );

		Bi = rol64((Asa^Da), 3);
		Bo = rol64((Ake^De), 45);
		Bu = rol64((Abi^Di), 61);
		Ba = rol64((Amo^Do), 28);
		Be = rol64((Agu^Du), 20);
		Asa =   Ba ^((~Be)&  Bi );
		Ake =   Be ^((~Bi)&  Bo );
		Abi =   Bi ^((~Bo)&  Bu );
		Amo =   Bo ^((~Bu)&  Ba );
		Agu =   Bu ^((~Ba)&  Be );

		Bu = rol64((Ama^Da), 18);
		Ba = rol64((Age^De), 1);
		Be = rol64((Asi^Di), 6);
		Bi = rol64((Ako^Do), 25);
		Bo = rol64((Abu^Du), 8);
		Ama =   Ba ^((~Be)&  Bi );
		Age =   Be ^((~Bi)&  Bo );
		Asi =   Bi ^((~Bo)&  Bu );
		Ako =   Bo ^((~Bu)&  Ba );
		Abu =   Bu ^((~Ba)&  Be );

		Be = rol64((Aka^Da), 36);
		Bi = rol64((Abe^De), 10);
		Bo = rol64((Ami^Di), 15);
		Bu = rol64((Ago^Do), 56);
		Ba = rol64((Asu^Du), 27);
		Aka =   Ba ^((~Be)&  Bi );
		Abe =   Be ^((~Bi)&  Bo );
		Ami =   Bi ^((~Bo)&  Bu );
		Ago =   Bo ^((~Bu)&  Ba );
		Asu =   Bu ^((~Ba)&  Be );

		Bo = rol64((Aga^Da), 41);
		Bu = rol64((Ase^De), 2);
		Ba = rol64((Aki^Di), 62);
		Be = rol64((Abo^Do), 55);
		Bi = rol64((Amu^Du), 39);
		Aga =   Ba ^((~Be)&  Bi );
		Ase =   Be ^((~Bi)&  Bo );
		Aki =   Bi ^((~Bo)&  Bu );
		Abo =   Bo ^((~Bu)&  Ba );
		Amu =   Bu ^((~Ba)&  Be );

		Ca = Aba^Asa^Ama^Aka^Aga;
		Ce = Ame^Ake^Age^Abe^Ase;
		Ci = Agi^Abi^Asi^Ami^Aki;
		Co = Aso^Amo^Ako^Ago^Abo;
		Cu = Aku^Agu^Abu^Asu^Amu;
		Da = Cu^rol64(Ce, 1);
		De = Ca^rol64(Ci, 1);
		Di = Ce^rol64(Co, 1);
		Do = Ci^rol64(Cu, 1);
		Du = Co^rol64(Ca, 1);

		Ba = (Aba^Da);
		Be = rol64((Ake^De), 44);
		Bi = rol64((Asi^Di), 43);
		Bo = rol64((Ago^Do), 21);
		Bu = rol64((Amu^Du), 14);
		Aba =   Ba ^((~Be)&  Bi );
		Aba ^= RoundConstants64[i+2];
		Ake =   Be ^((~Bi)&  Bo );
		Asi =   Bi ^((~Bo)&  Bu );
		Ago =   Bo ^((~Bu)&  Ba );
		Amu =   Bu ^((~Ba)&  Be );

		Bi = rol64((Ama^Da), 3);
		Bo = rol64((Abe^De), 45);
		Bu = rol64((Aki^Di), 61);
		Ba = rol64((Aso^Do), 28);
		Be = rol64((Agu^Du), 20);
		Ama =   Ba ^((~Be)&  Bi );
		Abe =   Be ^((~Bi)&  Bo );
		Aki =   Bi ^((~Bo)&  Bu );
		Aso =   Bo ^((~Bu)&  Ba );
		Agu =   Bu ^((~Ba)&  Be );

		Bu = rol64((Aga^Da), 18);
		Ba = rol64((Ame^De), 1);
		Be = rol64((Abi^Di), 6);
		Bi = rol64((Ako^Do), 25);
		Bo = rol64((Asu^Du), 8);
		Aga =   Ba ^((~Be)&  Bi );
		Ame =   Be ^((~Bi)&  Bo );
		Abi =   Bi ^((~Bo)&  Bu );
		Ako =   Bo ^((~Bu)&  Ba );
		Asu =   Bu ^((~Ba)&  Be );

		Be = rol64((Asa^Da), 36);
		Bi = rol64((Age^De), 10);
		Bo = rol64((Ami^Di), 15);
		Bu = rol64((Abo^Do), 56);
		Ba = rol64((Aku^Du), 27);
		Asa =   Ba ^((~Be)&  Bi );
		Age =   Be ^((~Bi)&  Bo );
		Ami =   Bi ^((~Bo)&  Bu );
		Abo =   Bo ^((~Bu)&  Ba );
		Aku =   Bu ^((~Ba)&  Be );

		Bo = rol64((Aka^Da), 41);
		Bu = rol64((Ase^De), 2);
		Ba = rol64((Agi^Di), 62);
		Be = rol64((Amo^Do), 55);
		Bi = rol64((Abu^Du), 39);
		Aka =   Ba ^((~Be)&  Bi );
		Ase =   Be ^((~Bi)&  Bo );
		Agi =   Bi ^((~Bo)&  Bu );
		Amo =   Bo ^((~Bu)&  Ba );
		Abu =   Bu ^((~Ba)&  Be );

		Ca = Aba^Ama^Aga^Asa^Aka;
		Ce = Ake^Abe^Ame^Age^Ase;
		Ci = Asi^Aki^Abi^Ami^Agi;
		Co = Ago^Aso^Ako^Abo^Amo;
		Cu = Amu^Agu^Asu^Aku^Abu;
		Da = Cu^rol64(Ce, 1);
		De = Ca^rol64(Ci, 1);
		Di = Ce^rol64(Co, 1);
		Do = Ci^rol64(Cu, 1);
		Du = Co^rol64(Ca, 1);

		Ba = (Aba^Da);
		Be = rol64((Abe^De), 44);
		Bi = rol64((Abi^Di), 43);
		Bo = rol64((Abo^Do), 21);
		Bu = rol64((Abu^Du), 14);
		Aba =   Ba ^((~Be)&  Bi );
		Aba ^= RoundConstants64[i+3];
		Abe =   Be ^((~Bi)&  Bo );
		Abi =   Bi ^((~Bo)&  Bu );
		Abo =   Bo ^((~Bu)&  Ba );
		Abu =   Bu ^((~Ba)&  Be );

		Bi = rol64((Aga^Da), 3);
		Bo = rol64((Age^De), 45);
		Bu = rol64((Agi^Di), 61);
		Ba = rol64((Ago^Do), 28);
		Be = rol64((Agu^Du), 20);
		Aga =   Ba ^((~Be)&  Bi );
		Age =   Be ^((~Bi)&  Bo );
		Agi =   Bi ^((~Bo)&  Bu );
		Ago =   Bo ^((~Bu)&  Ba );
		Agu =   Bu ^((~Ba)&  Be );

		Bu = rol64((Aka^Da), 18);
		Ba = rol64((Ake^De), 1);
		Be = rol64((Aki^Di), 6);
		Bi = rol64((Ako^Do), 25);
		Bo = rol64((Aku^Du), 8);
		Aka =   Ba ^((~Be)&  Bi );
		Ake =   Be ^((~Bi)&  Bo );
		Aki =   Bi ^((~Bo)&  Bu );
		Ako =   Bo ^((~Bu)&  Ba );
		Aku =   Bu ^((~Ba)&  Be );

		Be = rol64((Ama^Da), 36);
		Bi = rol64((Ame^De), 10);
		Bo = rol64((Ami^Di), 15);
		Bu = rol64((Amo^Do), 56);
		Ba = rol64((Amu^Du), 27);
		Ama =   Ba ^((~Be)&  Bi );
		Ame =   Be ^((~Bi)&  Bo );
		Ami =   Bi ^((~Bo)&  Bu );
		Amo =   Bo ^((~Bu)&  Ba );
		Amu =   Bu ^((~Ba)&  Be );

		Bo = rol64((Asa^Da), 41);
		Bu = rol64((Ase^De), 2);
		Ba = rol64((Asi^Di), 62);
		Be = rol64((Aso^Do), 55);
		Bi = rol64((Asu^Du), 39);
		Asa =   Ba ^((~Be)&  Bi );
		Ase =   Be ^((~Bi)&  Bo );
		Asi =   Bi ^((~Bo)&  Bu );
		Aso =   Bo ^((~Bu)&  Ba );
		Asu =   Bu ^((~Ba)&  Be );
	}
}

static inline void xor_lane(struct KeccakContext *ctx, int lane, uint64_t val)
{
	ctx->u.state64[lane] ^= val;
}

static void extract(uint8_t *dst, const struct KeccakContext *ctx, int laneCount)
{
	const uint64_t *src = ctx->u.state64;

	while (laneCount--) {
		le64enc(dst, *src++);
		dst += 8;
	}
}


#else /* KECCAK_32BIT */


/*
 * 32-bit implementation - one 64-bit lane is mapped
 * to two interleaved 32-bit words.
 */

static const uint32_t RoundConstants32[2*KECCAK_ROUNDS] = {
	0x00000001, 0x00000000, 0x00000000, 0x00000089,
	0x00000000, 0x8000008b, 0x00000000, 0x80008080,
	0x00000001, 0x0000008b, 0x00000001, 0x00008000,
	0x00000001, 0x80008088, 0x00000001, 0x80000082,
	0x00000000, 0x0000000b, 0x00000000, 0x0000000a,
	0x00000001, 0x00008082, 0x00000000, 0x00008003,
	0x00000001, 0x0000808b, 0x00000001, 0x8000000b,
	0x00000001, 0x8000008a, 0x00000001, 0x80000081,
	0x00000000, 0x80000081, 0x00000000, 0x80000008,
	0x00000000, 0x00000083, 0x00000000, 0x80008003,
	0x00000001, 0x80008088, 0x00000000, 0x80000088,
	0x00000001, 0x00008000, 0x00000000, 0x80008082,
};

#define KeccakAtoD_round0() \
	Cx = Abu0^Agu0^Aku0^Amu0^Asu0; \
	Du1 = Abe1^Age1^Ake1^Ame1^Ase1; \
	Da0 = Cx^rol32(Du1, 1); \
	Cz = Abu1^Agu1^Aku1^Amu1^Asu1; \
	Du0 = Abe0^Age0^Ake0^Ame0^Ase0; \
	Da1 = Cz^Du0; \
	\
	Cw = Abi0^Agi0^Aki0^Ami0^Asi0; \
	Do0 = Cw^rol32(Cz, 1); \
	Cy = Abi1^Agi1^Aki1^Ami1^Asi1; \
	Do1 = Cy^Cx; \
	\
	Cx = Aba0^Aga0^Aka0^Ama0^Asa0; \
	De0 = Cx^rol32(Cy, 1); \
	Cz = Aba1^Aga1^Aka1^Ama1^Asa1; \
	De1 = Cz^Cw; \
	\
	Cy = Abo1^Ago1^Ako1^Amo1^Aso1; \
	Di0 = Du0^rol32(Cy, 1); \
	Cw = Abo0^Ago0^Ako0^Amo0^Aso0; \
	Di1 = Du1^Cw; \
	\
	Du0 = Cw^rol32(Cz, 1); \
	Du1 = Cy^Cx;

#define KeccakAtoD_round1() \
	Cx = Asu0^Agu0^Amu0^Abu1^Aku1; \
	Du1 = Age1^Ame0^Abe0^Ake1^Ase1; \
	Da0 = Cx^rol32(Du1, 1); \
	Cz = Asu1^Agu1^Amu1^Abu0^Aku0; \
	Du0 = Age0^Ame1^Abe1^Ake0^Ase0; \
	Da1 = Cz^Du0; \
	\
	Cw = Aki1^Asi1^Agi0^Ami1^Abi0; \
	Do0 = Cw^rol32(Cz, 1); \
	Cy = Aki0^Asi0^Agi1^Ami0^Abi1; \
	Do1 = Cy^Cx; \
	\
	Cx = Aba0^Aka1^Asa0^Aga0^Ama1; \
	De0 = Cx^rol32(Cy, 1); \
	Cz = Aba1^Aka0^Asa1^Aga1^Ama0; \
	De1 = Cz^Cw; \
	\
	Cy = Amo0^Abo1^Ako0^Aso1^Ago0; \
	Di0 = Du0^rol32(Cy, 1); \
	Cw = Amo1^Abo0^Ako1^Aso0^Ago1; \
	Di1 = Du1^Cw; \
	\
	Du0 = Cw^rol32(Cz, 1); \
	Du1 = Cy^Cx;

#define KeccakAtoD_round2() \
	Cx = Aku1^Agu0^Abu1^Asu1^Amu1; \
	Du1 = Ame0^Ake0^Age0^Abe0^Ase1; \
	Da0 = Cx^rol32(Du1, 1); \
	Cz = Aku0^Agu1^Abu0^Asu0^Amu0; \
	Du0 = Ame1^Ake1^Age1^Abe1^Ase0; \
	Da1 = Cz^Du0; \
	\
	Cw = Agi1^Abi1^Asi1^Ami0^Aki1; \
	Do0 = Cw^rol32(Cz, 1); \
	Cy = Agi0^Abi0^Asi0^Ami1^Aki0; \
	Do1 = Cy^Cx; \
	\
	Cx = Aba0^Asa1^Ama1^Aka1^Aga1; \
	De0 = Cx^rol32(Cy, 1); \
	Cz = Aba1^Asa0^Ama0^Aka0^Aga0; \
	De1 = Cz^Cw; \
	\
	Cy = Aso0^Amo0^Ako1^Ago0^Abo0; \
	Di0 = Du0^rol32(Cy, 1); \
	Cw = Aso1^Amo1^Ako0^Ago1^Abo1; \
	Di1 = Du1^Cw; \
	\
	Du0 = Cw^rol32(Cz, 1); \
	Du1 = Cy^Cx;

#define KeccakAtoD_round3() \
	Cx = Amu1^Agu0^Asu1^Aku0^Abu0; \
	Du1 = Ake0^Abe1^Ame1^Age0^Ase1; \
	Da0 = Cx^rol32(Du1, 1); \
	Cz = Amu0^Agu1^Asu0^Aku1^Abu1; \
	Du0 = Ake1^Abe0^Ame0^Age1^Ase0; \
	Da1 = Cz^Du0; \
	\
	Cw = Asi0^Aki0^Abi1^Ami1^Agi1; \
	Do0 = Cw^rol32(Cz, 1); \
	Cy = Asi1^Aki1^Abi0^Ami0^Agi0; \
	Do1 = Cy^Cx; \
	\
	Cx = Aba0^Ama0^Aga1^Asa1^Aka0; \
	De0 = Cx^rol32(Cy, 1); \
	Cz = Aba1^Ama1^Aga0^Asa0^Aka1; \
	De1 = Cz^Cw; \
	\
	Cy = Ago1^Aso0^Ako0^Abo0^Amo1; \
	Di0 = Du0^rol32(Cy, 1); \
	Cw = Ago0^Aso1^Ako1^Abo1^Amo0; \
	Di1 = Du1^Cw; \
	\
	Du0 = Cw^rol32(Cz, 1); \
	Du1 = Cy^Cx;

static void keccak_f(struct KeccakContext *ctx)
{
	uint32_t *state = ctx->u.state32;
	uint32_t Da0, De0, Di0, Do0, Du0;
	uint32_t Da1, De1, Di1, Do1, Du1;
	uint32_t Ca0, Ce0, Ci0, Co0, Cu0;
	uint32_t Cx, Cy, Cz, Cw;
	int i;

#define Ba Ca0
#define Be Ce0
#define Bi Ci0
#define Bo Co0
#define Bu Cu0

#define Aba0 state[ 0]
#define Aba1 state[ 1]
#define Abe0 state[ 2]
#define Abe1 state[ 3]
#define Abi0 state[ 4]
#define Abi1 state[ 5]
#define Abo0 state[ 6]
#define Abo1 state[ 7]
#define Abu0 state[ 8]
#define Abu1 state[ 9]
#define Aga0 state[10]
#define Aga1 state[11]
#define Age0 state[12]
#define Age1 state[13]
#define Agi0 state[14]
#define Agi1 state[15]
#define Ago0 state[16]
#define Ago1 state[17]
#define Agu0 state[18]
#define Agu1 state[19]
#define Aka0 state[20]
#define Aka1 state[21]
#define Ake0 state[22]
#define Ake1 state[23]
#define Aki0 state[24]
#define Aki1 state[25]
#define Ako0 state[26]
#define Ako1 state[27]
#define Aku0 state[28]
#define Aku1 state[29]
#define Ama0 state[30]
#define Ama1 state[31]
#define Ame0 state[32]
#define Ame1 state[33]
#define Ami0 state[34]
#define Ami1 state[35]
#define Amo0 state[36]
#define Amo1 state[37]
#define Amu0 state[38]
#define Amu1 state[39]
#define Asa0 state[40]
#define Asa1 state[41]
#define Ase0 state[42]
#define Ase1 state[43]
#define Asi0 state[44]
#define Asi1 state[45]
#define Aso0 state[46]
#define Aso1 state[47]
#define Asu0 state[48]
#define Asu1 state[49]

	for (i = 0; i < KECCAK_ROUNDS*2; i += 8) {
		/* Code for 4 rounds */
		KeccakAtoD_round0();

		Ba = (Aba0^Da0);
		Be = rol32((Age0^De0), 22);
		Bi = rol32((Aki1^Di1), 22);
		Bo = rol32((Amo1^Do1), 11);
		Bu = rol32((Asu0^Du0), 7);
		Aba0 =   Ba ^((~Be)&  Bi );
		Aba0 ^= RoundConstants32[i+0];
		Age0 =   Be ^((~Bi)&  Bo );
		Aki1 =   Bi ^((~Bo)&  Bu );
		Amo1 =   Bo ^((~Bu)&  Ba );
		Asu0 =   Bu ^((~Ba)&  Be );

		Ba = (Aba1^Da1);
		Be = rol32((Age1^De1), 22);
		Bi = rol32((Aki0^Di0), 21);
		Bo = rol32((Amo0^Do0), 10);
		Bu = rol32((Asu1^Du1), 7);
		Aba1 =   Ba ^((~Be)&  Bi );
		Aba1 ^= RoundConstants32[i+1];
		Age1 =   Be ^((~Bi)&  Bo );
		Aki0 =   Bi ^((~Bo)&  Bu );
		Amo0 =   Bo ^((~Bu)&  Ba );
		Asu1 =   Bu ^((~Ba)&  Be );

		Bi = rol32((Aka1^Da1), 2);
		Bo = rol32((Ame1^De1), 23);
		Bu = rol32((Asi1^Di1), 31);
		Ba = rol32((Abo0^Do0), 14);
		Be = rol32((Agu0^Du0), 10);
		Aka1 =   Ba ^((~Be)&  Bi );
		Ame1 =   Be ^((~Bi)&  Bo );
		Asi1 =   Bi ^((~Bo)&  Bu );
		Abo0 =   Bo ^((~Bu)&  Ba );
		Agu0 =   Bu ^((~Ba)&  Be );

		Bi = rol32((Aka0^Da0), 1);
		Bo = rol32((Ame0^De0), 22);
		Bu = rol32((Asi0^Di0), 30);
		Ba = rol32((Abo1^Do1), 14);
		Be = rol32((Agu1^Du1), 10);
		Aka0 =   Ba ^((~Be)&  Bi );
		Ame0 =   Be ^((~Bi)&  Bo );
		Asi0 =   Bi ^((~Bo)&  Bu );
		Abo1 =   Bo ^((~Bu)&  Ba );
		Agu1 =   Bu ^((~Ba)&  Be );

		Bu = rol32((Asa0^Da0), 9);
		Ba = rol32((Abe1^De1), 1);
		Be = rol32((Agi0^Di0), 3);
		Bi = rol32((Ako1^Do1), 13);
		Bo = rol32((Amu0^Du0), 4);
		Asa0 =   Ba ^((~Be)&  Bi );
		Abe1 =   Be ^((~Bi)&  Bo );
		Agi0 =   Bi ^((~Bo)&  Bu );
		Ako1 =   Bo ^((~Bu)&  Ba );
		Amu0 =   Bu ^((~Ba)&  Be );

		Bu = rol32((Asa1^Da1), 9);
		Ba = (Abe0^De0);
		Be = rol32((Agi1^Di1), 3);
		Bi = rol32((Ako0^Do0), 12);
		Bo = rol32((Amu1^Du1), 4);
		Asa1 =   Ba ^((~Be)&  Bi );
		Abe0 =   Be ^((~Bi)&  Bo );
		Agi1 =   Bi ^((~Bo)&  Bu );
		Ako0 =   Bo ^((~Bu)&  Ba );
		Amu1 =   Bu ^((~Ba)&  Be );

		Be = rol32((Aga0^Da0), 18);
		Bi = rol32((Ake0^De0), 5);
		Bo = rol32((Ami1^Di1), 8);
		Bu = rol32((Aso0^Do0), 28);
		Ba = rol32((Abu1^Du1), 14);
		Aga0 =   Ba ^((~Be)&  Bi );
		Ake0 =   Be ^((~Bi)&  Bo );
		Ami1 =   Bi ^((~Bo)&  Bu );
		Aso0 =   Bo ^((~Bu)&  Ba );
		Abu1 =   Bu ^((~Ba)&  Be );

		Be = rol32((Aga1^Da1), 18);
		Bi = rol32((Ake1^De1), 5);
		Bo = rol32((Ami0^Di0), 7);
		Bu = rol32((Aso1^Do1), 28);
		Ba = rol32((Abu0^Du0), 13);
		Aga1 =   Ba ^((~Be)&  Bi );
		Ake1 =   Be ^((~Bi)&  Bo );
		Ami0 =   Bi ^((~Bo)&  Bu );
		Aso1 =   Bo ^((~Bu)&  Ba );
		Abu0 =   Bu ^((~Ba)&  Be );

		Bo = rol32((Ama1^Da1), 21);
		Bu = rol32((Ase0^De0), 1);
		Ba = rol32((Abi0^Di0), 31);
		Be = rol32((Ago1^Do1), 28);
		Bi = rol32((Aku1^Du1), 20);
		Ama1 =   Ba ^((~Be)&  Bi );
		Ase0 =   Be ^((~Bi)&  Bo );
		Abi0 =   Bi ^((~Bo)&  Bu );
		Ago1 =   Bo ^((~Bu)&  Ba );
		Aku1 =   Bu ^((~Ba)&  Be );

		Bo = rol32((Ama0^Da0), 20);
		Bu = rol32((Ase1^De1), 1);
		Ba = rol32((Abi1^Di1), 31);
		Be = rol32((Ago0^Do0), 27);
		Bi = rol32((Aku0^Du0), 19);
		Ama0 =   Ba ^((~Be)&  Bi );
		Ase1 =   Be ^((~Bi)&  Bo );
		Abi1 =   Bi ^((~Bo)&  Bu );
		Ago0 =   Bo ^((~Bu)&  Ba );
		Aku0 =   Bu ^((~Ba)&  Be );

		KeccakAtoD_round1();

		Ba = (Aba0^Da0);
		Be = rol32((Ame1^De0), 22);
		Bi = rol32((Agi1^Di1), 22);
		Bo = rol32((Aso1^Do1), 11);
		Bu = rol32((Aku1^Du0), 7);
		Aba0 =   Ba ^((~Be)&  Bi );
		Aba0 ^= RoundConstants32[i+2];
		Ame1 =   Be ^((~Bi)&  Bo );
		Agi1 =   Bi ^((~Bo)&  Bu );
		Aso1 =   Bo ^((~Bu)&  Ba );
		Aku1 =   Bu ^((~Ba)&  Be );

		Ba = (Aba1^Da1);
		Be = rol32((Ame0^De1), 22);
		Bi = rol32((Agi0^Di0), 21);
		Bo = rol32((Aso0^Do0), 10);
		Bu = rol32((Aku0^Du1), 7);
		Aba1 =   Ba ^((~Be)&  Bi );
		Aba1 ^= RoundConstants32[i+3];
		Ame0 =   Be ^((~Bi)&  Bo );
		Agi0 =   Bi ^((~Bo)&  Bu );
		Aso0 =   Bo ^((~Bu)&  Ba );
		Aku0 =   Bu ^((~Ba)&  Be );

		Bi = rol32((Asa1^Da1), 2);
		Bo = rol32((Ake1^De1), 23);
		Bu = rol32((Abi1^Di1), 31);
		Ba = rol32((Amo1^Do0), 14);
		Be = rol32((Agu0^Du0), 10);
		Asa1 =   Ba ^((~Be)&  Bi );
		Ake1 =   Be ^((~Bi)&  Bo );
		Abi1 =   Bi ^((~Bo)&  Bu );
		Amo1 =   Bo ^((~Bu)&  Ba );
		Agu0 =   Bu ^((~Ba)&  Be );

		Bi = rol32((Asa0^Da0), 1);
		Bo = rol32((Ake0^De0), 22);
		Bu = rol32((Abi0^Di0), 30);
		Ba = rol32((Amo0^Do1), 14);
		Be = rol32((Agu1^Du1), 10);
		Asa0 =   Ba ^((~Be)&  Bi );
		Ake0 =   Be ^((~Bi)&  Bo );
		Abi0 =   Bi ^((~Bo)&  Bu );
		Amo0 =   Bo ^((~Bu)&  Ba );
		Agu1 =   Bu ^((~Ba)&  Be );

		Bu = rol32((Ama1^Da0), 9);
		Ba = rol32((Age1^De1), 1);
		Be = rol32((Asi1^Di0), 3);
		Bi = rol32((Ako0^Do1), 13);
		Bo = rol32((Abu1^Du0), 4);
		Ama1 =   Ba ^((~Be)&  Bi );
		Age1 =   Be ^((~Bi)&  Bo );
		Asi1 =   Bi ^((~Bo)&  Bu );
		Ako0 =   Bo ^((~Bu)&  Ba );
		Abu1 =   Bu ^((~Ba)&  Be );

		Bu = rol32((Ama0^Da1), 9);
		Ba = (Age0^De0);
		Be = rol32((Asi0^Di1), 3);
		Bi = rol32((Ako1^Do0), 12);
		Bo = rol32((Abu0^Du1), 4);
		Ama0 =   Ba ^((~Be)&  Bi );
		Age0 =   Be ^((~Bi)&  Bo );
		Asi0 =   Bi ^((~Bo)&  Bu );
		Ako1 =   Bo ^((~Bu)&  Ba );
		Abu0 =   Bu ^((~Ba)&  Be );

		Be = rol32((Aka1^Da0), 18);
		Bi = rol32((Abe1^De0), 5);
		Bo = rol32((Ami0^Di1), 8);
		Bu = rol32((Ago1^Do0), 28);
		Ba = rol32((Asu1^Du1), 14);
		Aka1 =   Ba ^((~Be)&  Bi );
		Abe1 =   Be ^((~Bi)&  Bo );
		Ami0 =   Bi ^((~Bo)&  Bu );
		Ago1 =   Bo ^((~Bu)&  Ba );
		Asu1 =   Bu ^((~Ba)&  Be );

		Be = rol32((Aka0^Da1), 18);
		Bi = rol32((Abe0^De1), 5);
		Bo = rol32((Ami1^Di0), 7);
		Bu = rol32((Ago0^Do1), 28);
		Ba = rol32((Asu0^Du0), 13);
		Aka0 =   Ba ^((~Be)&  Bi );
		Abe0 =   Be ^((~Bi)&  Bo );
		Ami1 =   Bi ^((~Bo)&  Bu );
		Ago0 =   Bo ^((~Bu)&  Ba );
		Asu0 =   Bu ^((~Ba)&  Be );

		Bo = rol32((Aga1^Da1), 21);
		Bu = rol32((Ase0^De0), 1);
		Ba = rol32((Aki1^Di0), 31);
		Be = rol32((Abo1^Do1), 28);
		Bi = rol32((Amu1^Du1), 20);
		Aga1 =   Ba ^((~Be)&  Bi );
		Ase0 =   Be ^((~Bi)&  Bo );
		Aki1 =   Bi ^((~Bo)&  Bu );
		Abo1 =   Bo ^((~Bu)&  Ba );
		Amu1 =   Bu ^((~Ba)&  Be );

		Bo = rol32((Aga0^Da0), 20);
		Bu = rol32((Ase1^De1), 1);
		Ba = rol32((Aki0^Di1), 31);
		Be = rol32((Abo0^Do0), 27);
		Bi = rol32((Amu0^Du0), 19);
		Aga0 =   Ba ^((~Be)&  Bi );
		Ase1 =   Be ^((~Bi)&  Bo );
		Aki0 =   Bi ^((~Bo)&  Bu );
		Abo0 =   Bo ^((~Bu)&  Ba );
		Amu0 =   Bu ^((~Ba)&  Be );

		KeccakAtoD_round2();

		Ba = (Aba0^Da0);
		Be = rol32((Ake1^De0), 22);
		Bi = rol32((Asi0^Di1), 22);
		Bo = rol32((Ago0^Do1), 11);
		Bu = rol32((Amu1^Du0), 7);
		Aba0 =   Ba ^((~Be)&  Bi );
		Aba0 ^= RoundConstants32[i+4];
		Ake1 =   Be ^((~Bi)&  Bo );
		Asi0 =   Bi ^((~Bo)&  Bu );
		Ago0 =   Bo ^((~Bu)&  Ba );
		Amu1 =   Bu ^((~Ba)&  Be );

		Ba = (Aba1^Da1);
		Be = rol32((Ake0^De1), 22);
		Bi = rol32((Asi1^Di0), 21);
		Bo = rol32((Ago1^Do0), 10);
		Bu = rol32((Amu0^Du1), 7);
		Aba1 =   Ba ^((~Be)&  Bi );
		Aba1 ^= RoundConstants32[i+5];
		Ake0 =   Be ^((~Bi)&  Bo );
		Asi1 =   Bi ^((~Bo)&  Bu );
		Ago1 =   Bo ^((~Bu)&  Ba );
		Amu0 =   Bu ^((~Ba)&  Be );

		Bi = rol32((Ama0^Da1), 2);
		Bo = rol32((Abe0^De1), 23);
		Bu = rol32((Aki0^Di1), 31);
		Ba = rol32((Aso1^Do0), 14);
		Be = rol32((Agu0^Du0), 10);
		Ama0 =   Ba ^((~Be)&  Bi );
		Abe0 =   Be ^((~Bi)&  Bo );
		Aki0 =   Bi ^((~Bo)&  Bu );
		Aso1 =   Bo ^((~Bu)&  Ba );
		Agu0 =   Bu ^((~Ba)&  Be );

		Bi = rol32((Ama1^Da0), 1);
		Bo = rol32((Abe1^De0), 22);
		Bu = rol32((Aki1^Di0), 30);
		Ba = rol32((Aso0^Do1), 14);
		Be = rol32((Agu1^Du1), 10);
		Ama1 =   Ba ^((~Be)&  Bi );
		Abe1 =   Be ^((~Bi)&  Bo );
		Aki1 =   Bi ^((~Bo)&  Bu );
		Aso0 =   Bo ^((~Bu)&  Ba );
		Agu1 =   Bu ^((~Ba)&  Be );

		Bu = rol32((Aga1^Da0), 9);
		Ba = rol32((Ame0^De1), 1);
		Be = rol32((Abi1^Di0), 3);
		Bi = rol32((Ako1^Do1), 13);
		Bo = rol32((Asu1^Du0), 4);
		Aga1 =   Ba ^((~Be)&  Bi );
		Ame0 =   Be ^((~Bi)&  Bo );
		Abi1 =   Bi ^((~Bo)&  Bu );
		Ako1 =   Bo ^((~Bu)&  Ba );
		Asu1 =   Bu ^((~Ba)&  Be );

		Bu = rol32((Aga0^Da1), 9);
		Ba = (Ame1^De0);
		Be = rol32((Abi0^Di1), 3);
		Bi = rol32((Ako0^Do0), 12);
		Bo = rol32((Asu0^Du1), 4);
		Aga0 =   Ba ^((~Be)&  Bi );
		Ame1 =   Be ^((~Bi)&  Bo );
		Abi0 =   Bi ^((~Bo)&  Bu );
		Ako0 =   Bo ^((~Bu)&  Ba );
		Asu0 =   Bu ^((~Ba)&  Be );

		Be = rol32((Asa1^Da0), 18);
		Bi = rol32((Age1^De0), 5);
		Bo = rol32((Ami1^Di1), 8);
		Bu = rol32((Abo1^Do0), 28);
		Ba = rol32((Aku0^Du1), 14);
		Asa1 =   Ba ^((~Be)&  Bi );
		Age1 =   Be ^((~Bi)&  Bo );
		Ami1 =   Bi ^((~Bo)&  Bu );
		Abo1 =   Bo ^((~Bu)&  Ba );
		Aku0 =   Bu ^((~Ba)&  Be );

		Be = rol32((Asa0^Da1), 18);
		Bi = rol32((Age0^De1), 5);
		Bo = rol32((Ami0^Di0), 7);
		Bu = rol32((Abo0^Do1), 28);
		Ba = rol32((Aku1^Du0), 13);
		Asa0 =   Ba ^((~Be)&  Bi );
		Age0 =   Be ^((~Bi)&  Bo );
		Ami0 =   Bi ^((~Bo)&  Bu );
		Abo0 =   Bo ^((~Bu)&  Ba );
		Aku1 =   Bu ^((~Ba)&  Be );

		Bo = rol32((Aka0^Da1), 21);
		Bu = rol32((Ase0^De0), 1);
		Ba = rol32((Agi1^Di0), 31);
		Be = rol32((Amo0^Do1), 28);
		Bi = rol32((Abu0^Du1), 20);
		Aka0 =   Ba ^((~Be)&  Bi );
		Ase0 =   Be ^((~Bi)&  Bo );
		Agi1 =   Bi ^((~Bo)&  Bu );
		Amo0 =   Bo ^((~Bu)&  Ba );
		Abu0 =   Bu ^((~Ba)&  Be );

		Bo = rol32((Aka1^Da0), 20);
		Bu = rol32((Ase1^De1), 1);
		Ba = rol32((Agi0^Di1), 31);
		Be = rol32((Amo1^Do0), 27);
		Bi = rol32((Abu1^Du0), 19);
		Aka1 =   Ba ^((~Be)&  Bi );
		Ase1 =   Be ^((~Bi)&  Bo );
		Agi0 =   Bi ^((~Bo)&  Bu );
		Amo1 =   Bo ^((~Bu)&  Ba );
		Abu1 =   Bu ^((~Ba)&  Be );

		KeccakAtoD_round3();

		Ba = (Aba0^Da0);
		Be = rol32((Abe0^De0), 22);
		Bi = rol32((Abi0^Di1), 22);
		Bo = rol32((Abo0^Do1), 11);
		Bu = rol32((Abu0^Du0), 7);
		Aba0 =   Ba ^((~Be)&  Bi );
		Aba0 ^= RoundConstants32[i+6];
		Abe0 =   Be ^((~Bi)&  Bo );
		Abi0 =   Bi ^((~Bo)&  Bu );
		Abo0 =   Bo ^((~Bu)&  Ba );
		Abu0 =   Bu ^((~Ba)&  Be );

		Ba = (Aba1^Da1);
		Be = rol32((Abe1^De1), 22);
		Bi = rol32((Abi1^Di0), 21);
		Bo = rol32((Abo1^Do0), 10);
		Bu = rol32((Abu1^Du1), 7);
		Aba1 =   Ba ^((~Be)&  Bi );
		Aba1 ^= RoundConstants32[i+7];
		Abe1 =   Be ^((~Bi)&  Bo );
		Abi1 =   Bi ^((~Bo)&  Bu );
		Abo1 =   Bo ^((~Bu)&  Ba );
		Abu1 =   Bu ^((~Ba)&  Be );

		Bi = rol32((Aga0^Da1), 2);
		Bo = rol32((Age0^De1), 23);
		Bu = rol32((Agi0^Di1), 31);
		Ba = rol32((Ago0^Do0), 14);
		Be = rol32((Agu0^Du0), 10);
		Aga0 =   Ba ^((~Be)&  Bi );
		Age0 =   Be ^((~Bi)&  Bo );
		Agi0 =   Bi ^((~Bo)&  Bu );
		Ago0 =   Bo ^((~Bu)&  Ba );
		Agu0 =   Bu ^((~Ba)&  Be );

		Bi = rol32((Aga1^Da0), 1);
		Bo = rol32((Age1^De0), 22);
		Bu = rol32((Agi1^Di0), 30);
		Ba = rol32((Ago1^Do1), 14);
		Be = rol32((Agu1^Du1), 10);
		Aga1 =   Ba ^((~Be)&  Bi );
		Age1 =   Be ^((~Bi)&  Bo );
		Agi1 =   Bi ^((~Bo)&  Bu );
		Ago1 =   Bo ^((~Bu)&  Ba );
		Agu1 =   Bu ^((~Ba)&  Be );

		Bu = rol32((Aka0^Da0), 9);
		Ba = rol32((Ake0^De1), 1);
		Be = rol32((Aki0^Di0), 3);
		Bi = rol32((Ako0^Do1), 13);
		Bo = rol32((Aku0^Du0), 4);
		Aka0 =   Ba ^((~Be)&  Bi );
		Ake0 =   Be ^((~Bi)&  Bo );
		Aki0 =   Bi ^((~Bo)&  Bu );
		Ako0 =   Bo ^((~Bu)&  Ba );
		Aku0 =   Bu ^((~Ba)&  Be );

		Bu = rol32((Aka1^Da1), 9);
		Ba = (Ake1^De0);
		Be = rol32((Aki1^Di1), 3);
		Bi = rol32((Ako1^Do0), 12);
		Bo = rol32((Aku1^Du1), 4);
		Aka1 =   Ba ^((~Be)&  Bi );
		Ake1 =   Be ^((~Bi)&  Bo );
		Aki1 =   Bi ^((~Bo)&  Bu );
		Ako1 =   Bo ^((~Bu)&  Ba );
		Aku1 =   Bu ^((~Ba)&  Be );

		Be = rol32((Ama0^Da0), 18);
		Bi = rol32((Ame0^De0), 5);
		Bo = rol32((Ami0^Di1), 8);
		Bu = rol32((Amo0^Do0), 28);
		Ba = rol32((Amu0^Du1), 14);
		Ama0 =   Ba ^((~Be)&  Bi );
		Ame0 =   Be ^((~Bi)&  Bo );
		Ami0 =   Bi ^((~Bo)&  Bu );
		Amo0 =   Bo ^((~Bu)&  Ba );
		Amu0 =   Bu ^((~Ba)&  Be );

		Be = rol32((Ama1^Da1), 18);
		Bi = rol32((Ame1^De1), 5);
		Bo = rol32((Ami1^Di0), 7);
		Bu = rol32((Amo1^Do1), 28);
		Ba = rol32((Amu1^Du0), 13);
		Ama1 =   Ba ^((~Be)&  Bi );
		Ame1 =   Be ^((~Bi)&  Bo );
		Ami1 =   Bi ^((~Bo)&  Bu );
		Amo1 =   Bo ^((~Bu)&  Ba );
		Amu1 =   Bu ^((~Ba)&  Be );

		Bo = rol32((Asa0^Da1), 21);
		Bu = rol32((Ase0^De0), 1);
		Ba = rol32((Asi0^Di0), 31);
		Be = rol32((Aso0^Do1), 28);
		Bi = rol32((Asu0^Du1), 20);
		Asa0 =   Ba ^((~Be)&  Bi );
		Ase0 =   Be ^((~Bi)&  Bo );
		Asi0 =   Bi ^((~Bo)&  Bu );
		Aso0 =   Bo ^((~Bu)&  Ba );
		Asu0 =   Bu ^((~Ba)&  Be );

		Bo = rol32((Asa1^Da0), 20);
		Bu = rol32((Ase1^De1), 1);
		Ba = rol32((Asi1^Di1), 31);
		Be = rol32((Aso1^Do0), 27);
		Bi = rol32((Asu1^Du0), 19);
		Asa1 =   Ba ^((~Be)&  Bi );
		Ase1 =   Be ^((~Bi)&  Bo );
		Asi1 =   Bi ^((~Bo)&  Bu );
		Aso1 =   Bo ^((~Bu)&  Ba );
		Asu1 =   Bu ^((~Ba)&  Be );
	}
}

static void xor_lane(struct KeccakContext *ctx, int lane, uint64_t val)
{
	uint32_t x0, x1, t;
	uint32_t *dst = ctx->u.state32 + lane*2;

	x0 = val;
	t = (x0 ^ (x0 >>  1)) & 0x22222222;  x0 = x0 ^ t ^ (t <<  1);
	t = (x0 ^ (x0 >>  2)) & 0x0C0C0C0C;  x0 = x0 ^ t ^ (t <<  2);
	t = (x0 ^ (x0 >>  4)) & 0x00F000F0;  x0 = x0 ^ t ^ (t <<  4);
	t = (x0 ^ (x0 >>  8)) & 0x0000FF00;  x0 = x0 ^ t ^ (t <<  8);
	x1 = val >> 32;
	t = (x1 ^ (x1 >>  1)) & 0x22222222;  x1 = x1 ^ t ^ (t <<  1);
	t = (x1 ^ (x1 >>  2)) & 0x0C0C0C0C;  x1 = x1 ^ t ^ (t <<  2);
	t = (x1 ^ (x1 >>  4)) & 0x00F000F0;  x1 = x1 ^ t ^ (t <<  4);
	t = (x1 ^ (x1 >>  8)) & 0x0000FF00;  x1 = x1 ^ t ^ (t <<  8);
	dst[0] ^= (x0 & 0x0000FFFF) | (x1 << 16);
	dst[1] ^= (x0 >> 16) | (x1 & 0xFFFF0000);
}

static void extract(uint8_t *dst, const struct KeccakContext *ctx, int laneCount)
{
	const uint32_t *src = ctx->u.state32;
	uint32_t t, x0, x1;

	while (laneCount--) {
		x0 = *src++;
		x1 = *src++;
		t = (x0 & 0x0000FFFF) | (x1 << 16);
		x1 = (x0 >> 16) | (x1 & 0xFFFF0000);
		x0 = t;
		t = (x0 ^ (x0 >>  8)) & 0x0000FF00;  x0 = x0 ^ t ^ (t <<  8);
		t = (x0 ^ (x0 >>  4)) & 0x00F000F0;  x0 = x0 ^ t ^ (t <<  4);
		t = (x0 ^ (x0 >>  2)) & 0x0C0C0C0C;  x0 = x0 ^ t ^ (t <<  2);
		t = (x0 ^ (x0 >>  1)) & 0x22222222;  x0 = x0 ^ t ^ (t <<  1);
		t = (x1 ^ (x1 >>  8)) & 0x0000FF00;  x1 = x1 ^ t ^ (t <<  8);
		t = (x1 ^ (x1 >>  4)) & 0x00F000F0;  x1 = x1 ^ t ^ (t <<  4);
		t = (x1 ^ (x1 >>  2)) & 0x0C0C0C0C;  x1 = x1 ^ t ^ (t <<  2);
		t = (x1 ^ (x1 >>  1)) & 0x22222222;  x1 = x1 ^ t ^ (t <<  1);
		le32enc(dst + 0, x0);
		le32enc(dst + 4, x1);
		dst += 8;
	}
}

#endif /* KECCAK_32BIT */


/*
 * Common code
 */

static void xor_byte(struct KeccakContext *ctx, int nbyte, uint8_t val)
{
	int o = nbyte / 8;
	int s = (nbyte % 8) * 8;

	xor_lane(ctx, o, (uint64_t)(val) << s);
}

static void add_bytes(struct KeccakContext *ctx, const uint8_t *p, unsigned int len)
{
	uint64_t w;
	unsigned int m = ctx->bytes % 8;

	/* partial word */
	if (m) {
		m = 8 - m;
		if (m > len)
			m = len;
		while (m--) {
			xor_byte(ctx, ctx->bytes++, *p++);
			len--;
		}
	}

	/* full words */
	while (len >= 8) {
		w = le64dec(p);
		xor_lane(ctx, ctx->bytes / 8, w);
		ctx->bytes += 8;
		p += 8;
		len -= 8;
	}

	/* partial word */
	while (len--)
		xor_byte(ctx, ctx->bytes++, *p++);
}

static void reset(struct KeccakContext *ctx, int rbytes, int obytes)
{
	memset(ctx, 0, sizeof(struct KeccakContext));
	ctx->rbytes = rbytes;
	ctx->obytes = obytes;
}

/*
 * Public API
 */

void keccak224_init(struct KeccakContext *ctx)
{
	reset(ctx, KECCAK224_BLOCK_SIZE, KECCAK224_DIGEST_LENGTH);
}

void keccak256_init(struct KeccakContext *ctx)
{
	reset(ctx, KECCAK256_BLOCK_SIZE, KECCAK256_DIGEST_LENGTH);
}

void keccak384_init(struct KeccakContext *ctx)
{
	reset(ctx, KECCAK384_BLOCK_SIZE, KECCAK384_DIGEST_LENGTH);
}

void keccak512_init(struct KeccakContext *ctx)
{
	reset(ctx, KECCAK512_BLOCK_SIZE, KECCAK512_DIGEST_LENGTH);
}

void keccak_stream_init(struct KeccakContext *ctx)
{
	reset(ctx, KECCAK_STREAM_BLOCK_SIZE, KECCAK_STREAM_DIGEST_LENGTH);
}

void keccak_update(struct KeccakContext *ctx, const void *data, unsigned int len)
{
	unsigned int n;
	const uint8_t *ptr = data;

	while (len > 0) {
		n = ctx->rbytes - ctx->bytes;
		if (n > len)
			n = len;
		add_bytes(ctx, ptr, n);
		ptr += n;
		len -= n;

		if (ctx->bytes == ctx->rbytes) {
			keccak_f(ctx);
			ctx->bytes = 0;
		}
	}
}

void keccak_final(struct KeccakContext *ctx, uint8_t *dst)
{
	if (!ctx->padded) {
		/* 2-bit padding, assumes bytes < rbytes */
		xor_byte(ctx, ctx->bytes, 0x01);
		xor_byte(ctx, ctx->rbytes - 1, 0x80);
		ctx->padded = 1;
	}

	keccak_f(ctx);

	if (ctx->obytes == KECCAK224_DIGEST_LENGTH) {
		/* 224-bit result uses partial words */
		uint8_t buf[KECCAK256_DIGEST_LENGTH];
		extract(buf, ctx, KECCAK256_DIGEST_LENGTH / 8);
		memcpy(dst, buf, KECCAK224_DIGEST_LENGTH);
		memset(buf, 0, sizeof(buf));
	} else {
		extract(dst, ctx, ctx->obytes / 8);
	}
}

/*
 * DigestInfo
 */

const struct DigestInfo *digest_KECCAK224(void)
{
	static const struct DigestInfo info = {
		(DigestInitFunc *)keccak224_init,
		(DigestUpdateFunc *)keccak_update,
		(DigestFinalFunc *)keccak_final,
		sizeof(struct KeccakContext),
		KECCAK224_DIGEST_LENGTH,
		KECCAK224_BLOCK_SIZE
	};
	return &info;
}

const struct DigestInfo *digest_KECCAK256(void)
{
	static const struct DigestInfo info = {
		(DigestInitFunc *)keccak256_init,
		(DigestUpdateFunc *)keccak_update,
		(DigestFinalFunc *)keccak_final,
		sizeof(struct KeccakContext),
		KECCAK256_DIGEST_LENGTH,
		KECCAK256_BLOCK_SIZE
	};
	return &info;
}

const struct DigestInfo *digest_KECCAK384(void)
{
	static const struct DigestInfo info = {
		(DigestInitFunc *)keccak384_init,
		(DigestUpdateFunc *)keccak_update,
		(DigestFinalFunc *)keccak_final,
		sizeof(struct KeccakContext),
		KECCAK384_DIGEST_LENGTH,
		KECCAK384_BLOCK_SIZE
	};
	return &info;
}

const struct DigestInfo *digest_KECCAK512(void)
{
	static const struct DigestInfo info = {
		(DigestInitFunc *)keccak512_init,
		(DigestUpdateFunc *)keccak_update,
		(DigestFinalFunc *)keccak_final,
		sizeof(struct KeccakContext),
		KECCAK512_DIGEST_LENGTH,
		KECCAK512_BLOCK_SIZE
	};
	return &info;
}

const struct DigestInfo *digest_KECCAK_STREAM(void)
{
	static const struct DigestInfo info = {
		(DigestInitFunc *)keccak_stream_init,
		(DigestUpdateFunc *)keccak_update,
		(DigestFinalFunc *)keccak_final,
		sizeof(struct KeccakContext),
		KECCAK_STREAM_DIGEST_LENGTH,
		KECCAK_STREAM_BLOCK_SIZE
	};
	return &info;
}

