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 if (dataByteLen-i > rateInBytes-instance->byteIOIndex) 190 partialBlock = rateInBytes-instance->byteIOIndex; 191 else 192 partialBlock = (unsigned int)(dataByteLen - i); 193 #ifdef KeccakReference 194 displayBytes(1, "Block to be absorbed (part)", curData, partialBlock); 195 #endif 196 i += partialBlock; 197 198 SnP_AddBytes(instance->state, curData, instance->byteIOIndex, partialBlock); 199 curData += partialBlock; 200 instance->byteIOIndex += partialBlock; 201 if (instance->byteIOIndex == rateInBytes) { 202 SnP_Permute(instance->state); 203 instance->byteIOIndex = 0; 204 } 205 } 206 } 207 return 0; 208} 209 210/* ---------------------------------------------------------------- */ 211 212int SpongeAbsorbLastFewBits(SpongeInstance *instance, unsigned char delimitedData) 213{ 214 unsigned int rateInBytes = instance->rate/8; 215 216 if (delimitedData == 0) 217 return 1; 218 if (instance->squeezing) 219 return 1; /* Too late for additional input */ 220 221 #ifdef KeccakReference 222 { 223 unsigned char delimitedData1[1]; 224 delimitedData1[0] = delimitedData; 225 displayBytes(1, "Block to be absorbed (last few bits + first bit of padding)", delimitedData1, 1); 226 } 227 #endif 228 /* Last few bits, whose delimiter coincides with first bit of padding */ 229 SnP_AddByte(instance->state, delimitedData, instance->byteIOIndex); 230 /* If the first bit of padding is at position rate-1, we need a whole new block for the second bit of padding */ 231 if ((delimitedData >= 0x80) && (instance->byteIOIndex == (rateInBytes-1))) 232 SnP_Permute(instance->state); 233 /* Second bit of padding */ 234 SnP_AddByte(instance->state, 0x80, rateInBytes-1); 235 #ifdef KeccakReference 236 { 237 unsigned char block[SnP_width/8]; 238 memset(block, 0, SnP_width/8); 239 block[rateInBytes-1] = 0x80; 240 displayBytes(1, "Second bit of padding", block, rateInBytes); 241 } 242 #endif 243 SnP_Permute(instance->state); 244 instance->byteIOIndex = 0; 245 instance->squeezing = 1; 246 #ifdef KeccakReference 247 displayText(1, "--- Switching to squeezing phase ---"); 248 #endif 249 return 0; 250} 251 252/* ---------------------------------------------------------------- */ 253 254int SpongeSqueeze(SpongeInstance *instance, unsigned char *data, size_t dataByteLen) 255{ 256 size_t i, j; 257 unsigned int partialBlock; 258 unsigned int rateInBytes = instance->rate/8; 259 unsigned char *curData; 260 261 if (!instance->squeezing) 262 SpongeAbsorbLastFewBits(instance, 0x01); 263 264 i = 0; 265 curData = data; 266 while(i < dataByteLen) { 267 if ((instance->byteIOIndex == rateInBytes) && (dataByteLen-i >= rateInBytes)) { 268 for(j=dataByteLen-i; j>=rateInBytes; j-=rateInBytes) { 269 SnP_Permute(instance->state); 270 SnP_ExtractBytes(instance->state, curData, 0, rateInBytes); 271 #ifdef KeccakReference 272 displayBytes(1, "Squeezed block", curData, rateInBytes); 273 #endif 274 curData+=rateInBytes; 275 } 276 i = dataByteLen - j; 277 } 278 else { 279 /* normal lane: using the message queue */ 280 if (instance->byteIOIndex == rateInBytes) { 281 SnP_Permute(instance->state); 282 instance->byteIOIndex = 0; 283 } 284 if (dataByteLen-i > rateInBytes-instance->byteIOIndex) 285 partialBlock = rateInBytes-instance->byteIOIndex; 286 else 287 partialBlock = (unsigned int)(dataByteLen - i); 288 i += partialBlock; 289 290 SnP_ExtractBytes(instance->state, curData, instance->byteIOIndex, partialBlock); 291 #ifdef KeccakReference 292 displayBytes(1, "Squeezed block (part)", curData, partialBlock); 293 #endif 294 curData += partialBlock; 295 instance->byteIOIndex += partialBlock; 296 } 297 } 298 return 0; 299} 300 301/* ---------------------------------------------------------------- */ 302 303#undef Sponge 304#undef SpongeInstance 305#undef SpongeInitialize 306#undef SpongeAbsorb 307#undef SpongeAbsorbLastFewBits 308#undef SpongeSqueeze 309#undef SnP_stateSizeInBytes 310#undef SnP_stateAlignment 311#undef SnP_StaticInitialize 312#undef SnP_Initialize 313#undef SnP_AddByte 314#undef SnP_AddBytes 315#undef SnP_ExtractBytes 316