static 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 Duplexing(duplexState *state, const unsigned char *in, unsigned int inBitLen, unsigned char *out, unsigned int outBitLen, unsigned int rounds) { KECCAK_ALIGN unsigned char block[KeccakPermutationSizeInBytes]; if (inBitLen > state->rho_max) return 1; if ((inBitLen % 8) != 0) { unsigned char mask = ~((1 << (inBitLen % 8)) - 1); if ((in[inBitLen/8] & mask) != 0) return 1; // The bits of the last incomplete byte must be aligned on the LSB } if (outBitLen > state->rate) return 1; // The output length must not be greater than the rate memcpy(block, in, (inBitLen+7)/8); memset(block+(inBitLen+7)/8, 0, ((state->rate+63)/64)*8 - (inBitLen+7)/8); block[inBitLen/8] |= 1 << (inBitLen%8); block[(state->rate-1)/8] |= 1 << ((state->rate-1) % 8); #ifdef KeccakReference displayBytes(1, "Block to be absorbed (after padding)", block, (state->rate+7)/8); #endif KeccakAbsorb(state->state, block, (state->rate+63)/64, rounds); KeccakExtract(state->state, block, (state->rate+63)/64); memcpy(out, block, (outBitLen+7)/8); if ((outBitLen % 8) != 0) { unsigned char mask = (1 << (outBitLen % 8)) - 1; out[outBitLen/8] &= mask; } return 0; }
static 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; }