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