1*e7be843bSPierre Pronchery /*
2*e7be843bSPierre Pronchery * Copyright 2015-2025 The OpenSSL Project Authors. All Rights Reserved.
3*e7be843bSPierre Pronchery *
4*e7be843bSPierre Pronchery * Licensed under the Apache License 2.0 (the "License"). You may not use
5*e7be843bSPierre Pronchery * this file except in compliance with the License. You can obtain a copy
6*e7be843bSPierre Pronchery * in the file LICENSE in the source distribution or at
7*e7be843bSPierre Pronchery * https://www.openssl.org/source/license.html
8*e7be843bSPierre Pronchery */
9*e7be843bSPierre Pronchery
10*e7be843bSPierre Pronchery #include <stdio.h>
11*e7be843bSPierre Pronchery #include <stdlib.h>
12*e7be843bSPierre Pronchery #include <string.h>
13*e7be843bSPierre Pronchery #include <openssl/conf.h>
14*e7be843bSPierre Pronchery #include <openssl/crypto.h>
15*e7be843bSPierre Pronchery #include <openssl/err.h>
16*e7be843bSPierre Pronchery #include <openssl/evp.h>
17*e7be843bSPierre Pronchery #include <openssl/provider.h>
18*e7be843bSPierre Pronchery #include <openssl/core_names.h>
19*e7be843bSPierre Pronchery #include <openssl/params.h>
20*e7be843bSPierre Pronchery #include <openssl/param_build.h>
21*e7be843bSPierre Pronchery #include <openssl/rand.h>
22*e7be843bSPierre Pronchery #include <crypto/ml_kem.h>
23*e7be843bSPierre Pronchery #include "testutil.h"
24*e7be843bSPierre Pronchery
25*e7be843bSPierre Pronchery static OSSL_LIB_CTX *testctx = NULL;
26*e7be843bSPierre Pronchery
27*e7be843bSPierre Pronchery typedef enum OPTION_choice {
28*e7be843bSPierre Pronchery OPT_ERR = -1,
29*e7be843bSPierre Pronchery OPT_EOF = 0,
30*e7be843bSPierre Pronchery OPT_CONFIG_FILE,
31*e7be843bSPierre Pronchery OPT_TEST_RAND,
32*e7be843bSPierre Pronchery OPT_TEST_ENUM
33*e7be843bSPierre Pronchery } OPTION_CHOICE;
34*e7be843bSPierre Pronchery
test_get_options(void)35*e7be843bSPierre Pronchery const OPTIONS *test_get_options(void)
36*e7be843bSPierre Pronchery {
37*e7be843bSPierre Pronchery static const OPTIONS options[] = {
38*e7be843bSPierre Pronchery OPT_TEST_OPTIONS_DEFAULT_USAGE,
39*e7be843bSPierre Pronchery { "test-rand", OPT_TEST_RAND, '-', "Test non-derandomised ML-KEM" },
40*e7be843bSPierre Pronchery { NULL }
41*e7be843bSPierre Pronchery };
42*e7be843bSPierre Pronchery return options;
43*e7be843bSPierre Pronchery }
44*e7be843bSPierre Pronchery
45*e7be843bSPierre Pronchery static uint8_t gen_seed[64] = {
46*e7be843bSPierre Pronchery 0x7c, 0x99, 0x35, 0xa0, 0xb0, 0x76, 0x94, 0xaa, 0x0c, 0x6d, 0x10, 0xe4,
47*e7be843bSPierre Pronchery 0xdb, 0x6b, 0x1a, 0xdd, 0x2f, 0xd8, 0x1a, 0x25, 0xcc, 0xb1, 0x48, 0x03,
48*e7be843bSPierre Pronchery 0x2d, 0xcd, 0x73, 0x99, 0x36, 0x73, 0x7f, 0x2d, 0x86, 0x26, 0xed, 0x79,
49*e7be843bSPierre Pronchery 0xd4, 0x51, 0x14, 0x08, 0x00, 0xe0, 0x3b, 0x59, 0xb9, 0x56, 0xf8, 0x21,
50*e7be843bSPierre Pronchery 0x0e, 0x55, 0x60, 0x67, 0x40, 0x7d, 0x13, 0xdc, 0x90, 0xfa, 0x9e, 0x8b,
51*e7be843bSPierre Pronchery 0x87, 0x2b, 0xfb, 0x8f
52*e7be843bSPierre Pronchery };
53*e7be843bSPierre Pronchery static uint8_t enc_seed[32] = {
54*e7be843bSPierre Pronchery 0x14, 0x7c, 0x03, 0xf7, 0xa5, 0xbe, 0xbb, 0xa4, 0x06, 0xc8, 0xfa, 0xe1,
55*e7be843bSPierre Pronchery 0x87, 0x4d, 0x7f, 0x13, 0xc8, 0x0e, 0xfe, 0x79, 0xa3, 0xa9, 0xa8, 0x74,
56*e7be843bSPierre Pronchery 0xcc, 0x09, 0xfe, 0x76, 0xf6, 0x99, 0x76, 0x15
57*e7be843bSPierre Pronchery };
58*e7be843bSPierre Pronchery static uint8_t dec_seed[32] = {
59*e7be843bSPierre Pronchery 0x4e, 0x6f, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x72, 0x6f, 0x69,
60*e7be843bSPierre Pronchery 0x64, 0x73, 0x20, 0x79, 0x6f, 0x75, 0x27, 0x72, 0x65, 0x20, 0x6c, 0x6f,
61*e7be843bSPierre Pronchery 0x6f, 0x6b, 0x69, 0x6e, 0x67, 0x20, 0x66, 0x6f
62*e7be843bSPierre Pronchery };
63*e7be843bSPierre Pronchery static uint8_t expected_rho[3][32] = {
64*e7be843bSPierre Pronchery {
65*e7be843bSPierre Pronchery 0x7e, 0xfb, 0x9e, 0x40, 0xc3, 0xbf, 0x0f, 0xf0, 0x43, 0x29, 0x86, 0xae,
66*e7be843bSPierre Pronchery 0x4b, 0xc1, 0xa2, 0x42, 0xce, 0x99, 0x21, 0xaa, 0x9e, 0x22, 0x44, 0x88,
67*e7be843bSPierre Pronchery 0x19, 0x58, 0x5d, 0xea, 0x30, 0x8e, 0xb0, 0x39
68*e7be843bSPierre Pronchery },
69*e7be843bSPierre Pronchery {
70*e7be843bSPierre Pronchery 0x16, 0x2e, 0xc0, 0x98, 0xa9, 0x00, 0xb1, 0x2d, 0xd8, 0xfa, 0xbb, 0xfb,
71*e7be843bSPierre Pronchery 0x3f, 0xe8, 0xcb, 0x1d, 0xc4, 0xe8, 0x31, 0x5f, 0x2a, 0xf0, 0xd3, 0x2f,
72*e7be843bSPierre Pronchery 0x00, 0x17, 0xae, 0x13, 0x6e, 0x19, 0xf0, 0x28
73*e7be843bSPierre Pronchery },
74*e7be843bSPierre Pronchery {
75*e7be843bSPierre Pronchery 0x29, 0xb4, 0xf9, 0xf8, 0xcf, 0xba, 0xdf, 0x2e, 0x41, 0x86, 0x9a, 0xbf,
76*e7be843bSPierre Pronchery 0xba, 0xd1, 0x07, 0x38, 0xad, 0x04, 0xcc, 0x75, 0x2b, 0xc2, 0x0c, 0x39,
77*e7be843bSPierre Pronchery 0x47, 0x46, 0x85, 0x0e, 0x0c, 0x48, 0x47, 0xdb
78*e7be843bSPierre Pronchery }
79*e7be843bSPierre Pronchery };
80*e7be843bSPierre Pronchery static uint8_t expected_ctext_sha256[3][32] = {
81*e7be843bSPierre Pronchery {
82*e7be843bSPierre Pronchery 0xbc, 0x29, 0xd7, 0xdf, 0x8b, 0xc5, 0x46, 0x5d, 0x98, 0x06, 0x01, 0xd8,
83*e7be843bSPierre Pronchery 0x00, 0x25, 0x97, 0x93, 0xe2, 0x60, 0x38, 0x25, 0xa5, 0x72, 0xda, 0x6c,
84*e7be843bSPierre Pronchery 0xd1, 0x98, 0xa5, 0x12, 0xcc, 0x6d, 0x1a, 0x34
85*e7be843bSPierre Pronchery },
86*e7be843bSPierre Pronchery {
87*e7be843bSPierre Pronchery 0x36, 0x82, 0x9a, 0x2f, 0x35, 0xcb, 0xf4, 0xde, 0xb6, 0x2c, 0x0a, 0x12,
88*e7be843bSPierre Pronchery 0xa1, 0x5c, 0x22, 0xda, 0xe9, 0xf8, 0xd2, 0xc2, 0x52, 0x56, 0x6f, 0xc2,
89*e7be843bSPierre Pronchery 0x4f, 0x88, 0xab, 0xe8, 0x05, 0xcb, 0x57, 0x5e
90*e7be843bSPierre Pronchery },
91*e7be843bSPierre Pronchery {
92*e7be843bSPierre Pronchery 0x50, 0x81, 0x36, 0xa1, 0x3f, 0x8a, 0x79, 0x20, 0xe3, 0x43, 0x44, 0x98,
93*e7be843bSPierre Pronchery 0xc6, 0x97, 0x5c, 0xbb, 0xab, 0x45, 0x7d, 0x80, 0x93, 0x09, 0xeb, 0x2f,
94*e7be843bSPierre Pronchery 0x92, 0x45, 0x3e, 0x74, 0x09, 0x73, 0x82, 0x10
95*e7be843bSPierre Pronchery }
96*e7be843bSPierre Pronchery };
97*e7be843bSPierre Pronchery static uint8_t expected_shared_secret[3][32] = {
98*e7be843bSPierre Pronchery {
99*e7be843bSPierre Pronchery 0x31, 0x98, 0x39, 0xe8, 0x2a, 0xb6, 0xb2, 0x22, 0xde, 0x7b, 0x61, 0x9e,
100*e7be843bSPierre Pronchery 0x80, 0xda, 0x83, 0x91, 0x52, 0x2b, 0xbb, 0x37, 0x67, 0x70, 0x18, 0x49,
101*e7be843bSPierre Pronchery 0x4a, 0x47, 0x42, 0xc5, 0x3f, 0x9a, 0xbf, 0xdf
102*e7be843bSPierre Pronchery },
103*e7be843bSPierre Pronchery {
104*e7be843bSPierre Pronchery 0xe7, 0x18, 0x4a, 0x09, 0x75, 0xee, 0x34, 0x70, 0x87, 0x8d, 0x2d, 0x15,
105*e7be843bSPierre Pronchery 0x9e, 0xc8, 0x31, 0x29, 0xc8, 0xae, 0xc2, 0x53, 0xd4, 0xee, 0x17, 0xb4,
106*e7be843bSPierre Pronchery 0x81, 0x03, 0x11, 0xd1, 0x98, 0xcd, 0x03, 0x68
107*e7be843bSPierre Pronchery },
108*e7be843bSPierre Pronchery {
109*e7be843bSPierre Pronchery 0x48, 0x9d, 0xd1, 0xe9, 0xc2, 0xbe, 0x4a, 0xf3, 0x48, 0x2b, 0xdb, 0x35,
110*e7be843bSPierre Pronchery 0xbb, 0x26, 0xce, 0x76, 0x0e, 0x6e, 0x41, 0x4d, 0xa6, 0xec, 0xbe, 0x48,
111*e7be843bSPierre Pronchery 0x99, 0x85, 0x74, 0x8a, 0x82, 0x5f, 0x1c, 0xd6
112*e7be843bSPierre Pronchery },
113*e7be843bSPierre Pronchery };
114*e7be843bSPierre Pronchery
test_ml_kem(void)115*e7be843bSPierre Pronchery static int test_ml_kem(void)
116*e7be843bSPierre Pronchery {
117*e7be843bSPierre Pronchery EVP_PKEY *akey, *bkey = NULL;
118*e7be843bSPierre Pronchery int res = 0;
119*e7be843bSPierre Pronchery size_t publen;
120*e7be843bSPierre Pronchery unsigned char *rawpub = NULL;
121*e7be843bSPierre Pronchery EVP_PKEY_CTX *ctx = NULL;
122*e7be843bSPierre Pronchery unsigned char *wrpkey = NULL, *agenkey = NULL, *bgenkey = NULL;
123*e7be843bSPierre Pronchery size_t wrpkeylen, agenkeylen, bgenkeylen, i;
124*e7be843bSPierre Pronchery
125*e7be843bSPierre Pronchery /* Generate Alice's key */
126*e7be843bSPierre Pronchery akey = EVP_PKEY_Q_keygen(testctx, NULL, "ML-KEM-768");
127*e7be843bSPierre Pronchery if (!TEST_ptr(akey))
128*e7be843bSPierre Pronchery goto err;
129*e7be843bSPierre Pronchery
130*e7be843bSPierre Pronchery /* Get the raw public key */
131*e7be843bSPierre Pronchery publen = EVP_PKEY_get1_encoded_public_key(akey, &rawpub);
132*e7be843bSPierre Pronchery if (!TEST_size_t_gt(publen, 0))
133*e7be843bSPierre Pronchery goto err;
134*e7be843bSPierre Pronchery
135*e7be843bSPierre Pronchery /* Create Bob's key and populate it with Alice's public key data */
136*e7be843bSPierre Pronchery bkey = EVP_PKEY_new();
137*e7be843bSPierre Pronchery if (!TEST_ptr(bkey))
138*e7be843bSPierre Pronchery goto err;
139*e7be843bSPierre Pronchery
140*e7be843bSPierre Pronchery if (!TEST_int_gt(EVP_PKEY_copy_parameters(bkey, akey), 0))
141*e7be843bSPierre Pronchery goto err;
142*e7be843bSPierre Pronchery
143*e7be843bSPierre Pronchery if (!TEST_true(EVP_PKEY_set1_encoded_public_key(bkey, rawpub, publen)))
144*e7be843bSPierre Pronchery goto err;
145*e7be843bSPierre Pronchery
146*e7be843bSPierre Pronchery /* Encapsulate Bob's key */
147*e7be843bSPierre Pronchery ctx = EVP_PKEY_CTX_new_from_pkey(testctx, bkey, NULL);
148*e7be843bSPierre Pronchery if (!TEST_ptr(ctx))
149*e7be843bSPierre Pronchery goto err;
150*e7be843bSPierre Pronchery
151*e7be843bSPierre Pronchery if (!TEST_int_gt(EVP_PKEY_encapsulate_init(ctx, NULL), 0))
152*e7be843bSPierre Pronchery goto err;
153*e7be843bSPierre Pronchery
154*e7be843bSPierre Pronchery if (!TEST_int_gt(EVP_PKEY_encapsulate(ctx, NULL, &wrpkeylen, NULL,
155*e7be843bSPierre Pronchery &bgenkeylen), 0))
156*e7be843bSPierre Pronchery goto err;
157*e7be843bSPierre Pronchery
158*e7be843bSPierre Pronchery if (!TEST_size_t_gt(wrpkeylen, 0) || !TEST_size_t_gt(bgenkeylen, 0))
159*e7be843bSPierre Pronchery goto err;
160*e7be843bSPierre Pronchery
161*e7be843bSPierre Pronchery wrpkey = OPENSSL_zalloc(wrpkeylen);
162*e7be843bSPierre Pronchery bgenkey = OPENSSL_zalloc(bgenkeylen);
163*e7be843bSPierre Pronchery if (!TEST_ptr(wrpkey) || !TEST_ptr(bgenkey))
164*e7be843bSPierre Pronchery goto err;
165*e7be843bSPierre Pronchery
166*e7be843bSPierre Pronchery if (!TEST_int_gt(EVP_PKEY_encapsulate(ctx, wrpkey, &wrpkeylen, bgenkey,
167*e7be843bSPierre Pronchery &bgenkeylen), 0))
168*e7be843bSPierre Pronchery goto err;
169*e7be843bSPierre Pronchery
170*e7be843bSPierre Pronchery EVP_PKEY_CTX_free(ctx);
171*e7be843bSPierre Pronchery
172*e7be843bSPierre Pronchery /* Alice now decapsulates Bob's key */
173*e7be843bSPierre Pronchery ctx = EVP_PKEY_CTX_new_from_pkey(testctx, akey, NULL);
174*e7be843bSPierre Pronchery if (!TEST_ptr(ctx))
175*e7be843bSPierre Pronchery goto err;
176*e7be843bSPierre Pronchery
177*e7be843bSPierre Pronchery if (!TEST_int_gt(EVP_PKEY_decapsulate_init(ctx, NULL), 0))
178*e7be843bSPierre Pronchery goto err;
179*e7be843bSPierre Pronchery
180*e7be843bSPierre Pronchery if (!TEST_int_gt(EVP_PKEY_decapsulate(ctx, NULL, &agenkeylen, wrpkey,
181*e7be843bSPierre Pronchery wrpkeylen), 0))
182*e7be843bSPierre Pronchery goto err;
183*e7be843bSPierre Pronchery
184*e7be843bSPierre Pronchery if (!TEST_size_t_gt(agenkeylen, 0))
185*e7be843bSPierre Pronchery goto err;
186*e7be843bSPierre Pronchery
187*e7be843bSPierre Pronchery agenkey = OPENSSL_zalloc(agenkeylen);
188*e7be843bSPierre Pronchery if (!TEST_ptr(agenkey))
189*e7be843bSPierre Pronchery goto err;
190*e7be843bSPierre Pronchery
191*e7be843bSPierre Pronchery if (!TEST_int_gt(EVP_PKEY_decapsulate(ctx, agenkey, &agenkeylen, wrpkey,
192*e7be843bSPierre Pronchery wrpkeylen), 0))
193*e7be843bSPierre Pronchery goto err;
194*e7be843bSPierre Pronchery
195*e7be843bSPierre Pronchery /* Hopefully we ended up with a shared key */
196*e7be843bSPierre Pronchery if (!TEST_mem_eq(agenkey, agenkeylen, bgenkey, bgenkeylen))
197*e7be843bSPierre Pronchery goto err;
198*e7be843bSPierre Pronchery
199*e7be843bSPierre Pronchery /* Verify we generated a non-zero shared key */
200*e7be843bSPierre Pronchery for (i = 0; i < agenkeylen; i++)
201*e7be843bSPierre Pronchery if (agenkey[i] != 0)
202*e7be843bSPierre Pronchery break;
203*e7be843bSPierre Pronchery if (!TEST_size_t_ne(i, agenkeylen))
204*e7be843bSPierre Pronchery goto err;
205*e7be843bSPierre Pronchery
206*e7be843bSPierre Pronchery res = 1;
207*e7be843bSPierre Pronchery err:
208*e7be843bSPierre Pronchery EVP_PKEY_CTX_free(ctx);
209*e7be843bSPierre Pronchery EVP_PKEY_free(akey);
210*e7be843bSPierre Pronchery EVP_PKEY_free(bkey);
211*e7be843bSPierre Pronchery OPENSSL_free(rawpub);
212*e7be843bSPierre Pronchery OPENSSL_free(wrpkey);
213*e7be843bSPierre Pronchery OPENSSL_free(agenkey);
214*e7be843bSPierre Pronchery OPENSSL_free(bgenkey);
215*e7be843bSPierre Pronchery return res;
216*e7be843bSPierre Pronchery }
217*e7be843bSPierre Pronchery
test_non_derandomised_ml_kem(void)218*e7be843bSPierre Pronchery static int test_non_derandomised_ml_kem(void)
219*e7be843bSPierre Pronchery {
220*e7be843bSPierre Pronchery static const int alg[3] = {
221*e7be843bSPierre Pronchery EVP_PKEY_ML_KEM_512,
222*e7be843bSPierre Pronchery EVP_PKEY_ML_KEM_768,
223*e7be843bSPierre Pronchery EVP_PKEY_ML_KEM_1024
224*e7be843bSPierre Pronchery };
225*e7be843bSPierre Pronchery EVP_RAND_CTX *privctx;
226*e7be843bSPierre Pronchery EVP_RAND_CTX *pubctx;
227*e7be843bSPierre Pronchery EVP_MD *sha256;
228*e7be843bSPierre Pronchery int i, ret = 0;
229*e7be843bSPierre Pronchery
230*e7be843bSPierre Pronchery if (!TEST_ptr(privctx = RAND_get0_private(NULL))
231*e7be843bSPierre Pronchery || !TEST_ptr(pubctx = RAND_get0_public(NULL)))
232*e7be843bSPierre Pronchery return 0;
233*e7be843bSPierre Pronchery
234*e7be843bSPierre Pronchery if (!TEST_ptr(sha256 = EVP_MD_fetch(NULL, "sha256", NULL)))
235*e7be843bSPierre Pronchery return 0;
236*e7be843bSPierre Pronchery
237*e7be843bSPierre Pronchery for (i = 0; i < (int) OSSL_NELEM(alg); ++i) {
238*e7be843bSPierre Pronchery const ML_KEM_VINFO *v;
239*e7be843bSPierre Pronchery OSSL_PARAM params[3], *p;
240*e7be843bSPierre Pronchery uint8_t hash[32];
241*e7be843bSPierre Pronchery EVP_PKEY *akey = NULL, *bkey = NULL;
242*e7be843bSPierre Pronchery size_t publen;
243*e7be843bSPierre Pronchery unsigned char *rawpub = NULL;
244*e7be843bSPierre Pronchery EVP_PKEY_CTX *ctx = NULL;
245*e7be843bSPierre Pronchery unsigned char *wrpkey = NULL, *agenkey = NULL, *bgenkey = NULL;
246*e7be843bSPierre Pronchery size_t wrpkeylen, agenkeylen, bgenkeylen;
247*e7be843bSPierre Pronchery unsigned int strength = 256;
248*e7be843bSPierre Pronchery unsigned char c;
249*e7be843bSPierre Pronchery int res = -1;
250*e7be843bSPierre Pronchery
251*e7be843bSPierre Pronchery if ((v = ossl_ml_kem_get_vinfo(alg[i])) == NULL)
252*e7be843bSPierre Pronchery goto done;
253*e7be843bSPierre Pronchery
254*e7be843bSPierre Pronchery /* Configure the private RNG to output just the keygen seed */
255*e7be843bSPierre Pronchery p = params;
256*e7be843bSPierre Pronchery *p++ = OSSL_PARAM_construct_octet_string(OSSL_RAND_PARAM_TEST_ENTROPY,
257*e7be843bSPierre Pronchery gen_seed, sizeof(gen_seed));
258*e7be843bSPierre Pronchery *p++ = OSSL_PARAM_construct_uint(OSSL_RAND_PARAM_STRENGTH, &strength);
259*e7be843bSPierre Pronchery *p = OSSL_PARAM_construct_end();
260*e7be843bSPierre Pronchery if (!TEST_true(EVP_RAND_CTX_set_params(privctx, params)))
261*e7be843bSPierre Pronchery goto done;
262*e7be843bSPierre Pronchery
263*e7be843bSPierre Pronchery res = -2;
264*e7be843bSPierre Pronchery /* Generate Alice's key */
265*e7be843bSPierre Pronchery akey = EVP_PKEY_Q_keygen(testctx, NULL, v->algorithm_name);
266*e7be843bSPierre Pronchery if (!TEST_ptr(akey))
267*e7be843bSPierre Pronchery goto done;
268*e7be843bSPierre Pronchery
269*e7be843bSPierre Pronchery /* Check that no more entropy is available! */
270*e7be843bSPierre Pronchery if (!TEST_int_le(RAND_priv_bytes(&c, 1), 0))
271*e7be843bSPierre Pronchery goto done;
272*e7be843bSPierre Pronchery
273*e7be843bSPierre Pronchery /* Get the raw public key */
274*e7be843bSPierre Pronchery publen = EVP_PKEY_get1_encoded_public_key(akey, &rawpub);
275*e7be843bSPierre Pronchery if (!TEST_size_t_eq(publen, v->pubkey_bytes))
276*e7be843bSPierre Pronchery goto done;
277*e7be843bSPierre Pronchery
278*e7be843bSPierre Pronchery res = -3;
279*e7be843bSPierre Pronchery /* Check that we got the expected 'rho' value in the ciphertext */
280*e7be843bSPierre Pronchery if (!TEST_mem_eq(rawpub + v->vector_bytes, ML_KEM_RANDOM_BYTES,
281*e7be843bSPierre Pronchery expected_rho[i], ML_KEM_RANDOM_BYTES))
282*e7be843bSPierre Pronchery goto done;
283*e7be843bSPierre Pronchery
284*e7be843bSPierre Pronchery res = -4;
285*e7be843bSPierre Pronchery /* Create Bob's key and populate it with Alice's public key data */
286*e7be843bSPierre Pronchery bkey = EVP_PKEY_new();
287*e7be843bSPierre Pronchery if (!TEST_ptr(bkey))
288*e7be843bSPierre Pronchery goto done;
289*e7be843bSPierre Pronchery if (!TEST_int_gt(EVP_PKEY_copy_parameters(bkey, akey), 0))
290*e7be843bSPierre Pronchery goto done;
291*e7be843bSPierre Pronchery if (!TEST_true(EVP_PKEY_set1_encoded_public_key(bkey, rawpub, publen)))
292*e7be843bSPierre Pronchery goto done;
293*e7be843bSPierre Pronchery
294*e7be843bSPierre Pronchery /* Configure the public RNG to output just the encap seed */
295*e7be843bSPierre Pronchery p = params;
296*e7be843bSPierre Pronchery *p = OSSL_PARAM_construct_octet_string(OSSL_RAND_PARAM_TEST_ENTROPY,
297*e7be843bSPierre Pronchery enc_seed, sizeof(enc_seed));
298*e7be843bSPierre Pronchery if (!TEST_true(EVP_RAND_CTX_set_params(pubctx, params)))
299*e7be843bSPierre Pronchery goto done;
300*e7be843bSPierre Pronchery
301*e7be843bSPierre Pronchery /* Encapsulate Bob's key */
302*e7be843bSPierre Pronchery res = -5;
303*e7be843bSPierre Pronchery ctx = EVP_PKEY_CTX_new_from_pkey(testctx, bkey, NULL);
304*e7be843bSPierre Pronchery if (!TEST_ptr(ctx))
305*e7be843bSPierre Pronchery goto done;
306*e7be843bSPierre Pronchery if (!TEST_int_gt(EVP_PKEY_encapsulate_init(ctx, NULL), 0))
307*e7be843bSPierre Pronchery goto done;
308*e7be843bSPierre Pronchery if (!TEST_int_gt(EVP_PKEY_encapsulate(ctx, NULL, &wrpkeylen, NULL,
309*e7be843bSPierre Pronchery &bgenkeylen), 0))
310*e7be843bSPierre Pronchery goto done;
311*e7be843bSPierre Pronchery if (!TEST_size_t_eq(wrpkeylen, v->ctext_bytes)
312*e7be843bSPierre Pronchery || !TEST_size_t_eq(bgenkeylen, ML_KEM_SHARED_SECRET_BYTES))
313*e7be843bSPierre Pronchery goto done;
314*e7be843bSPierre Pronchery wrpkey = OPENSSL_zalloc(wrpkeylen);
315*e7be843bSPierre Pronchery bgenkey = OPENSSL_zalloc(bgenkeylen);
316*e7be843bSPierre Pronchery if (!TEST_ptr(wrpkey) || !TEST_ptr(bgenkey))
317*e7be843bSPierre Pronchery goto done;
318*e7be843bSPierre Pronchery if (!TEST_true(EVP_PKEY_encapsulate(ctx, wrpkey, &wrpkeylen, bgenkey,
319*e7be843bSPierre Pronchery &bgenkeylen)))
320*e7be843bSPierre Pronchery goto done;
321*e7be843bSPierre Pronchery EVP_PKEY_CTX_free(ctx);
322*e7be843bSPierre Pronchery ctx = NULL;
323*e7be843bSPierre Pronchery /* Check that no more public entropy is available! */
324*e7be843bSPierre Pronchery if (!TEST_int_le(RAND_bytes(&c, 1), 0))
325*e7be843bSPierre Pronchery goto done;
326*e7be843bSPierre Pronchery
327*e7be843bSPierre Pronchery res = -6;
328*e7be843bSPierre Pronchery /* Check the ciphertext hash */
329*e7be843bSPierre Pronchery if (!TEST_true(EVP_Digest(wrpkey, v->ctext_bytes,
330*e7be843bSPierre Pronchery hash, NULL, sha256, NULL))
331*e7be843bSPierre Pronchery || !TEST_mem_eq(hash, sizeof(hash),
332*e7be843bSPierre Pronchery expected_ctext_sha256[i],
333*e7be843bSPierre Pronchery sizeof(expected_ctext_sha256[i])))
334*e7be843bSPierre Pronchery goto done;
335*e7be843bSPierre Pronchery /* Check for the expected shared secret */
336*e7be843bSPierre Pronchery if (!TEST_mem_eq(bgenkey, bgenkeylen,
337*e7be843bSPierre Pronchery expected_shared_secret[i], ML_KEM_SHARED_SECRET_BYTES))
338*e7be843bSPierre Pronchery goto done;
339*e7be843bSPierre Pronchery
340*e7be843bSPierre Pronchery /*
341*e7be843bSPierre Pronchery * Alice now decapsulates Bob's key. Decap should not need a seed if
342*e7be843bSPierre Pronchery * the ciphertext length is good.
343*e7be843bSPierre Pronchery */
344*e7be843bSPierre Pronchery res = -7;
345*e7be843bSPierre Pronchery ctx = EVP_PKEY_CTX_new_from_pkey(testctx, akey, NULL);
346*e7be843bSPierre Pronchery if (!TEST_ptr(ctx))
347*e7be843bSPierre Pronchery goto done;
348*e7be843bSPierre Pronchery if (!TEST_int_gt(EVP_PKEY_decapsulate_init(ctx, NULL), 0))
349*e7be843bSPierre Pronchery goto done;
350*e7be843bSPierre Pronchery if (!TEST_true(EVP_PKEY_decapsulate(ctx, NULL, &agenkeylen, wrpkey,
351*e7be843bSPierre Pronchery wrpkeylen)))
352*e7be843bSPierre Pronchery goto done;
353*e7be843bSPierre Pronchery if (!TEST_size_t_eq(agenkeylen, ML_KEM_SHARED_SECRET_BYTES))
354*e7be843bSPierre Pronchery goto done;
355*e7be843bSPierre Pronchery agenkey = OPENSSL_zalloc(agenkeylen);
356*e7be843bSPierre Pronchery if (!TEST_ptr(agenkey))
357*e7be843bSPierre Pronchery goto done;
358*e7be843bSPierre Pronchery if (!TEST_true(EVP_PKEY_decapsulate(ctx, agenkey, &agenkeylen, wrpkey,
359*e7be843bSPierre Pronchery wrpkeylen)))
360*e7be843bSPierre Pronchery goto done;
361*e7be843bSPierre Pronchery /* Hopefully we ended up with a shared key */
362*e7be843bSPierre Pronchery if (!TEST_mem_eq(agenkey, agenkeylen, bgenkey, bgenkeylen))
363*e7be843bSPierre Pronchery goto done;
364*e7be843bSPierre Pronchery
365*e7be843bSPierre Pronchery res = -8;
366*e7be843bSPierre Pronchery /* Now a quick negative test by zeroing the ciphertext */
367*e7be843bSPierre Pronchery memset(wrpkey, 0, v->ctext_bytes);
368*e7be843bSPierre Pronchery if (!TEST_true(EVP_PKEY_decapsulate(ctx, agenkey, &agenkeylen, wrpkey,
369*e7be843bSPierre Pronchery wrpkeylen)))
370*e7be843bSPierre Pronchery goto done;
371*e7be843bSPierre Pronchery if (!TEST_mem_ne(agenkey, agenkeylen, bgenkey, bgenkeylen))
372*e7be843bSPierre Pronchery goto done;
373*e7be843bSPierre Pronchery
374*e7be843bSPierre Pronchery res = -9;
375*e7be843bSPierre Pronchery /* Configure decap entropy for a bad ciphertext length */
376*e7be843bSPierre Pronchery p = params;
377*e7be843bSPierre Pronchery *p = OSSL_PARAM_construct_octet_string(OSSL_RAND_PARAM_TEST_ENTROPY,
378*e7be843bSPierre Pronchery dec_seed, sizeof(dec_seed));
379*e7be843bSPierre Pronchery if (!TEST_true(EVP_RAND_CTX_set_params(pubctx, params)))
380*e7be843bSPierre Pronchery goto done;
381*e7be843bSPierre Pronchery
382*e7be843bSPierre Pronchery /* This time decap should fail, and return the decap entropy */
383*e7be843bSPierre Pronchery if (!TEST_false(EVP_PKEY_decapsulate(ctx, agenkey, &agenkeylen, wrpkey,
384*e7be843bSPierre Pronchery wrpkeylen - 1)))
385*e7be843bSPierre Pronchery goto done;
386*e7be843bSPierre Pronchery if (!TEST_mem_eq(agenkey, agenkeylen, dec_seed, sizeof(dec_seed)))
387*e7be843bSPierre Pronchery goto done;
388*e7be843bSPierre Pronchery
389*e7be843bSPierre Pronchery res = 0;
390*e7be843bSPierre Pronchery
391*e7be843bSPierre Pronchery done:
392*e7be843bSPierre Pronchery EVP_PKEY_CTX_free(ctx);
393*e7be843bSPierre Pronchery EVP_PKEY_free(akey);
394*e7be843bSPierre Pronchery EVP_PKEY_free(bkey);
395*e7be843bSPierre Pronchery OPENSSL_free(rawpub);
396*e7be843bSPierre Pronchery OPENSSL_free(wrpkey);
397*e7be843bSPierre Pronchery OPENSSL_free(agenkey);
398*e7be843bSPierre Pronchery OPENSSL_free(bgenkey);
399*e7be843bSPierre Pronchery if (res != 0)
400*e7be843bSPierre Pronchery ret = res;
401*e7be843bSPierre Pronchery }
402*e7be843bSPierre Pronchery
403*e7be843bSPierre Pronchery EVP_MD_free(sha256);
404*e7be843bSPierre Pronchery return ret == 0;
405*e7be843bSPierre Pronchery }
406*e7be843bSPierre Pronchery
setup_tests(void)407*e7be843bSPierre Pronchery int setup_tests(void)
408*e7be843bSPierre Pronchery {
409*e7be843bSPierre Pronchery int test_rand = 0;
410*e7be843bSPierre Pronchery OPTION_CHOICE o;
411*e7be843bSPierre Pronchery
412*e7be843bSPierre Pronchery while ((o = opt_next()) != OPT_EOF) {
413*e7be843bSPierre Pronchery switch (o) {
414*e7be843bSPierre Pronchery case OPT_TEST_RAND:
415*e7be843bSPierre Pronchery test_rand = 1;
416*e7be843bSPierre Pronchery break;
417*e7be843bSPierre Pronchery case OPT_TEST_CASES:
418*e7be843bSPierre Pronchery break;
419*e7be843bSPierre Pronchery default:
420*e7be843bSPierre Pronchery return 0;
421*e7be843bSPierre Pronchery }
422*e7be843bSPierre Pronchery }
423*e7be843bSPierre Pronchery
424*e7be843bSPierre Pronchery if (test_rand != 0) {
425*e7be843bSPierre Pronchery /* Cargo-culted from test/rand_test.c, this may need changes */
426*e7be843bSPierre Pronchery if (!TEST_true(RAND_set_DRBG_type(NULL, "TEST-RAND", "fips=no",
427*e7be843bSPierre Pronchery NULL, NULL)))
428*e7be843bSPierre Pronchery return 0;
429*e7be843bSPierre Pronchery ADD_TEST(test_non_derandomised_ml_kem);
430*e7be843bSPierre Pronchery return 1;
431*e7be843bSPierre Pronchery }
432*e7be843bSPierre Pronchery
433*e7be843bSPierre Pronchery ADD_TEST(test_ml_kem);
434*e7be843bSPierre Pronchery return 1;
435*e7be843bSPierre Pronchery }
436