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