--- /dev/null
+/*
+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 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/
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include "brg_endian.h"
+#include "displayIntermediateValues.h"
+#include "KeccakNISTInterface.h"
+#include "KeccakF-1600-interface.h"
+
+typedef unsigned char UINT8;
+typedef unsigned long long int UINT64;
+
+#define nrRounds 24
+UINT64 KeccakRoundConstants[nrRounds];
+#define nrLanes 25
+unsigned int KeccakRhoOffsets[nrLanes];
+
+void KeccakPermutationOnWords(UINT64 *state);
+void theta(UINT64 *A);
+void rho(UINT64 *A);
+void pi(UINT64 *A);
+void chi(UINT64 *A);
+void iota(UINT64 *A, unsigned int indexRound);
+
+void fromBytesToWords(UINT64 *stateAsWords, const unsigned char *state)
+{
+ unsigned int i, j;
+
+ for(i=0; i<(KeccakPermutationSize/64); i++) {
+ stateAsWords[i] = 0;
+ for(j=0; j<(64/8); j++)
+ stateAsWords[i] |= (UINT64)(state[i*(64/8)+j]) << (8*j);
+ }
+}
+
+void fromWordsToBytes(unsigned char *state, const UINT64 *stateAsWords)
+{
+ unsigned int i, j;
+
+ for(i=0; i<(KeccakPermutationSize/64); i++)
+ for(j=0; j<(64/8); j++)
+ state[i*(64/8)+j] = (stateAsWords[i] >> (8*j)) & 0xFF;
+}
+
+void KeccakPermutation(unsigned char *state)
+{
+#if (PLATFORM_BYTE_ORDER != IS_LITTLE_ENDIAN)
+ UINT64 stateAsWords[KeccakPermutationSize/64];
+#endif
+
+ displayStateAsBytes(1, "Input of permutation", state);
+#if (PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN)
+ KeccakPermutationOnWords((UINT64*)state);
+#else
+ fromBytesToWords(stateAsWords, state);
+ KeccakPermutationOnWords(stateAsWords);
+ fromWordsToBytes(state, stateAsWords);
+#endif
+ displayStateAsBytes(1, "State after permutation", state);
+}
+
+void KeccakPermutationAfterXor(unsigned char *state, const unsigned char *data, unsigned int dataLengthInBytes)
+{
+ unsigned int i;
+
+ for(i=0; i<dataLengthInBytes; i++)
+ state[i] ^= data[i];
+ KeccakPermutation(state);
+}
+
+void KeccakPermutationOnWords(UINT64 *state)
+{
+ unsigned int i;
+
+ displayStateAs64bitWords(3, "Same, with lanes as 64-bit words", state);
+
+ for(i=0; i<nrRounds; i++) {
+ displayRoundNumber(3, i);
+
+ theta(state);
+ displayStateAs64bitWords(3, "After theta", state);
+
+ rho(state);
+ displayStateAs64bitWords(3, "After rho", state);
+
+ pi(state);
+ displayStateAs64bitWords(3, "After pi", state);
+
+ chi(state);
+ displayStateAs64bitWords(3, "After chi", state);
+
+ iota(state, i);
+ displayStateAs64bitWords(3, "After iota", state);
+ }
+}
+
+#define index(x, y) (((x)%5)+5*((y)%5))
+#define ROL64(a, offset) ((offset != 0) ? ((((UINT64)a) << offset) ^ (((UINT64)a) >> (64-offset))) : a)
+
+void theta(UINT64 *A)
+{
+ unsigned int x, y;
+ UINT64 C[5], D[5];
+
+ for(x=0; x<5; x++) {
+ C[x] = 0;
+ for(y=0; y<5; y++)
+ C[x] ^= A[index(x, y)];
+ }
+ for(x=0; x<5; x++)
+ D[x] = ROL64(C[(x+1)%5], 1) ^ C[(x+4)%5];
+ for(x=0; x<5; x++)
+ for(y=0; y<5; y++)
+ A[index(x, y)] ^= D[x];
+}
+
+void rho(UINT64 *A)
+{
+ unsigned int x, y;
+
+ for(x=0; x<5; x++) for(y=0; y<5; y++)
+ A[index(x, y)] = ROL64(A[index(x, y)], KeccakRhoOffsets[index(x, y)]);
+}
+
+void pi(UINT64 *A)
+{
+ unsigned int x, y;
+ UINT64 tempA[25];
+
+ for(x=0; x<5; x++) for(y=0; y<5; y++)
+ tempA[index(x, y)] = A[index(x, y)];
+ for(x=0; x<5; x++) for(y=0; y<5; y++)
+ A[index(0*x+1*y, 2*x+3*y)] = tempA[index(x, y)];
+}
+
+void chi(UINT64 *A)
+{
+ unsigned int x, y;
+ UINT64 C[5];
+
+ for(y=0; y<5; y++) {
+ for(x=0; x<5; x++)
+ C[x] = A[index(x, y)] ^ ((~A[index(x+1, y)]) & A[index(x+2, y)]);
+ for(x=0; x<5; x++)
+ A[index(x, y)] = C[x];
+ }
+}
+
+void iota(UINT64 *A, unsigned int indexRound)
+{
+ A[index(0, 0)] ^= KeccakRoundConstants[indexRound];
+}
+
+int LFSR86540(UINT8 *LFSR)
+{
+ int result = ((*LFSR) & 0x01) != 0;
+ if (((*LFSR) & 0x80) != 0)
+ // Primitive polynomial over GF(2): x^8+x^6+x^5+x^4+1
+ (*LFSR) = ((*LFSR) << 1) ^ 0x71;
+ else
+ (*LFSR) <<= 1;
+ return result;
+}
+
+void KeccakInitializeRoundConstants()
+{
+ UINT8 LFSRstate = 0x01;
+ unsigned int i, j, bitPosition;
+
+ for(i=0; i<nrRounds; i++) {
+ KeccakRoundConstants[i] = 0;
+ for(j=0; j<7; j++) {
+ bitPosition = (1<<j)-1; //2^j-1
+ if (LFSR86540(&LFSRstate))
+ KeccakRoundConstants[i] ^= (UINT64)1<<bitPosition;
+ }
+ }
+}
+
+void KeccakInitializeRhoOffsets()
+{
+ unsigned int x, y, t, newX, newY;
+
+ KeccakRhoOffsets[index(0, 0)] = 0;
+ x = 1;
+ y = 0;
+ for(t=0; t<24; t++) {
+ KeccakRhoOffsets[index(x, y)] = ((t+1)*(t+2)/2) % 64;
+ newX = (0*x+1*y) % 5;
+ newY = (2*x+3*y) % 5;
+ x = newX;
+ y = newY;
+ }
+}
+
+void KeccakInitialize()
+{
+ KeccakInitializeRoundConstants();
+ KeccakInitializeRhoOffsets();
+}
+
+void displayRoundConstants(FILE *f)
+{
+ unsigned int i;
+
+ for(i=0; i<nrRounds; i++) {
+ fprintf(f, "RC[%02i][0][0] = ", i);
+ fprintf(f, "%08X", (unsigned int)(KeccakRoundConstants[i] >> 32));
+ fprintf(f, "%08X", (unsigned int)(KeccakRoundConstants[i] & 0xFFFFFFFFULL));
+ fprintf(f, "\n");
+ }
+ fprintf(f, "\n");
+}
+
+void displayRhoOffsets(FILE *f)
+{
+ unsigned int x, y;
+
+ for(y=0; y<5; y++) for(x=0; x<5; x++) {
+ fprintf(f, "RhoOffset[%i][%i] = ", x, y);
+ fprintf(f, "%2i", KeccakRhoOffsets[index(x, y)]);
+ fprintf(f, "\n");
+ }
+ fprintf(f, "\n");
+}
+
+void KeccakInitializeState(unsigned char *state)
+{
+ memset(state, 0, KeccakPermutationSizeInBytes);
+}
+
+#ifdef ProvideFast576
+void KeccakAbsorb576bits(unsigned char *state, const unsigned char *data)
+{
+ KeccakPermutationAfterXor(state, data, 72);
+}
+#endif
+
+#ifdef ProvideFast832
+void KeccakAbsorb832bits(unsigned char *state, const unsigned char *data)
+{
+ KeccakPermutationAfterXor(state, data, 104);
+}
+#endif
+
+#ifdef ProvideFast1024
+void KeccakAbsorb1024bits(unsigned char *state, const unsigned char *data)
+{
+ KeccakPermutationAfterXor(state, data, 128);
+}
+#endif
+
+#ifdef ProvideFast1088
+void KeccakAbsorb1088bits(unsigned char *state, const unsigned char *data)
+{
+ KeccakPermutationAfterXor(state, data, 136);
+}
+#endif
+
+#ifdef ProvideFast1152
+void KeccakAbsorb1152bits(unsigned char *state, const unsigned char *data)
+{
+ KeccakPermutationAfterXor(state, data, 144);
+}
+#endif
+
+#ifdef ProvideFast1344
+void KeccakAbsorb1344bits(unsigned char *state, const unsigned char *data)
+{
+ KeccakPermutationAfterXor(state, data, 168);
+}
+#endif
+
+void KeccakAbsorb(unsigned char *state, const unsigned char *data, unsigned int laneCount)
+{
+ KeccakPermutationAfterXor(state, data, laneCount*8);
+}
+
+#ifdef ProvideFast1024
+void KeccakExtract1024bits(const unsigned char *state, unsigned char *data)
+{
+ memcpy(data, state, 128);
+}
+#endif
+
+void KeccakExtract(const unsigned char *state, unsigned char *data, unsigned int laneCount)
+{
+ memcpy(data, state, laneCount*8);
+}
--- /dev/null
+/*
+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 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/
+*/
+
+#include <string.h>
+#include "KeccakSponge.h"
+#include "KeccakF-1600-interface.h"
+#ifdef KeccakReference
+#include "displayIntermediateValues.h"
+#endif
+
+int InitSponge(spongeState *state, unsigned int rate, unsigned int capacity)
+{
+ if (rate+capacity != 1600)
+ return 1;
+ if ((rate <= 0) || (rate >= 1600) || ((rate % 64) != 0))
+ return 1;
+ KeccakInitialize();
+ state->rate = rate;
+ state->capacity = capacity;
+ state->fixedOutputLength = 0;
+ KeccakInitializeState(state->state);
+ memset(state->dataQueue, 0, KeccakMaximumRateInBytes);
+ state->bitsInQueue = 0;
+ state->squeezing = 0;
+ state->bitsAvailableForSqueezing = 0;
+
+ return 0;
+}
+
+void AbsorbQueue(spongeState *state)
+{
+ // state->bitsInQueue is assumed to be equal to state->rate
+ #ifdef KeccakReference
+ displayBytes(1, "Block to be absorbed", state->dataQueue, state->rate/8);
+ #endif
+#ifdef ProvideFast576
+ if (state->rate == 576)
+ KeccakAbsorb576bits(state->state, state->dataQueue);
+ else
+#endif
+#ifdef ProvideFast832
+ if (state->rate == 832)
+ KeccakAbsorb832bits(state->state, state->dataQueue);
+ else
+#endif
+#ifdef ProvideFast1024
+ if (state->rate == 1024)
+ KeccakAbsorb1024bits(state->state, state->dataQueue);
+ else
+#endif
+#ifdef ProvideFast1088
+ if (state->rate == 1088)
+ KeccakAbsorb1088bits(state->state, state->dataQueue);
+ else
+#endif
+#ifdef ProvideFast1152
+ if (state->rate == 1152)
+ KeccakAbsorb1152bits(state->state, state->dataQueue);
+ else
+#endif
+#ifdef ProvideFast1344
+ if (state->rate == 1344)
+ KeccakAbsorb1344bits(state->state, state->dataQueue);
+ else
+#endif
+ KeccakAbsorb(state->state, state->dataQueue, state->rate/64);
+ state->bitsInQueue = 0;
+}
+
+int Absorb(spongeState *state, const unsigned char *data, unsigned long long databitlen)
+{
+ unsigned long long i, j, wholeBlocks;
+ unsigned int partialBlock, partialByte;
+ const unsigned char *curData;
+
+ if ((state->bitsInQueue % 8) != 0)
+ return 1; // Only the last call may contain a partial byte
+ if (state->squeezing)
+ return 1; // Too late for additional input
+
+ i = 0;
+ while(i < databitlen) {
+ if ((state->bitsInQueue == 0) && (databitlen >= state->rate) && (i <= (databitlen-state->rate))) {
+ wholeBlocks = (databitlen-i)/state->rate;
+ curData = data+i/8;
+#ifdef ProvideFast576
+ if (state->rate == 576) {
+ for(j=0; j<wholeBlocks; j++, curData+=576/8) {
+ #ifdef KeccakReference
+ displayBytes(1, "Block to be absorbed", curData, state->rate/8);
+ #endif
+ KeccakAbsorb576bits(state->state, curData);
+ }
+ }
+ else
+#endif
+#ifdef ProvideFast832
+ if (state->rate == 832) {
+ for(j=0; j<wholeBlocks; j++, curData+=832/8) {
+ #ifdef KeccakReference
+ displayBytes(1, "Block to be absorbed", curData, state->rate/8);
+ #endif
+ KeccakAbsorb832bits(state->state, curData);
+ }
+ }
+ else
+#endif
+#ifdef ProvideFast1024
+ if (state->rate == 1024) {
+ for(j=0; j<wholeBlocks; j++, curData+=1024/8) {
+ #ifdef KeccakReference
+ displayBytes(1, "Block to be absorbed", curData, state->rate/8);
+ #endif
+ KeccakAbsorb1024bits(state->state, curData);
+ }
+ }
+ else
+#endif
+#ifdef ProvideFast1088
+ if (state->rate == 1088) {
+ for(j=0; j<wholeBlocks; j++, curData+=1088/8) {
+ #ifdef KeccakReference
+ displayBytes(1, "Block to be absorbed", curData, state->rate/8);
+ #endif
+ KeccakAbsorb1088bits(state->state, curData);
+ }
+ }
+ else
+#endif
+#ifdef ProvideFast1152
+ if (state->rate == 1152) {
+ for(j=0; j<wholeBlocks; j++, curData+=1152/8) {
+ #ifdef KeccakReference
+ displayBytes(1, "Block to be absorbed", curData, state->rate/8);
+ #endif
+ KeccakAbsorb1152bits(state->state, curData);
+ }
+ }
+ else
+#endif
+#ifdef ProvideFast1344
+ if (state->rate == 1344) {
+ for(j=0; j<wholeBlocks; j++, curData+=1344/8) {
+ #ifdef KeccakReference
+ displayBytes(1, "Block to be absorbed", curData, state->rate/8);
+ #endif
+ KeccakAbsorb1344bits(state->state, curData);
+ }
+ }
+ else
+#endif
+ {
+ for(j=0; j<wholeBlocks; j++, curData+=state->rate/8) {
+ #ifdef KeccakReference
+ displayBytes(1, "Block to be absorbed", curData, state->rate/8);
+ #endif
+ KeccakAbsorb(state->state, curData, state->rate/64);
+ }
+ }
+ i += wholeBlocks*state->rate;
+ }
+ else {
+ partialBlock = (unsigned int)(databitlen - i);
+ if (partialBlock+state->bitsInQueue > state->rate)
+ partialBlock = state->rate-state->bitsInQueue;
+ partialByte = partialBlock % 8;
+ partialBlock -= partialByte;
+ memcpy(state->dataQueue+state->bitsInQueue/8, data+i/8, partialBlock/8);
+ state->bitsInQueue += partialBlock;
+ i += partialBlock;
+ if (state->bitsInQueue == state->rate)
+ AbsorbQueue(state);
+ if (partialByte > 0) {
+ unsigned char mask = (1 << partialByte)-1;
+ state->dataQueue[state->bitsInQueue/8] = data[i/8] & mask;
+ state->bitsInQueue += partialByte;
+ i += partialByte;
+ }
+ }
+ }
+ return 0;
+}
+
+void PadAndSwitchToSqueezingPhase(spongeState *state)
+{
+ // Note: the bits are numbered from 0=LSB to 7=MSB
+ if (state->bitsInQueue + 1 == state->rate) {
+ state->dataQueue[state->bitsInQueue/8 ] |= 1 << (state->bitsInQueue % 8);
+ AbsorbQueue(state);
+ memset(state->dataQueue, 0, state->rate/8);
+ }
+ else {
+ memset(state->dataQueue + (state->bitsInQueue+7)/8, 0, state->rate/8 - (state->bitsInQueue+7)/8);
+ state->dataQueue[state->bitsInQueue/8 ] |= 1 << (state->bitsInQueue % 8);
+ }
+ state->dataQueue[(state->rate-1)/8] |= 1 << ((state->rate-1) % 8);
+ AbsorbQueue(state);
+
+ #ifdef KeccakReference
+ displayText(1, "--- Switching to squeezing phase ---");
+ #endif
+#ifdef ProvideFast1024
+ if (state->rate == 1024) {
+ KeccakExtract1024bits(state->state, state->dataQueue);
+ state->bitsAvailableForSqueezing = 1024;
+ }
+ else
+#endif
+ {
+ KeccakExtract(state->state, state->dataQueue, state->rate/64);
+ state->bitsAvailableForSqueezing = state->rate;
+ }
+ #ifdef KeccakReference
+ displayBytes(1, "Block available for squeezing", state->dataQueue, state->bitsAvailableForSqueezing/8);
+ #endif
+ state->squeezing = 1;
+}
+
+int Squeeze(spongeState *state, unsigned char *output, unsigned long long outputLength)
+{
+ unsigned long long i;
+ unsigned int partialBlock;
+
+ if (!state->squeezing)
+ PadAndSwitchToSqueezingPhase(state);
+ if ((outputLength % 8) != 0)
+ return 1; // Only multiple of 8 bits are allowed, truncation can be done at user level
+
+ i = 0;
+ while(i < outputLength) {
+ if (state->bitsAvailableForSqueezing == 0) {
+ KeccakPermutation(state->state);
+#ifdef ProvideFast1024
+ if (state->rate == 1024) {
+ KeccakExtract1024bits(state->state, state->dataQueue);
+ state->bitsAvailableForSqueezing = 1024;
+ }
+ else
+#endif
+ {
+ KeccakExtract(state->state, state->dataQueue, state->rate/64);
+ state->bitsAvailableForSqueezing = state->rate;
+ }
+ #ifdef KeccakReference
+ displayBytes(1, "Block available for squeezing", state->dataQueue, state->bitsAvailableForSqueezing/8);
+ #endif
+ }
+ partialBlock = state->bitsAvailableForSqueezing;
+ if ((unsigned long long)partialBlock > outputLength - i)
+ partialBlock = (unsigned int)(outputLength - i);
+ memcpy(output+i/8, state->dataQueue+(state->rate-state->bitsAvailableForSqueezing)/8, partialBlock/8);
+ state->bitsAvailableForSqueezing -= partialBlock;
+ i += partialBlock;
+ }
+ return 0;
+}
--- /dev/null
+.PHONY: all
+
+all:
+ gcc -o krem-keccak -Wall -Werror -g -std=c99 krem_keccak.c -Wno-unused
--- /dev/null
+/*
+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 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/
+*/
+
+#include <stdio.h>
+#include "displayIntermediateValues.h"
+#include "KeccakNISTInterface.h"
+
+FILE *intermediateValueFile = 0;
+int displayLevel = 0;
+
+void displaySetIntermediateValueFile(FILE *f)
+{
+ intermediateValueFile = f;
+}
+
+void displaySetLevel(int level)
+{
+ displayLevel = level;
+}
+
+void displayBytes(int level, const char *text, const unsigned char *bytes, unsigned int size)
+{
+ unsigned int i;
+
+ if ((intermediateValueFile) && (level <= displayLevel)) {
+ fprintf(intermediateValueFile, "%s:\n", text);
+ for(i=0; i<size; i++)
+ fprintf(intermediateValueFile, "%02X ", bytes[i]);
+ fprintf(intermediateValueFile, "\n");
+ fprintf(intermediateValueFile, "\n");
+ }
+}
+
+void displayBits(int level, const char *text, const unsigned char *data, unsigned int size, int MSBfirst)
+{
+ unsigned int i, iByte, iBit;
+
+ if ((intermediateValueFile) && (level <= displayLevel)) {
+ fprintf(intermediateValueFile, "%s:\n", text);
+ for(i=0; i<size; i++) {
+ iByte = i/8;
+ iBit = i%8;
+ if (MSBfirst)
+ fprintf(intermediateValueFile, "%d ", ((data[iByte] << iBit) & 0x80) != 0);
+ else
+ fprintf(intermediateValueFile, "%d ", ((data[iByte] >> iBit) & 0x01) != 0);
+ }
+ fprintf(intermediateValueFile, "\n");
+ fprintf(intermediateValueFile, "\n");
+ }
+}
+
+void displayStateAsBytes(int level, const char *text, const unsigned char *state)
+{
+ displayBytes(level, text, state, KeccakPermutationSizeInBytes);
+}
+
+void displayStateAs32bitWords(int level, const char *text, const unsigned int *state)
+{
+ unsigned int i;
+
+ if ((intermediateValueFile) && (level <= displayLevel)) {
+ fprintf(intermediateValueFile, "%s:\n", text);
+ for(i=0; i<KeccakPermutationSize/64; i++) {
+ fprintf(intermediateValueFile, "%08X:%08X", (unsigned int)state[2*i+0], (unsigned int)state[2*i+1]);
+ if ((i%5) == 4)
+ fprintf(intermediateValueFile, "\n");
+ else
+ fprintf(intermediateValueFile, " ");
+ }
+ }
+}
+
+void displayStateAs64bitWords(int level, const char *text, const unsigned long long int *state)
+{
+ unsigned int i;
+
+ if ((intermediateValueFile) && (level <= displayLevel)) {
+ fprintf(intermediateValueFile, "%s:\n", text);
+ for(i=0; i<KeccakPermutationSize/64; i++) {
+ fprintf(intermediateValueFile, "%08X", (unsigned int)(state[i] >> 32));
+ fprintf(intermediateValueFile, "%08X", (unsigned int)(state[i] & 0xFFFFFFFFULL));
+ if ((i%5) == 4)
+ fprintf(intermediateValueFile, "\n");
+ else
+ fprintf(intermediateValueFile, " ");
+ }
+ }
+}
+
+void displayRoundNumber(int level, unsigned int i)
+{
+ if ((intermediateValueFile) && (level <= displayLevel)) {
+ fprintf(intermediateValueFile, "\n");
+ fprintf(intermediateValueFile, "--- Round %d ---\n", i);
+ fprintf(intermediateValueFile, "\n");
+ }
+}
+
+void displayText(int level, const char *text)
+{
+ if ((intermediateValueFile) && (level <= displayLevel)) {
+ fprintf(intermediateValueFile, text);
+ fprintf(intermediateValueFile, "\n");
+ fprintf(intermediateValueFile, "\n");
+ }
+}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "../keccak-ref/Sources/KeccakSponge.c"
+#include "../keccak-ref/Sources/KeccakF-1600-reference.c"
+#include "../keccak-ref/Sources/displayIntermediateValues.c"
+
+#define HI_NIBBLE(b) (((b) >> 4) & 0x0F)
+#define LO_NIBBLE(b) ((b) & 0x0F)
+
+int main(int argc, char *argv[]) {
+
+ unsigned int r, c, i;
+ spongeState *state;
+
+ FILE *input;
+ struct stat input_stat;
+ unsigned char *input_buf, *output_buf;
+ size_t input_bytes_read;
+
+ if(argc != 2) {
+
+ printf("no input file provided\nUSAGE: %s <file>\n", argv[0]);
+ exit(1);
+
+ } else if( ! (input = fopen(argv[1], "r"))) {
+
+ printf("error opening file '%s'\n", argv[1]);
+ exit(1);
+ }
+
+ /* significant values */
+ r = 576;
+ c = 1024;
+
+ state = (spongeState*) calloc(1, sizeof(spongeState));
+
+ if(stat(argv[1], &input_stat) || input_stat.st_size <= 0) {
+
+ printf("failed to stat '%s'\n", argv[1]);
+ exit(1);
+
+ } else if(InitSponge(state, r, c) || !state) {
+
+ printf("error during sponge construction\n");
+ exit(1);
+
+ } else if(input_stat.st_size > SIZE_MAX) {
+
+ printf("large files not supported yet\n");
+ exit(1);
+ }
+
+ input_buf = (unsigned char *) calloc(1, (size_t) input_stat.st_size);
+ output_buf = (unsigned char *) calloc(1, (size_t) 64);
+
+ if( ! (input_bytes_read = fread(input_buf, 1, (size_t)input_stat.st_size, input))) {
+
+ printf("error reading file\n");
+ exit(1);
+ }
+
+ fclose(input);
+
+ if(Absorb(state, input_buf, (unsigned long long) (8 * input_stat.st_size))) {
+
+ printf("encryption failure\n");
+ exit(1);
+
+ } else if(Squeeze(state, output_buf, (unsigned long long) (8 * input_stat.st_size))) {
+
+ printf("decryption failure\n");
+ exit(1);
+ }
+
+ i = 0;
+ for(; i < 64; i++)
+ printf("%x%x", HI_NIBBLE(output_buf[i]), LO_NIBBLE(output_buf[i]));
+
+ free(state);
+
+ return 0;
+}