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 }