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
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
143int 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
160int 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
225int 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
271int 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