• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2024 The BoringSSL Authors
2  *
3  * Permission to use, copy, modify, and/or distribute this software for any
4  * purpose with or without fee is hereby granted, provided that the above
5  * copyright notice and this permission notice appear in all copies.
6  *
7  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14 
15 #include <cstdint>
16 #include <vector>
17 
18 #include <string.h>
19 
20 #include <gtest/gtest.h>
21 
22 #include <openssl/base.h>
23 #include <openssl/bytestring.h>
24 #include <openssl/mem.h>
25 #include <openssl/mlkem.h>
26 
27 #include "../fipsmodule/bcm_interface.h"
28 #include "../fipsmodule/keccak/internal.h"
29 #include "../internal.h"
30 #include "../test/file_test.h"
31 #include "../test/test_util.h"
32 
33 
34 namespace {
35 
36 template <typename T>
Marshal(int (* marshal_func)(CBB *,const T *),const T * t)37 std::vector<uint8_t> Marshal(int (*marshal_func)(CBB *, const T *),
38                              const T *t) {
39   bssl::ScopedCBB cbb;
40   uint8_t *encoded;
41   size_t encoded_len;
42   if (!CBB_init(cbb.get(), 1) ||      //
43       !marshal_func(cbb.get(), t) ||  //
44       !CBB_finish(cbb.get(), &encoded, &encoded_len)) {
45     abort();
46   }
47 
48   std::vector<uint8_t> ret(encoded, encoded + encoded_len);
49   OPENSSL_free(encoded);
50   return ret;
51 }
52 
53 // These functions wrap the methods that are only in the BCM interface. They
54 // take care of casting the key types from the public keys to the BCM types.
55 // That saves casting noise in the template functions.
56 
wrapper_768_marshal_private_key(CBB * out,const struct MLKEM768_private_key * private_key)57 int wrapper_768_marshal_private_key(
58     CBB *out, const struct MLKEM768_private_key *private_key) {
59   return bcm_success(BCM_mlkem768_marshal_private_key(
60       out, reinterpret_cast<const BCM_mlkem768_private_key *>(private_key)));
61 }
62 
wrapper_1024_marshal_private_key(CBB * out,const struct MLKEM1024_private_key * private_key)63 int wrapper_1024_marshal_private_key(
64     CBB *out, const struct MLKEM1024_private_key *private_key) {
65   return bcm_success(BCM_mlkem1024_marshal_private_key(
66       out, reinterpret_cast<const BCM_mlkem1024_private_key *>(private_key)));
67 }
68 
wrapper_768_generate_key_external_seed(uint8_t out_encoded_public_key[MLKEM768_PUBLIC_KEY_BYTES],struct MLKEM768_private_key * out_private_key,const uint8_t seed[MLKEM_SEED_BYTES])69 void wrapper_768_generate_key_external_seed(
70     uint8_t out_encoded_public_key[MLKEM768_PUBLIC_KEY_BYTES],
71     struct MLKEM768_private_key *out_private_key,
72     const uint8_t seed[MLKEM_SEED_BYTES]) {
73   BCM_mlkem768_generate_key_external_seed(
74       out_encoded_public_key,
75       reinterpret_cast<BCM_mlkem768_private_key *>(out_private_key), seed);
76 }
77 
wrapper_1024_generate_key_external_seed(uint8_t out_encoded_public_key[MLKEM1024_PUBLIC_KEY_BYTES],struct MLKEM1024_private_key * out_private_key,const uint8_t seed[MLKEM_SEED_BYTES])78 void wrapper_1024_generate_key_external_seed(
79     uint8_t out_encoded_public_key[MLKEM1024_PUBLIC_KEY_BYTES],
80     struct MLKEM1024_private_key *out_private_key,
81     const uint8_t seed[MLKEM_SEED_BYTES]) {
82   BCM_mlkem1024_generate_key_external_seed(
83       out_encoded_public_key,
84       reinterpret_cast<BCM_mlkem1024_private_key *>(out_private_key), seed);
85 }
86 
wrapper_768_encap_external_entropy(uint8_t out_ciphertext[MLKEM768_CIPHERTEXT_BYTES],uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES],const struct MLKEM768_public_key * public_key,const uint8_t entropy[BCM_MLKEM_ENCAP_ENTROPY])87 void wrapper_768_encap_external_entropy(
88     uint8_t out_ciphertext[MLKEM768_CIPHERTEXT_BYTES],
89     uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES],
90     const struct MLKEM768_public_key *public_key,
91     const uint8_t entropy[BCM_MLKEM_ENCAP_ENTROPY]) {
92   BCM_mlkem768_encap_external_entropy(
93       out_ciphertext, out_shared_secret,
94       reinterpret_cast<const BCM_mlkem768_public_key *>(public_key), entropy);
95 }
96 
wrapper_1024_encap_external_entropy(uint8_t out_ciphertext[MLKEM1024_CIPHERTEXT_BYTES],uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES],const struct MLKEM1024_public_key * public_key,const uint8_t entropy[BCM_MLKEM_ENCAP_ENTROPY])97 void wrapper_1024_encap_external_entropy(
98     uint8_t out_ciphertext[MLKEM1024_CIPHERTEXT_BYTES],
99     uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES],
100     const struct MLKEM1024_public_key *public_key,
101     const uint8_t entropy[BCM_MLKEM_ENCAP_ENTROPY]) {
102   BCM_mlkem1024_encap_external_entropy(
103       out_ciphertext, out_shared_secret,
104       reinterpret_cast<const BCM_mlkem1024_public_key *>(public_key), entropy);
105 }
106 
wrapper_768_parse_private_key(struct MLKEM768_private_key * out_private_key,CBS * in)107 int wrapper_768_parse_private_key(struct MLKEM768_private_key *out_private_key,
108                                   CBS *in) {
109   return bcm_success(BCM_mlkem768_parse_private_key(
110       reinterpret_cast<BCM_mlkem768_private_key *>(out_private_key), in));
111 }
112 
wrapper_1024_parse_private_key(struct MLKEM1024_private_key * out_private_key,CBS * in)113 int wrapper_1024_parse_private_key(
114     struct MLKEM1024_private_key *out_private_key, CBS *in) {
115   return bcm_success(BCM_mlkem1024_parse_private_key(
116       reinterpret_cast<BCM_mlkem1024_private_key *>(out_private_key), in));
117 }
118 
119 template <typename PUBLIC_KEY, size_t PUBLIC_KEY_BYTES, typename PRIVATE_KEY,
120           size_t PRIVATE_KEY_BYTES,
121           void (*GENERATE)(uint8_t *, uint8_t *, PRIVATE_KEY *),
122           int (*FROM_SEED)(PRIVATE_KEY *, const uint8_t *, size_t),
123           void (*PUBLIC_FROM_PRIVATE)(PUBLIC_KEY *, const PRIVATE_KEY *),
124           int (*PARSE_PUBLIC)(PUBLIC_KEY *, CBS *),
125           int (*MARSHAL_PUBLIC)(CBB *, const PUBLIC_KEY *),
126           int (*PARSE_PRIVATE)(PRIVATE_KEY *, CBS *),
127           int (*MARSHAL_PRIVATE)(CBB *, const PRIVATE_KEY *),
128           size_t CIPHERTEXT_BYTES,
129           void (*ENCAP)(uint8_t *, uint8_t *, const PUBLIC_KEY *),
130           int (*DECAP)(uint8_t *, const uint8_t *, size_t, const PRIVATE_KEY *)>
BasicTest()131 void BasicTest() {
132   // This function makes several ML-KEM keys, which runs up against stack
133   // limits. Heap-allocate them instead.
134 
135   uint8_t encoded_public_key[PUBLIC_KEY_BYTES];
136   uint8_t seed[MLKEM_SEED_BYTES];
137   auto priv = std::make_unique<PRIVATE_KEY>();
138   GENERATE(encoded_public_key, seed, priv.get());
139 
140   {
141     auto priv2 = std::make_unique<PRIVATE_KEY>();
142     ASSERT_TRUE(FROM_SEED(priv2.get(), seed, sizeof(seed)));
143     EXPECT_EQ(Bytes(Declassified(Marshal(MARSHAL_PRIVATE, priv.get()))),
144               Bytes(Declassified(Marshal(MARSHAL_PRIVATE, priv2.get()))));
145   }
146 
147   uint8_t first_two_bytes[2];
148   OPENSSL_memcpy(first_two_bytes, encoded_public_key, sizeof(first_two_bytes));
149   OPENSSL_memset(encoded_public_key, 0xff, sizeof(first_two_bytes));
150   CBS encoded_public_key_cbs;
151   CBS_init(&encoded_public_key_cbs, encoded_public_key,
152            sizeof(encoded_public_key));
153   auto pub = std::make_unique<PUBLIC_KEY>();
154   // Parsing should fail because the first coefficient is >= kPrime;
155   ASSERT_FALSE(PARSE_PUBLIC(pub.get(), &encoded_public_key_cbs));
156 
157   OPENSSL_memcpy(encoded_public_key, first_two_bytes, sizeof(first_two_bytes));
158   CBS_init(&encoded_public_key_cbs, encoded_public_key,
159            sizeof(encoded_public_key));
160   ASSERT_TRUE(PARSE_PUBLIC(pub.get(), &encoded_public_key_cbs));
161   EXPECT_EQ(CBS_len(&encoded_public_key_cbs), 0u);
162 
163   EXPECT_EQ(Bytes(encoded_public_key),
164             Bytes(Marshal(MARSHAL_PUBLIC, pub.get())));
165 
166   auto pub2 = std::make_unique<PUBLIC_KEY>();
167   PUBLIC_FROM_PRIVATE(pub2.get(), priv.get());
168   EXPECT_EQ(Bytes(encoded_public_key),
169             Bytes(Marshal(MARSHAL_PUBLIC, pub2.get())));
170 
171   std::vector<uint8_t> encoded_private_key(
172       Marshal(MARSHAL_PRIVATE, priv.get()));
173   EXPECT_EQ(encoded_private_key.size(), size_t{PRIVATE_KEY_BYTES});
174 
175   OPENSSL_memcpy(first_two_bytes, encoded_private_key.data(),
176                  sizeof(first_two_bytes));
177   OPENSSL_memset(encoded_private_key.data(), 0xff, sizeof(first_two_bytes));
178   CBS cbs;
179   CBS_init(&cbs, encoded_private_key.data(), encoded_private_key.size());
180   auto priv2 = std::make_unique<PRIVATE_KEY>();
181   // Parsing should fail because the first coefficient is >= kPrime.
182   ASSERT_FALSE(PARSE_PRIVATE(priv2.get(), &cbs));
183 
184   OPENSSL_memcpy(encoded_private_key.data(), first_two_bytes,
185                  sizeof(first_two_bytes));
186   CBS_init(&cbs, encoded_private_key.data(), encoded_private_key.size());
187   ASSERT_TRUE(PARSE_PRIVATE(priv2.get(), &cbs));
188   EXPECT_EQ(Bytes(Declassified(encoded_private_key)),
189             Bytes(Declassified(Marshal(MARSHAL_PRIVATE, priv2.get()))));
190 
191   uint8_t ciphertext[CIPHERTEXT_BYTES];
192   uint8_t shared_secret1[MLKEM_SHARED_SECRET_BYTES];
193   uint8_t shared_secret2[MLKEM_SHARED_SECRET_BYTES];
194   ENCAP(ciphertext, shared_secret1, pub.get());
195   ASSERT_TRUE(
196       DECAP(shared_secret2, ciphertext, sizeof(ciphertext), priv.get()));
197   EXPECT_EQ(Bytes(Declassified(shared_secret1)),
198             Bytes(Declassified(shared_secret2)));
199   ASSERT_TRUE(
200       DECAP(shared_secret2, ciphertext, sizeof(ciphertext), priv2.get()));
201   EXPECT_EQ(Bytes(Declassified(shared_secret1)),
202             Bytes(Declassified(shared_secret2)));
203 }
204 
TEST(MLKEMTest,Basic768)205 TEST(MLKEMTest, Basic768) {
206   BasicTest<MLKEM768_public_key, MLKEM768_PUBLIC_KEY_BYTES,
207             MLKEM768_private_key, BCM_MLKEM768_PRIVATE_KEY_BYTES,
208             MLKEM768_generate_key, MLKEM768_private_key_from_seed,
209             MLKEM768_public_from_private, MLKEM768_parse_public_key,
210             MLKEM768_marshal_public_key, wrapper_768_parse_private_key,
211             wrapper_768_marshal_private_key, MLKEM768_CIPHERTEXT_BYTES,
212             MLKEM768_encap, MLKEM768_decap>();
213 }
214 
TEST(MLKEMTest,Basic1024)215 TEST(MLKEMTest, Basic1024) {
216   BasicTest<MLKEM1024_public_key, MLKEM1024_PUBLIC_KEY_BYTES,
217             MLKEM1024_private_key, BCM_MLKEM1024_PRIVATE_KEY_BYTES,
218             MLKEM1024_generate_key, MLKEM1024_private_key_from_seed,
219             MLKEM1024_public_from_private, MLKEM1024_parse_public_key,
220             MLKEM1024_marshal_public_key, wrapper_1024_parse_private_key,
221             wrapper_1024_marshal_private_key, MLKEM1024_CIPHERTEXT_BYTES,
222             MLKEM1024_encap, MLKEM1024_decap>();
223 }
224 
225 template <typename PUBLIC_KEY, size_t PUBLIC_KEY_BYTES, typename PRIVATE_KEY,
226           int (*MARSHAL_PRIVATE)(CBB *, const PRIVATE_KEY *),
227           void (*GENERATE)(uint8_t *, PRIVATE_KEY *, const uint8_t *)>
MLKEMKeyGenFileTest(FileTest * t)228 void MLKEMKeyGenFileTest(FileTest *t) {
229   std::vector<uint8_t> expected_pub_key_bytes, seed, expected_priv_key_bytes;
230   ASSERT_TRUE(t->GetBytes(&seed, "seed"));
231   CONSTTIME_SECRET(seed.data(), seed.size());
232   ASSERT_TRUE(t->GetBytes(&expected_pub_key_bytes, "public_key"));
233   ASSERT_TRUE(t->GetBytes(&expected_priv_key_bytes, "private_key"));
234 
235   ASSERT_EQ(seed.size(), size_t{MLKEM_SEED_BYTES});
236 
237   std::vector<uint8_t> pub_key_bytes(PUBLIC_KEY_BYTES);
238   auto priv = std::make_unique<PRIVATE_KEY>();
239   GENERATE(pub_key_bytes.data(), priv.get(), seed.data());
240   const std::vector<uint8_t> priv_key_bytes(
241       Marshal(MARSHAL_PRIVATE, priv.get()));
242 
243   EXPECT_EQ(Bytes(pub_key_bytes), Bytes(expected_pub_key_bytes));
244   EXPECT_EQ(Bytes(Declassified(priv_key_bytes)),
245             Bytes(expected_priv_key_bytes));
246 }
247 
TEST(MLKEMTest,KeyGen768TestVectors)248 TEST(MLKEMTest, KeyGen768TestVectors) {
249   FileTestGTest(
250       "crypto/mlkem/mlkem768_keygen_tests.txt",
251       MLKEMKeyGenFileTest<MLKEM768_public_key, MLKEM768_PUBLIC_KEY_BYTES,
252                           MLKEM768_private_key, wrapper_768_marshal_private_key,
253                           wrapper_768_generate_key_external_seed>);
254 }
255 
TEST(MLKEMTest,KeyGen1024TestVectors)256 TEST(MLKEMTest, KeyGen1024TestVectors) {
257   FileTestGTest(
258       "crypto/mlkem/mlkem1024_keygen_tests.txt",
259       MLKEMKeyGenFileTest<MLKEM1024_public_key, MLKEM1024_PUBLIC_KEY_BYTES,
260                           MLKEM1024_private_key,
261                           wrapper_1024_marshal_private_key,
262                           wrapper_1024_generate_key_external_seed>);
263 }
264 
265 template <typename PUBLIC_KEY, size_t PUBLIC_KEY_BYTES, typename PRIVATE_KEY,
266           int (*MARSHAL_PRIVATE)(CBB *, const PRIVATE_KEY *),
267           void (*GENERATE)(uint8_t *, PRIVATE_KEY *, const uint8_t *)>
MLKEMNistKeyGenFileTest(FileTest * t)268 void MLKEMNistKeyGenFileTest(FileTest *t) {
269   std::vector<uint8_t> expected_pub_key_bytes, z, d, expected_priv_key_bytes;
270   ASSERT_TRUE(t->GetBytes(&z, "z"));
271   ASSERT_TRUE(t->GetBytes(&d, "d"));
272   ASSERT_TRUE(t->GetBytes(&expected_pub_key_bytes, "ek"));
273   ASSERT_TRUE(t->GetBytes(&expected_priv_key_bytes, "dk"));
274 
275   ASSERT_EQ(z.size(), size_t{MLKEM_SEED_BYTES} / 2);
276   ASSERT_EQ(d.size(), size_t{MLKEM_SEED_BYTES} / 2);
277 
278   uint8_t seed[MLKEM_SEED_BYTES];
279   OPENSSL_memcpy(&seed[0], d.data(), d.size());
280   OPENSSL_memcpy(&seed[MLKEM_SEED_BYTES / 2], z.data(), z.size());
281   std::vector<uint8_t> pub_key_bytes(PUBLIC_KEY_BYTES);
282   auto priv = std::make_unique<PRIVATE_KEY>();
283   GENERATE(pub_key_bytes.data(), priv.get(), seed);
284   const std::vector<uint8_t> priv_key_bytes(
285       Marshal(MARSHAL_PRIVATE, priv.get()));
286 
287   EXPECT_EQ(Bytes(pub_key_bytes), Bytes(expected_pub_key_bytes));
288   EXPECT_EQ(Bytes(priv_key_bytes), Bytes(expected_priv_key_bytes));
289 }
290 
TEST(MLKEMTest,NISTKeyGen768TestVectors)291 TEST(MLKEMTest, NISTKeyGen768TestVectors) {
292   FileTestGTest(
293       "crypto/mlkem/mlkem768_nist_keygen_tests.txt",
294       MLKEMNistKeyGenFileTest<MLKEM768_public_key, MLKEM768_PUBLIC_KEY_BYTES,
295                               MLKEM768_private_key,
296                               wrapper_768_marshal_private_key,
297                               wrapper_768_generate_key_external_seed>);
298 }
299 
TEST(MLKEMTest,NISTKeyGen1024TestVectors)300 TEST(MLKEMTest, NISTKeyGen1024TestVectors) {
301   FileTestGTest(
302       "crypto/mlkem/mlkem1024_nist_keygen_tests.txt",
303       MLKEMNistKeyGenFileTest<MLKEM1024_public_key, MLKEM1024_PUBLIC_KEY_BYTES,
304                               MLKEM1024_private_key,
305                               wrapper_1024_marshal_private_key,
306                               wrapper_1024_generate_key_external_seed>);
307 }
308 
309 template <typename PUBLIC_KEY, size_t PUBLIC_KEY_BYTES,
310           int (*PARSE_PUBLIC)(PUBLIC_KEY *, CBS *), size_t CIPHERTEXT_BYTES,
311           void (*ENCAP)(uint8_t *, uint8_t *, const PUBLIC_KEY *,
312                         const uint8_t *)>
MLKEMEncapFileTest(FileTest * t)313 void MLKEMEncapFileTest(FileTest *t) {
314   std::vector<uint8_t> pub_key_bytes, entropy, expected_ciphertext,
315       expected_shared_secret;
316   ASSERT_TRUE(t->GetBytes(&entropy, "entropy"));
317   CONSTTIME_SECRET(entropy.data(), entropy.size());
318   ASSERT_TRUE(t->GetBytes(&pub_key_bytes, "public_key"));
319   ASSERT_TRUE(t->GetBytes(&expected_ciphertext, "ciphertext"));
320   ASSERT_TRUE(t->GetBytes(&expected_shared_secret, "shared_secret"));
321   std::string result;
322   ASSERT_TRUE(t->GetAttribute(&result, "result"));
323 
324   PUBLIC_KEY pub_key;
325   CBS pub_key_cbs;
326   CBS_init(&pub_key_cbs, pub_key_bytes.data(), pub_key_bytes.size());
327   const int parse_ok = PARSE_PUBLIC(&pub_key, &pub_key_cbs);
328   ASSERT_EQ(parse_ok, result == "pass");
329   if (!parse_ok) {
330     return;
331   }
332 
333   uint8_t ciphertext[CIPHERTEXT_BYTES];
334   uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES];
335   ENCAP(ciphertext, shared_secret, &pub_key, entropy.data());
336 
337   ASSERT_EQ(Bytes(expected_ciphertext), Bytes(ciphertext));
338   ASSERT_EQ(Bytes(expected_shared_secret), Bytes(Declassified(shared_secret)));
339 }
340 
TEST(MLKEMTest,Encap768TestVectors)341 TEST(MLKEMTest, Encap768TestVectors) {
342   FileTestGTest(
343       "crypto/mlkem/mlkem768_encap_tests.txt",
344       MLKEMEncapFileTest<MLKEM768_public_key, MLKEM768_PUBLIC_KEY_BYTES,
345                          MLKEM768_parse_public_key, MLKEM768_CIPHERTEXT_BYTES,
346                          wrapper_768_encap_external_entropy>);
347 }
348 
TEST(MLKEMTest,Encap1024TestVectors)349 TEST(MLKEMTest, Encap1024TestVectors) {
350   FileTestGTest(
351       "crypto/mlkem/mlkem1024_encap_tests.txt",
352       MLKEMEncapFileTest<MLKEM1024_public_key, MLKEM1024_PUBLIC_KEY_BYTES,
353                          MLKEM1024_parse_public_key, MLKEM1024_CIPHERTEXT_BYTES,
354                          wrapper_1024_encap_external_entropy>);
355 }
356 
357 template <typename PRIVATE_KEY, size_t PRIVATE_KEY_BYTES,
358           int (*PARSE_PRIVATE)(PRIVATE_KEY *, CBS *), size_t CIPHERTEXT_BYTES,
359           int (*DECAP)(uint8_t *, const uint8_t *, size_t, const PRIVATE_KEY *)>
MLKEMDecapFileTest(FileTest * t)360 void MLKEMDecapFileTest(FileTest *t) {
361   std::vector<uint8_t> priv_key_bytes, ciphertext, expected_shared_secret;
362   ASSERT_TRUE(t->GetBytes(&priv_key_bytes, "private_key"));
363   ASSERT_TRUE(t->GetBytes(&ciphertext, "ciphertext"));
364   ASSERT_TRUE(t->GetBytes(&expected_shared_secret, "shared_secret"));
365   std::string result;
366   ASSERT_TRUE(t->GetAttribute(&result, "result"));
367 
368   PRIVATE_KEY priv_key;
369   CBS priv_key_cbs;
370   CBS_init(&priv_key_cbs, priv_key_bytes.data(), priv_key_bytes.size());
371   const int parse_ok = PARSE_PRIVATE(&priv_key, &priv_key_cbs);
372   if (!parse_ok) {
373     ASSERT_NE(result, "pass");
374     return;
375   }
376 
377   uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES];
378   const int decap_ok =
379       DECAP(shared_secret, ciphertext.data(), ciphertext.size(), &priv_key);
380   if (!decap_ok) {
381     ASSERT_NE(result, "pass");
382     return;
383   }
384 
385   ASSERT_EQ(Bytes(expected_shared_secret), Bytes(shared_secret));
386 }
387 
TEST(MLKEMTest,Decap768TestVectors)388 TEST(MLKEMTest, Decap768TestVectors) {
389   FileTestGTest(
390       "crypto/mlkem/mlkem768_decap_tests.txt",
391       MLKEMDecapFileTest<MLKEM768_private_key, BCM_MLKEM768_PRIVATE_KEY_BYTES,
392                          wrapper_768_parse_private_key,
393                          MLKEM768_CIPHERTEXT_BYTES, MLKEM768_decap>);
394 }
395 
TEST(MLKEMTest,Decap1024TestVectors)396 TEST(MLKEMTest, Decap1024TestVectors) {
397   FileTestGTest(
398       "crypto/mlkem/mlkem1024_decap_tests.txt",
399       MLKEMDecapFileTest<MLKEM1024_private_key, BCM_MLKEM1024_PRIVATE_KEY_BYTES,
400                          wrapper_1024_parse_private_key,
401                          MLKEM1024_CIPHERTEXT_BYTES, MLKEM1024_decap>);
402 }
403 
404 template <typename PRIVATE_KEY, int (*PARSE_PRIVATE)(PRIVATE_KEY *, CBS *),
405           int (*DECAP)(uint8_t *, const uint8_t *, size_t, const PRIVATE_KEY *)>
MLKEMNistDecapFileTest(FileTest * t)406 void MLKEMNistDecapFileTest(FileTest *t) {
407   std::vector<uint8_t> ciphertext, expected_shared_secret, private_key_bytes;
408   ASSERT_TRUE(t->GetBytes(&ciphertext, "c"));
409   ASSERT_TRUE(t->GetBytes(&expected_shared_secret, "k"));
410   ASSERT_TRUE(t->GetInstructionBytes(&private_key_bytes, "dk"));
411 
412   PRIVATE_KEY priv;
413   CBS private_key_cbs;
414   CBS_init(&private_key_cbs, private_key_bytes.data(),
415            private_key_bytes.size());
416   ASSERT_TRUE(PARSE_PRIVATE(&priv, &private_key_cbs));
417 
418   uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES];
419   ASSERT_TRUE(
420       DECAP(shared_secret, ciphertext.data(), ciphertext.size(), &priv));
421 
422   ASSERT_EQ(Bytes(shared_secret), Bytes(expected_shared_secret));
423 }
424 
TEST(MLKEMTest,NistDecap768TestVectors)425 TEST(MLKEMTest, NistDecap768TestVectors) {
426   FileTestGTest(
427       "crypto/mlkem/mlkem768_nist_decap_tests.txt",
428       MLKEMNistDecapFileTest<MLKEM768_private_key,
429                              wrapper_768_parse_private_key, MLKEM768_decap>);
430 }
431 
TEST(MLKEMTest,NistDecap1024TestVectors)432 TEST(MLKEMTest, NistDecap1024TestVectors) {
433   FileTestGTest(
434       "crypto/mlkem/mlkem1024_nist_decap_tests.txt",
435       MLKEMNistDecapFileTest<MLKEM1024_private_key,
436                              wrapper_1024_parse_private_key, MLKEM1024_decap>);
437 }
438 
439 template <
440     typename PUBLIC_KEY, size_t PUBLIC_KEY_BYTES, typename PRIVATE_KEY,
441     size_t PRIVATE_KEY_BYTES,
442     void (*GENERATE)(uint8_t *, PRIVATE_KEY *, const uint8_t *),
443     void (*TO_PUBLIC)(PUBLIC_KEY *, const PRIVATE_KEY *),
444     int (*MARSHAL_PRIVATE)(CBB *, const PRIVATE_KEY *), size_t CIPHERTEXT_BYTES,
445     void (*ENCAP)(uint8_t *, uint8_t *, const PUBLIC_KEY *, const uint8_t *),
446     int (*DECAP)(uint8_t *, const uint8_t *, size_t, const PRIVATE_KEY *)>
IteratedTest(uint8_t out[32])447 void IteratedTest(uint8_t out[32]) {
448   BORINGSSL_keccak_st generate_st;
449   BORINGSSL_keccak_init(&generate_st, boringssl_shake128);
450   BORINGSSL_keccak_st results_st;
451   BORINGSSL_keccak_init(&results_st, boringssl_shake128);
452 
453   auto priv = std::make_unique<PRIVATE_KEY>();
454   auto pub = std::make_unique<PUBLIC_KEY>();
455   for (int i = 0; i < 10000; i++) {
456     uint8_t seed[MLKEM_SEED_BYTES];
457     BORINGSSL_keccak_squeeze(&generate_st, seed, sizeof(seed));
458     uint8_t encoded_pub[PUBLIC_KEY_BYTES];
459     GENERATE(encoded_pub, priv.get(), seed);
460     TO_PUBLIC(pub.get(), priv.get());
461 
462     BORINGSSL_keccak_absorb(&results_st, encoded_pub, sizeof(encoded_pub));
463     const std::vector<uint8_t> encoded_priv(
464         Marshal(MARSHAL_PRIVATE, priv.get()));
465     BORINGSSL_keccak_absorb(&results_st, encoded_priv.data(),
466                             encoded_priv.size());
467 
468     uint8_t encap_entropy[BCM_MLKEM_ENCAP_ENTROPY];
469     BORINGSSL_keccak_squeeze(&generate_st, encap_entropy,
470                              sizeof(encap_entropy));
471     uint8_t ciphertext[CIPHERTEXT_BYTES];
472     uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES];
473     ENCAP(ciphertext, shared_secret, pub.get(), encap_entropy);
474 
475     BORINGSSL_keccak_absorb(&results_st, ciphertext, sizeof(ciphertext));
476     BORINGSSL_keccak_absorb(&results_st, shared_secret, sizeof(shared_secret));
477 
478     uint8_t invalid_ciphertext[CIPHERTEXT_BYTES];
479     BORINGSSL_keccak_squeeze(&generate_st, invalid_ciphertext,
480                              sizeof(invalid_ciphertext));
481     ASSERT_TRUE(DECAP(shared_secret, invalid_ciphertext,
482                       sizeof(invalid_ciphertext), priv.get()));
483 
484     BORINGSSL_keccak_absorb(&results_st, shared_secret, sizeof(shared_secret));
485   }
486 
487   BORINGSSL_keccak_squeeze(&results_st, out, 32);
488 }
489 
TEST(MLKEMTest,Iterate768)490 TEST(MLKEMTest, Iterate768) {
491   // The structure of this test is taken from
492   // https://github.com/C2SP/CCTV/blob/main/ML-KEM/README.md?ref=words.filippo.io#accumulated-pq-crystals-vectors
493   // but the final value has been updated to reflect the change from Kyber to
494   // ML-KEM.
495   uint8_t result[32];
496   IteratedTest<MLKEM768_public_key, MLKEM768_PUBLIC_KEY_BYTES,
497                MLKEM768_private_key, BCM_MLKEM768_PRIVATE_KEY_BYTES,
498                wrapper_768_generate_key_external_seed,
499                MLKEM768_public_from_private, wrapper_768_marshal_private_key,
500                MLKEM768_CIPHERTEXT_BYTES, wrapper_768_encap_external_entropy,
501                MLKEM768_decap>(result);
502 
503   const uint8_t kExpected[32] = {
504       0xf9, 0x59, 0xd1, 0x8d, 0x3d, 0x11, 0x80, 0x12, 0x14, 0x33, 0xbf,
505       0x0e, 0x05, 0xf1, 0x1e, 0x79, 0x08, 0xcf, 0x9d, 0x03, 0xed, 0xc1,
506       0x50, 0xb2, 0xb0, 0x7c, 0xb9, 0x0b, 0xef, 0x5b, 0xc1, 0xc1};
507   EXPECT_EQ(Bytes(result), Bytes(kExpected));
508 }
509 
510 
TEST(MLKEMTest,Iterate1024)511 TEST(MLKEMTest, Iterate1024) {
512   // The structure of this test is taken from
513   // https://github.com/C2SP/CCTV/blob/main/ML-KEM/README.md?ref=words.filippo.io#accumulated-pq-crystals-vectors
514   // but the final value has been updated to reflect the change from Kyber to
515   // ML-KEM.
516   uint8_t result[32];
517   IteratedTest<MLKEM1024_public_key, MLKEM1024_PUBLIC_KEY_BYTES,
518                MLKEM1024_private_key, BCM_MLKEM1024_PRIVATE_KEY_BYTES,
519                wrapper_1024_generate_key_external_seed,
520                MLKEM1024_public_from_private, wrapper_1024_marshal_private_key,
521                MLKEM1024_CIPHERTEXT_BYTES, wrapper_1024_encap_external_entropy,
522                MLKEM1024_decap>(result);
523 
524   const uint8_t kExpected[32] = {
525       0xe3, 0xbf, 0x82, 0xb0, 0x13, 0x30, 0x7b, 0x2e, 0x9d, 0x47, 0xdd,
526       0xe7, 0x91, 0xff, 0x6d, 0xfc, 0x82, 0xe6, 0x94, 0xe6, 0x38, 0x24,
527       0x04, 0xab, 0xdb, 0x94, 0x8b, 0x90, 0x8b, 0x75, 0xba, 0xd5};
528   EXPECT_EQ(Bytes(result), Bytes(kExpected));
529 }
530 
TEST(MLKEMTest,Self)531 TEST(MLKEMTest, Self) { ASSERT_TRUE(boringssl_self_test_mlkem()); }
532 
TEST(MLKEMTest,PWCT)533 TEST(MLKEMTest, PWCT) {
534   auto pub768 = std::make_unique<uint8_t[]>(BCM_MLKEM768_PUBLIC_KEY_BYTES);
535   auto priv768 = std::make_unique<BCM_mlkem768_private_key>();
536   ASSERT_EQ(
537       BCM_mlkem768_generate_key_fips(pub768.get(), nullptr, priv768.get()),
538       bcm_status::approved);
539 
540   auto pub1024 = std::make_unique<uint8_t[]>(BCM_MLKEM1024_PUBLIC_KEY_BYTES);
541   auto priv1024 = std::make_unique<BCM_mlkem1024_private_key>();
542   ASSERT_EQ(
543       BCM_mlkem1024_generate_key_fips(pub1024.get(), nullptr, priv1024.get()),
544       bcm_status::approved);
545 }
546 
547 }  // namespace
548