Coverage Report

Created: 2026-10-19 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/crypto/fipsmodule/mlkem/mlkem.cc.inc
Line
Count
Source
1
// Copyright 2014 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 <stdint.h>
19
#include <stdlib.h>
20
#include <string.h>
21
22
#include <openssl/base.h>
23
#include <openssl/bytestring.h>
24
#include <openssl/mem.h>
25
#include <openssl/rand.h>
26
27
#include "../../internal.h"
28
#include "../bcm_interface.h"
29
#include "../keccak/internal.h"
30
31
32
using namespace bssl;
33
34
#if defined(BORINGSSL_FIPS)
35
36
DEFINE_STATIC_ONCE(g_mlkem_keygen_self_test_once)
37
DEFINE_STATIC_ONCE(g_mlkem_encap_self_test_once)
38
DEFINE_STATIC_ONCE(g_mlkem_decap_self_test_once)
39
40
#endif
41
42
namespace mlkem {
43
namespace {
44
45
namespace fips {
46
void ensure_keygen_self_test();
47
void ensure_encap_self_test();
48
void ensure_decap_self_test();
49
}  // namespace fips
50
51
// See
52
// https://csrc.nist.gov/pubs/fips/203/final
53
54
104k
inline void prf(uint8_t *out, size_t out_len, const uint8_t in[33]) {
55
104k
  BORINGSSL_keccak(out, out_len, in, 33, boringssl_shake256);
56
104k
}
57
58
#if defined(HAVE_KECCAK_X2)
59
inline void prf_x2(uint8_t *outs[2], size_t out_len,
60
104k
                   const uint8_t *ins[2] /* 33 each */) {
61
104k
  BORINGSSL_keccak_short_x2(outs, out_len, ins, 33, boringssl_shake256);
62
104k
}
63
#endif
64
65
#if defined(HAVE_KECCAK_X4)
66
inline void prf_x4(uint8_t *outs[4], size_t out_len,
67
188
                   const uint8_t *ins[4] /* 33 each */) {
68
188
  BORINGSSL_keccak_short_x4(outs, out_len, ins, 33, boringssl_shake256);
69
188
}
70
#endif
71
72
// Section 4.1
73
52.5k
void hash_h(uint8_t out[32], const uint8_t *in, size_t len) {
74
52.5k
  BORINGSSL_keccak(out, 32, in, len, boringssl_sha3_256);
75
52.5k
}
76
77
52.0k
void hash_g(uint8_t out[64], const uint8_t *in, size_t len) {
78
52.0k
  BORINGSSL_keccak(out, 64, in, len, boringssl_sha3_512);
79
52.0k
}
80
81
// This is called `J` in the spec.
82
void kdf(uint8_t out[MLKEM_SHARED_SECRET_BYTES],
83
         const uint8_t failure_secret[32], const uint8_t *ciphertext,
84
23
         size_t ciphertext_len) {
85
23
  BORINGSSL_keccak_st st;
86
23
  BORINGSSL_keccak_init(&st, boringssl_shake256);
87
23
  BORINGSSL_keccak_absorb(&st, failure_secret, 32);
88
23
  BORINGSSL_keccak_absorb(&st, ciphertext, ciphertext_len);
89
23
  BORINGSSL_keccak_squeeze(&st, out, MLKEM_SHARED_SECRET_BYTES);
90
23
}
91
92
// Constants that are common across all sizes.
93
344M
#define DEGREE 256
94
const size_t kBarrettMultiplier = 1290167;
95
const unsigned kBarrettShift = 32;
96
const uint16_t kPrime = 3329;
97
const int kLog2Prime = 12;
98
const uint16_t kHalfPrime = (/*kPrime=*/3329 - 1) / 2;
99
// kInverseDegree is 128^-1 mod 3329; 128 because kPrime does not have a 512th
100
// root of unity.
101
const uint16_t kInverseDegree = 3303;
102
103
// Rank-specific constants.
104
1.31k
#define RANK768 3
105
const int kDU768 = 10;
106
const int kDV768 = 4;
107
#define RANK1024 4
108
const int kDU1024 = 11;
109
const int kDV1024 = 5;
110
111
157k
constexpr size_t encoded_vector_size(int rank) {
112
157k
  return (kLog2Prime * DEGREE / 8) * static_cast<size_t>(rank);
113
157k
}
114
115
104k
constexpr size_t encoded_public_key_size(int rank) {
116
104k
  return encoded_vector_size(rank) + /*sizeof(rho)=*/32;
117
104k
}
118
119
static_assert(encoded_public_key_size(RANK768) == MLKEM768_PUBLIC_KEY_BYTES);
120
static_assert(encoded_public_key_size(RANK1024) == MLKEM1024_PUBLIC_KEY_BYTES);
121
122
516
constexpr size_t compressed_vector_size(int rank) {
123
  // `if constexpr` isn't available in C++17.
124
516
  return (rank == RANK768 ? kDU768 : kDU1024) * static_cast<size_t>(rank) *
125
516
         DEGREE / 8;
126
516
}
127
128
235
constexpr size_t ciphertext_size(int rank) {
129
235
  return compressed_vector_size(rank) +
130
235
         (rank == RANK768 ? kDV768 : kDV1024) * DEGREE / 8;
131
235
}
132
133
static_assert(ciphertext_size(RANK768) == MLKEM768_CIPHERTEXT_BYTES);
134
static_assert(ciphertext_size(RANK1024) == MLKEM1024_CIPHERTEXT_BYTES);
135
136
struct scalar {
137
  // On every function entry and exit, 0 <= c < kPrime.
138
  uint16_t c[DEGREE];
139
};
140
141
template <int RANK>
142
struct vector {
143
  scalar v[RANK];
144
};
145
146
template <int RANK>
147
struct matrix {
148
  scalar v[RANK][RANK];
149
};
150
151
// This bit of Python will be referenced in some of the following comments:
152
//
153
// p = 3329
154
//
155
// def bitreverse(i):
156
//     ret = 0
157
//     for n in range(7):
158
//         bit = i & 1
159
//         ret <<= 1
160
//         ret |= bit
161
//         i >>= 1
162
//     return ret
163
164
// kNTTRoots = [pow(17, bitreverse(i), p) for i in range(128)]
165
const uint16_t kNTTRoots[128] = {
166
    1,    1729, 2580, 3289, 2642, 630,  1897, 848,  1062, 1919, 193,  797,
167
    2786, 3260, 569,  1746, 296,  2447, 1339, 1476, 3046, 56,   2240, 1333,
168
    1426, 2094, 535,  2882, 2393, 2879, 1974, 821,  289,  331,  3253, 1756,
169
    1197, 2304, 2277, 2055, 650,  1977, 2513, 632,  2865, 33,   1320, 1915,
170
    2319, 1435, 807,  452,  1438, 2868, 1534, 2402, 2647, 2617, 1481, 648,
171
    2474, 3110, 1227, 910,  17,   2761, 583,  2649, 1637, 723,  2288, 1100,
172
    1409, 2662, 3281, 233,  756,  2156, 3015, 3050, 1703, 1651, 2789, 1789,
173
    1847, 952,  1461, 2687, 939,  2308, 2437, 2388, 733,  2337, 268,  641,
174
    1584, 2298, 2037, 3220, 375,  2549, 2090, 1645, 1063, 319,  2773, 757,
175
    2099, 561,  2466, 2594, 2804, 1092, 403,  1026, 1143, 2150, 2775, 886,
176
    1722, 1212, 1874, 1029, 2110, 2935, 885,  2154,
177
};
178
179
// kInverseNTTRoots = [pow(17, -bitreverse(i), p) for i in range(128)]
180
const uint16_t kInverseNTTRoots[128] = {
181
    1,    1600, 40,   749,  2481, 1432, 2699, 687,  1583, 2760, 69,   543,
182
    2532, 3136, 1410, 2267, 2508, 1355, 450,  936,  447,  2794, 1235, 1903,
183
    1996, 1089, 3273, 283,  1853, 1990, 882,  3033, 2419, 2102, 219,  855,
184
    2681, 1848, 712,  682,  927,  1795, 461,  1891, 2877, 2522, 1894, 1010,
185
    1414, 2009, 3296, 464,  2697, 816,  1352, 2679, 1274, 1052, 1025, 2132,
186
    1573, 76,   2998, 3040, 1175, 2444, 394,  1219, 2300, 1455, 2117, 1607,
187
    2443, 554,  1179, 2186, 2303, 2926, 2237, 525,  735,  863,  2768, 1230,
188
    2572, 556,  3010, 2266, 1684, 1239, 780,  2954, 109,  1292, 1031, 1745,
189
    2688, 3061, 992,  2596, 941,  892,  1021, 2390, 642,  1868, 2377, 1482,
190
    1540, 540,  1678, 1626, 279,  314,  1173, 2573, 3096, 48,   667,  1920,
191
    2229, 1041, 2606, 1692, 680,  2746, 568,  3312,
192
};
193
194
// kModRoots = [pow(17, 2*bitreverse(i) + 1, p) for i in range(128)]
195
const uint16_t kModRoots[128] = {
196
    17,   3312, 2761, 568,  583,  2746, 2649, 680,  1637, 1692, 723,  2606,
197
    2288, 1041, 1100, 2229, 1409, 1920, 2662, 667,  3281, 48,   233,  3096,
198
    756,  2573, 2156, 1173, 3015, 314,  3050, 279,  1703, 1626, 1651, 1678,
199
    2789, 540,  1789, 1540, 1847, 1482, 952,  2377, 1461, 1868, 2687, 642,
200
    939,  2390, 2308, 1021, 2437, 892,  2388, 941,  733,  2596, 2337, 992,
201
    268,  3061, 641,  2688, 1584, 1745, 2298, 1031, 2037, 1292, 3220, 109,
202
    375,  2954, 2549, 780,  2090, 1239, 1645, 1684, 1063, 2266, 319,  3010,
203
    2773, 556,  757,  2572, 2099, 1230, 561,  2768, 2466, 863,  2594, 735,
204
    2804, 525,  1092, 2237, 403,  2926, 1026, 2303, 1143, 2186, 2150, 1179,
205
    2775, 554,  886,  2443, 1722, 1607, 1212, 2117, 1874, 1455, 1029, 2300,
206
    2110, 1219, 2935, 394,  885,  2444, 2154, 1175,
207
};
208
209
// reduce_once reduces 0 <= x < 2*kPrime, mod kPrime.
210
180M
inline uint16_t reduce_once(uint16_t x) {
211
180M
  declassify_assert(x < 2 * kPrime);
212
180M
  const uint16_t subtracted = x - kPrime;
213
180M
  uint16_t mask = 0u - (subtracted >> 15);
214
  // Although this is a constant-time select, we omit a value barrier here.
215
  // Value barriers impede auto-vectorization (likely because it forces the
216
  // value to transit through a general-purpose register). On AArch64, this is a
217
  // difference of 2x.
218
  //
219
  // We usually add value barriers to selects because Clang turns consecutive
220
  // selects with the same condition into a branch instead of CMOV/CSEL. This
221
  // condition does not occur in ML-KEM, so omitting it seems to be safe so far,
222
  // but see `scalar_centered_binomial_distribution_eta_2_with_prf`.
223
180M
  return (mask & x) | (~mask & subtracted);
224
180M
}
225
226
// reduce_partial returns a number equivalent to x mod kPrime. The output is
227
// less than 2 * kPrime. `x` can be any `uint32_t`.
228
420M
inline uint32_t reduce_partial(uint32_t x) {
229
420M
  uint64_t product = (uint64_t)x * kBarrettMultiplier;
230
420M
  uint32_t quotient = (uint32_t)(product >> kBarrettShift);
231
420M
  uint32_t remainder = x - quotient * kPrime;
232
420M
  return remainder;
233
420M
}
234
235
// constant time reduce x mod kPrime using Barrett reduction. `x` can be any
236
// `uint32_t`.
237
140M
inline uint16_t reduce(uint32_t x) { return reduce_once(reduce_partial(x)); }
238
239
// In place number theoretic transform of a given scalar.
240
// Note that MLKEM's kPrime 3329 does not have a 512th root of unity, so this
241
// transform leaves off the last iteration of the usual FFT code, with the 128
242
// relevant roots of unity being stored in `kNTTRoots`. This means the output
243
// should be seen as 128 elements in GF(3329^2), with the coefficients of the
244
// elements being consecutive entries in `s->c`.
245
312k
inline void scalar_ntt(scalar *s) {
246
  // Manually unrolled loop to maximize vectorization.
247
  //
248
  // Intermediate values of `s` are not fully reduced. `ITER` writes to every
249
  // element of `s` exactly once. Each write adds less than 2*kPrime to some
250
  // value from the previous iteration. After seven iterations, each element
251
  // will be less than 15*kPrime. This fits in `uint16_t`, so we never overflow.
252
312k
#define ITER(step, offset)                                                    \
253
2.18M
  {                                                                           \
254
2.18M
    int k = 0;                                                                \
255
41.8M
    for (int i = 0; i < step; i++) {                                          \
256
39.6M
      const uint32_t step_root = kNTTRoots[step + i];                         \
257
319M
      for (int j = k; j < k + offset; j++) {                                  \
258
279M
        uint32_t even = s->c[j];                                              \
259
        /* `reduce_partial` works on values up to 2^32.                       \
260
         * `step_root < kPrime` because it's static data. `s->c[...] < 2^16`  \
261
         * because it's 16-bit. */                                            \
262
279M
        uint32_t odd =                                                        \
263
279M
            reduce_partial(uint32_t{step_root} * uint32_t{s->c[j + offset]}); \
264
279M
        s->c[j] = even + odd;                                                 \
265
279M
        s->c[j + offset] = even + 2 * kPrime - odd;                           \
266
279M
      }                                                                       \
267
39.6M
      k += 2 * offset;                                                        \
268
39.6M
    }                                                                         \
269
2.18M
  }
270
271
  // for (int step = 1; step < DEGREE / 2; step <<= 1)
272
312k
  ITER(1, 128)
273
312k
  ITER(2, 64)
274
312k
  ITER(4, 32)
275
312k
  ITER(8, 16)
276
312k
  ITER(16, 8)
277
312k
  ITER(32, 4)
278
312k
  ITER(64, 2)
279
312k
  static_assert(DEGREE == 256);
280
312k
#undef ITER
281
282
  // Now `s` is correct but the elements are not fully reduced. Reduce them.
283
80.1M
  for (int i = 0; i < DEGREE; i++) {
284
79.8M
    s->c[i] = reduce(s->c[i]);
285
79.8M
  }
286
312k
}
287
288
template <int RANK>
289
103k
inline void vector_ntt(vector<RANK> *a) {
290
416k
  for (int i = 0; i < RANK; i++) {
291
312k
    scalar_ntt(&a->v[i]);
292
312k
  }
293
103k
}
bcm.cc:void mlkem::(anonymous namespace)::vector_ntt<3>(mlkem::(anonymous namespace)::vector<3>*)
Line
Count
Source
289
103k
inline void vector_ntt(vector<RANK> *a) {
290
415k
  for (int i = 0; i < RANK; i++) {
291
311k
    scalar_ntt(&a->v[i]);
292
311k
  }
293
103k
}
bcm.cc:void mlkem::(anonymous namespace)::vector_ntt<4>(mlkem::(anonymous namespace)::vector<4>*)
Line
Count
Source
289
188
inline void vector_ntt(vector<RANK> *a) {
290
940
  for (int i = 0; i < RANK; i++) {
291
752
    scalar_ntt(&a->v[i]);
292
752
  }
293
188
}
294
295
// In place inverse number theoretic transform of a given scalar, with pairs of
296
// entries of s->v being interpreted as elements of GF(3329^2). Just as with the
297
// number theoretic transform, this leaves off the first step of the normal iFFT
298
// to account for the fact that 3329 does not have a 512th root of unity, using
299
// the precomputed 128 roots of unity stored in `kInverseNTTRoots`.
300
//
301
// FIPS 203, Algorithm 10 (`NTT^-1`).
302
1.05k
void scalar_inverse_ntt(scalar *s) {
303
  // Manually unrolled loop to maximize vectorization.
304
  //
305
  // Intermediate values are not fully reduced. `ITER` writes to every element
306
  // exactly once. Each write either adds two values from the previous
307
  // iteration, or is at most 2 * kPrime. After seven iterations, each element
308
  // will be less than 2^7 * kPrime = 128 * kPrime. This fits in `uint32_t`, so
309
  // we never overflow.
310
1.05k
  uint32_t c[DEGREE];
311
1.05k
#define ITER(step, offset, src)                                              \
312
7.38k
  {                                                                          \
313
7.38k
    int k = 0;                                                               \
314
141k
    for (int i = 0; i < step; i++) {                                         \
315
133k
      const uint32_t step_root = kInverseNTTRoots[step + i];                 \
316
1.07M
      for (int j = k; j < k + offset; j++) {                                 \
317
945k
        uint32_t even = (src)[j];                                            \
318
945k
        uint32_t odd = (src)[j + offset];                                    \
319
945k
        c[j] = odd + even;                                                   \
320
        /* `reduce_partial` works on values up to 2^32.                      \
321
         * `step_root < kPrime` because it's static data. The other term is  \
322
         * less than 2^32, and does not overflow because `odd` is at most    \
323
         * 128 * kPrime per the above. */                                    \
324
945k
        c[j + offset] = reduce_partial(uint32_t{step_root} *                 \
325
945k
                                       uint32_t{128 * kPrime + even - odd}); \
326
945k
      }                                                                      \
327
133k
      k += 2 * offset;                                                       \
328
133k
    }                                                                        \
329
7.38k
  }
330
331
  // for (int offset = 2; offset < DEGREE; offset <<= 1)
332
1.05k
  ITER(64, 2, s->c)
333
1.05k
  ITER(32, 4, c)
334
1.05k
  ITER(16, 8, c)
335
1.05k
  ITER(8, 16, c)
336
1.05k
  ITER(4, 32, c)
337
1.05k
  ITER(2, 64, c)
338
1.05k
  ITER(1, 128, c)
339
1.05k
  static_assert(DEGREE == 256);
340
1.05k
#undef ITER
341
342
  // The final multiplication by `kInverseDegree` also fully reduces the
343
  // partially-reduced values above.
344
271k
  for (int i = 0; i < DEGREE; i++) {
345
270k
    s->c[i] = reduce(c[i] * kInverseDegree);
346
270k
  }
347
1.05k
}
348
349
template <int RANK>
350
258
void vector_inverse_ntt(vector<RANK> *a) {
351
1.03k
  for (int i = 0; i < RANK; i++) {
352
774
    scalar_inverse_ntt(&a->v[i]);
353
774
  }
354
258
}
bcm.cc:void mlkem::(anonymous namespace)::vector_inverse_ntt<3>(mlkem::(anonymous namespace)::vector<3>*)
Line
Count
Source
350
258
void vector_inverse_ntt(vector<RANK> *a) {
351
1.03k
  for (int i = 0; i < RANK; i++) {
352
774
    scalar_inverse_ntt(&a->v[i]);
353
774
  }
354
258
}
Unexecuted instantiation: bcm.cc:void mlkem::(anonymous namespace)::vector_inverse_ntt<4>(mlkem::(anonymous namespace)::vector<4>*)
355
356
156k
inline void scalar_add(scalar *lhs, const scalar *rhs) {
357
40.3M
  for (int i = 0; i < DEGREE; i++) {
358
40.1M
    lhs->c[i] = reduce_once(lhs->c[i] + rhs->c[i]);
359
40.1M
  }
360
156k
}
361
362
23
inline void scalar_sub(scalar *lhs, const scalar *rhs) {
363
5.91k
  for (int i = 0; i < DEGREE; i++) {
364
5.88k
    lhs->c[i] = reduce_once(lhs->c[i] - rhs->c[i] + kPrime);
365
5.88k
  }
366
23
}
367
368
// Multiplying two scalars in the number theoretically transformed state. Since
369
// 3329 does not have a 512th root of unity, this means we have to interpret
370
// the 2*ith and (2*i+1)th entries of the scalar as elements of GF(3329)[X]/(X^2
371
// - 17^(2*bitreverse(i)+1)) The value of 17^(2*bitreverse(i)+1) mod 3329 is
372
// stored in the precomputed `kModRoots` table.
373
//
374
// Writing the two elements as a0 + a1*X and b0 + b1*X, and the root as zeta,
375
// their product is (a0*b0 + a1*(b1*zeta)) + (a0*b1 + a1*b0)*X. Products are
376
// only ever needed as terms of a sum, in matrix-vector and inner products, so
377
// they are computed lazily:
378
//
379
// - b1*zeta mod kPrime only depends on the right-hand side, which is shared by
380
//   every row of a matrix-vector product. It is computed once per scalar and
381
//   stored in a `scalar_mulcache`. This is the "asymmetric multiplication" of
382
//   https://eprint.iacr.org/2021/986.
383
// - The terms are summed in a `scalar_accumulator` without any modular
384
//   reduction, and the sum is reduced once, at the end.
385
386
// scalar_mulcache holds, for a scalar b, b[2*i+1] * kModRoots[i] mod kPrime.
387
struct scalar_mulcache {
388
  // On every function entry and exit, 0 <= c < kPrime.
389
  uint16_t c[DEGREE / 2];
390
};
391
392
template <int RANK>
393
struct vector_mulcache {
394
  scalar_mulcache v[RANK];
395
};
396
397
156k
inline void scalar_mulcache_compute(scalar_mulcache *out, const scalar *b) {
398
20.1M
  for (int i = 0; i < DEGREE / 2; i++) {
399
20.0M
    out->c[i] = reduce(uint32_t{b->c[2 * i + 1]} * kModRoots[i]);
400
20.0M
  }
401
156k
}
402
403
template <int RANK>
404
inline void vector_mulcache_compute(vector_mulcache<RANK> *out,
405
52.1k
                                    const vector<RANK> *b) {
406
208k
  for (int i = 0; i < RANK; i++) {
407
156k
    scalar_mulcache_compute(&out->v[i], &b->v[i]);
408
156k
  }
409
52.1k
}
bcm.cc:void mlkem::(anonymous namespace)::vector_mulcache_compute<3>(mlkem::(anonymous namespace)::vector_mulcache<3>*, mlkem::(anonymous namespace)::vector<3> const*)
Line
Count
Source
405
52.0k
                                    const vector<RANK> *b) {
406
208k
  for (int i = 0; i < RANK; i++) {
407
156k
    scalar_mulcache_compute(&out->v[i], &b->v[i]);
408
156k
  }
409
52.0k
}
bcm.cc:void mlkem::(anonymous namespace)::vector_mulcache_compute<4>(mlkem::(anonymous namespace)::vector_mulcache<4>*, mlkem::(anonymous namespace)::vector<4> const*)
Line
Count
Source
405
94
                                    const vector<RANK> *b) {
406
470
  for (int i = 0; i < RANK; i++) {
407
376
    scalar_mulcache_compute(&out->v[i], &b->v[i]);
408
376
  }
409
94
}
410
411
// scalar_accumulator holds a sum of products of scalars, not reduced mod
412
// kPrime.
413
struct scalar_accumulator {
414
  uint32_t c[DEGREE];
415
};
416
417
// Scalars are fully reduced, so each product adds at most 2 * (kPrime - 1)^2 to
418
// each element of a `scalar_accumulator`. Sums have at most RANK1024 terms, so
419
// the elements never overflow.
420
static_assert(uint64_t{RANK1024} * 2 * (kPrime - 1) * (kPrime - 1) <=
421
              UINT32_MAX);
422
423
// scalar_mult_accumulate adds `lhs * rhs` to `acc`. `rhs_cache` must have been
424
// computed from `rhs`.
425
inline void scalar_mult_accumulate(scalar_accumulator *acc, const scalar *lhs,
426
                                   const scalar *rhs,
427
470k
                                   const scalar_mulcache *rhs_cache) {
428
60.6M
  for (int i = 0; i < DEGREE / 2; i++) {
429
60.2M
    const uint32_t lhs_real = lhs->c[2 * i];
430
60.2M
    const uint32_t lhs_img = lhs->c[2 * i + 1];
431
60.2M
    acc->c[2 * i] += lhs_real * rhs->c[2 * i] + lhs_img * rhs_cache->c[i];
432
60.2M
    acc->c[2 * i + 1] += lhs_real * rhs->c[2 * i + 1] + lhs_img * rhs->c[2 * i];
433
60.2M
  }
434
470k
}
435
436
// scalar_from_accumulator sets `out` to `acc` mod kPrime.
437
inline void scalar_from_accumulator(scalar *out,
438
156k
                                    const scalar_accumulator *acc) {
439
40.2M
  for (int i = 0; i < DEGREE; i++) {
440
40.1M
    out->c[i] = reduce(acc->c[i]);
441
40.1M
  }
442
156k
}
443
444
template <int RANK>
445
52.0k
inline void vector_add(vector<RANK> *lhs, const vector<RANK> *rhs) {
446
208k
  for (int i = 0; i < RANK; i++) {
447
156k
    scalar_add(&lhs->v[i], &rhs->v[i]);
448
156k
  }
449
52.0k
}
bcm.cc:void mlkem::(anonymous namespace)::vector_add<3>(mlkem::(anonymous namespace)::vector<3>*, mlkem::(anonymous namespace)::vector<3> const*)
Line
Count
Source
445
52.0k
inline void vector_add(vector<RANK> *lhs, const vector<RANK> *rhs) {
446
208k
  for (int i = 0; i < RANK; i++) {
447
156k
    scalar_add(&lhs->v[i], &rhs->v[i]);
448
156k
  }
449
52.0k
}
bcm.cc:void mlkem::(anonymous namespace)::vector_add<4>(mlkem::(anonymous namespace)::vector<4>*, mlkem::(anonymous namespace)::vector<4> const*)
Line
Count
Source
445
94
inline void vector_add(vector<RANK> *lhs, const vector<RANK> *rhs) {
446
470
  for (int i = 0; i < RANK; i++) {
447
376
    scalar_add(&lhs->v[i], &rhs->v[i]);
448
376
  }
449
94
}
450
451
template <int RANK>
452
inline void matrix_mult(vector<RANK> *out, const matrix<RANK> *m,
453
                        const vector<RANK> *a,
454
258
                        const vector_mulcache<RANK> *a_cache) {
455
1.03k
  for (int i = 0; i < RANK; i++) {
456
774
    scalar_accumulator acc = {};
457
3.09k
    for (int j = 0; j < RANK; j++) {
458
2.32k
      scalar_mult_accumulate(&acc, &m->v[i][j], &a->v[j], &a_cache->v[j]);
459
2.32k
    }
460
774
    scalar_from_accumulator(&out->v[i], &acc);
461
774
  }
462
258
}
bcm.cc:void mlkem::(anonymous namespace)::matrix_mult<3>(mlkem::(anonymous namespace)::vector<3>*, mlkem::(anonymous namespace)::matrix<3> const*, mlkem::(anonymous namespace)::vector<3> const*, mlkem::(anonymous namespace)::vector_mulcache<3> const*)
Line
Count
Source
454
258
                        const vector_mulcache<RANK> *a_cache) {
455
1.03k
  for (int i = 0; i < RANK; i++) {
456
774
    scalar_accumulator acc = {};
457
3.09k
    for (int j = 0; j < RANK; j++) {
458
2.32k
      scalar_mult_accumulate(&acc, &m->v[i][j], &a->v[j], &a_cache->v[j]);
459
2.32k
    }
460
774
    scalar_from_accumulator(&out->v[i], &acc);
461
774
  }
462
258
}
Unexecuted instantiation: bcm.cc:void mlkem::(anonymous namespace)::matrix_mult<4>(mlkem::(anonymous namespace)::vector<4>*, mlkem::(anonymous namespace)::matrix<4> const*, mlkem::(anonymous namespace)::vector<4> const*, mlkem::(anonymous namespace)::vector_mulcache<4> const*)
463
464
template <int RANK>
465
inline void matrix_mult_transpose(vector<RANK> *out, const matrix<RANK> *m,
466
                                  const vector<RANK> *a,
467
51.8k
                                  const vector_mulcache<RANK> *a_cache) {
468
207k
  for (int i = 0; i < RANK; i++) {
469
155k
    scalar_accumulator acc = {};
470
622k
    for (int j = 0; j < RANK; j++) {
471
467k
      scalar_mult_accumulate(&acc, &m->v[j][i], &a->v[j], &a_cache->v[j]);
472
467k
    }
473
155k
    scalar_from_accumulator(&out->v[i], &acc);
474
155k
  }
475
51.8k
}
bcm.cc:void mlkem::(anonymous namespace)::matrix_mult_transpose<3>(mlkem::(anonymous namespace)::vector<3>*, mlkem::(anonymous namespace)::matrix<3> const*, mlkem::(anonymous namespace)::vector<3> const*, mlkem::(anonymous namespace)::vector_mulcache<3> const*)
Line
Count
Source
467
51.7k
                                  const vector_mulcache<RANK> *a_cache) {
468
206k
  for (int i = 0; i < RANK; i++) {
469
155k
    scalar_accumulator acc = {};
470
620k
    for (int j = 0; j < RANK; j++) {
471
465k
      scalar_mult_accumulate(&acc, &m->v[j][i], &a->v[j], &a_cache->v[j]);
472
465k
    }
473
155k
    scalar_from_accumulator(&out->v[i], &acc);
474
155k
  }
475
51.7k
}
bcm.cc:void mlkem::(anonymous namespace)::matrix_mult_transpose<4>(mlkem::(anonymous namespace)::vector<4>*, mlkem::(anonymous namespace)::matrix<4> const*, mlkem::(anonymous namespace)::vector<4> const*, mlkem::(anonymous namespace)::vector_mulcache<4> const*)
Line
Count
Source
467
94
                                  const vector_mulcache<RANK> *a_cache) {
468
470
  for (int i = 0; i < RANK; i++) {
469
376
    scalar_accumulator acc = {};
470
1.88k
    for (int j = 0; j < RANK; j++) {
471
1.50k
      scalar_mult_accumulate(&acc, &m->v[j][i], &a->v[j], &a_cache->v[j]);
472
1.50k
    }
473
376
    scalar_from_accumulator(&out->v[i], &acc);
474
376
  }
475
94
}
476
477
template <int RANK>
478
inline void scalar_inner_product(scalar *out, const vector<RANK> *lhs,
479
                                 const vector<RANK> *rhs,
480
281
                                 const vector_mulcache<RANK> *rhs_cache) {
481
281
  scalar_accumulator acc = {};
482
1.12k
  for (int i = 0; i < RANK; i++) {
483
843
    scalar_mult_accumulate(&acc, &lhs->v[i], &rhs->v[i], &rhs_cache->v[i]);
484
843
  }
485
281
  scalar_from_accumulator(out, &acc);
486
281
}
bcm.cc:void mlkem::(anonymous namespace)::scalar_inner_product<3>(mlkem::(anonymous namespace)::scalar*, mlkem::(anonymous namespace)::vector<3> const*, mlkem::(anonymous namespace)::vector<3> const*, mlkem::(anonymous namespace)::vector_mulcache<3> const*)
Line
Count
Source
480
281
                                 const vector_mulcache<RANK> *rhs_cache) {
481
281
  scalar_accumulator acc = {};
482
1.12k
  for (int i = 0; i < RANK; i++) {
483
843
    scalar_mult_accumulate(&acc, &lhs->v[i], &rhs->v[i], &rhs_cache->v[i]);
484
843
  }
485
281
  scalar_from_accumulator(out, &acc);
486
281
}
Unexecuted instantiation: bcm.cc:void mlkem::(anonymous namespace)::scalar_inner_product<4>(mlkem::(anonymous namespace)::scalar*, mlkem::(anonymous namespace)::vector<4> const*, mlkem::(anonymous namespace)::vector<4> const*, mlkem::(anonymous namespace)::vector_mulcache<4> const*)
487
488
inline void scalar_from_keccak_block_vartime(scalar *out, int *done,
489
1.43M
                                             const uint8_t block[168]) {
490
  // kStep is the number of loop iterations to do at once. May need to become
491
  // platform dependent at some point. Must be a compile-time constant - if we
492
  // ever need to runtime dispatch on it, it has to be made a template argument.
493
1.43M
  const size_t kStep = 2;
494
495
  // Branchless sampling as long as there is enough space in the output buffer
496
  // even if all sampled numbers are < `kPrime`.
497
1.43M
  size_t i = 0;
498
38.5M
  for (; i <= size_t{168 - 3 * kStep} && *done <= int{DEGREE - 2 * kStep};
499
37.0M
       i += 3 * kStep) {
500
37.0M
    uint16_t d[2 * kStep];
501
111M
    for (size_t k = 0; k < kStep; ++k) {
502
74.1M
      size_t di = 2 * k;
503
74.1M
      size_t bi = i + 3 * k;
504
74.1M
      d[di] = block[bi] + 256 * (block[bi + 1] % 16);
505
74.1M
      d[di + 1] = block[bi + 1] / 16 + 16 * block[bi + 2];
506
74.1M
    }
507
185M
    for (size_t k = 0; k < 2 * kStep; ++k) {
508
148M
      out->c[*done] = d[k];
509
148M
      *done += d[k] < kPrime;
510
148M
    }
511
37.0M
  }
512
513
  // Branchful "tail".
514
2.07M
  for (; i < 168 && *done < DEGREE; i += 3) {
515
639k
    uint16_t d1 = block[i] + 256 * (block[i + 1] % 16);
516
639k
    uint16_t d2 = block[i + 1] / 16 + 16 * block[i + 2];
517
639k
    if (d1 < kPrime) {
518
518k
      out->c[(*done)++] = d1;
519
518k
    }
520
639k
    if (d2 < kPrime && *done < DEGREE) {
521
326k
      out->c[(*done)++] = d2;
522
326k
    }
523
639k
  }
524
1.43M
}
525
526
// Algorithm 7 from the spec. Rejection samples a Keccak stream to get
527
// uniformly distributed elements. This is used for matrix expansion and only
528
// operates on public inputs.
529
inline void scalar_from_keccak_vartime(scalar *out,
530
52.3k
                                       BORINGSSL_keccak_st *keccak_ctx) {
531
52.3k
  assert(keccak_ctx->squeeze_offset == 0);
532
52.3k
  assert(keccak_ctx->rate_bytes == 168);
533
52.3k
  static_assert(168 % 3 == 0, "block and coefficient boundaries do not align");
534
535
52.3k
  int done = 0;
536
209k
  while (done < DEGREE) {
537
157k
    uint8_t block[168];
538
157k
    BORINGSSL_keccak_squeeze(keccak_ctx, block, sizeof(block));
539
157k
    scalar_from_keccak_block_vartime(out, &done, block);
540
157k
  }
541
52.3k
}
542
543
#if defined(HAVE_KECCAK_X2)
544
inline void scalar_from_keccak_vartime_x2(scalar *out[2],
545
0
                                          BORINGSSL_keccak_st keccak_ctx[2]) {
546
0
  assert(keccak_ctx[0].squeeze_offset == 0);
547
0
  assert(keccak_ctx[0].rate_bytes == 168);
548
0
  assert(keccak_ctx[1].squeeze_offset == 0);
549
0
  assert(keccak_ctx[1].rate_bytes == 168);
550
0
  static_assert(168 % 3 == 0, "block and coefficient boundaries do not align");
551
552
0
  int done[2] = {0, 0};
553
0
  while (done[0] < DEGREE || done[1] < DEGREE) {
554
0
    uint8_t block[2][168];
555
0
    uint8_t *blocks[] = {block[0], block[1]};
556
0
    BORINGSSL_keccak_squeeze_x2(keccak_ctx, blocks, sizeof(block[0]));
557
0
    scalar_from_keccak_block_vartime(out[0], &done[0], block[0]);
558
0
    scalar_from_keccak_block_vartime(out[1], &done[1], block[1]);
559
0
  }
560
0
}
561
#endif
562
563
#if defined(HAVE_KECCAK_X4)
564
inline void scalar_from_keccak_vartime_x4(scalar *out[4],
565
105k
                                          BORINGSSL_keccak_st keccak_ctx[]) {
566
527k
  for (int i = 0; i < 4; i++) {
567
421k
    assert(keccak_ctx[i].squeeze_offset == 0);
568
421k
    assert(keccak_ctx[i].rate_bytes == 168);
569
421k
  }
570
105k
  static_assert(168 % 3 == 0, "block and coefficient boundaries do not align");
571
572
105k
  int done[4] = {0, 0, 0, 0};
573
425k
  while (done[0] < DEGREE || done[1] < DEGREE || done[2] < DEGREE ||
574
319k
         done[3] < DEGREE) {
575
319k
    uint8_t block[4][168];
576
319k
    uint8_t *blocks[] = {block[0], block[1], block[2], block[3]};
577
319k
    BORINGSSL_keccak_squeeze_x4(keccak_ctx, blocks, sizeof(block[0]));
578
319k
    scalar_from_keccak_block_vartime(out[0], &done[0], block[0]);
579
319k
    scalar_from_keccak_block_vartime(out[1], &done[1], block[1]);
580
319k
    scalar_from_keccak_block_vartime(out[2], &done[2], block[2]);
581
319k
    scalar_from_keccak_block_vartime(out[3], &done[3], block[3]);
582
319k
  }
583
105k
}
584
#endif
585
586
static void scalar_centered_binomial_distribution_eta_2(
587
313k
    scalar *out, const uint8_t entropy[128]) {
588
40.3M
  for (int i = 0; i < DEGREE; i += 2) {
589
40.0M
    uint8_t byte = entropy[i / 2];
590
591
40.0M
    uint16_t value = (byte & 1) + ((byte >> 1) & 1);
592
40.0M
    value -= ((byte >> 2) & 1) + ((byte >> 3) & 1);
593
    // Add `kPrime` if `value` underflowed. See `reduce_once` for a discussion
594
    // on why the value barrier is omitted. While this could have been written
595
    // reduce_once(value + kPrime), this is one extra addition and small range
596
    // of `value` tempts some versions of Clang to emit a branch.
597
40.0M
    uint16_t mask = 0u - (value >> 15);
598
40.0M
    out->c[i] = ((value + kPrime) & mask) | (value & ~mask);
599
600
40.0M
    byte >>= 4;
601
40.0M
    value = (byte & 1) + ((byte >> 1) & 1);
602
40.0M
    value -= ((byte >> 2) & 1) + ((byte >> 3) & 1);
603
    // See above.
604
40.0M
    mask = 0u - (value >> 15);
605
40.0M
    out->c[i + 1] = ((value + kPrime) & mask) | (value & ~mask);
606
40.0M
  }
607
313k
}
608
609
// Algorithm 8 from the spec, with eta fixed to two and the PRF call
610
// included. Creates binominally distributed elements by sampling 2*`eta` bits,
611
// and setting the coefficient to the count of the first bits minus the count of
612
// the second bits, resulting in a centered binomial distribution. Since eta is
613
// two this gives -2/2 with a probability of 1/16, -1/1 with probability 1/4,
614
// and 0 with probability 3/8.
615
void scalar_centered_binomial_distribution_eta_2_with_prf(
616
104k
    scalar *out, const uint8_t input[33]) {
617
104k
  uint8_t entropy[128];
618
104k
  static_assert(sizeof(entropy) == 2 * /*kEta=*/2 * DEGREE / 8);
619
104k
  prf(entropy, sizeof(entropy), input);
620
104k
  scalar_centered_binomial_distribution_eta_2(out, entropy);
621
104k
}
622
623
#if defined(HAVE_KECCAK_X2)
624
// scalar_centered_binomial_distribution_eta_2_with_prf_x2 computes two blocks
625
// of scalar_centered_binomial_distribution_eta_2_with_prf.
626
static void scalar_centered_binomial_distribution_eta_2_with_prf_x2(
627
104k
    scalar out[2], uint8_t input[33]) {
628
104k
  uint8_t entropy[2][128];
629
104k
  static_assert(sizeof(entropy[0]) == 2 * /*kEta=*/2 * DEGREE / 8);
630
631
104k
  uint8_t input1[33];
632
104k
  OPENSSL_memcpy(input1, input, 33);
633
104k
  ++input1[32];  // Counter.
634
635
104k
  uint8_t *entropies[] = {entropy[0], entropy[1]};
636
104k
  const uint8_t *inputs[2] = {input, input1};
637
104k
  prf_x2(entropies, sizeof(entropy[0]), inputs);
638
639
312k
  for (int k = 0; k < 2; k++) {
640
208k
    scalar_centered_binomial_distribution_eta_2(&out[k], entropy[k]);
641
208k
  }
642
104k
}
643
#endif
644
645
#if defined(HAVE_KECCAK_X4)
646
// scalar_centered_binomial_distribution_eta_2_with_prf_x4 computes four blocks
647
// of scalar_centered_binomial_distribution_eta_2_with_prf.
648
static void scalar_centered_binomial_distribution_eta_2_with_prf_x4(
649
188
    scalar out[4], uint8_t input[33]) {
650
188
  uint8_t entropy[4][128];
651
188
  static_assert(sizeof(entropy[0]) == 2 * /*kEta=*/2 * DEGREE / 8);
652
653
188
  uint8_t inputs[4][33];
654
940
  for (int i = 0; i < 4; i++) {
655
752
    OPENSSL_memcpy(inputs[i], input, 33);
656
752
    inputs[i][32] += i;
657
752
  }
658
188
  uint8_t *entropies[] = {entropy[0], entropy[1], entropy[2], entropy[3]};
659
188
  const uint8_t *input_ptrs[4] = {inputs[0], inputs[1], inputs[2], inputs[3]};
660
188
  prf_x4(entropies, sizeof(entropy[0]), input_ptrs);
661
662
940
  for (int k = 0; k < 4; k++) {
663
752
    scalar_centered_binomial_distribution_eta_2(&out[k], entropy[k]);
664
752
  }
665
188
}
666
#endif
667
668
// Generates a secret vector by using
669
// `scalar_centered_binomial_distribution_eta_2_with_prf`, using the given seed
670
// appending and incrementing `counter` for entry of the vector.
671
template <int RANK>
672
void vector_generate_secret_eta_2(vector<RANK> *out, uint8_t *counter,
673
104k
                                  const uint8_t seed[32]) {
674
104k
  uint8_t input[33];
675
104k
  OPENSSL_memcpy(input, seed, 32);
676
677
104k
  int i = 0;
678
104k
#if defined(HAVE_KECCAK_X4)
679
104k
  if (BORINGSSL_have_keccak_x4()) {
680
104k
    for (; i + 4 <= RANK; i += 4) {
681
188
      input[32] = *counter;
682
188
      *counter += 4;
683
188
      scalar_centered_binomial_distribution_eta_2_with_prf_x4(&out->v[i],
684
188
                                                              input);
685
188
    }
686
104k
  }
687
104k
#endif
688
104k
#if defined(HAVE_KECCAK_X2)
689
208k
  for (; i + 2 <= RANK; i += 2) {
690
104k
    input[32] = *counter;
691
104k
    *counter += 2;
692
104k
    scalar_centered_binomial_distribution_eta_2_with_prf_x2(&out->v[i], input);
693
104k
  }
694
104k
#endif
695
696
208k
  for (; i < RANK; i++) {
697
104k
    input[32] = (*counter)++;
698
104k
    scalar_centered_binomial_distribution_eta_2_with_prf(&out->v[i], input);
699
104k
  }
700
104k
}
bcm.cc:void mlkem::(anonymous namespace)::vector_generate_secret_eta_2<3>(mlkem::(anonymous namespace)::vector<3>*, unsigned char*, unsigned char const*)
Line
Count
Source
673
104k
                                  const uint8_t seed[32]) {
674
104k
  uint8_t input[33];
675
104k
  OPENSSL_memcpy(input, seed, 32);
676
677
104k
  int i = 0;
678
104k
#if defined(HAVE_KECCAK_X4)
679
104k
  if (BORINGSSL_have_keccak_x4()) {
680
104k
    for (; i + 4 <= RANK; i += 4) {
681
0
      input[32] = *counter;
682
0
      *counter += 4;
683
0
      scalar_centered_binomial_distribution_eta_2_with_prf_x4(&out->v[i],
684
0
                                                              input);
685
0
    }
686
104k
  }
687
104k
#endif
688
104k
#if defined(HAVE_KECCAK_X2)
689
208k
  for (; i + 2 <= RANK; i += 2) {
690
104k
    input[32] = *counter;
691
104k
    *counter += 2;
692
104k
    scalar_centered_binomial_distribution_eta_2_with_prf_x2(&out->v[i], input);
693
104k
  }
694
104k
#endif
695
696
208k
  for (; i < RANK; i++) {
697
104k
    input[32] = (*counter)++;
698
104k
    scalar_centered_binomial_distribution_eta_2_with_prf(&out->v[i], input);
699
104k
  }
700
104k
}
bcm.cc:void mlkem::(anonymous namespace)::vector_generate_secret_eta_2<4>(mlkem::(anonymous namespace)::vector<4>*, unsigned char*, unsigned char const*)
Line
Count
Source
673
188
                                  const uint8_t seed[32]) {
674
188
  uint8_t input[33];
675
188
  OPENSSL_memcpy(input, seed, 32);
676
677
188
  int i = 0;
678
188
#if defined(HAVE_KECCAK_X4)
679
188
  if (BORINGSSL_have_keccak_x4()) {
680
376
    for (; i + 4 <= RANK; i += 4) {
681
188
      input[32] = *counter;
682
188
      *counter += 4;
683
188
      scalar_centered_binomial_distribution_eta_2_with_prf_x4(&out->v[i],
684
188
                                                              input);
685
188
    }
686
188
  }
687
188
#endif
688
188
#if defined(HAVE_KECCAK_X2)
689
188
  for (; i + 2 <= RANK; i += 2) {
690
0
    input[32] = *counter;
691
0
    *counter += 2;
692
0
    scalar_centered_binomial_distribution_eta_2_with_prf_x2(&out->v[i], input);
693
0
  }
694
188
#endif
695
696
188
  for (; i < RANK; i++) {
697
0
    input[32] = (*counter)++;
698
0
    scalar_centered_binomial_distribution_eta_2_with_prf(&out->v[i], input);
699
0
  }
700
188
}
701
702
template <int RANK>
703
52.3k
void matrix_expand_step(scalar *out, uint8_t input[34], int i) {
704
52.3k
  input[32] = i / RANK;
705
52.3k
  input[33] = i % RANK;
706
52.3k
  BORINGSSL_keccak_st keccak_ctx;
707
52.3k
  BORINGSSL_keccak_init(&keccak_ctx, boringssl_shake128);
708
52.3k
  BORINGSSL_keccak_absorb(&keccak_ctx, input, 34);
709
52.3k
  scalar_from_keccak_vartime(out, &keccak_ctx);
710
52.3k
}
bcm.cc:void mlkem::(anonymous namespace)::matrix_expand_step<3>(mlkem::(anonymous namespace)::scalar*, unsigned char*, int)
Line
Count
Source
703
52.3k
void matrix_expand_step(scalar *out, uint8_t input[34], int i) {
704
52.3k
  input[32] = i / RANK;
705
52.3k
  input[33] = i % RANK;
706
52.3k
  BORINGSSL_keccak_st keccak_ctx;
707
52.3k
  BORINGSSL_keccak_init(&keccak_ctx, boringssl_shake128);
708
52.3k
  BORINGSSL_keccak_absorb(&keccak_ctx, input, 34);
709
52.3k
  scalar_from_keccak_vartime(out, &keccak_ctx);
710
52.3k
}
Unexecuted instantiation: bcm.cc:void mlkem::(anonymous namespace)::matrix_expand_step<4>(mlkem::(anonymous namespace)::scalar*, unsigned char*, int)
711
712
#if defined(HAVE_KECCAK_X2)
713
template <int RANK>
714
0
void matrix_expand_step_x2(matrix<RANK> *out, uint8_t input[34], int i) {
715
0
  input[32] = i / RANK;
716
0
  input[33] = i % RANK;
717
0
  uint8_t input1[34];
718
0
  OPENSSL_memcpy(input1, input, 32);
719
0
  input1[32] = (i + 1) / RANK;
720
0
  input1[33] = (i + 1) % RANK;
721
0
  BORINGSSL_keccak_st keccak_ctx[2];
722
0
  BORINGSSL_keccak_init(&keccak_ctx[0], boringssl_shake128);
723
0
  BORINGSSL_keccak_init(&keccak_ctx[1], boringssl_shake128);
724
0
  BORINGSSL_keccak_absorb(&keccak_ctx[0], input, 34);
725
0
  BORINGSSL_keccak_absorb(&keccak_ctx[1], input1, 34);
726
0
  scalar *outs[] = {&out->v[i / RANK][i % RANK],
727
0
                    &out->v[(i + 1) / RANK][(i + 1) % RANK]};
728
0
  scalar_from_keccak_vartime_x2(outs, keccak_ctx);
729
0
}
Unexecuted instantiation: bcm.cc:void mlkem::(anonymous namespace)::matrix_expand_step_x2<3>(mlkem::(anonymous namespace)::matrix<3>*, unsigned char*, int)
Unexecuted instantiation: bcm.cc:void mlkem::(anonymous namespace)::matrix_expand_step_x2<4>(mlkem::(anonymous namespace)::matrix<4>*, unsigned char*, int)
730
#endif
731
732
#if defined(HAVE_KECCAK_X4)
733
template <int RANK>
734
105k
void matrix_expand_step_x4(matrix<RANK> *out, uint8_t input[34], int i) {
735
105k
  uint8_t inputs[4][34];
736
105k
  BORINGSSL_keccak_st keccak_ctx[4];
737
527k
  for (int k = 0; k < 4; k++) {
738
421k
    OPENSSL_memcpy(inputs[k], input, 32);
739
421k
    inputs[k][32] = (i + k) / RANK;
740
421k
    inputs[k][33] = (i + k) % RANK;
741
421k
    BORINGSSL_keccak_init(&keccak_ctx[k], boringssl_shake128);
742
421k
    BORINGSSL_keccak_absorb(&keccak_ctx[k], inputs[k], 34);
743
421k
  }
744
105k
  scalar *outs[] = {&out->v[i / RANK][i % RANK],
745
105k
                    &out->v[(i + 1) / RANK][(i + 1) % RANK],
746
105k
                    &out->v[(i + 2) / RANK][(i + 2) % RANK],
747
105k
                    &out->v[(i + 3) / RANK][(i + 3) % RANK]};
748
105k
  scalar_from_keccak_vartime_x4(outs, keccak_ctx);
749
105k
}
bcm.cc:void mlkem::(anonymous namespace)::matrix_expand_step_x4<3>(mlkem::(anonymous namespace)::matrix<3>*, unsigned char*, int)
Line
Count
Source
734
104k
void matrix_expand_step_x4(matrix<RANK> *out, uint8_t input[34], int i) {
735
104k
  uint8_t inputs[4][34];
736
104k
  BORINGSSL_keccak_st keccak_ctx[4];
737
523k
  for (int k = 0; k < 4; k++) {
738
418k
    OPENSSL_memcpy(inputs[k], input, 32);
739
418k
    inputs[k][32] = (i + k) / RANK;
740
418k
    inputs[k][33] = (i + k) % RANK;
741
418k
    BORINGSSL_keccak_init(&keccak_ctx[k], boringssl_shake128);
742
418k
    BORINGSSL_keccak_absorb(&keccak_ctx[k], inputs[k], 34);
743
418k
  }
744
104k
  scalar *outs[] = {&out->v[i / RANK][i % RANK],
745
104k
                    &out->v[(i + 1) / RANK][(i + 1) % RANK],
746
104k
                    &out->v[(i + 2) / RANK][(i + 2) % RANK],
747
104k
                    &out->v[(i + 3) / RANK][(i + 3) % RANK]};
748
104k
  scalar_from_keccak_vartime_x4(outs, keccak_ctx);
749
104k
}
bcm.cc:void mlkem::(anonymous namespace)::matrix_expand_step_x4<4>(mlkem::(anonymous namespace)::matrix<4>*, unsigned char*, int)
Line
Count
Source
734
696
void matrix_expand_step_x4(matrix<RANK> *out, uint8_t input[34], int i) {
735
696
  uint8_t inputs[4][34];
736
696
  BORINGSSL_keccak_st keccak_ctx[4];
737
3.48k
  for (int k = 0; k < 4; k++) {
738
2.78k
    OPENSSL_memcpy(inputs[k], input, 32);
739
2.78k
    inputs[k][32] = (i + k) / RANK;
740
2.78k
    inputs[k][33] = (i + k) % RANK;
741
2.78k
    BORINGSSL_keccak_init(&keccak_ctx[k], boringssl_shake128);
742
2.78k
    BORINGSSL_keccak_absorb(&keccak_ctx[k], inputs[k], 34);
743
2.78k
  }
744
696
  scalar *outs[] = {&out->v[i / RANK][i % RANK],
745
696
                    &out->v[(i + 1) / RANK][(i + 1) % RANK],
746
696
                    &out->v[(i + 2) / RANK][(i + 2) % RANK],
747
696
                    &out->v[(i + 3) / RANK][(i + 3) % RANK]};
748
696
  scalar_from_keccak_vartime_x4(outs, keccak_ctx);
749
696
}
750
#endif
751
752
// Expands the matrix of a seed for key generation and for encaps-CPA.
753
template <int RANK>
754
52.5k
void matrix_expand(matrix<RANK> *out, const uint8_t rho[32]) {
755
52.5k
  uint8_t input[34];
756
52.5k
  OPENSSL_memcpy(input, rho, 32);
757
758
52.5k
  int i = 0;
759
52.5k
#if defined(HAVE_KECCAK_X4)
760
52.5k
  if (BORINGSSL_have_keccak_x4()) {
761
157k
    for (; i + 4 <= RANK * RANK; i += 4) {
762
105k
      matrix_expand_step_x4<RANK>(out, input, i);
763
105k
    }
764
52.5k
  }
765
52.5k
#endif
766
52.5k
#if defined(HAVE_KECCAK_X2)
767
52.5k
  for (; i + 2 <= RANK * RANK; i += 2) {
768
0
    matrix_expand_step_x2<RANK>(out, input, i);
769
0
  }
770
52.5k
#endif
771
772
104k
  for (; i < RANK * RANK; i++) {
773
52.3k
    matrix_expand_step<RANK>(&out->v[i / RANK][i % RANK], input, i);
774
52.3k
  }
775
52.5k
}
bcm.cc:void mlkem::(anonymous namespace)::matrix_expand<3>(mlkem::(anonymous namespace)::matrix<3>*, unsigned char const*)
Line
Count
Source
754
52.3k
void matrix_expand(matrix<RANK> *out, const uint8_t rho[32]) {
755
52.3k
  uint8_t input[34];
756
52.3k
  OPENSSL_memcpy(input, rho, 32);
757
758
52.3k
  int i = 0;
759
52.3k
#if defined(HAVE_KECCAK_X4)
760
52.3k
  if (BORINGSSL_have_keccak_x4()) {
761
157k
    for (; i + 4 <= RANK * RANK; i += 4) {
762
104k
      matrix_expand_step_x4<RANK>(out, input, i);
763
104k
    }
764
52.3k
  }
765
52.3k
#endif
766
52.3k
#if defined(HAVE_KECCAK_X2)
767
52.3k
  for (; i + 2 <= RANK * RANK; i += 2) {
768
0
    matrix_expand_step_x2<RANK>(out, input, i);
769
0
  }
770
52.3k
#endif
771
772
104k
  for (; i < RANK * RANK; i++) {
773
52.3k
    matrix_expand_step<RANK>(&out->v[i / RANK][i % RANK], input, i);
774
52.3k
  }
775
52.3k
}
bcm.cc:void mlkem::(anonymous namespace)::matrix_expand<4>(mlkem::(anonymous namespace)::matrix<4>*, unsigned char const*)
Line
Count
Source
754
174
void matrix_expand(matrix<RANK> *out, const uint8_t rho[32]) {
755
174
  uint8_t input[34];
756
174
  OPENSSL_memcpy(input, rho, 32);
757
758
174
  int i = 0;
759
174
#if defined(HAVE_KECCAK_X4)
760
174
  if (BORINGSSL_have_keccak_x4()) {
761
870
    for (; i + 4 <= RANK * RANK; i += 4) {
762
696
      matrix_expand_step_x4<RANK>(out, input, i);
763
696
    }
764
174
  }
765
174
#endif
766
174
#if defined(HAVE_KECCAK_X2)
767
174
  for (; i + 2 <= RANK * RANK; i += 2) {
768
0
    matrix_expand_step_x2<RANK>(out, input, i);
769
0
  }
770
174
#endif
771
772
174
  for (; i < RANK * RANK; i++) {
773
0
    matrix_expand_step<RANK>(&out->v[i / RANK][i % RANK], input, i);
774
0
  }
775
174
}
776
777
// Encodes a scalar of 256 `BITS`-bit words into 32*`BITS` bytes by splitting
778
// and joining into bytes using LSB-first bit order (i.e. opposite to standard
779
// reading order). See below for examples. If an input is >= 1 << `BITS`, the
780
// result is undefined.
781
template <int BITS>
782
void scalar_encode(uint8_t *out, const scalar *s);
783
784
// Encodes a scalar of 256 10-bit words into 320 bytes as follows:
785
// 000000Aaaaaaaaaa 000000Bbbbbbbbbb 000000Cccccccccc 000000Dddddddddd ...
786
// -> aaaaaaaa bbbbbbAa ccccBbbb ddCccccc Dddddddd ...
787
template <>
788
774
void scalar_encode<10>(uint8_t out[320], const scalar *s) {
789
50.3k
  for (int i = 0; i < DEGREE; i += 4) {
790
49.5k
    uint16_t s0 = s->c[i];
791
49.5k
    uint16_t s1 = s->c[i + 1];
792
49.5k
    uint16_t s2 = s->c[i + 2];
793
49.5k
    uint16_t s3 = s->c[i + 3];
794
49.5k
    declassify_assert((s0 | s1 | s2 | s3) < (1 << 10));
795
49.5k
    out[0] = (uint8_t)s0;
796
49.5k
    out[1] = (uint8_t)((s0 >> 8) | (s1 << 2));
797
49.5k
    out[2] = (uint8_t)((s1 >> 6) | (s2 << 4));
798
49.5k
    out[3] = (uint8_t)((s2 >> 4) | (s3 << 6));
799
49.5k
    out[4] = (uint8_t)(s3 >> 2);
800
49.5k
    out += 5;
801
49.5k
  }
802
774
}
803
804
// Encodes a scalar of 256 12-bit words into 384 bytes as follows:
805
// 0000Aaaaaaaaaaaa 0000Bbbbbbbbbbbb 0000Cccccccccccc 0000Dddddddddddd ...
806
// -> aaaaaaaa bbbbAaaa Bbbbbbbb cccccccc ddddCccc Dddddddd ....
807
template <>
808
156k
void scalar_encode<12>(uint8_t out[384], const scalar *s) {
809
20.1M
  for (int i = 0; i < DEGREE; i += 2) {
810
19.9M
    uint16_t s0 = s->c[i];
811
19.9M
    uint16_t s1 = s->c[i + 1];
812
19.9M
    declassify_assert((s0 | s1) < (1 << 12));
813
19.9M
    out[0] = (uint8_t)s0;
814
19.9M
    out[1] = (uint8_t)((s0 >> 8) | (s1 << 4));
815
19.9M
    out[2] = (uint8_t)(s1 >> 4);
816
19.9M
    out += 3;
817
19.9M
  }
818
156k
}
819
820
// Encodes a scalar of 256 4-bit words into 128 bytes as follows:
821
// 000000000000Aaaa 00000000000Bbbb 000000000000Cccc 000000000000Dddd ...
822
// -> BbbbAaaa DdddCccc ...
823
template <>
824
258
void scalar_encode<4>(uint8_t out[128], const scalar *s) {
825
33.2k
  for (int i = 0; i < DEGREE; i += 2) {
826
33.0k
    uint16_t s0 = s->c[i];
827
33.0k
    uint16_t s1 = s->c[i + 1];
828
33.0k
    declassify_assert((s0 | s1) < (1 << 4));
829
33.0k
    out[0] = (uint8_t)(s0 | (s1 << 4));
830
33.0k
    out += 1;
831
33.0k
  }
832
258
}
833
834
// Encodes a scalar of 256 11-bit words into 352 bytes as follows:
835
// 00000Aaaaaaaaaaa 00000Bbbbbbbbbbb 00000Ccccccccccc 00000Ddddddddddd ...
836
// -> aaaaaaaa bbbbbAaa ccBbbbbb cccccccc dddddddC eeeeDddd fEeeeeee ...
837
template <>
838
0
void scalar_encode<11>(uint8_t out[352], const scalar *s) {
839
0
  for (int i = 0; i < DEGREE; i += 8) {
840
0
    uint16_t s0 = s->c[i];
841
0
    uint16_t s1 = s->c[i + 1];
842
0
    uint16_t s2 = s->c[i + 2];
843
0
    uint16_t s3 = s->c[i + 3];
844
0
    uint16_t s4 = s->c[i + 4];
845
0
    uint16_t s5 = s->c[i + 5];
846
0
    uint16_t s6 = s->c[i + 6];
847
0
    uint16_t s7 = s->c[i + 7];
848
0
    declassify_assert((s0 | s1 | s2 | s3 | s4 | s5 | s6 | s7) < (1 << 11));
849
0
    out[0] = (uint8_t)s0;
850
0
    out[1] = (uint8_t)((s0 >> 8) | (s1 << 3));
851
0
    out[2] = (uint8_t)((s1 >> 5) | (s2 << 6));
852
0
    out[3] = (uint8_t)(s2 >> 2);
853
0
    out[4] = (uint8_t)((s2 >> 10) | (s3 << 1));
854
0
    out[5] = (uint8_t)((s3 >> 7) | (s4 << 4));
855
0
    out[6] = (uint8_t)((s4 >> 4) | (s5 << 7));
856
0
    out[7] = (uint8_t)(s5 >> 1);
857
0
    out[8] = (uint8_t)((s5 >> 9) | (s6 << 2));
858
0
    out[9] = (uint8_t)((s6 >> 6) | (s7 << 5));
859
0
    out[10] = (uint8_t)(s7 >> 3);
860
0
    out += 11;
861
0
  }
862
0
}
863
864
// Encodes a scalar of 256 5-bit words into 160 bytes as follows:
865
// 00000000000Aaaaa 00000000000Bbbbb 00000000000Ccccc 00000000000Ddddd ...
866
// -> bbbAaaaa dCccccBb eeeeDddd ggFffffE HhhhhGgg ...
867
template <>
868
0
void scalar_encode<5>(uint8_t out[160], const scalar *s) {
869
0
  for (int i = 0; i < DEGREE; i += 8) {
870
0
    uint16_t s0 = s->c[i];
871
0
    uint16_t s1 = s->c[i + 1];
872
0
    uint16_t s2 = s->c[i + 2];
873
0
    uint16_t s3 = s->c[i + 3];
874
0
    uint16_t s4 = s->c[i + 4];
875
0
    uint16_t s5 = s->c[i + 5];
876
0
    uint16_t s6 = s->c[i + 6];
877
0
    uint16_t s7 = s->c[i + 7];
878
0
    declassify_assert((s0 | s1 | s2 | s3 | s4 | s5 | s6 | s7) < (1 << 5));
879
0
    out[0] = (uint8_t)(s0 | (s1 << 5));
880
0
    out[1] = (uint8_t)((s1 >> 3) | (s2 << 2) | (s3 << 7));
881
0
    out[2] = (uint8_t)((s3 >> 1) | (s4 << 4));
882
0
    out[3] = (uint8_t)((s4 >> 4) | (s5 << 1) | (s6 << 6));
883
0
    out[4] = (uint8_t)((s6 >> 2) | (s7 << 3));
884
0
    out += 5;
885
0
  }
886
0
}
887
888
// Encodes a scalar of 256 1-bit "words" into 32 bytes as follows:
889
// 0000000000000A 000000000000000B 000000000000000C 000000000000000D ...
890
// -> HGFEDCBA PONMLKJI XWVUTSRQ ...
891
// This order is best understood as the natural way of joining into bytes
892
// assuming LSB-first bit order.
893
template <>
894
23
void scalar_encode<1>(uint8_t out[32], const scalar *s) {
895
759
  for (int i = 0; i < DEGREE; i += 8) {
896
736
    uint8_t out_byte = 0;
897
6.62k
    for (int j = 0; j < 8; j++) {
898
5.88k
      declassify_assert(s->c[i + j] <= 1);
899
5.88k
      out_byte |= s->c[i + j] << j;
900
5.88k
    }
901
736
    out[i / 8] = out_byte;
902
736
  }
903
23
}
904
905
// Encodes an entire vector into 32*`RANK`*`bits` bytes. Note that since 256
906
// (DEGREE) is divisible by 8, the individual vector entries will always fill a
907
// whole number of bytes, so we do not need to worry about bit packing here.
908
template <int bits, int RANK>
909
52.2k
void vector_encode(uint8_t *out, const vector<RANK> *a) {
910
209k
  for (int i = 0; i < RANK; i++) {
911
156k
    scalar_encode<bits>(out + i * bits * DEGREE / 8, &a->v[i]);
912
156k
  }
913
52.2k
}
bcm.cc:void mlkem::(anonymous namespace)::vector_encode<12, 3>(unsigned char*, mlkem::(anonymous namespace)::vector<3> const*)
Line
Count
Source
909
51.8k
void vector_encode(uint8_t *out, const vector<RANK> *a) {
910
207k
  for (int i = 0; i < RANK; i++) {
911
155k
    scalar_encode<bits>(out + i * bits * DEGREE / 8, &a->v[i]);
912
155k
  }
913
51.8k
}
bcm.cc:void mlkem::(anonymous namespace)::vector_encode<10, 3>(unsigned char*, mlkem::(anonymous namespace)::vector<3> const*)
Line
Count
Source
909
258
void vector_encode(uint8_t *out, const vector<RANK> *a) {
910
1.03k
  for (int i = 0; i < RANK; i++) {
911
774
    scalar_encode<bits>(out + i * bits * DEGREE / 8, &a->v[i]);
912
774
  }
913
258
}
Unexecuted instantiation: bcm.cc:void mlkem::(anonymous namespace)::vector_encode<11, 4>(unsigned char*, mlkem::(anonymous namespace)::vector<4> const*)
bcm.cc:void mlkem::(anonymous namespace)::vector_encode<12, 4>(unsigned char*, mlkem::(anonymous namespace)::vector<4> const*)
Line
Count
Source
909
117
void vector_encode(uint8_t *out, const vector<RANK> *a) {
910
585
  for (int i = 0; i < RANK; i++) {
911
468
    scalar_encode<bits>(out + i * bits * DEGREE / 8, &a->v[i]);
912
468
  }
913
117
}
914
915
// scalar_decode parses `DEGREE * BITS` bits from `in` into `DEGREE` values in
916
// `out`. This is the inverse of `scalar_encode`. This is only defined for `BITS
917
// < 12`. Otherwise, the decoding is fallible and must use `scalar_decode_12`
918
// instead.
919
template <int BITS>
920
void scalar_decode(scalar *out, const uint8_t *in);
921
922
template <>
923
69
void scalar_decode<10>(scalar *out, const uint8_t in[320]) {
924
4.48k
  for (int i = 0; i < DEGREE; i += 4) {
925
4.41k
    uint16_t s0 = (uint16_t)(in[0] | ((in[1] & 0x03) << 8));
926
4.41k
    uint16_t s1 = (uint16_t)((in[1] >> 2) | ((in[2] & 0x0f) << 6));
927
4.41k
    uint16_t s2 = (uint16_t)((in[2] >> 4) | ((in[3] & 0x3f) << 4));
928
4.41k
    uint16_t s3 = (uint16_t)((in[3] >> 6) | (in[4] << 2));
929
4.41k
    out->c[i] = s0;
930
4.41k
    out->c[i + 1] = s1;
931
4.41k
    out->c[i + 2] = s2;
932
4.41k
    out->c[i + 3] = s3;
933
4.41k
    in += 5;
934
4.41k
  }
935
69
}
936
937
template <>
938
23
void scalar_decode<4>(scalar *out, const uint8_t in[128]) {
939
2.96k
  for (int i = 0; i < DEGREE; i += 2) {
940
2.94k
    uint16_t s0 = (uint16_t)(in[0] & 0x0f);
941
2.94k
    uint16_t s1 = (uint16_t)(in[0] >> 4);
942
    // kPrime is 3329, so 4-bit values are always < kPrime.
943
2.94k
    out->c[i] = s0;
944
2.94k
    out->c[i + 1] = s1;
945
2.94k
    in += 1;
946
2.94k
  }
947
23
}
948
949
template <>
950
0
void scalar_decode<11>(scalar *out, const uint8_t in[352]) {
951
0
  for (int i = 0; i < DEGREE; i += 8) {
952
0
    uint16_t s0 = (uint16_t)(in[0] | ((in[1] & 0x07) << 8));
953
0
    uint16_t s1 = (uint16_t)((in[1] >> 3) | ((in[2] & 0x3f) << 5));
954
0
    uint16_t s2 =
955
0
        (uint16_t)((in[2] >> 6) | (in[3] << 2) | ((in[4] & 0x01) << 10));
956
0
    uint16_t s3 = (uint16_t)((in[4] >> 1) | ((in[5] & 0x0f) << 7));
957
0
    uint16_t s4 = (uint16_t)((in[5] >> 4) | ((in[6] & 0x7f) << 4));
958
0
    uint16_t s5 =
959
0
        (uint16_t)((in[6] >> 7) | (in[7] << 1) | ((in[8] & 0x03) << 9));
960
0
    uint16_t s6 = (uint16_t)((in[8] >> 2) | ((in[9] & 0x1f) << 6));
961
0
    uint16_t s7 = (uint16_t)((in[9] >> 5) | (in[10] << 3));
962
0
    out->c[i] = s0;
963
0
    out->c[i + 1] = s1;
964
0
    out->c[i + 2] = s2;
965
0
    out->c[i + 3] = s3;
966
0
    out->c[i + 4] = s4;
967
0
    out->c[i + 5] = s5;
968
0
    out->c[i + 6] = s6;
969
0
    out->c[i + 7] = s7;
970
0
    in += 11;
971
0
  }
972
0
}
973
974
template <>
975
0
void scalar_decode<5>(scalar *out, const uint8_t in[160]) {
976
0
  for (int i = 0; i < DEGREE; i += 8) {
977
0
    uint16_t s0 = (uint16_t)(in[0] & 0x1f);
978
0
    uint16_t s1 = (uint16_t)((in[0] >> 5) | ((in[1] & 0x03) << 3));
979
0
    uint16_t s2 = (uint16_t)((in[1] >> 2) & 0x1f);
980
0
    uint16_t s3 = (uint16_t)((in[1] >> 7) | ((in[2] & 0x0f) << 1));
981
0
    uint16_t s4 = (uint16_t)((in[2] >> 4) | ((in[3] & 0x01) << 4));
982
0
    uint16_t s5 = (uint16_t)((in[3] >> 1) & 0x1f);
983
0
    uint16_t s6 = (uint16_t)((in[3] >> 6) | ((in[4] & 0x07) << 2));
984
0
    uint16_t s7 = (uint16_t)(in[4] >> 3);
985
    // kPrime is 3329, so 5-bit values are always < kPrime.
986
0
    out->c[i] = s0;
987
0
    out->c[i + 1] = s1;
988
0
    out->c[i + 2] = s2;
989
0
    out->c[i + 3] = s3;
990
0
    out->c[i + 4] = s4;
991
0
    out->c[i + 5] = s5;
992
0
    out->c[i + 6] = s6;
993
0
    out->c[i + 7] = s7;
994
0
    in += 5;
995
0
  }
996
0
}
997
998
template <>
999
258
void scalar_decode<1>(scalar *out, const uint8_t in[32]) {
1000
8.51k
  for (int i = 0; i < DEGREE; i += 8) {
1001
8.25k
    uint8_t in_byte = in[i / 8];
1002
74.3k
    for (int j = 0; j < 8; j++) {
1003
66.0k
      out->c[i + j] = (in_byte >> j) & 1;
1004
66.0k
    }
1005
8.25k
  }
1006
258
}
1007
1008
// The inverse of `scalar_encode<12>`. Returns 1 iff the encoded scalar is
1009
// valid, i.e. all components are < `kPrime`. Otherwise, returns 0 and the value
1010
// of `out` is undefined.
1011
2.38k
int scalar_decode_12(scalar *out, const uint8_t in[384]) {
1012
296k
  for (int i = 0; i < DEGREE; i += 2) {
1013
293k
    uint16_t s0 = (uint16_t)(in[0] | ((in[1] & 0x0f) << 8));
1014
293k
    uint16_t s1 = (uint16_t)((in[1] >> 4) | (in[2] << 4));
1015
    // This is only used with secret input when parsing the test-only
1016
    // semi-expanded format. Leaking information about invalid inputs is OK.
1017
293k
    if (constant_time_declassify_int(s0 >= kPrime) ||
1018
293k
        constant_time_declassify_int(s1 >= kPrime)) {
1019
109
      return 0;
1020
109
    }
1021
293k
    out->c[i] = s0;
1022
293k
    out->c[i + 1] = s1;
1023
293k
    in += 3;
1024
293k
  }
1025
2.27k
  return 1;
1026
2.38k
}
1027
1028
// Decodes 32*`RANK`*`bits` bytes from `in` into `out`. This only supports `bits
1029
// < 12`, necessary for decoding to be infallible.
1030
template <int bits, int RANK>
1031
23
inline void vector_decode(vector<RANK> *out, const uint8_t *in) {
1032
23
  static_assert(bits < 12);
1033
92
  for (int i = 0; i < RANK; i++) {
1034
69
    scalar_decode<bits>(&out->v[i], in + i * bits * DEGREE / 8);
1035
69
  }
1036
23
}
bcm.cc:void mlkem::(anonymous namespace)::vector_decode<10, 3>(mlkem::(anonymous namespace)::vector<3>*, unsigned char const*)
Line
Count
Source
1031
23
inline void vector_decode(vector<RANK> *out, const uint8_t *in) {
1032
23
  static_assert(bits < 12);
1033
92
  for (int i = 0; i < RANK; i++) {
1034
69
    scalar_decode<bits>(&out->v[i], in + i * bits * DEGREE / 8);
1035
69
  }
1036
23
}
Unexecuted instantiation: bcm.cc:void mlkem::(anonymous namespace)::vector_decode<11, 4>(mlkem::(anonymous namespace)::vector<4>*, unsigned char const*)
1037
1038
// Decodes 32*`RANK`*12 bytes from `in` into `out` It returns one on success or
1039
// zero if any parsed value is >= `kPrime`.
1040
template <int RANK>
1041
807
inline int vector_decode_12(vector<RANK> *out, const uint8_t *in) {
1042
3.08k
  for (int i = 0; i < RANK; i++) {
1043
2.38k
    if (!scalar_decode_12(&out->v[i], in + i * 12 * DEGREE / 8)) {
1044
109
      return 0;
1045
109
    }
1046
2.38k
  }
1047
698
  return 1;
1048
807
}
bcm.cc:int mlkem::(anonymous namespace)::vector_decode_12<3>(mlkem::(anonymous namespace)::vector<3>*, unsigned char const*)
Line
Count
Source
1041
682
inline int vector_decode_12(vector<RANK> *out, const uint8_t *in) {
1042
2.59k
  for (int i = 0; i < RANK; i++) {
1043
1.97k
    if (!scalar_decode_12(&out->v[i], in + i * 12 * DEGREE / 8)) {
1044
66
      return 0;
1045
66
    }
1046
1.97k
  }
1047
616
  return 1;
1048
682
}
bcm.cc:int mlkem::(anonymous namespace)::vector_decode_12<4>(mlkem::(anonymous namespace)::vector<4>*, unsigned char const*)
Line
Count
Source
1041
125
inline int vector_decode_12(vector<RANK> *out, const uint8_t *in) {
1042
493
  for (int i = 0; i < RANK; i++) {
1043
411
    if (!scalar_decode_12(&out->v[i], in + i * 12 * DEGREE / 8)) {
1044
43
      return 0;
1045
43
    }
1046
411
  }
1047
82
  return 1;
1048
125
}
1049
1050
// Compresses (lossily) an input `x` mod 3329 into `bits` many bits by grouping
1051
// numbers close to each other together. The formula used is
1052
// round(2^`bits`/kPrime*x) mod 2^`bits`.
1053
// Uses Barrett reduction to achieve constant time. Since we need both the
1054
// remainder (for rounding) and the quotient (as the result), we cannot use
1055
// `reduce` here, but need to do the Barrett reduction directly.
1056
270k
inline uint16_t compress(uint16_t x, int bits) {
1057
270k
  uint32_t shifted = (uint32_t)x << bits;
1058
270k
  uint64_t product = (uint64_t)shifted * kBarrettMultiplier;
1059
270k
  uint32_t quotient = (uint32_t)(product >> kBarrettShift);
1060
270k
  uint32_t remainder = shifted - quotient * kPrime;
1061
1062
  // Adjust the quotient to round correctly:
1063
  //   0 <= remainder <= kHalfPrime round to 0
1064
  //   kHalfPrime < remainder <= kPrime + kHalfPrime round to 1
1065
  //   kPrime + kHalfPrime < remainder < 2 * kPrime round to 2
1066
270k
  declassify_assert(remainder < 2u * kPrime);
1067
270k
  quotient += 1 & constant_time_lt_w(kHalfPrime, remainder);
1068
270k
  quotient += 1 & constant_time_lt_w(kPrime + kHalfPrime, remainder);
1069
270k
  return quotient & ((1 << bits) - 1);
1070
270k
}
1071
1072
// Decompresses `x` by using an equi-distant representative. The formula is
1073
// round(kPrime/2^`bits`*x). Note that 2^`bits` being the divisor allows us to
1074
// implement this logic using only bit operations.
1075
89.6k
inline uint16_t decompress(uint16_t x, int bits) {
1076
89.6k
  uint32_t product = (uint32_t)x * kPrime;
1077
89.6k
  uint32_t power = 1 << bits;
1078
  // This is `product` % power, since `power` is a power of 2.
1079
89.6k
  uint32_t remainder = product & (power - 1);
1080
  // This is `product` / power, since `power` is a power of 2.
1081
89.6k
  uint32_t lower = product >> bits;
1082
  // The rounding logic works since the first half of numbers mod `power` have a
1083
  // 0 as first bit, and the second half has a 1 as first bit, since `power` is
1084
  // a power of 2. As a 12 bit number, `remainder` is always positive, so we
1085
  // will shift in 0s for a right shift.
1086
89.6k
  return lower + (remainder >> (bits - 1));
1087
89.6k
}
1088
1089
1.05k
inline void scalar_compress(scalar *s, int bits) {
1090
271k
  for (int i = 0; i < DEGREE; i++) {
1091
270k
    s->c[i] = compress(s->c[i], bits);
1092
270k
  }
1093
1.05k
}
1094
1095
350
inline void scalar_decompress(scalar *s, int bits) {
1096
89.9k
  for (int i = 0; i < DEGREE; i++) {
1097
89.6k
    s->c[i] = decompress(s->c[i], bits);
1098
89.6k
  }
1099
350
}
1100
1101
template <int RANK>
1102
258
void vector_compress(vector<RANK> *a, int bits) {
1103
1.03k
  for (int i = 0; i < RANK; i++) {
1104
774
    scalar_compress(&a->v[i], bits);
1105
774
  }
1106
258
}
bcm.cc:void mlkem::(anonymous namespace)::vector_compress<3>(mlkem::(anonymous namespace)::vector<3>*, int)
Line
Count
Source
1102
258
void vector_compress(vector<RANK> *a, int bits) {
1103
1.03k
  for (int i = 0; i < RANK; i++) {
1104
774
    scalar_compress(&a->v[i], bits);
1105
774
  }
1106
258
}
Unexecuted instantiation: bcm.cc:void mlkem::(anonymous namespace)::vector_compress<4>(mlkem::(anonymous namespace)::vector<4>*, int)
1107
1108
template <int RANK>
1109
23
void vector_decompress(vector<RANK> *a, int bits) {
1110
92
  for (int i = 0; i < RANK; i++) {
1111
69
    scalar_decompress(&a->v[i], bits);
1112
69
  }
1113
23
}
bcm.cc:void mlkem::(anonymous namespace)::vector_decompress<3>(mlkem::(anonymous namespace)::vector<3>*, int)
Line
Count
Source
1109
23
void vector_decompress(vector<RANK> *a, int bits) {
1110
92
  for (int i = 0; i < RANK; i++) {
1111
69
    scalar_decompress(&a->v[i], bits);
1112
69
  }
1113
23
}
Unexecuted instantiation: bcm.cc:void mlkem::(anonymous namespace)::vector_decompress<4>(mlkem::(anonymous namespace)::vector<4>*, int)
1114
1115
template <int RANK>
1116
struct public_key {
1117
  vector<RANK> t;
1118
  uint8_t rho[32];
1119
  uint8_t public_key_hash[32];
1120
  matrix<RANK> m;
1121
};
1122
1123
template <int RANK>
1124
struct private_key {
1125
  public_key<RANK> pub;
1126
  vector<RANK> s;
1127
  uint8_t fo_failure_secret[32];
1128
};
1129
1130
template <int RANK>
1131
inline void decrypt_cpa(uint8_t out[32], const private_key<RANK> *priv,
1132
23
                        const uint8_t ciphertext[MLKEM768_CIPHERTEXT_BYTES]) {
1133
23
  constexpr int du = RANK == RANK768 ? kDU768 : kDU1024;
1134
23
  constexpr int dv = RANK == RANK768 ? kDV768 : kDV1024;
1135
1136
23
  vector<RANK> u;
1137
23
  vector_decode<du>(&u, ciphertext);
1138
23
  vector_decompress(&u, du);
1139
23
  vector_ntt(&u);
1140
23
  vector_mulcache<RANK> u_cache;
1141
23
  vector_mulcache_compute(&u_cache, &u);
1142
23
  scalar v;
1143
23
  scalar_decode<dv>(&v, ciphertext + compressed_vector_size(RANK));
1144
23
  scalar_decompress(&v, dv);
1145
23
  scalar mask;
1146
23
  scalar_inner_product(&mask, &priv->s, &u, &u_cache);
1147
23
  scalar_inverse_ntt(&mask);
1148
23
  scalar_sub(&v, &mask);
1149
23
  scalar_compress(&v, 1);
1150
23
  scalar_encode<1>(out, &v);
1151
23
}
bcm.cc:void mlkem::(anonymous namespace)::decrypt_cpa<3>(unsigned char*, mlkem::(anonymous namespace)::private_key<3> const*, unsigned char const*)
Line
Count
Source
1132
23
                        const uint8_t ciphertext[MLKEM768_CIPHERTEXT_BYTES]) {
1133
23
  constexpr int du = RANK == RANK768 ? kDU768 : kDU1024;
1134
23
  constexpr int dv = RANK == RANK768 ? kDV768 : kDV1024;
1135
1136
23
  vector<RANK> u;
1137
23
  vector_decode<du>(&u, ciphertext);
1138
23
  vector_decompress(&u, du);
1139
23
  vector_ntt(&u);
1140
23
  vector_mulcache<RANK> u_cache;
1141
23
  vector_mulcache_compute(&u_cache, &u);
1142
23
  scalar v;
1143
23
  scalar_decode<dv>(&v, ciphertext + compressed_vector_size(RANK));
1144
23
  scalar_decompress(&v, dv);
1145
23
  scalar mask;
1146
23
  scalar_inner_product(&mask, &priv->s, &u, &u_cache);
1147
23
  scalar_inverse_ntt(&mask);
1148
23
  scalar_sub(&v, &mask);
1149
23
  scalar_compress(&v, 1);
1150
23
  scalar_encode<1>(out, &v);
1151
23
}
Unexecuted instantiation: bcm.cc:void mlkem::(anonymous namespace)::decrypt_cpa<4>(unsigned char*, mlkem::(anonymous namespace)::private_key<4> const*, unsigned char const*)
1152
1153
template <int RANK>
1154
inline bcm_status mlkem_marshal_public_key(CBB *out,
1155
51.9k
                                           const public_key<RANK> *pub) {
1156
51.9k
  uint8_t *vector_output;
1157
51.9k
  if (!CBB_add_space(out, &vector_output, encoded_vector_size(RANK))) {
1158
0
    return bcm_status::failure;
1159
0
  }
1160
51.9k
  vector_encode<kLog2Prime>(vector_output, &pub->t);
1161
51.9k
  if (!CBB_add_bytes(out, pub->rho, sizeof(pub->rho))) {
1162
0
    return bcm_status::failure;
1163
0
  }
1164
51.9k
  return bcm_status::approved;
1165
51.9k
}
bcm.cc:bssl::bcm_status_t mlkem::(anonymous namespace)::mlkem_marshal_public_key<3>(cbb_st*, mlkem::(anonymous namespace)::public_key<3> const*)
Line
Count
Source
1155
51.8k
                                           const public_key<RANK> *pub) {
1156
51.8k
  uint8_t *vector_output;
1157
51.8k
  if (!CBB_add_space(out, &vector_output, encoded_vector_size(RANK))) {
1158
0
    return bcm_status::failure;
1159
0
  }
1160
51.8k
  vector_encode<kLog2Prime>(vector_output, &pub->t);
1161
51.8k
  if (!CBB_add_bytes(out, pub->rho, sizeof(pub->rho))) {
1162
0
    return bcm_status::failure;
1163
0
  }
1164
51.8k
  return bcm_status::approved;
1165
51.8k
}
bcm.cc:bssl::bcm_status_t mlkem::(anonymous namespace)::mlkem_marshal_public_key<4>(cbb_st*, mlkem::(anonymous namespace)::public_key<4> const*)
Line
Count
Source
1155
117
                                           const public_key<RANK> *pub) {
1156
117
  uint8_t *vector_output;
1157
117
  if (!CBB_add_space(out, &vector_output, encoded_vector_size(RANK))) {
1158
0
    return bcm_status::failure;
1159
0
  }
1160
117
  vector_encode<kLog2Prime>(vector_output, &pub->t);
1161
117
  if (!CBB_add_bytes(out, pub->rho, sizeof(pub->rho))) {
1162
0
    return bcm_status::failure;
1163
0
  }
1164
117
  return bcm_status::approved;
1165
117
}
1166
1167
template <int RANK>
1168
inline bool mlkem_public_keys_equal(const public_key<RANK> *a,
1169
0
                                    const public_key<RANK> *b) {
1170
0
  return OPENSSL_memcmp(a->public_key_hash, b->public_key_hash, 32) == 0;
1171
0
}
Unexecuted instantiation: bcm.cc:bool mlkem::(anonymous namespace)::mlkem_public_keys_equal<3>(mlkem::(anonymous namespace)::public_key<3> const*, mlkem::(anonymous namespace)::public_key<3> const*)
Unexecuted instantiation: bcm.cc:bool mlkem::(anonymous namespace)::mlkem_public_keys_equal<4>(mlkem::(anonymous namespace)::public_key<4> const*, mlkem::(anonymous namespace)::public_key<4> const*)
1172
1173
template <int RANK>
1174
void mlkem_generate_key_external_seed_no_self_test(
1175
    uint8_t *out_encoded_public_key, private_key<RANK> *priv,
1176
51.8k
    const uint8_t seed[MLKEM_SEED_BYTES]) {
1177
51.8k
  uint8_t augmented_seed[33];
1178
51.8k
  OPENSSL_memcpy(augmented_seed, seed, 32);
1179
51.8k
  augmented_seed[32] = RANK;
1180
1181
51.8k
  uint8_t hashed[64];
1182
51.8k
  hash_g(hashed, augmented_seed, sizeof(augmented_seed));
1183
51.8k
  const uint8_t *const rho = hashed;
1184
51.8k
  const uint8_t *const sigma = hashed + 32;
1185
  // rho is public.
1186
51.8k
  CONSTTIME_DECLASSIFY(rho, 32);
1187
51.8k
  OPENSSL_memcpy(priv->pub.rho, hashed, sizeof(priv->pub.rho));
1188
51.8k
  matrix_expand(&priv->pub.m, rho);
1189
51.8k
  uint8_t counter = 0;
1190
51.8k
  vector_generate_secret_eta_2(&priv->s, &counter, sigma);
1191
51.8k
  vector_ntt(&priv->s);
1192
51.8k
  vector<RANK> error;
1193
51.8k
  vector_generate_secret_eta_2(&error, &counter, sigma);
1194
51.8k
  vector_ntt(&error);
1195
51.8k
  vector_mulcache<RANK> s_cache;
1196
51.8k
  vector_mulcache_compute(&s_cache, &priv->s);
1197
51.8k
  matrix_mult_transpose(&priv->pub.t, &priv->pub.m, &priv->s, &s_cache);
1198
51.8k
  vector_add(&priv->pub.t, &error);
1199
  // t is part of the public key and thus is public.
1200
51.8k
  CONSTTIME_DECLASSIFY(&priv->pub.t, sizeof(priv->pub.t));
1201
1202
51.8k
  CBB cbb;
1203
51.8k
  CBB_init_fixed(&cbb, out_encoded_public_key, encoded_public_key_size(RANK));
1204
51.8k
  if (!bcm_success(mlkem_marshal_public_key(&cbb, &priv->pub))) {
1205
0
    abort();
1206
0
  }
1207
1208
51.8k
  hash_h(priv->pub.public_key_hash, out_encoded_public_key,
1209
51.8k
         encoded_public_key_size(RANK));
1210
51.8k
  OPENSSL_memcpy(priv->fo_failure_secret, seed + 32, 32);
1211
51.8k
}
bcm.cc:void mlkem::(anonymous namespace)::mlkem_generate_key_external_seed_no_self_test<3>(unsigned char*, mlkem::(anonymous namespace)::private_key<3>*, unsigned char const*)
Line
Count
Source
1176
51.7k
    const uint8_t seed[MLKEM_SEED_BYTES]) {
1177
51.7k
  uint8_t augmented_seed[33];
1178
51.7k
  OPENSSL_memcpy(augmented_seed, seed, 32);
1179
51.7k
  augmented_seed[32] = RANK;
1180
1181
51.7k
  uint8_t hashed[64];
1182
51.7k
  hash_g(hashed, augmented_seed, sizeof(augmented_seed));
1183
51.7k
  const uint8_t *const rho = hashed;
1184
51.7k
  const uint8_t *const sigma = hashed + 32;
1185
  // rho is public.
1186
51.7k
  CONSTTIME_DECLASSIFY(rho, 32);
1187
51.7k
  OPENSSL_memcpy(priv->pub.rho, hashed, sizeof(priv->pub.rho));
1188
51.7k
  matrix_expand(&priv->pub.m, rho);
1189
51.7k
  uint8_t counter = 0;
1190
51.7k
  vector_generate_secret_eta_2(&priv->s, &counter, sigma);
1191
51.7k
  vector_ntt(&priv->s);
1192
51.7k
  vector<RANK> error;
1193
51.7k
  vector_generate_secret_eta_2(&error, &counter, sigma);
1194
51.7k
  vector_ntt(&error);
1195
51.7k
  vector_mulcache<RANK> s_cache;
1196
51.7k
  vector_mulcache_compute(&s_cache, &priv->s);
1197
51.7k
  matrix_mult_transpose(&priv->pub.t, &priv->pub.m, &priv->s, &s_cache);
1198
51.7k
  vector_add(&priv->pub.t, &error);
1199
  // t is part of the public key and thus is public.
1200
51.7k
  CONSTTIME_DECLASSIFY(&priv->pub.t, sizeof(priv->pub.t));
1201
1202
51.7k
  CBB cbb;
1203
51.7k
  CBB_init_fixed(&cbb, out_encoded_public_key, encoded_public_key_size(RANK));
1204
51.7k
  if (!bcm_success(mlkem_marshal_public_key(&cbb, &priv->pub))) {
1205
0
    abort();
1206
0
  }
1207
1208
51.7k
  hash_h(priv->pub.public_key_hash, out_encoded_public_key,
1209
51.7k
         encoded_public_key_size(RANK));
1210
51.7k
  OPENSSL_memcpy(priv->fo_failure_secret, seed + 32, 32);
1211
51.7k
}
bcm.cc:void mlkem::(anonymous namespace)::mlkem_generate_key_external_seed_no_self_test<4>(unsigned char*, mlkem::(anonymous namespace)::private_key<4>*, unsigned char const*)
Line
Count
Source
1176
94
    const uint8_t seed[MLKEM_SEED_BYTES]) {
1177
94
  uint8_t augmented_seed[33];
1178
94
  OPENSSL_memcpy(augmented_seed, seed, 32);
1179
94
  augmented_seed[32] = RANK;
1180
1181
94
  uint8_t hashed[64];
1182
94
  hash_g(hashed, augmented_seed, sizeof(augmented_seed));
1183
94
  const uint8_t *const rho = hashed;
1184
94
  const uint8_t *const sigma = hashed + 32;
1185
  // rho is public.
1186
94
  CONSTTIME_DECLASSIFY(rho, 32);
1187
94
  OPENSSL_memcpy(priv->pub.rho, hashed, sizeof(priv->pub.rho));
1188
94
  matrix_expand(&priv->pub.m, rho);
1189
94
  uint8_t counter = 0;
1190
94
  vector_generate_secret_eta_2(&priv->s, &counter, sigma);
1191
94
  vector_ntt(&priv->s);
1192
94
  vector<RANK> error;
1193
94
  vector_generate_secret_eta_2(&error, &counter, sigma);
1194
94
  vector_ntt(&error);
1195
94
  vector_mulcache<RANK> s_cache;
1196
94
  vector_mulcache_compute(&s_cache, &priv->s);
1197
94
  matrix_mult_transpose(&priv->pub.t, &priv->pub.m, &priv->s, &s_cache);
1198
94
  vector_add(&priv->pub.t, &error);
1199
  // t is part of the public key and thus is public.
1200
94
  CONSTTIME_DECLASSIFY(&priv->pub.t, sizeof(priv->pub.t));
1201
1202
94
  CBB cbb;
1203
94
  CBB_init_fixed(&cbb, out_encoded_public_key, encoded_public_key_size(RANK));
1204
94
  if (!bcm_success(mlkem_marshal_public_key(&cbb, &priv->pub))) {
1205
0
    abort();
1206
0
  }
1207
1208
94
  hash_h(priv->pub.public_key_hash, out_encoded_public_key,
1209
94
         encoded_public_key_size(RANK));
1210
94
  OPENSSL_memcpy(priv->fo_failure_secret, seed + 32, 32);
1211
94
}
1212
1213
template <int RANK>
1214
void mlkem_generate_key_external_seed(uint8_t *out_encoded_public_key,
1215
                                      private_key<RANK> *priv,
1216
51.8k
                                      const uint8_t seed[MLKEM_SEED_BYTES]) {
1217
51.8k
  fips::ensure_keygen_self_test();
1218
51.8k
  mlkem_generate_key_external_seed_no_self_test(out_encoded_public_key, priv,
1219
51.8k
                                                seed);
1220
51.8k
}
bcm.cc:void mlkem::(anonymous namespace)::mlkem_generate_key_external_seed<3>(unsigned char*, mlkem::(anonymous namespace)::private_key<3>*, unsigned char const*)
Line
Count
Source
1216
51.7k
                                      const uint8_t seed[MLKEM_SEED_BYTES]) {
1217
51.7k
  fips::ensure_keygen_self_test();
1218
51.7k
  mlkem_generate_key_external_seed_no_self_test(out_encoded_public_key, priv,
1219
51.7k
                                                seed);
1220
51.7k
}
bcm.cc:void mlkem::(anonymous namespace)::mlkem_generate_key_external_seed<4>(unsigned char*, mlkem::(anonymous namespace)::private_key<4>*, unsigned char const*)
Line
Count
Source
1216
94
                                      const uint8_t seed[MLKEM_SEED_BYTES]) {
1217
94
  fips::ensure_keygen_self_test();
1218
94
  mlkem_generate_key_external_seed_no_self_test(out_encoded_public_key, priv,
1219
94
                                                seed);
1220
94
}
1221
1222
// Encrypts a message with given randomness to
1223
// the ciphertext in `out`. Without applying the Fujisaki-Okamoto transform this
1224
// would not result in a CCA secure scheme, since lattice schemes are vulnerable
1225
// to decryption failure oracles.
1226
template <int RANK>
1227
void encrypt_cpa(uint8_t *out, const mlkem::public_key<RANK> *pub,
1228
258
                 const uint8_t message[32], const uint8_t randomness[32]) {
1229
258
  constexpr int du = RANK == RANK768 ? mlkem::kDU768 : mlkem::kDU1024;
1230
258
  constexpr int dv = RANK == RANK768 ? mlkem::kDV768 : mlkem::kDV1024;
1231
1232
258
  uint8_t counter = 0;
1233
258
  mlkem::vector<RANK> secret;
1234
258
  vector_generate_secret_eta_2(&secret, &counter, randomness);
1235
258
  vector_ntt(&secret);
1236
258
  mlkem::vector_mulcache<RANK> secret_cache;
1237
258
  vector_mulcache_compute(&secret_cache, &secret);
1238
258
  mlkem::vector<RANK> error;
1239
258
  vector_generate_secret_eta_2(&error, &counter, randomness);
1240
258
  uint8_t input[33];
1241
258
  OPENSSL_memcpy(input, randomness, 32);
1242
258
  input[32] = counter;
1243
258
  mlkem::scalar scalar_error;
1244
258
  scalar_centered_binomial_distribution_eta_2_with_prf(&scalar_error, input);
1245
258
  mlkem::vector<RANK> u;
1246
258
  matrix_mult(&u, &pub->m, &secret, &secret_cache);
1247
258
  vector_inverse_ntt(&u);
1248
258
  vector_add(&u, &error);
1249
258
  mlkem::scalar v;
1250
258
  scalar_inner_product(&v, &pub->t, &secret, &secret_cache);
1251
258
  scalar_inverse_ntt(&v);
1252
258
  scalar_add(&v, &scalar_error);
1253
258
  mlkem::scalar expanded_message;
1254
258
  scalar_decode<1>(&expanded_message, message);
1255
258
  scalar_decompress(&expanded_message, 1);
1256
258
  scalar_add(&v, &expanded_message);
1257
258
  vector_compress(&u, du);
1258
258
  vector_encode<du>(out, &u);
1259
258
  scalar_compress(&v, dv);
1260
258
  scalar_encode<dv>(out + mlkem::compressed_vector_size(RANK), &v);
1261
258
}
bcm.cc:void mlkem::(anonymous namespace)::encrypt_cpa<3>(unsigned char*, mlkem::(anonymous namespace)::public_key<3> const*, unsigned char const*, unsigned char const*)
Line
Count
Source
1228
258
                 const uint8_t message[32], const uint8_t randomness[32]) {
1229
258
  constexpr int du = RANK == RANK768 ? mlkem::kDU768 : mlkem::kDU1024;
1230
258
  constexpr int dv = RANK == RANK768 ? mlkem::kDV768 : mlkem::kDV1024;
1231
1232
258
  uint8_t counter = 0;
1233
258
  mlkem::vector<RANK> secret;
1234
258
  vector_generate_secret_eta_2(&secret, &counter, randomness);
1235
258
  vector_ntt(&secret);
1236
258
  mlkem::vector_mulcache<RANK> secret_cache;
1237
258
  vector_mulcache_compute(&secret_cache, &secret);
1238
258
  mlkem::vector<RANK> error;
1239
258
  vector_generate_secret_eta_2(&error, &counter, randomness);
1240
258
  uint8_t input[33];
1241
258
  OPENSSL_memcpy(input, randomness, 32);
1242
258
  input[32] = counter;
1243
258
  mlkem::scalar scalar_error;
1244
258
  scalar_centered_binomial_distribution_eta_2_with_prf(&scalar_error, input);
1245
258
  mlkem::vector<RANK> u;
1246
258
  matrix_mult(&u, &pub->m, &secret, &secret_cache);
1247
258
  vector_inverse_ntt(&u);
1248
258
  vector_add(&u, &error);
1249
258
  mlkem::scalar v;
1250
258
  scalar_inner_product(&v, &pub->t, &secret, &secret_cache);
1251
258
  scalar_inverse_ntt(&v);
1252
258
  scalar_add(&v, &scalar_error);
1253
258
  mlkem::scalar expanded_message;
1254
258
  scalar_decode<1>(&expanded_message, message);
1255
258
  scalar_decompress(&expanded_message, 1);
1256
258
  scalar_add(&v, &expanded_message);
1257
258
  vector_compress(&u, du);
1258
258
  vector_encode<du>(out, &u);
1259
258
  scalar_compress(&v, dv);
1260
258
  scalar_encode<dv>(out + mlkem::compressed_vector_size(RANK), &v);
1261
258
}
Unexecuted instantiation: bcm.cc:void mlkem::(anonymous namespace)::encrypt_cpa<4>(unsigned char*, mlkem::(anonymous namespace)::public_key<4> const*, unsigned char const*, unsigned char const*)
1262
1263
// See section 6.3
1264
template <int RANK>
1265
void mlkem_decap_no_self_test(
1266
    uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES],
1267
23
    const uint8_t *ciphertext, const private_key<RANK> *priv) {
1268
23
  uint8_t decrypted[64];
1269
23
  decrypt_cpa(decrypted, priv, ciphertext);
1270
23
  OPENSSL_memcpy(decrypted + 32, priv->pub.public_key_hash,
1271
23
                 sizeof(decrypted) - 32);
1272
23
  uint8_t key_and_randomness[64];
1273
23
  hash_g(key_and_randomness, decrypted, sizeof(decrypted));
1274
23
  constexpr size_t ciphertext_len = ciphertext_size(RANK);
1275
23
  uint8_t expected_ciphertext[MLKEM1024_CIPHERTEXT_BYTES];
1276
23
  static_assert(ciphertext_len <= sizeof(expected_ciphertext));
1277
23
  encrypt_cpa(expected_ciphertext, &priv->pub, decrypted,
1278
23
              key_and_randomness + 32);
1279
1280
23
  uint8_t failure_key[32];
1281
23
  kdf(failure_key, priv->fo_failure_secret, ciphertext, ciphertext_len);
1282
1283
23
  uint8_t mask = constant_time_eq_int_8(
1284
23
      CRYPTO_memcmp(ciphertext, expected_ciphertext, ciphertext_len), 0);
1285
759
  for (int i = 0; i < MLKEM_SHARED_SECRET_BYTES; i++) {
1286
736
    out_shared_secret[i] =
1287
736
        constant_time_select_8(mask, key_and_randomness[i], failure_key[i]);
1288
736
  }
1289
23
}
bcm.cc:void mlkem::(anonymous namespace)::mlkem_decap_no_self_test<3>(unsigned char*, unsigned char const*, mlkem::(anonymous namespace)::private_key<3> const*)
Line
Count
Source
1267
23
    const uint8_t *ciphertext, const private_key<RANK> *priv) {
1268
23
  uint8_t decrypted[64];
1269
23
  decrypt_cpa(decrypted, priv, ciphertext);
1270
23
  OPENSSL_memcpy(decrypted + 32, priv->pub.public_key_hash,
1271
23
                 sizeof(decrypted) - 32);
1272
23
  uint8_t key_and_randomness[64];
1273
23
  hash_g(key_and_randomness, decrypted, sizeof(decrypted));
1274
23
  constexpr size_t ciphertext_len = ciphertext_size(RANK);
1275
23
  uint8_t expected_ciphertext[MLKEM1024_CIPHERTEXT_BYTES];
1276
23
  static_assert(ciphertext_len <= sizeof(expected_ciphertext));
1277
23
  encrypt_cpa(expected_ciphertext, &priv->pub, decrypted,
1278
23
              key_and_randomness + 32);
1279
1280
23
  uint8_t failure_key[32];
1281
23
  kdf(failure_key, priv->fo_failure_secret, ciphertext, ciphertext_len);
1282
1283
23
  uint8_t mask = constant_time_eq_int_8(
1284
23
      CRYPTO_memcmp(ciphertext, expected_ciphertext, ciphertext_len), 0);
1285
759
  for (int i = 0; i < MLKEM_SHARED_SECRET_BYTES; i++) {
1286
736
    out_shared_secret[i] =
1287
736
        constant_time_select_8(mask, key_and_randomness[i], failure_key[i]);
1288
736
  }
1289
23
}
Unexecuted instantiation: bcm.cc:void mlkem::(anonymous namespace)::mlkem_decap_no_self_test<4>(unsigned char*, unsigned char const*, mlkem::(anonymous namespace)::private_key<4> const*)
1290
1291
template <int RANK>
1292
void mlkem_decap(uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES],
1293
23
                 const uint8_t *ciphertext, const private_key<RANK> *priv) {
1294
23
  fips::ensure_decap_self_test();
1295
23
  mlkem_decap_no_self_test(out_shared_secret, ciphertext, priv);
1296
23
}
bcm.cc:void mlkem::(anonymous namespace)::mlkem_decap<3>(unsigned char*, unsigned char const*, mlkem::(anonymous namespace)::private_key<3> const*)
Line
Count
Source
1293
23
                 const uint8_t *ciphertext, const private_key<RANK> *priv) {
1294
23
  fips::ensure_decap_self_test();
1295
23
  mlkem_decap_no_self_test(out_shared_secret, ciphertext, priv);
1296
23
}
Unexecuted instantiation: bcm.cc:void mlkem::(anonymous namespace)::mlkem_decap<4>(unsigned char*, unsigned char const*, mlkem::(anonymous namespace)::private_key<4> const*)
1297
1298
// mlkem_parse_public_key_with_trailing_data parses `in` into `pub` but leaves
1299
// trailing data in `in` for the caller.
1300
template <int RANK>
1301
818
int mlkem_parse_public_key_with_trailing_data(public_key<RANK> *pub, CBS *in) {
1302
818
  CBS orig_in = *in;
1303
818
  CBS t_bytes;
1304
818
  if (!CBS_get_bytes(in, &t_bytes, encoded_vector_size(RANK)) ||
1305
807
      !vector_decode_12(&pub->t, CBS_data(&t_bytes)) ||
1306
698
      !CBS_copy_bytes(in, pub->rho, sizeof(pub->rho))) {
1307
124
    return 0;
1308
124
  }
1309
694
  matrix_expand(&pub->m, pub->rho);
1310
694
  size_t pub_key_len = CBS_len(&orig_in) - CBS_len(in);
1311
694
  assert(pub_key_len == encoded_public_key_size(RANK));
1312
694
  hash_h(pub->public_key_hash, CBS_data(&orig_in), pub_key_len);
1313
694
  return 1;
1314
694
}
bcm.cc:int mlkem::(anonymous namespace)::mlkem_parse_public_key_with_trailing_data<3>(mlkem::(anonymous namespace)::public_key<3>*, cbs_st*)
Line
Count
Source
1301
686
int mlkem_parse_public_key_with_trailing_data(public_key<RANK> *pub, CBS *in) {
1302
686
  CBS orig_in = *in;
1303
686
  CBS t_bytes;
1304
686
  if (!CBS_get_bytes(in, &t_bytes, encoded_vector_size(RANK)) ||
1305
682
      !vector_decode_12(&pub->t, CBS_data(&t_bytes)) ||
1306
616
      !CBS_copy_bytes(in, pub->rho, sizeof(pub->rho))) {
1307
72
    return 0;
1308
72
  }
1309
614
  matrix_expand(&pub->m, pub->rho);
1310
614
  size_t pub_key_len = CBS_len(&orig_in) - CBS_len(in);
1311
614
  assert(pub_key_len == encoded_public_key_size(RANK));
1312
614
  hash_h(pub->public_key_hash, CBS_data(&orig_in), pub_key_len);
1313
614
  return 1;
1314
614
}
bcm.cc:int mlkem::(anonymous namespace)::mlkem_parse_public_key_with_trailing_data<4>(mlkem::(anonymous namespace)::public_key<4>*, cbs_st*)
Line
Count
Source
1301
132
int mlkem_parse_public_key_with_trailing_data(public_key<RANK> *pub, CBS *in) {
1302
132
  CBS orig_in = *in;
1303
132
  CBS t_bytes;
1304
132
  if (!CBS_get_bytes(in, &t_bytes, encoded_vector_size(RANK)) ||
1305
125
      !vector_decode_12(&pub->t, CBS_data(&t_bytes)) ||
1306
82
      !CBS_copy_bytes(in, pub->rho, sizeof(pub->rho))) {
1307
52
    return 0;
1308
52
  }
1309
80
  matrix_expand(&pub->m, pub->rho);
1310
80
  size_t pub_key_len = CBS_len(&orig_in) - CBS_len(in);
1311
80
  assert(pub_key_len == encoded_public_key_size(RANK));
1312
80
  hash_h(pub->public_key_hash, CBS_data(&orig_in), pub_key_len);
1313
80
  return 1;
1314
80
}
1315
1316
template <int RANK>
1317
818
int mlkem_parse_public_key(public_key<RANK> *pub, CBS *in) {
1318
818
  if (!mlkem_parse_public_key_with_trailing_data(pub, in) ||  //
1319
694
      CBS_len(in) != 0) {
1320
270
    return 0;
1321
270
  }
1322
548
  return 1;
1323
818
}
bcm.cc:int mlkem::(anonymous namespace)::mlkem_parse_public_key<3>(mlkem::(anonymous namespace)::public_key<3>*, cbs_st*)
Line
Count
Source
1317
686
int mlkem_parse_public_key(public_key<RANK> *pub, CBS *in) {
1318
686
  if (!mlkem_parse_public_key_with_trailing_data(pub, in) ||  //
1319
614
      CBS_len(in) != 0) {
1320
179
    return 0;
1321
179
  }
1322
507
  return 1;
1323
686
}
bcm.cc:int mlkem::(anonymous namespace)::mlkem_parse_public_key<4>(mlkem::(anonymous namespace)::public_key<4>*, cbs_st*)
Line
Count
Source
1317
132
int mlkem_parse_public_key(public_key<RANK> *pub, CBS *in) {
1318
132
  if (!mlkem_parse_public_key_with_trailing_data(pub, in) ||  //
1319
91
      CBS_len(in) != 0) {
1320
91
    return 0;
1321
91
  }
1322
41
  return 1;
1323
132
}
1324
1325
template <int RANK>
1326
0
int mlkem_parse_private_key(private_key<RANK> *priv, CBS *in) {
1327
0
  CBS s_bytes, public_key_hash;
1328
0
  if (!CBS_get_bytes(in, &s_bytes, encoded_vector_size(RANK)) ||
1329
0
      !vector_decode_12(&priv->s, CBS_data(&s_bytes)) ||
1330
0
      !mlkem_parse_public_key_with_trailing_data(&priv->pub, in) ||
1331
      // We compute the public key hash ourselves, but check it matched.
1332
0
      !CBS_get_bytes(in, &public_key_hash, sizeof(priv->pub.public_key_hash)) ||
1333
0
      !CBS_mem_equal(&public_key_hash, priv->pub.public_key_hash,
1334
0
                     sizeof(priv->pub.public_key_hash)) ||
1335
0
      !CBS_copy_bytes(in, priv->fo_failure_secret,
1336
0
                      sizeof(priv->fo_failure_secret)) ||
1337
0
      CBS_len(in) != 0) {
1338
0
    return 0;
1339
0
  }
1340
0
  return 1;
1341
0
}
Unexecuted instantiation: bcm.cc:int mlkem::(anonymous namespace)::mlkem_parse_private_key<3>(mlkem::(anonymous namespace)::private_key<3>*, cbs_st*)
Unexecuted instantiation: bcm.cc:int mlkem::(anonymous namespace)::mlkem_parse_private_key<4>(mlkem::(anonymous namespace)::private_key<4>*, cbs_st*)
1342
1343
template <int RANK>
1344
0
int mlkem_marshal_private_key(CBB *out, const private_key<RANK> *priv) {
1345
0
  uint8_t *s_output;
1346
0
  if (!CBB_add_space(out, &s_output, encoded_vector_size(RANK))) {
1347
0
    return 0;
1348
0
  }
1349
0
  vector_encode<kLog2Prime>(s_output, &priv->s);
1350
0
  if (!bcm_success(mlkem_marshal_public_key(out, &priv->pub)) ||
1351
0
      !CBB_add_bytes(out, priv->pub.public_key_hash,
1352
0
                     sizeof(priv->pub.public_key_hash)) ||
1353
0
      !CBB_add_bytes(out, priv->fo_failure_secret,
1354
0
                     sizeof(priv->fo_failure_secret))) {
1355
0
    return 0;
1356
0
  }
1357
0
  return 1;
1358
0
}
Unexecuted instantiation: bcm.cc:int mlkem::(anonymous namespace)::mlkem_marshal_private_key<3>(cbb_st*, mlkem::(anonymous namespace)::private_key<3> const*)
Unexecuted instantiation: bcm.cc:int mlkem::(anonymous namespace)::mlkem_marshal_private_key<4>(cbb_st*, mlkem::(anonymous namespace)::private_key<4> const*)
1359
1360
static_assert(sizeof(MLKEM768_public_key) == sizeof(public_key<RANK768>));
1361
static_assert(alignof(MLKEM768_public_key) == alignof(public_key<RANK768>));
1362
1363
const public_key<RANK768> *public_key_768_from_external(
1364
342
    const MLKEM768_public_key *external) {
1365
342
  return reinterpret_cast<const public_key<RANK768> *>(external);
1366
342
}
1367
public_key<RANK768> *public_key_768_from_external(
1368
686
    MLKEM768_public_key *external) {
1369
686
  return reinterpret_cast<public_key<RANK768> *>(external);
1370
686
}
1371
const MLKEM768_public_key *public_key_768_to_external(
1372
0
    const public_key<RANK768> *public_key) {
1373
0
  return reinterpret_cast<const MLKEM768_public_key *>(public_key);
1374
0
}
1375
1376
static_assert(sizeof(MLKEM1024_public_key) == sizeof(public_key<RANK1024>));
1377
static_assert(alignof(MLKEM1024_public_key) == alignof(public_key<RANK1024>));
1378
1379
const public_key<RANK1024> *public_key_1024_from_external(
1380
23
    const MLKEM1024_public_key *external) {
1381
23
  return reinterpret_cast<const public_key<RANK1024> *>(external);
1382
23
}
1383
public_key<RANK1024> *public_key_1024_from_external(
1384
132
    MLKEM1024_public_key *external) {
1385
132
  return reinterpret_cast<public_key<RANK1024> *>(external);
1386
132
}
1387
1388
const MLKEM1024_public_key *public_key_1024_to_external(
1389
0
    const public_key<RANK1024> *public_key) {
1390
0
  return reinterpret_cast<const MLKEM1024_public_key *>(public_key);
1391
0
}
1392
1393
static_assert(sizeof(MLKEM768_private_key) >= sizeof(private_key<RANK768>));
1394
static_assert(alignof(MLKEM768_private_key) >= alignof(private_key<RANK768>));
1395
1396
const private_key<RANK768> *private_key_768_from_external(
1397
23
    const MLKEM768_private_key *external) {
1398
23
  return reinterpret_cast<const private_key<RANK768> *>(external);
1399
23
}
1400
private_key<RANK768> *private_key_768_from_external(
1401
51.7k
    MLKEM768_private_key *external) {
1402
51.7k
  return reinterpret_cast<private_key<RANK768> *>(external);
1403
51.7k
}
1404
1405
static_assert(sizeof(MLKEM1024_private_key) >= sizeof(private_key<RANK1024>));
1406
static_assert(alignof(MLKEM1024_private_key) >= alignof(private_key<RANK1024>));
1407
1408
const private_key<RANK1024> *private_key_1024_from_external(
1409
0
    const MLKEM1024_private_key *external) {
1410
0
  return reinterpret_cast<const private_key<RANK1024> *>(external);
1411
0
}
1412
private_key<RANK1024> *private_key_1024_from_external(
1413
94
    MLKEM1024_private_key *external) {
1414
94
  return reinterpret_cast<private_key<RANK1024> *>(external);
1415
94
}
1416
1417
// See section 6.2.
1418
template <int RANK>
1419
void mlkem_encap_external_entropy_no_self_test(
1420
    uint8_t *out_ciphertext,
1421
    uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES],
1422
    const mlkem::public_key<RANK> *pub,
1423
235
    const uint8_t entropy[BCM_MLKEM_ENCAP_ENTROPY]) {
1424
235
  uint8_t input[64];
1425
235
  OPENSSL_memcpy(input, entropy, BCM_MLKEM_ENCAP_ENTROPY);
1426
235
  OPENSSL_memcpy(input + BCM_MLKEM_ENCAP_ENTROPY, pub->public_key_hash,
1427
235
                 sizeof(input) - BCM_MLKEM_ENCAP_ENTROPY);
1428
235
  uint8_t key_and_randomness[64];
1429
235
  mlkem::hash_g(key_and_randomness, input, sizeof(input));
1430
235
  encrypt_cpa(out_ciphertext, pub, entropy, key_and_randomness + 32);
1431
  // The ciphertext is public.
1432
235
  CONSTTIME_DECLASSIFY(out_ciphertext, mlkem::ciphertext_size(RANK));
1433
235
  static_assert(MLKEM_SHARED_SECRET_BYTES == 32);
1434
235
  memcpy(out_shared_secret, key_and_randomness, 32);
1435
235
}
bcm.cc:void mlkem::(anonymous namespace)::mlkem_encap_external_entropy_no_self_test<3>(unsigned char*, unsigned char*, mlkem::(anonymous namespace)::public_key<3> const*, unsigned char const*)
Line
Count
Source
1423
235
    const uint8_t entropy[BCM_MLKEM_ENCAP_ENTROPY]) {
1424
235
  uint8_t input[64];
1425
235
  OPENSSL_memcpy(input, entropy, BCM_MLKEM_ENCAP_ENTROPY);
1426
235
  OPENSSL_memcpy(input + BCM_MLKEM_ENCAP_ENTROPY, pub->public_key_hash,
1427
235
                 sizeof(input) - BCM_MLKEM_ENCAP_ENTROPY);
1428
235
  uint8_t key_and_randomness[64];
1429
235
  mlkem::hash_g(key_and_randomness, input, sizeof(input));
1430
235
  encrypt_cpa(out_ciphertext, pub, entropy, key_and_randomness + 32);
1431
  // The ciphertext is public.
1432
235
  CONSTTIME_DECLASSIFY(out_ciphertext, mlkem::ciphertext_size(RANK));
1433
235
  static_assert(MLKEM_SHARED_SECRET_BYTES == 32);
1434
235
  memcpy(out_shared_secret, key_and_randomness, 32);
1435
235
}
Unexecuted instantiation: bcm.cc:void mlkem::(anonymous namespace)::mlkem_encap_external_entropy_no_self_test<4>(unsigned char*, unsigned char*, mlkem::(anonymous namespace)::public_key<4> const*, unsigned char const*)
1436
1437
template <int RANK>
1438
void mlkem_encap_external_entropy(
1439
    uint8_t *out_ciphertext,
1440
    uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES],
1441
    const mlkem::public_key<RANK> *pub,
1442
235
    const uint8_t entropy[BCM_MLKEM_ENCAP_ENTROPY]) {
1443
235
  fips::ensure_encap_self_test();
1444
235
  mlkem_encap_external_entropy_no_self_test(out_ciphertext, out_shared_secret,
1445
235
                                            pub, entropy);
1446
235
}
bcm.cc:void mlkem::(anonymous namespace)::mlkem_encap_external_entropy<3>(unsigned char*, unsigned char*, mlkem::(anonymous namespace)::public_key<3> const*, unsigned char const*)
Line
Count
Source
1442
235
    const uint8_t entropy[BCM_MLKEM_ENCAP_ENTROPY]) {
1443
235
  fips::ensure_encap_self_test();
1444
235
  mlkem_encap_external_entropy_no_self_test(out_ciphertext, out_shared_secret,
1445
235
                                            pub, entropy);
1446
235
}
Unexecuted instantiation: bcm.cc:void mlkem::(anonymous namespace)::mlkem_encap_external_entropy<4>(unsigned char*, unsigned char*, mlkem::(anonymous namespace)::public_key<4> const*, unsigned char const*)
1447
1448
namespace fips {
1449
1450
#include "fips_known_values.inc"
1451
1452
0
inline int keygen_self_test() {
1453
0
  uint8_t pub_key[MLKEM768_PUBLIC_KEY_BYTES];
1454
0
  private_key<RANK768> priv;
1455
0
  static_assert(sizeof(kTestEntropy) >= MLKEM_SEED_BYTES);
1456
0
  mlkem_generate_key_external_seed_no_self_test(pub_key, &priv, kTestEntropy);
1457
0
  CBB cbb;
1458
0
  constexpr size_t kMarshaledPrivateKeySize = 2400;
1459
0
  uint8_t priv_bytes[kMarshaledPrivateKeySize];
1460
0
  CBB_init_fixed(&cbb, priv_bytes, sizeof(priv_bytes));
1461
0
  if (!mlkem_marshal_private_key(&cbb, &priv) ||
1462
0
      !BORINGSSL_check_test(kExpectedPrivateKeyBytes, priv_bytes,
1463
0
                            "ML-KEM keygen private key") ||
1464
0
      !BORINGSSL_check_test(kExpectedPublicKeyBytes, pub_key,
1465
0
                            "ML-KEM keygen public key")) {
1466
0
    return 0;
1467
0
  }
1468
0
  return 1;
1469
0
}
1470
1471
0
inline int encap_self_test() {
1472
0
  CBS cbs;
1473
0
  CBS_init(&cbs, kExpectedPublicKeyBytes, sizeof(kExpectedPublicKeyBytes));
1474
0
  public_key<RANK768> pub;
1475
0
  if (!mlkem_parse_public_key(&pub, &cbs)) {
1476
0
    return 0;
1477
0
  }
1478
0
  uint8_t ciphertext[MLKEM768_CIPHERTEXT_BYTES];
1479
0
  uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES];
1480
0
  static_assert(sizeof(kTestEntropy) >= BCM_MLKEM_ENCAP_ENTROPY);
1481
0
  mlkem_encap_external_entropy_no_self_test(ciphertext, shared_secret, &pub,
1482
0
                                            kTestEntropy);
1483
0
  if (!BORINGSSL_check_test(ciphertext, kExpectedCiphertext,
1484
0
                            "ML-KEM encap ciphertext") ||
1485
0
      !BORINGSSL_check_test(kExpectedSharedSecret, shared_secret,
1486
0
                            "ML-KEM encap shared secret")) {
1487
0
    return 0;
1488
0
  }
1489
0
  return 1;
1490
0
}
1491
1492
0
inline int decap_self_test() {
1493
0
  CBS cbs;
1494
0
  CBS_init(&cbs, kExpectedPrivateKeyBytes, sizeof(kExpectedPrivateKeyBytes));
1495
0
  private_key<RANK768> priv;
1496
0
  if (!mlkem_parse_private_key(&priv, &cbs)) {
1497
0
    return 0;
1498
0
  }
1499
0
  uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES];
1500
0
  mlkem_decap_no_self_test(shared_secret, kExpectedCiphertext, &priv);
1501
0
  if (!BORINGSSL_check_test(kExpectedSharedSecret, shared_secret,
1502
0
                            "ML-KEM decap shared secret")) {
1503
0
    return 0;
1504
0
  }
1505
1506
0
  uint8_t implicit_rejection_shared_secret[MLKEM_SHARED_SECRET_BYTES];
1507
0
  static_assert(sizeof(kExpectedPrivateKeyBytes) >=
1508
0
                sizeof(kExpectedCiphertext));
1509
0
  mlkem_decap_no_self_test(implicit_rejection_shared_secret,
1510
0
                           kExpectedPrivateKeyBytes, &priv);
1511
0
  if (!BORINGSSL_check_test(kExpectedImplicitRejectionSharedSecret,
1512
0
                            implicit_rejection_shared_secret,
1513
0
                            "ML-KEM decap implicit rejection shared secret")) {
1514
0
    return 0;
1515
0
  }
1516
0
  return 1;
1517
0
}
1518
1519
#if defined(BORINGSSL_FIPS)
1520
1521
void ensure_keygen_self_test() {
1522
  CRYPTO_once(g_mlkem_keygen_self_test_once_bss_get(), []() {
1523
    if (!keygen_self_test()) {
1524
      BORINGSSL_FIPS_abort();
1525
    }
1526
  });
1527
}
1528
1529
void ensure_encap_self_test() {
1530
  CRYPTO_once(g_mlkem_encap_self_test_once_bss_get(), []() {
1531
    if (!encap_self_test()) {
1532
      BORINGSSL_FIPS_abort();
1533
    }
1534
  });
1535
}
1536
1537
void ensure_decap_self_test() {
1538
  CRYPTO_once(g_mlkem_decap_self_test_once_bss_get(), []() {
1539
    if (!decap_self_test()) {
1540
      BORINGSSL_FIPS_abort();
1541
    }
1542
  });
1543
}
1544
1545
#else
1546
1547
51.8k
void ensure_keygen_self_test() {}
1548
235
void ensure_encap_self_test() {}
1549
23
void ensure_decap_self_test() {}
1550
1551
#endif
1552
}  // namespace fips
1553
1554
}  // namespace
1555
}  // namespace mlkem
1556
1557
bcm_status bssl::BCM_mlkem768_check_fips(
1558
0
    const MLKEM768_private_key *private_key) {
1559
0
  const mlkem::private_key<RANK768> *priv =
1560
0
      mlkem::private_key_768_from_external(private_key);
1561
1562
0
  const uint8_t entropy[BCM_MLKEM_ENCAP_ENTROPY] = {1, 2, 3, 4};
1563
0
  uint8_t ciphertext[MLKEM768_CIPHERTEXT_BYTES];
1564
0
  uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES];
1565
0
  mlkem_encap_external_entropy_no_self_test(ciphertext, shared_secret,
1566
0
                                            &priv->pub, entropy);
1567
1568
0
  if (boringssl_fips_break_test("MLKEM_PWCT")) {
1569
0
    shared_secret[0] ^= 1;
1570
0
  }
1571
1572
0
  uint8_t shared_secret2[MLKEM_SHARED_SECRET_BYTES];
1573
0
  mlkem::mlkem_decap_no_self_test(shared_secret2, ciphertext, priv);
1574
0
  if (CRYPTO_memcmp(shared_secret, shared_secret2, sizeof(shared_secret)) !=
1575
0
      0) {
1576
0
    return bcm_status::failure;
1577
0
  }
1578
0
  return bcm_status::approved;
1579
0
}
1580
1581
bcm_status bssl::BCM_mlkem768_generate_key_fips(
1582
    uint8_t out_encoded_public_key[MLKEM768_PUBLIC_KEY_BYTES],
1583
    uint8_t optional_out_seed[MLKEM_SEED_BYTES],
1584
0
    MLKEM768_private_key *out_private_key) {
1585
0
  if (out_encoded_public_key == nullptr || out_private_key == nullptr) {
1586
0
    return bcm_status::failure;
1587
0
  }
1588
0
  BCM_mlkem768_generate_key(out_encoded_public_key, optional_out_seed,
1589
0
                            out_private_key);
1590
0
  return BCM_mlkem768_check_fips(out_private_key);
1591
0
}
1592
1593
bcm_infallible bssl::BCM_mlkem768_generate_key(
1594
    uint8_t out_encoded_public_key[MLKEM768_PUBLIC_KEY_BYTES],
1595
    uint8_t optional_out_seed[MLKEM_SEED_BYTES],
1596
51.6k
    MLKEM768_private_key *out_private_key) {
1597
51.6k
  uint8_t seed[MLKEM_SEED_BYTES];
1598
51.6k
  BCM_rand_bytes(seed, sizeof(seed));
1599
51.6k
  CONSTTIME_SECRET(seed, sizeof(seed));
1600
51.6k
  if (optional_out_seed) {
1601
0
    OPENSSL_memcpy(optional_out_seed, seed, sizeof(seed));
1602
0
  }
1603
51.6k
  BCM_mlkem768_generate_key_external_seed(out_encoded_public_key,
1604
51.6k
                                          out_private_key, seed);
1605
51.6k
  return bcm_infallible::not_approved;
1606
51.6k
}
1607
1608
bcm_status bssl::BCM_mlkem768_private_key_from_seed(
1609
    MLKEM768_private_key *out_private_key, const uint8_t *seed,
1610
61
    size_t seed_len) {
1611
61
  if (seed_len != MLKEM_SEED_BYTES) {
1612
0
    return bcm_status::failure;
1613
0
  }
1614
1615
61
  uint8_t public_key_bytes[MLKEM768_PUBLIC_KEY_BYTES];
1616
61
  BCM_mlkem768_generate_key_external_seed(public_key_bytes, out_private_key,
1617
61
                                          seed);
1618
61
  return bcm_status::not_approved;
1619
61
}
1620
1621
bcm_status bssl::BCM_mlkem1024_check_fips(
1622
0
    const MLKEM1024_private_key *private_key) {
1623
0
  const mlkem::private_key<RANK1024> *priv =
1624
0
      mlkem::private_key_1024_from_external(private_key);
1625
1626
0
  const uint8_t entropy[BCM_MLKEM_ENCAP_ENTROPY] = {1, 2, 3, 4};
1627
0
  uint8_t ciphertext[MLKEM1024_CIPHERTEXT_BYTES];
1628
0
  uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES];
1629
0
  mlkem_encap_external_entropy_no_self_test(ciphertext, shared_secret,
1630
0
                                            &priv->pub, entropy);
1631
1632
0
  if (boringssl_fips_break_test("MLKEM_PWCT")) {
1633
0
    shared_secret[0] ^= 1;
1634
0
  }
1635
1636
0
  uint8_t shared_secret2[MLKEM_SHARED_SECRET_BYTES];
1637
0
  mlkem::mlkem_decap_no_self_test(shared_secret2, ciphertext, priv);
1638
0
  if (CRYPTO_memcmp(shared_secret, shared_secret2, sizeof(shared_secret)) !=
1639
0
      0) {
1640
0
    return bcm_status::failure;
1641
0
  }
1642
0
  return bcm_status::approved;
1643
0
}
1644
1645
bcm_status bssl::BCM_mlkem1024_generate_key_fips(
1646
    uint8_t out_encoded_public_key[MLKEM1024_PUBLIC_KEY_BYTES],
1647
    uint8_t optional_out_seed[MLKEM_SEED_BYTES],
1648
0
    MLKEM1024_private_key *out_private_key) {
1649
0
  if (out_encoded_public_key == nullptr || out_private_key == nullptr) {
1650
0
    return bcm_status::failure;
1651
0
  }
1652
0
  BCM_mlkem1024_generate_key(out_encoded_public_key, optional_out_seed,
1653
0
                             out_private_key);
1654
0
  return BCM_mlkem1024_check_fips(out_private_key);
1655
0
}
1656
1657
bcm_infallible bssl::BCM_mlkem1024_generate_key(
1658
    uint8_t out_encoded_public_key[MLKEM1024_PUBLIC_KEY_BYTES],
1659
    uint8_t optional_out_seed[MLKEM_SEED_BYTES],
1660
24
    MLKEM1024_private_key *out_private_key) {
1661
24
  uint8_t seed[MLKEM_SEED_BYTES];
1662
24
  BCM_rand_bytes(seed, sizeof(seed));
1663
24
  CONSTTIME_SECRET(seed, sizeof(seed));
1664
24
  if (optional_out_seed) {
1665
0
    OPENSSL_memcpy(optional_out_seed, seed, sizeof(seed));
1666
0
  }
1667
24
  BCM_mlkem1024_generate_key_external_seed(out_encoded_public_key,
1668
24
                                           out_private_key, seed);
1669
24
  return bcm_infallible::not_approved;
1670
24
}
1671
1672
bcm_status bssl::BCM_mlkem1024_private_key_from_seed(
1673
    MLKEM1024_private_key *out_private_key, const uint8_t *seed,
1674
70
    size_t seed_len) {
1675
70
  if (seed_len != MLKEM_SEED_BYTES) {
1676
0
    return bcm_status::failure;
1677
0
  }
1678
70
  uint8_t public_key_bytes[MLKEM1024_PUBLIC_KEY_BYTES];
1679
70
  BCM_mlkem1024_generate_key_external_seed(public_key_bytes, out_private_key,
1680
70
                                           seed);
1681
70
  return bcm_status::not_approved;
1682
70
}
1683
1684
bcm_infallible bssl::BCM_mlkem768_generate_key_external_seed(
1685
    uint8_t out_encoded_public_key[MLKEM768_PUBLIC_KEY_BYTES],
1686
    MLKEM768_private_key *out_private_key,
1687
51.7k
    const uint8_t seed[MLKEM_SEED_BYTES]) {
1688
51.7k
  mlkem::private_key<RANK768> *priv =
1689
51.7k
      mlkem::private_key_768_from_external(out_private_key);
1690
51.7k
  mlkem_generate_key_external_seed(out_encoded_public_key, priv, seed);
1691
51.7k
  return bcm_infallible::approved;
1692
51.7k
}
1693
1694
bcm_infallible bssl::BCM_mlkem1024_generate_key_external_seed(
1695
    uint8_t out_encoded_public_key[MLKEM1024_PUBLIC_KEY_BYTES],
1696
    MLKEM1024_private_key *out_private_key,
1697
94
    const uint8_t seed[MLKEM_SEED_BYTES]) {
1698
94
  mlkem::private_key<RANK1024> *priv =
1699
94
      mlkem::private_key_1024_from_external(out_private_key);
1700
94
  mlkem_generate_key_external_seed(out_encoded_public_key, priv, seed);
1701
94
  return bcm_infallible::approved;
1702
94
}
1703
1704
bcm_infallible bssl::BCM_mlkem768_public_from_private(
1705
    MLKEM768_public_key *out_public_key,
1706
0
    const MLKEM768_private_key *private_key) {
1707
0
  mlkem::public_key<RANK768> *const pub =
1708
0
      mlkem::public_key_768_from_external(out_public_key);
1709
0
  const mlkem::private_key<RANK768> *const priv =
1710
0
      mlkem::private_key_768_from_external(private_key);
1711
0
  *pub = priv->pub;
1712
0
  return bcm_infallible::approved;
1713
0
}
1714
1715
bcm_infallible bssl::BCM_mlkem1024_public_from_private(
1716
    MLKEM1024_public_key *out_public_key,
1717
0
    const MLKEM1024_private_key *private_key) {
1718
0
  mlkem::public_key<RANK1024> *const pub =
1719
0
      mlkem::public_key_1024_from_external(out_public_key);
1720
0
  const mlkem::private_key<RANK1024> *const priv =
1721
0
      mlkem::private_key_1024_from_external(private_key);
1722
0
  *pub = priv->pub;
1723
0
  return bcm_infallible::approved;
1724
0
}
1725
1726
const MLKEM768_public_key *bssl::BCM_mlkem768_public_of_private(
1727
0
    const MLKEM768_private_key *private_key) {
1728
0
  const mlkem::private_key<RANK768> *const priv =
1729
0
      mlkem::private_key_768_from_external(private_key);
1730
0
  return mlkem::public_key_768_to_external(&priv->pub);
1731
0
}
1732
1733
const MLKEM1024_public_key *bssl::BCM_mlkem1024_public_of_private(
1734
0
    const MLKEM1024_private_key *private_key) {
1735
0
  const mlkem::private_key<RANK1024> *const priv =
1736
0
      mlkem::private_key_1024_from_external(private_key);
1737
0
  return mlkem::public_key_1024_to_external(&priv->pub);
1738
0
}
1739
1740
// Calls `MLKEM768_encap_external_entropy` with random bytes from
1741
// `BCM_rand_bytes`
1742
bcm_infallible bssl::BCM_mlkem768_encap(
1743
    uint8_t out_ciphertext[MLKEM768_CIPHERTEXT_BYTES],
1744
    uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES],
1745
235
    const MLKEM768_public_key *public_key) {
1746
235
  uint8_t entropy[BCM_MLKEM_ENCAP_ENTROPY];
1747
235
  BCM_rand_bytes(entropy, BCM_MLKEM_ENCAP_ENTROPY);
1748
235
  CONSTTIME_SECRET(entropy, BCM_MLKEM_ENCAP_ENTROPY);
1749
235
  BCM_mlkem768_encap_external_entropy(out_ciphertext, out_shared_secret,
1750
235
                                      public_key, entropy);
1751
235
  return bcm_infallible::approved;
1752
235
}
1753
1754
bcm_infallible bssl::BCM_mlkem1024_encap(
1755
    uint8_t out_ciphertext[MLKEM1024_CIPHERTEXT_BYTES],
1756
    uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES],
1757
0
    const MLKEM1024_public_key *public_key) {
1758
0
  uint8_t entropy[BCM_MLKEM_ENCAP_ENTROPY];
1759
0
  BCM_rand_bytes(entropy, BCM_MLKEM_ENCAP_ENTROPY);
1760
0
  CONSTTIME_SECRET(entropy, BCM_MLKEM_ENCAP_ENTROPY);
1761
0
  BCM_mlkem1024_encap_external_entropy(out_ciphertext, out_shared_secret,
1762
0
                                       public_key, entropy);
1763
0
  return bcm_infallible::approved;
1764
0
}
1765
1766
bcm_infallible bssl::BCM_mlkem768_encap_external_entropy(
1767
    uint8_t out_ciphertext[MLKEM768_CIPHERTEXT_BYTES],
1768
    uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES],
1769
    const MLKEM768_public_key *public_key,
1770
235
    const uint8_t entropy[BCM_MLKEM_ENCAP_ENTROPY]) {
1771
235
  const mlkem::public_key<RANK768> *pub =
1772
235
      mlkem::public_key_768_from_external(public_key);
1773
235
  mlkem_encap_external_entropy(out_ciphertext, out_shared_secret, pub, entropy);
1774
235
  return bcm_infallible::approved;
1775
235
}
1776
1777
bcm_infallible bssl::BCM_mlkem1024_encap_external_entropy(
1778
    uint8_t out_ciphertext[MLKEM1024_CIPHERTEXT_BYTES],
1779
    uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES],
1780
    const MLKEM1024_public_key *public_key,
1781
0
    const uint8_t entropy[BCM_MLKEM_ENCAP_ENTROPY]) {
1782
0
  const mlkem::public_key<RANK1024> *pub =
1783
0
      mlkem::public_key_1024_from_external(public_key);
1784
0
  mlkem_encap_external_entropy(out_ciphertext, out_shared_secret, pub, entropy);
1785
0
  return bcm_infallible::approved;
1786
0
}
1787
1788
bcm_status bssl::BCM_mlkem768_decap(
1789
    uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES],
1790
    const uint8_t *ciphertext, size_t ciphertext_len,
1791
23
    const MLKEM768_private_key *private_key) {
1792
23
  if (ciphertext_len != MLKEM768_CIPHERTEXT_BYTES) {
1793
0
    BCM_rand_bytes(out_shared_secret, MLKEM_SHARED_SECRET_BYTES);
1794
0
    return bcm_status::failure;
1795
0
  }
1796
23
  const mlkem::private_key<RANK768> *priv =
1797
23
      mlkem::private_key_768_from_external(private_key);
1798
23
  mlkem_decap(out_shared_secret, ciphertext, priv);
1799
23
  return bcm_status::approved;
1800
23
}
1801
1802
bcm_status bssl::BCM_mlkem1024_decap(
1803
    uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES],
1804
    const uint8_t *ciphertext, size_t ciphertext_len,
1805
1
    const MLKEM1024_private_key *private_key) {
1806
1
  if (ciphertext_len != MLKEM1024_CIPHERTEXT_BYTES) {
1807
1
    BCM_rand_bytes(out_shared_secret, MLKEM_SHARED_SECRET_BYTES);
1808
1
    return bcm_status::failure;
1809
1
  }
1810
0
  const mlkem::private_key<RANK1024> *priv =
1811
0
      mlkem::private_key_1024_from_external(private_key);
1812
0
  mlkem_decap(out_shared_secret, ciphertext, priv);
1813
0
  return bcm_status::approved;
1814
1
}
1815
1816
bcm_status bssl::BCM_mlkem768_marshal_public_key(
1817
107
    CBB *out, const MLKEM768_public_key *public_key) {
1818
107
  return mlkem_marshal_public_key(
1819
107
      out, mlkem::public_key_768_from_external(public_key));
1820
107
}
1821
1822
bcm_status bssl::BCM_mlkem1024_marshal_public_key(
1823
23
    CBB *out, const MLKEM1024_public_key *public_key) {
1824
23
  return mlkem_marshal_public_key(
1825
23
      out, mlkem::public_key_1024_from_external(public_key));
1826
23
}
1827
1828
int bssl::BCM_mlkem768_public_keys_equal(const MLKEM768_public_key *a,
1829
0
                                         const MLKEM768_public_key *b) {
1830
0
  const auto *pub_a = mlkem::public_key_768_from_external(a);
1831
0
  const auto *pub_b = mlkem::public_key_768_from_external(b);
1832
0
  if (mlkem_public_keys_equal(pub_a, pub_b)) {
1833
0
    return 1;
1834
0
  }
1835
0
  return 0;
1836
0
}
1837
1838
int bssl::BCM_mlkem1024_public_keys_equal(const MLKEM1024_public_key *a,
1839
0
                                          const MLKEM1024_public_key *b) {
1840
0
  const auto *pub_a = mlkem::public_key_1024_from_external(a);
1841
0
  const auto *pub_b = mlkem::public_key_1024_from_external(b);
1842
0
  if (mlkem_public_keys_equal(pub_a, pub_b)) {
1843
0
    return 1;
1844
0
  }
1845
0
  return 0;
1846
0
}
1847
1848
bcm_status bssl::BCM_mlkem768_parse_public_key(MLKEM768_public_key *public_key,
1849
686
                                               CBS *in) {
1850
686
  mlkem::public_key<RANK768> *pub =
1851
686
      mlkem::public_key_768_from_external(public_key);
1852
686
  if (!mlkem_parse_public_key(pub, in)) {
1853
179
    return bcm_status::failure;
1854
179
  }
1855
507
  return bcm_status::approved;
1856
686
}
1857
1858
bcm_status bssl::BCM_mlkem1024_parse_public_key(
1859
132
    MLKEM1024_public_key *public_key, CBS *in) {
1860
132
  mlkem::public_key<RANK1024> *pub =
1861
132
      mlkem::public_key_1024_from_external(public_key);
1862
132
  if (!mlkem_parse_public_key(pub, in)) {
1863
91
    return bcm_status::failure;
1864
91
  }
1865
41
  return bcm_status::approved;
1866
132
}
1867
1868
bcm_status bssl::BCM_mlkem768_marshal_private_key(
1869
0
    CBB *out, const MLKEM768_private_key *private_key) {
1870
0
  const mlkem::private_key<RANK768> *const priv =
1871
0
      mlkem::private_key_768_from_external(private_key);
1872
0
  if (!mlkem_marshal_private_key(out, priv)) {
1873
0
    return bcm_status::failure;
1874
0
  }
1875
0
  return bcm_status::approved;
1876
0
}
1877
1878
bcm_status bssl::BCM_mlkem1024_marshal_private_key(
1879
0
    CBB *out, const MLKEM1024_private_key *private_key) {
1880
0
  const mlkem::private_key<RANK1024> *const priv =
1881
0
      mlkem::private_key_1024_from_external(private_key);
1882
0
  if (!mlkem_marshal_private_key(out, priv)) {
1883
0
    return bcm_status::failure;
1884
0
  }
1885
0
  return bcm_status::approved;
1886
0
}
1887
1888
bcm_status bssl::BCM_mlkem768_parse_private_key(
1889
0
    MLKEM768_private_key *out_private_key, CBS *in) {
1890
0
  mlkem::private_key<RANK768> *const priv =
1891
0
      mlkem::private_key_768_from_external(out_private_key);
1892
0
  if (!mlkem_parse_private_key(priv, in)) {
1893
0
    return bcm_status::failure;
1894
0
  }
1895
0
  return bcm_status::approved;
1896
0
}
1897
1898
bcm_status bssl::BCM_mlkem1024_parse_private_key(
1899
0
    MLKEM1024_private_key *out_private_key, CBS *in) {
1900
0
  mlkem::private_key<RANK1024> *const priv =
1901
0
      mlkem::private_key_1024_from_external(out_private_key);
1902
0
  if (!mlkem_parse_private_key(priv, in)) {
1903
0
    return bcm_status::failure;
1904
0
  }
1905
0
  return bcm_status::approved;
1906
0
}
1907
1908
0
int bssl::boringssl_self_test_mlkem() {
1909
0
  return mlkem::fips::keygen_self_test() && mlkem::fips::encap_self_test() &&
1910
0
         mlkem::fips::decap_self_test();
1911
0
}