blob: e10739deafa836d571fb46fc4eed98f75b1dc00e [file] [log] [blame]
/*
Implementation by the Keccak, Keyak and Ketje Teams, namely, Guido Bertoni,
Joan Daemen, Michaƫl Peeters, Gilles Van Assche and Ronny Van Keer, hereby
denoted as "the implementer".
For more information, feedback or questions, please refer to our websites:
http://keccak.noekeon.org/
http://keyak.noekeon.org/
http://ketje.noekeon.org/
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/
*/
#define JOIN0(a, b) a ## b
#define JOIN(a, b) JOIN0(a, b)
#define Sponge JOIN(prefix, _Sponge)
#define SpongeInstance JOIN(prefix, _SpongeInstance)
#define SpongeInitialize JOIN(prefix, _SpongeInitialize)
#define SpongeAbsorb JOIN(prefix, _SpongeAbsorb)
#define SpongeAbsorbLastFewBits JOIN(prefix, _SpongeAbsorbLastFewBits)
#define SpongeSqueeze JOIN(prefix, _SpongeSqueeze)
#define SnP_stateSizeInBytes JOIN(SnP, _stateSizeInBytes)
#define SnP_stateAlignment JOIN(SnP, _stateAlignment)
#define SnP_StaticInitialize JOIN(SnP, _StaticInitialize)
#define SnP_Initialize JOIN(SnP, _Initialize)
#define SnP_AddByte JOIN(SnP, _AddByte)
#define SnP_AddBytes JOIN(SnP, _AddBytes)
#define SnP_ExtractBytes JOIN(SnP, _ExtractBytes)
int Sponge(unsigned int rate, unsigned int capacity, const unsigned char *input, size_t inputByteLen, unsigned char suffix, unsigned char *output, size_t outputByteLen)
{
ALIGN(SnP_stateAlignment) unsigned char state[SnP_stateSizeInBytes];
unsigned int partialBlock;
const unsigned char *curInput = input;
unsigned char *curOutput = output;
unsigned int rateInBytes = rate/8;
if (rate+capacity != SnP_width)
return 1;
if ((rate <= 0) || (rate > SnP_width) || ((rate % 8) != 0))
return 1;
if (suffix == 0)
return 1;
/* Initialize the state */
SnP_StaticInitialize();
SnP_Initialize(state);
/* First, absorb whole blocks */
#ifdef SnP_FastLoop_Absorb
if (((rateInBytes % (SnP_width/200)) == 0) && (inputByteLen >= rateInBytes)) {
/* fast lane: whole lane rate */
size_t j;
j = SnP_FastLoop_Absorb(state, rateInBytes/(SnP_width/200), curInput, inputByteLen);
curInput += j;
inputByteLen -= j;
}
#endif
while(inputByteLen >= (size_t)rateInBytes) {
#ifdef KeccakReference
displayBytes(1, "Block to be absorbed", curInput, rateInBytes);
#endif
SnP_AddBytes(state, curInput, 0, rateInBytes);
SnP_Permute(state);
curInput += rateInBytes;
inputByteLen -= rateInBytes;
}
/* Then, absorb what remains */
partialBlock = (unsigned int)inputByteLen;
#ifdef KeccakReference
displayBytes(1, "Block to be absorbed (part)", curInput, partialBlock);
#endif
SnP_AddBytes(state, curInput, 0, partialBlock);
/* Finally, absorb the suffix */
#ifdef KeccakReference
{
unsigned char delimitedData1[1];
delimitedData1[0] = suffix;
displayBytes(1, "Block to be absorbed (last few bits + first bit of padding)", delimitedData1, 1);
}
#endif
/* Last few bits, whose delimiter coincides with first bit of padding */
SnP_AddByte(state, suffix, partialBlock);
/* If the first bit of padding is at position rate-1, we need a whole new block for the second bit of padding */
if ((suffix >= 0x80) && (partialBlock == (rateInBytes-1)))
SnP_Permute(state);
/* Second bit of padding */
SnP_AddByte(state, 0x80, rateInBytes-1);
#ifdef KeccakReference
{
unsigned char block[SnP_width/8];
memset(block, 0, SnP_width/8);
block[rateInBytes-1] = 0x80;
displayBytes(1, "Second bit of padding", block, rateInBytes);
}
#endif
SnP_Permute(state);
#ifdef KeccakReference
displayText(1, "--- Switching to squeezing phase ---");
#endif
/* First, output whole blocks */
while(outputByteLen > (size_t)rateInBytes) {
SnP_ExtractBytes(state, curOutput, 0, rateInBytes);
SnP_Permute(state);
#ifdef KeccakReference
displayBytes(1, "Squeezed block", curOutput, rateInBytes);
#endif
curOutput += rateInBytes;
outputByteLen -= rateInBytes;
}
/* Finally, output what remains */
partialBlock = (unsigned int)outputByteLen;
SnP_ExtractBytes(state, curOutput, 0, partialBlock);
#ifdef KeccakReference
displayBytes(1, "Squeezed block (part)", curOutput, partialBlock);
#endif
return 0;
}
/* ---------------------------------------------------------------- */
/* ---------------------------------------------------------------- */
/* ---------------------------------------------------------------- */
int SpongeInitialize(SpongeInstance *instance, unsigned int rate, unsigned int capacity)
{
if (rate+capacity != SnP_width)
return 1;
if ((rate <= 0) || (rate > SnP_width) || ((rate % 8) != 0))
return 1;
SnP_StaticInitialize();
SnP_Initialize(instance->state);
instance->rate = rate;
instance->byteIOIndex = 0;
instance->squeezing = 0;
return 0;
}
/* ---------------------------------------------------------------- */
int SpongeAbsorb(SpongeInstance *instance, const unsigned char *data, size_t dataByteLen)
{
size_t i, j;
unsigned int partialBlock;
const unsigned char *curData;
unsigned int rateInBytes = instance->rate/8;
if (instance->squeezing)
return 1; /* Too late for additional input */
i = 0;
curData = data;
while(i < dataByteLen) {
if ((instance->byteIOIndex == 0) && (dataByteLen >= (i + rateInBytes))) {
#ifdef SnP_FastLoop_Absorb
/* processing full blocks first */
if ((rateInBytes % (SnP_width/200)) == 0) {
/* fast lane: whole lane rate */
j = SnP_FastLoop_Absorb(instance->state, rateInBytes/(SnP_width/200), curData, dataByteLen - i);
i += j;
curData += j;
}
else {
#endif
for(j=dataByteLen-i; j>=rateInBytes; j-=rateInBytes) {
#ifdef KeccakReference
displayBytes(1, "Block to be absorbed", curData, rateInBytes);
#endif
SnP_AddBytes(instance->state, curData, 0, rateInBytes);
SnP_Permute(instance->state);
curData+=rateInBytes;
}
i = dataByteLen - j;
#ifdef SnP_FastLoop_Absorb
}
#endif
}
else {
/* normal lane: using the message queue */
partialBlock = (unsigned int)(dataByteLen - i);
if (partialBlock+instance->byteIOIndex > rateInBytes)
partialBlock = rateInBytes-instance->byteIOIndex;
#ifdef KeccakReference
displayBytes(1, "Block to be absorbed (part)", curData, partialBlock);
#endif
i += partialBlock;
SnP_AddBytes(instance->state, curData, instance->byteIOIndex, partialBlock);
curData += partialBlock;
instance->byteIOIndex += partialBlock;
if (instance->byteIOIndex == rateInBytes) {
SnP_Permute(instance->state);
instance->byteIOIndex = 0;
}
}
}
return 0;
}
/* ---------------------------------------------------------------- */
int SpongeAbsorbLastFewBits(SpongeInstance *instance, unsigned char delimitedData)
{
unsigned int rateInBytes = instance->rate/8;
if (delimitedData == 0)
return 1;
if (instance->squeezing)
return 1; /* Too late for additional input */
#ifdef KeccakReference
{
unsigned char delimitedData1[1];
delimitedData1[0] = delimitedData;
displayBytes(1, "Block to be absorbed (last few bits + first bit of padding)", delimitedData1, 1);
}
#endif
/* Last few bits, whose delimiter coincides with first bit of padding */
SnP_AddByte(instance->state, delimitedData, instance->byteIOIndex);
/* If the first bit of padding is at position rate-1, we need a whole new block for the second bit of padding */
if ((delimitedData >= 0x80) && (instance->byteIOIndex == (rateInBytes-1)))
SnP_Permute(instance->state);
/* Second bit of padding */
SnP_AddByte(instance->state, 0x80, rateInBytes-1);
#ifdef KeccakReference
{
unsigned char block[SnP_width/8];
memset(block, 0, SnP_width/8);
block[rateInBytes-1] = 0x80;
displayBytes(1, "Second bit of padding", block, rateInBytes);
}
#endif
SnP_Permute(instance->state);
instance->byteIOIndex = 0;
instance->squeezing = 1;
#ifdef KeccakReference
displayText(1, "--- Switching to squeezing phase ---");
#endif
return 0;
}
/* ---------------------------------------------------------------- */
int SpongeSqueeze(SpongeInstance *instance, unsigned char *data, size_t dataByteLen)
{
size_t i, j;
unsigned int partialBlock;
unsigned int rateInBytes = instance->rate/8;
unsigned char *curData;
if (!instance->squeezing)
SpongeAbsorbLastFewBits(instance, 0x01);
i = 0;
curData = data;
while(i < dataByteLen) {
if ((instance->byteIOIndex == rateInBytes) && (dataByteLen >= (i + rateInBytes))) {
for(j=dataByteLen-i; j>=rateInBytes; j-=rateInBytes) {
SnP_Permute(instance->state);
SnP_ExtractBytes(instance->state, curData, 0, rateInBytes);
#ifdef KeccakReference
displayBytes(1, "Squeezed block", curData, rateInBytes);
#endif
curData+=rateInBytes;
}
i = dataByteLen - j;
}
else {
/* normal lane: using the message queue */
if (instance->byteIOIndex == rateInBytes) {
SnP_Permute(instance->state);
instance->byteIOIndex = 0;
}
partialBlock = (unsigned int)(dataByteLen - i);
if (partialBlock+instance->byteIOIndex > rateInBytes)
partialBlock = rateInBytes-instance->byteIOIndex;
i += partialBlock;
SnP_ExtractBytes(instance->state, curData, instance->byteIOIndex, partialBlock);
#ifdef KeccakReference
displayBytes(1, "Squeezed block (part)", curData, partialBlock);
#endif
curData += partialBlock;
instance->byteIOIndex += partialBlock;
}
}
return 0;
}
/* ---------------------------------------------------------------- */
#undef Sponge
#undef SpongeInstance
#undef SpongeInitialize
#undef SpongeAbsorb
#undef SpongeAbsorbLastFewBits
#undef SpongeSqueeze
#undef SnP_stateSizeInBytes
#undef SnP_stateAlignment
#undef SnP_StaticInitialize
#undef SnP_Initialize
#undef SnP_AddByte
#undef SnP_AddBytes
#undef SnP_ExtractBytes