Coverage Report

Created: 2025-11-17 06:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/crypto/fipsmodule/keccak/keccak.cc.inc
Line
Count
Source
1
// Copyright 2023 The BoringSSL Authors
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     https://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
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.
27
2.87M
static void keccak_f(uint64_t state[25]) {
28
2.87M
  static const int kNumRounds = 24;
29
71.9M
  for (int round = 0; round < kNumRounds; round++) {
30
    // θ step
31
69.0M
    uint64_t c[5];
32
414M
    for (int x = 0; x < 5; x++) {
33
345M
      c[x] = state[x] ^ state[x + 5] ^ state[x + 10] ^ state[x + 15] ^
34
345M
             state[x + 20];
35
345M
    }
36
37
414M
    for (int x = 0; x < 5; x++) {
38
345M
      const uint64_t d = c[(x + 4) % 5] ^ CRYPTO_rotl_u64(c[(x + 1) % 5], 1);
39
2.07G
      for (int y = 0; y < 5; y++) {
40
1.72G
        state[y * 5 + x] ^= d;
41
1.72G
      }
42
345M
    }
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
69.0M
    uint64_t prev_value = state[1];
60
69.0M
#define PI_RHO_STEP(index, rotation)                              \
61
1.65G
  do {                                                            \
62
1.65G
    const uint64_t value = CRYPTO_rotl_u64(prev_value, rotation); \
63
1.65G
    prev_value = state[index];                                    \
64
1.65G
    state[index] = value;                                         \
65
1.65G
  } while (0)
66
67
69.0M
    PI_RHO_STEP(10, 1);
68
69.0M
    PI_RHO_STEP(7, 3);
69
69.0M
    PI_RHO_STEP(11, 6);
70
69.0M
    PI_RHO_STEP(17, 10);
71
69.0M
    PI_RHO_STEP(18, 15);
72
69.0M
    PI_RHO_STEP(3, 21);
73
69.0M
    PI_RHO_STEP(5, 28);
74
69.0M
    PI_RHO_STEP(16, 36);
75
69.0M
    PI_RHO_STEP(8, 45);
76
69.0M
    PI_RHO_STEP(21, 55);
77
69.0M
    PI_RHO_STEP(24, 2);
78
69.0M
    PI_RHO_STEP(4, 14);
79
69.0M
    PI_RHO_STEP(15, 27);
80
69.0M
    PI_RHO_STEP(23, 41);
81
69.0M
    PI_RHO_STEP(19, 56);
82
69.0M
    PI_RHO_STEP(13, 8);
83
69.0M
    PI_RHO_STEP(12, 25);
84
69.0M
    PI_RHO_STEP(2, 43);
85
69.0M
    PI_RHO_STEP(20, 62);
86
69.0M
    PI_RHO_STEP(14, 18);
87
69.0M
    PI_RHO_STEP(22, 39);
88
69.0M
    PI_RHO_STEP(9, 61);
89
69.0M
    PI_RHO_STEP(6, 20);
90
69.0M
    PI_RHO_STEP(1, 44);
91
92
69.0M
#undef PI_RHO_STEP
93
94
    // χ step
95
414M
    for (int y = 0; y < 5; y++) {
96
345M
      const int row_index = 5 * y;
97
345M
      const uint64_t orig_x0 = state[row_index];
98
345M
      const uint64_t orig_x1 = state[row_index + 1];
99
345M
      state[row_index] ^= ~orig_x1 & state[row_index + 2];
100
345M
      state[row_index + 1] ^= ~state[row_index + 2] & state[row_index + 3];
101
345M
      state[row_index + 2] ^= ~state[row_index + 3] & state[row_index + 4];
102
345M
      state[row_index + 3] ^= ~state[row_index + 4] & orig_x0;
103
345M
      state[row_index + 4] ^= ~orig_x0 & orig_x1;
104
345M
    }
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
69.0M
    static const uint64_t kRoundConstants[24] = {
114
69.0M
        0x0000000000000001, 0x0000000000008082, 0x800000000000808a,
115
69.0M
        0x8000000080008000, 0x000000000000808b, 0x0000000080000001,
116
69.0M
        0x8000000080008081, 0x8000000000008009, 0x000000000000008a,
117
69.0M
        0x0000000000000088, 0x0000000080008009, 0x000000008000000a,
118
69.0M
        0x000000008000808b, 0x800000000000008b, 0x8000000000008089,
119
69.0M
        0x8000000000008003, 0x8000000000008002, 0x8000000000000080,
120
69.0M
        0x000000000000800a, 0x800000008000000a, 0x8000000080008081,
121
69.0M
        0x8000000000008080, 0x0000000080000001, 0x8000000080008008,
122
69.0M
    };
123
124
69.0M
    state[0] ^= kRoundConstants[round];
125
69.0M
  }
126
2.87M
}
127
128
static void keccak_init(struct BORINGSSL_keccak_st *ctx,
129
1.13M
                        enum boringssl_keccak_config_t config) {
130
1.13M
  size_t required_out_len;
131
1.13M
  size_t capacity_bytes;
132
1.13M
  switch (config) {
133
66.8k
    case boringssl_sha3_256:
134
66.8k
      capacity_bytes = 512 / 8;
135
66.8k
      required_out_len = 32;
136
66.8k
      break;
137
66.7k
    case boringssl_sha3_512:
138
66.7k
      capacity_bytes = 1024 / 8;
139
66.7k
      required_out_len = 64;
140
66.7k
      break;
141
600k
    case boringssl_shake128:
142
600k
      capacity_bytes = 256 / 8;
143
600k
      required_out_len = 0;
144
600k
      break;
145
400k
    case boringssl_shake256:
146
400k
      capacity_bytes = 512 / 8;
147
400k
      required_out_len = 0;
148
400k
      break;
149
0
    default:
150
0
      abort();
151
1.13M
  }
152
153
1.13M
  OPENSSL_memset(ctx, 0, sizeof(*ctx));
154
1.13M
  ctx->config = config;
155
1.13M
  ctx->phase = boringssl_keccak_phase_absorb;
156
1.13M
  ctx->required_out_len = required_out_len;
157
1.13M
  ctx->rate_bytes = 200 - capacity_bytes;
158
1.13M
  assert(ctx->rate_bytes % 8 == 0);
159
1.13M
}
160
161
void BORINGSSL_keccak(uint8_t *out, size_t out_len, const uint8_t *in,
162
534k
                      size_t in_len, enum boringssl_keccak_config_t config) {
163
534k
  struct BORINGSSL_keccak_st ctx;
164
534k
  keccak_init(&ctx, config);
165
534k
  if (ctx.required_out_len != 0 && out_len != ctx.required_out_len) {
166
0
    abort();
167
0
  }
168
534k
  BORINGSSL_keccak_absorb(&ctx, in, in_len);
169
534k
  BORINGSSL_keccak_squeeze(&ctx, out, out_len);
170
534k
}
171
172
void BORINGSSL_keccak_init(struct BORINGSSL_keccak_st *ctx,
173
600k
                           enum boringssl_keccak_config_t config) {
174
600k
  keccak_init(ctx, config);
175
600k
}
176
177
void BORINGSSL_keccak_absorb(struct BORINGSSL_keccak_st *ctx, const uint8_t *in,
178
1.13M
                             size_t in_len) {
179
1.13M
  if (ctx->phase == boringssl_keccak_phase_squeeze) {
180
    // It's illegal to call absorb() again after calling squeeze().
181
0
    abort();
182
0
  }
183
184
1.13M
  const size_t rate_words = ctx->rate_bytes / 8;
185
  // XOR the input. Accessing |ctx->state| as a |uint8_t*| is allowed by strict
186
  // aliasing because we require |uint8_t| to be a character type.
187
1.13M
  uint8_t *state_bytes = (uint8_t *)ctx->state;
188
189
  // Absorb partial block.
190
1.13M
  if (ctx->absorb_offset != 0) {
191
40
    assert(ctx->absorb_offset < ctx->rate_bytes);
192
40
    size_t first_block_len = ctx->rate_bytes - ctx->absorb_offset;
193
4.20k
    for (size_t i = 0; i < first_block_len && i < in_len; i++) {
194
4.16k
      state_bytes[ctx->absorb_offset + i] ^= in[i];
195
4.16k
    }
196
197
    // This input didn't fill the block.
198
40
    if (first_block_len > in_len) {
199
0
      ctx->absorb_offset += in_len;
200
0
      return;
201
0
    }
202
203
40
    keccak_f(ctx->state);
204
40
    in += first_block_len;
205
40
    in_len -= first_block_len;
206
40
  }
207
208
  // Absorb full blocks.
209
1.66M
  while (in_len >= ctx->rate_bytes) {
210
9.62M
    for (size_t i = 0; i < rate_words; i++) {
211
9.09M
      ctx->state[i] ^= CRYPTO_load_u64_le(in + 8 * i);
212
9.09M
    }
213
534k
    keccak_f(ctx->state);
214
534k
    in += ctx->rate_bytes;
215
534k
    in_len -= ctx->rate_bytes;
216
534k
  }
217
218
  // Absorb partial block.
219
1.13M
  assert(in_len < ctx->rate_bytes);
220
43.4M
  for (size_t i = 0; i < in_len; i++) {
221
42.2M
    state_bytes[i] ^= in[i];
222
42.2M
  }
223
1.13M
  ctx->absorb_offset = in_len;
224
1.13M
}
225
226
1.13M
static void keccak_finalize(struct BORINGSSL_keccak_st *ctx) {
227
1.13M
  uint8_t terminator;
228
1.13M
  switch (ctx->config) {
229
66.8k
    case boringssl_sha3_256:
230
133k
    case boringssl_sha3_512:
231
133k
      terminator = 0x06;
232
133k
      break;
233
600k
    case boringssl_shake128:
234
1.00M
    case boringssl_shake256:
235
1.00M
      terminator = 0x1f;
236
1.00M
      break;
237
0
    default:
238
0
      abort();
239
1.13M
  }
240
241
  // XOR the terminator. Accessing |ctx->state| as a |uint8_t*| is allowed by
242
  // strict aliasing because we require |uint8_t| to be a character type.
243
1.13M
  uint8_t *state_bytes = (uint8_t *)ctx->state;
244
1.13M
  state_bytes[ctx->absorb_offset] ^= terminator;
245
1.13M
  state_bytes[ctx->rate_bytes - 1] ^= 0x80;
246
1.13M
  keccak_f(ctx->state);
247
1.13M
}
248
249
void BORINGSSL_keccak_squeeze(struct BORINGSSL_keccak_st *ctx, uint8_t *out,
250
2.34M
                              size_t out_len) {
251
2.34M
  if (ctx->required_out_len != 0 &&
252
133k
      (ctx->phase == boringssl_keccak_phase_squeeze ||
253
133k
       out_len != ctx->required_out_len)) {
254
    // The SHA-3 variants must be squeezed in a single call, to confirm that the
255
    // output length is correct.
256
0
    abort();
257
0
  }
258
259
2.34M
  if (ctx->phase == boringssl_keccak_phase_absorb) {
260
1.13M
    keccak_finalize(ctx);
261
1.13M
    ctx->phase = boringssl_keccak_phase_squeeze;
262
1.13M
  }
263
264
  // Accessing |ctx->state| as a |uint8_t*| is allowed by strict aliasing
265
  // because we require |uint8_t| to be a character type.
266
2.34M
  const uint8_t *state_bytes = (const uint8_t *)ctx->state;
267
4.68M
  while (out_len) {
268
2.34M
    if (ctx->squeeze_offset == ctx->rate_bytes) {
269
1.20M
      keccak_f(ctx->state);
270
1.20M
      ctx->squeeze_offset = 0;
271
1.20M
    }
272
273
2.34M
    size_t remaining = ctx->rate_bytes - ctx->squeeze_offset;
274
2.34M
    size_t todo = out_len;
275
2.34M
    if (todo > remaining) {
276
0
      todo = remaining;
277
0
    }
278
2.34M
    OPENSSL_memcpy(out, &state_bytes[ctx->squeeze_offset], todo);
279
2.34M
    out += todo;
280
2.34M
    out_len -= todo;
281
2.34M
    ctx->squeeze_offset += todo;
282
2.34M
  }
283
2.34M
}