Coverage Report

Created: 2025-06-13 06:43

/src/php-src/ext/hash/sha3/generic64lc/KeccakP-1600-opt64.c
Line
Count
Source (jump to first uncovered line)
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
#include <string.h>
17
#include <stdlib.h>
18
#include "brg_endian.h"
19
#include "KeccakP-1600-opt64-config.h"
20
#ifdef __has_feature
21
# if __has_feature(undefined_behavior_sanitizer)
22
#  define ALLOW_MISALIGNED_ACCESS __attribute__((no_sanitize("alignment")))
23
# endif
24
#endif
25
#ifndef ALLOW_MISALIGNED_ACCESS
26
# define ALLOW_MISALIGNED_ACCESS
27
#endif
28
29
typedef unsigned char UINT8;
30
typedef unsigned long long int UINT64;
31
32
#if defined(KeccakP1600_useLaneComplementing)
33
#define UseBebigokimisa
34
#endif
35
36
#if defined(_MSC_VER)
37
#define ROL64(a, offset) _rotl64(a, offset)
38
#elif defined(KeccakP1600_useSHLD)
39
    #define ROL64(x,N) ({ \
40
    register UINT64 __out; \
41
    register UINT64 __in = x; \
42
    __asm__ ("shld %2,%0,%0" : "=r"(__out) : "0"(__in), "i"(N)); \
43
    __out; \
44
    })
45
#else
46
17.2M
#define ROL64(a, offset) ((((UINT64)a) << offset) ^ (((UINT64)a) >> (64-offset)))
47
#endif
48
49
#include "KeccakP-1600-64.macros"
50
#ifdef KeccakP1600_fullUnrolling
51
#define FullUnrolling
52
#else
53
#define Unrolling KeccakP1600_unrolling
54
#endif
55
#include "KeccakP-1600-unrolling.macros"
56
#include "SnP-Relaned.h"
57
58
static const UINT64 KeccakF1600RoundConstants[24] = {
59
    0x0000000000000001ULL,
60
    0x0000000000008082ULL,
61
    0x800000000000808aULL,
62
    0x8000000080008000ULL,
63
    0x000000000000808bULL,
64
    0x0000000080000001ULL,
65
    0x8000000080008081ULL,
66
    0x8000000000008009ULL,
67
    0x000000000000008aULL,
68
    0x0000000000000088ULL,
69
    0x0000000080008009ULL,
70
    0x000000008000000aULL,
71
    0x000000008000808bULL,
72
    0x800000000000008bULL,
73
    0x8000000000008089ULL,
74
    0x8000000000008003ULL,
75
    0x8000000000008002ULL,
76
    0x8000000000000080ULL,
77
    0x000000000000800aULL,
78
    0x800000008000000aULL,
79
    0x8000000080008081ULL,
80
    0x8000000000008080ULL,
81
    0x0000000080000001ULL,
82
    0x8000000080008008ULL };
83
84
/* ---------------------------------------------------------------- */
85
86
void KeccakP1600_Initialize(void *state)
87
147
{
88
147
    memset(state, 0, 200);
89
147
#ifdef KeccakP1600_useLaneComplementing
90
147
    ((UINT64*)state)[ 1] = ~(UINT64)0;
91
147
    ((UINT64*)state)[ 2] = ~(UINT64)0;
92
147
    ((UINT64*)state)[ 8] = ~(UINT64)0;
93
147
    ((UINT64*)state)[12] = ~(UINT64)0;
94
147
    ((UINT64*)state)[17] = ~(UINT64)0;
95
147
    ((UINT64*)state)[20] = ~(UINT64)0;
96
147
#endif
97
147
}
98
99
/* ---------------------------------------------------------------- */
100
101
void KeccakP1600_AddBytesInLane(void *state, unsigned int lanePosition, const unsigned char *data, unsigned int offset, unsigned int length)
102
541
{
103
541
#if (PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN)
104
541
    UINT64 lane;
105
541
    if (length == 0)
106
5
        return;
107
536
    if (length == 1)
108
41
        lane = data[0];
109
495
    else {
110
495
        lane = 0;
111
495
        memcpy(&lane, data, length);
112
495
    }
113
536
    lane <<= offset*8;
114
#else
115
    UINT64 lane = 0;
116
    unsigned int i;
117
    for(i=0; i<length; i++)
118
        lane |= ((UINT64)data[i]) << ((i+offset)*8);
119
#endif
120
536
    ((UINT64*)state)[lanePosition] ^= lane;
121
536
}
122
123
/* ---------------------------------------------------------------- */
124
125
ALLOW_MISALIGNED_ACCESS
126
void KeccakP1600_AddLanes(void *state, const unsigned char *data, unsigned int laneCount)
127
42
{
128
42
#if (PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN)
129
42
    unsigned int i = 0;
130
#ifdef NO_MISALIGNED_ACCESSES
131
    /* If either pointer is misaligned, fall back to byte-wise xor. */
132
    if (((((uintptr_t)state) & 7) != 0) || ((((uintptr_t)data) & 7) != 0)) {
133
      for (i = 0; i < laneCount * 8; i++) {
134
        ((unsigned char*)state)[i] ^= data[i];
135
      }
136
    }
137
    else
138
#endif
139
42
    {
140
      /* Otherwise... */
141
49
      for( ; (i+8)<=laneCount; i+=8) {
142
7
          ((UINT64*)state)[i+0] ^= ((UINT64*)data)[i+0];
143
7
          ((UINT64*)state)[i+1] ^= ((UINT64*)data)[i+1];
144
7
          ((UINT64*)state)[i+2] ^= ((UINT64*)data)[i+2];
145
7
          ((UINT64*)state)[i+3] ^= ((UINT64*)data)[i+3];
146
7
          ((UINT64*)state)[i+4] ^= ((UINT64*)data)[i+4];
147
7
          ((UINT64*)state)[i+5] ^= ((UINT64*)data)[i+5];
148
7
          ((UINT64*)state)[i+6] ^= ((UINT64*)data)[i+6];
149
7
          ((UINT64*)state)[i+7] ^= ((UINT64*)data)[i+7];
150
7
      }
151
54
      for( ; (i+4)<=laneCount; i+=4) {
152
12
          ((UINT64*)state)[i+0] ^= ((UINT64*)data)[i+0];
153
12
          ((UINT64*)state)[i+1] ^= ((UINT64*)data)[i+1];
154
12
          ((UINT64*)state)[i+2] ^= ((UINT64*)data)[i+2];
155
12
          ((UINT64*)state)[i+3] ^= ((UINT64*)data)[i+3];
156
12
      }
157
56
      for( ; (i+2)<=laneCount; i+=2) {
158
14
          ((UINT64*)state)[i+0] ^= ((UINT64*)data)[i+0];
159
14
          ((UINT64*)state)[i+1] ^= ((UINT64*)data)[i+1];
160
14
      }
161
42
      if (i<laneCount) {
162
15
          ((UINT64*)state)[i+0] ^= ((UINT64*)data)[i+0];
163
15
      }
164
42
    }
165
#else
166
    unsigned int i;
167
    UINT8 *curData = data;
168
    for(i=0; i<laneCount; i++, curData+=8) {
169
        UINT64 lane = (UINT64)curData[0]
170
            | ((UINT64)curData[1] << 8)
171
            | ((UINT64)curData[2] << 16)
172
            | ((UINT64)curData[3] << 24)
173
            | ((UINT64)curData[4] <<32)
174
            | ((UINT64)curData[5] << 40)
175
            | ((UINT64)curData[6] << 48)
176
            | ((UINT64)curData[7] << 56);
177
        ((UINT64*)state)[i] ^= lane;
178
    }
179
#endif
180
42
}
181
182
/* ---------------------------------------------------------------- */
183
184
#if (PLATFORM_BYTE_ORDER != IS_LITTLE_ENDIAN)
185
void KeccakP1600_AddByte(void *state, unsigned char byte, unsigned int offset)
186
{
187
    UINT64 lane = byte;
188
    lane <<= (offset%8)*8;
189
    ((UINT64*)state)[offset/8] ^= lane;
190
}
191
#endif
192
193
/* ---------------------------------------------------------------- */
194
195
void KeccakP1600_AddBytes(void *state, const unsigned char *data, unsigned int offset, unsigned int length)
196
111
{
197
111
    SnP_AddBytes(state, data, offset, length, KeccakP1600_AddLanes, KeccakP1600_AddBytesInLane, 8);
198
111
}
199
200
/* ---------------------------------------------------------------- */
201
202
void KeccakP1600_OverwriteBytesInLane(void *state, unsigned int lanePosition, const unsigned char *data, unsigned int offset, unsigned int length)
203
0
{
204
0
#if (PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN)
205
0
#ifdef KeccakP1600_useLaneComplementing
206
0
    if ((lanePosition == 1) || (lanePosition == 2) || (lanePosition == 8) || (lanePosition == 12) || (lanePosition == 17) || (lanePosition == 20)) {
207
0
        unsigned int i;
208
0
        for(i=0; i<length; i++)
209
0
            ((unsigned char*)state)[lanePosition*8+offset+i] = ~data[i];
210
0
    }
211
0
    else
212
0
#endif
213
0
    {
214
0
        memcpy((unsigned char*)state+lanePosition*8+offset, data, length);
215
0
    }
216
#else
217
#error "Not yet implemented"
218
#endif
219
0
}
220
221
/* ---------------------------------------------------------------- */
222
223
void KeccakP1600_OverwriteLanes(void *state, const unsigned char *data, unsigned int laneCount)
224
0
{
225
0
#if (PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN)
226
0
#ifdef KeccakP1600_useLaneComplementing
227
0
    unsigned int lanePosition;
228
229
0
    for(lanePosition=0; lanePosition<laneCount; lanePosition++)
230
0
        if ((lanePosition == 1) || (lanePosition == 2) || (lanePosition == 8) || (lanePosition == 12) || (lanePosition == 17) || (lanePosition == 20))
231
0
            ((UINT64*)state)[lanePosition] = ~((const UINT64*)data)[lanePosition];
232
0
        else
233
0
            ((UINT64*)state)[lanePosition] = ((const UINT64*)data)[lanePosition];
234
#else
235
    memcpy(state, data, laneCount*8);
236
#endif
237
#else
238
#error "Not yet implemented"
239
#endif
240
0
}
241
242
/* ---------------------------------------------------------------- */
243
244
void KeccakP1600_OverwriteBytes(void *state, const unsigned char *data, unsigned int offset, unsigned int length)
245
0
{
246
0
    SnP_OverwriteBytes(state, data, offset, length, KeccakP1600_OverwriteLanes, KeccakP1600_OverwriteBytesInLane, 8);
247
0
}
248
249
/* ---------------------------------------------------------------- */
250
251
void KeccakP1600_OverwriteWithZeroes(void *state, unsigned int byteCount)
252
0
{
253
0
#if (PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN)
254
0
#ifdef KeccakP1600_useLaneComplementing
255
0
    unsigned int lanePosition;
256
257
0
    for(lanePosition=0; lanePosition<byteCount/8; lanePosition++)
258
0
        if ((lanePosition == 1) || (lanePosition == 2) || (lanePosition == 8) || (lanePosition == 12) || (lanePosition == 17) || (lanePosition == 20))
259
0
            ((UINT64*)state)[lanePosition] = ~0;
260
0
        else
261
0
            ((UINT64*)state)[lanePosition] = 0;
262
0
    if (byteCount%8 != 0) {
263
0
        lanePosition = byteCount/8;
264
0
        if ((lanePosition == 1) || (lanePosition == 2) || (lanePosition == 8) || (lanePosition == 12) || (lanePosition == 17) || (lanePosition == 20))
265
0
            memset((unsigned char*)state+lanePosition*8, 0xFF, byteCount%8);
266
0
        else
267
0
            memset((unsigned char*)state+lanePosition*8, 0, byteCount%8);
268
0
    }
269
#else
270
    memset(state, 0, byteCount);
271
#endif
272
#else
273
#error "Not yet implemented"
274
#endif
275
0
}
276
277
/* ---------------------------------------------------------------- */
278
279
void KeccakP1600_Permute_Nrounds(void *state, unsigned int nr)
280
0
{
281
0
    declareABCDE
282
0
    unsigned int i;
283
0
    UINT64 *stateAsLanes = (UINT64*)state;
284
285
0
    copyFromState(A, stateAsLanes)
286
0
    roundsN(nr)
287
0
    copyToState(stateAsLanes, A)
288
289
0
}
290
291
/* ---------------------------------------------------------------- */
292
293
void KeccakP1600_Permute_24rounds(void *state)
294
145
{
295
145
    declareABCDE
296
    #ifndef KeccakP1600_fullUnrolling
297
    unsigned int i;
298
    #endif
299
145
    UINT64 *stateAsLanes = (UINT64*)state;
300
301
145
    copyFromState(A, stateAsLanes)
302
145
    rounds24
303
145
    copyToState(stateAsLanes, A)
304
145
}
305
306
/* ---------------------------------------------------------------- */
307
308
void KeccakP1600_Permute_12rounds(void *state)
309
0
{
310
0
    declareABCDE
311
    #ifndef KeccakP1600_fullUnrolling
312
    unsigned int i;
313
    #endif
314
0
    UINT64 *stateAsLanes = (UINT64*)state;
315
316
0
    copyFromState(A, stateAsLanes)
317
0
    rounds12
318
0
    copyToState(stateAsLanes, A)
319
0
}
320
321
/* ---------------------------------------------------------------- */
322
323
void KeccakP1600_ExtractBytesInLane(const void *state, unsigned int lanePosition, unsigned char *data, unsigned int offset, unsigned int length)
324
93
{
325
93
    UINT64 lane = ((UINT64*)state)[lanePosition];
326
93
#ifdef KeccakP1600_useLaneComplementing
327
93
    if ((lanePosition == 1) || (lanePosition == 2) || (lanePosition == 8) || (lanePosition == 12) || (lanePosition == 17) || (lanePosition == 20))
328
31
        lane = ~lane;
329
93
#endif
330
93
#if (PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN)
331
93
    {
332
93
        UINT64 lane1[1];
333
93
        lane1[0] = lane;
334
93
        memcpy(data, (UINT8*)lane1+offset, length);
335
93
    }
336
#else
337
    unsigned int i;
338
    lane >>= offset*8;
339
    for(i=0; i<length; i++) {
340
        data[i] = lane & 0xFF;
341
        lane >>= 8;
342
    }
343
#endif
344
93
}
345
346
/* ---------------------------------------------------------------- */
347
348
#if (PLATFORM_BYTE_ORDER != IS_LITTLE_ENDIAN)
349
void fromWordToBytes(UINT8 *bytes, const UINT64 word)
350
{
351
    unsigned int i;
352
353
    for(i=0; i<(64/8); i++)
354
        bytes[i] = (word >> (8*i)) & 0xFF;
355
}
356
#endif
357
358
void KeccakP1600_ExtractLanes(const void *state, unsigned char *data, unsigned int laneCount)
359
93
{
360
93
#if (PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN)
361
93
    memcpy(data, state, laneCount*8);
362
#else
363
    unsigned int i;
364
365
    for(i=0; i<laneCount; i++)
366
        fromWordToBytes(data+(i*8), ((const UINT64*)state)[i]);
367
#endif
368
93
#ifdef KeccakP1600_useLaneComplementing
369
93
    if (laneCount > 1) {
370
93
        ((UINT64*)data)[ 1] = ~((UINT64*)data)[ 1];
371
93
        if (laneCount > 2) {
372
93
            ((UINT64*)data)[ 2] = ~((UINT64*)data)[ 2];
373
93
            if (laneCount > 8) {
374
0
                ((UINT64*)data)[ 8] = ~((UINT64*)data)[ 8];
375
0
                if (laneCount > 12) {
376
0
                    ((UINT64*)data)[12] = ~((UINT64*)data)[12];
377
0
                    if (laneCount > 17) {
378
0
                        ((UINT64*)data)[17] = ~((UINT64*)data)[17];
379
0
                        if (laneCount > 20) {
380
0
                            ((UINT64*)data)[20] = ~((UINT64*)data)[20];
381
0
                        }
382
0
                    }
383
0
                }
384
0
            }
385
93
        }
386
93
    }
387
93
#endif
388
93
}
389
390
/* ---------------------------------------------------------------- */
391
392
void KeccakP1600_ExtractBytes(const void *state, unsigned char *data, unsigned int offset, unsigned int length)
393
93
{
394
93
    SnP_ExtractBytes(state, data, offset, length, KeccakP1600_ExtractLanes, KeccakP1600_ExtractBytesInLane, 8);
395
93
}
396
397
/* ---------------------------------------------------------------- */
398
399
void KeccakP1600_ExtractAndAddBytesInLane(const void *state, unsigned int lanePosition, const unsigned char *input, unsigned char *output, unsigned int offset, unsigned int length)
400
0
{
401
0
    UINT64 lane = ((UINT64*)state)[lanePosition];
402
0
#ifdef KeccakP1600_useLaneComplementing
403
0
    if ((lanePosition == 1) || (lanePosition == 2) || (lanePosition == 8) || (lanePosition == 12) || (lanePosition == 17) || (lanePosition == 20))
404
0
        lane = ~lane;
405
0
#endif
406
0
#if (PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN)
407
0
    {
408
0
        unsigned int i;
409
0
        UINT64 lane1[1];
410
0
        lane1[0] = lane;
411
0
        for(i=0; i<length; i++)
412
0
            output[i] = input[i] ^ ((UINT8*)lane1)[offset+i];
413
0
    }
414
#else
415
    unsigned int i;
416
    lane >>= offset*8;
417
    for(i=0; i<length; i++) {
418
        output[i] = input[i] ^ (lane & 0xFF);
419
        lane >>= 8;
420
    }
421
#endif
422
0
}
423
424
/* ---------------------------------------------------------------- */
425
426
void KeccakP1600_ExtractAndAddLanes(const void *state, const unsigned char *input, unsigned char *output, unsigned int laneCount)
427
0
{
428
0
    unsigned int i;
429
#if (PLATFORM_BYTE_ORDER != IS_LITTLE_ENDIAN)
430
    unsigned char temp[8];
431
    unsigned int j;
432
#endif
433
434
0
    for(i=0; i<laneCount; i++) {
435
0
#if (PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN)
436
0
        ((UINT64*)output)[i] = ((UINT64*)input)[i] ^ ((const UINT64*)state)[i];
437
#else
438
        fromWordToBytes(temp, ((const UINT64*)state)[i]);
439
        for(j=0; j<8; j++)
440
            output[i*8+j] = input[i*8+j] ^ temp[j];
441
#endif
442
0
    }
443
0
#ifdef KeccakP1600_useLaneComplementing
444
0
    if (laneCount > 1) {
445
0
        ((UINT64*)output)[ 1] = ~((UINT64*)output)[ 1];
446
0
        if (laneCount > 2) {
447
0
            ((UINT64*)output)[ 2] = ~((UINT64*)output)[ 2];
448
0
            if (laneCount > 8) {
449
0
                ((UINT64*)output)[ 8] = ~((UINT64*)output)[ 8];
450
0
                if (laneCount > 12) {
451
0
                    ((UINT64*)output)[12] = ~((UINT64*)output)[12];
452
0
                    if (laneCount > 17) {
453
0
                        ((UINT64*)output)[17] = ~((UINT64*)output)[17];
454
0
                        if (laneCount > 20) {
455
0
                            ((UINT64*)output)[20] = ~((UINT64*)output)[20];
456
0
                        }
457
0
                    }
458
0
                }
459
0
            }
460
0
        }
461
0
    }
462
0
#endif
463
0
}
464
465
/* ---------------------------------------------------------------- */
466
467
void KeccakP1600_ExtractAndAddBytes(const void *state, const unsigned char *input, unsigned char *output, unsigned int offset, unsigned int length)
468
0
{
469
0
    SnP_ExtractAndAddBytes(state, input, output, offset, length, KeccakP1600_ExtractAndAddLanes, KeccakP1600_ExtractAndAddBytesInLane, 8);
470
0
}
471
472
/* ---------------------------------------------------------------- */
473
474
ALLOW_MISALIGNED_ACCESS
475
size_t KeccakF1600_FastLoop_Absorb(void *state, unsigned int laneCount, const unsigned char *data, size_t dataByteLen)
476
66
{
477
66
    size_t originalDataByteLen = dataByteLen;
478
66
    declareABCDE
479
    #ifndef KeccakP1600_fullUnrolling
480
    unsigned int i;
481
    #endif
482
66
    UINT64 *stateAsLanes = (UINT64*)state;
483
66
    UINT64 *inDataAsLanes = (UINT64*)data;
484
485
66
    copyFromState(A, stateAsLanes)
486
24.6k
    while(dataByteLen >= laneCount*8) {
487
24.5k
        addInput(A, inDataAsLanes, laneCount)
488
24.5k
        rounds24
489
24.5k
        inDataAsLanes += laneCount;
490
24.5k
        dataByteLen -= laneCount*8;
491
24.5k
    }
492
66
    copyToState(stateAsLanes, A)
493
66
    return originalDataByteLen - dataByteLen;
494
66
}