Coverage Report

Created: 2026-10-28 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssl/crypto/ml_kem/ml_kem.c
Line
Count
Source
1
/*
2
 * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved.
3
 *
4
 * Licensed under the Apache License 2.0 (the "License").  You may not use
5
 * this file except in compliance with the License.  You can obtain a copy
6
 * in the file LICENSE in the source distribution or at
7
 * https://www.openssl.org/source/license.html
8
 */
9
10
#include <openssl/byteorder.h>
11
#include <openssl/rand.h>
12
#include <openssl/proverr.h>
13
#include "crypto/ml_kem.h"
14
#include "ml_kem_local.h"
15
#include "internal/constant_time.h"
16
#include "internal/sha3.h"
17
18
#if ML_KEM_SEED_BYTES != ML_KEM_SHARED_SECRET_BYTES + ML_KEM_RANDOM_BYTES
19
#error "ML-KEM keygen seed length != shared secret + random bytes length"
20
#endif
21
#if ML_KEM_SHARED_SECRET_BYTES != ML_KEM_RANDOM_BYTES
22
#error "Invalid unequal lengths of ML-KEM shared secret and random inputs"
23
#endif
24
25
#if UINT_MAX < UINT32_MAX
26
#error "Unsupported compiler: sizeof(unsigned int) < sizeof(uint32_t)"
27
#endif
28
29
/* Handy function-like bit-extraction macros */
30
0
#define bit0(b) ((b) & 1)
31
0
#define bitn(n, b) (((b) >> n) & 1)
32
33
/*
34
 * 12 bits are sufficient to losslessly represent values in [0, q-1].
35
 * INVERSE_DEGREE is (n/2)^-1 mod q; used in inverse NTT.
36
 */
37
0
#define DEGREE ML_KEM_DEGREE
38
#define INVERSE_DEGREE (ML_KEM_PRIME - 2 * 13)
39
/*
40
 * Barrett reduction approximates (x mod q) without a division instruction.
41
 * It pre-computes m = floor(2^BARRETT_SHIFT / q) and then estimates:
42
 *
43
 *   quotient = (x * m) >> BARRETT_SHIFT
44
 *   remainder = x - quotient * q         (corrected by reduce_once())
45
 *
46
 * Correctness requires BARRETT_SHIFT >= 2 * LOG2PRIME (== 2 * 12 == 24).
47
 * The minimum shift of 24 bits is sufficient for the Barrett reduction
48
 * bounds required by ML-KEM.
49
 *
50
 * On s390x, a Barrett shift of 32 allows (a * b) >> BARRETT_SHIFT to be
51
 * obtained directly from the high half of a 32x32->64-bit multiplication,
52
 * avoiding additional instructions.
53
 * This optimization is used by the generic implementations of `reduce`
54
 * and `compress`. In particular, `compress` is not manually vectorized,
55
 * so it can benefit from compiler autovectorization when
56
 * BARRETT_SHIFT == 32.
57
 *
58
 * On all other platforms BARRETT_SHIFT == 24 is used.  The multiplier
59
 * m = floor(2^24 / 3329) = 5039 fits in 13 bits, which the compiler can
60
 * represent as a small immediate.  On AArch64 the alternative value
61
 * m = floor(2^32 / 3329) = 1290167 requires a wider immediate encoding
62
 * (an extra movk instruction), making the 32-bit shift slightly less
63
 * efficient on that platform.
64
 */
65
#if defined(__s390x__)
66
#define BARRETT_SHIFT 32
67
#else
68
#define BARRETT_SHIFT 24
69
#endif
70
71
#ifdef SHA3_BLOCKSIZE
72
#define SHAKE128_BLOCKSIZE SHA3_BLOCKSIZE(128)
73
#endif
74
75
/*
76
 * The scalar rejection-sampling buffer size needs to be a multiple of 12, but
77
 * is otherwise arbitrary, the preferred block size matches the internal buffer
78
 * size of SHAKE128, avoiding internal buffering and copying in SHAKE128. That
79
 * block size of (1600 - 256)/8 bytes, or 168, just happens to divide by 12!
80
 *
81
 * If the blocksize is unknown, or is not divisible by 12, 168 is used as a
82
 * fallback.
83
 */
84
#if defined(SHAKE128_BLOCKSIZE) && (SHAKE128_BLOCKSIZE) % 12 == 0
85
#define SCALAR_SAMPLING_BUFSIZE (SHAKE128_BLOCKSIZE)
86
#else
87
#define SCALAR_SAMPLING_BUFSIZE 168
88
#endif
89
90
/* Key material allocation layout */
91
#define DECLARE_ML_KEM_PUBKEYDATA(name, rank)                  \
92
    struct name##_alloc {                                      \
93
        /* Public vector |t| */                                \
94
        scalar tbuf[(rank)];                                   \
95
        /* Pre-computed matrix |m| (FIPS 203 |A| transpose) */ \
96
        scalar mbuf[(rank) * (rank)];                          \
97
    }
98
99
#define DECLARE_ML_KEM_PRVKEYDATA(name, rank)  \
100
    struct name##_alloc {                      \
101
        scalar sbuf[rank];                     \
102
        uint8_t zbuf[2 * ML_KEM_RANDOM_BYTES]; \
103
    }
104
105
/* Declare variant-specific public and private storage */
106
#define DECLARE_ML_KEM_VARIANT_KEYDATA(bits)                        \
107
    DECLARE_ML_KEM_PUBKEYDATA(pubkey_##bits, ML_KEM_##bits##_RANK); \
108
    DECLARE_ML_KEM_PRVKEYDATA(prvkey_##bits, ML_KEM_##bits##_RANK)
109
110
DECLARE_ML_KEM_VARIANT_KEYDATA(512);
111
DECLARE_ML_KEM_VARIANT_KEYDATA(768);
112
DECLARE_ML_KEM_VARIANT_KEYDATA(1024);
113
#undef DECLARE_ML_KEM_VARIANT_KEYDATA
114
#undef DECLARE_ML_KEM_PUBKEYDATA
115
#undef DECLARE_ML_KEM_PRVKEYDATA
116
117
typedef __owur int (*CBD_FUNC)(scalar *out, uint8_t in[ML_KEM_RANDOM_BYTES + 1],
118
    EVP_MD_CTX *mdctx, const ML_KEM_KEY *key);
119
static void scalar_encode(uint8_t *out, const scalar *s, int bits);
120
121
/*
122
 * The wire-form of a losslessly encoded vector uses 12-bits per element.
123
 *
124
 * The wire-form public key consists of the lossless encoding of the public
125
 * vector |t|, followed by the public seed |rho|.
126
 *
127
 * Our serialised private key concatenates serialisations of the private vector
128
 * |s|, the public key, the public key hash, and the failure secret |z|.
129
 */
130
#define VECTOR_BYTES(b) ((3 * DEGREE / 2) * ML_KEM_##b##_RANK)
131
#define PUBKEY_BYTES(b) (VECTOR_BYTES(b) + ML_KEM_RANDOM_BYTES)
132
#define PRVKEY_BYTES(b) (2 * PUBKEY_BYTES(b) + ML_KEM_PKHASH_BYTES)
133
134
/*
135
 * Encapsulation produces a vector "u" and a scalar "v", whose coordinates
136
 * (numbers modulo the ML-KEM prime "q") are lossily encoded using as "du" and
137
 * "dv" bits, respectively.  This encoding is the ciphertext input for
138
 * decapsulation.
139
 */
140
#define U_VECTOR_BYTES(b) ((DEGREE / 8) * ML_KEM_##b##_DU * ML_KEM_##b##_RANK)
141
#define V_SCALAR_BYTES(b) ((DEGREE / 8) * ML_KEM_##b##_DV)
142
#define CTEXT_BYTES(b) (U_VECTOR_BYTES(b) + V_SCALAR_BYTES(b))
143
144
/*
145
 * Indices of slots in the vinfo tables below
146
 */
147
0
#define ML_KEM_512_VINFO 0
148
0
#define ML_KEM_768_VINFO 1
149
0
#define ML_KEM_1024_VINFO 2
150
151
/*
152
 * Per-variant fixed parameters
153
 */
154
static const ML_KEM_VINFO vinfo_map[3] = {
155
    { "ML-KEM-512",
156
        PRVKEY_BYTES(512),
157
        sizeof(struct prvkey_512_alloc),
158
        PUBKEY_BYTES(512),
159
        sizeof(struct pubkey_512_alloc),
160
        CTEXT_BYTES(512),
161
        VECTOR_BYTES(512),
162
        U_VECTOR_BYTES(512),
163
        EVP_PKEY_ML_KEM_512,
164
        ML_KEM_512_BITS,
165
        ML_KEM_512_RANK,
166
        ML_KEM_512_DU,
167
        ML_KEM_512_DV,
168
        ML_KEM_512_SECBITS,
169
        ML_KEM_512_SECURITY_CATEGORY },
170
    { "ML-KEM-768",
171
        PRVKEY_BYTES(768),
172
        sizeof(struct prvkey_768_alloc),
173
        PUBKEY_BYTES(768),
174
        sizeof(struct pubkey_768_alloc),
175
        CTEXT_BYTES(768),
176
        VECTOR_BYTES(768),
177
        U_VECTOR_BYTES(768),
178
        EVP_PKEY_ML_KEM_768,
179
        ML_KEM_768_BITS,
180
        ML_KEM_768_RANK,
181
        ML_KEM_768_DU,
182
        ML_KEM_768_DV,
183
        ML_KEM_768_SECBITS,
184
        ML_KEM_768_SECURITY_CATEGORY },
185
    { "ML-KEM-1024",
186
        PRVKEY_BYTES(1024),
187
        sizeof(struct prvkey_1024_alloc),
188
        PUBKEY_BYTES(1024),
189
        sizeof(struct pubkey_1024_alloc),
190
        CTEXT_BYTES(1024),
191
        VECTOR_BYTES(1024),
192
        U_VECTOR_BYTES(1024),
193
        EVP_PKEY_ML_KEM_1024,
194
        ML_KEM_1024_BITS,
195
        ML_KEM_1024_RANK,
196
        ML_KEM_1024_DU,
197
        ML_KEM_1024_DV,
198
        ML_KEM_1024_SECBITS,
199
        ML_KEM_1024_SECURITY_CATEGORY }
200
};
201
202
/*
203
 * Remainders modulo `kPrime`, for sufficiently small inputs, are computed in
204
 * constant time via Barrett reduction, and a final call to reduce_once(),
205
 * which reduces inputs that are at most 2*kPrime and is also constant-time.
206
 */
207
static const int kPrime = ML_KEM_PRIME;
208
static const unsigned int kBarrettShift = BARRETT_SHIFT;
209
static const size_t kBarrettMultiplier = (1ull << BARRETT_SHIFT) / ML_KEM_PRIME;
210
static const uint16_t kHalfPrime = (ML_KEM_PRIME - 1) / 2;
211
static const uint16_t kInverseDegree = INVERSE_DEGREE;
212
213
/*
214
 * Python helper:
215
 *
216
 * p = 3329
217
 * def bitreverse(i):
218
 *     ret = 0
219
 *     for n in range(7):
220
 *         bit = i & 1
221
 *         ret <<= 1
222
 *         ret |= bit
223
 *         i >>= 1
224
 *     return ret
225
 */
226
227
/*-
228
 * First precomputed array from Appendix A of FIPS 203, or else Python:
229
 * kNTTRoots = [pow(17, bitreverse(i), p) for i in range(128)]
230
 */
231
static const uint16_t kNTTRoots[128] = {
232
    0x001, 0x6c1, 0xa14, 0xcd9, 0xa52, 0x276, 0x769, 0x350,
233
    0x426, 0x77f, 0x0c1, 0x31d, 0xae2, 0xcbc, 0x239, 0x6d2,
234
    0x128, 0x98f, 0x53b, 0x5c4, 0xbe6, 0x038, 0x8c0, 0x535,
235
    0x592, 0x82e, 0x217, 0xb42, 0x959, 0xb3f, 0x7b6, 0x335,
236
    0x121, 0x14b, 0xcb5, 0x6dc, 0x4ad, 0x900, 0x8e5, 0x807,
237
    0x28a, 0x7b9, 0x9d1, 0x278, 0xb31, 0x021, 0x528, 0x77b,
238
    0x90f, 0x59b, 0x327, 0x1c4, 0x59e, 0xb34, 0x5fe, 0x962,
239
    0xa57, 0xa39, 0x5c9, 0x288, 0x9aa, 0xc26, 0x4cb, 0x38e,
240
    0x011, 0xac9, 0x247, 0xa59, 0x665, 0x2d3, 0x8f0, 0x44c,
241
    0x581, 0xa66, 0xcd1, 0x0e9, 0x2f4, 0x86c, 0xbc7, 0xbea,
242
    0x6a7, 0x673, 0xae5, 0x6fd, 0x737, 0x3b8, 0x5b5, 0xa7f,
243
    0x3ab, 0x904, 0x985, 0x954, 0x2dd, 0x921, 0x10c, 0x281,
244
    0x630, 0x8fa, 0x7f5, 0xc94, 0x177, 0x9f5, 0x82a, 0x66d,
245
    0x427, 0x13f, 0xad5, 0x2f5, 0x833, 0x231, 0x9a2, 0xa22,
246
    0xaf4, 0x444, 0x193, 0x402, 0x477, 0x866, 0xad7, 0x376,
247
    0x6ba, 0x4bc, 0x752, 0x405, 0x83e, 0xb77, 0x375, 0x86a
248
};
249
250
/*
251
 * InverseNTTRoots = [pow(17, -bitreverse(i), p) for i in range(128)]
252
 * Listed in order of use in the inverse NTT loop (index 0 is skipped):
253
 *
254
 *  0, 64, 65, ..., 127, 32, 33, ..., 63, 16, 17, ..., 31, 8, 9, ...
255
 */
256
static const uint16_t kInverseNTTRoots[128] = {
257
    0x001, 0x497, 0x98c, 0x18a, 0x4c3, 0x8fc, 0x5af, 0x845,
258
    0x647, 0x98b, 0x22a, 0x49b, 0x88a, 0x8ff, 0xb6e, 0x8bd,
259
    0x20d, 0x2df, 0x35f, 0xad0, 0x4ce, 0xa0c, 0x22c, 0xbc2,
260
    0x8da, 0x694, 0x4d7, 0x30c, 0xb8a, 0x06d, 0x50c, 0x407,
261
    0x6d1, 0xa80, 0xbf5, 0x3e0, 0xa24, 0x3ad, 0x37c, 0x3fd,
262
    0x956, 0x282, 0x74c, 0x949, 0x5ca, 0x604, 0x21c, 0x68e,
263
    0x65a, 0x117, 0x13a, 0x495, 0xa0d, 0xc18, 0x030, 0x29b,
264
    0x780, 0x8b5, 0x411, 0xa2e, 0x69c, 0x2a8, 0xaba, 0x238,
265
    0xcf0, 0x973, 0x836, 0x0db, 0x357, 0xa79, 0x738, 0x2c8,
266
    0x2aa, 0x39f, 0x703, 0x1cd, 0x763, 0xb3d, 0x9da, 0x766,
267
    0x3f2, 0x586, 0x7d9, 0xce0, 0x1d0, 0xa89, 0x330, 0x548,
268
    0xa77, 0x4fa, 0x41c, 0x401, 0x854, 0x625, 0x04c, 0xbb6,
269
    0xbe0, 0x9cc, 0x54b, 0x1c2, 0x3a8, 0x1bf, 0xaea, 0x4d3,
270
    0x76f, 0x7cc, 0x441, 0xcc9, 0x11b, 0x73d, 0x7c6, 0x372,
271
    0xbd9, 0x62f, 0xac8, 0x045, 0x21f, 0x9e4, 0xc40, 0x582,
272
    0x8db, 0x9b1, 0x598, 0xa8b, 0x2af, 0x028, 0x2ed, 0x640
273
};
274
275
/*
276
 * Second precomputed array from Appendix A of FIPS 203 (normalised positive),
277
 * or else Python:
278
 * ModRoots = [pow(17, 2*bitreverse(i) + 1, p) for i in range(128)]
279
 */
280
static const uint16_t kModRoots[128] = {
281
    0x011, 0xcf0, 0xac9, 0x238, 0x247, 0xaba, 0xa59, 0x2a8,
282
    0x665, 0x69c, 0x2d3, 0xa2e, 0x8f0, 0x411, 0x44c, 0x8b5,
283
    0x581, 0x780, 0xa66, 0x29b, 0xcd1, 0x030, 0x0e9, 0xc18,
284
    0x2f4, 0xa0d, 0x86c, 0x495, 0xbc7, 0x13a, 0xbea, 0x117,
285
    0x6a7, 0x65a, 0x673, 0x68e, 0xae5, 0x21c, 0x6fd, 0x604,
286
    0x737, 0x5ca, 0x3b8, 0x949, 0x5b5, 0x74c, 0xa7f, 0x282,
287
    0x3ab, 0x956, 0x904, 0x3fd, 0x985, 0x37c, 0x954, 0x3ad,
288
    0x2dd, 0xa24, 0x921, 0x3e0, 0x10c, 0xbf5, 0x281, 0xa80,
289
    0x630, 0x6d1, 0x8fa, 0x407, 0x7f5, 0x50c, 0xc94, 0x06d,
290
    0x177, 0xb8a, 0x9f5, 0x30c, 0x82a, 0x4d7, 0x66d, 0x694,
291
    0x427, 0x8da, 0x13f, 0xbc2, 0xad5, 0x22c, 0x2f5, 0xa0c,
292
    0x833, 0x4ce, 0x231, 0xad0, 0x9a2, 0x35f, 0xa22, 0x2df,
293
    0xaf4, 0x20d, 0x444, 0x8bd, 0x193, 0xb6e, 0x402, 0x8ff,
294
    0x477, 0x88a, 0x866, 0x49b, 0xad7, 0x22a, 0x376, 0x98b,
295
    0x6ba, 0x647, 0x4bc, 0x845, 0x752, 0x5af, 0x405, 0x8fc,
296
    0x83e, 0x4c3, 0xb77, 0x18a, 0x375, 0x98c, 0x86a, 0x497
297
};
298
299
/*
300
 * single_keccak hashes |inlen| bytes from |in| and writes |outlen| bytes of
301
 * output to |out|. If the |md| specifies a fixed-output function, like
302
 * SHA3-256, then |outlen| must be the correct length for that function.
303
 */
304
static __owur int single_keccak(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen,
305
    EVP_MD_CTX *mdctx)
306
0
{
307
0
    unsigned int sz = (unsigned int)outlen;
308
309
0
    if (!EVP_DigestUpdate(mdctx, in, inlen))
310
0
        return 0;
311
0
    if (EVP_MD_xof(EVP_MD_CTX_get0_md(mdctx)))
312
0
        return EVP_DigestFinalXOF(mdctx, out, outlen);
313
0
    return EVP_DigestFinal_ex(mdctx, out, &sz)
314
0
        && ossl_assert((size_t)sz == outlen);
315
0
}
316
317
/*
318
 * FIPS 203, Section 4.1, equation (4.3): PRF. Takes 32+1 input bytes, and uses
319
 * SHAKE256 to produce the input to SamplePolyCBD_eta: FIPS 203, algorithm 8.
320
 */
321
static __owur int prf(uint8_t *out, size_t len, const uint8_t in[ML_KEM_RANDOM_BYTES + 1],
322
    EVP_MD_CTX *mdctx, const ML_KEM_KEY *key)
323
0
{
324
0
    return EVP_DigestInit_ex(mdctx, key->shake256_md, NULL)
325
0
        && single_keccak(out, len, in, ML_KEM_RANDOM_BYTES + 1, mdctx);
326
0
}
327
328
/*
329
 * FIPS 203, Section 4.1, equation (4.4): H.  SHA3-256 hash of a variable
330
 * length input, producing 32 bytes of output.
331
 */
332
static __owur int hash_h(uint8_t out[ML_KEM_PKHASH_BYTES], const uint8_t *in, size_t len,
333
    EVP_MD_CTX *mdctx, const ML_KEM_KEY *key)
334
0
{
335
0
    return EVP_DigestInit_ex(mdctx, key->sha3_256_md, NULL)
336
0
        && single_keccak(out, ML_KEM_PKHASH_BYTES, in, len, mdctx);
337
0
}
338
339
/* Incremental hash_h of expanded public key */
340
static int
341
hash_h_pubkey(uint8_t pkhash[ML_KEM_PKHASH_BYTES],
342
    EVP_MD_CTX *mdctx, ML_KEM_KEY *key)
343
0
{
344
0
    const ML_KEM_VINFO *vinfo = key->vinfo;
345
0
    const scalar *t = key->t, *end = t + vinfo->rank;
346
0
    unsigned int sz;
347
348
0
    if (!EVP_DigestInit_ex(mdctx, key->sha3_256_md, NULL))
349
0
        return 0;
350
351
0
    do {
352
0
        uint8_t buf[3 * DEGREE / 2];
353
354
0
        scalar_encode(buf, t++, 12);
355
0
        if (!EVP_DigestUpdate(mdctx, buf, sizeof(buf)))
356
0
            return 0;
357
0
    } while (t < end);
358
359
0
    if (!EVP_DigestUpdate(mdctx, key->rho, ML_KEM_RANDOM_BYTES))
360
0
        return 0;
361
0
    return EVP_DigestFinal_ex(mdctx, pkhash, &sz)
362
0
        && ossl_assert(sz == ML_KEM_PKHASH_BYTES);
363
0
}
364
365
/*
366
 * FIPS 203, Section 4.1, equation (4.5): G.  SHA3-512 hash of a variable
367
 * length input, producing 64 bytes of output, in particular the seeds
368
 * (d,z) for key generation.
369
 */
370
static __owur int hash_g(uint8_t out[ML_KEM_SEED_BYTES], const uint8_t *in, size_t len,
371
    EVP_MD_CTX *mdctx, const ML_KEM_KEY *key)
372
0
{
373
0
    return EVP_DigestInit_ex(mdctx, key->sha3_512_md, NULL)
374
0
        && single_keccak(out, ML_KEM_SEED_BYTES, in, len, mdctx);
375
0
}
376
377
/*
378
 * FIPS 203, Section 4.1, equation (4.4): J. SHAKE256 taking a variable length
379
 * input to compute a 32-byte implicit rejection shared secret, of the same
380
 * length as the expected shared secret.  (Computed even on success to avoid
381
 * side-channel leaks).
382
 */
383
static __owur int kdf(uint8_t out[ML_KEM_SHARED_SECRET_BYTES],
384
    const uint8_t z[ML_KEM_RANDOM_BYTES],
385
    const uint8_t *ctext, size_t len,
386
    EVP_MD_CTX *mdctx, const ML_KEM_KEY *key)
387
0
{
388
0
    return EVP_DigestInit_ex(mdctx, key->shake256_md, NULL)
389
0
        && EVP_DigestUpdate(mdctx, z, ML_KEM_RANDOM_BYTES)
390
0
        && EVP_DigestUpdate(mdctx, ctext, len)
391
0
        && EVP_DigestFinalXOF(mdctx, out, ML_KEM_SHARED_SECRET_BYTES);
392
0
}
393
394
/*
395
 * FIPS 203, Section 4.2.2, Algorithm 7: "SampleNTT" (steps 3-17, steps 1, 2
396
 * are performed by the caller). Rejection-samples a Keccak stream to get
397
 * uniformly distributed elements in the range [0,q). This is used for matrix
398
 * expansion and only operates on public inputs.
399
 */
400
static __owur int sample_scalar(scalar *out, EVP_MD_CTX *mdctx)
401
0
{
402
0
    uint16_t *curr = out->c, *endout = curr + DEGREE;
403
0
    uint8_t buf[SCALAR_SAMPLING_BUFSIZE], *in;
404
0
    uint8_t *endin = buf + sizeof(buf);
405
0
    uint16_t d;
406
0
    uint8_t b1, b2, b3;
407
408
0
    do {
409
0
        if (!EVP_DigestSqueeze(mdctx, in = buf, sizeof(buf)))
410
0
            return 0;
411
0
        do {
412
0
            b1 = *in++;
413
0
            b2 = *in++;
414
0
            b3 = *in++;
415
416
0
            if (curr >= endout)
417
0
                break;
418
0
            if ((d = ((b2 & 0x0f) << 8) + b1) < kPrime)
419
0
                *curr++ = d;
420
0
            if (curr >= endout)
421
0
                break;
422
0
            if ((d = (b3 << 4) + (b2 >> 4)) < kPrime)
423
0
                *curr++ = d;
424
0
        } while (in < endin);
425
0
    } while (curr < endout);
426
0
    return 1;
427
0
}
428
429
static CRYPTO_ONCE ml_kem_ntt_once = CRYPTO_ONCE_STATIC_INIT;
430
431
#if defined(_ARCH_PPC64)
432
#include "arch/ppc_arch.h"
433
#endif
434
435
/*
436
 * Function pointer types for NTT dispatch.
437
 *
438
 * Three NTT-related entry points are dispatched at runtime:
439
 *
440
 *  scalar_ntt
441
 *      Forward NTT.  Converts a polynomial from standard into NTT domain.
442
 *
443
 *  scalar_inverse_ntt
444
 *      Full inverse NTT: butterfly stages followed by multiplication by
445
 *      INVERSE_DEGREE = (n/2)^-1 mod q.  Used inside matrix_mult_intt where
446
 *      each result row is immediately transformed back to standard form.
447
 *
448
 *  scalar_inverse_ntt_demontgomerize
449
 *      Inverse NTT whose input may still carry an inverse-Montgomery factor
450
 *      R^-1 from a preceding inner_product_montgomery call.  On the generic
451
 *      PPC, and AVX2 paths the two pointers are identical (both point at the same
452
 *      fully-reduced implementation), because the generic inner_product
453
 *      already produces fully-reduced outputs via Barrett reduction.  On the
454
 *      s390x/vec128 path the two are distinct:
455
 *        - inner_product_montgomery_vec128 accumulates the dot-product using
456
 *          Montgomery arithmetic and intentionally leaves each coefficient
457
 *          scaled by R^-1 (= 169 mod q), deferring the final conversion to
458
 *          save a per-coefficient multiply.
459
 *        - scalar_inverse_ntt_demontgomerize_vec128 first calls
460
 *          demontgomerize_scalar_vec128 to convert coefficients from
461
 *          inverse-Montgomery form to standard form, then runs the raw
462
 *          inverse NTT butterfly stages, and finally multiplies by
463
 *          INVERSE_DEGREE via scalar_mult_const_512_vec128.
464
 *
465
 * The net effect is that callers always see a fully-reduced standard-form
466
 * polynomial after the (inner_product_montgomery, scalar_inverse_ntt_demontgomerize)
467
 * pair, regardless of which backend is active.
468
 */
469
typedef void (*ml_kem_scalar_ntt_fn)(scalar *p);
470
typedef void (*ml_kem_scalar_inverse_ntt_fn)(scalar *p);
471
typedef void (*ml_kem_scalar_inverse_ntt_demontgomerize_fn)(scalar *p);
472
473
/* Forward declarations */
474
static void ossl_ml_kem_scalar_ntt_generic(scalar *s);
475
static void ossl_ml_kem_scalar_inverse_ntt_generic(scalar *s);
476
477
static ml_kem_scalar_ntt_fn scalar_ntt = ossl_ml_kem_scalar_ntt_generic;
478
/*
479
 * scalar_inverse_ntt: used by matrix_mult_intt, where inputs are already fully
480
 * reduced (no deferred Montgomery factor).
481
 */
482
static ml_kem_scalar_inverse_ntt_fn scalar_inverse_ntt = ossl_ml_kem_scalar_inverse_ntt_generic;
483
/*
484
 * scalar_inverse_ntt_demontgomerize: used after inner_product_montgomery.  On
485
 * generic/PPC/AVX2 this is the same function as scalar_inverse_ntt.  On s390x it is
486
 * a specialised variant that also removes the inverse-Montgomery factor R^-1
487
 * left by inner_product_montgomery_vec128.
488
 */
489
static ml_kem_scalar_inverse_ntt_demontgomerize_fn scalar_inverse_ntt_demontgomerize = ossl_ml_kem_scalar_inverse_ntt_generic;
490
491
#if defined(MLKEM_AVX2_X86_64_ASM)
492
int mlkem_avx2_capable(void);
493
void mlkem_ntt_avx2(uint16_t *c);
494
void mlkem_inverse_ntt_avx2(uint16_t *c);
495
496
static void scalar_ntt_avx2(scalar *s)
497
{
498
    mlkem_ntt_avx2(s->c);
499
}
500
501
static void scalar_inverse_ntt_avx2(scalar *s)
502
{
503
    mlkem_inverse_ntt_avx2(s->c);
504
}
505
#endif
506
507
#if defined(MLKEM_NTT_PPC_ASM) && defined(_ARCH_PPC64)
508
/*
509
 * PPC64LE Platform supports.
510
 */
511
void mlkem_ntt_ppc(uint16_t *c);
512
void mlkem_inverse_ntt_ppc(uint16_t *c);
513
514
static void scalar_ntt_ppc(scalar *s)
515
{
516
    mlkem_ntt_ppc(s->c);
517
}
518
519
static void scalar_inverse_ntt_ppc(scalar *s)
520
{
521
    mlkem_inverse_ntt_ppc(s->c);
522
}
523
#endif
524
525
/*
526
 * VX_COMPILER_SUPPORT_VEC128 is now defined (via include/crypto/ml_kem.h)
527
 * whenever OPENSSL_ML_KEM_S390X && __s390x__, without requiring __VX__.
528
 * This ensures the S390X_VX_CAPABLE macro and the vec128 function prototypes
529
 * are visible here even though ml_kem.c is compiled without -march=z13.
530
 */
531
#if defined(VX_COMPILER_SUPPORT_VEC128)
532
#include "arch/s390x_arch.h"
533
#endif
534
535
/*
536
 * Function pointer types for scalar multiplication dispatch.
537
 *
538
 *  scalar_mult_add
539
 *      Pointwise-multiply two NTT-domain scalars and accumulate the result
540
 *      into an existing scalar (out += lhs * rhs).
541
 *
542
 *  inner_product_montgomery
543
 *      Computes the dot-product of two rank-element NTT-domain vectors and
544
 *      stores the result in *out.  The name "montgomery" signals the output
545
 *      representation contract:
546
 *        - On the generic path the function uses Barrett reduction throughout
547
 *          and the output is fully reduced in [0, q).
548
 *        - On the s390x/vec128 path the function uses Montgomery multiplication
549
 *          internally and the output coefficients are left scaled by R^-1
550
 *          (= 169 mod q).  Callers MUST immediately follow this call with
551
 *          scalar_inverse_ntt_demontgomerize, which demontgomerizes the
552
 *          coefficients, runs the inverse NTT butterflies, and then applies
553
 *          the INVERSE_DEGREE normalization.
554
 *
555
 *  matrix_mult_intt
556
 *      Computes out[i] = INTT(sum_j m[i*rank+j] * a[j]) for each row i.
557
 *      The generic implementation accumulates each row in standard form (via
558
 *      Barrett reduction) and then calls scalar_inverse_ntt.  The s390x/vec128
559
 *      implementation accumulates each row in inverse-Montgomery form, then
560
 *      explicitly calls demontgomerize_scalar_vec128 to convert to standard
561
 *      form, and finally calls ossl_ml_kem_scalar_inverse_ntt_vec128 directly
562
 *      (not the demontgomerize INTT variant, which is reserved for use after
563
 *      inner_product_montgomery_vec128).
564
 */
565
typedef void (*ml_kem_scalar_mult_add_fn)(scalar *out, const scalar *lhs, const scalar *rhs);
566
typedef void (*ml_kem_inner_product_montgomery_fn)(scalar *out, const scalar *lhs, const scalar *rhs, int rank);
567
typedef void (*ml_kem_matrix_mult_intt_fn)(scalar *out, const scalar *m, const scalar *a, int rank);
568
typedef void (*ml_kem_matrix_mult_transpose_add_fn)(scalar *out, const scalar *m, const scalar *a, int rank);
569
570
/* Forward declarations */
571
static void scalar_mult_generic(scalar *out, const scalar *lhs, const scalar *rhs);
572
static void scalar_mult_add_generic(scalar *out, const scalar *lhs, const scalar *rhs);
573
static void inner_product_generic(scalar *out, const scalar *lhs, const scalar *rhs, int rank);
574
static void matrix_mult_intt_generic(scalar *out, const scalar *m, const scalar *a, int rank);
575
static void matrix_mult_transpose_add_generic(scalar *out, const scalar *m, const scalar *a, int rank);
576
577
#if defined(MLKEM_AVX2_X86_64_ASM)
578
void mlkem_basemul_acc_avx2(uint16_t *out, const uint16_t *lhs,
579
    const uint16_t *rhs, int rank);
580
void mlkem_basemul_acc_transpose_add_avx2(uint16_t *out, const uint16_t *lhs,
581
    const uint16_t *rhs, int rank);
582
583
static void inner_product_avx2(scalar *out, const scalar *lhs,
584
    const scalar *rhs, int rank)
585
{
586
    mlkem_basemul_acc_avx2(out->c, lhs->c, rhs->c, rank);
587
}
588
589
static void matrix_mult_intt_avx2(scalar *out, const scalar *m,
590
    const scalar *a, int rank)
591
{
592
    int i;
593
594
    for (i = 0; i < rank; i++, out++, m += rank) {
595
        mlkem_basemul_acc_avx2(out->c, m->c, a->c, rank);
596
        scalar_inverse_ntt(out);
597
    }
598
}
599
600
static void matrix_mult_transpose_add_avx2(scalar *out, const scalar *m,
601
    const scalar *a, int rank)
602
{
603
    int i;
604
605
    for (i = 0; i < rank; i++)
606
        mlkem_basemul_acc_transpose_add_avx2(out[i].c, m[i].c, a[0].c, rank);
607
}
608
609
#endif
610
611
/* Function pointers for dispatch */
612
static ml_kem_scalar_mult_add_fn scalar_mult_add = scalar_mult_add_generic;
613
/*
614
 * Produces the NTT-domain dot-product of two vectors.  Result is in
615
 * inverse-Montgomery form (each coefficient scaled by R^-1 = 169 mod q)
616
 * on s390x (must be followed by scalar_inverse_ntt_demontgomerize), and
617
 * fully reduced on all other platforms.
618
 */
619
static ml_kem_inner_product_montgomery_fn inner_product_montgomery = inner_product_generic;
620
static ml_kem_matrix_mult_intt_fn matrix_mult_intt = matrix_mult_intt_generic;
621
static ml_kem_matrix_mult_transpose_add_fn matrix_mult_transpose_add = matrix_mult_transpose_add_generic;
622
623
static void ml_kem_ntt_init(void)
624
0
{
625
#if defined(MLKEM_AVX2_X86_64_ASM)
626
    if (mlkem_avx2_capable()) {
627
        scalar_ntt = scalar_ntt_avx2;
628
        scalar_inverse_ntt = scalar_inverse_ntt_avx2;
629
        scalar_inverse_ntt_demontgomerize = scalar_inverse_ntt_avx2;
630
        inner_product_montgomery = inner_product_avx2;
631
        matrix_mult_intt = matrix_mult_intt_avx2;
632
        matrix_mult_transpose_add = matrix_mult_transpose_add_avx2;
633
    }
634
#endif
635
636
/*
637
 * Initialize NTT function pointers to PPC64le implementations if available.
638
 * Scalar implementations are used by default.
639
 */
640
#if defined(MLKEM_NTT_PPC_ASM) && defined(_ARCH_PPC64)
641
#if defined(__LITTLE_ENDIAN__) || (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
642
    if (OPENSSL_ppccap_P & PPC_CRYPTO207) {
643
        scalar_ntt = scalar_ntt_ppc;
644
        scalar_inverse_ntt = scalar_inverse_ntt_ppc;
645
        scalar_inverse_ntt_demontgomerize = scalar_inverse_ntt_ppc;
646
    }
647
#endif
648
#endif
649
650
/*
651
 * Initialize NTT and scalar and matrix multiplication function pointers to
652
 * the s390x/vec128 implementation if available.
653
 *
654
 * VX_COMPILER_SUPPORT_VEC128 is defined (via include/crypto/ml_kem.h) for
655
 * every s390x TU that has OPENSSL_ML_KEM_S390X set, regardless of whether
656
 * __VX__ is defined in this TU.  The runtime S390X_VX_CAPABLE check
657
 * (facility bit 129) ensures the vector functions are only called when the
658
 * hardware actually supports VX.
659
 *
660
 * On s390x three pointers differ from the generic ones in a coordinated way:
661
 *   - scalar_inverse_ntt and scalar_inverse_ntt_demontgomerize point to two
662
 *     DIFFERENT functions.  scalar_inverse_ntt_demontgomerize_vec128 is always
663
 *     paired with inner_product_montgomery_vec128: the latter leaves each
664
 *     coefficient in inverse-Montgomery form (scaled by R^-1 = 169 mod q),
665
 *     and the former demontgomerizes the result first, then runs the inverse
666
 *     NTT butterflies, and finally applies the INVERSE_DEGREE normalization.
667
 *   - inner_product_montgomery_vec128 deliberately omits the final
668
 *     inverse-Montgomery-to-standard conversion; callers must use
669
 *     scalar_inverse_ntt_demontgomerize (not scalar_inverse_ntt) afterward.
670
 *   - matrix_mult_intt_vec128 uses scalar_inverse_ntt_vec128 internally
671
 *     (not the demontgomerize variant), because it manages its own reduction
672
 *     strategy without a deferred Montgomery factor.
673
 */
674
#if defined(VX_COMPILER_SUPPORT_VEC128)
675
    if (S390X_VX_CAPABLE) {
676
        scalar_ntt = ossl_ml_kem_scalar_ntt_vec128;
677
        scalar_inverse_ntt = ossl_ml_kem_scalar_inverse_ntt_vec128;
678
        scalar_inverse_ntt_demontgomerize = ossl_ml_kem_scalar_inverse_ntt_demontgomerize_vec128;
679
        scalar_mult_add = ossl_ml_kem_scalar_mult_add_vec128;
680
        inner_product_montgomery = ossl_ml_kem_inner_product_montgomery_vec128;
681
        matrix_mult_intt = ossl_ml_kem_matrix_mult_intt_vec128;
682
    }
683
#endif
684
0
}
685
686
/*-
687
 * reduce_once reduces 0 <= x < 2*kPrime, mod kPrime.
688
 *
689
 * Subtract |q| if the input is larger, without exposing a side-channel,
690
 * avoiding the "clangover" attack.  See |constish_time_true| for a
691
 * discussion on why the value barrier is by default omitted.
692
 */
693
static __owur uint16_t reduce_once(uint16_t x)
694
0
{
695
0
    const uint16_t subtracted = x - kPrime;
696
0
    uint16_t mask = constish_time_true(subtracted >> 15);
697
698
0
    return (mask & x) | (~mask & subtracted);
699
0
}
700
701
/*
702
 * Constant-time Barrett reduction modulo kPrime.
703
 *
704
 * This implementation performs a single final correction via
705
 * reduce_once(), so it requires the Barrett approximation to leave
706
 * the intermediate remainder below 2*kPrime.
707
 *
708
 * All current callers satisfy
709
 *
710
 *     x < kPrime + 2*kPrime*kPrime,
711
 *
712
 * which covers products of two already reduced coefficients together
713
 * with the additions performed by scalar_mult_add_generic().
714
 *
715
 * For BARRETT_SHIFT == 24, this bound is below the first input that
716
 * would require more than one correction.  For BARRETT_SHIFT == 32,
717
 * a single correction is sufficient for every uint32_t input.
718
 */
719
static __owur uint16_t reduce(uint32_t x)
720
0
{
721
0
    uint64_t product = (uint64_t)x * kBarrettMultiplier;
722
0
    uint32_t quotient = (uint32_t)(product >> kBarrettShift);
723
0
    uint32_t remainder = x - quotient * kPrime;
724
725
0
    return reduce_once(remainder);
726
0
}
727
728
/* Multiply a scalar by a constant. */
729
static void scalar_mult_const(scalar *s, uint16_t a)
730
0
{
731
0
    uint16_t *curr = s->c, *end = curr + DEGREE, tmp;
732
733
0
    do {
734
0
        tmp = reduce(*curr * a);
735
0
        *curr++ = tmp;
736
0
    } while (curr < end);
737
0
}
738
739
/*-
740
 * FIPS 203, Section 4.3, Algorithm 9: "NTT".
741
 * In-place number theoretic transform of a given scalar.  Note that ML-KEM's
742
 * kPrime 3329 does not have a 512th root of unity, so this transform leaves
743
 * off the last iteration of the usual FFT code, with the 128 relevant roots of
744
 * unity being stored in NTTRoots.  This means the output should be seen as 128
745
 * elements in GF(3329^2), with the coefficients of the elements being
746
 * consecutive entries in |s->c|.
747
 */
748
void ossl_ml_kem_scalar_ntt_generic(scalar *s)
749
0
{
750
0
    const uint16_t *roots = kNTTRoots;
751
0
    uint16_t *end = s->c + DEGREE;
752
0
    int offset = DEGREE / 2;
753
754
0
    do {
755
0
        uint16_t *curr = s->c, *peer;
756
757
0
        do {
758
0
            uint16_t *pause = curr + offset, even, odd;
759
0
            uint32_t zeta = *++roots;
760
761
0
            peer = pause;
762
0
            do {
763
0
                even = *curr;
764
0
                odd = reduce(*peer * zeta);
765
0
                *peer++ = reduce_once(even - odd + kPrime);
766
0
                *curr++ = reduce_once(odd + even);
767
0
            } while (curr < pause);
768
0
        } while ((curr = peer) < end);
769
0
    } while ((offset >>= 1) >= 2);
770
0
}
771
772
/*-
773
 * FIPS 203, Section 4.3, Algorithm 10: "NTT^(-1)".
774
 * In-place inverse number theoretic transform of a given scalar, with pairs of
775
 * entries of s->v being interpreted as elements of GF(3329^2). Just as with
776
 * the number theoretic transform, this leaves off the first step of the normal
777
 * iFFT to account for the fact that 3329 does not have a 512th root of unity,
778
 * using the precomputed 128 roots of unity stored in InverseNTTRoots.
779
 */
780
void ossl_ml_kem_scalar_inverse_ntt_generic(scalar *s)
781
0
{
782
0
    const uint16_t *roots = kInverseNTTRoots;
783
0
    uint16_t *end = s->c + DEGREE;
784
0
    int offset = 2;
785
786
0
    do {
787
0
        uint16_t *curr = s->c, *peer;
788
789
0
        do {
790
0
            uint16_t *pause = curr + offset, even, odd;
791
0
            uint32_t zeta = *++roots;
792
793
0
            peer = pause;
794
0
            do {
795
0
                even = *curr;
796
0
                odd = *peer;
797
0
                *peer++ = reduce(zeta * (even - odd + kPrime));
798
0
                *curr++ = reduce_once(odd + even);
799
0
            } while (curr < pause);
800
0
        } while ((curr = peer) < end);
801
0
    } while ((offset <<= 1) < DEGREE);
802
0
    scalar_mult_const(s, kInverseDegree);
803
0
}
804
805
/* Addition updating the LHS scalar in-place. */
806
static void scalar_add(scalar *lhs, const scalar *rhs)
807
0
{
808
0
    int i;
809
810
0
    for (i = 0; i < DEGREE; i++)
811
0
        lhs->c[i] = reduce_once(lhs->c[i] + rhs->c[i]);
812
0
}
813
814
/* Subtraction updating the LHS scalar in-place. */
815
static void scalar_sub(scalar *lhs, const scalar *rhs)
816
0
{
817
0
    int i;
818
819
0
    for (i = 0; i < DEGREE; i++)
820
0
        lhs->c[i] = reduce_once(lhs->c[i] - rhs->c[i] + kPrime);
821
0
}
822
823
/*
824
 * Multiplying two scalars in the number theoretically transformed state. Since
825
 * 3329 does not have a 512th root of unity, this means we have to interpret
826
 * the 2*ith and (2*i+1)th entries of the scalar as elements of
827
 * GF(3329)[X]/(X^2 - 17^(2*bitreverse(i)+1)).
828
 *
829
 * The value of 17^(2*bitreverse(i)+1) mod 3329 is stored in the precomputed
830
 * ModRoots table. Note that our Barrett transform only allows us to multiply
831
 * two reduced numbers together, so we need some intermediate reduction steps,
832
 * even if an uint64_t could hold 3 multiplied numbers.
833
 */
834
835
static void scalar_mult_generic(scalar *out, const scalar *lhs,
836
    const scalar *rhs)
837
0
{
838
0
    uint16_t *curr = out->c, *end = curr + DEGREE;
839
0
    const uint16_t *lc = lhs->c, *rc = rhs->c;
840
0
    const uint16_t *roots = kModRoots;
841
842
0
    do {
843
0
        uint32_t l0 = *lc++, r0 = *rc++;
844
0
        uint32_t l1 = *lc++, r1 = *rc++;
845
0
        uint32_t zetapow = *roots++;
846
847
0
        *curr++ = reduce(l0 * r0 + reduce(l1 * r1) * zetapow);
848
0
        *curr++ = reduce(l0 * r1 + l1 * r0);
849
0
    } while (curr < end);
850
0
}
851
852
/* Above, but add the result to an existing scalar */
853
static ossl_inline void scalar_mult_add_generic(scalar *out, const scalar *lhs,
854
    const scalar *rhs)
855
0
{
856
0
    uint16_t *curr = out->c, *end = curr + DEGREE;
857
0
    const uint16_t *lc = lhs->c, *rc = rhs->c;
858
0
    const uint16_t *roots = kModRoots;
859
860
0
    do {
861
0
        uint32_t l0 = *lc++, r0 = *rc++;
862
0
        uint32_t l1 = *lc++, r1 = *rc++;
863
0
        uint16_t *c0 = curr++;
864
0
        uint16_t *c1 = curr++;
865
0
        uint32_t zetapow = *roots++;
866
867
0
        *c0 = reduce(*c0 + l0 * r0 + reduce(l1 * r1) * zetapow);
868
0
        *c1 = reduce(*c1 + l0 * r1 + l1 * r0);
869
0
    } while (curr < end);
870
0
}
871
872
/*-
873
 * FIPS 203, Section 4.2.1, Algorithm 5: "ByteEncode_d", for 2<=d<=12.
874
 * Here |bits| is |d|.  For efficiency, we handle the d=1 case separately.
875
 */
876
static void scalar_encode(uint8_t *out, const scalar *s, int bits)
877
0
{
878
0
    const uint16_t *curr = s->c, *end = curr + DEGREE;
879
0
    uint64_t accum = 0, element;
880
0
    int used = 0;
881
882
0
    do {
883
0
        element = *curr++;
884
0
        if (used + bits < 64) {
885
0
            accum |= element << used;
886
0
            used += bits;
887
0
        } else if (used + bits > 64) {
888
0
            out = OPENSSL_store_u64_le(out, accum | (element << used));
889
0
            accum = element >> (64 - used);
890
0
            used = (used + bits) - 64;
891
0
        } else {
892
0
            out = OPENSSL_store_u64_le(out, accum | (element << used));
893
0
            accum = 0;
894
0
            used = 0;
895
0
        }
896
0
    } while (curr < end);
897
0
}
898
899
/*
900
 * scalar_encode_1 is |scalar_encode| specialised for |bits| == 1.
901
 */
902
static void scalar_encode_1(uint8_t out[DEGREE / 8], const scalar *s)
903
0
{
904
0
    int i, j;
905
0
    uint8_t out_byte;
906
907
0
    for (i = 0; i < DEGREE; i += 8) {
908
0
        out_byte = 0;
909
0
        for (j = 0; j < 8; j++)
910
0
            out_byte |= bit0(s->c[i + j]) << j;
911
0
        *out = out_byte;
912
0
        out++;
913
0
    }
914
0
}
915
916
/*-
917
 * FIPS 203, Section 4.2.1, Algorithm 6: "ByteDecode_d", for 2<=d<12.
918
 * Here |bits| is |d|.  For efficiency, we handle the d=1 and d=12 cases
919
 * separately.
920
 *
921
 * scalar_decode parses |DEGREE * bits| bits from |in| into |DEGREE| values in
922
 * |out|.
923
 */
924
static void scalar_decode(scalar *out, const uint8_t *in, int bits)
925
0
{
926
0
    uint16_t *curr = out->c, *end = curr + DEGREE;
927
0
    uint64_t accum = 0;
928
0
    int accum_bits = 0, todo = bits;
929
0
    uint16_t bitmask = (((uint16_t)1) << bits) - 1, mask = bitmask;
930
0
    uint16_t element = 0;
931
932
0
    do {
933
0
        if (accum_bits == 0) {
934
0
            in = OPENSSL_load_u64_le(&accum, in);
935
0
            accum_bits = 64;
936
0
        }
937
0
        if (todo == bits && accum_bits >= bits) {
938
            /* No partial "element", and all the required bits available */
939
0
            *curr++ = ((uint16_t)accum) & mask;
940
0
            accum >>= bits;
941
0
            accum_bits -= bits;
942
0
        } else if (accum_bits >= todo) {
943
            /* A partial "element", and all the required bits available */
944
0
            *curr++ = element | ((((uint16_t)accum) & mask) << (bits - todo));
945
0
            accum >>= todo;
946
0
            accum_bits -= todo;
947
0
            element = 0;
948
0
            todo = bits;
949
0
            mask = bitmask;
950
0
        } else {
951
            /*
952
             * Only some of the requisite bits accumulated, store |accum_bits|
953
             * of these in |element|.  The accumulated bitcount becomes 0, but
954
             * as soon as we have more bits we'll want to merge accum_bits
955
             * fewer of them into the final |element|.
956
             *
957
             * Note that with a 64-bit accumulator and |bits| always 12 or
958
             * less, if we're here, the previous iteration had all the
959
             * requisite bits, and so there are no kept bits in |element|.
960
             */
961
0
            element = ((uint16_t)accum) & mask;
962
0
            todo -= accum_bits;
963
0
            mask = bitmask >> accum_bits;
964
0
            accum_bits = 0;
965
0
        }
966
0
    } while (curr < end);
967
0
}
968
969
static __owur int scalar_decode_12(scalar *out, const uint8_t in[3 * DEGREE / 2])
970
0
{
971
0
    int i;
972
0
    uint16_t *c = out->c;
973
974
0
    for (i = 0; i < DEGREE / 2; ++i) {
975
0
        uint8_t b1 = *in++;
976
0
        uint8_t b2 = *in++;
977
0
        uint8_t b3 = *in++;
978
0
        int outOfRange1 = (*c++ = b1 | ((b2 & 0x0f) << 8)) >= kPrime;
979
0
        int outOfRange2 = (*c++ = (b2 >> 4) | (b3 << 4)) >= kPrime;
980
981
0
        if (outOfRange1 | outOfRange2)
982
0
            return 0;
983
0
    }
984
0
    return 1;
985
0
}
986
987
/*-
988
 * scalar_decode_decompress_add is a combination of decoding and decompression
989
 * both specialised for |bits| == 1, with the result added (and sum reduced) to
990
 * the output scalar.
991
 *
992
 * NOTE: this function MUST not leak an input-data-depedennt timing signal.
993
 * A timing leak in a related function in the reference Kyber implementation
994
 * made the "clangover" attack (CVE-2024-37880) possible, giving key recovery
995
 * for ML-KEM-512 in minutes, provided the attacker has access to precise
996
 * timing of a CPU performing chosen-ciphertext decap.  Admittedly this is only
997
 * a risk when private keys are reused (perhaps KEMTLS servers).
998
 */
999
static void
1000
scalar_decode_decompress_add(scalar *out, const uint8_t in[DEGREE / 8])
1001
0
{
1002
0
    static const uint16_t half_q_plus_1 = (ML_KEM_PRIME >> 1) + 1;
1003
0
    uint16_t *curr = out->c, *end = curr + DEGREE;
1004
0
    uint16_t mask;
1005
0
    uint8_t b;
1006
1007
    /*
1008
     * Add |half_q_plus_1| if the bit is set, without exposing a side-channel,
1009
     * avoiding the "clangover" attack.  See |constish_time_true| for a
1010
     * discussion on why the value barrier is by default omitted.
1011
     */
1012
0
#define decode_decompress_add_bit                        \
1013
0
    mask = constish_time_true(bit0(b));                  \
1014
0
    *curr = reduce_once(*curr + (mask & half_q_plus_1)); \
1015
0
    curr++;                                              \
1016
0
    b >>= 1
1017
1018
    /* Unrolled to process each byte in one iteration */
1019
0
    do {
1020
0
        b = *in++;
1021
0
        decode_decompress_add_bit;
1022
0
        decode_decompress_add_bit;
1023
0
        decode_decompress_add_bit;
1024
0
        decode_decompress_add_bit;
1025
1026
0
        decode_decompress_add_bit;
1027
0
        decode_decompress_add_bit;
1028
0
        decode_decompress_add_bit;
1029
0
        decode_decompress_add_bit;
1030
0
    } while (curr < end);
1031
0
#undef decode_decompress_add_bit
1032
0
}
1033
1034
/*
1035
 * FIPS 203, Section 4.2.1, Equation (4.7): Compress_d.
1036
 *
1037
 * Compresses (lossily) an input |x| mod 3329 into |bits| many bits by grouping
1038
 * numbers close to each other together. The formula used is
1039
 * round(2^|bits|/kPrime*x) mod 2^|bits|.
1040
 * Uses Barrett reduction to achieve constant time. Since we need both the
1041
 * remainder (for rounding) and the quotient (as the result), we cannot use
1042
 * |reduce| here, but need to do the Barrett reduction directly.
1043
 */
1044
static __owur uint16_t compress(uint16_t x, int bits)
1045
0
{
1046
0
    uint32_t shifted = (uint32_t)x << bits;
1047
0
    uint64_t product = (uint64_t)shifted * kBarrettMultiplier;
1048
0
    uint32_t quotient = (uint32_t)(product >> kBarrettShift);
1049
0
    uint32_t remainder = shifted - quotient * kPrime;
1050
1051
    /*
1052
     * Adjust the quotient to round correctly:
1053
     *   0 <= remainder <= kHalfPrime round to 0
1054
     *   kHalfPrime < remainder <= kPrime + kHalfPrime round to 1
1055
     *   kPrime + kHalfPrime < remainder < 2 * kPrime round to 2
1056
     */
1057
0
    quotient += 1 & constant_time_lt_32(kHalfPrime, remainder);
1058
0
    quotient += 1 & constant_time_lt_32(kPrime + kHalfPrime, remainder);
1059
0
    return quotient & ((1 << bits) - 1);
1060
0
}
1061
1062
/*
1063
 * FIPS 203, Section 4.2.1, Equation (4.8): Decompress_d.
1064
1065
 * Decompresses |x| by using a close equi-distant representative. The formula
1066
 * is round(kPrime/2^|bits|*x). Note that 2^|bits| being the divisor allows us
1067
 * to implement this logic using only bit operations.
1068
 */
1069
static __owur uint16_t decompress(uint16_t x, int bits)
1070
0
{
1071
0
    uint32_t product = (uint32_t)x * kPrime;
1072
0
    uint32_t power = 1 << bits;
1073
    /* This is |product| % power, since |power| is a power of 2. */
1074
0
    uint32_t remainder = product & (power - 1);
1075
    /* This is |product| / power, since |power| is a power of 2. */
1076
0
    uint32_t lower = product >> bits;
1077
1078
    /*
1079
     * The rounding logic works since the first half of numbers mod |power|
1080
     * have a 0 as first bit, and the second half has a 1 as first bit, since
1081
     * |power| is a power of 2. As a 12 bit number, |remainder| is always
1082
     * positive, so we will shift in 0s for a right shift.
1083
     */
1084
0
    return lower + (remainder >> (bits - 1));
1085
0
}
1086
1087
/*-
1088
 * FIPS 203, Section 4.2.1, Equation (4.7): "Compress_d".
1089
 * In-place lossy rounding of scalars to 2^d bits.
1090
 */
1091
static void scalar_compress(scalar *s, int bits)
1092
0
{
1093
0
    int i;
1094
1095
0
    for (i = 0; i < DEGREE; i++)
1096
0
        s->c[i] = compress(s->c[i], bits);
1097
0
}
1098
1099
/*
1100
 * FIPS 203, Section 4.2.1, Equation (4.8): "Decompress_d".
1101
 * In-place approximate recovery of scalars from 2^d bit compression.
1102
 */
1103
static void scalar_decompress(scalar *s, int bits)
1104
0
{
1105
0
    int i;
1106
1107
0
    for (i = 0; i < DEGREE; i++)
1108
0
        s->c[i] = decompress(s->c[i], bits);
1109
0
}
1110
1111
/* Addition updating the LHS vector in-place. */
1112
static void vector_add(scalar *lhs, const scalar *rhs, int rank)
1113
0
{
1114
0
    do {
1115
0
        scalar_add(lhs++, rhs++);
1116
0
    } while (--rank > 0);
1117
0
}
1118
1119
/*
1120
 * Encodes an entire vector into 32*|rank|*|bits| bytes. Note that since 256
1121
 * (DEGREE) is divisible by 8, the individual vector entries will always fill a
1122
 * whole number of bytes, so we do not need to worry about bit packing here.
1123
 */
1124
static void vector_encode(uint8_t *out, const scalar *a, int bits, int rank)
1125
0
{
1126
0
    int stride = bits * DEGREE / 8;
1127
1128
0
    for (; rank-- > 0; out += stride)
1129
0
        scalar_encode(out, a++, bits);
1130
0
}
1131
1132
/*
1133
 * Decodes 32*|rank|*|bits| bytes from |in| into |out|. It returns early
1134
 * if any parsed value is >= |ML_KEM_PRIME|.  The resulting scalars are
1135
 * then decompressed and transformed via the NTT.
1136
 *
1137
 * Note: Used only in decrypt_cpa(), which returns void and so does not check
1138
 * the return value of this function.  Side-channels are fine when the input
1139
 * ciphertext to decap() is simply syntactically invalid.
1140
 */
1141
static void
1142
vector_decode_decompress_ntt(scalar *out, const uint8_t *in, int bits, int rank)
1143
0
{
1144
0
    int stride = bits * DEGREE / 8;
1145
1146
0
    for (; rank-- > 0; in += stride, ++out) {
1147
0
        scalar_decode(out, in, bits);
1148
0
        scalar_decompress(out, bits);
1149
0
        scalar_ntt(out);
1150
0
    }
1151
0
}
1152
1153
/* vector_decode(), specialised to bits == 12. */
1154
static __owur int vector_decode_12(scalar *out, const uint8_t in[3 * DEGREE / 2], int rank)
1155
0
{
1156
0
    int stride = 3 * DEGREE / 2;
1157
1158
0
    for (; rank-- > 0; in += stride)
1159
0
        if (!scalar_decode_12(out++, in))
1160
0
            return 0;
1161
0
    return 1;
1162
0
}
1163
1164
/* In-place compression of each scalar component */
1165
static void vector_compress(scalar *a, int bits, int rank)
1166
0
{
1167
0
    do {
1168
0
        scalar_compress(a++, bits);
1169
0
    } while (--rank > 0);
1170
0
}
1171
1172
/* The output scalar must not overlap with the inputs */
1173
static void inner_product_generic(scalar *out, const scalar *lhs, const scalar *rhs,
1174
    int rank)
1175
0
{
1176
0
    scalar_mult_generic(out, lhs, rhs);
1177
0
    while (--rank > 0)
1178
0
        scalar_mult_add_generic(out, ++lhs, ++rhs);
1179
0
}
1180
1181
/*
1182
 * Here, the output vector must not overlap with the inputs, the result is
1183
 * directly subjected to inverse NTT.
1184
 */
1185
static void matrix_mult_intt_generic(scalar *out, const scalar *m, const scalar *a, int rank)
1186
0
{
1187
0
    const scalar *ar;
1188
0
    int i, j;
1189
1190
0
    for (i = rank; i-- > 0; ++out) {
1191
0
        scalar_mult_generic(out, m++, ar = a);
1192
0
        for (j = rank - 1; j > 0; --j)
1193
0
            scalar_mult_add_generic(out, m++, ++ar);
1194
0
        scalar_inverse_ntt(out);
1195
0
    }
1196
0
}
1197
1198
/* Here, the output vector must not overlap with the inputs */
1199
static void
1200
matrix_mult_transpose_add_generic(scalar *out, const scalar *m, const scalar *a, int rank)
1201
0
{
1202
0
    const scalar *mc = m, *mr, *ar;
1203
0
    int i, j;
1204
1205
0
    for (i = rank; i-- > 0; ++out) {
1206
0
        scalar_mult_add(out, mr = mc++, ar = a);
1207
0
        for (j = rank; --j > 0;)
1208
0
            scalar_mult_add(out, (mr += rank), ++ar);
1209
0
    }
1210
0
}
1211
1212
/*-
1213
 * Expands the matrix from a seed for key generation and for encaps-CPA.
1214
 * NOTE: FIPS 203 matrix "A" is the transpose of this matrix, computed
1215
 * by appending the (i,j) indices to the seed in the opposite order!
1216
 *
1217
 * Where FIPS 203 computes t = A * s + e, we use the transpose of "m".
1218
 */
1219
static __owur int matrix_expand(EVP_MD_CTX *mdctx, ML_KEM_KEY *key)
1220
0
{
1221
0
    scalar *out = key->m;
1222
0
    uint8_t input[ML_KEM_RANDOM_BYTES + 2];
1223
0
    int rank = key->vinfo->rank;
1224
0
    int i, j;
1225
1226
    /*
1227
     * The seeds derived below and the sampling buffers in sample_scalar()
1228
     * are not cleansed: per FIPS 203 section 3.3 the matrix A is easily
1229
     * computed from the public encapsulation key and does not require any
1230
     * special protections.
1231
     */
1232
0
    memcpy(input, key->rho, ML_KEM_RANDOM_BYTES);
1233
0
    for (i = 0; i < rank; i++) {
1234
0
        for (j = 0; j < rank; j++) {
1235
0
            input[ML_KEM_RANDOM_BYTES] = i;
1236
0
            input[ML_KEM_RANDOM_BYTES + 1] = j;
1237
0
            if (!EVP_DigestInit_ex(mdctx, key->shake128_md, NULL)
1238
0
                || !EVP_DigestUpdate(mdctx, input, sizeof(input))
1239
0
                || !sample_scalar(out++, mdctx))
1240
0
                return 0;
1241
0
        }
1242
0
    }
1243
0
    return 1;
1244
0
}
1245
1246
/*
1247
 * Algorithm 7 from the spec, with eta fixed to two and the PRF call
1248
 * included. Creates binominally distributed elements by sampling 2*|eta| bits,
1249
 * and setting the coefficient to the count of the first bits minus the count of
1250
 * the second bits, resulting in a centered binomial distribution. Since eta is
1251
 * two this gives -2/2 with a probability of 1/16, -1/1 with probability 1/4,
1252
 * and 0 with probability 3/8.
1253
 */
1254
static __owur int cbd_2(scalar *out, uint8_t in[ML_KEM_RANDOM_BYTES + 1],
1255
    EVP_MD_CTX *mdctx, const ML_KEM_KEY *key)
1256
0
{
1257
0
    uint16_t *curr = out->c, *end = curr + DEGREE;
1258
0
    uint8_t randbuf[4 * DEGREE / 8], *r = randbuf; /* 64 * eta slots */
1259
0
    uint16_t value, mask;
1260
0
    uint8_t b;
1261
1262
0
    if (!prf(randbuf, sizeof(randbuf), in, mdctx, key)) {
1263
0
        OPENSSL_cleanse((void *)randbuf, sizeof(randbuf));
1264
0
        return 0;
1265
0
    }
1266
1267
0
    do {
1268
0
        b = *r++;
1269
1270
        /*
1271
         * Add |kPrime| if |value| underflowed.  See |constish_time_true| for
1272
         * a discussion on why the value barrier is by default omitted.  While
1273
         * this could have been written reduce_once(value + kPrime), this is
1274
         * one extra addition and small range of |value| tempts some versions
1275
         * of Clang to emit a branch.
1276
         */
1277
0
        value = bit0(b) + bitn(1, b);
1278
0
        value -= bitn(2, b) + bitn(3, b);
1279
0
        mask = constish_time_true(value >> 15);
1280
0
        *curr++ = value + (kPrime & mask);
1281
1282
0
        value = bitn(4, b) + bitn(5, b);
1283
0
        value -= bitn(6, b) + bitn(7, b);
1284
0
        mask = constish_time_true(value >> 15);
1285
0
        *curr++ = value + (kPrime & mask);
1286
0
    } while (curr < end);
1287
1288
0
    OPENSSL_cleanse((void *)randbuf, sizeof(randbuf));
1289
0
    return 1;
1290
0
}
1291
1292
/*
1293
 * Algorithm 7 from the spec, with eta fixed to three and the PRF call
1294
 * included. Creates binominally distributed elements by sampling 3*|eta| bits,
1295
 * and setting the coefficient to the count of the first bits minus the count of
1296
 * the second bits, resulting in a centered binomial distribution.
1297
 */
1298
static __owur int cbd_3(scalar *out, uint8_t in[ML_KEM_RANDOM_BYTES + 1],
1299
    EVP_MD_CTX *mdctx, const ML_KEM_KEY *key)
1300
0
{
1301
0
    uint16_t *curr = out->c, *end = curr + DEGREE;
1302
0
    uint8_t randbuf[6 * DEGREE / 8], *r = randbuf; /* 64 * eta slots */
1303
0
    uint8_t b1, b2, b3;
1304
0
    uint16_t value, mask;
1305
1306
0
    if (!prf(randbuf, sizeof(randbuf), in, mdctx, key)) {
1307
0
        OPENSSL_cleanse((void *)randbuf, sizeof(randbuf));
1308
0
        return 0;
1309
0
    }
1310
1311
0
    do {
1312
0
        b1 = *r++;
1313
0
        b2 = *r++;
1314
0
        b3 = *r++;
1315
1316
        /*
1317
         * Add |kPrime| if |value| underflowed.  See |constish_time_true|
1318
         * for a discussion on why the value barrier is by default omitted.
1319
         * While this could have been written reduce_once(value + kPrime), this
1320
         * is one extra addition and small range of |value| tempts some
1321
         * versions of Clang to emit a branch.
1322
         */
1323
0
        value = bit0(b1) + bitn(1, b1) + bitn(2, b1);
1324
0
        value -= bitn(3, b1) + bitn(4, b1) + bitn(5, b1);
1325
0
        mask = constish_time_true(value >> 15);
1326
0
        *curr++ = value + (kPrime & mask);
1327
1328
0
        value = bitn(6, b1) + bitn(7, b1) + bit0(b2);
1329
0
        value -= bitn(1, b2) + bitn(2, b2) + bitn(3, b2);
1330
0
        mask = constish_time_true(value >> 15);
1331
0
        *curr++ = value + (kPrime & mask);
1332
1333
0
        value = bitn(4, b2) + bitn(5, b2) + bitn(6, b2);
1334
0
        value -= bitn(7, b2) + bit0(b3) + bitn(1, b3);
1335
0
        mask = constish_time_true(value >> 15);
1336
0
        *curr++ = value + (kPrime & mask);
1337
1338
0
        value = bitn(2, b3) + bitn(3, b3) + bitn(4, b3);
1339
0
        value -= bitn(5, b3) + bitn(6, b3) + bitn(7, b3);
1340
0
        mask = constish_time_true(value >> 15);
1341
0
        *curr++ = value + (kPrime & mask);
1342
0
    } while (curr < end);
1343
1344
0
    OPENSSL_cleanse((void *)randbuf, sizeof(randbuf));
1345
0
    return 1;
1346
0
}
1347
1348
/*
1349
 * Generates a secret vector by using |cbd| with the given seed to generate
1350
 * scalar elements and incrementing |counter| for each slot of the vector.
1351
 */
1352
static __owur int gencbd_vector(scalar *out, CBD_FUNC cbd, uint8_t *counter,
1353
    const uint8_t seed[ML_KEM_RANDOM_BYTES], int rank,
1354
    EVP_MD_CTX *mdctx, const ML_KEM_KEY *key)
1355
0
{
1356
0
    uint8_t input[ML_KEM_RANDOM_BYTES + 1];
1357
0
    int ret = 0;
1358
1359
0
    memcpy(input, seed, ML_KEM_RANDOM_BYTES);
1360
0
    do {
1361
0
        input[ML_KEM_RANDOM_BYTES] = (*counter)++;
1362
0
        if (!cbd(out++, input, mdctx, key))
1363
0
            goto end;
1364
0
    } while (--rank > 0);
1365
0
    ret = 1;
1366
1367
0
end:
1368
0
    OPENSSL_cleanse((void *)input, sizeof(input));
1369
0
    return ret;
1370
0
}
1371
1372
/*
1373
 * As above plus NTT transform.
1374
 */
1375
static __owur int gencbd_vector_ntt(scalar *out, CBD_FUNC cbd, uint8_t *counter,
1376
    const uint8_t seed[ML_KEM_RANDOM_BYTES], int rank,
1377
    EVP_MD_CTX *mdctx, const ML_KEM_KEY *key)
1378
0
{
1379
0
    uint8_t input[ML_KEM_RANDOM_BYTES + 1];
1380
0
    int ret = 0;
1381
1382
0
    memcpy(input, seed, ML_KEM_RANDOM_BYTES);
1383
0
    do {
1384
0
        input[ML_KEM_RANDOM_BYTES] = (*counter)++;
1385
0
        if (!cbd(out, input, mdctx, key))
1386
0
            goto end;
1387
0
        scalar_ntt(out++);
1388
0
    } while (--rank > 0);
1389
0
    ret = 1;
1390
1391
0
end:
1392
0
    OPENSSL_cleanse((void *)input, sizeof(input));
1393
0
    return ret;
1394
0
}
1395
1396
/* The |ETA1| value for ML-KEM-512 is 3, the rest and all ETA2 values are 2. */
1397
0
#define CBD1(evp_type) ((evp_type) == EVP_PKEY_ML_KEM_512 ? cbd_3 : cbd_2)
1398
1399
/*
1400
 * FIPS 203, Section 5.2, Algorithm 14: K-PKE.Encrypt.
1401
 *
1402
 * Encrypts a message with given randomness to the ciphertext in |out|. Without
1403
 * applying the Fujisaki-Okamoto transform this would not result in a CCA
1404
 * secure scheme, since lattice schemes are vulnerable to decryption failure
1405
 * oracles.
1406
 *
1407
 * The steps are re-ordered to make more efficient/localised use of storage.
1408
 *
1409
 * Note also that the input public key is assumed to hold a precomputed matrix
1410
 * |A| (our key->m, with the public key holding an expanded (16-bit per scalar
1411
 * coefficient) key->t vector).
1412
 *
1413
 * Caller passes storage in |tmp| for two temporary vectors.
1414
 */
1415
static __owur int encrypt_cpa(uint8_t out[ML_KEM_SHARED_SECRET_BYTES],
1416
    const uint8_t message[DEGREE / 8],
1417
    const uint8_t r[ML_KEM_RANDOM_BYTES], scalar *tmp,
1418
    EVP_MD_CTX *mdctx, const ML_KEM_KEY *key)
1419
0
{
1420
0
    const ML_KEM_VINFO *vinfo = key->vinfo;
1421
0
    CBD_FUNC cbd_1 = CBD1(vinfo->evp_type);
1422
0
    int rank = vinfo->rank;
1423
    /* We can use tmp[0..rank-1] as storage for |y|, then |e1|, ... */
1424
0
    scalar *y = &tmp[0], *e1 = y, *e2 = y;
1425
    /* We can use tmp[rank]..tmp[2*rank - 1] for |u| */
1426
0
    scalar *u = &tmp[rank];
1427
0
    scalar v;
1428
0
    uint8_t input[ML_KEM_RANDOM_BYTES + 1];
1429
0
    uint8_t counter = 0;
1430
0
    int du = vinfo->du;
1431
0
    int dv = vinfo->dv;
1432
0
    int ret = 0;
1433
1434
    /* FIPS 203 "y" vector */
1435
0
    if (!gencbd_vector_ntt(y, cbd_1, &counter, r, rank, mdctx, key))
1436
0
        goto end;
1437
    /* FIPS 203 "v" scalar */
1438
0
    inner_product_montgomery(&v, key->t, y, rank);
1439
0
    scalar_inverse_ntt_demontgomerize(&v);
1440
    /* FIPS 203 "u" vector */
1441
0
    matrix_mult_intt(u, key->m, y, rank);
1442
1443
    /* All done with |y|, now free to reuse tmp[0] for FIPS 203 |e1| */
1444
0
    if (!gencbd_vector(e1, cbd_2, &counter, r, rank, mdctx, key))
1445
0
        goto end;
1446
0
    vector_add(u, e1, rank);
1447
0
    vector_compress(u, du, rank);
1448
0
    vector_encode(out, u, du, rank);
1449
1450
    /* All done with |e1|, now free to reuse tmp[0] for FIPS 203 |e2| */
1451
0
    memcpy(input, r, ML_KEM_RANDOM_BYTES);
1452
0
    input[ML_KEM_RANDOM_BYTES] = counter;
1453
0
    if (!cbd_2(e2, input, mdctx, key))
1454
0
        goto end;
1455
0
    scalar_add(&v, e2);
1456
1457
    /* Combine message with |v| */
1458
0
    scalar_decode_decompress_add(&v, message);
1459
0
    scalar_compress(&v, dv);
1460
0
    scalar_encode(out + vinfo->u_vector_bytes, &v, dv);
1461
0
    ret = 1;
1462
1463
0
end:
1464
0
    OPENSSL_cleanse((void *)input, sizeof(input));
1465
0
    OPENSSL_cleanse((void *)&v, sizeof(v));
1466
0
    return ret;
1467
0
}
1468
1469
/*
1470
 * FIPS 203, Section 5.3, Algorithm 15: K-PKE.Decrypt.
1471
 */
1472
static void
1473
decrypt_cpa(uint8_t out[ML_KEM_SHARED_SECRET_BYTES],
1474
    const uint8_t *ctext, scalar *u, const ML_KEM_KEY *key)
1475
0
{
1476
0
    const ML_KEM_VINFO *vinfo = key->vinfo;
1477
0
    scalar v, mask;
1478
0
    int rank = vinfo->rank;
1479
0
    int du = vinfo->du;
1480
0
    int dv = vinfo->dv;
1481
1482
0
    vector_decode_decompress_ntt(u, ctext, du, rank);
1483
0
    scalar_decode(&v, ctext + vinfo->u_vector_bytes, dv);
1484
0
    scalar_decompress(&v, dv);
1485
0
    inner_product_montgomery(&mask, key->s, u, rank);
1486
0
    scalar_inverse_ntt_demontgomerize(&mask);
1487
0
    scalar_sub(&v, &mask);
1488
0
    scalar_compress(&v, 1);
1489
0
    scalar_encode_1(out, &v);
1490
1491
0
    OPENSSL_cleanse((void *)&v, sizeof(v));
1492
0
    OPENSSL_cleanse((void *)&mask, sizeof(mask));
1493
0
}
1494
1495
/*-
1496
 * FIPS 203, Section 7.1, Algorithm 19: "ML-KEM.KeyGen".
1497
 * FIPS 203, Section 7.2, Algorithm 20: "ML-KEM.Encaps".
1498
 *
1499
 * Fills the |out| buffer with the |ek| output of "ML-KEM.KeyGen", or,
1500
 * equivalently, the |ek| input of "ML-KEM.Encaps", i.e. returns the
1501
 * wire-format of an ML-KEM public key.
1502
 */
1503
static void encode_pubkey(uint8_t *out, const ML_KEM_KEY *key)
1504
0
{
1505
0
    const uint8_t *rho = key->rho;
1506
0
    const ML_KEM_VINFO *vinfo = key->vinfo;
1507
1508
0
    vector_encode(out, key->t, 12, vinfo->rank);
1509
0
    memcpy(out + vinfo->vector_bytes, rho, ML_KEM_RANDOM_BYTES);
1510
0
}
1511
1512
/*-
1513
 * FIPS 203, Section 7.1, Algorithm 19: "ML-KEM.KeyGen".
1514
 *
1515
 * Fills the |out| buffer with the |dk| output of "ML-KEM.KeyGen".
1516
 * This matches the input format of parse_prvkey() below.
1517
 */
1518
static void encode_prvkey(uint8_t *out, const ML_KEM_KEY *key)
1519
0
{
1520
0
    const ML_KEM_VINFO *vinfo = key->vinfo;
1521
1522
0
    vector_encode(out, key->s, 12, vinfo->rank);
1523
0
    out += vinfo->vector_bytes;
1524
0
    encode_pubkey(out, key);
1525
0
    out += vinfo->pubkey_bytes;
1526
0
    memcpy(out, key->pkhash, ML_KEM_PKHASH_BYTES);
1527
0
    out += ML_KEM_PKHASH_BYTES;
1528
0
    memcpy(out, key->z, ML_KEM_RANDOM_BYTES);
1529
0
}
1530
1531
/*-
1532
 * FIPS 203, Section 7.1, Algorithm 19: "ML-KEM.KeyGen".
1533
 * FIPS 203, Section 7.2, Algorithm 20: "ML-KEM.Encaps".
1534
 *
1535
 * This function parses the |in| buffer as the |ek| output of "ML-KEM.KeyGen",
1536
 * or, equivalently, the |ek| input of "ML-KEM.Encaps", i.e. decodes the
1537
 * wire-format of the ML-KEM public key.
1538
 */
1539
static int parse_pubkey(const uint8_t *in, EVP_MD_CTX *mdctx, ML_KEM_KEY *key)
1540
0
{
1541
0
    const ML_KEM_VINFO *vinfo = key->vinfo;
1542
1543
    /* Decode and check |t| */
1544
0
    if (!vector_decode_12(key->t, in, vinfo->rank)) {
1545
0
        ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY,
1546
0
            "%s invalid public 't' vector",
1547
0
            vinfo->algorithm_name);
1548
0
        return 0;
1549
0
    }
1550
    /* Save the matrix |m| recovery seed |rho| */
1551
0
    memcpy(key->rho, in + vinfo->vector_bytes, ML_KEM_RANDOM_BYTES);
1552
    /*
1553
     * Pre-compute the public key hash, needed for both encap and decap.
1554
     * Also pre-compute the matrix expansion, stored with the public key.
1555
     */
1556
0
    if (!hash_h(key->pkhash, in, vinfo->pubkey_bytes, mdctx, key)
1557
0
        || !matrix_expand(mdctx, key)) {
1558
0
        ERR_raise_data(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR,
1559
0
            "internal error while parsing %s public key",
1560
0
            vinfo->algorithm_name);
1561
0
        return 0;
1562
0
    }
1563
0
    return 1;
1564
0
}
1565
1566
/*
1567
 * FIPS 203, Section 7.1, Algorithm 19: "ML-KEM.KeyGen".
1568
 *
1569
 * Parses the |in| buffer as a |dk| output of "ML-KEM.KeyGen".
1570
 * This matches the output format of encode_prvkey() above.
1571
 */
1572
static int parse_prvkey(const uint8_t *in, EVP_MD_CTX *mdctx, ML_KEM_KEY *key)
1573
0
{
1574
0
    const ML_KEM_VINFO *vinfo = key->vinfo;
1575
1576
    /* Decode and check |s|. */
1577
0
    if (!vector_decode_12(key->s, in, vinfo->rank)) {
1578
0
        ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY,
1579
0
            "%s invalid private 's' vector",
1580
0
            vinfo->algorithm_name);
1581
0
        return 0;
1582
0
    }
1583
0
    in += vinfo->vector_bytes;
1584
1585
0
    if (!parse_pubkey(in, mdctx, key))
1586
0
        return 0;
1587
0
    in += vinfo->pubkey_bytes;
1588
1589
    /* Check public key hash. */
1590
0
    if (memcmp(key->pkhash, in, ML_KEM_PKHASH_BYTES) != 0) {
1591
0
        ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY,
1592
0
            "%s public key hash mismatch",
1593
0
            vinfo->algorithm_name);
1594
0
        return 0;
1595
0
    }
1596
0
    in += ML_KEM_PKHASH_BYTES;
1597
1598
0
    memcpy(key->z, in, ML_KEM_RANDOM_BYTES);
1599
0
    return 1;
1600
0
}
1601
1602
/*
1603
 * FIPS 203, Section 6.1, Algorithm 16: "ML-KEM.KeyGen_internal".
1604
 *
1605
 * The implementation of Section 5.1, Algorithm 13, "K-PKE.KeyGen(d)" is
1606
 * inlined.
1607
 *
1608
 * The caller MUST pass a pre-allocated digest context that is not shared with
1609
 * any concurrent computation.
1610
 *
1611
 * This function optionally outputs the serialised wire-form |ek| public key
1612
 * into the provided |pubenc| buffer, and generates the content of the |rho|,
1613
 * |pkhash|, |t|, |m|, |s| and |z| components of the private |key| (which must
1614
 * have preallocated space for these).
1615
 *
1616
 * Keys are computed from a 32-byte random |d| plus the 1 byte rank for
1617
 * domain separation.  These are concatenated and hashed to produce a pair of
1618
 * 32-byte seeds public "rho", used to generate the matrix, and private "sigma",
1619
 * used to generate the secret vector |s|.
1620
 *
1621
 * The second random input |z| is copied verbatim into the Fujisaki-Okamoto
1622
 * (FO) transform "implicit-rejection" secret (the |z| component of the private
1623
 * key), which thwarts chosen-ciphertext attacks, provided decap() runs in
1624
 * constant time, with no side channel leaks, on all well-formed (valid length,
1625
 * and correctly encoded) ciphertext inputs.
1626
 */
1627
static __owur int genkey(const uint8_t seed[ML_KEM_SEED_BYTES],
1628
    EVP_MD_CTX *mdctx, uint8_t *pubenc, ML_KEM_KEY *key)
1629
0
{
1630
0
    uint8_t hashed[2 * ML_KEM_RANDOM_BYTES];
1631
0
    const uint8_t *const sigma = hashed + ML_KEM_RANDOM_BYTES;
1632
0
    uint8_t augmented_seed[ML_KEM_RANDOM_BYTES + 1];
1633
0
    const ML_KEM_VINFO *vinfo = key->vinfo;
1634
0
    CBD_FUNC cbd_1 = CBD1(vinfo->evp_type);
1635
0
    int rank = vinfo->rank;
1636
0
    uint8_t counter = 0;
1637
0
    int ret = 0;
1638
1639
    /*
1640
     * Use the "d" seed salted with the rank to derive the public and private
1641
     * seeds rho and sigma.
1642
     */
1643
0
    memcpy(augmented_seed, seed, ML_KEM_RANDOM_BYTES);
1644
0
    augmented_seed[ML_KEM_RANDOM_BYTES] = (uint8_t)rank;
1645
0
    if (!hash_g(hashed, augmented_seed, sizeof(augmented_seed), mdctx, key))
1646
0
        goto end;
1647
0
    memcpy(key->rho, hashed, ML_KEM_RANDOM_BYTES);
1648
    /* The |rho| matrix seed is public */
1649
0
    CONSTTIME_DECLASSIFY(key->rho, ML_KEM_RANDOM_BYTES);
1650
1651
    /* FIPS 203 |e| vector is initial value of key->t */
1652
0
    if (!matrix_expand(mdctx, key)
1653
0
        || !gencbd_vector_ntt(key->s, cbd_1, &counter, sigma, rank, mdctx, key)
1654
0
        || !gencbd_vector_ntt(key->t, cbd_1, &counter, sigma, rank, mdctx, key))
1655
0
        goto end;
1656
1657
    /* To |e| we now add the product of transpose |m| and |s|, giving |t|. */
1658
0
    matrix_mult_transpose_add(key->t, key->m, key->s, rank);
1659
    /* The |t| vector is public */
1660
0
    CONSTTIME_DECLASSIFY(key->t, vinfo->rank * sizeof(scalar));
1661
1662
0
    if (pubenc == NULL) {
1663
        /* Incremental digest of public key without in-full serialisation. */
1664
0
        if (!hash_h_pubkey(key->pkhash, mdctx, key))
1665
0
            goto end;
1666
0
    } else {
1667
0
        encode_pubkey(pubenc, key);
1668
0
        if (!hash_h(key->pkhash, pubenc, vinfo->pubkey_bytes, mdctx, key))
1669
0
            goto end;
1670
0
    }
1671
1672
    /* Save |z| portion of seed for "implicit rejection" on failure. */
1673
0
    memcpy(key->z, seed + ML_KEM_RANDOM_BYTES, ML_KEM_RANDOM_BYTES);
1674
1675
    /* Save the |d| portion of the seed */
1676
0
    key->d = key->z + ML_KEM_RANDOM_BYTES;
1677
0
    memcpy(key->d, seed, ML_KEM_RANDOM_BYTES);
1678
1679
0
    ret = 1;
1680
0
end:
1681
0
    OPENSSL_cleanse((void *)augmented_seed, sizeof(augmented_seed));
1682
0
    OPENSSL_cleanse((void *)hashed, sizeof(hashed));
1683
0
    if (ret == 0) {
1684
0
        ERR_raise_data(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR,
1685
0
            "internal error while generating %s private key",
1686
0
            vinfo->algorithm_name);
1687
0
    }
1688
0
    return ret;
1689
0
}
1690
1691
/*-
1692
 * FIPS 203, Section 6.2, Algorithm 17: "ML-KEM.Encaps_internal".
1693
 * This is the deterministic version with randomness supplied externally.
1694
 *
1695
 * The caller must pass space for two vectors in |tmp|.
1696
 * The |ctext| buffer have space for the ciphertext of the ML-KEM variant
1697
 * of the provided key.
1698
 */
1699
static int encap(uint8_t *ctext, uint8_t secret[ML_KEM_SHARED_SECRET_BYTES],
1700
    const uint8_t entropy[ML_KEM_RANDOM_BYTES],
1701
    scalar *tmp, EVP_MD_CTX *mdctx, const ML_KEM_KEY *key)
1702
0
{
1703
0
    uint8_t input[ML_KEM_RANDOM_BYTES + ML_KEM_PKHASH_BYTES];
1704
0
    uint8_t Kr[ML_KEM_SHARED_SECRET_BYTES + ML_KEM_RANDOM_BYTES];
1705
0
    uint8_t *r = Kr + ML_KEM_SHARED_SECRET_BYTES;
1706
0
    int ret;
1707
1708
0
    memcpy(input, entropy, ML_KEM_RANDOM_BYTES);
1709
0
    memcpy(input + ML_KEM_RANDOM_BYTES, key->pkhash, ML_KEM_PKHASH_BYTES);
1710
0
    ret = hash_g(Kr, input, sizeof(input), mdctx, key)
1711
0
        && encrypt_cpa(ctext, entropy, r, tmp, mdctx, key);
1712
0
    OPENSSL_cleanse((void *)input, sizeof(input));
1713
1714
0
    if (ret)
1715
0
        memcpy(secret, Kr, ML_KEM_SHARED_SECRET_BYTES);
1716
0
    else
1717
0
        ERR_raise_data(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR,
1718
0
            "internal error while performing %s encapsulation",
1719
0
            key->vinfo->algorithm_name);
1720
0
    OPENSSL_cleanse((void *)Kr, sizeof(Kr));
1721
0
    return ret;
1722
0
}
1723
1724
/*
1725
 * Hash the input message |m'| and public key digest |h|
1726
 * to obtain |K| and |r|.
1727
 */
1728
static int hash_kr(uint8_t *out, uint8_t *in,
1729
    EVP_MD_CTX *mdctx, const ML_KEM_KEY *key)
1730
0
{
1731
0
    unsigned int sz, wanted;
1732
1733
0
    wanted = ML_KEM_SHARED_SECRET_BYTES + ML_KEM_RANDOM_BYTES;
1734
0
    return (EVP_DigestInit_ex(mdctx, key->sha3_512_md, NULL)
1735
0
        && EVP_DigestUpdate(mdctx, in, ML_KEM_RANDOM_BYTES)
1736
0
        && EVP_DigestUpdate(mdctx, key->pkhash, ML_KEM_PKHASH_BYTES)
1737
0
        && EVP_DigestFinal_ex(mdctx, out, &sz)
1738
0
        && ossl_assert(sz == wanted));
1739
0
}
1740
1741
/*-
1742
 * Decap needs space for: Kbar | K | r | m'
1743
 * We slice up a single buffer to hold them all.
1744
 * We don't need to cleanse the public pkhash value.
1745
 */
1746
0
#define DECAP_BUFFER_SZ (2 * ML_KEM_SHARED_SECRET_BYTES + 2 * ML_KEM_RANDOM_BYTES)
1747
1748
/*
1749
 * FIPS 203, Section 6.3, Algorithm 18: ML-KEM.Decaps_internal
1750
 *
1751
 * Barring failure of the supporting SHA3/SHAKE primitives, this is fully
1752
 * deterministic, the randomness for the FO transform is extracted during
1753
 * private key generation.
1754
 *
1755
 * The caller must pass space for two vectors in |tmp|.
1756
 * The |ctext| and |tmp_ctext| buffers must each have space for the ciphertext
1757
 * of the key's ML-KEM variant.
1758
 */
1759
static int decap(uint8_t secret[ML_KEM_SHARED_SECRET_BYTES],
1760
    const uint8_t *ctext, uint8_t *tmp_ctext, scalar *tmp,
1761
    EVP_MD_CTX *mdctx, const ML_KEM_KEY *key)
1762
0
{
1763
0
    uint8_t buf[DECAP_BUFFER_SZ];
1764
0
    uint8_t *failure_key = buf; /* Kbar */
1765
0
    uint8_t *Kr = failure_key + ML_KEM_SHARED_SECRET_BYTES;
1766
0
    uint8_t *r = Kr + ML_KEM_SHARED_SECRET_BYTES;
1767
0
    uint8_t *m = r + ML_KEM_RANDOM_BYTES; /* m' */
1768
0
    const ML_KEM_VINFO *vinfo = key->vinfo;
1769
0
    int i;
1770
0
    uint8_t mask;
1771
0
    int ret = 0;
1772
1773
    /*
1774
     * The functions called below (kdf, hash_kr, encrypt_cpa) only fail on
1775
     * catastrophic failure of an underlying SHA3/SHAKE primitive, for example
1776
     * a memory allocation failure in EVP_DigestInit_ex(). None of these
1777
     * failures are dependent on the ciphertext content, so reporting them as a
1778
     * hard error does not create a chosen-ciphertext oracle and does not affect
1779
     * the constant-time properties of the implicit rejection path below.
1780
     */
1781
0
    if (!kdf(failure_key, key->z, ctext, vinfo->ctext_bytes, mdctx, key)) {
1782
0
        ERR_raise_data(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR,
1783
0
            "internal error while performing %s decapsulation",
1784
0
            vinfo->algorithm_name);
1785
0
        goto end;
1786
0
    }
1787
0
    decrypt_cpa(m, ctext, tmp, key);
1788
0
    if (!hash_kr(Kr, m, mdctx, key)
1789
0
        || !encrypt_cpa(tmp_ctext, m, r, tmp, mdctx, key)) {
1790
0
        ERR_raise_data(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR,
1791
0
            "internal error while performing %s decapsulation",
1792
0
            vinfo->algorithm_name);
1793
0
        goto end;
1794
0
    }
1795
0
    mask = constant_time_eq_int_8(0,
1796
0
        CRYPTO_memcmp(ctext, tmp_ctext, vinfo->ctext_bytes));
1797
0
    for (i = 0; i < ML_KEM_SHARED_SECRET_BYTES; i++)
1798
0
        secret[i] = constant_time_select_8(mask, Kr[i], failure_key[i]);
1799
0
    ret = 1;
1800
0
end:
1801
0
    OPENSSL_cleanse(buf, DECAP_BUFFER_SZ);
1802
0
    return ret;
1803
0
}
1804
1805
/*
1806
 * Aligned allocation helpers for the VX path.
1807
 *
1808
 * On s390x with VX support the scalar type carries ALIGN16 but both
1809
 * OPENSSL_malloc and OPENSSL_secure_malloc may return only 8-byte-aligned
1810
 * storage.  Both the public-key buffer (t + m) and the private-key buffer
1811
 * (s + z + d) are therefore allocated with 16-byte alignment using a
1812
 * self-describing header-word technique:
1813
 *
1814
 *   - Over-allocate by sizeof(void *) + (SCALAR_ALIGN - 1) bytes.
1815
 *   - Advance the pointer to the next SCALAR_ALIGN boundary that is at least
1816
 *     sizeof(void *) bytes past the raw allocation, so there is always room
1817
 *     for a void * header even when raw is already SCALAR_ALIGN-aligned.
1818
 *   - Store the original raw pointer in the sizeof(void *) bytes of slack
1819
 *     immediately before the aligned pointer.
1820
 *   - To free: read back the raw pointer from that header slot.
1821
 *
1822
 * This is safe because sizeof(void *) <= 8 <= SCALAR_ALIGN = 16 on all
1823
 * supported platforms.  No raw-pointer field is needed in ML_KEM_KEY, so the
1824
 * struct layout is identical regardless of whether VX support is compiled in.
1825
 */
1826
#if defined(VX_COMPILER_SUPPORT_VEC128)
1827
#define SCALAR_ALIGN 16
1828
1829
static scalar *alloc_pub_aligned(size_t puballoc)
1830
{
1831
    uint8_t *raw = OPENSSL_malloc(puballoc + sizeof(void *) + (SCALAR_ALIGN - 1));
1832
    uintptr_t addr;
1833
1834
    if (raw == NULL)
1835
        return NULL;
1836
    addr = ((uintptr_t)raw + sizeof(void *) + (SCALAR_ALIGN - 1)) & ~(uintptr_t)(SCALAR_ALIGN - 1);
1837
    *(void **)((uint8_t *)(void *)addr - sizeof(void *)) = raw;
1838
    return (scalar *)(void *)addr;
1839
}
1840
1841
static void free_pub_aligned(scalar *p)
1842
{
1843
    if (p == NULL)
1844
        return;
1845
    OPENSSL_free(*(void **)((uint8_t *)p - sizeof(void *)));
1846
}
1847
1848
static scalar *alloc_prv_aligned(size_t prvalloc)
1849
{
1850
    uint8_t *raw = OPENSSL_secure_malloc(prvalloc + sizeof(void *) + (SCALAR_ALIGN - 1));
1851
    uintptr_t addr;
1852
1853
    if (raw == NULL)
1854
        return NULL;
1855
    addr = ((uintptr_t)raw + sizeof(void *) + (SCALAR_ALIGN - 1)) & ~(uintptr_t)(SCALAR_ALIGN - 1);
1856
    *(void **)((uint8_t *)(void *)addr - sizeof(void *)) = raw;
1857
    return (scalar *)(void *)addr;
1858
}
1859
1860
static void free_prv_aligned(scalar *p, size_t prvalloc)
1861
{
1862
    if (p == NULL)
1863
        return;
1864
    OPENSSL_secure_clear_free(*(void **)((uint8_t *)p - sizeof(void *)),
1865
        prvalloc + sizeof(void *) + (SCALAR_ALIGN - 1));
1866
}
1867
#endif /* VX_COMPILER_SUPPORT_VEC128 */
1868
1869
/*
1870
 * After allocating storage for public or private key data, update the key
1871
 * component pointers to reference that storage.
1872
 *
1873
 * The caller should only store private data in `priv` *after* a successful
1874
 * (non-zero) return from this function.
1875
 */
1876
static __owur int add_storage(scalar *pub, scalar *priv,
1877
    int private, int dup, ML_KEM_KEY *key)
1878
0
{
1879
0
    int rank = key->vinfo->rank;
1880
1881
0
    if (pub == NULL || (private && priv == NULL)) {
1882
        /*
1883
         * One of these could be allocated correctly. It is legal to call free with a NULL
1884
         * pointer, so always attempt to free both allocations here
1885
         */
1886
#if defined(VX_COMPILER_SUPPORT_VEC128)
1887
        free_pub_aligned(pub);
1888
        free_prv_aligned(priv, key->vinfo->prvalloc);
1889
#else
1890
0
        OPENSSL_free(pub);
1891
0
        OPENSSL_secure_free(priv);
1892
0
#endif
1893
0
        return 0;
1894
0
    }
1895
1896
    /*
1897
     * We're adding key material, set up rho and pkhash to point to the
1898
     * rho_pkhash buffer.  Zero the key hash when creating fresh keys.
1899
     */
1900
0
    if (dup == 0)
1901
0
        memset(key->rho_pkhash, 0, sizeof(key->rho_pkhash));
1902
0
    key->rho = key->rho_pkhash;
1903
0
    key->pkhash = key->rho_pkhash + ML_KEM_RANDOM_BYTES;
1904
0
    key->d = key->z = NULL;
1905
1906
    /* A public key needs space for |t| and |m| */
1907
0
    key->m = (key->t = pub) + rank;
1908
1909
    /*
1910
     * A private key also needs space for |s| and |z|.
1911
     * The |z| buffer always includes additional space for |d|, but a key's |d|
1912
     * pointer is left NULL when parsed from the NIST format, which omits that
1913
     * information.  Only keys generated from a (d, z) seed pair will have a
1914
     * non-NULL |d| pointer.
1915
     */
1916
0
    if (private)
1917
0
        key->z = (uint8_t *)(rank + (key->s = priv));
1918
0
    return 1;
1919
0
}
1920
1921
/*
1922
 * After freeing the storage associated with a key that failed to be
1923
 * constructed, reset the internal pointers back to NULL.
1924
 */
1925
void ossl_ml_kem_key_reset(ML_KEM_KEY *key)
1926
0
{
1927
    /*
1928
     * seedbuf can be allocated and contain |z| and |d| if the key is
1929
     * being created from a private key encoding.  Similarly a pending
1930
     * serialised (encoded) private key may be queued up to load.
1931
     * Clear and free that data now.
1932
     */
1933
0
    if (key->seedbuf != NULL)
1934
0
        OPENSSL_secure_clear_free(key->seedbuf, ML_KEM_SEED_BYTES);
1935
0
    if (ossl_ml_kem_have_dkenc(key))
1936
0
        OPENSSL_secure_clear_free(key->encoded_dk, key->vinfo->prvkey_bytes);
1937
1938
    /*-
1939
     * Cleanse any sensitive data:
1940
     * - The private vector |s| is immediately followed by the FO failure
1941
     *   secret |z|, and seed |d|, we can cleanse all three in one call.
1942
     */
1943
0
    if (key->t != NULL) {
1944
0
        if (ossl_ml_kem_have_prvkey(key)) {
1945
#if defined(VX_COMPILER_SUPPORT_VEC128)
1946
            free_prv_aligned(key->s, key->vinfo->prvalloc);
1947
#else
1948
0
            OPENSSL_secure_clear_free(key->s, key->vinfo->prvalloc);
1949
0
#endif
1950
0
        }
1951
#if defined(VX_COMPILER_SUPPORT_VEC128)
1952
        free_pub_aligned(key->t);
1953
#else
1954
0
        OPENSSL_free(key->t);
1955
0
#endif
1956
0
    }
1957
0
    key->d = key->z = key->seedbuf = key->encoded_dk = (uint8_t *)(key->s = key->m = key->t = NULL);
1958
0
}
1959
1960
/*
1961
 * ----- API exported to the provider
1962
 *
1963
 * Parameters with an implicit fixed length in the internal static API of each
1964
 * variant have an explicit checked length argument at this layer.
1965
 */
1966
1967
/* Retrieve the parameters of one of the ML-KEM variants */
1968
const ML_KEM_VINFO *ossl_ml_kem_get_vinfo(int evp_type)
1969
0
{
1970
0
    (void)CRYPTO_THREAD_run_once(&ml_kem_ntt_once, ml_kem_ntt_init);
1971
1972
0
    switch (evp_type) {
1973
0
    case EVP_PKEY_ML_KEM_512:
1974
0
        return &vinfo_map[ML_KEM_512_VINFO];
1975
0
    case EVP_PKEY_ML_KEM_768:
1976
0
        return &vinfo_map[ML_KEM_768_VINFO];
1977
0
    case EVP_PKEY_ML_KEM_1024:
1978
0
        return &vinfo_map[ML_KEM_1024_VINFO];
1979
0
    }
1980
0
    return NULL;
1981
0
}
1982
1983
/*
1984
 * @brief Fetch digest algorithms based on a propq.
1985
 * For the import case ossl_ml_kem_key_new() gets passed a NULL propq,
1986
 * so the propq is optionally deferred to the import using OSSL_PARAM.
1987
 */
1988
int ossl_ml_kem_key_fetch_digest(ML_KEM_KEY *key, const char *propq)
1989
0
{
1990
0
    if (key->shake128_md != NULL) {
1991
0
        EVP_MD_free(key->shake128_md);
1992
0
        EVP_MD_free(key->shake256_md);
1993
0
        EVP_MD_free(key->sha3_256_md);
1994
0
        EVP_MD_free(key->sha3_512_md);
1995
0
    }
1996
0
    key->shake128_md = EVP_MD_fetch(key->libctx, "SHAKE128", propq);
1997
0
    key->shake256_md = EVP_MD_fetch(key->libctx, "SHAKE256", propq);
1998
0
    key->sha3_256_md = EVP_MD_fetch(key->libctx, "SHA3-256", propq);
1999
0
    key->sha3_512_md = EVP_MD_fetch(key->libctx, "SHA3-512", propq);
2000
0
    return (key->shake128_md != NULL && key->shake256_md != NULL
2001
0
        && key->sha3_256_md != NULL && key->sha3_512_md != NULL);
2002
0
}
2003
2004
ML_KEM_KEY *ossl_ml_kem_key_new(OSSL_LIB_CTX *libctx, const char *properties,
2005
    int evp_type)
2006
0
{
2007
0
    const ML_KEM_VINFO *vinfo = ossl_ml_kem_get_vinfo(evp_type);
2008
0
    ML_KEM_KEY *key;
2009
2010
0
    if (vinfo == NULL) {
2011
0
        ERR_raise_data(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT,
2012
0
            "unsupported ML-KEM key type: %d", evp_type);
2013
0
        return NULL;
2014
0
    }
2015
2016
0
    if ((key = OPENSSL_malloc(sizeof(*key))) == NULL)
2017
0
        return NULL;
2018
2019
0
    key->vinfo = vinfo;
2020
0
    key->libctx = libctx;
2021
0
    key->prov_flags = ML_KEM_KEY_PROV_FLAGS_DEFAULT;
2022
0
    key->d = key->z = key->rho = key->pkhash = key->encoded_dk = key->seedbuf = NULL;
2023
0
    key->s = key->m = key->t = NULL;
2024
0
    key->shake128_md = key->shake256_md = key->sha3_256_md = key->sha3_512_md = NULL;
2025
0
    if (ossl_ml_kem_key_fetch_digest(key, properties))
2026
0
        return key;
2027
2028
0
    ossl_ml_kem_key_free(key);
2029
0
    ERR_raise_data(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR,
2030
0
        "missing SHA3 digest algorithms while creating %s key",
2031
0
        vinfo->algorithm_name);
2032
0
    return NULL;
2033
0
}
2034
2035
ML_KEM_KEY *ossl_ml_kem_key_dup(const ML_KEM_KEY *key, int selection)
2036
0
{
2037
0
    int ok = 0;
2038
0
    ML_KEM_KEY *ret;
2039
2040
0
    if (key == NULL)
2041
0
        return NULL;
2042
    /*
2043
     * Partially decoded keys, not yet imported or loaded, should never be
2044
     * duplicated.
2045
     */
2046
0
    if (ossl_ml_kem_decoded_key(key))
2047
0
        return NULL;
2048
2049
0
    else if ((ret = OPENSSL_memdup(key, sizeof(*key))) == NULL)
2050
0
        return NULL;
2051
2052
0
    ret->d = ret->z = ret->rho = ret->pkhash = NULL;
2053
0
    ret->s = ret->m = ret->t = NULL;
2054
2055
    /* Clear selection bits we can't fulfill */
2056
0
    if (!ossl_ml_kem_have_pubkey(key))
2057
0
        selection = 0;
2058
0
    else if (!ossl_ml_kem_have_prvkey(key))
2059
0
        selection &= ~OSSL_KEYMGMT_SELECT_PRIVATE_KEY;
2060
0
    else if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
2061
0
        selection &= ~OSSL_KEYMGMT_SELECT_PUBLIC_KEY;
2062
2063
0
    switch (selection & OSSL_KEYMGMT_SELECT_KEYPAIR) {
2064
0
    case 0:
2065
0
        ok = 1;
2066
0
        break;
2067
0
    case OSSL_KEYMGMT_SELECT_PUBLIC_KEY:
2068
#if defined(VX_COMPILER_SUPPORT_VEC128)
2069
    {
2070
        scalar *pub = alloc_pub_aligned(key->vinfo->puballoc);
2071
2072
        if (pub != NULL)
2073
            memcpy(pub, key->t, key->vinfo->puballoc);
2074
        ok = add_storage(pub, NULL, 0, 1, ret);
2075
    }
2076
#else
2077
0
        ok = add_storage(OPENSSL_memdup(key->t, key->vinfo->puballoc), NULL, 0, 1, ret);
2078
0
#endif
2079
0
    break;
2080
0
    case OSSL_KEYMGMT_SELECT_PRIVATE_KEY:
2081
        /* Frees both and returns 0 if either is NULL */
2082
#if defined(VX_COMPILER_SUPPORT_VEC128)
2083
    {
2084
        scalar *pub = alloc_pub_aligned(key->vinfo->puballoc);
2085
        scalar *priv = alloc_prv_aligned(key->vinfo->prvalloc);
2086
2087
        if (pub != NULL)
2088
            memcpy(pub, key->t, key->vinfo->puballoc);
2089
        ok = add_storage(pub, priv, 1, 1, ret);
2090
    }
2091
#else
2092
0
        ok = add_storage(OPENSSL_memdup(key->t, key->vinfo->puballoc),
2093
0
            OPENSSL_secure_malloc(key->vinfo->prvalloc), 1, 1, ret);
2094
0
#endif
2095
0
        if (ok) {
2096
0
            memcpy(ret->s, key->s, key->vinfo->prvalloc);
2097
2098
            /* Duplicated keys retain |d|, if available */
2099
0
            if (key->d != NULL)
2100
0
                ret->d = ret->z + ML_KEM_RANDOM_BYTES;
2101
0
        }
2102
0
        break;
2103
0
    }
2104
2105
0
    if (!ok) {
2106
0
        OPENSSL_free(ret);
2107
0
        return NULL;
2108
0
    }
2109
2110
0
    EVP_MD_up_ref(ret->shake128_md);
2111
0
    EVP_MD_up_ref(ret->shake256_md);
2112
0
    EVP_MD_up_ref(ret->sha3_256_md);
2113
0
    EVP_MD_up_ref(ret->sha3_512_md);
2114
2115
0
    return ret;
2116
0
}
2117
2118
void ossl_ml_kem_key_free(ML_KEM_KEY *key)
2119
0
{
2120
0
    if (key == NULL)
2121
0
        return;
2122
2123
0
    EVP_MD_free(key->shake128_md);
2124
0
    EVP_MD_free(key->shake256_md);
2125
0
    EVP_MD_free(key->sha3_256_md);
2126
0
    EVP_MD_free(key->sha3_512_md);
2127
2128
0
    ossl_ml_kem_key_reset(key);
2129
0
    OPENSSL_free(key);
2130
0
}
2131
2132
/* Serialise the public component of an ML-KEM key */
2133
int ossl_ml_kem_encode_public_key(uint8_t *out, size_t len,
2134
    const ML_KEM_KEY *key)
2135
0
{
2136
0
    if (!ossl_ml_kem_have_pubkey(key)
2137
0
        || len != key->vinfo->pubkey_bytes)
2138
0
        return 0;
2139
0
    encode_pubkey(out, key);
2140
0
    return 1;
2141
0
}
2142
2143
/* Serialise an ML-KEM private key */
2144
int ossl_ml_kem_encode_private_key(uint8_t *out, size_t len,
2145
    const ML_KEM_KEY *key)
2146
0
{
2147
0
    if (!ossl_ml_kem_have_prvkey(key)
2148
0
        || len != key->vinfo->prvkey_bytes)
2149
0
        return 0;
2150
0
    encode_prvkey(out, key);
2151
0
    return 1;
2152
0
}
2153
2154
int ossl_ml_kem_encode_seed(uint8_t *out, size_t len,
2155
    const ML_KEM_KEY *key)
2156
0
{
2157
0
    if (key == NULL || key->d == NULL || len != ML_KEM_SEED_BYTES)
2158
0
        return 0;
2159
    /*
2160
     * Both in the seed buffer, and in the allocated storage, the |d| component
2161
     * of the seed is stored last, so we must copy each separately.
2162
     */
2163
0
    memcpy(out, key->d, ML_KEM_RANDOM_BYTES);
2164
0
    out += ML_KEM_RANDOM_BYTES;
2165
0
    memcpy(out, key->z, ML_KEM_RANDOM_BYTES);
2166
0
    return 1;
2167
0
}
2168
2169
/*
2170
 * Stash the seed without (yet) performing a keygen, used during decoding, to
2171
 * avoid an extra keygen if we're only going to export the key again to load
2172
 * into another provider.
2173
 */
2174
ML_KEM_KEY *ossl_ml_kem_set_seed(const uint8_t *seed, size_t seedlen, ML_KEM_KEY *key)
2175
0
{
2176
0
    if (key == NULL
2177
0
        || ossl_ml_kem_have_pubkey(key)
2178
0
        || ossl_ml_kem_have_seed(key)
2179
0
        || seedlen != ML_KEM_SEED_BYTES)
2180
0
        return NULL;
2181
2182
0
    if (key->seedbuf == NULL) {
2183
0
        key->seedbuf = OPENSSL_secure_malloc(seedlen);
2184
0
        if (key->seedbuf == NULL)
2185
0
            return NULL;
2186
0
    }
2187
2188
0
    key->z = key->seedbuf;
2189
0
    key->d = key->z + ML_KEM_RANDOM_BYTES;
2190
0
    memcpy(key->d, seed, ML_KEM_RANDOM_BYTES);
2191
0
    seed += ML_KEM_RANDOM_BYTES;
2192
0
    memcpy(key->z, seed, ML_KEM_RANDOM_BYTES);
2193
0
    return key;
2194
0
}
2195
2196
/* Parse input as a public key */
2197
int ossl_ml_kem_parse_public_key(const uint8_t *in, size_t len, ML_KEM_KEY *key)
2198
0
{
2199
0
    EVP_MD_CTX *mdctx = NULL;
2200
0
    const ML_KEM_VINFO *vinfo;
2201
0
    int ret = 0;
2202
2203
    /* Keys with key material are immutable */
2204
0
    if (key == NULL
2205
0
        || ossl_ml_kem_have_pubkey(key)
2206
0
        || ossl_ml_kem_have_dkenc(key))
2207
0
        return 0;
2208
0
    vinfo = key->vinfo;
2209
2210
0
    if (len != vinfo->pubkey_bytes
2211
0
        || (mdctx = EVP_MD_CTX_new()) == NULL)
2212
0
        return 0;
2213
2214
#if defined(VX_COMPILER_SUPPORT_VEC128)
2215
    if (add_storage(alloc_pub_aligned(vinfo->puballoc),
2216
            NULL, 0, 0, key))
2217
#else
2218
0
    if (add_storage(OPENSSL_malloc(vinfo->puballoc), NULL, 0, 0, key))
2219
0
#endif
2220
0
        ret = parse_pubkey(in, mdctx, key);
2221
2222
0
    if (!ret)
2223
0
        ossl_ml_kem_key_reset(key);
2224
0
    EVP_MD_CTX_free(mdctx);
2225
0
    return ret;
2226
0
}
2227
2228
/* Parse input as a new private key */
2229
int ossl_ml_kem_parse_private_key(const uint8_t *in, size_t len,
2230
    ML_KEM_KEY *key)
2231
0
{
2232
0
    EVP_MD_CTX *mdctx = NULL;
2233
0
    const ML_KEM_VINFO *vinfo;
2234
0
    int ret = 0;
2235
2236
    /* Keys with key material are immutable */
2237
0
    if (key == NULL
2238
0
        || ossl_ml_kem_have_pubkey(key)
2239
0
        || ossl_ml_kem_have_dkenc(key))
2240
0
        return 0;
2241
0
    vinfo = key->vinfo;
2242
2243
0
    if (len != vinfo->prvkey_bytes
2244
0
        || (mdctx = EVP_MD_CTX_new()) == NULL)
2245
0
        return 0;
2246
2247
    /* Clear any unused seed */
2248
0
    ossl_ml_kem_key_reset(key);
2249
2250
#if defined(VX_COMPILER_SUPPORT_VEC128)
2251
    if (add_storage(alloc_pub_aligned(vinfo->puballoc),
2252
            alloc_prv_aligned(vinfo->prvalloc), 1, 0, key))
2253
#else
2254
0
    if (add_storage(OPENSSL_malloc(vinfo->puballoc),
2255
0
            OPENSSL_secure_malloc(vinfo->prvalloc), 1, 0, key))
2256
0
#endif
2257
0
        ret = parse_prvkey(in, mdctx, key);
2258
2259
0
    if (!ret)
2260
0
        ossl_ml_kem_key_reset(key);
2261
0
    EVP_MD_CTX_free(mdctx);
2262
0
    return ret;
2263
0
}
2264
2265
/*
2266
 * Generate a new keypair, either from the saved seed (when non-null), or from
2267
 * the RNG.
2268
 */
2269
int ossl_ml_kem_genkey(uint8_t *pubenc, size_t publen, ML_KEM_KEY *key)
2270
0
{
2271
0
    uint8_t seed[ML_KEM_SEED_BYTES];
2272
0
    EVP_MD_CTX *mdctx = NULL;
2273
0
    const ML_KEM_VINFO *vinfo;
2274
0
    int ret = 0;
2275
2276
0
    if (key == NULL
2277
0
        || ossl_ml_kem_have_pubkey(key)
2278
0
        || ossl_ml_kem_have_dkenc(key))
2279
0
        return 0;
2280
0
    vinfo = key->vinfo;
2281
2282
0
    if (pubenc != NULL && publen != vinfo->pubkey_bytes)
2283
0
        return 0;
2284
2285
0
    if (key->seedbuf != NULL) {
2286
0
        if (!ossl_ml_kem_encode_seed(seed, sizeof(seed), key))
2287
0
            return 0;
2288
0
        ossl_ml_kem_key_reset(key);
2289
0
    } else if (RAND_priv_bytes_ex(key->libctx, seed, sizeof(seed),
2290
0
                   key->vinfo->secbits)
2291
0
        <= 0) {
2292
0
        return 0;
2293
0
    }
2294
2295
0
    if ((mdctx = EVP_MD_CTX_new()) == NULL)
2296
0
        return 0;
2297
2298
    /*
2299
     * Data derived from (d, z) defaults secret, and to avoid side-channel
2300
     * leaks should not influence control flow.
2301
     */
2302
0
    CONSTTIME_SECRET(seed, ML_KEM_SEED_BYTES);
2303
2304
#if defined(VX_COMPILER_SUPPORT_VEC128)
2305
    if (add_storage(alloc_pub_aligned(vinfo->puballoc),
2306
            alloc_prv_aligned(vinfo->prvalloc), 1, 0, key))
2307
#else
2308
0
    if (add_storage(OPENSSL_malloc(vinfo->puballoc),
2309
0
            OPENSSL_secure_malloc(vinfo->prvalloc), 1, 0, key))
2310
0
#endif
2311
0
        ret = genkey(seed, mdctx, pubenc, key);
2312
0
    OPENSSL_cleanse(seed, sizeof(seed));
2313
2314
    /* Declassify secret inputs and derived outputs before returning control */
2315
0
    CONSTTIME_DECLASSIFY(seed, ML_KEM_SEED_BYTES);
2316
2317
0
    EVP_MD_CTX_free(mdctx);
2318
0
    if (!ret) {
2319
        /* Erase any partial public key output */
2320
0
        if (pubenc != NULL)
2321
0
            OPENSSL_cleanse(pubenc, vinfo->pubkey_bytes);
2322
0
        ossl_ml_kem_key_reset(key);
2323
0
        return 0;
2324
0
    }
2325
2326
    /* The public components are already declassified */
2327
0
    CONSTTIME_DECLASSIFY(key->s, vinfo->rank * sizeof(scalar));
2328
0
    CONSTTIME_DECLASSIFY(key->z, 2 * ML_KEM_RANDOM_BYTES);
2329
0
    return 1;
2330
0
}
2331
2332
/*
2333
 * FIPS 203, Section 6.2, Algorithm 17: ML-KEM.Encaps_internal
2334
 * This is the deterministic version with randomness supplied externally.
2335
 */
2336
int ossl_ml_kem_encap_seed(uint8_t *ctext, size_t clen,
2337
    uint8_t *shared_secret, size_t slen,
2338
    const uint8_t *entropy, size_t elen,
2339
    const ML_KEM_KEY *key)
2340
0
{
2341
0
    const ML_KEM_VINFO *vinfo;
2342
0
    EVP_MD_CTX *mdctx;
2343
0
    int ret = 0;
2344
2345
0
    if (key == NULL || !ossl_ml_kem_have_pubkey(key))
2346
0
        return 0;
2347
0
    vinfo = key->vinfo;
2348
2349
0
    if (ctext == NULL || clen != vinfo->ctext_bytes
2350
0
        || shared_secret == NULL || slen != ML_KEM_SHARED_SECRET_BYTES
2351
0
        || entropy == NULL || elen != ML_KEM_RANDOM_BYTES
2352
0
        || (mdctx = EVP_MD_CTX_new()) == NULL)
2353
0
        return 0;
2354
    /*
2355
     * Data derived from the encap entropy defaults secret, and to avoid
2356
     * side-channel leaks should not influence control flow.
2357
     */
2358
0
    CONSTTIME_SECRET(entropy, elen);
2359
2360
    /*-
2361
     * This avoids the need to handle allocation failures for two (max 2KB
2362
     * each) vectors, that are never retained on return from this function.
2363
     * We stack-allocate these.
2364
     */
2365
0
#define case_encap_seed(bits)                                        \
2366
0
    {                                                                \
2367
0
        scalar tmp[2 * ML_KEM_##bits##_RANK];                        \
2368
0
                                                                     \
2369
0
        ret = encap(ctext, shared_secret, entropy, tmp, mdctx, key); \
2370
0
        OPENSSL_cleanse((void *)tmp, sizeof(tmp));                   \
2371
0
    }
2372
0
    switch (vinfo->evp_type) {
2373
0
    case EVP_PKEY_ML_KEM_512:
2374
0
        case_encap_seed(512);
2375
0
        break;
2376
0
    case EVP_PKEY_ML_KEM_768:
2377
0
        case_encap_seed(768);
2378
0
        break;
2379
0
    case EVP_PKEY_ML_KEM_1024:
2380
0
        case_encap_seed(1024);
2381
0
        break;
2382
0
    }
2383
0
#undef case_encap_seed
2384
2385
    /* Erase any partial ciphertext output on failure */
2386
0
    if (!ret)
2387
0
        OPENSSL_cleanse(ctext, clen);
2388
2389
    /* Declassify secret inputs and derived outputs before returning control */
2390
0
    CONSTTIME_DECLASSIFY(entropy, elen);
2391
0
    CONSTTIME_DECLASSIFY(ctext, clen);
2392
0
    CONSTTIME_DECLASSIFY(shared_secret, slen);
2393
2394
0
    EVP_MD_CTX_free(mdctx);
2395
0
    return ret;
2396
0
}
2397
2398
int ossl_ml_kem_encap_rand(uint8_t *ctext, size_t clen,
2399
    uint8_t *shared_secret, size_t slen,
2400
    const ML_KEM_KEY *key)
2401
0
{
2402
0
    uint8_t r[ML_KEM_RANDOM_BYTES];
2403
0
    int ret;
2404
2405
0
    if (key == NULL)
2406
0
        return 0;
2407
2408
0
    if (RAND_bytes_ex(key->libctx, r, ML_KEM_RANDOM_BYTES,
2409
0
            key->vinfo->secbits)
2410
0
        < 1)
2411
0
        return 0;
2412
2413
0
    ret = ossl_ml_kem_encap_seed(ctext, clen, shared_secret, slen,
2414
0
        r, sizeof(r), key);
2415
2416
0
    OPENSSL_cleanse((void *)r, sizeof(r));
2417
0
    return ret;
2418
0
}
2419
2420
int ossl_ml_kem_decap(uint8_t *shared_secret, size_t slen,
2421
    const uint8_t *ctext, size_t clen,
2422
    const ML_KEM_KEY *key)
2423
0
{
2424
0
    const ML_KEM_VINFO *vinfo;
2425
0
    EVP_MD_CTX *mdctx;
2426
0
    int ret = 0;
2427
#if defined(OPENSSL_CONSTANT_TIME_VALIDATION)
2428
    int classify_bytes;
2429
#endif
2430
2431
    /* Need a private key here */
2432
0
    if (!ossl_ml_kem_have_prvkey(key)
2433
0
        || shared_secret == NULL
2434
0
        || slen < ML_KEM_SHARED_SECRET_BYTES)
2435
0
        return 0;
2436
0
    vinfo = key->vinfo;
2437
2438
0
    if (slen != ML_KEM_SHARED_SECRET_BYTES
2439
0
        || ctext == NULL || clen != vinfo->ctext_bytes
2440
0
        || (mdctx = EVP_MD_CTX_new()) == NULL) {
2441
0
        (void)RAND_bytes_ex(key->libctx, shared_secret,
2442
0
            ML_KEM_SHARED_SECRET_BYTES, vinfo->secbits);
2443
0
        return 0;
2444
0
    }
2445
    /*
2446
     * Data derived from |s| and |z| defaults secret, and to avoid side-channel
2447
     * leaks should not influence control flow.
2448
     */
2449
#if defined(OPENSSL_CONSTANT_TIME_VALIDATION)
2450
    classify_bytes = vinfo->rank * sizeof(scalar) + ML_KEM_RANDOM_BYTES;
2451
#endif
2452
0
    CONSTTIME_SECRET(key->s, classify_bytes);
2453
2454
    /*-
2455
     * This avoids the need to handle allocation failures for two (max 2KB
2456
     * each) vectors and an encoded ciphertext (max 1568 bytes), that are never
2457
     * retained on return from this function.
2458
     * We stack-allocate these.
2459
     */
2460
0
#define case_decap(bits)                                          \
2461
0
    {                                                             \
2462
0
        uint8_t cbuf[CTEXT_BYTES(bits)];                          \
2463
0
        scalar tmp[2 * ML_KEM_##bits##_RANK];                     \
2464
0
                                                                  \
2465
0
        ret = decap(shared_secret, ctext, cbuf, tmp, mdctx, key); \
2466
0
        OPENSSL_cleanse((void *)tmp, sizeof(tmp));                \
2467
0
        OPENSSL_cleanse((void *)cbuf, sizeof(cbuf));              \
2468
0
    }
2469
0
    switch (vinfo->evp_type) {
2470
0
    case EVP_PKEY_ML_KEM_512:
2471
0
        case_decap(512);
2472
0
        break;
2473
0
    case EVP_PKEY_ML_KEM_768:
2474
0
        case_decap(768);
2475
0
        break;
2476
0
    case EVP_PKEY_ML_KEM_1024:
2477
0
        case_decap(1024);
2478
0
        break;
2479
0
    }
2480
0
#undef case_decap
2481
2482
    /* Declassify secret inputs and derived outputs before returning control */
2483
0
    CONSTTIME_DECLASSIFY(key->s, classify_bytes);
2484
0
    CONSTTIME_DECLASSIFY(shared_secret, slen);
2485
0
    EVP_MD_CTX_free(mdctx);
2486
2487
0
    return ret;
2488
0
}
2489
2490
int ossl_ml_kem_pubkey_cmp(const ML_KEM_KEY *key1, const ML_KEM_KEY *key2)
2491
0
{
2492
    /*
2493
     * This handles any unexpected differences in the ML-KEM variant rank,
2494
     * giving different key component structures, barring SHA3-256 hash
2495
     * collisions, the keys are the same size.
2496
     */
2497
0
    if (ossl_ml_kem_have_pubkey(key1) && ossl_ml_kem_have_pubkey(key2))
2498
0
        return memcmp(key1->pkhash, key2->pkhash, ML_KEM_PKHASH_BYTES) == 0;
2499
2500
    /*
2501
     * No match if just one of the public keys is not available, otherwise both
2502
     * are unavailable, and for now such keys are considered equal.
2503
     */
2504
0
    return (!(ossl_ml_kem_have_pubkey(key1) ^ ossl_ml_kem_have_pubkey(key2)));
2505
0
}