1 | /* |
2 | Implementation by the Keccak, Keyak and Ketje Teams, namely, Guido Bertoni, |
3 | Joan Daemen, Michaƫl Peeters, Gilles Van Assche and Ronny Van Keer, hereby |
4 | denoted as "the implementer". |
5 | |
6 | For more information, feedback or questions, please refer to our websites: |
7 | http://keccak.noekeon.org/ |
8 | http://keyak.noekeon.org/ |
9 | http://ketje.noekeon.org/ |
10 | |
11 | To the extent possible under law, the implementer has waived all copyright |
12 | and related or neighboring rights to the source code in this file. |
13 | http://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 JOIN(SnP, _ExtractBytes) |
33 | |
34 | int 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 | |
143 | int 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 | |
160 | int 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 | |
225 | int 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 | |
271 | int 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 | |