1/* 2Implementation by the Keccak, Keyak and Ketje Teams, namely, Guido Bertoni, 3Joan Daemen, Michaël Peeters, Gilles Van Assche and Ronny Van Keer, hereby 4denoted as "the implementer". 5 6For more information, feedback or questions, please refer to our websites: 7http://keccak.noekeon.org/ 8http://keyak.noekeon.org/ 9http://ketje.noekeon.org/ 10 11To the extent possible under law, the implementer has waived all copyright 12and related or neighboring rights to the source code in this file. 13http://creativecommons.org/publicdomain/zero/1.0/ 14*/ 15 16#define JOIN0(a, b) a ## b 17#define JOIN(a, b) JOIN0(a, b) 18 19#define Sponge JOIN(prefix, _Sponge) 20#define SpongeInstance JOIN(prefix, _SpongeInstance) 21#define SpongeInitialize JOIN(prefix, _SpongeInitialize) 22#define SpongeAbsorb JOIN(prefix, _SpongeAbsorb) 23#define SpongeAbsorbLastFewBits JOIN(prefix, _SpongeAbsorbLastFewBits) 24#define SpongeSqueeze JOIN(prefix, _SpongeSqueeze) 25 26#define SnP_stateSizeInBytes JOIN(SnP, _stateSizeInBytes) 27#define SnP_stateAlignment JOIN(SnP, _stateAlignment) 28#define SnP_StaticInitialize JOIN(SnP, _StaticInitialize) 29#define SnP_Initialize JOIN(SnP, _Initialize) 30#define SnP_AddByte JOIN(SnP, _AddByte) 31#define SnP_AddBytes JOIN(SnP, _AddBytes) 32#define SnP_ExtractBytes JOIN(SnP, _ExtractBytes) 33 34int Sponge(unsigned int rate, unsigned int capacity, const unsigned char *input, size_t inputByteLen, unsigned char suffix, unsigned char *output, size_t outputByteLen) 35{ 36 ALIGN(SnP_stateAlignment) unsigned char state[SnP_stateSizeInBytes]; 37 unsigned int partialBlock; 38 const unsigned char *curInput = input; 39 unsigned char *curOutput = output; 40 unsigned int rateInBytes = rate/8; 41 42 if (rate+capacity != SnP_width) 43 return 1; 44 if ((rate <= 0) || (rate > SnP_width) || ((rate % 8) != 0)) 45 return 1; 46 if (suffix == 0) 47 return 1; 48 49 /* Initialize the state */ 50 51 SnP_StaticInitialize(); 52 SnP_Initialize(state); 53 54 /* First, absorb whole blocks */ 55 56#ifdef SnP_FastLoop_Absorb 57 if (((rateInBytes % (SnP_width/200)) == 0) && (inputByteLen >= rateInBytes)) { 58 /* fast lane: whole lane rate */ 59 60 size_t j; 61 j = SnP_FastLoop_Absorb(state, rateInBytes/(SnP_width/200), curInput, inputByteLen); 62 curInput += j; 63 inputByteLen -= j; 64 } 65#endif 66 while(inputByteLen >= (size_t)rateInBytes) { 67 #ifdef KeccakReference 68 displayBytes(1, "Block to be absorbed", curInput, rateInBytes); 69 #endif 70 SnP_AddBytes(state, curInput, 0, rateInBytes); 71 SnP_Permute(state); 72 curInput += rateInBytes; 73 inputByteLen -= rateInBytes; 74 } 75 76 /* Then, absorb what remains */ 77 78 partialBlock = (unsigned int)inputByteLen; 79 #ifdef KeccakReference 80 displayBytes(1, "Block to be absorbed (part)", curInput, partialBlock); 81 #endif 82 SnP_AddBytes(state, curInput, 0, partialBlock); 83 84 /* Finally, absorb the suffix */ 85 86 #ifdef KeccakReference 87 { 88 unsigned char delimitedData1[1]; 89 delimitedData1[0] = suffix; 90 displayBytes(1, "Block to be absorbed (last few bits + first bit of padding)", delimitedData1, 1); 91 } 92 #endif 93 /* Last few bits, whose delimiter coincides with first bit of padding */ 94 95 SnP_AddByte(state, suffix, partialBlock); 96 /* If the first bit of padding is at position rate-1, we need a whole new block for the second bit of padding */ 97 98 if ((suffix >= 0x80) && (partialBlock == (rateInBytes-1))) 99 SnP_Permute(state); 100 /* Second bit of padding */ 101 102 SnP_AddByte(state, 0x80, rateInBytes-1); 103 #ifdef KeccakReference 104 { 105 unsigned char block[SnP_width/8]; 106 memset(block, 0, SnP_width/8); 107 block[rateInBytes-1] = 0x80; 108 displayBytes(1, "Second bit of padding", block, rateInBytes); 109 } 110 #endif 111 SnP_Permute(state); 112 #ifdef KeccakReference 113 displayText(1, "--- Switching to squeezing phase ---"); 114 #endif 115 116 /* First, output whole blocks */ 117 118 while(outputByteLen > (size_t)rateInBytes) { 119 SnP_ExtractBytes(state, curOutput, 0, rateInBytes); 120 SnP_Permute(state); 121 #ifdef KeccakReference 122 displayBytes(1, "Squeezed block", curOutput, rateInBytes); 123 #endif 124 curOutput += rateInBytes; 125 outputByteLen -= rateInBytes; 126 } 127 128 /* Finally, output what remains */ 129 130 partialBlock = (unsigned int)outputByteLen; 131 SnP_ExtractBytes(state, curOutput, 0, partialBlock); 132 #ifdef KeccakReference 133 displayBytes(1, "Squeezed block (part)", curOutput, partialBlock); 134 #endif 135 136 return 0; 137} 138 139/* ---------------------------------------------------------------- */ 140/* ---------------------------------------------------------------- */ 141/* ---------------------------------------------------------------- */ 142 143int SpongeInitialize(SpongeInstance *instance, unsigned int rate, unsigned int capacity) 144{ 145 if (rate+capacity != SnP_width) 146 return 1; 147 if ((rate <= 0) || (rate > SnP_width) || ((rate % 8) != 0)) 148 return 1; 149 SnP_StaticInitialize(); 150 SnP_Initialize(instance->state); 151 instance->rate = rate; 152 instance->byteIOIndex = 0; 153 instance->squeezing = 0; 154 155 return 0; 156} 157 158/* ---------------------------------------------------------------- */ 159 160int SpongeAbsorb(SpongeInstance *instance, const unsigned char *data, size_t dataByteLen) 161{ 162 size_t i, j; 163 unsigned int partialBlock; 164 const unsigned char *curData; 165 unsigned int rateInBytes = instance->rate/8; 166 167 if (instance->squeezing) 168 return 1; /* Too late for additional input */ 169 170 171 i = 0; 172 curData = data; 173 while(i < dataByteLen) { 174 if ((instance->byteIOIndex == 0) && (dataByteLen >= (i + rateInBytes))) { 175#ifdef SnP_FastLoop_Absorb 176 /* processing full blocks first */ 177 178 if ((rateInBytes % (SnP_width/200)) == 0) { 179 /* fast lane: whole lane rate */ 180 181 j = SnP_FastLoop_Absorb(instance->state, rateInBytes/(SnP_width/200), curData, dataByteLen - i); 182 i += j; 183 curData += j; 184 } 185 else { 186#endif 187 for(j=dataByteLen-i; j>=rateInBytes; j-=rateInBytes) { 188 #ifdef KeccakReference 189 displayBytes(1, "Block to be absorbed", curData, rateInBytes); 190 #endif 191 SnP_AddBytes(instance->state, curData, 0, rateInBytes); 192 SnP_Permute(instance->state); 193 curData+=rateInBytes; 194 } 195 i = dataByteLen - j; 196#ifdef SnP_FastLoop_Absorb 197 } 198#endif 199 } 200 else { 201 /* normal lane: using the message queue */ 202 203 partialBlock = (unsigned int)(dataByteLen - i); 204 if (partialBlock+instance->byteIOIndex > rateInBytes) 205 partialBlock = rateInBytes-instance->byteIOIndex; 206 #ifdef KeccakReference 207 displayBytes(1, "Block to be absorbed (part)", curData, partialBlock); 208 #endif 209 i += partialBlock; 210 211 SnP_AddBytes(instance->state, curData, instance->byteIOIndex, partialBlock); 212 curData += partialBlock; 213 instance->byteIOIndex += partialBlock; 214 if (instance->byteIOIndex == rateInBytes) { 215 SnP_Permute(instance->state); 216 instance->byteIOIndex = 0; 217 } 218 } 219 } 220 return 0; 221} 222 223/* ---------------------------------------------------------------- */ 224 225int SpongeAbsorbLastFewBits(SpongeInstance *instance, unsigned char delimitedData) 226{ 227 unsigned int rateInBytes = instance->rate/8; 228 229 if (delimitedData == 0) 230 return 1; 231 if (instance->squeezing) 232 return 1; /* Too late for additional input */ 233 234 235 #ifdef KeccakReference 236 { 237 unsigned char delimitedData1[1]; 238 delimitedData1[0] = delimitedData; 239 displayBytes(1, "Block to be absorbed (last few bits + first bit of padding)", delimitedData1, 1); 240 } 241 #endif 242 /* Last few bits, whose delimiter coincides with first bit of padding */ 243 244 SnP_AddByte(instance->state, delimitedData, instance->byteIOIndex); 245 /* If the first bit of padding is at position rate-1, we need a whole new block for the second bit of padding */ 246 247 if ((delimitedData >= 0x80) && (instance->byteIOIndex == (rateInBytes-1))) 248 SnP_Permute(instance->state); 249 /* Second bit of padding */ 250 251 SnP_AddByte(instance->state, 0x80, rateInBytes-1); 252 #ifdef KeccakReference 253 { 254 unsigned char block[SnP_width/8]; 255 memset(block, 0, SnP_width/8); 256 block[rateInBytes-1] = 0x80; 257 displayBytes(1, "Second bit of padding", block, rateInBytes); 258 } 259 #endif 260 SnP_Permute(instance->state); 261 instance->byteIOIndex = 0; 262 instance->squeezing = 1; 263 #ifdef KeccakReference 264 displayText(1, "--- Switching to squeezing phase ---"); 265 #endif 266 return 0; 267} 268 269/* ---------------------------------------------------------------- */ 270 271int SpongeSqueeze(SpongeInstance *instance, unsigned char *data, size_t dataByteLen) 272{ 273 size_t i, j; 274 unsigned int partialBlock; 275 unsigned int rateInBytes = instance->rate/8; 276 unsigned char *curData; 277 278 if (!instance->squeezing) 279 SpongeAbsorbLastFewBits(instance, 0x01); 280 281 i = 0; 282 curData = data; 283 while(i < dataByteLen) { 284 if ((instance->byteIOIndex == rateInBytes) && (dataByteLen >= (i + rateInBytes))) { 285 for(j=dataByteLen-i; j>=rateInBytes; j-=rateInBytes) { 286 SnP_Permute(instance->state); 287 SnP_ExtractBytes(instance->state, curData, 0, rateInBytes); 288 #ifdef KeccakReference 289 displayBytes(1, "Squeezed block", curData, rateInBytes); 290 #endif 291 curData+=rateInBytes; 292 } 293 i = dataByteLen - j; 294 } 295 else { 296 /* normal lane: using the message queue */ 297 298 if (instance->byteIOIndex == rateInBytes) { 299 SnP_Permute(instance->state); 300 instance->byteIOIndex = 0; 301 } 302 partialBlock = (unsigned int)(dataByteLen - i); 303 if (partialBlock+instance->byteIOIndex > rateInBytes) 304 partialBlock = rateInBytes-instance->byteIOIndex; 305 i += partialBlock; 306 307 SnP_ExtractBytes(instance->state, curData, instance->byteIOIndex, partialBlock); 308 #ifdef KeccakReference 309 displayBytes(1, "Squeezed block (part)", curData, partialBlock); 310 #endif 311 curData += partialBlock; 312 instance->byteIOIndex += partialBlock; 313 } 314 } 315 return 0; 316} 317 318/* ---------------------------------------------------------------- */ 319 320#undef Sponge 321#undef SpongeInstance 322#undef SpongeInitialize 323#undef SpongeAbsorb 324#undef SpongeAbsorbLastFewBits 325#undef SpongeSqueeze 326#undef SnP_stateSizeInBytes 327#undef SnP_stateAlignment 328#undef SnP_StaticInitialize 329#undef SnP_Initialize 330#undef SnP_AddByte 331#undef SnP_AddBytes 332#undef SnP_ExtractBytes 333