| /* Copyright (c) 2024, Google Inc. |
| * |
| * Permission to use, copy, modify, and/or distribute this software for any |
| * purpose with or without fee is hereby granted, provided that the above |
| * copyright notice and this permission notice appear in all copies. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
| * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
| * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ |
| |
| #include <cstdint> |
| #include <vector> |
| |
| #include <string.h> |
| |
| #include <gtest/gtest.h> |
| |
| #include <openssl/base.h> |
| #include <openssl/bytestring.h> |
| #include <openssl/mem.h> |
| #include <openssl/mlkem.h> |
| |
| #include "../keccak/internal.h" |
| #include "../test/file_test.h" |
| #include "../test/test_util.h" |
| #include "./internal.h" |
| |
| |
| namespace { |
| |
| template <typename T> |
| std::vector<uint8_t> Marshal(int (*marshal_func)(CBB *, const T *), |
| const T *t) { |
| bssl::ScopedCBB cbb; |
| uint8_t *encoded; |
| size_t encoded_len; |
| if (!CBB_init(cbb.get(), 1) || // |
| !marshal_func(cbb.get(), t) || // |
| !CBB_finish(cbb.get(), &encoded, &encoded_len)) { |
| abort(); |
| } |
| |
| std::vector<uint8_t> ret(encoded, encoded + encoded_len); |
| OPENSSL_free(encoded); |
| return ret; |
| } |
| |
| template <typename PUBLIC_KEY, size_t PUBLIC_KEY_BYTES, typename PRIVATE_KEY, |
| size_t PRIVATE_KEY_BYTES, |
| void (*GENERATE)(uint8_t *, uint8_t *, PRIVATE_KEY *), |
| int (*FROM_SEED)(PRIVATE_KEY *, const uint8_t *, size_t), |
| void PUBLIC_FROM_PRIVATE(PUBLIC_KEY *, const PRIVATE_KEY *), |
| int (*PARSE_PUBLIC)(PUBLIC_KEY *, CBS *), |
| int (*MARSHAL_PUBLIC)(CBB *, const PUBLIC_KEY *), |
| int (*PARSE_PRIVATE)(PRIVATE_KEY *, CBS *), |
| int (*MARSHAL_PRIVATE)(CBB *, const PRIVATE_KEY *), |
| size_t CIPHERTEXT_BYTES, |
| void (*ENCAP)(uint8_t *, uint8_t *, const PUBLIC_KEY *), |
| int (*DECAP)(uint8_t *, const uint8_t *, size_t, const PRIVATE_KEY *)> |
| void BasicTest() { |
| // This function makes several ML-KEM keys, which runs up against stack |
| // limits. Heap-allocate them instead. |
| |
| uint8_t encoded_public_key[PUBLIC_KEY_BYTES]; |
| uint8_t seed[MLKEM_SEED_BYTES]; |
| auto priv = std::make_unique<PRIVATE_KEY>(); |
| GENERATE(encoded_public_key, seed, priv.get()); |
| |
| { |
| auto priv2 = std::make_unique<PRIVATE_KEY>(); |
| ASSERT_TRUE(FROM_SEED(priv2.get(), seed, sizeof(seed))); |
| EXPECT_EQ(Bytes(Marshal(MARSHAL_PRIVATE, priv.get())), |
| Bytes(Marshal(MARSHAL_PRIVATE, priv2.get()))); |
| } |
| |
| uint8_t first_two_bytes[2]; |
| OPENSSL_memcpy(first_two_bytes, encoded_public_key, sizeof(first_two_bytes)); |
| OPENSSL_memset(encoded_public_key, 0xff, sizeof(first_two_bytes)); |
| CBS encoded_public_key_cbs; |
| CBS_init(&encoded_public_key_cbs, encoded_public_key, |
| sizeof(encoded_public_key)); |
| auto pub = std::make_unique<PUBLIC_KEY>(); |
| // Parsing should fail because the first coefficient is >= kPrime; |
| ASSERT_FALSE(PARSE_PUBLIC(pub.get(), &encoded_public_key_cbs)); |
| |
| OPENSSL_memcpy(encoded_public_key, first_two_bytes, sizeof(first_two_bytes)); |
| CBS_init(&encoded_public_key_cbs, encoded_public_key, |
| sizeof(encoded_public_key)); |
| ASSERT_TRUE(PARSE_PUBLIC(pub.get(), &encoded_public_key_cbs)); |
| EXPECT_EQ(CBS_len(&encoded_public_key_cbs), 0u); |
| |
| EXPECT_EQ(Bytes(encoded_public_key), |
| Bytes(Marshal(MARSHAL_PUBLIC, pub.get()))); |
| |
| auto pub2 = std::make_unique<PUBLIC_KEY>(); |
| PUBLIC_FROM_PRIVATE(pub2.get(), priv.get()); |
| EXPECT_EQ(Bytes(encoded_public_key), |
| Bytes(Marshal(MARSHAL_PUBLIC, pub2.get()))); |
| |
| std::vector<uint8_t> encoded_private_key( |
| Marshal(MARSHAL_PRIVATE, priv.get())); |
| EXPECT_EQ(encoded_private_key.size(), size_t{PRIVATE_KEY_BYTES}); |
| |
| OPENSSL_memcpy(first_two_bytes, encoded_private_key.data(), |
| sizeof(first_two_bytes)); |
| OPENSSL_memset(encoded_private_key.data(), 0xff, sizeof(first_two_bytes)); |
| CBS cbs; |
| CBS_init(&cbs, encoded_private_key.data(), encoded_private_key.size()); |
| auto priv2 = std::make_unique<PRIVATE_KEY>(); |
| // Parsing should fail because the first coefficient is >= kPrime. |
| ASSERT_FALSE(PARSE_PRIVATE(priv2.get(), &cbs)); |
| |
| OPENSSL_memcpy(encoded_private_key.data(), first_two_bytes, |
| sizeof(first_two_bytes)); |
| CBS_init(&cbs, encoded_private_key.data(), encoded_private_key.size()); |
| ASSERT_TRUE(PARSE_PRIVATE(priv2.get(), &cbs)); |
| EXPECT_EQ(Bytes(encoded_private_key), |
| Bytes(Marshal(MARSHAL_PRIVATE, priv2.get()))); |
| |
| uint8_t ciphertext[CIPHERTEXT_BYTES]; |
| uint8_t shared_secret1[MLKEM_SHARED_SECRET_BYTES]; |
| uint8_t shared_secret2[MLKEM_SHARED_SECRET_BYTES]; |
| ENCAP(ciphertext, shared_secret1, pub.get()); |
| ASSERT_TRUE( |
| DECAP(shared_secret2, ciphertext, sizeof(ciphertext), priv.get())); |
| EXPECT_EQ(Bytes(shared_secret1), Bytes(shared_secret2)); |
| ASSERT_TRUE( |
| DECAP(shared_secret2, ciphertext, sizeof(ciphertext), priv2.get())); |
| EXPECT_EQ(Bytes(shared_secret1), Bytes(shared_secret2)); |
| } |
| |
| TEST(MLKEMTest, Basic768) { |
| BasicTest<MLKEM768_public_key, MLKEM768_PUBLIC_KEY_BYTES, |
| MLKEM768_private_key, MLKEM768_PRIVATE_KEY_BYTES, |
| MLKEM768_generate_key, MLKEM768_private_key_from_seed, |
| MLKEM768_public_from_private, MLKEM768_parse_public_key, |
| MLKEM768_marshal_public_key, MLKEM768_parse_private_key, |
| MLKEM768_marshal_private_key, MLKEM768_CIPHERTEXT_BYTES, |
| MLKEM768_encap, MLKEM768_decap>(); |
| } |
| |
| TEST(MLKEMTest, Basic1024) { |
| BasicTest<MLKEM1024_public_key, MLKEM1024_PUBLIC_KEY_BYTES, |
| MLKEM1024_private_key, MLKEM1024_PRIVATE_KEY_BYTES, |
| MLKEM1024_generate_key, MLKEM1024_private_key_from_seed, |
| MLKEM1024_public_from_private, MLKEM1024_parse_public_key, |
| MLKEM1024_marshal_public_key, MLKEM1024_parse_private_key, |
| MLKEM1024_marshal_private_key, MLKEM1024_CIPHERTEXT_BYTES, |
| MLKEM1024_encap, MLKEM1024_decap>(); |
| } |
| |
| template <typename PUBLIC_KEY, size_t PUBLIC_KEY_BYTES, typename PRIVATE_KEY, |
| int (*MARSHAL_PRIVATE)(CBB *, const PRIVATE_KEY *), |
| void (*GENERATE)(uint8_t *, PRIVATE_KEY *, const uint8_t *)> |
| void MLKEMKeyGenFileTest(FileTest *t) { |
| std::vector<uint8_t> expected_pub_key_bytes, seed, expected_priv_key_bytes; |
| ASSERT_TRUE(t->GetBytes(&seed, "seed")); |
| ASSERT_TRUE(t->GetBytes(&expected_pub_key_bytes, "public_key")); |
| ASSERT_TRUE(t->GetBytes(&expected_priv_key_bytes, "private_key")); |
| |
| ASSERT_EQ(seed.size(), size_t{MLKEM_SEED_BYTES}); |
| |
| std::vector<uint8_t> pub_key_bytes(PUBLIC_KEY_BYTES); |
| auto priv = std::make_unique<PRIVATE_KEY>(); |
| GENERATE(pub_key_bytes.data(), priv.get(), seed.data()); |
| const std::vector<uint8_t> priv_key_bytes( |
| Marshal(MARSHAL_PRIVATE, priv.get())); |
| |
| EXPECT_EQ(Bytes(pub_key_bytes), Bytes(expected_pub_key_bytes)); |
| EXPECT_EQ(Bytes(priv_key_bytes), Bytes(expected_priv_key_bytes)); |
| } |
| |
| TEST(MLKEMTest, KeyGen768TestVectors) { |
| FileTestGTest( |
| "crypto/mlkem/mlkem768_keygen_tests.txt", |
| MLKEMKeyGenFileTest<MLKEM768_public_key, MLKEM768_PUBLIC_KEY_BYTES, |
| MLKEM768_private_key, MLKEM768_marshal_private_key, |
| MLKEM768_generate_key_external_seed>); |
| } |
| |
| TEST(MLKEMTest, KeyGen1024TestVectors) { |
| FileTestGTest( |
| "crypto/mlkem/mlkem1024_keygen_tests.txt", |
| MLKEMKeyGenFileTest<MLKEM1024_public_key, MLKEM1024_PUBLIC_KEY_BYTES, |
| MLKEM1024_private_key, MLKEM1024_marshal_private_key, |
| MLKEM1024_generate_key_external_seed>); |
| } |
| |
| template <typename PUBLIC_KEY, size_t PUBLIC_KEY_BYTES, typename PRIVATE_KEY, |
| int (*MARSHAL_PRIVATE)(CBB *, const PRIVATE_KEY *), |
| void (*GENERATE)(uint8_t *, PRIVATE_KEY *, const uint8_t *)> |
| void MLKEMNistKeyGenFileTest(FileTest *t) { |
| std::vector<uint8_t> expected_pub_key_bytes, z, d, expected_priv_key_bytes; |
| ASSERT_TRUE(t->GetBytes(&z, "z")); |
| ASSERT_TRUE(t->GetBytes(&d, "d")); |
| ASSERT_TRUE(t->GetBytes(&expected_pub_key_bytes, "ek")); |
| ASSERT_TRUE(t->GetBytes(&expected_priv_key_bytes, "dk")); |
| |
| ASSERT_EQ(z.size(), size_t{MLKEM_SEED_BYTES} / 2); |
| ASSERT_EQ(d.size(), size_t{MLKEM_SEED_BYTES} / 2); |
| |
| uint8_t seed[MLKEM_SEED_BYTES]; |
| OPENSSL_memcpy(&seed[0], d.data(), d.size()); |
| OPENSSL_memcpy(&seed[MLKEM_SEED_BYTES / 2], z.data(), z.size()); |
| std::vector<uint8_t> pub_key_bytes(PUBLIC_KEY_BYTES); |
| auto priv = std::make_unique<PRIVATE_KEY>(); |
| GENERATE(pub_key_bytes.data(), priv.get(), seed); |
| const std::vector<uint8_t> priv_key_bytes( |
| Marshal(MARSHAL_PRIVATE, priv.get())); |
| |
| EXPECT_EQ(Bytes(pub_key_bytes), Bytes(expected_pub_key_bytes)); |
| EXPECT_EQ(Bytes(priv_key_bytes), Bytes(expected_priv_key_bytes)); |
| } |
| |
| TEST(MLKEMTest, NISTKeyGen768TestVectors) { |
| FileTestGTest( |
| "crypto/mlkem/mlkem768_nist_keygen_tests.txt", |
| MLKEMNistKeyGenFileTest< |
| MLKEM768_public_key, MLKEM768_PUBLIC_KEY_BYTES, MLKEM768_private_key, |
| MLKEM768_marshal_private_key, MLKEM768_generate_key_external_seed>); |
| } |
| |
| TEST(MLKEMTest, NISTKeyGen1024TestVectors) { |
| FileTestGTest( |
| "crypto/mlkem/mlkem1024_nist_keygen_tests.txt", |
| MLKEMNistKeyGenFileTest<MLKEM1024_public_key, MLKEM1024_PUBLIC_KEY_BYTES, |
| MLKEM1024_private_key, |
| MLKEM1024_marshal_private_key, |
| MLKEM1024_generate_key_external_seed>); |
| } |
| |
| template <typename PUBLIC_KEY, size_t PUBLIC_KEY_BYTES, |
| int (*PARSE_PUBLIC)(PUBLIC_KEY *, CBS *), size_t CIPHERTEXT_BYTES, |
| void (*ENCAP)(uint8_t *, uint8_t *, const PUBLIC_KEY *, |
| const uint8_t *)> |
| void MLKEMEncapFileTest(FileTest *t) { |
| std::vector<uint8_t> pub_key_bytes, entropy, expected_ciphertext, |
| expected_shared_secret; |
| ASSERT_TRUE(t->GetBytes(&entropy, "entropy")); |
| ASSERT_TRUE(t->GetBytes(&pub_key_bytes, "public_key")); |
| ASSERT_TRUE(t->GetBytes(&expected_ciphertext, "ciphertext")); |
| ASSERT_TRUE(t->GetBytes(&expected_shared_secret, "shared_secret")); |
| std::string result; |
| ASSERT_TRUE(t->GetAttribute(&result, "result")); |
| |
| PUBLIC_KEY pub_key; |
| CBS pub_key_cbs; |
| CBS_init(&pub_key_cbs, pub_key_bytes.data(), pub_key_bytes.size()); |
| const int parse_ok = PARSE_PUBLIC(&pub_key, &pub_key_cbs); |
| ASSERT_EQ(parse_ok, result == "pass"); |
| if (!parse_ok) { |
| return; |
| } |
| |
| uint8_t ciphertext[CIPHERTEXT_BYTES]; |
| uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES]; |
| ENCAP(ciphertext, shared_secret, &pub_key, entropy.data()); |
| |
| ASSERT_EQ(Bytes(expected_ciphertext), Bytes(ciphertext)); |
| ASSERT_EQ(Bytes(expected_shared_secret), Bytes(shared_secret)); |
| } |
| |
| TEST(MLKEMTest, Encap768TestVectors) { |
| FileTestGTest( |
| "crypto/mlkem/mlkem768_encap_tests.txt", |
| MLKEMEncapFileTest<MLKEM768_public_key, MLKEM768_PUBLIC_KEY_BYTES, |
| MLKEM768_parse_public_key, MLKEM768_CIPHERTEXT_BYTES, |
| MLKEM768_encap_external_entropy>); |
| } |
| |
| TEST(MLKEMTest, Encap1024TestVectors) { |
| FileTestGTest( |
| "crypto/mlkem/mlkem1024_encap_tests.txt", |
| MLKEMEncapFileTest<MLKEM1024_public_key, MLKEM1024_PUBLIC_KEY_BYTES, |
| MLKEM1024_parse_public_key, MLKEM1024_CIPHERTEXT_BYTES, |
| MLKEM1024_encap_external_entropy>); |
| } |
| |
| template <typename PRIVATE_KEY, size_t PRIVATE_KEY_BYTES, |
| int (*PARSE_PRIVATE)(PRIVATE_KEY *, CBS *), size_t CIPHERTEXT_BYTES, |
| int (*DECAP)(uint8_t *, const uint8_t *, size_t, const PRIVATE_KEY *)> |
| void MLKEMDecapFileTest(FileTest *t) { |
| std::vector<uint8_t> priv_key_bytes, ciphertext, expected_shared_secret; |
| ASSERT_TRUE(t->GetBytes(&priv_key_bytes, "private_key")); |
| ASSERT_TRUE(t->GetBytes(&ciphertext, "ciphertext")); |
| ASSERT_TRUE(t->GetBytes(&expected_shared_secret, "shared_secret")); |
| std::string result; |
| ASSERT_TRUE(t->GetAttribute(&result, "result")); |
| |
| PRIVATE_KEY priv_key; |
| CBS priv_key_cbs; |
| CBS_init(&priv_key_cbs, priv_key_bytes.data(), priv_key_bytes.size()); |
| const int parse_ok = PARSE_PRIVATE(&priv_key, &priv_key_cbs); |
| if (!parse_ok) { |
| ASSERT_NE(result, "pass"); |
| return; |
| } |
| |
| uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES]; |
| const int decap_ok = |
| DECAP(shared_secret, ciphertext.data(), ciphertext.size(), &priv_key); |
| if (!decap_ok) { |
| ASSERT_NE(result, "pass"); |
| return; |
| } |
| |
| ASSERT_EQ(Bytes(expected_shared_secret), Bytes(shared_secret)); |
| } |
| |
| TEST(MLKEMTest, Decap768TestVectors) { |
| FileTestGTest( |
| "crypto/mlkem/mlkem768_decap_tests.txt", |
| MLKEMDecapFileTest<MLKEM768_private_key, MLKEM768_PRIVATE_KEY_BYTES, |
| MLKEM768_parse_private_key, MLKEM768_CIPHERTEXT_BYTES, |
| MLKEM768_decap>); |
| } |
| |
| TEST(MLKEMTest, Decap1024TestVectors) { |
| FileTestGTest( |
| "crypto/mlkem/mlkem1024_decap_tests.txt", |
| MLKEMDecapFileTest<MLKEM1024_private_key, MLKEM1024_PRIVATE_KEY_BYTES, |
| MLKEM1024_parse_private_key, |
| MLKEM1024_CIPHERTEXT_BYTES, MLKEM1024_decap>); |
| } |
| |
| template <typename PRIVATE_KEY, int (*PARSE_PRIVATE)(PRIVATE_KEY *, CBS *), |
| int (*DECAP)(uint8_t *, const uint8_t *, size_t, const PRIVATE_KEY *)> |
| void MLKEMNistDecapFileTest(FileTest *t) { |
| std::vector<uint8_t> ciphertext, expected_shared_secret, private_key_bytes; |
| ASSERT_TRUE(t->GetBytes(&ciphertext, "c")); |
| ASSERT_TRUE(t->GetBytes(&expected_shared_secret, "k")); |
| ASSERT_TRUE(t->GetInstructionBytes(&private_key_bytes, "dk")); |
| |
| PRIVATE_KEY priv; |
| CBS private_key_cbs; |
| CBS_init(&private_key_cbs, private_key_bytes.data(), |
| private_key_bytes.size()); |
| ASSERT_TRUE(PARSE_PRIVATE(&priv, &private_key_cbs)); |
| |
| uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES]; |
| ASSERT_TRUE( |
| DECAP(shared_secret, ciphertext.data(), ciphertext.size(), &priv)); |
| |
| ASSERT_EQ(Bytes(shared_secret), Bytes(expected_shared_secret)); |
| } |
| |
| TEST(MLKEMTest, NistDecap768TestVectors) { |
| FileTestGTest( |
| "crypto/mlkem/mlkem768_nist_decap_tests.txt", |
| MLKEMNistDecapFileTest<MLKEM768_private_key, MLKEM768_parse_private_key, |
| MLKEM768_decap>); |
| } |
| |
| TEST(MLKEMTest, NistDecap1024TestVectors) { |
| FileTestGTest( |
| "crypto/mlkem/mlkem1024_nist_decap_tests.txt", |
| MLKEMNistDecapFileTest<MLKEM1024_private_key, MLKEM1024_parse_private_key, |
| MLKEM1024_decap>); |
| } |
| |
| template < |
| typename PUBLIC_KEY, size_t PUBLIC_KEY_BYTES, typename PRIVATE_KEY, |
| size_t PRIVATE_KEY_BYTES, |
| void (*GENERATE)(uint8_t *, PRIVATE_KEY *, const uint8_t *), |
| void (*TO_PUBLIC)(PUBLIC_KEY *, const PRIVATE_KEY *), |
| int (*MARSHAL_PRIVATE)(CBB *, const PRIVATE_KEY *), size_t CIPHERTEXT_BYTES, |
| void (*ENCAP)(uint8_t *, uint8_t *, const PUBLIC_KEY *, const uint8_t *), |
| int (*DECAP)(uint8_t *, const uint8_t *, size_t, const PRIVATE_KEY *)> |
| void IteratedTest(uint8_t out[32]) { |
| BORINGSSL_keccak_st generate_st; |
| BORINGSSL_keccak_init(&generate_st, boringssl_shake128); |
| BORINGSSL_keccak_st results_st; |
| BORINGSSL_keccak_init(&results_st, boringssl_shake128); |
| |
| auto priv = std::make_unique<PRIVATE_KEY>(); |
| auto pub = std::make_unique<PUBLIC_KEY>(); |
| for (int i = 0; i < 10000; i++) { |
| uint8_t seed[MLKEM_SEED_BYTES]; |
| BORINGSSL_keccak_squeeze(&generate_st, seed, sizeof(seed)); |
| uint8_t encoded_pub[PUBLIC_KEY_BYTES]; |
| GENERATE(encoded_pub, priv.get(), seed); |
| TO_PUBLIC(pub.get(), priv.get()); |
| |
| BORINGSSL_keccak_absorb(&results_st, encoded_pub, sizeof(encoded_pub)); |
| const std::vector<uint8_t> encoded_priv( |
| Marshal(MARSHAL_PRIVATE, priv.get())); |
| BORINGSSL_keccak_absorb(&results_st, encoded_priv.data(), |
| encoded_priv.size()); |
| |
| uint8_t encap_entropy[MLKEM_ENCAP_ENTROPY]; |
| BORINGSSL_keccak_squeeze(&generate_st, encap_entropy, |
| sizeof(encap_entropy)); |
| uint8_t ciphertext[CIPHERTEXT_BYTES]; |
| uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES]; |
| ENCAP(ciphertext, shared_secret, pub.get(), encap_entropy); |
| |
| BORINGSSL_keccak_absorb(&results_st, ciphertext, sizeof(ciphertext)); |
| BORINGSSL_keccak_absorb(&results_st, shared_secret, sizeof(shared_secret)); |
| |
| uint8_t invalid_ciphertext[CIPHERTEXT_BYTES]; |
| BORINGSSL_keccak_squeeze(&generate_st, invalid_ciphertext, |
| sizeof(invalid_ciphertext)); |
| ASSERT_TRUE(DECAP(shared_secret, invalid_ciphertext, |
| sizeof(invalid_ciphertext), priv.get())); |
| |
| BORINGSSL_keccak_absorb(&results_st, shared_secret, sizeof(shared_secret)); |
| } |
| |
| BORINGSSL_keccak_squeeze(&results_st, out, 32); |
| } |
| |
| TEST(MLKEMTest, Iterate768) { |
| // The structure of this test is taken from |
| // https://github.com/C2SP/CCTV/blob/main/ML-KEM/README.md?ref=words.filippo.io#accumulated-pq-crystals-vectors |
| // but the final value has been updated to reflect the change from Kyber to |
| // ML-KEM. |
| uint8_t result[32]; |
| IteratedTest<MLKEM768_public_key, MLKEM768_PUBLIC_KEY_BYTES, |
| MLKEM768_private_key, MLKEM768_PRIVATE_KEY_BYTES, |
| MLKEM768_generate_key_external_seed, |
| MLKEM768_public_from_private, MLKEM768_marshal_private_key, |
| MLKEM768_CIPHERTEXT_BYTES, MLKEM768_encap_external_entropy, |
| MLKEM768_decap>(result); |
| |
| const uint8_t kExpected[32] = { |
| 0xf9, 0x59, 0xd1, 0x8d, 0x3d, 0x11, 0x80, 0x12, 0x14, 0x33, 0xbf, |
| 0x0e, 0x05, 0xf1, 0x1e, 0x79, 0x08, 0xcf, 0x9d, 0x03, 0xed, 0xc1, |
| 0x50, 0xb2, 0xb0, 0x7c, 0xb9, 0x0b, 0xef, 0x5b, 0xc1, 0xc1}; |
| EXPECT_EQ(Bytes(result), Bytes(kExpected)); |
| } |
| |
| |
| TEST(MLKEMTest, Iterate1024) { |
| // The structure of this test is taken from |
| // https://github.com/C2SP/CCTV/blob/main/ML-KEM/README.md?ref=words.filippo.io#accumulated-pq-crystals-vectors |
| // but the final value has been updated to reflect the change from Kyber to |
| // ML-KEM. |
| uint8_t result[32]; |
| IteratedTest<MLKEM1024_public_key, MLKEM1024_PUBLIC_KEY_BYTES, |
| MLKEM1024_private_key, MLKEM1024_PRIVATE_KEY_BYTES, |
| MLKEM1024_generate_key_external_seed, |
| MLKEM1024_public_from_private, MLKEM1024_marshal_private_key, |
| MLKEM1024_CIPHERTEXT_BYTES, MLKEM1024_encap_external_entropy, |
| MLKEM1024_decap>(result); |
| |
| const uint8_t kExpected[32] = { |
| 0xe3, 0xbf, 0x82, 0xb0, 0x13, 0x30, 0x7b, 0x2e, 0x9d, 0x47, 0xdd, |
| 0xe7, 0x91, 0xff, 0x6d, 0xfc, 0x82, 0xe6, 0x94, 0xe6, 0x38, 0x24, |
| 0x04, 0xab, 0xdb, 0x94, 0x8b, 0x90, 0x8b, 0x75, 0xba, 0xd5}; |
| EXPECT_EQ(Bytes(result), Bytes(kExpected)); |
| } |
| } // namespace |