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 | static 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->state); |
32 | memset(s: state->dataQueue, c: 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, data: state->dataQueue); |
49 | else |
50 | #endif |
51 | #ifdef ProvideFast832 |
52 | if (state->rate == 832) |
53 | KeccakAbsorb832bits(state: state->state, data: state->dataQueue); |
54 | else |
55 | #endif |
56 | #ifdef ProvideFast1024 |
57 | if (state->rate == 1024) |
58 | KeccakAbsorb1024bits(state: state->state, data: state->dataQueue); |
59 | else |
60 | #endif |
61 | #ifdef ProvideFast1088 |
62 | if (state->rate == 1088) |
63 | KeccakAbsorb1088bits(state: state->state, data: state->dataQueue); |
64 | else |
65 | #endif |
66 | #ifdef ProvideFast1152 |
67 | if (state->rate == 1152) |
68 | KeccakAbsorb1152bits(state: state->state, data: state->dataQueue); |
69 | else |
70 | #endif |
71 | #ifdef ProvideFast1344 |
72 | if (state->rate == 1344) |
73 | KeccakAbsorb1344bits(state: state->state, data: state->dataQueue); |
74 | else |
75 | #endif |
76 | KeccakAbsorb(state: state->state, data: state->dataQueue, laneCount: state->rate/64); |
77 | state->bitsInQueue = 0; |
78 | } |
79 | |
80 | static 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->state, data: 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->state, data: 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->state, data: 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->state, data: 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->state, data: 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->state, data: 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->state, data: curData, laneCount: state->rate/64); |
168 | } |
169 | } |
170 | i += wholeBlocks*state->rate; |
171 | } |
172 | else { |
173 | if (databitlen-i > state->rate - state->bitsInQueue) |
174 | partialBlock = state->rate-state->bitsInQueue; |
175 | else |
176 | partialBlock = (unsigned int)(databitlen - i); |
177 | partialByte = partialBlock % 8; |
178 | partialBlock -= partialByte; |
179 | memcpy(dest: state->dataQueue+state->bitsInQueue/8, src: data+i/8, n: partialBlock/8); |
180 | state->bitsInQueue += partialBlock; |
181 | i += partialBlock; |
182 | if (state->bitsInQueue == state->rate) |
183 | AbsorbQueue(state); |
184 | if (partialByte > 0) { |
185 | unsigned char mask = (1 << partialByte)-1; |
186 | state->dataQueue[state->bitsInQueue/8] = data[i/8] & mask; |
187 | state->bitsInQueue += partialByte; |
188 | i += partialByte; |
189 | } |
190 | } |
191 | } |
192 | return 0; |
193 | } |
194 | |
195 | static void PadAndSwitchToSqueezingPhase(spongeState *state) |
196 | { |
197 | // Note: the bits are numbered from 0=LSB to 7=MSB |
198 | if (state->bitsInQueue + 1 == state->rate) { |
199 | state->dataQueue[state->bitsInQueue/8 ] |= 1 << (state->bitsInQueue % 8); |
200 | AbsorbQueue(state); |
201 | memset(s: state->dataQueue, c: 0, n: state->rate/8); |
202 | } |
203 | else { |
204 | memset(s: state->dataQueue + (state->bitsInQueue+7)/8, c: 0, n: state->rate/8 - (state->bitsInQueue+7)/8); |
205 | state->dataQueue[state->bitsInQueue/8 ] |= 1 << (state->bitsInQueue % 8); |
206 | } |
207 | state->dataQueue[(state->rate-1)/8] |= 1 << ((state->rate-1) % 8); |
208 | AbsorbQueue(state); |
209 | |
210 | #ifdef KeccakReference |
211 | displayText(1, "--- Switching to squeezing phase ---" ); |
212 | #endif |
213 | #ifdef ProvideFast1024 |
214 | if (state->rate == 1024) { |
215 | KeccakExtract1024bits(state: state->state, data: state->dataQueue); |
216 | state->bitsAvailableForSqueezing = 1024; |
217 | } |
218 | else |
219 | #endif |
220 | { |
221 | KeccakExtract(state: state->state, data: state->dataQueue, laneCount: state->rate/64); |
222 | state->bitsAvailableForSqueezing = state->rate; |
223 | } |
224 | #ifdef KeccakReference |
225 | displayBytes(1, "Block available for squeezing" , state->dataQueue, state->bitsAvailableForSqueezing/8); |
226 | #endif |
227 | state->squeezing = 1; |
228 | } |
229 | |
230 | static int Squeeze(spongeState *state, unsigned char *output, unsigned long long outputLength) |
231 | { |
232 | unsigned long long i; |
233 | unsigned int partialBlock; |
234 | |
235 | if (!state->squeezing) |
236 | PadAndSwitchToSqueezingPhase(state); |
237 | if ((outputLength % 8) != 0) |
238 | return 1; // Only multiple of 8 bits are allowed, truncation can be done at user level |
239 | |
240 | i = 0; |
241 | while(i < outputLength) { |
242 | if (state->bitsAvailableForSqueezing == 0) { |
243 | KeccakPermutation(state: state->state); |
244 | #ifdef ProvideFast1024 |
245 | if (state->rate == 1024) { |
246 | KeccakExtract1024bits(state: state->state, data: state->dataQueue); |
247 | state->bitsAvailableForSqueezing = 1024; |
248 | } |
249 | else |
250 | #endif |
251 | { |
252 | KeccakExtract(state: state->state, data: state->dataQueue, laneCount: state->rate/64); |
253 | state->bitsAvailableForSqueezing = state->rate; |
254 | } |
255 | #ifdef KeccakReference |
256 | displayBytes(1, "Block available for squeezing" , state->dataQueue, state->bitsAvailableForSqueezing/8); |
257 | #endif |
258 | } |
259 | partialBlock = state->bitsAvailableForSqueezing; |
260 | if ((unsigned long long)partialBlock > outputLength - i) |
261 | partialBlock = (unsigned int)(outputLength - i); |
262 | memcpy(dest: output+i/8, src: state->dataQueue+(state->rate-state->bitsAvailableForSqueezing)/8, n: partialBlock/8); |
263 | state->bitsAvailableForSqueezing -= partialBlock; |
264 | i += partialBlock; |
265 | } |
266 | return 0; |
267 | } |
268 | |