DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
sha3.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
5
6#if DETWS_ENABLE_PQC_KEX
7
8// Keccak-f[1600] permutation constants (FIPS 202): iota round constants, rho rotation offsets, and
9// the rho/pi lane-permutation order.
10static const uint64_t keccak_rc[24] = {
11 0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL, 0x8000000080008000ULL, 0x000000000000808bULL,
12 0x0000000080000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008aULL, 0x0000000000000088ULL,
13 0x0000000080008009ULL, 0x000000008000000aULL, 0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL,
14 0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL, 0x000000000000800aULL, 0x800000008000000aULL,
15 0x8000000080008081ULL, 0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL};
16
17static const uint8_t keccak_rot[24] = {1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14,
18 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44};
19
20static const uint8_t keccak_pi[24] = {10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4,
21 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1};
22
23static inline uint64_t rotl64(uint64_t x, unsigned n)
24{
25 return (x << n) | (x >> (64 - n));
26}
27
28static void keccakf(uint64_t st[25])
29{
30 for (int r = 0; r < 24; r++)
31 {
32 uint64_t bc[5];
33 // Theta
34 for (int i = 0; i < 5; i++)
35 bc[i] = st[i] ^ st[i + 5] ^ st[i + 10] ^ st[i + 15] ^ st[i + 20];
36 for (int i = 0; i < 5; i++)
37 {
38 uint64_t t = bc[(i + 4) % 5] ^ rotl64(bc[(i + 1) % 5], 1);
39 for (int j = 0; j < 25; j += 5)
40 st[j + i] ^= t;
41 }
42 // Rho + Pi
43 uint64_t t = st[1];
44 for (int i = 0; i < 24; i++)
45 {
46 int j = keccak_pi[i];
47 uint64_t tmp = st[j];
48 st[j] = rotl64(t, keccak_rot[i]);
49 t = tmp;
50 }
51 // Chi
52 for (int j = 0; j < 25; j += 5)
53 {
54 for (int i = 0; i < 5; i++)
55 bc[i] = st[j + i];
56 for (int i = 0; i < 5; i++)
57 st[j + i] ^= (~bc[(i + 1) % 5]) & bc[(i + 2) % 5];
58 }
59 // Iota
60 st[0] ^= keccak_rc[r];
61 }
62}
63
64// The sponge state is addressed as a little-endian octet string: octet p lives in lane p/8 at byte
65// p%8. This makes absorb/squeeze byte order independent of the host's.
66static inline void st_xor_byte(uint64_t st[25], size_t p, uint8_t b)
67{
68 st[p >> 3] ^= (uint64_t)b << (8 * (p & 7));
69}
70
71static inline uint8_t st_get_byte(const uint64_t st[25], size_t p)
72{
73 return (uint8_t)(st[p >> 3] >> (8 * (p & 7)));
74}
75
76void keccak_absorb(KeccakCtx *c, uint32_t rate, const uint8_t *in, size_t inlen, uint8_t domain)
77{
78 for (int i = 0; i < 25; i++)
79 c->st[i] = 0;
80 c->rate = rate;
81
82 while (inlen >= rate)
83 {
84 for (uint32_t p = 0; p < rate; p++)
85 st_xor_byte(c->st, p, in[p]);
86 keccakf(c->st);
87 in += rate;
88 inlen -= rate;
89 }
90 for (size_t p = 0; p < inlen; p++)
91 st_xor_byte(c->st, p, in[p]);
92 // Pad10*1 with the domain-separation byte, and the high bit of the last rate octet.
93 st_xor_byte(c->st, inlen, domain);
94 st_xor_byte(c->st, rate - 1, 0x80);
95 c->out_pos = rate; // force a permutation on the first squeeze
96}
97
98void keccak_squeeze(KeccakCtx *c, uint8_t *out, size_t outlen)
99{
100 while (outlen)
101 {
102 if (c->out_pos == c->rate)
103 {
104 keccakf(c->st);
105 c->out_pos = 0;
106 }
107 uint32_t n = c->rate - c->out_pos;
108 if (n > outlen)
109 n = (uint32_t)outlen;
110 for (uint32_t k = 0; k < n; k++)
111 out[k] = st_get_byte(c->st, c->out_pos + k);
112 out += n;
113 outlen -= n;
114 c->out_pos += n;
115 }
116}
117
118void sha3_256(uint8_t out[32], const uint8_t *in, size_t inlen)
119{
120 KeccakCtx c;
121 keccak_absorb(&c, KECCAK_RATE_SHA3_256, in, inlen, 0x06);
122 keccak_squeeze(&c, out, 32);
123}
124
125void sha3_512(uint8_t out[64], const uint8_t *in, size_t inlen)
126{
127 KeccakCtx c;
128 keccak_absorb(&c, KECCAK_RATE_SHA3_512, in, inlen, 0x06);
129 keccak_squeeze(&c, out, 64);
130}
131
132void shake128(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen)
133{
134 KeccakCtx c;
135 keccak_absorb(&c, KECCAK_RATE_SHAKE128, in, inlen, 0x1F);
136 keccak_squeeze(&c, out, outlen);
137}
138
139void shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen)
140{
141 KeccakCtx c;
142 keccak_absorb(&c, KECCAK_RATE_SHAKE256, in, inlen, 0x1F);
143 keccak_squeeze(&c, out, outlen);
144}
145
146void shake128_absorb(KeccakCtx *c, const uint8_t *in, size_t inlen)
147{
148 keccak_absorb(c, KECCAK_RATE_SHAKE128, in, inlen, 0x1F);
149}
150
151#endif // DETWS_ENABLE_PQC_KEX
Keccak-f[1600] sponge: SHA3-256, SHA3-512, SHAKE128, SHAKE256 (FIPS 202).