/*
* This file is a part of Pcompress, a chunked parallel multi-
* algorithm lossless compression and decompression program.
*
* Copyright (C) 2012-2013 Moinak Ghosh. All rights reserved.
* Use is subject to license terms.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program.
* If not, see .
*
* moinakg@belenix.org, http://moinakg.wordpress.com/
*
*/
/*
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
#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; jrate/8);
#endif
KeccakAbsorb576bits(state->state, curData);
}
}
else
#endif
#ifdef ProvideFast832
if (state->rate == 832) {
for(j=0; jrate/8);
#endif
KeccakAbsorb832bits(state->state, curData);
}
}
else
#endif
#ifdef ProvideFast1024
if (state->rate == 1024) {
for(j=0; jrate/8);
#endif
KeccakAbsorb1024bits(state->state, curData);
}
}
else
#endif
#ifdef ProvideFast1088
if (state->rate == 1088) {
for(j=0; jrate/8);
#endif
KeccakAbsorb1088bits(state->state, curData);
}
}
else
#endif
#ifdef ProvideFast1152
if (state->rate == 1152) {
for(j=0; jrate/8);
#endif
KeccakAbsorb1152bits(state->state, curData);
}
}
else
#endif
#ifdef ProvideFast1344
if (state->rate == 1344) {
for(j=0; jrate/8);
#endif
KeccakAbsorb1344bits(state->state, curData);
}
}
else
#endif
{
for(j=0; jrate/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;
}