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 SnP_StaticInitialize(); 51 SnP_Initialize(state); 52 53 /* First, absorb whole blocks */ 54#ifdef SnP_FastLoop_Absorb 55 if (((rateInBytes % (SnP_width/200)) == 0) && (inputByteLen >= rateInBytes)) { 56 /* fast lane: whole lane rate */ 57 size_t j; 58 j = SnP_FastLoop_Absorb(state, rateInBytes/(SnP_width/200), curInput, inputByteLen); 59 curInput += j; 60 inputByteLen -= j; 61 } 62#endif 63 while(inputByteLen >= (size_t)rateInBytes) { 64 #ifdef KeccakReference 65 displayBytes(1, "Block to be absorbed", curInput, rateInBytes); 66 #endif 67 SnP_AddBytes(state, curInput, 0, rateInBytes); 68 SnP_Permute(state); 69 curInput += rateInBytes; 70 inputByteLen -= rateInBytes; 71 } 72 73 /* Then, absorb what remains */ 74 partialBlock = (unsigned int)inputByteLen; 75 #ifdef KeccakReference 76 displayBytes(1, "Block to be absorbed (part)", curInput, partialBlock); 77 #endif 78 SnP_AddBytes(state, curInput, 0, partialBlock); 79 80 /* Finally, absorb the suffix */ 81 #ifdef KeccakReference 82 { 83 unsigned char delimitedData1[1]; 84 delimitedData1[0] = suffix; 85 displayBytes(1, "Block to be absorbed (last few bits + first bit of padding)", delimitedData1, 1); 86 } 87 #endif 88 /* Last few bits, whose delimiter coincides with first bit of padding */ 89 SnP_AddByte(state, suffix, partialBlock); 90 /* If the first bit of padding is at position rate-1, we need a whole new block for the second bit of padding */ 91 if ((suffix >= 0x80) && (partialBlock == (rateInBytes-1))) 92 SnP_Permute(state); 93 /* Second bit of padding */ 94 SnP_AddByte(state, 0x80, rateInBytes-1); 95 #ifdef KeccakReference 96 { 97 unsigned char block[SnP_width/8]; 98 memset(block, 0, SnP_width/8); 99 block[rateInBytes-1] = 0x80; 100 displayBytes(1, "Second bit of padding", block, rateInBytes); 101 } 102 #endif 103 SnP_Permute(state); 104 #ifdef KeccakReference 105 displayText(1, "--- Switching to squeezing phase ---"); 106 #endif 107 108 /* First, output whole blocks */ 109 while(outputByteLen > (size_t)rateInBytes) { 110 SnP_ExtractBytes(state, curOutput, 0, rateInBytes); 111 SnP_Permute(state); 112 #ifdef KeccakReference 113 displayBytes(1, "Squeezed block", curOutput, rateInBytes); 114 #endif 115 curOutput += rateInBytes; 116 outputByteLen -= rateInBytes; 117 } 118 119 /* Finally, output what remains */ 120 partialBlock = (unsigned int)outputByteLen; 121 SnP_ExtractBytes(state, curOutput, 0, partialBlock); 122 #ifdef KeccakReference 123 displayBytes(1, "Squeezed block (part)", curOutput, partialBlock); 124 #endif 125 126 return 0; 127} 128 129/* ---------------------------------------------------------------- */ 130/* ---------------------------------------------------------------- */ 131/* ---------------------------------------------------------------- */ 132 133int SpongeInitialize(SpongeInstance *instance, unsigned int rate, unsigned int capacity) 134{ 135 if (rate+capacity != SnP_width) 136 return 1; 137 if ((rate <= 0) || (rate > SnP_width) || ((rate % 8) != 0)) 138 return 1; 139 SnP_StaticInitialize(); 140 SnP_Initialize(instance->state); 141 instance->rate = rate; 142 instance->byteIOIndex = 0; 143 instance->squeezing = 0; 144 145 return 0; 146} 147 148/* ---------------------------------------------------------------- */ 149 150int SpongeAbsorb(SpongeInstance *instance, const unsigned char *data, size_t dataByteLen) 151{ 152 size_t i, j; 153 unsigned int partialBlock; 154 const unsigned char *curData; 155 unsigned int rateInBytes = instance->rate/8; 156 157 if (instance->squeezing) 158 return 1; /* Too late for additional input */ 159 160 i = 0; 161 curData = data; 162 while(i < dataByteLen) { 163 if ((instance->byteIOIndex == 0) && (dataByteLen >= (i + rateInBytes))) { 164#ifdef SnP_FastLoop_Absorb 165 /* processing full blocks first */ 166 if ((rateInBytes % (SnP_width/200)) == 0) { 167 /* fast lane: whole lane rate */ 168 j = SnP_FastLoop_Absorb(instance->state, rateInBytes/(SnP_width/200), curData, dataByteLen - i); 169 i += j; 170 curData += j; 171 } 172 else { 173#endif 174 for(j=dataByteLen-i; j>=rateInBytes; j-=rateInBytes) { 175 #ifdef KeccakReference 176 displayBytes(1, "Block to be absorbed", curData, rateInBytes); 177 #endif 178 SnP_AddBytes(instance->state, curData, 0, rateInBytes); 179 SnP_Permute(instance->state); 180 curData+=rateInBytes; 181 } 182 i = dataByteLen - j; 183#ifdef SnP_FastLoop_Absorb 184 } 185#endif 186 } 187 else { 188 /* normal lane: using the message queue */ 189 partialBlock = (unsigned int)(dataByteLen - i); 190 if (partialBlock+instance->byteIOIndex > rateInBytes) 191 partialBlock = rateInBytes-instance->byteIOIndex; 192 #ifdef KeccakReference 193 displayBytes(1, "Block to be absorbed (part)", curData, partialBlock); 194 #endif 195 i += partialBlock; 196 197 SnP_AddBytes(instance->state, curData, instance->byteIOIndex, partialBlock); 198 curData += partialBlock; 199 instance->byteIOIndex += partialBlock; 200 if (instance->byteIOIndex == rateInBytes) { 201 SnP_Permute(instance->state); 202 instance->byteIOIndex = 0; 203 } 204 } 205 } 206 return 0; 207} 208 209/* ---------------------------------------------------------------- */ 210 211int SpongeAbsorbLastFewBits(SpongeInstance *instance, unsigned char delimitedData) 212{ 213 unsigned int rateInBytes = instance->rate/8; 214 215 if (delimitedData == 0) 216 return 1; 217 if (instance->squeezing) 218 return 1; /* Too late for additional input */ 219 220 #ifdef KeccakReference 221 { 222 unsigned char delimitedData1[1]; 223 delimitedData1[0] = delimitedData; 224 displayBytes(1, "Block to be absorbed (last few bits + first bit of padding)", delimitedData1, 1); 225 } 226 #endif 227 /* Last few bits, whose delimiter coincides with first bit of padding */ 228 SnP_AddByte(instance->state, delimitedData, instance->byteIOIndex); 229 /* If the first bit of padding is at position rate-1, we need a whole new block for the second bit of padding */ 230 if ((delimitedData >= 0x80) && (instance->byteIOIndex == (rateInBytes-1))) 231 SnP_Permute(instance->state); 232 /* Second bit of padding */ 233 SnP_AddByte(instance->state, 0x80, rateInBytes-1); 234 #ifdef KeccakReference 235 { 236 unsigned char block[SnP_width/8]; 237 memset(block, 0, SnP_width/8); 238 block[rateInBytes-1] = 0x80; 239 displayBytes(1, "Second bit of padding", block, rateInBytes); 240 } 241 #endif 242 SnP_Permute(instance->state); 243 instance->byteIOIndex = 0; 244 instance->squeezing = 1; 245 #ifdef KeccakReference 246 displayText(1, "--- Switching to squeezing phase ---"); 247 #endif 248 return 0; 249} 250 251/* ---------------------------------------------------------------- */ 252 253int SpongeSqueeze(SpongeInstance *instance, unsigned char *data, size_t dataByteLen) 254{ 255 size_t i, j; 256 unsigned int partialBlock; 257 unsigned int rateInBytes = instance->rate/8; 258 unsigned char *curData; 259 260 if (!instance->squeezing) 261 SpongeAbsorbLastFewBits(instance, 0x01); 262 263 i = 0; 264 curData = data; 265 while(i < dataByteLen) { 266 if ((instance->byteIOIndex == rateInBytes) && (dataByteLen >= (i + rateInBytes))) { 267 for(j=dataByteLen-i; j>=rateInBytes; j-=rateInBytes) { 268 SnP_Permute(instance->state); 269 SnP_ExtractBytes(instance->state, curData, 0, rateInBytes); 270 #ifdef KeccakReference 271 displayBytes(1, "Squeezed block", curData, rateInBytes); 272 #endif 273 curData+=rateInBytes; 274 } 275 i = dataByteLen - j; 276 } 277 else { 278 /* normal lane: using the message queue */ 279 if (instance->byteIOIndex == rateInBytes) { 280 SnP_Permute(instance->state); 281 instance->byteIOIndex = 0; 282 } 283 partialBlock = (unsigned int)(dataByteLen - i); 284 if (partialBlock+instance->byteIOIndex > rateInBytes) 285 partialBlock = rateInBytes-instance->byteIOIndex; 286 i += partialBlock; 287 288 SnP_ExtractBytes(instance->state, curData, instance->byteIOIndex, partialBlock); 289 #ifdef KeccakReference 290 displayBytes(1, "Squeezed block (part)", curData, partialBlock); 291 #endif 292 curData += partialBlock; 293 instance->byteIOIndex += partialBlock; 294 } 295 } 296 return 0; 297} 298 299/* ---------------------------------------------------------------- */ 300 301#undef Sponge 302#undef SpongeInstance 303#undef SpongeInitialize 304#undef SpongeAbsorb 305#undef SpongeAbsorbLastFewBits 306#undef SpongeSqueeze 307#undef SnP_stateSizeInBytes 308#undef SnP_stateAlignment 309#undef SnP_StaticInitialize 310#undef SnP_Initialize 311#undef SnP_AddByte 312#undef SnP_AddBytes 313#undef SnP_ExtractBytes 314