/ c_src / KeccakSponge.c
KeccakSponge.c
  1  /*
  2  The Keccak sponge function, designed by Guido Bertoni, Joan Daemen,
  3  Michaƫl Peeters and Gilles Van Assche. For more information, feedback or
  4  questions, please refer to our website: http://keccak.noekeon.org/
  5  
  6  Implementation by the designers,
  7  hereby denoted as "the implementer".
  8  
  9  To the extent possible under law, the implementer has waived all copyright
 10  and related or neighboring rights to the source code in this file.
 11  http://creativecommons.org/publicdomain/zero/1.0/
 12  */
 13  
 14  #include <string.h>
 15  #include "KeccakSponge.h"
 16  #include "KeccakF-1600-interface.h"
 17  #ifdef KeccakReference
 18  #include "displayIntermediateValues.h"
 19  #endif
 20  
 21  int InitSponge(spongeState *state, unsigned int rate, unsigned int capacity)
 22  {
 23      if (rate+capacity != 1600)
 24          return 1;
 25      if ((rate <= 0) || (rate >= 1600) || ((rate % 64) != 0))
 26          return 1;
 27      KeccakInitialize();
 28      state->rate = rate;
 29      state->capacity = capacity;
 30      state->fixedOutputLength = 0;
 31      KeccakInitializeState(state->state);
 32      memset(state->dataQueue, 0, KeccakMaximumRateInBytes);
 33      state->bitsInQueue = 0;
 34      state->squeezing = 0;
 35      state->bitsAvailableForSqueezing = 0;
 36  
 37      return 0;
 38  }
 39  
 40  static void AbsorbQueue(spongeState *state)
 41  {
 42      // state->bitsInQueue is assumed to be equal to state->rate
 43      #ifdef KeccakReference
 44      displayBytes(1, "Block to be absorbed", state->dataQueue, state->rate/8);
 45      #endif
 46  #ifdef ProvideFast576
 47      if (state->rate == 576)
 48          KeccakAbsorb576bits(state->state, state->dataQueue);
 49      else 
 50  #endif
 51  #ifdef ProvideFast832
 52      if (state->rate == 832)
 53          KeccakAbsorb832bits(state->state, state->dataQueue);
 54      else 
 55  #endif
 56  #ifdef ProvideFast1024
 57      if (state->rate == 1024)
 58          KeccakAbsorb1024bits(state->state, state->dataQueue);
 59      else 
 60  #endif
 61  #ifdef ProvideFast1088
 62      if (state->rate == 1088)
 63          KeccakAbsorb1088bits(state->state, state->dataQueue);
 64      else
 65  #endif
 66  #ifdef ProvideFast1152
 67      if (state->rate == 1152)
 68          KeccakAbsorb1152bits(state->state, state->dataQueue);
 69      else 
 70  #endif
 71  #ifdef ProvideFast1344
 72      if (state->rate == 1344)
 73          KeccakAbsorb1344bits(state->state, state->dataQueue);
 74      else 
 75  #endif
 76          KeccakAbsorb(state->state, state->dataQueue, state->rate/64);
 77      state->bitsInQueue = 0;
 78  }
 79  
 80  int Absorb(spongeState *state, const unsigned char *data, unsigned long long databitlen)
 81  {
 82      unsigned long long i, j, wholeBlocks;
 83      unsigned int partialBlock, partialByte;
 84      const unsigned char *curData;
 85  
 86      if ((state->bitsInQueue % 8) != 0)
 87          return 1; // Only the last call may contain a partial byte
 88      if (state->squeezing)
 89          return 1; // Too late for additional input
 90  
 91      i = 0;
 92      while(i < databitlen) {
 93          if ((state->bitsInQueue == 0) && (databitlen >= state->rate) && (i <= (databitlen-state->rate))) {
 94              wholeBlocks = (databitlen-i)/state->rate;
 95              curData = data+i/8;
 96  #ifdef ProvideFast576
 97              if (state->rate == 576) {
 98                  for(j=0; j<wholeBlocks; j++, curData+=576/8) {
 99                      #ifdef KeccakReference
100                      displayBytes(1, "Block to be absorbed", curData, state->rate/8);
101                      #endif
102                      KeccakAbsorb576bits(state->state, curData);
103                  }
104              }
105              else
106  #endif
107  #ifdef ProvideFast832
108              if (state->rate == 832) {
109                  for(j=0; j<wholeBlocks; j++, curData+=832/8) {
110                      #ifdef KeccakReference
111                      displayBytes(1, "Block to be absorbed", curData, state->rate/8);
112                      #endif
113                      KeccakAbsorb832bits(state->state, curData);
114                  }
115              }
116              else
117  #endif
118  #ifdef ProvideFast1024
119              if (state->rate == 1024) {
120                  for(j=0; j<wholeBlocks; j++, curData+=1024/8) {
121                      #ifdef KeccakReference
122                      displayBytes(1, "Block to be absorbed", curData, state->rate/8);
123                      #endif
124                      KeccakAbsorb1024bits(state->state, curData);
125                  }
126              }
127              else
128  #endif
129  #ifdef ProvideFast1088
130              if (state->rate == 1088) {
131                  for(j=0; j<wholeBlocks; j++, curData+=1088/8) {
132                      #ifdef KeccakReference
133                      displayBytes(1, "Block to be absorbed", curData, state->rate/8);
134                      #endif
135                      KeccakAbsorb1088bits(state->state, curData);
136                  }
137              }
138              else
139  #endif
140  #ifdef ProvideFast1152
141              if (state->rate == 1152) {
142                  for(j=0; j<wholeBlocks; j++, curData+=1152/8) {
143                      #ifdef KeccakReference
144                      displayBytes(1, "Block to be absorbed", curData, state->rate/8);
145                      #endif
146                      KeccakAbsorb1152bits(state->state, curData);
147                  }
148              }
149              else
150  #endif
151  #ifdef ProvideFast1344
152              if (state->rate == 1344) {
153                  for(j=0; j<wholeBlocks; j++, curData+=1344/8) {
154                      #ifdef KeccakReference
155                      displayBytes(1, "Block to be absorbed", curData, state->rate/8);
156                      #endif
157                      KeccakAbsorb1344bits(state->state, curData);
158                  }
159              }
160              else
161  #endif
162              {
163                  for(j=0; j<wholeBlocks; j++, curData+=state->rate/8) {
164                      #ifdef KeccakReference
165                      displayBytes(1, "Block to be absorbed", curData, state->rate/8);
166                      #endif
167                      KeccakAbsorb(state->state, curData, state->rate/64);
168                  }
169              }
170              i += wholeBlocks*state->rate;
171          }
172          else {
173              partialBlock = (unsigned int)(databitlen - i);
174              if (partialBlock+state->bitsInQueue > state->rate)
175                  partialBlock = state->rate-state->bitsInQueue;
176              partialByte = partialBlock % 8;
177              partialBlock -= partialByte;
178              memcpy(state->dataQueue+state->bitsInQueue/8, data+i/8, partialBlock/8);
179              state->bitsInQueue += partialBlock;
180              i += partialBlock;
181              if (state->bitsInQueue == state->rate)
182                  AbsorbQueue(state);
183              if (partialByte > 0) {
184                  unsigned char mask = (1 << partialByte)-1;
185                  state->dataQueue[state->bitsInQueue/8] = data[i/8] & mask;
186                  state->bitsInQueue += partialByte;
187                  i += partialByte;
188              }
189          }
190      }
191      return 0;
192  }
193  
194  static void PadAndSwitchToSqueezingPhase(spongeState *state)
195  {
196      // Note: the bits are numbered from 0=LSB to 7=MSB
197      if (state->bitsInQueue + 1 == state->rate) {
198          state->dataQueue[state->bitsInQueue/8 ] |= 1 << (state->bitsInQueue % 8);
199          AbsorbQueue(state);
200          memset(state->dataQueue, 0, state->rate/8);
201      }
202      else {
203          memset(state->dataQueue + (state->bitsInQueue+7)/8, 0, state->rate/8 - (state->bitsInQueue+7)/8);
204          state->dataQueue[state->bitsInQueue/8 ] |= 1 << (state->bitsInQueue % 8);
205      }
206      state->dataQueue[(state->rate-1)/8] |= 1 << ((state->rate-1) % 8);
207      AbsorbQueue(state);
208  
209      #ifdef KeccakReference
210      displayText(1, "--- Switching to squeezing phase ---");
211      #endif
212  #ifdef ProvideFast1024
213      if (state->rate == 1024) {
214          KeccakExtract1024bits(state->state, state->dataQueue);
215          state->bitsAvailableForSqueezing = 1024;
216      }
217      else
218  #endif
219      {
220          KeccakExtract(state->state, state->dataQueue, state->rate/64);
221          state->bitsAvailableForSqueezing = state->rate;
222      }
223      #ifdef KeccakReference
224      displayBytes(1, "Block available for squeezing", state->dataQueue, state->bitsAvailableForSqueezing/8);
225      #endif
226      state->squeezing = 1;
227  }
228  
229  int Squeeze(spongeState *state, unsigned char *output, unsigned long long outputLength)
230  {
231      unsigned long long i;
232      unsigned int partialBlock;
233  
234      if (!state->squeezing)
235          PadAndSwitchToSqueezingPhase(state);
236      if ((outputLength % 8) != 0)
237          return 1; // Only multiple of 8 bits are allowed, truncation can be done at user level
238  
239      i = 0;
240      while(i < outputLength) {
241          if (state->bitsAvailableForSqueezing == 0) {
242              KeccakPermutation(state->state);
243  #ifdef ProvideFast1024
244              if (state->rate == 1024) {
245                  KeccakExtract1024bits(state->state, state->dataQueue);
246                  state->bitsAvailableForSqueezing = 1024;
247              }
248              else
249  #endif
250              {
251                  KeccakExtract(state->state, state->dataQueue, state->rate/64);
252                  state->bitsAvailableForSqueezing = state->rate;
253              }
254              #ifdef KeccakReference
255              displayBytes(1, "Block available for squeezing", state->dataQueue, state->bitsAvailableForSqueezing/8);
256              #endif
257          }
258          partialBlock = state->bitsAvailableForSqueezing;
259          if ((unsigned long long)partialBlock > outputLength - i)
260              partialBlock = (unsigned int)(outputLength - i);
261          memcpy(output+i/8, state->dataQueue+(state->rate-state->bitsAvailableForSqueezing)/8, partialBlock/8);
262          state->bitsAvailableForSqueezing -= partialBlock;
263          i += partialBlock;
264      }
265      return 0;
266  }