xref: /aosp_15_r20/external/boringssl/src/crypto/keccak/keccak.c (revision 8fb009dc861624b67b6cdb62ea21f0f22d0c584b)
1 /* Copyright (c) 2023, Google Inc.
2  *
3  * Permission to use, copy, modify, and/or distribute this software for any
4  * purpose with or without fee is hereby granted, provided that the above
5  * copyright notice and this permission notice appear in all copies.
6  *
7  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14 
15 #include <openssl/base.h>
16 
17 #include <assert.h>
18 #include <stdlib.h>
19 
20 #include "../internal.h"
21 #include "./internal.h"
22 
23 
24 // keccak_f implements the Keccak-1600 permutation as described at
25 // https://keccak.team/keccak_specs_summary.html. Each lane is represented as a
26 // 64-bit value and the 5×5 lanes are stored as an array in row-major order.
keccak_f(uint64_t state[25])27 static void keccak_f(uint64_t state[25]) {
28   static const int kNumRounds = 24;
29   for (int round = 0; round < kNumRounds; round++) {
30     // θ step
31     uint64_t c[5];
32     for (int x = 0; x < 5; x++) {
33       c[x] = state[x] ^ state[x + 5] ^ state[x + 10] ^ state[x + 15] ^
34              state[x + 20];
35     }
36 
37     for (int x = 0; x < 5; x++) {
38       const uint64_t d = c[(x + 4) % 5] ^ CRYPTO_rotl_u64(c[(x + 1) % 5], 1);
39       for (int y = 0; y < 5; y++) {
40         state[y * 5 + x] ^= d;
41       }
42     }
43 
44     // ρ and π steps.
45     //
46     // These steps involve a mapping of the state matrix. Each input point,
47     // (x,y), is rotated and written to the point (y, 2x + 3y). In the Keccak
48     // pseudo-code a separate array is used because an in-place operation would
49     // overwrite some values that are subsequently needed. However, the mapping
50     // forms a trail through 24 of the 25 values so we can do it in place with
51     // only a single temporary variable.
52     //
53     // Start with (1, 0). The value here will be mapped and end up at (0, 2).
54     // That value will end up at (2, 1), then (1, 2), and so on. After 24
55     // steps, 24 of the 25 values have been hit (as this mapping is injective)
56     // and the sequence will repeat. All that remains is to handle the element
57     // at (0, 0), but the rotation for that element is zero, and it goes to (0,
58     // 0), so we can ignore it.
59     uint64_t prev_value = state[1];
60 #define PI_RHO_STEP(index, rotation)                              \
61   do {                                                            \
62     const uint64_t value = CRYPTO_rotl_u64(prev_value, rotation); \
63     prev_value = state[index];                                    \
64     state[index] = value;                                         \
65   } while (0)
66 
67     PI_RHO_STEP(10, 1);
68     PI_RHO_STEP(7, 3);
69     PI_RHO_STEP(11, 6);
70     PI_RHO_STEP(17, 10);
71     PI_RHO_STEP(18, 15);
72     PI_RHO_STEP(3, 21);
73     PI_RHO_STEP(5, 28);
74     PI_RHO_STEP(16, 36);
75     PI_RHO_STEP(8, 45);
76     PI_RHO_STEP(21, 55);
77     PI_RHO_STEP(24, 2);
78     PI_RHO_STEP(4, 14);
79     PI_RHO_STEP(15, 27);
80     PI_RHO_STEP(23, 41);
81     PI_RHO_STEP(19, 56);
82     PI_RHO_STEP(13, 8);
83     PI_RHO_STEP(12, 25);
84     PI_RHO_STEP(2, 43);
85     PI_RHO_STEP(20, 62);
86     PI_RHO_STEP(14, 18);
87     PI_RHO_STEP(22, 39);
88     PI_RHO_STEP(9, 61);
89     PI_RHO_STEP(6, 20);
90     PI_RHO_STEP(1, 44);
91 
92 #undef PI_RHO_STEP
93 
94     // χ step
95     for (int y = 0; y < 5; y++) {
96       const int row_index = 5 * y;
97       const uint64_t orig_x0 = state[row_index];
98       const uint64_t orig_x1 = state[row_index + 1];
99       state[row_index] ^= ~orig_x1 & state[row_index + 2];
100       state[row_index + 1] ^= ~state[row_index + 2] & state[row_index + 3];
101       state[row_index + 2] ^= ~state[row_index + 3] & state[row_index + 4];
102       state[row_index + 3] ^= ~state[row_index + 4] & orig_x0;
103       state[row_index + 4] ^= ~orig_x0 & orig_x1;
104     }
105 
106     // ι step
107     //
108     // From https://keccak.team/files/Keccak-reference-3.0.pdf, section
109     // 1.2, the round constants are based on the output of a LFSR. Thus, as
110     // suggested in the appendix of of
111     // https://keccak.team/keccak_specs_summary.html, the values are
112     // simply encoded here.
113     static const uint64_t kRoundConstants[24] = {
114         0x0000000000000001, 0x0000000000008082, 0x800000000000808a,
115         0x8000000080008000, 0x000000000000808b, 0x0000000080000001,
116         0x8000000080008081, 0x8000000000008009, 0x000000000000008a,
117         0x0000000000000088, 0x0000000080008009, 0x000000008000000a,
118         0x000000008000808b, 0x800000000000008b, 0x8000000000008089,
119         0x8000000000008003, 0x8000000000008002, 0x8000000000000080,
120         0x000000000000800a, 0x800000008000000a, 0x8000000080008081,
121         0x8000000000008080, 0x0000000080000001, 0x8000000080008008,
122     };
123 
124     state[0] ^= kRoundConstants[round];
125   }
126 }
127 
keccak_init(struct BORINGSSL_keccak_st * ctx,size_t * out_required_out_len,enum boringssl_keccak_config_t config)128 static void keccak_init(struct BORINGSSL_keccak_st *ctx,
129                         size_t *out_required_out_len,
130                         enum boringssl_keccak_config_t config) {
131   size_t capacity_bytes;
132   switch (config) {
133     case boringssl_sha3_256:
134       capacity_bytes = 512 / 8;
135       *out_required_out_len = 32;
136       break;
137     case boringssl_sha3_512:
138       capacity_bytes = 1024 / 8;
139       *out_required_out_len = 64;
140       break;
141     case boringssl_shake128:
142       capacity_bytes = 256 / 8;
143       *out_required_out_len = 0;
144       break;
145     case boringssl_shake256:
146       capacity_bytes = 512 / 8;
147       *out_required_out_len = 0;
148       break;
149     default:
150       abort();
151   }
152 
153   OPENSSL_memset(ctx, 0, sizeof(*ctx));
154   ctx->config = config;
155   ctx->phase = boringssl_keccak_phase_absorb;
156   ctx->rate_bytes = 200 - capacity_bytes;
157   assert(ctx->rate_bytes % 8 == 0);
158 }
159 
BORINGSSL_keccak(uint8_t * out,size_t out_len,const uint8_t * in,size_t in_len,enum boringssl_keccak_config_t config)160 void BORINGSSL_keccak(uint8_t *out, size_t out_len, const uint8_t *in,
161                       size_t in_len, enum boringssl_keccak_config_t config) {
162   struct BORINGSSL_keccak_st ctx;
163   size_t required_out_len;
164   keccak_init(&ctx, &required_out_len, config);
165   if (required_out_len != 0 && out_len != required_out_len) {
166     abort();
167   }
168   BORINGSSL_keccak_absorb(&ctx, in, in_len);
169   BORINGSSL_keccak_squeeze(&ctx, out, out_len);
170 }
171 
BORINGSSL_keccak_init(struct BORINGSSL_keccak_st * ctx,enum boringssl_keccak_config_t config)172 void BORINGSSL_keccak_init(struct BORINGSSL_keccak_st *ctx,
173                            enum boringssl_keccak_config_t config) {
174   size_t required_out_len;
175   keccak_init(ctx, &required_out_len, config);
176   if (required_out_len != 0) {
177     abort();
178   }
179 }
180 
BORINGSSL_keccak_absorb(struct BORINGSSL_keccak_st * ctx,const uint8_t * in,size_t in_len)181 void BORINGSSL_keccak_absorb(struct BORINGSSL_keccak_st *ctx, const uint8_t *in,
182                              size_t in_len) {
183   if (ctx->phase == boringssl_keccak_phase_squeeze) {
184     // It's illegal to call absorb() again after calling squeeze().
185     abort();
186   }
187 
188   const size_t rate_words = ctx->rate_bytes / 8;
189   // XOR the input. Accessing |ctx->state| as a |uint8_t*| is allowed by strict
190   // aliasing because we require |uint8_t| to be a character type.
191   uint8_t *state_bytes = (uint8_t *)ctx->state;
192 
193   // Absorb partial block.
194   if (ctx->absorb_offset != 0) {
195     assert(ctx->absorb_offset < ctx->rate_bytes);
196     size_t first_block_len = ctx->rate_bytes - ctx->absorb_offset;
197     for (size_t i = 0; i < first_block_len && i < in_len; i++) {
198       state_bytes[ctx->absorb_offset + i] ^= in[i];
199     }
200 
201     // This input didn't fill the block.
202     if (first_block_len > in_len) {
203       ctx->absorb_offset += in_len;
204       return;
205     }
206 
207     keccak_f(ctx->state);
208     in += first_block_len;
209     in_len -= first_block_len;
210   }
211 
212   // Absorb full blocks.
213   while (in_len >= ctx->rate_bytes) {
214     for (size_t i = 0; i < rate_words; i++) {
215       ctx->state[i] ^= CRYPTO_load_u64_le(in + 8 * i);
216     }
217     keccak_f(ctx->state);
218     in += ctx->rate_bytes;
219     in_len -= ctx->rate_bytes;
220   }
221 
222   // Absorb partial block.
223   assert(in_len < ctx->rate_bytes);
224   for (size_t i = 0; i < in_len; i++) {
225     state_bytes[i] ^= in[i];
226   }
227   ctx->absorb_offset = in_len;
228 }
229 
keccak_finalize(struct BORINGSSL_keccak_st * ctx)230 static void keccak_finalize(struct BORINGSSL_keccak_st *ctx) {
231   uint8_t terminator;
232   switch (ctx->config) {
233     case boringssl_sha3_256:
234     case boringssl_sha3_512:
235       terminator = 0x06;
236       break;
237     case boringssl_shake128:
238     case boringssl_shake256:
239       terminator = 0x1f;
240       break;
241     default:
242       abort();
243   }
244 
245   // XOR the terminator. Accessing |ctx->state| as a |uint8_t*| is allowed by
246   // strict aliasing because we require |uint8_t| to be a character type.
247   uint8_t *state_bytes = (uint8_t *)ctx->state;
248   state_bytes[ctx->absorb_offset] ^= terminator;
249   state_bytes[ctx->rate_bytes - 1] ^= 0x80;
250   keccak_f(ctx->state);
251 }
252 
BORINGSSL_keccak_squeeze(struct BORINGSSL_keccak_st * ctx,uint8_t * out,size_t out_len)253 void BORINGSSL_keccak_squeeze(struct BORINGSSL_keccak_st *ctx, uint8_t *out,
254                               size_t out_len) {
255   if (ctx->phase == boringssl_keccak_phase_absorb) {
256     keccak_finalize(ctx);
257     ctx->phase = boringssl_keccak_phase_squeeze;
258   }
259 
260   // Accessing |ctx->state| as a |uint8_t*| is allowed by strict aliasing
261   // because we require |uint8_t| to be a character type.
262   const uint8_t *state_bytes = (const uint8_t *)ctx->state;
263   while (out_len) {
264     if (ctx->squeeze_offset == ctx->rate_bytes) {
265       keccak_f(ctx->state);
266       ctx->squeeze_offset = 0;
267     }
268 
269     size_t remaining = ctx->rate_bytes - ctx->squeeze_offset;
270     size_t todo = out_len;
271     if (todo > remaining) {
272       todo = remaining;
273     }
274     OPENSSL_memcpy(out, &state_bytes[ctx->squeeze_offset], todo);
275     out += todo;
276     out_len -= todo;
277     ctx->squeeze_offset += todo;
278   }
279 }
280