diff --git a/doc/api_ref/pubkey.rst b/doc/api_ref/pubkey.rst index cce2414d6d7..109367b34a7 100644 --- a/doc/api_ref/pubkey.rst +++ b/doc/api_ref/pubkey.rst @@ -194,6 +194,21 @@ Currently two flavors of Kyber are implemented in separate Botan modules: * ``kyber_90s``, that uses AES/SHA-2 instead of Keccak-based primitives. This mode is deprecated and will be removed in a future release. +ML-KEM-composite (draft-ietf-lamps-pq-composite-kem-16) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +ML-KEM-composite algorithms are accessible in Botan via the generic algorithm string +"ML-KEM-composite" and the respective OIDs registered +under the names MLKEM768-RSA2048-SHA3-256, MLKEM768-RSA3072-SHA3-256, +MLKEM768-RSA4096-SHA3-256, MLKEM768-X25519-SHA3-256, +MLKEM768-ECDH-P256-SHA3-256, MLKEM768-ECDH-P384-SHA3-256, +MLKEM768-ECDH-brainpoolP256r1-SHA3-256, MLKEM1024-RSA3072-SHA3-256, +MLKEM1024-ECDH-P384-SHA3-256, MLKEM1024-ECDH-brainpoolP384r1-SHA3-256, +MLKEM1024-X448-SHA3-256, MLKEM1024-ECDH-P521-SHA3-256. + +There is no default parameter set defined, thus a parameter string has to be +provided in any case. + Ed25519 and Ed448 ~~~~~~~~~~~~~~~~~ diff --git a/readme.rst b/readme.rst index 78a77e5c83b..facce35d5f2 100644 --- a/readme.rst +++ b/readme.rst @@ -117,7 +117,8 @@ Public Key Cryptography * DH, ECDH, X25519 and X448 key agreement * Elliptic curve signature schemes ECDSA, Ed25519, Ed448, ECGDSA, ECKCDSA, SM2 * Post-quantum signature schemes ML-DSA (Dilithium), SLH-DSA (SPHINCS+), HSS/LMS, XMSS -* Post-quantum key encapsulation schemes ML-KEM (Kyber), FrodoKEM, Classic McEliece +* Post-quantum key encapsulation schemes ML-KEM (Kyber), ML-KEM-composite + according to draft-ietf-lamps-pq-composite-kem-16, FrodoKEM, Classic McEliece Ciphers, hashes, MACs, and checksums ---------------------------------------- diff --git a/src/build-data/oids.txt b/src/build-data/oids.txt index 1ab9e883541..78b63d89442 100644 --- a/src/build-data/oids.txt +++ b/src/build-data/oids.txt @@ -493,3 +493,16 @@ 1.3.6.1.4.1.25258.4.1 = numsp256d1 1.3.6.1.4.1.25258.4.2 = numsp384d1 1.3.6.1.4.1.25258.4.3 = numsp512d1 + +1.3.6.1.5.5.7.6.55 = MLKEM768-RSA2048-SHA3-256 +1.3.6.1.5.5.7.6.56 = MLKEM768-RSA3072-SHA3-256 +1.3.6.1.5.5.7.6.57 = MLKEM768-RSA4096-SHA3-256 +1.3.6.1.5.5.7.6.58 = MLKEM768-X25519-SHA3-256 +1.3.6.1.5.5.7.6.59 = MLKEM768-ECDH-P256-SHA3-256 +1.3.6.1.5.5.7.6.60 = MLKEM768-ECDH-P384-SHA3-256 +1.3.6.1.5.5.7.6.61 = MLKEM768-ECDH-brainpoolP256r1-SHA3-256 +1.3.6.1.5.5.7.6.62 = MLKEM1024-RSA3072-SHA3-256 +1.3.6.1.5.5.7.6.63 = MLKEM1024-ECDH-P384-SHA3-256 +1.3.6.1.5.5.7.6.64 = MLKEM1024-ECDH-brainpoolP384r1-SHA3-256 +1.3.6.1.5.5.7.6.65 = MLKEM1024-X448-SHA3-256 +1.3.6.1.5.5.7.6.66 = MLKEM1024-ECDH-P521-SHA3-256 diff --git a/src/build-data/policy/bsi.txt b/src/build-data/policy/bsi.txt index 19c5f252c5a..6a2819aa143 100644 --- a/src/build-data/policy/bsi.txt +++ b/src/build-data/policy/bsi.txt @@ -9,6 +9,7 @@ rsa ecies dh ecdh +mlkem-composite # Allowed KDF for ECIES (see 2.3.4) kdf1_iso18033 diff --git a/src/cli/perf_pk_kem.cpp b/src/cli/perf_pk_kem.cpp index 63b22a711dd..6a59afe6433 100644 --- a/src/cli/perf_pk_kem.cpp +++ b/src/cli/perf_pk_kem.cpp @@ -7,6 +7,7 @@ #include "perf.h" #include +#include #if defined(BOTAN_HAS_PUBLIC_KEY_CRYPTO) #include @@ -14,6 +15,10 @@ #include #endif +#if defined(BOTAN_HAS_MLKEM_COMPOSITE) + #include +#endif + namespace Botan_CLI { namespace { @@ -45,7 +50,12 @@ class PerfTest_PK_KEM : public PerfTest { const auto msec = config.runtime(); auto& rng = config.rng(); - const std::string kdf = "KDF2(SHA-256)"; // arbitrary choice + std::string kdf = "KDF2(SHA-256)"; // arbitrary choice + #if BOTAN_HAS_MLKEM_COMPOSITE + if(algo == Botan::MLKEM_Composite_Param::generic_algo_name) { + kdf = ""; + } + #endif auto keygen_timer = config.make_timer(nm, 1, "keygen"); @@ -130,6 +140,27 @@ BOTAN_REGISTER_PERF_TEST("ML-KEM", PerfTest_ML_KEM); #endif +#if defined(BOTAN_HAS_MLKEM_COMPOSITE) + +class PerfTest_MLKEM_Composite final : public PerfTest_PK_KEM { + public: + std::string algo() const override { return std::string(Botan::MLKEM_Composite_Param::generic_algo_name); } + + std::vector keygen_params(const PerfConfig& /*config*/) const override { + const auto all_params = Botan::MLKEM_Composite_Param::all_supported_param_sets(); + std::vector result; + result.reserve(all_params.size()); + for(const auto& param : all_params) { + result.push_back(param.id_str()); + } + return result; + } +}; + +BOTAN_REGISTER_PERF_TEST("MLKEM-Composite", PerfTest_MLKEM_Composite); + +#endif + #if defined(BOTAN_HAS_FRODOKEM) class PerfTest_FrodoKEM final : public PerfTest_PK_KEM { diff --git a/src/configs/typos.toml b/src/configs/typos.toml index 32d5c0942be..b0af9f3a774 100644 --- a/src/configs/typos.toml +++ b/src/configs/typos.toml @@ -4,6 +4,7 @@ extend-exclude = [ "src/build-data/cc/msvc.txt", "src/build-data/cc/clangcl.txt", "doc/authors.txt", + "/src/tests/data/pubkey/mlkem_composite.vec", ] [default] diff --git a/src/lib/asn1/static_oids.cpp b/src/lib/asn1/static_oids.cpp index f6c7fc77473..070446ee1a6 100644 --- a/src/lib/asn1/static_oids.cpp +++ b/src/lib/asn1/static_oids.cpp @@ -1,5 +1,5 @@ /* -* This file was automatically generated by ./src/scripts/dev_tools/gen_oids.py on 2026-05-13 +* This file was automatically generated by src/scripts/dev_tools/gen_oids.py on 2026-06-16 * All manual changes will be lost. Edit the script instead. * * Botan is released under the Simplified BSD License (see license.txt) @@ -583,6 +583,30 @@ std::optional OID_Map::lookup_static_oid(const OID& oid) { return if_match(oid, {1, 3, 6, 1, 5, 5, 7, 3, 8}, "PKIX.TimeStamping"); case 0x94929: return if_match(oid, {1, 3, 6, 1, 5, 5, 7, 3, 9}, "PKIX.OCSPSigning"); + case 0x94B9A: + return if_match(oid, {1, 3, 6, 1, 5, 5, 7, 6, 55}, "MLKEM768-RSA2048-SHA3-256"); + case 0x94B9B: + return if_match(oid, {1, 3, 6, 1, 5, 5, 7, 6, 56}, "MLKEM768-RSA3072-SHA3-256"); + case 0x94B9C: + return if_match(oid, {1, 3, 6, 1, 5, 5, 7, 6, 57}, "MLKEM768-RSA4096-SHA3-256"); + case 0x94B9D: + return if_match(oid, {1, 3, 6, 1, 5, 5, 7, 6, 58}, "MLKEM768-X25519-SHA3-256"); + case 0x94B9E: + return if_match(oid, {1, 3, 6, 1, 5, 5, 7, 6, 59}, "MLKEM768-ECDH-P256-SHA3-256"); + case 0x94B9F: + return if_match(oid, {1, 3, 6, 1, 5, 5, 7, 6, 60}, "MLKEM768-ECDH-P384-SHA3-256"); + case 0x94BA0: + return if_match(oid, {1, 3, 6, 1, 5, 5, 7, 6, 61}, "MLKEM768-ECDH-brainpoolP256r1-SHA3-256"); + case 0x94BA1: + return if_match(oid, {1, 3, 6, 1, 5, 5, 7, 6, 62}, "MLKEM1024-RSA3072-SHA3-256"); + case 0x94BA2: + return if_match(oid, {1, 3, 6, 1, 5, 5, 7, 6, 63}, "MLKEM1024-ECDH-P384-SHA3-256"); + case 0x94BA3: + return if_match(oid, {1, 3, 6, 1, 5, 5, 7, 6, 64}, "MLKEM1024-ECDH-brainpoolP384r1-SHA3-256"); + case 0x94BA4: + return if_match(oid, {1, 3, 6, 1, 5, 5, 7, 6, 65}, "MLKEM1024-X448-SHA3-256"); + case 0x94BA5: + return if_match(oid, {1, 3, 6, 1, 5, 5, 7, 6, 66}, "MLKEM1024-ECDH-P521-SHA3-256"); case 0x94CEA: return if_match(oid, {1, 3, 6, 1, 5, 5, 7, 8, 5}, "PKIX.XMPPAddr"); case 0x94CEE: @@ -793,6 +817,8 @@ std::optional OID_Map::lookup_static_oid_name(std::string_view req) { return if_match(req, "Camellia-256/GCM", {0, 3, 4401, 5, 3, 1, 9, 46}); case 0x1033D: return if_match(req, "DSA/SHA-3(384)", {2, 16, 840, 1, 101, 3, 4, 3, 7}); + case 0x104EA: + return if_match(req, "MLKEM768-RSA4096-SHA3-256", {1, 3, 6, 1, 5, 5, 7, 6, 57}); case 0x1139D: return if_match(req, "secp192k1", {1, 3, 132, 0, 31}); case 0x113D6: @@ -927,6 +953,8 @@ std::optional OID_Map::lookup_static_oid_name(std::string_view req) { return if_match(req, "SLH-DSA-SHAKE-192f", {2, 16, 840, 1, 101, 3, 4, 3, 29}); case 0x3BC97: return if_match(req, "SLH-DSA-SHAKE-192s", {2, 16, 840, 1, 101, 3, 4, 3, 28}); + case 0x3BD00: + return if_match(req, "MLKEM1024-RSA3072-SHA3-256", {1, 3, 6, 1, 5, 5, 7, 6, 62}); case 0x3D127: return if_match(req, "DSA", {1, 2, 840, 10040, 4, 1}); case 0x3E249: @@ -971,6 +999,8 @@ std::optional OID_Map::lookup_static_oid_name(std::string_view req) { return if_match(req, "Dilithium-4x4-AES-r3", {1, 3, 6, 1, 4, 1, 25258, 1, 10, 1}); case 0x48861: return if_match(req, "ChaCha20Poly1305", {1, 2, 840, 113549, 1, 9, 16, 3, 18}); + case 0x49045: + return if_match(req, "MLKEM1024-ECDH-brainpoolP384r1-SHA3-256", {1, 3, 6, 1, 5, 5, 7, 6, 64}); case 0x4A292: return if_match(req, "frp256v1", {1, 2, 250, 1, 223, 101, 256, 1}); case 0x4A9EE: @@ -1003,6 +1033,8 @@ std::optional OID_Map::lookup_static_oid_name(std::string_view req) { return if_match(req, "PKCS9.ContentType", {1, 2, 840, 113549, 1, 9, 3}); case 0x50B26: return if_match(req, "FrodoKEM-640-AES", {1, 3, 6, 1, 4, 1, 25258, 1, 15, 1}); + case 0x50D65: + return if_match(req, "MLKEM768-ECDH-brainpoolP256r1-SHA3-256", {1, 3, 6, 1, 5, 5, 7, 6, 61}); case 0x50D78: return if_match(req, "x962_p192v2", {1, 2, 840, 10045, 3, 1, 2}); case 0x50D79: @@ -1019,6 +1051,8 @@ std::optional OID_Map::lookup_static_oid_name(std::string_view req) { return if_match(req, "Serpent/CBC", {1, 3, 6, 1, 4, 1, 25258, 3, 1}); case 0x5576D: return if_match(req, "SphincsPlus-sha2-128f-r3.1", {1, 3, 6, 1, 4, 1, 25258, 1, 12, 2, 2}); + case 0x55EE5: + return if_match(req, "MLKEM1024-X448-SHA3-256", {1, 3, 6, 1, 5, 5, 7, 6, 65}); case 0x55EF6: return if_match(req, "AES-192/OCB", {1, 3, 6, 1, 4, 1, 25258, 3, 2, 2}); case 0x55FFA: @@ -1083,6 +1117,8 @@ std::optional OID_Map::lookup_static_oid_name(std::string_view req) { return if_match(req, "AES-192/CBC", {2, 16, 840, 1, 101, 3, 4, 1, 22}); case 0x61F7E: return if_match(req, "AES-192/CCM", {2, 16, 840, 1, 101, 3, 4, 1, 27}); + case 0x62CDB: + return if_match(req, "MLKEM768-X25519-SHA3-256", {1, 3, 6, 1, 5, 5, 7, 6, 58}); case 0x64947: return if_match(req, "OpenPGP.Ed25519", {1, 3, 6, 1, 4, 1, 11591, 15, 1}); case 0x652E7: @@ -1095,6 +1131,8 @@ std::optional OID_Map::lookup_static_oid_name(std::string_view req) { return if_match(req, "HMAC(SHA-384)", {1, 2, 840, 113549, 2, 10}); case 0x67D86: return if_match(req, "ECGDSA/SHA-384", {1, 3, 36, 3, 3, 2, 5, 4, 5}); + case 0x67FCB: + return if_match(req, "MLKEM768-RSA2048-SHA3-256", {1, 3, 6, 1, 5, 5, 7, 6, 55}); case 0x68A0B: return if_match(req, "Camellia-128/OCB", {1, 3, 6, 1, 4, 1, 25258, 3, 2, 6}); case 0x68E33: @@ -1103,6 +1141,8 @@ std::optional OID_Map::lookup_static_oid_name(std::string_view req) { return if_match(req, "X509v3.SubjectAlternativeName", {2, 5, 29, 17}); case 0x692F8: return if_match(req, "SM4/CBC", {1, 2, 156, 10197, 1, 104, 2}); + case 0x693E5: + return if_match(req, "MLKEM1024-ECDH-P384-SHA3-256", {1, 3, 6, 1, 5, 5, 7, 6, 63}); case 0x695E1: return if_match(req, "Dilithium-4x4-r3", {1, 3, 6, 1, 4, 1, 25258, 1, 9, 1}); case 0x696DC: @@ -1243,16 +1283,22 @@ std::optional OID_Map::lookup_static_oid_name(std::string_view req) { return if_match(req, "ECKCDSA", {1, 0, 14888, 3, 0, 5}); case 0x8E0C1: return if_match(req, "X509v3.CertificatePolicies", {2, 5, 29, 32}); + case 0x8E1BF: + return if_match(req, "MLKEM1024-ECDH-P521-SHA3-256", {1, 3, 6, 1, 5, 5, 7, 6, 66}); case 0x8E39A: return if_match(req, "HSS-LMS-Private-Key", {1, 3, 6, 1, 4, 1, 25258, 1, 13}); case 0x8EC51: return if_match(req, "Kyber-768-r3", {1, 3, 6, 1, 4, 1, 25258, 1, 7, 2}); case 0x8F94A: return if_match(req, "Dilithium-6x5-r3", {1, 3, 6, 1, 4, 1, 25258, 1, 9, 2}); + case 0x8FB4C: + return if_match(req, "MLKEM768-ECDH-P256-SHA3-256", {1, 3, 6, 1, 5, 5, 7, 6, 59}); case 0x8FC20: return if_match(req, "AES-128/SIV", {1, 3, 6, 1, 4, 1, 25258, 3, 4, 1}); case 0x8FDE0: return if_match(req, "SHA-3(256)", {2, 16, 840, 1, 101, 3, 4, 2, 8}); + case 0x909D3: + return if_match(req, "MLKEM768-ECDH-P384-SHA3-256", {1, 3, 6, 1, 5, 5, 7, 6, 60}); case 0x919E3: return if_match(req, "Serpent/GCM", {1, 3, 6, 1, 4, 1, 25258, 3, 101}); case 0x91C1A: @@ -1381,6 +1427,8 @@ std::optional OID_Map::lookup_static_oid_name(std::string_view req) { return if_match(req, "RSA/PKCS1v15(SHA-3(512))", {2, 16, 840, 1, 101, 3, 4, 3, 16}); case 0xB6427: return if_match(req, "Camellia-192/GCM", {0, 3, 4401, 5, 3, 1, 9, 26}); + case 0xB70A8: + return if_match(req, "MLKEM768-RSA3072-SHA3-256", {1, 3, 6, 1, 5, 5, 7, 6, 56}); case 0xB7102: return if_match(req, "brainpool224r1", {1, 3, 36, 3, 3, 2, 8, 1, 1, 5}); case 0xB710D: diff --git a/src/lib/ffi/ffi.h b/src/lib/ffi/ffi.h index 79ad43a37da..daeca212574 100644 --- a/src/lib/ffi/ffi.h +++ b/src/lib/ffi/ffi.h @@ -2111,6 +2111,22 @@ int botan_privkey_load_ml_kem(botan_privkey_t* key, const uint8_t privkey[], siz BOTAN_FFI_EXPORT(3, 6) int botan_pubkey_load_ml_kem(botan_pubkey_t* key, const uint8_t pubkey[], size_t key_len, const char* mlkem_mode); +/* +* Algorithm specific key operations: MLKEM-Composite +*/ + +BOTAN_FFI_EXPORT(3, 12) +int botan_privkey_load_mlkem_composite(botan_privkey_t* key, + const uint8_t privkey[], + size_t key_len, + const char* mlkem_composite_algo); + +BOTAN_FFI_EXPORT(3, 12) +int botan_pubkey_load_mlkem_composite(botan_pubkey_t* key, + const uint8_t pubkey[], + size_t key_len, + const char* mlkem_composite_algo); + /* * Algorithm specific key operations: SLH-DSA */ diff --git a/src/lib/ffi/ffi_pkey_algs.cpp b/src/lib/ffi/ffi_pkey_algs.cpp index a8f43251621..6fd00452630 100644 --- a/src/lib/ffi/ffi_pkey_algs.cpp +++ b/src/lib/ffi/ffi_pkey_algs.cpp @@ -79,6 +79,10 @@ #include #endif +#if defined(BOTAN_HAS_MLKEM_COMPOSITE) + #include +#endif + #if defined(BOTAN_HAS_FRODOKEM) #include #endif @@ -1348,6 +1352,63 @@ int botan_pubkey_load_ml_kem(botan_pubkey_t* key, const uint8_t pubkey[], size_t #endif } +/* +* Algorithm specific key operations: MLKEM-Composite +*/ + +int botan_privkey_load_mlkem_composite(botan_privkey_t* key, + const uint8_t privkey[], + size_t key_len, + const char* mlkem_composite_algo) { +#if defined(BOTAN_HAS_MLKEM_COMPOSITE) + if(key == nullptr || privkey == nullptr || mlkem_composite_algo == nullptr) { + return BOTAN_FFI_ERROR_NULL_POINTER; + } + *key = nullptr; + + return ffi_guard_thunk(__func__, [=]() -> int { + auto param = Botan::MLKEM_Composite_Param::from_id_str(mlkem_composite_algo); + if(!param.has_value()) { + return BOTAN_FFI_ERROR_BAD_PARAMETER; + } + + auto mlkem_composite_key = + std::make_unique(param.value().id(), std::span{privkey, key_len}); + return ffi_new_object(key, std::move(mlkem_composite_key)); + }); +#else + BOTAN_UNUSED(key, key_len, privkey, mlkem_composite_algo); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif +} + +int botan_pubkey_load_mlkem_composite(botan_pubkey_t* key, + const uint8_t pubkey[], + size_t key_len, + const char* mlkem_composite_algo) { +#if defined(BOTAN_HAS_MLKEM_COMPOSITE) + if(key == nullptr || pubkey == nullptr || mlkem_composite_algo == nullptr) { + return BOTAN_FFI_ERROR_NULL_POINTER; + } + + *key = nullptr; + + return ffi_guard_thunk(__func__, [=]() -> int { + auto param = Botan::MLKEM_Composite_Param::from_id_str(mlkem_composite_algo); + if(!param.has_value()) { + return BOTAN_FFI_ERROR_BAD_PARAMETER; + } + + auto mlkem_composite_key = + std::make_unique(param.value().id(), std::span{pubkey, key_len}); + return ffi_new_object(key, std::move(mlkem_composite_key)); + }); +#else + BOTAN_UNUSED(key, key_len, pubkey, mlkem_composite_algo); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif +} + /* * Algorithm specific key operations: ML-DSA */ diff --git a/src/lib/pubkey/ecc_key/ecc_key.cpp b/src/lib/pubkey/ecc_key/ecc_key.cpp index 9258e968642..97645d40ff9 100644 --- a/src/lib/pubkey/ecc_key/ecc_key.cpp +++ b/src/lib/pubkey/ecc_key/ecc_key.cpp @@ -17,6 +17,8 @@ #include #include +#include + #if defined(BOTAN_HAS_LEGACY_EC_POINT) #include #endif @@ -177,8 +179,6 @@ EC_PrivateKey::EC_PrivateKey(const AlgorithmIdentifier& alg_id, std::span key_bits, bool with_modular_inverse) : m_with_modular_inverse(with_modular_inverse) { - const EC_Group group(alg_id.parameters()); - OID key_parameters; secure_vector private_key_bits; secure_vector public_key_bits; @@ -192,12 +192,31 @@ EC_PrivateKey::EC_PrivateKey(const AlgorithmIdentifier& alg_id, .end_cons() .verify_end(); - m_private_key = std::make_shared(group, private_key_bits); + std::unique_ptr group; + + if(!alg_id.parameters_are_empty()) { + group = std::make_unique(alg_id.parameters()); + } + if(!key_parameters.empty()) { + if(group) { + if(EC_Group(key_parameters) != *group) { + throw Invalid_Argument( + "Domain parameters supplied AlgorithmIdentifier does not match the ECC private key's domain parameters in EC_PrivateKey construction"); + } + } else { + group = std::make_unique(key_parameters); + } + } + if(!group) { + throw Invalid_Argument("Domain parameters are not supplied in EC_PrivateKey construction"); + } + + m_private_key = std::make_shared(*group, private_key_bits); if(public_key_bits.empty()) { m_public_key = m_private_key->public_key(with_modular_inverse); } else { - m_public_key = std::make_shared(group, public_key_bits); + m_public_key = std::make_shared(*group, public_key_bits); } m_domain_encoding = default_encoding_for(domain()); diff --git a/src/lib/pubkey/mlkem-composite/info.txt b/src/lib/pubkey/mlkem-composite/info.txt new file mode 100644 index 00000000000..995774e24be --- /dev/null +++ b/src/lib/pubkey/mlkem-composite/info.txt @@ -0,0 +1,22 @@ + +MLKEM_COMPOSITE -> 20260615 + + + +name -> "ML-KEM-composite" + + + +mlkem_comp.h +mlkem_comp_parameters.h + + + + + + +kyber +rng +hash +asn1 + diff --git a/src/lib/pubkey/mlkem-composite/mlkem_comp.cpp b/src/lib/pubkey/mlkem-composite/mlkem_comp.cpp new file mode 100644 index 00000000000..f872fed0267 --- /dev/null +++ b/src/lib/pubkey/mlkem-composite/mlkem_comp.cpp @@ -0,0 +1,606 @@ +/* + * ML-KEM Composite KEM + * (C) 2026 Falko Strenzke, MTG AG + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#include +#include +#include +#include +#include + +#include +#include +#include +#if defined BOTAN_HAS_ECDH + #include + #include +#endif + +#if defined BOTAN_HAS_X25519 + #include +#endif +#if defined BOTAN_HAS_X448 + #include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +// with C++23, to be replaced by std::ranges::contains() +template +constexpr bool contains(const std::array& c, const T& e) { + return std::find(begin(c), std::end(c), e) != std::end(c); +} + +std::span mlkem_pubkey_subspan(const MLKEM_Composite_Param& param, std::span key_bits) { + if(key_bits.size() <= param.mlkem_pubkey_size()) { + throw Invalid_Argument(fmt("encoded MLKEM component public key is too short (len = {})", key_bits.size())); + } + return std::span(key_bits.begin(), param.mlkem_pubkey_size()); +} + +std::span mlkem_privkey_subspan(const MLKEM_Composite_Param& param, std::span key_bits) { + if(key_bits.size() <= param.mlkem_privkey_size()) { + throw Invalid_Argument("encoded MLKEM component private key is too short"); + } + return std::span(key_bits.begin(), param.mlkem_privkey_size()); +} + +std::span traditional_pubkey_subspan(const MLKEM_Composite_Param& param, + std::span key_bits) { + const size_t offset = param.mlkem_pubkey_size(); + if(key_bits.size() <= 1 + offset) { + throw Invalid_Argument(fmt("encoded traditional component public key is too short (len = {})", key_bits.size())); + } + return std::span(key_bits.begin() + offset, key_bits.end()); +} + +std::span traditional_privkey_subspan(const MLKEM_Composite_Param& param, + std::span key_bits) { + const size_t offset = param.mlkem_privkey_size(); + if(key_bits.size() <= 1 + offset) { + throw Invalid_Argument("encoded traditional component private key is too short"); + } + return std::span(key_bits.begin() + offset, key_bits.end()); +} + +void ensure_consistent_algo_names(const Public_Key* trad_pubkey, const MLKEM_Composite_Param& param) { + if(trad_pubkey->algo_name() != param.traditional_algorithm()) { + throw Invalid_Argument( + fmt("MLKEM_Composite_Param indicates {} as the traditional algorithm – this does not fit to the {} public key", + param.traditional_algorithm(), + trad_pubkey->algo_name())); + } +} +} // namespace + +class MLKEM_Composite_Encapsulation_Operation final : public PK_Ops::KEM_Encryption { + public: + explicit MLKEM_Composite_Encapsulation_Operation( //RandomNumberGenerator& rng, + const MLKEM_Composite_Param& param, + const ML_KEM_PublicKey& mlkem_pubkey, + const Public_Key* trad_pubkey, + std::string_view provider) : + m_parameters(param), + m_mlkem_enc_op(mlkem_pubkey.create_kem_encryption_op("Raw", "")), + m_traditional_pubkey_encoded(trad_pubkey->public_key_bits()) { + ensure_consistent_algo_names(trad_pubkey, param); + if(trad_pubkey->algo_name() == "RSA") { + m_traditional_enc_op.emplace>( + trad_pubkey->create_encryption_op(m_null_rng, param.traditional_padding(), provider)); + } else { + // this cast, which would simplify the code (remove the X... branches below), doesn't work: + //const PK_Key_Agreement_Key* ec_key = dynamic_cast(trad_pubkey); + //m_traditional_enc_op.emplace>(ec_key->public_value()); +#if BOTAN_HAS_ECDH + if(param.traditional_algorithm() == "ECDH") { + const ECDH_PublicKey* ecdh_key = dynamic_cast(trad_pubkey); + m_traditional_enc_op.emplace>(ecdh_key->public_value()); + m_ec_group_opt = ecdh_key->domain(); + } else +#endif +#if BOTAN_HAS_X25519 + if(param.traditional_algorithm() == "X25519") { + const X25519_PublicKey* ecdh_key = dynamic_cast(trad_pubkey); + m_traditional_enc_op.emplace>(ecdh_key->public_value()); + } else +#endif +#if BOTAN_HAS_X448 + if(param.traditional_algorithm() == "X448") { + const X448_PublicKey* ecdh_key = dynamic_cast(trad_pubkey); + m_traditional_enc_op.emplace>(ecdh_key->public_value()); + } else +#endif + { + throw Not_Implemented("MLKEM_Composite_Encapsulation_Operation(): parameters not supported"); + } + } + } + + void kem_encrypt(std::span out_encapsulated_key, + std::span out_shared_key, + RandomNumberGenerator& rng, + size_t /*desired_shared_key_len*/, + std::span /*salt*/) override { + static const std::vector empty_salt; + secure_vector ss_mlkem(m_mlkem_enc_op->shared_key_length(32)); + secure_vector ss_trad(traditional_shared_key_length()); + if(out_encapsulated_key.size() != encapsulated_key_length()) { + throw Invalid_Argument( + fmt("provided ML-KEM composite ciphertext size for output invalid: expected: {} bytes; got {} bytes", + encapsulated_key_length(), + out_encapsulated_key.size())); + } + const std::span out_mlkem_ct(out_encapsulated_key.begin(), + out_encapsulated_key.begin() + m_parameters.mlkem_ciphertext_size()); + m_mlkem_enc_op->kem_encrypt(out_mlkem_ct, ss_mlkem, rng, 32, empty_salt); + rng.randomize_with_ts_input(ss_trad); + std::vector trad_ct; + if(std::get_if>(&this->m_traditional_enc_op) != nullptr) { + PK_Ops::Encryption& encr_op = *std::get>(this->m_traditional_enc_op); + try { + trad_ct = encr_op.encrypt(ss_trad, rng); + } catch(const PRNG_Unseeded&) { + throw Internal_Error( + "RSA encryption operation failed with PRNG_Unseeded even though use of the provided Null_RNG is not expected"); + } + } else { + std::unique_ptr privkey; +#if defined(BOTAN_HAS_ECDH) + if(m_parameters.traditional_algorithm() == "ECDH") { + privkey = std::make_unique(rng, m_ec_group_opt.value()); + } else +#endif +#if defined(BOTAN_HAS_X25519) + if(m_parameters.traditional_algorithm() == "X25519") { + privkey = std::make_unique(rng); + } else +#endif +#if defined(BOTAN_HAS_X448) + if(m_parameters.traditional_algorithm() == "X448") { + privkey = std::make_unique(rng); + } else +#endif + { + throw Internal_Error("kem_encrypt(): requested algorithm not implemented"); + } + perform_key_agreement(ss_trad, trad_ct, privkey.get(), rng); + } + + std::copy(trad_ct.begin(), trad_ct.end(), out_encapsulated_key.begin() + m_parameters.mlkem_ciphertext_size()); + // ss = SHA3-256(mlkemSS || tradSS || tradCT || tradPK || Label) + const auto sha3_256 = Botan::HashFunction::create_or_throw("SHA-3(256)"); + sha3_256->update(ss_mlkem); + sha3_256->update(ss_trad); + sha3_256->update(trad_ct); + sha3_256->update(m_traditional_pubkey_encoded); + sha3_256->update(m_parameters.label()); + sha3_256->final(out_shared_key); + } + + void perform_key_agreement(secure_vector& ss_trad, + std::vector& trad_ct, + const PK_Key_Agreement_Key* privkey, + RandomNumberGenerator& rng) { + const Botan::PK_Key_Agreement ka(*privkey, rng, "Raw"); + std::vector public_value = std::get>(m_traditional_enc_op); + ss_trad = ka.derive_key(0, public_value).bits_of(); + trad_ct = privkey->public_value(); + } + + size_t shared_key_length(size_t /*desired_shared_key_len*/) const override { return 32; } + + size_t traditional_shared_key_length() const { + if(m_parameters.traditional_algorithm() == "RSA" || m_parameters.traditional_algorithm() == "X25519") { + return 32; + } else if(m_parameters.traditional_algorithm() == "X448") { + return 56; + } else if(m_parameters.traditional_algorithm() == "ECDH") { + const size_t result = m_ec_group_opt.value().get_p_bytes(); + return result; + } + throw Not_Implemented("traditional_shared_key_length(): todo"); + } + + size_t traditional_ciphertext_length() const { + size_t result = 0; + if(m_parameters.traditional_algorithm() == "RSA") { + result = std::get>(m_traditional_enc_op) + ->ciphertext_length(traditional_shared_key_length()); + } else if(m_parameters.traditional_algorithm() == "ECDH") { + result = m_ec_group_opt.value().get_p_bytes() * 2 + 1; + } else if(m_parameters.traditional_algorithm() == "X25519") { + result = 32; + } else if(m_parameters.traditional_algorithm() == "X448") { + result = 56; + } else { + throw Not_Implemented("MLKEM_Composite_Encapsulation_Operation::traditional_ciphertext_length(): todo"); + } + return result; + } + + size_t encapsulated_key_length() const override { + return m_mlkem_enc_op->encapsulated_key_length() + traditional_ciphertext_length(); + } + + private: + MLKEM_Composite_Param m_parameters; + + std::unique_ptr m_mlkem_enc_op; + // This variant can be either an encryption_op (RSA-OAEP) or the public_value of key agreement key: + std::variant, std::vector> m_traditional_enc_op; + std::vector m_traditional_pubkey_encoded; + std::optional m_ec_group_opt; + Null_RNG m_null_rng; +}; + +class MLKEM_Composite_Decapsulation_Operation final : public PK_Ops::KEM_Decryption { + public: + explicit MLKEM_Composite_Decapsulation_Operation(RandomNumberGenerator& rng, + const MLKEM_Composite_Param& param, + const ML_KEM_PrivateKey& mlkem_privkey, + const Private_Key* trad_privkey, + std::string_view provider) : + m_parameters(param), + m_mlkem_dec_op(mlkem_privkey.create_kem_decryption_op(rng, "Raw", "")), + m_traditional_pubkey_encoded(trad_privkey->public_key()->public_key_bits()) { + if(trad_privkey->algo_name() == "RSA") { + m_traditional_dec_op.emplace>( + trad_privkey->create_decryption_op(rng, param.traditional_padding(), provider)); + // For some reason, the RSA decryption OP can't tell us it's ciphertext size. Thus we have to delve into the details... + m_rsa_modulus_bytes = dynamic_cast(trad_privkey->public_key().get())->get_n().bytes(); + } +#if BOTAN_HAS_ECDH + else if(param.traditional_algorithm() == "ECDH") { + m_traditional_dec_op.emplace(PK_Key_Agreement(*trad_privkey, rng, "Raw")); + const ECDH_PublicKey* ecdh_key = dynamic_cast(trad_privkey); + if(ecdh_key == nullptr) { + throw Internal_Error( + "ECDH_PublicKey ptr is null in MLKEM_Composite_Decapsulation_Operation, this should not happen"); + } + m_ec_group_opt = ecdh_key->domain(); + } +#endif + else if(contains<2>({"X25519", "X448"}, param.traditional_algorithm())) { + m_traditional_dec_op.emplace(PK_Key_Agreement(*trad_privkey, rng, "Raw")); + } else { + throw Not_Implemented("MLKEM_Composite_Decapsulation_Operation()::ctor todo"); + } + } + + void kem_decrypt(std::span out_shared_key, + std::span encapsulated_key, + size_t /*desired_shared_key_len*/, + std::span /*salt*/) override { + secure_vector ss_mlkem(m_mlkem_dec_op->shared_key_length(32)); + secure_vector ss_trad(traditional_shared_key_length()); + if(encapsulated_key.size() != encapsulated_key_length()) { + throw Invalid_Argument( + fmt("ML-KEM composite ciphertext length is wrong. Should be {} bytes, but is {} bytes", + encapsulated_key_length(), + encapsulated_key.size())); + } + const std::span mlkem_ct(encapsulated_key.begin(), + encapsulated_key.begin() + m_mlkem_dec_op->encapsulated_key_length()); + const std::span trad_ct(encapsulated_key.begin() + m_mlkem_dec_op->encapsulated_key_length(), + encapsulated_key.end()); + m_mlkem_dec_op->kem_decrypt(ss_mlkem, mlkem_ct, 32, std::span()); + + if(std::get_if>(&this->m_traditional_dec_op) != nullptr) { + PK_Ops::Decryption& decr_op = *std::get>(this->m_traditional_dec_op); + uint8_t valid_mask = 0; + ss_trad = decr_op.decrypt(valid_mask, trad_ct); + if(valid_mask == 0) { + // draft-ietf-lamps-pq-composite-kem-14: "In general, in the case that one of the component primitives generates an error during Composite ML-KEM KeyGen, Encaps, or Decaps, Composite ML-KEM MUST clear all buffers containing key material and forward the error to its caller; i.e. Composite ML-KEM MUST be explicitly rejecting whenever one of its components is." + throw Invalid_Argument("ciphertext was rejected during decryption"); + } + } else if(contains<3>({"ECDH", "X25519", "X448"}, m_parameters.traditional_algorithm())) { + ss_trad = std::get(m_traditional_dec_op).derive_key(0, trad_ct).bits_of(); + } else { + throw Not_Implemented("kem_decrypt: unknown algo " + m_parameters.traditional_algorithm()); + } + + const auto sha3_256 = Botan::HashFunction::create_or_throw("SHA-3(256)"); + sha3_256->update(ss_mlkem); + sha3_256->update(ss_trad); + sha3_256->update(trad_ct); + sha3_256->update(m_traditional_pubkey_encoded); + sha3_256->update(m_parameters.label()); + sha3_256->final(out_shared_key); + } + + size_t shared_key_length(size_t /*desired_shared_key_len*/) const override { return 32; } + + size_t traditional_shared_key_length() const { + if(m_parameters.traditional_algorithm() == "RSA" || m_parameters.traditional_algorithm() == "X25519") { + return 32; + } else if(m_parameters.traditional_algorithm() == "X448") { + return 56; + } else if(m_parameters.traditional_algorithm() == "ECDH") { + const size_t result = m_ec_group_opt.value().get_p_bytes(); + if(result > (521 + 7) / 8) { + throw Internal_Error("invalid ECC public key size"); + } + return result; + } + throw Internal_Error("traditional_shared_key_length(): Unknown algorithm"); + } + + size_t traditional_ciphertext_length() const { + if(m_parameters.traditional_algorithm() == "RSA") { + return m_rsa_modulus_bytes; + } else if(m_parameters.traditional_algorithm() == "ECDH") { + const size_t result = m_ec_group_opt.value().get_p_bytes() * 2 + 1; + return result; + } else if(m_parameters.traditional_algorithm() == "X25519") { + return 32; + } else if(m_parameters.traditional_algorithm() == "X448") { + return 56; + } + + throw Internal_Error("traditional_ciphertext_length(): unknown algorithm"); + } + + size_t encapsulated_key_length() const override { + return m_mlkem_dec_op->encapsulated_key_length() + traditional_ciphertext_length(); + } + + private: + MLKEM_Composite_Param m_parameters; + std::unique_ptr m_mlkem_dec_op; + std::variant, PK_Key_Agreement> m_traditional_dec_op; + std::vector m_traditional_pubkey_encoded; + size_t m_rsa_modulus_bytes = 0; + std::optional m_ec_group_opt; +}; + +// static +std::shared_ptr MLKEM_Composite_PublicKey::load_traditional_public_key(const MLKEM_Composite_Param& param, + std::span key_bits) { +#if defined(BOTAN_HAS_ECDH) + if(param.traditional_algorithm() == "ECDH") { + const auto group = Botan::EC_Group::from_name(param.curve()); + return std::make_shared(group, EC_AffinePoint(group, key_bits)); + } +#endif + return load_public_key(param.get_traditional_algorithm_id(), key_bits); +} + +MLKEM_Composite_PublicKey::MLKEM_Composite_PublicKey(const MLKEM_Composite_PublicKey& other) : + m_parameters(std::make_shared(*other.m_parameters)), + m_mlkem_pubkey(std::make_shared(*other.m_mlkem_pubkey)), + m_traditional_pubkey(load_traditional_public_key(*m_parameters, other.m_traditional_pubkey->public_key_bits())) {} + +MLKEM_Composite_PublicKey::MLKEM_Composite_PublicKey(const AlgorithmIdentifier& algo_id, + std::span key_bits) : + m_parameters(std::make_shared(MLKEM_Composite_Param::from_algo_id_or_throw(algo_id))), + m_mlkem_pubkey(std::make_shared(m_parameters->get_mlkem_algorithm_id(), + mlkem_pubkey_subspan(*m_parameters, key_bits))), + m_traditional_pubkey( + load_traditional_public_key(*m_parameters, traditional_pubkey_subspan(*m_parameters, key_bits))) {} + +MLKEM_Composite_PublicKey::MLKEM_Composite_PublicKey(MLKEM_Composite_Param::id_t id, + std::span key_bits) : + m_parameters(std::make_shared(MLKEM_Composite_Param::from_id_supported_or_throw(id))), + m_mlkem_pubkey(std::make_shared(m_parameters->get_mlkem_algorithm_id(), + mlkem_pubkey_subspan(*m_parameters, key_bits))), + m_traditional_pubkey( + load_traditional_public_key(*m_parameters, traditional_pubkey_subspan(*m_parameters, key_bits))) {} + +MLKEM_Composite_PublicKey& MLKEM_Composite_PublicKey::operator=(const MLKEM_Composite_PublicKey& rhs) { + if(this == &rhs) { + return *this; + } + m_parameters = std::make_shared(*rhs.m_parameters); + m_mlkem_pubkey = std::make_shared(*rhs.m_mlkem_pubkey); + m_traditional_pubkey = load_traditional_public_key(*m_parameters, rhs.m_traditional_pubkey->public_key_bits()); + return *this; +} + +std::vector MLKEM_Composite_PublicKey::raw_public_key_bits() const { + return public_key_bits(); +} + +OID MLKEM_Composite_PublicKey::object_identifier() const { + return m_parameters->object_identifier(); +} + +std::vector MLKEM_Composite_PublicKey::public_key_bits() const { + std::vector result(this->m_mlkem_pubkey->public_key_bits()); + std::vector trad_bytes = this->m_traditional_pubkey->public_key_bits(); + result.insert(result.end(), trad_bytes.begin(), trad_bytes.end()); + return result; +} + +std::unique_ptr MLKEM_Composite_PublicKey::generate_another(RandomNumberGenerator& rng) const { + return std::make_unique(rng, *m_parameters); +} + +std::unique_ptr MLKEM_Composite_PublicKey::create_kem_encryption_op( + std::string_view params, std::string_view provider) const { + if(!params.empty() && params != "Raw") { + throw Botan::Invalid_Argument("only empty parameters or 'Raw' is supported by MLKEM-composite KEM"); + } + if(provider.empty() || provider == "base") { + return std::make_unique( + *this->m_parameters, *this->m_mlkem_pubkey, this->m_traditional_pubkey.get(), provider); + } + throw Provider_Not_Found(algo_name(), provider); +} + +std::shared_ptr MLKEM_Composite_PrivateKey::load_traditional_private_key( + const MLKEM_Composite_Param& param, std::span trad_key_bits) { +#if defined(BOTAN_HAS_X25519) + if(param.traditional_algorithm() == "X25519") { + return std::shared_ptr(std::make_shared((X25519_PrivateKey(trad_key_bits)))); + } +#endif +#if defined(BOTAN_HAS_X448) + if(param.traditional_algorithm() == "X448") { + return std::shared_ptr(std::make_shared((X448_PrivateKey(trad_key_bits)))); + } +#endif + + return load_private_key(param.get_traditional_algorithm_id(), trad_key_bits); +} + +MLKEM_Composite_PrivateKey::MLKEM_Composite_PrivateKey(MLKEM_Composite_Param::id_t id, std::span sk) : + m_parameters(std::make_shared(MLKEM_Composite_Param::from_id_supported_or_throw(id))), + m_mlkem_privkey(std::make_shared(m_parameters->get_mlkem_algorithm_id(), + mlkem_privkey_subspan(*m_parameters, sk))), + m_traditional_privkey( + load_traditional_private_key(*m_parameters, traditional_privkey_subspan(*m_parameters, sk))) { + init_pubkey_members(); +} + +secure_vector MLKEM_Composite_PrivateKey::encode_traditional_private_key() const { + secure_vector trad_bytes; + + if(m_parameters->traditional_algorithm() == "ECDH") { + /* For ML-KEM hybrid, we MUST encode this private key format + * ( defined in https://www.rfc-editor.org/info/rfc5915/#section-3 and + * further restricted in https://www.ietf.org/archive/id/draft-ietf-lamps-pq-composite-kem-14.html#section-4-6.3.1 ) + * + * SEQUENCE { + * INTEGER 1 + * OCTET STRING + * B9 4E 76 09 A7 17 6A BA FB D4 A3 4F AB AE 42 B0 + * 91 E4 4D 9E 46 E6 7F CA 56 6C 2A 18 8A 63 C6 5F + * [0] { + * OBJECT IDENTIFIER prime256v1 (1 2 840 10045 3 1 7) + * } + * } */ + const OID oid = OIDS::str2oid_or_empty(m_parameters->curve()); + BOTAN_ASSERT(!oid.empty(), "lookup of MLKEM-composite elliptic curve OID"); + trad_bytes = DER_Encoder() + .start_sequence() + .encode(static_cast(1)) + .encode(m_traditional_privkey->raw_private_key_bits(), ASN1_Type::OctetString) + .start_explicit_context_specific(0) + .encode(oid) + .end_cons() + .end_cons() + .get_contents(); + } else { + trad_bytes = m_traditional_privkey->private_key_bits(); + } + if(m_parameters->traditional_algorithm() == "X25519" || m_parameters->traditional_algorithm() == "X448") { + secure_vector key_bits; + BER_Decoder(trad_bytes).decode(key_bits, ASN1_Type::OctetString).discard_remaining(); + std::swap(trad_bytes, key_bits); + } + return trad_bytes; +} + +secure_vector MLKEM_Composite_PrivateKey::private_key_bits() const { + secure_vector result = + m_mlkem_privkey + ->raw_private_key_bits(); // "raw_...()" should still return the raw seed even after fixing the PKCS#8 encoding format for ML-KEM + secure_vector trad_bytes = encode_traditional_private_key(); + result.insert(result.end(), trad_bytes.begin(), trad_bytes.end()); + return result; +} + +secure_vector MLKEM_Composite_PrivateKey::raw_private_key_bits() const { + return private_key_bits(); +} + +std::unique_ptr MLKEM_Composite_PrivateKey::public_key() const { + return std::make_unique(*this); +} + +/** + * Create a decryption operation that produces a MLKEM_Composite KEM Decryption Operation. + */ +std::unique_ptr MLKEM_Composite_PrivateKey::create_kem_decryption_op( + RandomNumberGenerator& rng, std::string_view params, std::string_view provider) const { + if(!params.empty() && params != "Raw") { + throw Botan::Invalid_Argument("only empty parameters or 'Raw' is supported by MLKEM-composite KEM"); + } + if(provider.empty() || provider == "base") { + auto result = std::make_unique( + rng, *this->m_parameters, *this->m_mlkem_privkey, this->m_traditional_privkey.get(), provider); + return result; + } + throw Provider_Not_Found(algo_name(), provider); +} + +MLKEM_Composite_PrivateKey::MLKEM_Composite_PrivateKey(const AlgorithmIdentifier& algo_id, + std::span sk) : + + m_parameters(std::make_shared(MLKEM_Composite_Param::from_algo_id_or_throw(algo_id))), + m_mlkem_privkey(std::make_shared(m_parameters->get_mlkem_algorithm_id(), + mlkem_privkey_subspan(*m_parameters, sk))), + m_traditional_privkey(load_traditional_private_key(*m_parameters, traditional_privkey_subspan(*m_parameters, sk))) + +{ + init_pubkey_members(); +} + +// static +std::unique_ptr MLKEM_Composite_PrivateKey::create_traditional_private_key(RandomNumberGenerator& rng, + MLKEM_Composite_Param param) { +#if defined(BOTAN_HAS_ECDH) + if(param.traditional_algorithm() == "ECDH") { + const auto group = Botan::EC_Group::from_name(param.curve()); + return std::make_unique(rng, group); + } +#endif + return create_private_key(param.traditional_algorithm(), rng, param.get_traditional_algo_param_str()); +} + +MLKEM_Composite_PrivateKey::MLKEM_Composite_PrivateKey(RandomNumberGenerator& rng, MLKEM_Composite_Param param) : + m_parameters(std::make_shared(param)), + m_mlkem_privkey(std::make_shared(rng, m_parameters->get_mlkem_mode())), + m_traditional_privkey(create_traditional_private_key(rng, param)) { + init_pubkey_members(); +} + +void MLKEM_Composite_PrivateKey::init_pubkey_members() { + MLKEM_Composite_PublicKey::m_parameters = m_parameters; + MLKEM_Composite_PublicKey::m_mlkem_pubkey = m_mlkem_privkey; + MLKEM_Composite_PublicKey::m_traditional_pubkey = m_traditional_privkey; +} + +MLKEM_Composite_PrivateKey::MLKEM_Composite_PrivateKey(const MLKEM_Composite_PrivateKey& other) : + MLKEM_Composite_PublicKey(other), // this assigns private-key independent members in the public key! + m_parameters(std::make_shared(*other.m_parameters)), + m_mlkem_privkey(std::make_shared(*other.m_mlkem_privkey)), + m_traditional_privkey(load_traditional_private_key( + *m_parameters, traditional_privkey_subspan(*m_parameters, other.private_key_bits()))) { + init_pubkey_members(); // set them as shared, otherwise inconsistency may result +} + +MLKEM_Composite_PrivateKey& MLKEM_Composite_PrivateKey::operator=(const MLKEM_Composite_PrivateKey& rhs) { + if(this == &rhs) { + return *this; + } + m_parameters = std::make_shared(*rhs.m_parameters); + m_mlkem_privkey = std::make_shared(*rhs.m_mlkem_privkey); + m_traditional_privkey = + load_traditional_private_key(*m_parameters, traditional_privkey_subspan(*m_parameters, rhs.private_key_bits())); + init_pubkey_members(); // set them as shared, otherwise inconsistency may result + + return *this; +} +} // namespace Botan diff --git a/src/lib/pubkey/mlkem-composite/mlkem_comp.h b/src/lib/pubkey/mlkem-composite/mlkem_comp.h new file mode 100644 index 00000000000..1f57d807ad0 --- /dev/null +++ b/src/lib/pubkey/mlkem-composite/mlkem_comp.h @@ -0,0 +1,154 @@ +/* + * ML-KEM Composite KEM + * (C) 2026 Falko Strenzke, MTG AG + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#ifndef BOTAN_MLKEM_COMP_H_ +#define BOTAN_MLKEM_COMP_H_ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { +class BOTAN_PUBLIC_API(3, 0) MLKEM_Composite_PublicKey : public virtual Public_Key { + public: + /** + * Loads a public key. + * + * @param key_bits DER encoded public key bits + */ + BOTAN_FUTURE_EXPLICIT MLKEM_Composite_PublicKey(MLKEM_Composite_Param::id_t id, + std::span key_bits); + + BOTAN_FUTURE_EXPLICIT MLKEM_Composite_PublicKey(const AlgorithmIdentifier& algo_id, + std::span key_bits); + + std::string algo_name() const override { return "MLKEM_Composite"; } + + AlgorithmIdentifier algorithm_identifier() const override { + return AlgorithmIdentifier(object_identifier(), AlgorithmIdentifier::USE_EMPTY_PARAM); + } + + bool check_key(RandomNumberGenerator& rng, bool strong) const override { + return this->m_mlkem_pubkey->check_key(rng, strong) && this->m_traditional_pubkey->check_key(rng, strong); + } + + OID object_identifier() const override; + + /** + * Return the pessimistic estimated key strength, i.e., the smaller strength of the component keys. + * This is justified by the assumption that composite algorithms are used in the assumption that + * one of the component algorithms might be broken. + * + * @return the mimium of the components' estimated strengths. + */ + size_t estimated_strength() const override { + return std::max(this->m_mlkem_pubkey->estimated_strength(), this->m_traditional_pubkey->estimated_strength()); + } + + /** + * + * @return The sum of the component key lengths. + */ + size_t key_length() const override { return m_mlkem_pubkey->key_length() + m_traditional_pubkey->key_length(); } + + std::vector raw_public_key_bits() const override; + + std::vector public_key_bits() const override; + + BOTAN_DEPRECATED("Use raw_public_key_bits()") std::vector raw_public_key() const; + + std::unique_ptr generate_another(RandomNumberGenerator& rng) const final; + + bool supports_operation(PublicKeyOperation op) const override { + return (op == PublicKeyOperation::KeyEncapsulation); + } + + std::unique_ptr create_kem_encryption_op(std::string_view params, + std::string_view provider) const override; + + MLKEM_Composite_PublicKey(const MLKEM_Composite_PublicKey& other); + + MLKEM_Composite_PublicKey& operator=(const MLKEM_Composite_PublicKey& rhs); + + ~MLKEM_Composite_PublicKey() override = default; + + MLKEM_Composite_PublicKey(const MLKEM_Composite_PublicKey&& other) = delete; + MLKEM_Composite_PublicKey& operator=(const MLKEM_Composite_PublicKey&& rhs) = delete; + + protected: + static std::shared_ptr load_traditional_public_key(const MLKEM_Composite_Param& param, + std::span key_bits); + MLKEM_Composite_PublicKey() = default; + + std::shared_ptr m_parameters; // NOLINT(*non-private-member-variable*) + std::shared_ptr m_mlkem_pubkey; // NOLINT(*non-private-member-variable*) + std::shared_ptr m_traditional_pubkey; // NOLINT(*non-private-member-variable*) +}; + +BOTAN_DIAGNOSTIC_PUSH +BOTAN_DIAGNOSTIC_IGNORE_INHERITED_VIA_DOMINANCE + +class BOTAN_PUBLIC_API(3, 0) MLKEM_Composite_PrivateKey final : public virtual MLKEM_Composite_PublicKey, + public virtual Botan::Private_Key { + public: + std::unique_ptr public_key() const override; + + /** + * Generates a new key pair + */ + MLKEM_Composite_PrivateKey(RandomNumberGenerator& rng, MLKEM_Composite_Param param); + + /** + * Read an encoded private key. + */ + MLKEM_Composite_PrivateKey(const AlgorithmIdentifier& alg_id, std::span sk); + + /** + * Read an encoded private key. + */ + MLKEM_Composite_PrivateKey(MLKEM_Composite_Param::id_t id, std::span sk); + + secure_vector private_key_bits() const override; + + secure_vector raw_private_key_bits() const override; + + /** + * Create a signature operation that produces a MLKEM_Composite signature. + */ + std::unique_ptr create_kem_decryption_op(RandomNumberGenerator& rng, + std::string_view params, + std::string_view provider) const override; + + MLKEM_Composite_PrivateKey(const MLKEM_Composite_PrivateKey& other); + + MLKEM_Composite_PrivateKey& operator=(const MLKEM_Composite_PrivateKey& rhs); + + ~MLKEM_Composite_PrivateKey() override = default; + + MLKEM_Composite_PrivateKey(const MLKEM_Composite_PrivateKey&& other) = delete; + MLKEM_Composite_PrivateKey& operator=(const MLKEM_Composite_PrivateKey&& rhs) = delete; + + private: + static std::shared_ptr load_traditional_private_key(const MLKEM_Composite_Param& param, + std::span key_bits); + static std::unique_ptr create_traditional_private_key(RandomNumberGenerator& rng, + MLKEM_Composite_Param param); + void init_pubkey_members(); + + secure_vector encode_traditional_private_key() const; + friend class MLKEM_Composite_Signature_Operation; + std::shared_ptr m_parameters; + std::shared_ptr m_mlkem_privkey; + std::shared_ptr m_traditional_privkey; +}; +} // namespace Botan + +#endif /* BOTAN_MLKEM_COMP_H_ */ diff --git a/src/lib/pubkey/mlkem-composite/mlkem_comp_parameters.cpp b/src/lib/pubkey/mlkem-composite/mlkem_comp_parameters.cpp new file mode 100644 index 00000000000..afd61f33ac2 --- /dev/null +++ b/src/lib/pubkey/mlkem-composite/mlkem_comp_parameters.cpp @@ -0,0 +1,332 @@ +/* + * ML-KEM Composite KEM Parameters + * (C) 2026 Falko Strenzke, MTG AG + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace Botan { + +const MLKEM_Composite_Param MLKEM_Composite_Param::mlkem_composite_registry[] = { + + MLKEM_Composite_Param(MLKEM_Composite_Param::id_t::MLKEM768_RSA2048_SHA3_256, + "MLKEM768-RSA2048-SHA3-256", + "MLKEM768-RSAOAEP2048", + ML_KEM_Mode::Mode::ML_KEM_768, + "RSA", + "OAEP(SHA-256)", + "", + 2048), + MLKEM_Composite_Param(MLKEM_Composite_Param::id_t::MLKEM768_RSA3072_SHA3_256, + "MLKEM768-RSA3072-SHA3-256", + "MLKEM768-RSAOAEP3072", + ML_KEM_Mode::Mode::ML_KEM_768, + "RSA", + "OAEP(SHA-256)", + "", + 3072), + MLKEM_Composite_Param(MLKEM_Composite_Param::id_t::MLKEM768_RSA4096_SHA3_256, + "MLKEM768-RSA4096-SHA3-256", + "MLKEM768-RSAOAEP4096", + ML_KEM_Mode::Mode::ML_KEM_768, + "RSA", + "OAEP(SHA-256)", + "", + 4096), + MLKEM_Composite_Param(MLKEM768_X25519_SHA3_256, + "MLKEM768-X25519-SHA3-256", + "\\.//^\\", + ML_KEM_Mode::Mode::ML_KEM_768, + "X25519", + "", + "", + 255), + MLKEM_Composite_Param(MLKEM_Composite_Param::id_t::MLKEM1024_RSA3072_SHA3_256, + "MLKEM1024-RSA3072-SHA3-256", + "MLKEM1024-RSAOAEP3072", + ML_KEM_Mode::Mode::ML_KEM_1024, + "RSA", + "OAEP(SHA-256)", + "", + 3072), + MLKEM_Composite_Param(MLKEM768_ECDH_P256_SHA3_256, + "MLKEM768-ECDH-P256-SHA3-256", + "MLKEM768-P256", + ML_KEM_Mode::Mode::ML_KEM_768, + "ECDH", + "", + "secp256r1", + 256), + MLKEM_Composite_Param(MLKEM768_ECDH_P384_SHA3_256, + "MLKEM768-ECDH-P384-SHA3-256", + "MLKEM768-P384", + ML_KEM_Mode::Mode::ML_KEM_768, + "ECDH", + "", + "secp384r1", + 384), + MLKEM_Composite_Param(MLKEM768_ECDH_brainpoolP256r1_SHA3_256, + "MLKEM768-ECDH-brainpoolP256r1-SHA3-256", + "MLKEM768-BP256", + ML_KEM_Mode::Mode::ML_KEM_768, + "ECDH", + "", + "brainpool256r1", + 256), + MLKEM_Composite_Param(MLKEM1024_ECDH_P384_SHA3_256, + "MLKEM1024-ECDH-P384-SHA3-256", + "MLKEM1024-P384", + ML_KEM_Mode::Mode::ML_KEM_1024, + "ECDH", + "", + "secp384r1", + 384), + MLKEM_Composite_Param(MLKEM1024_ECDH_brainpoolP384r1_SHA3_256, + "MLKEM1024-ECDH-brainpoolP384r1-SHA3-256", + "MLKEM1024-BP384", + ML_KEM_Mode::Mode::ML_KEM_1024, + "ECDH", + "", + "brainpool384r1", + 384), + MLKEM_Composite_Param(MLKEM1024_X448_SHA3_256, + "MLKEM1024-X448-SHA3-256", + "MLKEM1024-X448", + ML_KEM_Mode::Mode::ML_KEM_1024, + "X448", + "", + "", + 224), + MLKEM_Composite_Param(MLKEM1024_ECDH_P521_SHA3_256, + "MLKEM1024-ECDH-P521-SHA3-256", + "MLKEM1024-P521", + ML_KEM_Mode::Mode::ML_KEM_1024, + "ECDH", + "", + "secp521r1", + 521) + +}; + +// static +std::vector MLKEM_Composite_Param::all_param_sets() { + std::vector result; + for(const auto& param : mlkem_composite_registry) { + result.push_back(param); + } + return result; +} + +// static +std::vector MLKEM_Composite_Param::all_supported_param_sets() { + std::vector result; + for(const auto& param : mlkem_composite_registry) { + if(param.is_supported()) { + result.push_back(param); + } + } + return result; +} + +// static +std::optional MLKEM_Composite_Param::from_id_str(std::string_view id_str) { + for(const auto& param : mlkem_composite_registry) { + if(param.m_id_str == id_str) { + return std::optional(param); + } + } + return std::optional(); +} + +//static +std::optional MLKEM_Composite_Param::from_algo_id(const AlgorithmIdentifier& algo_id) { + for(const auto& param : mlkem_composite_registry) { + if(param.get_composite_algorithm_id() == algo_id) { + return std::optional(param); + } + } + return std::optional(); +} + +//static +MLKEM_Composite_Param MLKEM_Composite_Param::from_algo_id_or_throw(const AlgorithmIdentifier& algo_id) { + const auto result = from_algo_id(algo_id); + if(!result.has_value()) { + throw Botan::Invalid_Argument("no parameter found for provided MLKEM composite algo id"); + } + return result.value(); +} + +// static +MLKEM_Composite_Param MLKEM_Composite_Param::from_id_str_or_throw(std::string_view id_str) { + const auto result = from_id_str(id_str); + if(!result.has_value()) { + throw Botan::Invalid_Argument("no parameter found for provided MLKEM composite id " + std::string(id_str)); + } + return result.value(); +} + +// static +std::optional MLKEM_Composite_Param::from_id(MLKEM_Composite_Param::id_t id) { + for(const auto& param : mlkem_composite_registry) { + if(param.m_id == id) { + return std::optional(param); + } + } + return std::optional(); +} + +// static +MLKEM_Composite_Param MLKEM_Composite_Param::from_id_supported_or_throw(MLKEM_Composite_Param::id_t id) { + const auto result = from_id(id); + if(!result.has_value()) { + throw Botan::Invalid_Argument("no parameter found for provided MLKEM composite id (enum)"); + } + if(!result.value().is_supported()) { + throw Not_Implemented("Parameter set " + result.value().id_str() + + " is not supported by Botan's build configuration"); + } + return result.value(); +} + +MLKEM_Composite_Param::MLKEM_Composite_Param(id_t the_id, + const char* the_id_str, + const char* the_label, + ML_KEM_Mode::Mode the_mlkem_variant, + const char* the_traditional_algorithm, + const char* the_traditional_padding, + const char* the_curve, + uint32_t the_traditional_key_size) noexcept : + m_id_str(the_id_str), + m_label(the_label), + m_traditional_algorithm(the_traditional_algorithm), + m_traditional_padding(the_traditional_padding), + m_curve(the_curve), + m_id(the_id), + m_traditional_key_size(the_traditional_key_size), + m_mlkem_variant(the_mlkem_variant) {} + +const char* MLKEM_Composite_Param::mlkem_oid_str() const { + if(m_mlkem_variant == ML_KEM_Mode::ML_KEM_768) { + return "2.16.840.1.101.3.4.4.2"; + } else if(m_mlkem_variant == ML_KEM_Mode::ML_KEM_1024) { + return "2.16.840.1.101.3.4.4.3"; + } + throw Internal_Error("invalid MLKEM mode in MLKEM composite parameters"); +} + +size_t MLKEM_Composite_Param::mlkem_pubkey_size() const { + if(m_mlkem_variant == ML_KEM_Mode::Mode::ML_KEM_768) { + return 1184; + } + return 1568; // must be ML-KEM-1024 +} + +size_t MLKEM_Composite_Param::mlkem_ciphertext_size() const { + if(this->m_mlkem_variant == ML_KEM_Mode::Mode::ML_KEM_768) { + return 1088; + } else if(this->m_mlkem_variant == ML_KEM_Mode::Mode::ML_KEM_1024) { + return 1568; + } + throw Botan::Internal_Error("MLKEM_Composite_Param::mlkem_signature_size() encountered unknown ML-KEM variant "); +} + +AlgorithmIdentifier MLKEM_Composite_Param::get_composite_algorithm_id() const { + std::optional oid; + oid = OID::from_name(m_id_str); + if(!oid.has_value()) { + throw Botan::Internal_Error(fmt("could not look up own MLKEM Composite OID for ID-string '{}'", m_id_str)); + } + return AlgorithmIdentifier(oid.value(), AlgorithmIdentifier::Encoding_Option::USE_EMPTY_PARAM); +} + +AlgorithmIdentifier MLKEM_Composite_Param::get_mlkem_algorithm_id() const { + const OID oid(this->mlkem_oid_str()); + return AlgorithmIdentifier(oid, AlgorithmIdentifier::Encoding_Option::USE_EMPTY_PARAM); +} + +AlgorithmIdentifier MLKEM_Composite_Param::get_traditional_algorithm_id() const { + std::optional oid; + if(0 == std::strcmp(this->m_traditional_algorithm, "ECDH")) { + oid = OID::from_name(std::string("ECDH")); + } else { + oid = OID::from_name(this->m_traditional_algorithm); + } + if(!oid.has_value()) { + throw Botan::Internal_Error( + "MLKEM_Composite_Param::get_traditional_algorithm_id_by_id(): could not lookup algorithm OID of traditional algorithm as expected"); + } + return AlgorithmIdentifier(oid.value(), AlgorithmIdentifier::Encoding_Option::USE_EMPTY_PARAM); +} + +size_t MLKEM_Composite_Param::traditional_pubkey_size() const { + if(0 == std::strcmp(this->m_traditional_algorithm, "RSA")) { + return m_traditional_key_size; + } + throw Not_Implemented("todo"); +} + +size_t MLKEM_Composite_Param::traditional_ciphertext_length() const { + if(traditional_algorithm() == "RSA") { + return (traditional_pubkey_size() + 7) / 8; + } + throw Not_Implemented("todo"); +} + +std::string MLKEM_Composite_Param::get_traditional_algo_param_str() const { + if(0 == strcmp(this->m_traditional_algorithm, "RSA")) { + return std::to_string(m_traditional_key_size); + } + return ""; +} + +OID MLKEM_Composite_Param::object_identifier() const { + return OID_Map::global_registry().str2oid(this->m_id_str); +} + +bool MLKEM_Composite_Param::is_supported() const { + bool result = false; +#if defined(BOTAN_HAS_RSA) && defined(BOTAN_HAS_OAEP) + result = result || m_id == MLKEM768_RSA2048_SHA3_256 || m_id == MLKEM768_RSA3072_SHA3_256 || + m_id == MLKEM768_RSA4096_SHA3_256 || m_id == MLKEM1024_RSA3072_SHA3_256; +#endif +#if defined(BOTAN_HAS_ECDH) + #if defined(BOTAN_HAS_PCURVES_GENERIC) || defined(BOTAN_HAS_PCURVES_SECP256R1) + result = result || m_id == MLKEM768_ECDH_P256_SHA3_256; + #endif + #if defined(BOTAN_HAS_PCURVES_GENERIC) || defined(BOTAN_HAS_PCURVES_SECP384R1) + result = result || m_id == MLKEM768_ECDH_P384_SHA3_256 || m_id == MLKEM1024_ECDH_P384_SHA3_256; + #endif + #if defined(BOTAN_HAS_PCURVES_GENERIC) || defined(BOTAN_HAS_PCURVES_BRAINPOOL256R1) + result = result || m_id == MLKEM768_ECDH_brainpoolP256r1_SHA3_256; + #endif + #if defined(BOTAN_HAS_PCURVES_GENERIC) || defined(BOTAN_HAS_PCURVES_BRAINPOOL384R1) + result = result || m_id == MLKEM1024_ECDH_brainpoolP384r1_SHA3_256; + #endif + #if defined(BOTAN_HAS_PCURVES_GENERIC) || defined(BOTAN_HAS_PCURVES_SECP521R1) + result = result || m_id == MLKEM1024_ECDH_P521_SHA3_256; + #endif +#endif +#if defined(BOTAN_HAS_X25519) + result = result || m_id == MLKEM768_X25519_SHA3_256; +#endif +#if defined(BOTAN_HAS_X448) + result = result || m_id == MLKEM1024_X448_SHA3_256; +#endif + return result; +} + +} // namespace Botan diff --git a/src/lib/pubkey/mlkem-composite/mlkem_comp_parameters.h b/src/lib/pubkey/mlkem-composite/mlkem_comp_parameters.h new file mode 100644 index 00000000000..885e7901a1d --- /dev/null +++ b/src/lib/pubkey/mlkem-composite/mlkem_comp_parameters.h @@ -0,0 +1,132 @@ +/* + * ML-KEM Composite KEM Parameters + * (C) 2026 Falko Strenzke, MTG AG + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#ifndef BOTAN_MLKEM_COMP_PARAMETERS_H_ +#define BOTAN_MLKEM_COMP_PARAMETERS_H_ + +#include +#include +#include + +namespace Botan { + +class BOTAN_PUBLIC_API(3, 0) MLKEM_Composite_Param { + public: + enum id_t : uint32_t /* NOLINT(*-enum-size,*-use-enum-class) */ { + MLKEM768_RSA2048_SHA3_256, + MLKEM768_RSA3072_SHA3_256, + MLKEM768_RSA4096_SHA3_256, + MLKEM768_X25519_SHA3_256, + MLKEM768_ECDH_P256_SHA3_256, + MLKEM768_ECDH_P384_SHA3_256, + MLKEM1024_RSA3072_SHA3_256, + MLKEM768_ECDH_brainpoolP256r1_SHA3_256, + MLKEM1024_ECDH_P384_SHA3_256, + MLKEM1024_ECDH_brainpoolP384r1_SHA3_256, + MLKEM1024_X448_SHA3_256, + MLKEM1024_ECDH_P521_SHA3_256 + }; + + static inline const char* generic_algo_name = "ML-KEM-Composite"; + + static std::vector all_param_sets(); + + static std::vector all_supported_param_sets(); + + /** + * @brief Create a parameters object from the provided id. If the parameters are not supported by the build configuration of the library, throw a Not_Implemented exception. + * + * @param id The id of the parameter set to create. + * + * @return The parameter object. + */ + static MLKEM_Composite_Param from_id_supported_or_throw(MLKEM_Composite_Param::id_t id); + + static std::optional from_id(MLKEM_Composite_Param::id_t id); + + static MLKEM_Composite_Param from_id_str_or_throw(std::string_view id_str); + + static std::optional from_id_str(std::string_view id_str); + + static std::optional from_algo_id(const AlgorithmIdentifier& algo_id); + + static MLKEM_Composite_Param from_algo_id_or_throw(const AlgorithmIdentifier& algo_id); + + MLKEM_Composite_Param clone() const { return MLKEM_Composite_Param::from_id_supported_or_throw(m_id); } + + /** + * @brief + * Find out whether the library build supports this parameter. + * + * @return true if the parameter is supported, false otherwise + */ + bool is_supported() const; + + AlgorithmIdentifier get_composite_algorithm_id() const; + + AlgorithmIdentifier get_mlkem_algorithm_id() const; + + AlgorithmIdentifier get_traditional_algorithm_id() const; + + size_t traditional_shared_key_length() const; + + OID object_identifier() const; + + /* std::string mlkem_param_str() const; */ + + ML_KEM_Mode get_mlkem_mode() const { return m_mlkem_variant; } + + size_t mlkem_ciphertext_size() const; + + size_t mlkem_pubkey_size() const; + + const char* mlkem_oid_str() const; + + MLKEM_Composite_Param::id_t id() const { return m_id; } + + std::string id_str() const { return std::string(this->m_id_str); } + + std::string label() const { return std::string(this->m_label); } + + std::string traditional_algorithm() const { return std::string(this->m_traditional_algorithm); } + + std::string traditional_padding() const { return std::string(this->m_traditional_padding); } + + std::string curve() const { return std::string(this->m_curve); } + + std::string get_traditional_algo_param_str() const; + size_t traditional_pubkey_size() const; + + size_t traditional_ciphertext_length() const; + + size_t mlkem_privkey_size() const { return 64; } + + private: + MLKEM_Composite_Param(id_t id, + const char* id_str, + const char* label, + ML_KEM_Mode::Mode mlkem_variant, + const char* traditional_algorithm, + const char* traditional_padding, + const char* curve, + uint32_t traditional_key_size) noexcept; + + const char* m_id_str; + const char* m_label; + const char* m_traditional_algorithm; + const char* m_traditional_padding; + const char* m_curve; + id_t m_id; + uint32_t m_traditional_key_size; + ML_KEM_Mode::Mode m_mlkem_variant; + + static const MLKEM_Composite_Param mlkem_composite_registry[]; +}; + +} // namespace Botan + +#endif /* BOTAN_MLKEM_COMP_PARAMETERS_H_ */ diff --git a/src/lib/pubkey/pk_algs.cpp b/src/lib/pubkey/pk_algs.cpp index 4e8a4e13a3a..9c6bfb15841 100644 --- a/src/lib/pubkey/pk_algs.cpp +++ b/src/lib/pubkey/pk_algs.cpp @@ -97,6 +97,10 @@ #include #endif +#if defined(BOTAN_HAS_MLKEM_COMPOSITE) + #include +#endif + #if defined(BOTAN_HAS_HSS_LMS) #include #endif @@ -183,6 +187,21 @@ std::unique_ptr load_public_key(const AlgorithmIdentifier& alg_id, } #endif +#if defined(BOTAN_HAS_MLKEM_COMPOSITE) + { + auto mlkem_comp_param_opt = MLKEM_Composite_Param::from_algo_id(alg_id); + if(mlkem_comp_param_opt.has_value()) { + auto& comp_parm = mlkem_comp_param_opt.value(); + if(comp_parm.is_supported()) { + return std::make_unique(alg_id, key_bits); + } else { + throw Not_Implemented(fmt("MLKEM-composite is supported, but the requested parameter set {} is not", + alg_id.get_oid().to_string())); + } + } + } +#endif + #if defined(BOTAN_HAS_ECDSA) if(alg_name == "ECDSA") { return std::make_unique(alg_id, key_bits); @@ -368,6 +387,21 @@ std::unique_ptr load_private_key(const AlgorithmIdentifier& alg_id, } #endif +#if defined(BOTAN_HAS_MLKEM_COMPOSITE) + { + auto mlkem_comp_param_opt = MLKEM_Composite_Param::from_algo_id(alg_id); + if(mlkem_comp_param_opt.has_value()) { + auto& comp_param = mlkem_comp_param_opt.value(); + if(comp_param.is_supported()) { + return std::make_unique(alg_id, key_bits); + } else { + throw Not_Implemented(fmt("MLKEM-composite is supported, but the requested parameter set {} is not", + alg_id.get_oid().to_string())); + } + } + } +#endif + #if defined(BOTAN_HAS_MCELIECE) if(alg_name == "McEliece") { return std::make_unique(alg_id, key_bits); @@ -595,6 +629,20 @@ std::unique_ptr create_private_key(std::string_view alg_name, } #endif +#if defined(BOTAN_HAS_MLKEM_COMPOSITE) + { + if(alg_name == MLKEM_Composite_Param::generic_algo_name) { + auto comp_param = MLKEM_Composite_Param::from_id_str_or_throw(params); + if(comp_param.is_supported()) { + return std::make_unique(rng, comp_param); + } else { + throw Not_Implemented( + fmt("MLKEM-composite is supported, but the requested parameter set {} is not", params)); + } + } + } +#endif + #if defined(BOTAN_HAS_DILITHIUM) || defined(BOTAN_HAS_DILITHIUM_AES) if(alg_name == "Dilithium" || alg_name.starts_with("Dilithium-")) { const auto mode = [&]() -> DilithiumMode { diff --git a/src/lib/pubkey/pk_ops.cpp b/src/lib/pubkey/pk_ops.cpp index f5c4eea7a39..6eb20f07d15 100644 --- a/src/lib/pubkey/pk_ops.cpp +++ b/src/lib/pubkey/pk_ops.cpp @@ -219,8 +219,14 @@ void PK_Ops::KEM_Encryption_with_KDF::kem_encrypt(std::span out_encapsu size_t desired_shared_key_len, std::span salt) { BOTAN_ARG_CHECK(salt.empty() || m_kdf, "PK_KEM_Encryptor::encrypt requires a KDF to use a salt"); - BOTAN_ASSERT_NOMSG(out_encapsulated_key.size() == encapsulated_key_length()); - + BOTAN_ASSERT_EQUAL( + out_encapsulated_key.size(), + encapsulated_key_length(), + fmt( + "size of ciphertext argument to kem_encrypt ({} bytes) and the ciphertext size expected by the KEM_Encryption_with_KDF instance ({} bytes) differ", + out_encapsulated_key.size(), + encapsulated_key_length()) + .c_str()); if(m_kdf) { BOTAN_ASSERT_EQUAL( out_shared_key.size(), desired_shared_key_len, "KDF output length and shared key length match"); diff --git a/src/lib/pubkey/pubkey.cpp b/src/lib/pubkey/pubkey.cpp index 8d400854a65..2ec54db062f 100644 --- a/src/lib/pubkey/pubkey.cpp +++ b/src/lib/pubkey/pubkey.cpp @@ -205,8 +205,14 @@ void PK_KEM_Decryptor::decrypt(std::span out_shared_key, std::span encap_key, size_t desired_shared_key_len, std::span salt) { - BOTAN_ARG_CHECK(out_shared_key.size() == shared_key_length(desired_shared_key_len), - "inconsistent size of shared key output buffer"); + BOTAN_ARG_CHECK( + out_shared_key.size() == shared_key_length(desired_shared_key_len), + fmt( + "inconsistent size of shared key output buffer: requested in call to decrypt: {} bytes; determined in PK_KEM_Decryptor instance for desired key length of {} bytes: {} bytes", + out_shared_key.size(), + desired_shared_key_len, + shared_key_length(desired_shared_key_len)) + .c_str()); m_op->kem_decrypt(out_shared_key, encap_key, desired_shared_key_len, salt); } diff --git a/src/python/botan3.py b/src/python/botan3.py index 9c039eb1051..9c7ebf2a1c6 100755 --- a/src/python/botan3.py +++ b/src/python/botan3.py @@ -457,6 +457,8 @@ def ffi_api(fn, args, allowed_errors=None): ffi_api(dll.botan_pubkey_view_kyber_raw_key, [c_void_p, c_void_p, VIEW_BIN_CALLBACK]) ffi_api(dll.botan_privkey_load_ml_kem, [c_void_p, c_void_p, c_int, c_char_p]) ffi_api(dll.botan_pubkey_load_ml_kem, [c_void_p, c_void_p, c_int, c_char_p]) + ffi_api(dll.botan_privkey_load_mlkem_composite, [c_void_p, c_void_p, c_int, c_char_p]) + ffi_api(dll.botan_pubkey_load_mlkem_composite, [c_void_p, c_void_p, c_int, c_char_p]) ffi_api(dll.botan_privkey_load_frodokem, [c_void_p, c_void_p, c_int, c_char_p]) ffi_api(dll.botan_pubkey_load_frodokem, [c_void_p, c_void_p, c_int, c_char_p]) ffi_api(dll.botan_privkey_load_classic_mceliece, [c_void_p, c_void_p, c_int, c_char_p]) @@ -1617,6 +1619,14 @@ def load_ml_kem(cls, mlkem_mode: str, key: bytes) -> PublicKey: _DLL.botan_pubkey_load_ml_kem(byref(pub.handle_()), key, len(key), _ctype_str(mlkem_mode)) return pub + @classmethod + def load_mlkem_composite(cls, mlkem_composite_mode: str, key: bytes) -> PublicKey: + """Load an ML-KEM-Composite public key giving the mode as a string + (like "MLKEM768-X25519-SHA3-256") and the raw encoding of the public key.""" + pub = PublicKey() + _DLL.botan_pubkey_load_mlkem_composite(byref(pub.handle_()), key, len(key), _ctype_str(mlkem_composite_mode)) + return pub + @classmethod def load_ml_dsa(cls, mldsa_mode: str, key: bytes) -> PublicKey: """Load an ML-DSA public key giving the mode as a string (like "ML-DSA-4x4") @@ -1872,6 +1882,13 @@ def load_ml_kem(cls, mlkem_mode: str, key: bytes) -> PrivateKey: _DLL.botan_privkey_load_ml_kem(byref(priv.handle_()), key, len(key), _ctype_str(mlkem_mode)) return priv + @classmethod + def load_mlkem_composite(cls, mlkem_composite_mode: str, key: bytes) -> PrivateKey: + """Return a private ML-KEM-Composite key""" + priv = PrivateKey() + _DLL.botan_privkey_load_mlkem_composite(byref(priv.handle_()), key, len(key), _ctype_str(mlkem_composite_mode)) + return priv + @classmethod def load_ml_dsa(cls, mldsa_mode: str, key: bytes) -> PrivateKey: """Return a private ML-DSA key""" diff --git a/src/scripts/test_python.py b/src/scripts/test_python.py index 359f3a842dd..b3c4b9ad961 100644 --- a/src/scripts/test_python.py +++ b/src/scripts/test_python.py @@ -1241,6 +1241,20 @@ def test_ml_kem_raw_keys(self): self.assertEqual(sk_read.to_raw(), sk_bits) self.assertEqual(pk_read.to_raw(), pk_bits) + def test_ml_kem_composite_raw_keys(self): + mlkem_composite_mode = "MLKEM768-X25519-SHA3-256" + sk = botan.PrivateKey.create("ML-KEM-Composite", mlkem_composite_mode, botan.RandomNumberGenerator("user")) + pk = sk.get_public_key() + + sk_bits = sk.to_raw() + pk_bits = pk.to_raw() + + sk_read = botan.PrivateKey.load_mlkem_composite(mlkem_composite_mode, sk_bits) + pk_read = botan.PublicKey.load_mlkem_composite(mlkem_composite_mode, pk_bits) + + self.assertEqual(sk_read.to_raw(), sk_bits) + self.assertEqual(pk_read.to_raw(), pk_bits) + def test_ml_dsa_raw_keys(self): mldsa_mode = "ML-DSA-4x4" sk = botan.PrivateKey.create("ML-DSA", mldsa_mode, botan.RandomNumberGenerator("user")) diff --git a/src/tests/data/pubkey/ecc-key-and-param.vec b/src/tests/data/pubkey/ecc-key-and-param.vec new file mode 100644 index 00000000000..1a86941dba2 --- /dev/null +++ b/src/tests/data/pubkey/ecc-key-and-param.vec @@ -0,0 +1,25 @@ + +# Test encoded group in key only +key = 30310201010420984397BCC439C060EF5109CCE70B96DD735A33D0EE53A17AB997A9CCE46ACAABA00A06082A8648CE3D030107 +param = +valid = true + +# Test group in AlgorithmIdentifier parameter only +key = 30250201010420984397BCC439C060EF5109CCE70B96DD735A33D0EE53A17AB997A9CCE46ACAAB +param = 1.2.840.10045.3.1.7 +valid = true + +# Test valid combination of same encoded group in key and in AlgorithmIdentifier parameter +key = 30310201010420984397BCC439C060EF5109CCE70B96DD735A33D0EE53A17AB997A9CCE46ACAABA00A06082A8648CE3D030107 +param = 1.2.840.10045.3.1.7 +valid = true + +# Test invalid combination of encoded group and AlgorithmIdentifier parameter +key = 30310201010420984397BCC439C060EF5109CCE70B96DD735A33D0EE53A17AB997A9CCE46ACAABA00A06082A8648CE3D030107 +param = 1.3.132.0.34 +valid = false + +# Test no parameter at all +key = 30250201010420984397BCC439C060EF5109CCE70B96DD735A33D0EE53A17AB997A9CCE46ACAAB +param = +valid = false diff --git a/src/tests/data/pubkey/mlkem_composite.vec b/src/tests/data/pubkey/mlkem_composite.vec new file mode 100644 index 00000000000..2d95e8466bc --- /dev/null +++ b/src/tests/data/pubkey/mlkem_composite.vec @@ -0,0 +1,107 @@ +[Draft-test-vectors-id-MLKEM768-RSA2048-SHA3-256] +tcId = id-MLKEM768-RSA2048-SHA3-256 +ek = /+mxLivC6sQTbdxajYhuYlV204eeposhbRMd6uKQOWchu5orB7wxXJY3VoQl7GnA++OjhcQOwXZRRldl2UsWRaDJVCUWRukNR9wml7UAZuNlrWaOtFs9WrkgO/VP1xsWMOkQsRC5nsdM7kmayIvPp2FFrwa+QpE6XTJvZnMeVdzG0xk2EmqCjrUef1O3WJg3VGGYFbha2OyTMmA8HuyiTGwRP7V7MPgHAGnI1WVU//EeuTjMg9LJO5KBkLQPPXACe6JxA9FgFUC2AURPolVtgCal5wqErjW0iSBnJlvNvzRyLved7iFfmHW0bJtj92k/znRkRjZQhVpxGFIf0TG7Kqu1LGGYBqR4PKMQ4jQfwGypZ5LNEjK8mVcQhPoorJYTGfUN62rAQ8kfPjjKtQIOV0lLfLWVPqJc8BO4I2gpaOwkCMZLCoK8S0e9FwYF9/oOfVgNKQkhZHaRjCkd6nswwKWeJLIv1+Ei/mxamUFpy0QPwwdOA4o65uUB0deUNGKlznpwmeTD5hNTB7twNAAJOJnKI1S7PaIzOEAddrBXv1BzDfxtRnczp0eWEDcM6cyUDisL+9qpEkdtoNcBKaSH9ZRG6qBp06ICckdZVMIGtZcbg5VoVmMRCeyIHAZR0rpo7kO/PUAcnJVME4esXPKdjahuS3wWgZQQPOqhxipI/XQGZtM9YsFkfFtXs9wWB0Y/CYinhlRcJsfBTIlvThgLMXMLgOvOGjyCYwSYTtyAEeI3UjTBcuKrqdWQviumvEKgm9SaESY3JMmJN5IrBCxVbinIUvc/mXgXeLWFPiiva5W44fRiRkAOxicUJiqgfLil80aeecBS4FJFbWAI+mqlYeactTVY/FebFEqdUAp59YpYEGM28jgWKqUuiuqbasyhTphexbkBpyR8BSaNmyU9E7IqK+sq5ip2fjUAUJurRgtpM8K0ZniypOjAcMVm7HKjzeZkk+iPGUshqNJLvjKn7qUEuba0cgB9ufw67hPP6dSXL+ybGjc2SVaBJqoWAiiS8km9/9kMlNGTANycuNENuLurExCW1Ku5pEZgjMMTeggWNSxHZWzB9oUkiJMv0gJJoLwV0vq3xuADfcNCNkteT2m63pR3dRSGkOYQsXI2oYhhx9u03sk7QBOdCesltBXKXVRH6fIq2/G/u5g/attT1PpFhpxqrJc1Q7Si0dtXU2plxTt9nCA9CVhQXfWCQYVRRVtUGeEoG3CNoiCnv3iBXRKdaJwPyMRjHoQASSqtzsDL84jP51O2l2xrabW5dnlpPMeKRYWhiaqRn+dpl4kfT1A4w/HEBqlRNUcprXRY5SB8RUC7p9w457kkHNjIgmK0J1sa2gJHhwV1ull+/DsuO/QpnuqIPVkPn7gbKaq5zmaOPbhy3Kprjiqh+qzNgyGljbFHzUEH0DeOkmaGPcQQW9QH1aAIckpUM1tSupBxHkRVLbx5TMCrN2ObvNiACmx7CfJjR1GXwqtm8Zw9xnEHdPnK3Py+LkVParSY2PQnDepim4AN5+pj4unCA5G1VGOdTsWxA0An6dRYZBZcHrabgkcl66gVWcWQ2qLA0jtUDY0wggEKAoIBAQDKwOC5Rffw2E81UhAMgxw1lgWPF6Nps3sUvpwKreE0+bhcFur/7T6iUtqlS3wG96C+rfFgpaii84DD1jhaD0r9Yu7GZVPiKwstSDwQSRYs3J8CX+0Kd3NIb/s9pU0VA1EZ4Qhh5V0Y7JrJZxxeY5qWq6qvMNHqJzj2C0j1ZsmZKzFMm2IeEuhVkzCc4/NMvZV0aH3030JjqzrWboyOk7dncsh0pfml0i5mQIWktpsq/B4YWrbSPpLjvXDBSaROndEkyqxd8I+QQctdgx9nKuvGC9/cwyy2LYTP7MnCUFQxigjZpssuZ3mewOOMTpZz6ePXzPw+A19cOPms8ALswdDRAgMBAAE= +x5c = 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 +dk = aG99T4ZrOaO10y8o6mOFJkAxBRwH2+NIh04PdBxUpDGhtDKJphtBCfe5CQlG950NxWcayyeSxLV4BClbh0c7pjCCBKMCAQACggEBAMrA4LlF9/DYTzVSEAyDHDWWBY8Xo2mzexS+nAqt4TT5uFwW6v/tPqJS2qVLfAb3oL6t8WClqKLzgMPWOFoPSv1i7sZlU+IrCy1IPBBJFizcnwJf7Qp3c0hv+z2lTRUDURnhCGHlXRjsmslnHF5jmparqq8w0eonOPYLSPVmyZkrMUybYh4S6FWTMJzj80y9lXRoffTfQmOrOtZujI6Tt2dyyHSl+aXSLmZAhaS2myr8HhhattI+kuO9cMFJpE6d0STKrF3wj5BBy12DH2cq68YL39zDLLYthM/sycJQVDGKCNmmyy5neZ7A44xOlnPp49fM/D4DX1w4+azwAuzB0NECAwEAAQKCAQAhiGriWY8bNztKb0sWNqz4s9oxg1BUkAmgMbIvFfj0QQTbvjKZp0w/noJo6iYWJOhiAPS17lAIu0slmI1zX6ogZDdneqS3+DR+Bb9hViUjwE1QIDtdCsp3RYYA+RDZk9Xa+NvhDQUrtR4Yh0Qq3EBaAQRWuzVMi7YhA1bKt3hKK443CMvb0gc4isVDPDho/Mt/QNcpjifh3UPBSejRIYTrqDO0GEA6YWeDZN9grO/21TuPWV8o98l6Tk/4OfezxKw3e+3OqbQyWHhUCoRdM8jctfui1ZFDWKBkAoYeqKOssV48rTJfBgF2FcsdkmQodfCXlf6GgQrfib+xsDK4fXD9AoGBAOlQFCKWlTC4CJlhlFlKCSNSg2eooM+Z6TjvrfAY7nZeD2DL8Di0kXSqoENKz3zS368sVhfkiEbhMaqIzIIbIg9CMpxf8sr3v4IW3oFKi3rLwbOax0DFF1/Ry0IEuXk9irETzOteat0CDFgIRHnw5OhGnX5MF45Y9WJ3C7nV7q8XAoGBAN54E3MY6Y7WJ6hm8kUe/rDQhX5Z6VdFriE00bVaN3NpHGA2U7rJZMUNB5JPaKaCgGCMV2o6VNxE3xfzhkaOW7UgotllYXDkEnXzLeDXKFUGgQ3LWA4GcK4bLwNm/Ho6VQItvPzhqwW2QR33Bo0myYisu/7LmULdCOS3QJmosDBXAoGAck7+nneifq0b4XISibChS4IIyYevyibBQlkDokfExY+N/0HL3yxwu3VBcda8U47JcvzI7YnVTszUVZYShIggptMrErxbqx+431avCy9nqPEdZQ6nIs+thQ+3gw/ng0QoqFtoIcUvnDp9q7/ZNNlWfYrjbNaBEAf7qZNj1le/Sl8CgYBmGRtr/inqKLSIn75eJIxknz40r5TcPZldmf0ISsAaEko4iZZBqf26RXGNHy57BHdgV+giU2Twthbgyh18sga6iKDUPqfKhJFIWnNatcPHybVenEzsGt6JuOYJnLEQc0biOhV6xSKU+4DE/MKf8wYY2JVqqQvMWN6lAMj//B/n/wKBgQCJIJezxHEm7Z9SOmuS4gqQg5ipiu7vVVhDbc4D8erysbZsBJL2akPsSnCaxeJMWMOaJa30wgnmBssCBlG8vIpmTNH60kHxbUDfJwXeunu1Eyul65S6uftVy90lp3Xc6dG4V0wlflwxF8Zzna0WOfVwVBharVlzxkoks95wfZwawg== +dk_pkcs8 = MIIE+gIBADAKBggrBgEFBQcGNwSCBOdob31Phms5o7XTLyjqY4UmQDEFHAfb40iHTg90HFSkMaG0MommG0EJ97kJCUb3nQ3FZxrLJ5LEtXgEKVuHRzumMIIEowIBAAKCAQEAysDguUX38NhPNVIQDIMcNZYFjxejabN7FL6cCq3hNPm4XBbq/+0+olLapUt8Bvegvq3xYKWoovOAw9Y4Wg9K/WLuxmVT4isLLUg8EEkWLNyfAl/tCndzSG/7PaVNFQNRGeEIYeVdGOyayWccXmOalquqrzDR6ic49gtI9WbJmSsxTJtiHhLoVZMwnOPzTL2VdGh99N9CY6s61m6MjpO3Z3LIdKX5pdIuZkCFpLabKvweGFq20j6S471wwUmkTp3RJMqsXfCPkEHLXYMfZyrrxgvf3MMsti2Ez+zJwlBUMYoI2abLLmd5nsDjjE6Wc+nj18z8PgNfXDj5rPAC7MHQ0QIDAQABAoIBACGIauJZjxs3O0pvSxY2rPiz2jGDUFSQCaAxsi8V+PRBBNu+MpmnTD+egmjqJhYk6GIA9LXuUAi7SyWYjXNfqiBkN2d6pLf4NH4Fv2FWJSPATVAgO10KyndFhgD5ENmT1dr42+ENBSu1HhiHRCrcQFoBBFa7NUyLtiEDVsq3eEorjjcIy9vSBziKxUM8OGj8y39A1ymOJ+HdQ8FJ6NEhhOuoM7QYQDphZ4Nk32Cs7/bVO49ZXyj3yXpOT/g597PErDd77c6ptDJYeFQKhF0zyNy1+6LVkUNYoGQChh6oo6yxXjytMl8GAXYVyx2SZCh18JeV/oaBCt+Jv7GwMrh9cP0CgYEA6VAUIpaVMLgImWGUWUoJI1KDZ6igz5npOO+t8Bjudl4PYMvwOLSRdKqgQ0rPfNLfryxWF+SIRuExqojMghsiD0IynF/yyve/ghbegUqLesvBs5rHQMUXX9HLQgS5eT2KsRPM615q3QIMWAhEefDk6EadfkwXjlj1YncLudXurxcCgYEA3ngTcxjpjtYnqGbyRR7+sNCFflnpV0WuITTRtVo3c2kcYDZTuslkxQ0Hkk9opoKAYIxXajpU3ETfF/OGRo5btSCi2WVhcOQSdfMt4NcoVQaBDctYDgZwrhsvA2b8ejpVAi28/OGrBbZBHfcGjSbJiKy7/suZQt0I5LdAmaiwMFcCgYByTv6ed6J+rRvhchKJsKFLggjJh6/KJsFCWQOiR8TFj43/QcvfLHC7dUFx1rxTjsly/MjtidVOzNRVlhKEiCCm0ysSvFurH7jfVq8LL2eo8R1lDqciz62FD7eDD+eDRCioW2ghxS+cOn2rv9k02VZ9iuNs1oEQB/upk2PWV79KXwKBgGYZG2v+KeootIifvl4kjGSfPjSvlNw9mV2Z/QhKwBoSSjiJlkGp/bpFcY0fLnsEd2BX6CJTZPC2FuDKHXyyBrqIoNQ+p8qEkUhac1q1w8fJtV6cTOwa3om45gmcsRBzRuI6FXrFIpT7gMT8wp/zBhjYlWqpC8xY3qUAyP/8H+f/AoGBAIkgl7PEcSbtn1I6a5LiCpCDmKmK7u9VWENtzgPx6vKxtmwEkvZqQ+xKcJrF4kxYw5olrfTCCeYGywIGUby8imZM0frSQfFtQN8nBd66e7UTK6XrlLq5+1XL3SWnddzp0bhXTCV+XDEXxnOdrRY59XBUGFqtWXPGSiSz3nB9nBrC +c = U4te+MSsI8fGYy2/muXfRQVRefvz56XKlw4egl62Hic2UEnXw7+WM/RvMYXDbNryvf2ay6dI0vpz5DNY+IwNyzGyUSMLPc536u7UtraJUAYm7VHBENAKJ7We85IM4tEm6NVpmImxebY7bjCxaz1g9pv7hnsYYH8Y9ME4pCO0lJMBsy3Kwj5rQCjOVxu3b0/iSwmUM1kpvZtkFWX5d6wGn/8YpjzmsfoKwkQQ/VqvFLkJka/gB2ZEPYrqwHwkJxRhfONxNzopPdP27GdM3JleufB0pUMHwdfhoYBWAZyAqz2ky2NSTe3FukdTC5zCpKHJfESuIjRJXoXbcAzjBTOKWebipPGwcBQuhCE8lhTPj14dg1T925j4AoAzqYxz9HIjGle/qUQlD5JCWL3A1ZsbWBLc9S6ITqYCpXWtptrpos+EzlgHAx3z8IkbUpSk98NexQLoxKUsyIE+GkIsviQzXpJSYD0EYFNBpCgSO0SyCjHntXMDunONAGvH+Rf4Fc+c/QTYgg5PMS3sGpi862cnrgqmesPw7e1ZsfXY8PwEuj1c1UBEbxR4ZOodGtq98YWZLvBqg4/yQVIa2GbQtxIEDNGcaH3+Mk1TDfvlIY3Qt6bsLmdpwc216g25spYCKc6gaAWZTdfPN4ZsX51h72leuMq+Xy/b6P4y5GDbqSiE8sXxTZ3oNkh8apc/EZlPjpDRON8j1Pl9HZfSnxv1d4D98ls6Q1SeA8FkbcFFatzNKWR6ToWf4ASqM/AQ2FPoM0F7nopqttNgnl6pzv6Z0lDexuADwYwypU3xOaeKWYlr3OYv6bvaKagry7+194ladAlFooU8ktGBzwigiKO3OQGYNPunOrhgW95D2b/NUnbIZGacKPDRiwPGYSC0PgOOfbmzvsS8x1tvlaBLammEi8MIR67biJ7b2vxAwBbxJsW43Z5cZ3vU/t1Bza6HCRNRmOMlnwaRiy/tJJmVO7vBdcGnw2rNKJup89WKL4+CCGwP4VTVrrjDeB/MJvJ/iP5evHyn3mpuRc1UnPZa1MtizF+xSFxE6YIgOTLsFrhuLkQb9Y4KCAAjYAjxuGZaOfU6gvFpaW4P97IScwFDBwO69uWp+LhaRuxRBoRBqL+kFc7GH58zs5dqkNl7nrXo2JP40fBnAiHF/1uE2XpYQAb7PnP+AQwUmvAXhXeOB395lRD98wv/lrTk3veix9snv4ffPkCPRdFzXjxmRgaI+ImlXudu2RZTNVJmNht0BWjJfrGttTxBOoo/3s4U+FpW/WnPJzPm9FHVy4+vnM7tRKaWs5N+ez1o3VStZ5dQ/Fg+OUKr5ktqQ+mb3FXbBfUSSqmvVDEWps9H6/eLrbA8sM2NAcfmlPdYlH11WELCV3rCdr4uUTvSCpdsofrubxQToPXzrFDZ/GwxofMOJ3xfSHP46Y1kobyAnsfclqVsHD4sxj3k9FFOa6YboKhgrzJumWKPHbq8h/ssWqKHhXc7y+0wzK3ZEWV0tDNwUG6T5UDPrWARdM5DVFM/mlp4GdtaQydIozrnJCnEQvmFbXwC2dYqav18ev6+VMP+xq/TBqRVy3fvpXGfeOZT1rXJg3dCf7t6lEdXVCQL2+p68IVEpakrC/qHEShq7rTktcqxaXhJgKn7wKbrJaIw5GG/oQ7my0+oNDJGCtUNJfHPC6JXnMa98RwmtrqPztxA2IOs9K/oozjqI6avee8KAjwr1rza6FlgdVOpJCG1H2l3ved5XCrt+scA1S7RM9nxmulImJ19MRCi5hs01RYEsxJEBcUooay/7vL9 +k = Mp+uhOs8AWbIOnF3n+z7DTN7deFlw+jmeKlPIXq781Q= + +[Draft-test-vectors-id-MLKEM768-RSA3072-SHA3-256] +tcId = id-MLKEM768-RSA3072-SHA3-256 +ek = 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 +x5c = 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 +dk = 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 +dk_pkcs8 = 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 +c = bRT+CGVJjWlhms3c7z1cr9MtPb5FzC3yG855tfRmHVXKAz92BekSaM1dynXs2XVcqYUmAyqXfNfZVQwbaap+iiJImFoVo36nRbYLVcBjGB/q9DHl2FUFTTsHrvMUpuRDw71i/xAwxhPZJn/++9iOYgib+Oc9rc0SiLfMFZIOzV2UPTqyeRTTNkCCqcjrovFXDMIVhXLii4A8vc8fZcZPKpnVC+xxep/0nBnePOh5Dfsw69KMR8+ARCJxvWHypLMVu7Wr+EzJKxqRMCJ7T3qhHGfdk+OvST78mMbjGMWxDzGS1Ao/B6rxLJsB3SdQ/7hOg4a6C/XAHuaLsgq+zBhsuX6OdKulwXgduhhOuDxOyEiemtJpbRkoxc1v+ukhLt4LFFEqMBsOfx1Or55O6QH3CNiXQZK4A5mQtEFIHc8l4cLF6aheCjkUJK95GjR48NOb8B7Nzasm6brmsUDpy46dZTN5Q4MFUU0cUcuuH1ew+f3BMdg7oMpFPmVASC8FzTysIcNkRzoik3H0wZ2YqDREwb3Q1s45xUjOgURzNhTVF3mHUftsZMc0xXMxfRiYDkK7tM8WvTg1kYHmJQmyc720rRO7th+DExMdHccDK4r8IdyYAoOSCe2GHDuP7nYu6jBL8G+4FhMJ//6nDHcwoHYlJW75AdJ1hdwLufEm1Y4TtPbqEFJQs4jm2r/zB9gNpwq1RCL12tfcC17TQArxOOJh5oUF9P/9xNL8ckXHlPD/uWHTi13vwAbd0SqyJ1JDKGbjnLoAWCggA5Aveq4SjGS+acGZBdk8e1zY8chYx4OJ2AXnEBEKkIlcxM4br7OadLlZQoXCJgFrg6CKYgu5Mxgo77i2w05R6dLe37F6CNxyDTMM4fJyxH0WJcovDVj83MP8JGD5eKIqqJhBnMI2/28n43tXqivRD3dZilyPHsvygMnwT3Ua2cOIHmCAqkfFofeRnPKEyhvT3IhGLXUMxCR3ZripQ7TiibUFJULXqC9JLEbCrARcS8D8GPS/TP6gz0kRIVaVX7Zu8QhSG0+bjEdSmIfFYNnwPOIZwNPOCj1a990tgC+cgwoksgkEGNXyloYU8u8SR0AnVL09vXJ5RQgPwUcfL/Nul+IBWYZy3VPksUehnOO6X3UHZq7HIywyGmMX/QAVPezWrX200y0aocbSR/MOKN2zCw/8aQr8p7EzGMpGiXortp6srcGKwlDxATX7D+mk/3sXPxJGBkdLgu3/VA9HkMfgG8yB2mAnpme9zCEPq1eVizFbR0R0TeZZq5RTvikTJ4jFJlANUca4sVZL1wtb+Mx9X2dqNSdEGSzly/H4eG6nOl+PHiK3VhQ9JERnpzNu0BzfrDzTICBzsND4xlhwMBWI2Gv2eLS4yA9Rj8Pah5B/gPaQBBAhEyq8L0BcOZ7dHhpYKYrdy0AFhwEXUR46KBsa0Ytdd893dtR1Gfx7VjVZSbcpKjM/YIvptorouXA/XKL76zNO82EHg6YvDmSWGUakpax9GQb9ndCdAKVXxU0HDu5HZwdD+zmqHdp3648FlUul0NH7TldoowHqgMI3EDl5cZM4i80iP1/sS0J5mUXeO73Ykk7dPqxoJBKTCxkCR5JNX+yjrngs/VxjmAEZbGonbV+OxsBHBdKJ1jFPNStcYCEbErgIJyFHgpH8ktp57FUMoFtGnQjkY4J7Cws2Ji0AGf8b4CjWr5ndD7ZJYJ9WearFL7RE90FZmzdwMyNIzZxqvyVeDhN3A3gg+ZtLRjZqAck+VmQSACtPWj9NEAswP8L1dT1bfXun8N+7SDkFu8mlzgsZNb6Q0ZmzSdq3Ht/5YniZLempGqPmNnTWX7xNPXc+MfbpPxe4u7v0XwdoqFSla1Bmd/4jrYhWmPSWn8ackvYein8QkaGptn2QBC6VDqtiGkx2bI0jlXborCDZF+u7Z43cCntWMnWiwbAGQl6dXfQ6B+2gmntN0do= +k = YBCTYQtTL9H57SRVaJjGwKKhM8AJ1LzIsmZYBeDPyUk= + +[Draft-test-vectors-id-MLKEM768-RSA4096-SHA3-256] +tcId = id-MLKEM768-RSA4096-SHA3-256 +ek = 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 +x5c = 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 +dk = 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 +dk_pkcs8 = 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 +c = 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 +k = t3uqJRz/Rrb3C7KHKbZ8dECpFBDXi7/tul8l7LCG8BA= + +[Draft-test-vectors-id-MLKEM768-X25519-SHA3-256] +tcId = id-MLKEM768-X25519-SHA3-256 +ek = yTKnA+IxwKxL//K5jBRDhGmEbYkBysYYF6mzXATNdaooYtl1NtSvtaqtYtICiYOGXfW4SYGWZtwks+m+bEio8HyhRnW/jRBqdnyaQlbKLklrpfaB7+ZQuAklFey/xDC5IgBdroI3qPkxrog+5mUD0aAr6LYGRgEWtRKkpKFGVGyQMgi4oUuJh0drb5dRH9QzZtJaOssLFsCbelS/IKXORfuoofRxNrS9JfkryQMtVwGaevos21wDNqJB4hUQfaIGA+VN+ytxuprB0eyqOFILfglqweWLwcV2cXhH7wxX1xRvJjbPfKF8krihxyeRYyWt8DZBWnU6pkK/qtF36Wg58AIicmOeM1YgcNam4IokMVMVYeOda4kWqaK4SOdAHnOorktmbWB4V7LEj5PHfYjJG1Cm38Uh5sm3Pjgo2iSCStNw3+lQDoBSb6KsOLS4gdcXOwx8KBFy2CGyRVSCcypNi7BnQSBF5JaknDJU+IBArdletNui6WXDj+Al3YWjVUWbb2FuEVU44nUYukRqcDYNiVk2n2hPmfGsGiKTAxcv0EVdSUK6EUacIKBkkuZ2cLZCztpSdttJyNjOuhSf4JKBYuLPWEMl8rUAYQKsBuKFd6xNWUSisNItLrK8bwcz2ZFnUlQWwIq6JBye+iCyFeFn4bGVVOxmNBA9VYx1JLhgY5VgJ8anULth2tt7ALBAQ6Yu0LEyW7gobFwDUFtm3uwVaVGqtqdv9VcuHfiQl4VvbljFy9AdT7sE20lrpDKnDHyVRnNKkhTOHIOHjpULd6qVMye/fNsUdGGQpkCBT/mGRRFpHjO1faMybNk5WaVtOWR08jlaCzoZHRhs2GM0T7aPPqy9JMQ/oyFM+OEe4Ihd++odTydYR2CdLuuf4gikjYAXY7UncZHBEmdulPWxWFSibWO7IIKJqHfP40hSkiWXRtQGQfSXiBktLynNxbJi/ixMnTNaDoGLBcbLNymsr8s3DxxfSwpdwIiko8WbBauHzDpyDAq4L6UoquMbGNmycYJ+tiy6b3ia9ssri9K/4HgU1UYARAlIZllf4QQnMiC0XOxK4/KvDAKp91rO//odHcm4IvFViySsg9w03bxUFLNEf2ADCDnFS7QaLCOHtucN6jpTqKtW+cZUXao5keB60zOn2Nm8eyo0WqsVJya3voXB7Qg96jPEDhN5zrnLIfAj91AjIcUKEUgdDpmyzrqcVzGBHytvwlBQANdNx2lnLBsSqpdVqhEzuhRC55cV0IIdqwwIASxV5tK6iDxIehlRVaSDTEErizNVG/enxoJYH0PLp/eOzXqEs6bDwwZMZNQ7LINGBWEDLVqcmmXHqFkJDlVK8Km2PYWgsEZcMxZjX9FFG7xOAaDLtWYE7vGhVchAmzeku8EpPUOM2ZcNE2hAq8FbGrJktuGPRskERsdEMdU7DsUq+2gEtOxauKhTrEWfIhNaOPkWzMEukax2hltYFGXMdxEKBoZfXVPAEzOXTkZIuBWc+wlPE/G9fAqIG9xPtmituIFDzvKxvifI4UALu6ydgqCdRGYCtQKJWZA5Tuf0jFimbVHgZqwEAEWC+XAmo6leQfVNjbdU2H6QrTXlMVR7zgbeHR/+J/ds9DBOyPCoWA== +x5c = MIISujCCBbegAwIBAgIURHAx+XL1507qW/pajcphiCdpX7kwCwYJYIZIAWUDBAMSMD0xDTALBgNVBAoMBElFVEYxDjAMBgNVBAsMBUxBTVBTMRwwGgYDVQQDDBNDb21wb3NpdGUgTUwtS0VNIENBMB4XDTI2MDExNDEyMTUzN1oXDTM2MDExNTEyMTUzN1owRTENMAsGA1UECgwESUVURjEOMAwGA1UECwwFTEFNUFMxJDAiBgNVBAMMG2lkLU1MS0VNNzY4LVgyNTUxOS1TSEEzLTI1NjCCBNEwCgYIKwYBBQUHBjoDggTBAMkypwPiMcCsS//yuYwUQ4RphG2JAcrGGBeps1wEzXWqKGLZdTbUr7WqrWLSAomDhl31uEmBlmbcJLPpvmxIqPB8oUZ1v40QanZ8mkJWyi5Ja6X2ge/mULgJJRXsv8QwuSIAXa6CN6j5Ma6IPuZlA9GgK+i2BkYBFrUSpKShRlRskDIIuKFLiYdHa2+XUR/UM2bSWjrLCxbAm3pUvyClzkX7qKH0cTa0vSX5K8kDLVcBmnr6LNtcAzaiQeIVEH2iBgPlTfsrcbqawdHsqjhSC34JasHli8HFdnF4R+8MV9cUbyY2z3yhfJK4occnkWMlrfA2QVp1OqZCv6rRd+loOfACInJjnjNWIHDWpuCKJDFTFWHjnWuJFqmiuEjnQB5zqK5LZm1geFeyxI+Tx32IyRtQpt/FIebJtz44KNokgkrTcN/pUA6AUm+irDi0uIHXFzsMfCgRctghskVUgnMqTYuwZ0EgReSWpJwyVPiAQK3ZXrTboullw4/gJd2Fo1VFm29hbhFVOOJ1GLpEanA2DYlZNp9oT5nxrBoikwMXL9BFXUlCuhFGnCCgZJLmdnC2Qs7aUnbbScjYzroUn+CSgWLiz1hDJfK1AGECrAbihXesTVlEorDSLS6yvG8HM9mRZ1JUFsCKuiQcnvogshXhZ+GxlVTsZjQQPVWMdSS4YGOVYCfGp1C7YdrbewCwQEOmLtCxMlu4KGxcA1BbZt7sFWlRqranb/VXLh34kJeFb25YxcvQHU+7BNtJa6Qypwx8lUZzSpIUzhyDh46VC3eqlTMnv3zbFHRhkKZAgU/5hkURaR4ztX2jMmzZOVmlbTlkdPI5Wgs6GR0YbNhjNE+2jz6svSTEP6MhTPjhHuCIXfvqHU8nWEdgnS7rn+IIpI2AF2O1J3GRwRJnbpT1sVhUom1juyCCiah3z+NIUpIll0bUBkH0l4gZLS8pzcWyYv4sTJ0zWg6BiwXGyzcprK/LNw8cX0sKXcCIpKPFmwWrh8w6cgwKuC+lKKrjGxjZsnGCfrYsum94mvbLK4vSv+B4FNVGAEQJSGZZX+EEJzIgtFzsSuPyrwwCqfdazv/6HR3JuCLxVYskrIPcNN28VBSzRH9gAwg5xUu0Giwjh7bnDeo6U6irVvnGVF2qOZHgetMzp9jZvHsqNFqrFScmt76Fwe0IPeozxA4Tec65yyHwI/dQIyHFChFIHQ6Zss66nFcxgR8rb8JQUADXTcdpZywbEqqXVaoRM7oUQueXFdCCHasMCAEsVebSuog8SHoZUVWkg0xBK4szVRv3p8aCWB9Dy6f3js16hLOmw8MGTGTUOyyDRgVhAy1anJplx6hZCQ5VSvCptj2FoLBGXDMWY1/RRRu8TgGgy7VmBO7xoVXIQJs3pLvBKT1DjNmXDRNoQKvBWxqyZLbhj0bJBEbHRDHVOw7FKvtoBLTsWrioU6xFnyITWjj5FszBLpGsdoZbWBRlzHcRCgaGX11TwBMzl05GSLgVnPsJTxPxvXwKiBvcT7ZorbiBQ87ysb4nyOFAC7usnYKgnURmArUCiVmQOU7n9IxYpm1R4GasBABFgvlwJqOpXkH1TY23VNh+kK015TFUe84G3h0f/if3bPQwTsjwqFijEjAQMA4GA1UdDwEB/wQEAwIFIDALBglghkgBZQMEAxIDggzuACNSe3+fWqBYY4TkMwl1BsmXtB848mA4ZxOX/AUAyAsJ0qErCIc0yVp7Poco6xvBKYGxMNIO777b8RGvpgxf6yIAG5fAfYBkugDvDH4i1VSt4W5OYYioCxYAPvOUyqnMs36RfkqS51XmnehGaHWb2O1QoC2uoaHub1j8baYkD8xnV4u8rk5ZvZ9pwLRB1k4jbAzSwFNFq68+6cVa7ftXWZjZj39Ebmt14gkmfKQxDxxoL2TM0uVcuBq5a8t1DV08yPphna5S+meEZSy+sAWgHF3Hkuov/s28sFUnWIb5vq49w4xTWdAiRgH/KRQm+X+uQjYI/1HvXikVL/eU9xsGNRs/JD9hQL4sZAaH4Z8/v/ugm4ZQ7s2G1dwrJyfspymO96f3hkdPeqCgxEZdLfaO8wWB7AspcUZGgbQhCsWWg74TRm5kKuL7UuHQTpe7u2LX58BaMozAjNg4K9nMZlOfYwFmTYmsm5W2RF+MUKjzF3OsRTUzeqJhmHlIi/aBhpvgAnJLl69n3LZ809nx0y0XsC+N1K/pAYcJR9yXNu+vxDc1BIDxH4bRW62vxujybaAKBQ674dHOIqZ/BnLUcyq6bxP3fxAWEjVr58rZbO7750QC5p7YJHQoTBl18VcDoczDO+O6AHR6gWgam0CUgIipy4sWPJpFQ5dQUCBZ9T7oiRPgmVj51HRJWjJNFvwasl5ln+Tj6VYSHTMgcoV3rEUKXn4j+KDlsMzjeOgW+ROtGKng/IAm1/8Mdp/XxM1zcByaUpwAYirgsnoRQghUDRZneH6bzfGJPqcZ15QSHocINc+5MQOfqHc8od8uRCZgo7x04yez9TMZiHy5jWjAYzOnd7GmSw5EuKOp+vnD2lGlRwn+YjkfaWsxMD8JaJwbZYTlK6MfspLOqgFwaNTj/4Zdq8JccSKD5/QkofPy2Dlh1TH4jcBQIcM5IAL6s98jxX+HyehcAQjv8Su4QW2KFfPXvjKhVwd2PmrIO38Vd2vDEhRC8TTCT7jeagHVB3wIEHErZUXr0qpKTi6DMFZHVof9+bfu0ml4Ui2ks544zS3+rTpj9+dT9m6+b3W26M6weMdED0E6Kj68ivq7gq1pi/ThkTGNuBhSp4jQiyx9VuNF4PVZSF7V+mSedm9Ih/KQYtIJ/NJXFrV8Eu7HU+1OmNnBQOrjDFFgXc47FUk+nIjJO8faAD/fUlpzKx3nnJ5nHgX1Se8ew3a2gsJSdlywsywNtj8+udtzBbxCjA+vAb+aVLxOoN1UItOLtsCXKa4596YVcr//JE8PNlrOe+6unp72D+8PQNfebWOu2RQqICraT2HTRAXhtdVRupCkITidPR18WUThOEtxmGbkxprl2ZwHSIG7ZWXoSf+LV2VqtnKM7k5Y2NfUAz+kuNpI7YrpO4k/sTcHoOAyKxpUvtNhqxmtZZ/LPzuLx8+pCTPQni7RtDlc3XYdu15/ydeYtr2JIQcZnJdJ65upaKyumiEdznDDakIsKJAVYJNddiSmLHqWs+O3pJvPBw9UoYPK1GieBw2+ZCcM2LuqLpy/g5nF5aDAs8g6LZ5AU2JYqniHvWqiIhLe9imTdFDcLw9w0wDRomQ1ZgK5p5vNDmGlhpQzI/mhnCsAQq0m2O9mq7kdEVVIhs5pwV7/nLsks8v/Dub+A9uDyPkoheIFW7l6k797kO7f94oaRR2qK2J5PkZVBPXSkH05zIL2u9aPpYNE483fSLBfO13I+ll6WGlnatodpPKah7PrUmjB76VlDxM2fK3gWp1yGhElLyZReoLBU0+z55rAQBu37u5cEPRnRY/KHqoiesBb6Y8v5FBCtsrbvA1J0YwsJhV5Zg3w8JCWqJSGPIj2s4jg8nH9coWloWWGwyyDv8R0wXXvs/PvXvm9ibORqWai0OXcU+pskhMZztWmKfU+vJ4xSMew9vgTm5IsdltPOVEAujcPU+WREyh1PkyuYp3F5O4n828Hsge1uYwqHUwmKZYA+UiLq4JH56RZjxQPtGtSqXnDcgbPyhtYCnkV6Tnv1bpb9lywECtaBYhAjDv6uiZtDK2ellbXw99AmmE5E6pb0SFgE9WkLeLEjJyMjxWKKNcbcD5+bnAxi68KqukdsCOkmByattmvuWlk+C9BdRTqg+rKK2pAHtjXOtY12lCzx0eHspFa7lOA8rTaxUgYdqsao+QxHusVl3zcwRGmNHyu5sgkzg7fOROduQwoxv+39Ed9QVC8sTh2Z7ErCRCdg94oVA/Nh7ONODiexlElkXk8SfpS5rSYFZquHrjh+CLMXdPlVPPxCtA1K3Ac2KaR0llOMMFtQA55C9U4yK0ePN7dTV3c6rjY4XUzq7xkSXF6Qvmpn6VEjxyZ8IK/jMelUloIQZzDNXruFcLiWCmaI332kQaS6mzh9hCFmbT3BSZNzTGREZ8l/41X1UzyjuAyXRUb87gQJXUsDjuu4ZRqDJNtDvIxx9HosPa90Md3iNwFok4x07rOy0H1h3oYtNFqq/M90XeAlDIlTvyJfisXnp4T6KtxBiIJ79NM+fo1R0VPTPqI44OnyvWJPG9CEo6uYgUbArE+ug+Iag2F4hsJ2ftSUeC0+x/x7hTffXuX1on68Kg4lFm/9L9ceilLhX802uA0kcRqIvGLkCducJoM3fUfIR3C6qkfmFQGpGNOJl9TQz9SRLP5PU4hBP2vZuULVs+bBcP7FxbT4OgaH6vvuS9OgWZJA6Tred6Wy2juSoLx4zH+Ovv5I157L0aQ+scorV16lFdt85LTi0KHIoJKYGEgOnboardRHqr5b+ijfQk7NO5MPA8G+7Z77WFXESpXGXDCIepXtXI42GwJo3rhrnv8eNq+oKyZrkcZbzK99dOLVBfz4if8WyFElWGceyTtrqcH9hcm5EvkjzgTYxUnjLarbyoRGTUJqKO8bepnY4Z323H6kufkEYOeS5LRd9J7lJ8lQx2zJ7sTkvcKLzPEjvXxyCjIv2K4RuFxHT/E0icU75DN6PkQ0LVtHt0baozj/TqJnnoCuaOQqM++/fdlH1tLa9qms63qcPcjBEov0JReqyfcUxfA7lw/mQstbgYJ78DsVQWKSiQd867RyzPLCAfF3j4c720wom5QdeJzAwhy8LsiklvRTUl9dw6ddbtENTda+h4Pf/I0pCSHoYEVBxHiPXTIy4mQCxazaL1L7glRn5R/wAu4hjwF/57QbkAz7Dq7x0ae7BQmWPFwfVaExLdBBZ+ula9aFB7Z6CVhYelKHoGrbaON7g6HZ9SzY/DxOJ22wXY5wd9JxvFgpL1/w/vBZ/zZs8aWCEIKk2AVIArhdNpHeF65It/m94lOjLKw14jXrHnxD0UKF0VsjvhhlKt6vGA3XqSNTfSt24zfwIBAHp4pcs5T4OmtrPPCEyAYuedGGXrZD8zjoXLblbE1w8rPBwqJ3BhIVrnenhNWqagobtbcyU+777fGfQFBDVNAU9SUm1Cp4T93efBa/ebw8N/JKQU6Fqhmm0eih5CWE1odR8gk6PHHzZUea53+NM6cI2lKpJpWv+CB1kS5ZDAyiA/66BPLSOTJBPlAwr22f4K1X5F0VMLosjkQVoMAiXIL1QygLdHk8vm3Pz9haswJNgdzpZqsowrLhTDwZzRWjM5khMFHWjho2uIobB0ybGN+HEfKiYzEgKIepNW80UPjpJUwGp7+FRbuRvw+to/f4AgjYAV05h3vEedd6Kitd2HxxK08/Lcn8ILXUzuk9kc9PFatwZtEy9UwYBKBY6XeY+aCb5KYS99XQgxTRiTnpDK7QY5nPGUfHMSHHkzDUWPR7Cve/fJvcnAU5hCVKSS/o1rBiMp43MVcHWyNh9taGFt+uyWeadRyYIBFlDnECdqnZ0GHMHB8Nnc09Nb7YvNiIrwQKmouzi7TPx6y7S31YS7LkeBoxW0QDNDg+FeJNCsqnqaUYNB+haNGGS46oPKsOvJJAvhEdQQE5XiStdTdIUvLqnTkDeA0GSOMnZVdxjXBlqe4sECzsNQNZHHquyCobcevwkh8UjvHk+Q1dbXI2Q0UHLXyIksixWZWM9Ub09M+enacBfEwj+UBtJ64rHYEQY3m4UDxbsKVYEM4BTDpxoI6B4KBHK48GSJAIdOlK40LGhTsuDe49C0r2ZIgy+qF+ehiu0r/cdz3+P1M4YOvxwUzwtKscy0cdc1LibRI1EBS8U3USjKTUTrLsN9uHyAtKQ3cFv1yWlG/rTu7NXxMOaUcGSB8gmfC8RoBdHRHZEDjI0SysCdZVgnoc4ZRdoxcSvHsDkN7hLQh8lxyGSM5X3l1NqK3oUIRNUrSMe0FXKCr7BXrg+vrWnZOHjBosehUdvXFAwhYbnCJ4SFWtOr7DhQahZqtvMrfLVBXZ4KRncNFR4ySlrnnDxdTXWSSmgAAAAAAAAAAAAAAAAcMFR0kKw== +dk = 2Ov6BBGEv4OnW8evCZH4CG+rlvXqDZDqCvVvG3UVnLqc2+yLnan2JQGlyKLHZUpkJkybxfGls7Q/Hj0UkzvfjIClCBG6rtKEZmde7iVHNvSL1WDv7+3ShnmO6ZXiv8Ja +dk_pkcs8 = MHECAQAwCgYIKwYBBQUHBjoEYNjr+gQRhL+Dp1vHrwmR+Ahvq5b16g2Q6gr1bxt1FZy6nNvsi52p9iUBpciix2VKZCZMm8XxpbO0Px49FJM734yApQgRuq7ShGZnXu4lRzb0i9Vg7+/t0oZ5jumV4r/CWg== +c = j+7gq1b2DzYXkOg+BcK8Kg5xm57QAHEFMFHhbfBRjhikEZLsfDUtOTwMDd3Jo7t7HRg1EUbPB9EkejLcUBPmeU6/9T81W90yYp/ibNvLpp//Xv4Gb1UhVj0zYn+iiryqnD44LRFdF1yeoxxmsxdfQ0eB/x4xRsQmNLvhefRIJR4lbfN/wzGdtOukUtpiSP4RY/GkvAxR5ZGMWho1hzJdEDxQpR83PVtFKvpPSsAJok9pysVDmDnKinTzdZFFN6/gbZ0shaxMEEnf5tg2rJAjwbasVN1sN3QqIHRb4kcOeG3wjNefDxBrx9L8/nN4+pyQ4Ae3Q0ixHi3IcyDdn3ELPew5bq6KmhaNLtGKDJX6SlzzzbqN7BDel1XYv2LRRsI5mt6KkjP19omSiEN+lq/zAMoY/uxeDF1f6KF1KUjIwP5dMMV+UITOWft2IEYiwfVMuTXB9Gz4j38L6rPGuyhWU2h29kBfhGfAf/6S4LQOvUWXWvTmMb8vWTeEJ+WM94vbj7Y3pOjpm1XvedvTrWn7uQwx+mxo589d2w2P7/ApbIEkDl3Aoo9S9l77CFVwh9mVjC1Y1RywR15lUXQa4TPattmg+cKXFgWBHcXTEV2PbeNQvLpp6YcenHf7DwyyOoeGyejDh6VqXwli4YpLkOs/ZJh9lECXWjxjtQMz+Zg1hgvAckp/lPP3rp9x7qVIyLPzaDqp6VEcC2YOAYBLDJquSxYPeSWguZhl4NVYetiyaA7DwMSHQukZziL/Ucz8+P69lEmdw/acH9uj1F+3uUvfh8s5Y/k1xioP6+jAAGmEoAYeoss1H4juylyBytk123k0L8TamEwzdLvbG3Tn0PbwYPkAWHtpd/N4NkO3Dvlv0n3XE6XAub/OmHIdqHjKi2mwd/FdVOZx5ADIZUxwLvc+G6MR5mRR8tpnJN96m8AZXsrFhQPQyxESypJ3D1HKAgXCjAG9IRmmF8bc2p3rFmjLZg4ETM3Qg5nM8eKMrgVeE9yvH7PN7GRQWweYNLM+xRRJswzcuXSXgsvfcxBN0AdUgbXmsSC0nduqy0PHSbFG8YlAT5ZV5eAYSsoeGyc2KYNIWvf6JdAj2KNwD6vdI6v4CIWrEODBdmjAN8AOSf9wsUvZf/O+iAXMNsLFQp0rb61NZLpvvfPKK69d9tg3EbFqqkuHNw0/2mrsnauVH8fbz85ndby2tFV/rqxNb7cHzsNvAmhIkB8WUzps8gabGN2kqYL7Fgsi5uBm588ElRX0Ac73zJGHBWNFESh3GsAm8qc5IcXqaodN3Iz43gwUTass6OLZLH062ZBvEL4+LY545nv+srprnCtQJeMoYIwvYkVwqj+Wilse4LniitRJExaR3pYxWamOCiUjPY/lvfl1otCRz7UxV2xRv0YY4qqMvzsGCvlwmHn49dZ+MeFkC1Ts5iMkiOekEW5b+5zixwhlCIV2tdy62iaN7c0ICew29mW2mMe2OPGSq0Q7U5q5h+D8LQ== +k = xJj1+/ivgv1L0Yud93pC1kTXxn1Gh/kdrClfry0lB2I= + +[Draft-test-vectors-id-MLKEM768-ECDH-P256-SHA3-256] +tcId = id-MLKEM768-ECDH-P256-SHA3-256 +ek = 18gVTXJY9LZ4X+MLsDMbsfgd7GEvA7J2fFFc7pxrhKSkQkNrsNaGCtaOfrAqNUaNYTRDjQxClORcg9ZY03W/WQEuTOAp0wrFkbpVMeJBuIQIbrEEvMCmmgcPDZUuZJQPipicxMOHvKOGEWvAr/obaQHH2QKWTSbOz8gVauuGj5JPmPPMiMxNQdEleogRetAY6oKUy+qpr/crSXIL79qmWFQ4lrIF0GZi54alZLKJvEcW8MyVHeukF8wpbGQJBlpzNzJtz5cQcqJ90ogHrqohnddscZIQjuErImMgnScVmDA9vEOJ0eWcN2aI4QKpRnG6ZVOKRkOCHSILtnQjffBrsciw5MEwwlsdGlmbKmll9zozOlkDbGcJeXcBlvaHG+mhjMjOfNzCriwObXLI0IgOm1cfsfyEDCA8TUw3sqFbUaeQfVU2LANERcxkunhEqusP76AiG8UWEKwT33hr6LwL53YX1WKvTMGQdxi0HSWIZXtBB6harNODGfVvLKsoFGQBEfAQAOlHnCRfqFhdNTwF16t2n1cd0nydcfXD5gIqKhufZdU/hYkvysiObAM2FhgUtnbHsEt/VeMTeQEQURJDJdY9IjMaTvjKDgCGNlskorpbgxKQ8+GRj7sTqio/okWn9BOBrszGRTCAGpgXFaN5jEOnXGerpkkCBGJIL+Ngx7S03bqXcAMu7eqGp5SxP+VBmnpnYKwzExhiscxNSTM0bHtpWYtjOOee3/RfInFgodl6D6eKTWE5FzrGpyuV/yG9VCE5P4GrOixZv2AYtDSeqWuj+Et05VodNToQ2VAO7Qmrjct15EgDCigKCXXLstuueDmnJqZHg2YFWjMz+Psaa6IU0lm+zgXFuoi66eZdAPKeKoqUQadvmSU8LygBizAmXkaIGzcI1mGOJ4MuMGRPLaR0rGCcCYUiK3Ys51WD0Aw9c8lDpiNCUXSeNDg4IfO8WIOkekbCrUG1vQEq20M/R1GRa8aMC/K19XK7bre9YPsPkiQXy8XPOVuyJZqBwZEc1gIij1aVp+u+WClX87CaJSWqnoFQTySuRYRA4Zg+sySgmLU5zzwfRAV1ZdF0XJwKo2jAfDpGDQgiAid4pKS7cGOqu5atcEyeLedRPxACOwiGqQI6Z5Qo9EYvhLacZNwlHekmAmwOZPaZ15WpCnors8wmBiknyQiarkI8SgqY4aEgXAtYV1rCdKYBdGyGsqA46qYje5YPdYFkt+aCHvqUIumFu9qmuYo/FHKVh/FcvIU4sfNxZVvOuHpO2tOIiZsZYqcN29YkYmS15oKSHCCXz4OZbzzKvZpfc2GgOxScdReYMDFjf4EnESzN2vaz9sZxLiZrJyERJ/DJOPaCysZQZzdlWkrOssQE88F2MWzN5nZ3ZJwHT0mwDYAIoEAvmGZlUNG1J4O7QFVjktXPawvPBOqMyBxXd4wu4DiXCOJ7S4SCV9B1ABotCfddEKc7ACV8EBF4YlYI2TAC+YuTRrS5WyF37EsEu9MqyFwgITpTuyVVLrtLlCJXeskJJgpAmhrA7EwPDJs9EpT50myi5NdEybFi4s/1IwQMpfqdRSPNQHIEGS3j2kYt2ylsgHtZXCtJ0UcjiQaQ4qjfx4hCFK3T5lxLiLk62H+OWzBS3tDKhxYzp1pPCUmVt7x5MQ2yuXFi0A== +x5c = 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 +dk = Tak6+hscMcHksvD9M1lJH3URy5ZL4o5kiJjO4Yc+DCn4gWlIgRe9RvZjoXXyR88ndbPF0WX8XzsFiopwet8jtzAxAgEBBCABe1PuA0S6EJH6s2EjDbZdi5YzNURL/L3xzZ8cmhKvqKAKBggqhkjOPQMBBw== +dk_pkcs8 = MIGEAgEAMAoGCCsGAQUFBwY7BHNNqTr6GxwxweSy8P0zWUkfdRHLlkvijmSImM7hhz4MKfiBaUiBF71G9mOhdfJHzyd1s8XRZfxfOwWKinB63yO3MDECAQEEIAF7U+4DRLoQkfqzYSMNtl2LljM1REv8vfHNnxyaEq+ooAoGCCqGSM49AwEH +c = E176afESSgFAigXPnBlt3vZ2aZWkYFO7Ym3cNxF3Cec7AigPN5nh+MJZoc59nV63jcLAli3p1BOmZ50LMdzrhumpSsxP9k7U/y2bs1kG4NHua0IG+mrEDtM+pyPoWUtC1jIpUyCDZ5oAaoseQuhKcQKNUzATBFjFiTS9PZhCwD+V/NGElRyqOTao9KjrzQumlC/3vC0haEusuNQ0eff/XYQo01dVVoOejhApe/x8ddPiGhomS+x+jGMIR9ngqw4wwex23jfWMUD+HjMy6lPh0BPTgbj95HsaWmCouo44r5BY/aV8MwKrAUZeDTjdAFtB2qvUmO/UdYscbu2dl3fGb4Dn7ceZOeisne1z2kmAN+c/MqAUxTZZ6AqHCdv7lAlQj9OO94RhG2UjM4eXlf+/WlCXtCVOqNwHeBF8YkG39ywd6uNjQR/34ObSwZZaDMBMn/EAaChnOMSxh5NGlfGckW82MIDdjDcL+k62tubF73QStQmQ45eZqJBD27qAgw5/bJw4iej4yOzrtaConPvg7+jij0Bkx8EzrkvJRY5MRhdwbz2gVYmxYUGW1cFlWMPKtBvvgkjY53NzyZPVYMq1hYtcYpDDY1MY0tkc42mysPwXrhBpF86VDFV5EKT+yuaPIoV6ucce7pNrbhL66CuLQH93GN8uVP7NwyBK7rHDP/eqvPpVJKX5qJEZEXSk2OlBZhzgMUNlCzXOgfPONoyOo4huqCUAaAJA4nata3UuYA/H3bTntdhzeQLn7OecrpjuGs/fFSfpRbtafmoxbZSHyoBJO4DBwBrngTaT0CxXz2hvT9LqSMIAqf1B30iGADIHqykHL5nNFGj8BCMZ0BOTBZsQc/HnIbgzmJEwGmXnJNfr2IX9jpP5cy2Xliom7jd4WHNckP9LknNjoOcFJ3iUeqKWcKa9SLGMXv2kkV026AuHDzP2Nk7Jl+mt4Y8hyQ1hGs1WgkjhRHdZvxjefrA0hgOV9gzRAsDwzLRfLRNnsiqh9cDXhL+uv/YmNqtG8JXu9P81acxIVizpz4PSKVDkaf9vD22ydDzglQGLbeYKvfjzytBkWn8h08TGBzvdTpM40i6PO3axhymHGR+8iVxUXqGiH8XkOUG1hGTPCWxdLY1dlhnny4K2bJvuf4RnKGlatPULvggvW+DynYpX44a9ZursfohXooi9Qezc+1fSqq32zp7hTrWE4dduT6IssUMUAF08xlLW5tmh+JspAcBnWzybXVxwaDjpfqGoVZ2sDHZHgSTcC386ccV9r79bxqb1OY8E+l6NfRiWFgMKIInrAgT4yqTXAHTnoNea4OMd77fjhloZP+eAWO5dxtjSw7qAGhEWIvpj5C/VDB87PDbQZz4QGGUE61WlITNU94GfFCWHdUfHvuiVCfirZ523G/Phf6PJ/iLjFi/nDzvuJ4oeeLGlNXthSiQdlm064q2gNr8EyquqC2v4YeGiE0HmjwkqYhdeB52Ppei58Ls1qcrp1L7IXKI4eDBFBb2R3E7GMH4gVBjLi/Bz9JtpVIWOn4fooA== +k = /3ZjIpVll4ukP+DwsPN9Xz/5VQDhN4fXGbzD9MMI6+Q= + +[Draft-test-vectors-id-MLKEM768-ECDH-P384-SHA3-256] +tcId = id-MLKEM768-ECDH-P384-SHA3-256 +ek = D4ZFoMcWY3RlIbtV4ksHjpCLB1m5iKQp7XnIAfuE8vBefCp/SHLIXjJmjzgcdfWqrddmZUHKCZQtNeGt0fY8uIQTKQhUsDQJMZKpMxKt3xAjgyd+WQqxB9wIiYzFLVyawbG1VYN5WMqUf0cQ4TAoEnVWGbabW3vAckwE/besjGgko7V2E8DOVFBh4Ol0InyHH1QFfTrF3PQYD4Aws6hyjMuOmuRlZnmAMNd0ATBSoYCiMQo/QTV/NPKvtSw+j7sMTYbIK3fElDtxHqGxGMI4R0waBfCxPYJdIoQNDfY2Fhel09QJr9oJvdaeM3NaPgmzUvRpZYm8MiMwNVUT/KFAVxtNN7oFmRNivzMIaTWftDqDeOQ1MiRbIgg3mjLKwIKJHbHMOFAT6vc4yUasqQAaMrN+hJQs88jHS2eWe1NFHmZq1/OeZ2i7GSlHNQFZdMo/malwPdpKw+NnqHY8zZBNPjjIeiZJxbEHAqSFXtY0dKpDA+gTJBgR80PAHkzDZRujD5oRzNVzI3K6JAOuWByoR3wWy2xIA0JRwHFc9qwU68iJeMOszRLCdwd7YfoUszAo+tWY5YBrnLJQMLYu3SEwHnfJG3ZoxHfPwVtChsVLoqMBbrtbzOCwtkWnIWSYwFgtWEyskANIdEsRuiJfdlafQLOBKxkRjxwsAWalw0sNv0nOJmQvglwTKMM+szYOfyhINpcTzzxKpFoaRws+AVVNembLIPUlCVctRHOKEEsh5vFVfXS5dFbDWaQR6nKeDPNg38M2euoDAuEYCBbB9dRPPNtJV0l3D8ACZKNWtllFIxAGKbWIRBmEUwVpaTdkITiMSqh7E9fHnGZtogSVBHZGZ1s5FHQOCzNZYXSLrkChokCKEZmksWGZjWpCgCmmnfIRXBW1q0UNVPs6maAtahobE3V3RKI/79q/jKRPHAQ9fncPbOABskQIJBNsVEAE39yzAISSv7uKFjcKwAY1tqEQcNsTXbZQwkWEkxUWNpCRFPSaWEJPE0TI9OtmEyyk9wImllJ1OANbIQM6AGcHiaWz4Pmac+LNUgi5lNzKBPiW8jp4LcpL5BwoHFBwdijFL8eutHKEZBukA5INBNZ/hDEhoeMexBYfYZFTaci+DhtBjkyZB+ACdPg5oKJm7xC+pRRDQvI6j/qiyjV8Q6Mow8Z4MWxMpdU2kVsIEPNNyyah/agC59OaJKsXd9MYPWkdpggBj4i0sEYttVZhcSYnoVK3lvEnTnp9ERAtlLomx0V0xgkrohAPqhg8U4cNaNmvb0MNHjJgjOpqbTNAxGjAukePvsSlq3SH8sxH6AJmHfAvgDUeXYUsFHqApMIm2AOzF2hOrTy7wUYdZIdbeJiX9hZgHlC/4KsTp8RmvxPHj9t4jwl+nodSLBiVP4WlPAUzyBpyceEBhBLPjUs4J+F0WXcp3PoPnXWyttsVNcqnNtmy0IM9IqNI5ovFbXaivpiXsrSa4kOhVVwKnvZtuXm+uGFahUAw0AA8GZmMYlo1anmZKhWklJFWNWiBVml5K2YhEnsyxazPCgrfYR7r2PlikpYKPtbQXZxU/rqNcMg6hpZ1WicEdo1PtU1qE9mD06el0u+ivhIJKWPtPMAJtnHymo9sIAPZo6mfOO5b91PbEzhYhki048l7pKDn/q0DvBSOgr38+UaVqN4NT6tjx23mF4Ss1E+iGoI+ns7rqn1e1gXO1CQG +x5c = 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 +dk = 9D1SHRdnX2hrYKGKeBs6QejMIinrJRwJD8leDodYwfe3/NYW8e+oIJaE3q9rHhLzfC1+DSv64/jKk5m52CEwZzA+AgEBBDBMg6jNwwPC7IJDS/Z+ZkgeJmZslEjVoSDtSDJx1Ne4HbM71AEKfKYd56TXFDfKIqugBwYFK4EEACI= +dk_pkcs8 = MIGSAgEAMAoGCCsGAQUFBwY8BIGA9D1SHRdnX2hrYKGKeBs6QejMIinrJRwJD8leDodYwfe3/NYW8e+oIJaE3q9rHhLzfC1+DSv64/jKk5m52CEwZzA+AgEBBDBMg6jNwwPC7IJDS/Z+ZkgeJmZslEjVoSDtSDJx1Ne4HbM71AEKfKYd56TXFDfKIqugBwYFK4EEACI= +c = bvsmJy2aYKJkVQ9zekRJ7OPbsKGYhf+y4Sh21vMkPUIoBeVggLi9ucVid+/3TnmvRwPxa+RYRqyR2KBX+W/fwb1vxRh69EL8S7vEhrxuODZG+9P/skVmI8VEZCnGkvDxOqNWQzi3J4fBdHQazlqwnsojfuK934jgL9kXzj7IgVLZ86pll/Vva+FOohS2VJqKlIsHwOkF56Plyd6xJlhIvyGdaYgkRn1I8fZfTiCcIc6ZgIcJdzOHMaht5ZWiM8f1ZmL1pkjScGTJxpNopYNIKyhKxEPI5Y27dRZM5mpu/gjaY3cMeI+kSYyn8IG86zn1ws+XH6h+ZYGI/QI5tcpkldL5tFHWzj4H92noHV1U+SlL9zUbxrgfD2yC6ICb52Yj4WP9qevlbsl0E0PdbXJbT1l1i4aPGk317ypwN+CUZpSazgUphVkhFaW5kkn5b/bummN+2fgXzq2v0r4p+KAHRuHrviVn9Q92ZpvwCMSVnwka5n0qbAot0uwMFSJ5HtvsGyQKtZIjJI55XGS8bjB3G8SnbqBn++8Tbk+lgxbzZYBoKa1QYAUcoeLsKx+MPcrYEEQ+4vS0LggYPhmjv4PlxCCDjxURxL34EQp4qk3Ne20l51giiJ6J4Pc2oCS06Lm27TeJ3lojce6xAZo1u6MVx5PfaF8lfH/VvP5vK5FhRAvA/oOggmmazyvudjv/1C4yZXOk68roEUxVhvlVhhDod16B+B8z9URHDWdqC24qucN32F5rezGyK45knEq6aavz+6GhA+rSFvhrX3YP+Kl07uBatMeExHUg6oxqtzXQIirtEVwoE2KCbGbzeLbzIN+cdacqsHOO3nOaUm1IfYL2Djf5p9WDC3yUVlNTF3Xg0pv5yOR8UMpYqcnQ3GZHeb1gxHLk1qIpx54AKvLV+tSx54PtylcjRsSN1IMbJxKFHNbmEMJx8tn1na4UC4g1i4u093CdthUJaXMhKQNQMnOKA6kJD3rqTW91FXjt9u1s8qFpP5qhnFr4YtsP54wj+LujvnBK9tIS3NUwovIKRD59XqtgTbRU44WsA2YnqCt/HAiPM1dnNu1ndBj0xhE6gUAH9RIMOjHvEDLXatt9TCv1L3QqZtD1fTwoQNLtD/bRlaCmV5wAHlJSyNV5IzI8Sm22NsePcHV/6qjgL/qL8qLqU8WGVvuJ7RuhJYFhUAa3JdcJxZwEeY1mI94qY6QbhlzgxO99rmiBmCJ83I6bRGFVp4KBnMz937/gbTIspwt0H96o9mL8UMeLAP8SFpF3BNOHkZOxiw1mOtHvm0cTpn5xnXTJGMd845BEEyRbq1DVNfsJf2j7Xx1DAoliztt8ewauQcr+2vP7yOzim5G5caeVHm8NXesofzYsLQW3iMc5Q0V3iOzrVJ0ZRUuywoqQ1wzOmlpmgvKUdqWtu9TuvLuyHbyKzsL89Zv5oPtD+lECingEzvOCTk8HhmPRDK72TCYXzBt3ulw3Qzx5nJ+MNL6Jl4p5RVoIaivS2GoTVLz+RpB3G9KM38U3joCPZ2vcrlWzlsr1cRFFx8Xg/griXT2mchZw+l6iegXeLRm9ULMIZSaV +k = s2xVQ7zLfmt4ZRKmNUMfVpNqLnBg76NLrSGQOZ+LyIU= + +[Draft-test-vectors-id-MLKEM768-ECDH-brainpoolP256r1-SHA3-256] +tcId = id-MLKEM768-ECDH-brainpoolP256r1-SHA3-256 +ek = ZrU2qOlnSTStBHBnTesvpPhpUpmeo6uxtLYQpOUoowqeNlnKQbwS4WhwAxlAZ9WInfGNoELL/4qPs8RiaCmuE9Aqh0FRSiQ2c5Wls1StE8JH/rxPlLJIz2q5wSwAQZWverI/lNKT0PeX9NsuR9YSSSEDtrGmhLm8rJQ8QgGDBtobl9Wk9nQKB/CnTXY+mKMxbnZeFNuaO8oFGdOhEyqSaIMgO3hfghyQZ6UI1Ds1A6K4qcmknJig6uJuZnakw1S9ckNAn3RviynNxDJpLlzBhEUKq9HFXTwel9eu9EuPcVPLmpYHBaquEii1UIh9qTRBpTeZQmdHgKAJpAM71fFY9fYesRFlpqmvSEeBw4TFjCqMf/kUGooWwmaNnYhUnZk2wPx80agbMHo8LCSZl/waqSy9FsAWu5GpStwpDyBSvAmSinWViZoYFLZtYpcH5jVMHww/BSDHxwiUxSuHFbEseOXHhqef0pJWcbQN9kpd3XJn1/IwbncNXJlxkYxIvouccyl04ESdp4Ru5/UHa1ipi6qPS+IOKgeSITVMLRJeU1iOT8Al03yJE2BTC0mQyCNCOsJcsUMOwCLHuLScBtHCCMCebtUeqqQXLhVx50yY7QmfqAYAdNOSjLe/wSNZHjNUszuaU5HNYmKBK6GUmLRbQ2ErVRmTsuBFnhGE+RKj+sKkmCYpPNkB20WOVlmvv2mrh3l9ZVWzkndoN0YZaddRZEA2u2UUWbarObBmuwx+Fcd613Qi8EWyXOpIxPiaZXcLTCA4QsYxS3LDt0Q2Hlwy6eVe/SUJX0UQKLOuGZVCj+FiLNE73Mc+MhLHjtOM3LVbdAViC7o9JXAsCotJk3K80QAQI+YSzogdFGRi7GNn6iyCAAGEEKxySrs0BmR066BnEGzIMdMncZlZooqeSTorYCtwXcXMRgBHbVFGw3sq3ZRs5xGKH8R7toe/GtKfcKbBuoBJX2XJu0TD5YZLRBZbsHZ3/EFderdP92XIb4mkPrnDFtlksssgrTxyNxGHC9ZthUtt5HQQQaqXjqe2PNyUxTOiSjVHp2wxJaSY8sNdPdYueYNnbyWSVbFdp6m3fYu5jVAQ+AAd5qd7CAFoiSO/haqTiawuS4OeyEnIPDJ56hqkzwmbJnB4pVFtuXwFYmxUXwLECqdjm/mBpYZQRwcqfiYy2vKxsZSTpVd1ETKDqGxgImUhE+OHR8fNdWBWpMk9ZxHEJfXP9lUR3HWCJ4Zqhehk46KyU/XKJ+pklhU93xQ2aVtw/+VoVEq8/bq3QdO0uKKW8viwmbpuOWhTchJDnmzPY1DGivmJJAqjmKEHM5d6gqQ4kZJ9RwgBOsyFExtkYcnLyNxEbty95TgIS2ytvcVLr3Qkx6ZnLVRobSET1UUwqTdvn0I/uaMwRngR8UioDWWzfCqjzDc7z2AgMhY2KXmyMjqAlkQd0fgZuWFkVvAPskCPCqy/gTlYG6MTMNewKeugyoSrwLA+hqKtnxAQOIYSQthoYsaUdVheD8zBQCezZ/iMcmili5d/xne+JVsHhcO1cYIu6POHeQxV6RK9EyqcTcmYNr5+ftpXJJaf/IEEFSVMvYbLQ839VQxRhU1Yh+EyYeYf/iwyJGn6mdOsnB1CGwXSktC+dQJ8fnHsZkScSgMjqfWFi3ZPJnxqpLi9Gg== +x5c = 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 +dk = rNKslqVed/DGHOtg3Oj+lTVEnPAo1uToOhn3Za6grdnmAMZFJV12luG0OvllC93grlEZuBb7vNKtdg/alkedXTAyAgEBBCBRdGKCX87QmE4zcNF8BjKeeQm4vV8UYKJnJ7utO9Ukk6ALBgkrJAMDAggBAQc= +dk_pkcs8 = MIGFAgEAMAoGCCsGAQUFBwY9BHSs0qyWpV538MYc62Dc6P6VNUSc8CjW5Og6GfdlrqCt2eYAxkUlXXaW4bQ6+WUL3eCuURm4Fvu80q12D9qWR51dMDICAQEEIFF0YoJfztCYTjNw0XwGMp55Cbi9XxRgomcnu6071SSToAsGCSskAwMCCAEBBw== +c = /SwiCizJ9eokwuBOfo8DHFJlxKonkb22OiQeYeWIJhiwUIyF426zCFtcPmrYEWdZoV8wKzs2xcxqD6DEnyZdwkN4Rmpdjl30WL9UIewL5M4ys7VR56siOy6z936qjSngrkGLsvVmRLUEm7LidNPpFEnGYg+9s86szJYzsPehzFx24n07Cm4YU+5tT0Ta8aaQSwWf8EepedeNL/ulvtwrS6nm00Z5jwrLWo+XyTJHEkY4Y5mwUqXvPuJnQUzd4gCKEyX/+uFOn6Ej83eDrOUI8Tt5YasPSz7l8U7WtDP87H8/BzmXOVaD50r3N7P8W/Wd+/8Dm86MWAkaT2ROPyo+ZOAtzixY+ShvyMGtFvERHz6NXUhAd3J43wIM7/+gQ0//3yhq+S+3W/MiIYvv7JdXuyzaFZII400zSJ0cGdrftPMveFkOmhW7ChftkBuw22hVMxdTYjAV1JkBVN2EF+5EOlzPmeComF66oLJrrZO2LXibWlWwzL4BVSdiKG9A8uui6e77/1gBCAG6Z3IqRsWZ5BvIQpwgByABSUnSAp5/xE6Dp+falkBa1PRcrXrKfOQmpC22KCMPnD5h3eTYNqY0Hf9AF5vvT8n2fKpvnfMEo/0p+7AQG1hTpNd+adCUOl6urmdbVIPKeR4Mnz5foL7Sk52JtPbDTsL5fRNMSgi2bX/UfBbEEBBvqB8zbklTYSrLAsdg3lk+xi54UdYWuyQI8I/ATCVlow0lY5k1zpTp1PMXiXUVaadxAqGODEKRE9CFGybr3IYlvYPSPFYjhT96ZXmtKfEWLln4kf6O8xCDGl8M97xxNXbgH2QZvehWs3B/SthOVslvYfyq0NALBDn0s/i4iRqeYBrs4V2qh4dYZUWJEt1cOZ0GoUIfN0qkgpuzjdOrOFYhwJZFphZrX94LOeTIKmwUYMqFK8CmCKZcl7IyFI8ILTDSRCIenyrsWua8d9sHQuX/RMIHr+RSHst+b1zy7mQM49yLEtlHuvzXKFOm1oZPNY9m9FuwFuVFqYy3Sl9/jPQPQgpjIFNlBrX8L/nNNMGLnEUE9Zow0G58H6iOP+L/zXa0d/PcC/Fh2qtK6YGV0ltOtt+rMvD3c2wLtiXPvNycnI84QKvxY10n7VbUdG/dvXVkhu3aKlQJ2BlFwMUEtn8CElPRoQ9s661YsBzko6O7OzLjPj+aiNkMsgyqlF7/ZcJt7o6qiOU///h9Qhir+OC4QYmLyht6L/gtrQ94bvv/pBoewUPXcIUPJ/fcjz3qPnYr7xGXhitt2Iq2RUL61u8kpVyBYF5ZTyoy5vAGMAhIi2Pfb2ZxeMFfEWGGDYaJWpG2DDDa4tKbk5vi6VXaWtgfBaVx1tWvD4d7QmoEJ/ju3poT2g3BA7snugXaWaNMD5G+RM02pZUClC2xz3GfCZ9N0NqPqF5/yT1F1qYhrQ+oz/onQjBqi8hh8WQEgqDHIqN9QuT2LVjQ4TEeTkr4HEPMNDpswo/0vfFxAp9v45A4U1IQwc2RjUpbNQmf4DfuGGG9NzPY9J2y7E/cDw== +k = 4pEH/JmlpUiMQ67oN1xent065WCvSYovabkneyASx6o= + +[Draft-test-vectors-id-MLKEM1024-RSA3072-SHA3-256] +tcId = id-MLKEM1024-RSA3072-SHA3-256 +ek = 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 +x5c = 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 +dk = YbIkekkePNyGdhePi+kl1KUQDzmRzsIj2j6QP90xQGCqvthqgO2V5zXnc5NenRjqejNgs3NFpdfVvIVpLXCp+DCCBuMCAQACggGBAM4EZGajHQRaquMSau80/5T3oeoxyLM0GiWXoAO5UEc0Ih3l5gDKPZ/ci2HF3WzOr8g02MTzWJobfHNzcR7/adsEAjeHdUwD+qCGnxvV4NEZMM2lx+Ima8KZEC8d4OBUCmMTDX5qoVF4urhoasIqA9Q8D6zYI/08ESN3fZSl5d6OcKxpGmEij8oW4mPCofr0RY1MQv/BXKtPmmMxPoukBVxh/llI4RYRQ4UBtADSLb3Lj7MQfGd5SKuN4BNVg6hzCtI0Q67EGuqF5+C0MablOfN9lB0Jn+Q0EUEY9hi8DaanilW4mYqsSRsFi3tlShzvrf9HUPU/jEZOeYlh3CjLlBRtPQmEhlX2/Z4KsOAsBO3ISck6S6SElG48jt/APoczVtySEz6ICYNPmExUcSNSXrk/QMhIiNp2x2idqLIGDOC+vA70yfm02uuo9I627vsXpXFQx6qxet4BwN99TNDw5KTfrofc3iW/foMtGyb8OYWzWJpm67j/hvBlgU45aSUmXQIDAQABAoIBgCzAG/4GfvJX7ohSExvgT4cwjkGErGOu1OInEDlW2ucInkOP0XkI9T9hJP6pQAqXT+wlfJO1h2C8STl70U3qLbiHI6Mjv7kyIRIXA/9EI2hQOD9nfCZ18ZDs9izB6PvZjYMNW7BC4cVEfAy8E7qW7Ut/+2iwb4rdrhxd44+zRJ4mIzf0QahpXUII3AbO+6f7QRNrBh+vhR1qNm9G/l7PU2HIoHsM/2WvfNLqtoq6HPj9+3oqQdepKv2m3Q5eFDH2QPbYQSsiiSz/NeaprXkq3PN7zKorMkxU/zR5M7Iz1NE+nP5W/4t6K0GAm6yZ0A1ti5R4TbnR/jqv5hilvcBAqi1t5K4f6r4XCxsyisMIELc7+bkNJn1n1Pq6FPiRGTzCnimqAjHQYL0a74glSKUX5aGpFoWRvLVDF5TWR+P8AXLKV3yQJTHzp4EiFteEyNVrl7RzURtteMDEsZWMrz9uwD0EFsVdja3PR9Q7IduwyWI3MB20XlQmw/FSflJlJDkbyQKBwQDxeADPmVc/fEmsDcbevVtRnrBZSx3PwxXODaT+SEEBbrsyNqjHjryIbAnVud78PDVqBx8Q2nC9sQA+keUcCMyWAXPL4WvX28aXETmFz1qC5nY90204cN/oDUNL7IGK8dVRtcim9OmVP4A3RP+NNY3nEtVaz2nDYfVYbX9J3DOpIAuhvbkr8Yf2Nb82gJRQwuPyKy2FpPd+nRD3DjWJHVKd2x0Fk+1PjeuVoOztDdYy5iNIfPwXx7Ovua2Kl0pu/TkCgcEA2mo7ZJHJiNFzQ8knM09MrUkJG09UWCaPMWGfZw8ZbS8YFlASTPtgno+KbZOiIhIMJDHDvFfV1U0G1tpDFzORuk/SGyPCj4SBegIl8EeMoMFlHHDO4kpt32/viKiRvlkOVsP2ixD4+rJ8c8wrQMPWOCVk3+FRfwj4/1qn3eiJLLCnUetQAwtlUrnCncNtmib8tF8R5uO71IID8S/ROLrWHD/wMbYS27lfr3nPN4OvZUJ+6ZPMIZQKMFSUofvDOBZFAoHAU18/yG4FdeIP/dvz4kw3D4NfGDWbYXTWPoLviOyhpUD6WWgN9nkOF3xWGPlISIbxWl6DF2qUqqpGj1QIaxmOqexucuKuPaWgd+B2oADsG24/PTGW8HnolVKe/cP3JmZBZSkC0sKVM/bs6ihko/jtue8Cw4wB1HgqIhIMdRAWtjpeScYb/VQzwYrlLohOrWPdGGxYF2DSI2FPzj2VtnXtZJuW9aoRsfoqcUtTArZYUtKrNAgTcpJ9NBtEFCoQhSnhAoHAYBhRHURPKRUN44sC5j5DfBIgIZXbhBUi9xT+bvdjtnf73wVHp/sJXXnF68QCl37dPKdweNMkT35ePfU1g2W6/f/UbwBiv4YK+UUsr/Sq2Kd99u9i9ojMonu7JaMUzGyeNGpvdGv5P0N8Ie54MTx4aad6JE4b7wphkuet56JBiBoI46/mOhCveaAlEghDlokEsc8KL02O/EZfuaPSJ2V8gl1XLmfvECEVCj1LgB898g05jUbrjvJ1MSJlaoc8MtcJAoHBAI4WvJeaFTxiMTsJuINHV7XlTmeDWKuzMET4fv1DgNa9JGHkr09r3uizqlKVdmKTEwtgtNbzBz7obkf0/KTnNaHjI/28AGmE4wHZ3ZM1Y8IjRX3S7GjSLslWdbw6pmaXWXp+p240ZWrGj2kSnSHQZVM0Yn3UAW6Fgu+wZ9g7d3f6dD5PIJk7WT1mkt5H6M+8oEmeOqkyrK403Ckpu532HyF45txv1uAJwht0GbordPM9fTTHe8JhJCmTc6D9WdI+3Q== +dk_pkcs8 = MIIHOgIBADAKBggrBgEFBQcGPgSCBydhsiR6SR483IZ2F4+L6SXUpRAPOZHOwiPaPpA/3TFAYKq+2GqA7ZXnNedzk16dGOp6M2Czc0Wl19W8hWktcKn4MIIG4wIBAAKCAYEAzgRkZqMdBFqq4xJq7zT/lPeh6jHIszQaJZegA7lQRzQiHeXmAMo9n9yLYcXdbM6vyDTYxPNYmht8c3NxHv9p2wQCN4d1TAP6oIafG9Xg0RkwzaXH4iZrwpkQLx3g4FQKYxMNfmqhUXi6uGhqwioD1DwPrNgj/TwRI3d9lKXl3o5wrGkaYSKPyhbiY8Kh+vRFjUxC/8Fcq0+aYzE+i6QFXGH+WUjhFhFDhQG0ANItvcuPsxB8Z3lIq43gE1WDqHMK0jRDrsQa6oXn4LQxpuU5832UHQmf5DQRQRj2GLwNpqeKVbiZiqxJGwWLe2VKHO+t/0dQ9T+MRk55iWHcKMuUFG09CYSGVfb9ngqw4CwE7chJyTpLpISUbjyO38A+hzNW3JITPogJg0+YTFRxI1JeuT9AyEiI2nbHaJ2osgYM4L68DvTJ+bTa66j0jrbu+xelcVDHqrF63gHA331M0PDkpN+uh9zeJb9+gy0bJvw5hbNYmmbruP+G8GWBTjlpJSZdAgMBAAECggGALMAb/gZ+8lfuiFITG+BPhzCOQYSsY67U4icQOVba5wieQ4/ReQj1P2Ek/qlACpdP7CV8k7WHYLxJOXvRTeotuIcjoyO/uTIhEhcD/0QjaFA4P2d8JnXxkOz2LMHo+9mNgw1bsELhxUR8DLwTupbtS3/7aLBvit2uHF3jj7NEniYjN/RBqGldQgjcBs77p/tBE2sGH6+FHWo2b0b+Xs9TYcigewz/Za980uq2iroc+P37eipB16kq/abdDl4UMfZA9thBKyKJLP815qmteSrc83vMqisyTFT/NHkzsjPU0T6c/lb/i3orQYCbrJnQDW2LlHhNudH+Oq/mGKW9wECqLW3krh/qvhcLGzKKwwgQtzv5uQ0mfWfU+roU+JEZPMKeKaoCMdBgvRrviCVIpRfloakWhZG8tUMXlNZH4/wBcspXfJAlMfOngSIW14TI1WuXtHNRG214wMSxlYyvP27APQQWxV2Nrc9H1Dsh27DJYjcwHbReVCbD8VJ+UmUkORvJAoHBAPF4AM+ZVz98SawNxt69W1GesFlLHc/DFc4NpP5IQQFuuzI2qMeOvIhsCdW53vw8NWoHHxDacL2xAD6R5RwIzJYBc8vha9fbxpcROYXPWoLmdj3TbThw3+gNQ0vsgYrx1VG1yKb06ZU/gDdE/401jecS1VrPacNh9Vhtf0ncM6kgC6G9uSvxh/Y1vzaAlFDC4/IrLYWk936dEPcONYkdUp3bHQWT7U+N65Wg7O0N1jLmI0h8/BfHs6+5rYqXSm79OQKBwQDaajtkkcmI0XNDySczT0ytSQkbT1RYJo8xYZ9nDxltLxgWUBJM+2Cej4ptk6IiEgwkMcO8V9XVTQbW2kMXM5G6T9IbI8KPhIF6AiXwR4ygwWUccM7iSm3fb++IqJG+WQ5Ww/aLEPj6snxzzCtAw9Y4JWTf4VF/CPj/Wqfd6IkssKdR61ADC2VSucKdw22aJvy0XxHm47vUggPxL9E4utYcP/AxthLbuV+vec83g69lQn7pk8whlAowVJSh+8M4FkUCgcBTXz/IbgV14g/92/PiTDcPg18YNZthdNY+gu+I7KGlQPpZaA32eQ4XfFYY+UhIhvFaXoMXapSqqkaPVAhrGY6p7G5y4q49paB34HagAOwbbj89MZbweeiVUp79w/cmZkFlKQLSwpUz9uzqKGSj+O257wLDjAHUeCoiEgx1EBa2Ol5Jxhv9VDPBiuUuiE6tY90YbFgXYNIjYU/OPZW2de1km5b1qhGx+ipxS1MCtlhS0qs0CBNykn00G0QUKhCFKeECgcBgGFEdRE8pFQ3jiwLmPkN8EiAhlduEFSL3FP5u92O2d/vfBUen+wldecXrxAKXft08p3B40yRPfl499TWDZbr9/9RvAGK/hgr5RSyv9KrYp33272L2iMyie7sloxTMbJ40am90a/k/Q3wh7ngxPHhpp3okThvvCmGS563nokGIGgjjr+Y6EK95oCUSCEOWiQSxzwovTY78Rl+5o9InZXyCXVcuZ+8QIRUKPUuAHz3yDTmNRuuO8nUxImVqhzwy1wkCgcEAjha8l5oVPGIxOwm4g0dXteVOZ4NYq7MwRPh+/UOA1r0kYeSvT2ve6LOqUpV2YpMTC2C01vMHPuhuR/T8pOc1oeMj/bwAaYTjAdndkzVjwiNFfdLsaNIuyVZ1vDqmZpdZen6nbjRlasaPaRKdIdBlUzRifdQBboWC77Bn2Dt3d/p0Pk8gmTtZPWaS3kfoz7ygSZ46qTKsrjTcKSm7nfYfIXjm3G/W4AnCG3QZuit08z19NMd7wmEkKZNzoP1Z0j7d +c = +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 +k = smNPMrd5yE/zwIiSYi5Az5LtyHc0FY5LkqQrNJz1JJI= + +[Draft-test-vectors-id-MLKEM1024-ECDH-P384-SHA3-256] +tcId = id-MLKEM1024-ECDH-P384-SHA3-256 +ek = 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 +x5c = MIIUfzCCB3ygAwIBAgIUHjPF5/bKoq4SI3vcPDgbLZmYdSUwCwYJYIZIAWUDBAMSMD0xDTALBgNVBAoMBElFVEYxDjAMBgNVBAsMBUxBTVBTMRwwGgYDVQQDDBNDb21wb3NpdGUgTUwtS0VNIENBMB4XDTI2MDExNDEyMTUzN1oXDTM2MDExNTEyMTUzN1owSTENMAsGA1UECgwESUVURjEOMAwGA1UECwwFTEFNUFMxKDAmBgNVBAMMH2lkLU1MS0VNMTAyNC1FQ0RILVAzODQtU0hBMy0yNTYwggaSMAoGCCsGAQUFBwY/A4IGggBToZVXR8zm+afCEDdqNBGkCwcZloUxt88DSSzzCc5EAAAnGKL7p3/3Im2mZb8D5S+4NGrBN8xm+m0TKxZjgDc+w25xCqh/E1xA2bwhYaR8h5pT2DQiKYSzoAoK6CSOWTcEWJCSgL8rYWWQS5NXGn3niHlBcsx+OL28zAZGPEJBDAdr4KF3XK4DRY34S2yZuW9PyGUHJQnNpp0v6lUe4iRKCchZcYMNvDw18cvW7LrIMLr5s6FOU1ws0l/9R5HgJTBOB19EszH2YBC5JoRhYsG15kC0qmIGW67CEzhlug3b8CKVtKo0ZTFxBIboBVdUpqhO9af4wxpOayunK8tfszNHRwuBQJY3JU/H6q17YHrHwzvwi7Wtgk/MhsQgMaAgu7pNcpcgg4w88U7SmQVsiYdos1X417s3kqXu66AdWY2S0ZrrdbDuCB/MisyuyRJ3UYNNB8r+FcGJ5r2yEnukRCbEp4t3cwBDl7dGB3MRiDvEJceTAXH+egg6BXmHQL4LQFrzBYuqqgNdYxYX6kUE9aCbx5otJoUh6aDkN263iWO5tzsyBz96mEWjmqsfZSixZlk40jmdBo6FejMhMyx7UG9ZanSsYB3M1JY6S2lzM8Vp7L5bGyMLxBu5ZUCyFs9YKyRd6m9NWV2Q0S55eMAYqzdrBC60lUrN4G/QLK55dJ87Kw46QG+5C5St1iAHugpf6CvsbGNJ2MNyDBzHmGF6grNxwnsxtAayxWZmRF5TWJHeS8q10BDdcqeIV6HjRB95V8Xs4C7Wt6NMxmVCjGoUrGlJU3kjqpnmQUeIRiIUV24b4jKI66Ve+TnOZJ7QcGc5MpUwlxwTyKUqDFd/1gYrvCRpUUZNkV8M7FxgMVCI47aCG0YWIxsBEZvJcVRFJCO8yphZCVTQx718W4icXEHuzDEhVLD9y86Ah0bP8L7X3KHO2Jp94QuYfGcqOriJmnL9RipXNhsct3ySXFOjqUJdRUMAkECbM530QkFQalJjWztckFFy86lzdC+fuQrcVzbXOrZBanVPi0skuJoqNszqzB0YKTpjfB/O8hkeg0p92wBBQCen4ZSCplWW8hyWRlX0NAKcIFdCOqWtmT7pcaFbEG5CYTEQ0x11oGwlKFX1OggqIm94LJtlZ5JWBqa80Lhl0LGWdQUtDLTEqbGvOkDemBgs1Vwi9XwceBVQpxJhiKqngMN5VGiNumVgzJjnta4NooLXwp8sZo+BaYHWx1jFBUrxd7Pjpz3StTXw12URwwRtoL0PxlnrsBcm4cwi1jIJOwW5FHu842UUm67rRoarSGAENCWYQn6BElNRurItJqcntJnWusyO8Lmzhkrf6VzCR1VsqSwxo5OgKElnZYbml05LPLVZI30EpJwxQKcspK81VldFt1dF4bPlhokX8ZsgK5tUFh8vOjHN2CXP2IeTOqwaKgANBA1L2oo6Y2/ZC3CZVMxs4zKcOwsW14F3mQ+YaHaWGwxvrBNSKq7Rh3ldYFMmkJo6IMiamYr9AAPe88/jEZZJO5/ZS5FmS4VjUyDYhamDAnj2Rz5Wdjb28aC2mzvYODoSUM6pE3HBqwJVUaNLGwc6qVxRdbJu12UV1XjAbKJzwiGZqDPZYI+fbEETiAeEXHwzyldvWVyTI3zfMx4Z46wKzL9e7Je0qHIhi8u3wUGmwbYUuqaXFUE44htrNh/bQ2vRRsIdOcVNyitBl2+r0y52Fp66UcWRJY0bWKyWoq9H11RNHHpTkyBXEHJvU2qZkwvh+SJjOqWbw3fDJwTmzIU3oRgLA4OPICGqpST4WCQr8gr3hnCW03yWXABMVy7/icAdAcbyO8SgVb6EFkVss7/sEyyi6zcEMxThwGVVV6QBrGKbIAvqk8jMOnXsQ6rMMcWCcRQjKci1hbH+5lT1HJFiVjJQpb1SUEAprHFI0AIcZpHut62Qg7nUgWhFh1Rh51yqRIV0MWk2MRhwdWp2VoJn4IY2lLSUN5cjsCbBc0QJ8ZahVroFt4Xg6TtqnB3UMbGqekVvMn8XB08VCSUpipP3mn3RcxnDScsxVhucfDIAXwdgo6b7Loa6eJx07+dVu/N8EhyUtBPTm8FrQV1uVQQR3/bdeB9sCvw57Oealts8I71gCTP6/SklIr7yveAdZZ9fyOvllrnRdMTZy7LiTNvjisPneIXnQl6B8JSKSDYzILcGsm2XFfp+Rp0oCgvVmkWVP/78K5pfPIjYHgMOf2qjEjAQMA4GA1UdDwEB/wQEAwIFIDALBglghkgBZQMEAxIDggzuAG51IGpWrSMOpEG7paEdx4IQ2k3SriIzuKR8TpJSApwdcTrtOuoS5PBRmRbsWIQbh61Z0EOeoCIP+LlrocTYBFOsys2Vr+3UG+RYYWwTUfwz7gqYP3VmEEs2LY0i3PahTbysmzm//MPuVSecqHy7dcIHtfZyiuSwAJfGf5RYpuLMHkWkH0ZZEhHxKwRnIRTGRm9jjyAD2P0QzoxuSk9XhfexfX2lXIlwae6AhvpO6UPcfi0LiMebjAb7mM/CwO7UvDicX+Dee1LbbLP4Mh5w2c6Q4CBPTh8kSeeLLeJnMne0w4Y7pQ0WNy2XmPpS+0Smrz+DrqKvGFnoMz2xjkYg3/HoVbvpQVS4Gq0iXohRSgPv+egNeD5zAXZu7TOKF24BDjtTLaZr/HJiKPzGpdm6QOnNBUF5oHPsGW4jDfgXTcpOfht3lzWDqJy2QQm7YOKnFHrNUAbTIo/Eb6C8Pr37gmqU9YhayMZgIjqklxpkjrBDJ7we2M/f5gxFuRsuDC5l6iNpBa/KKWUn+5QFRfwyrdo/3uFHt3BupU9i9yjBFjZNmWegqfbQgxziOiNB3Sdhe7Z9tzVpu5k34SR2wPawaq/C7twxlu4FICJsyRgKhvw8+uc3DWZMaS0zoPSjJmjQTqB43hPqyytwTUZeWpL72cPCQ4+6mVhIouqFITKpm2ZF8JeKdWcjyn0ehWAvDyfxZmgtRIi6OFrc9j4JuhY/7Vy9s1PMOn5niC85THWA0NxfOkzqCN/cA7i3dqdhoc8D7PkKBg7A7t1hVV0wtVUcL3vJrOqB9EAcNCc4/9VdwOqnAzwCryUCGyOJ2ARnLfH75rTZ8rnpV8lmOheSgXw5P319aa4DjARI3c6JcEoGc3zFK1k4QQWorTjEun1k8nE2HouBnBqxmaas6X757DWzS/owM+aMNKfuvSsRkwKHkkmxXi1e5y7MmsUiqPQHMvRz9Uagof3pVsq5JsJKAtGY3DiGjwa5Ct1nkxn2WqiyJAtWDdhVtE1rJo8NHiYNUdQIk+pIlVD2Rt4/iSOXevPLjUhwdY6QZyfumBL/q1Pkb2YVCDKeCRy4GQ+YA+Hq2Cg13uXcSzz41K26VWpg15vAqoyTCWzojzJhj3Q4r4A97oschG4spdK6SYIuQe4TgTWwafiY04Sgbu053ME7Mdj/2uGBjIKcDo2qALxksfA8dgNd/7taprSq+fP/wKPOcRTeMYiqvBZvXX4BvpkPo3PALW87QW28FidrqeF6Om39Sn6bGgYebHm7BA/G2jhr4Z84jwe9Pqm0Xe0eDonN6ncn5z/a5aUdK/bZL5UHD8LHZIK/43Yy13lQ1fBxOIcBYqofn+ubv575ICmqhKX/zd/A/E9asBsQA+mb9OzUfIN/Jlm/yotyMrd0PlWAFgvjUMCE6LFybEeE2smZOWv3tDBU4knMKnpwaPuB7IqRpQPg2dBHuhl+i/cwSpVuOqba6+7lCi9NtXDZjjT2fM9lMNs7dfd82YR+ZuYF/vbgZKinNtTn9Lr78Nkf22zNDyEPvKYileAAjIIgxryaiEHCkOdwgaWCYxTuFg3oLdSJpV8MB+fEJgkQoWylGEjpYl8LqyGP9NW+4GuYyngiS8n5TLacFKTs76EjX+ivtUQJ04WQuOF4WWLYgOi+aoV17x9nSyxRzpFiy9boqfq1v1APRqnS9gfCjYDZ+4ADQkpLcw3YZloHrM4UEgGrgy8h10e7/JX301ettAUkbqmeGilKmxssdD4s5hREUxvHstFHrktQ/rlOzrPxJ3y9EAvZs3glrIjj2CU5qfC6gfeQq5kqF325UeLDsDRULl04SIA69jMbiVLLpZhvf3GAnZO24keoaPRko9dVh8b/r856zbbpSWa6b7PqWZedAB9p3IsGxNYA/0beIy2EHsyDTtrs1ZWb3iQZ8/wrO+ixlatWbF5mpi3cs3tT2EwzHCYxiwi/y68rmihXKYRa9sO7T597qWk5Flg4oVjvfMjxGtVI2l2us0mGodrzU3k6xZtAbdhpxnUQHo+0txyFBbRwpNTbzq9Mcq2+35GWD6rBf0fiXNmQ7G4NltZbk8HYgH7C/z64Ys5jM805xngtKTG5DrEJUTMPhe7U9US/JYf5AMe+pvck/gS4KBGwq/5jVy5R6j90kPrqYqCAQbUgWefT9p+CtcqhgXSAiPSdfD4cPUV91g4Ed2dOfBUbHRVDVLWYXjepZwkzG5z73x+Mk2Pt80HJ0oljAOJFVxq09N4Ouae26qY/nRuq4GwkeIw0diIFzdYuLLS2mmBp+ivNnZxpbyLTuWw4jbxB2Z3OQS/b7fxyp2jMD01tIizdz9jYA+BjHo4Qb3I9CfaikDea1dhOSi3RnkPG2BOAEKpE2G2PNQIIcNI+cziWyR4lMwGjNqmIX1SLzZLE8ll+wB5HjKAJM6G8md7nFh47bEX+eH3DUP8pw9q+qcDAZFciqehXsp1H0TgXEg1/+/qosQkEl+C+gfhooZOuIrJLLLldSYpgGG2aZrwYXZaPRj9ipNykievOOd9rquemAMNbWQVPCcWPvMeI0gb6MSRB+RVZC8OMXAc/8mglpDxPHrfQexLMIYZGHTyTl+P4BkxoDvHZRmuL1zM9K8v2hnDZ6ULfjaexKAXZbJNmkeP884AsoTTdK4w9M5yU2ezcJx6hj9NPLy69ICRUEaMso29EjUSwiImekq+KGemW+P7NR5+LsvvirjkfEp+38wQrzHENGpZ25dGar17Gg+c8IwIvbDR8kJcoYkX+jYP+bpvdjuv9KSi3ZU+1GdbIOCh+tUlEeZYODTJlcIxt2ZHqaLX5ijy0yarRZDkTxw59c9hpMEeI7jw1aYegADqHQ5MFktwDYM1hSDtWfyGpt3b58+zdOSHm+X9VDhSoKYhinsX4/5evjjrmBmT5THh8WaDPduo8freG4tZN3BgQP9Yrdp/rbHI4OkwBNPHnVYKyqOcliX0a1tHuW2ZWYhP3Qy8+KdZM8s7rMjqcwT1GnREnyd1/8XruDXKuBT3X9RRgN5tLQLgF4wnDb9fhp/ps0Rrmg3QDMW+dewyI++OkHWX18IVyvWGGvUE6aJSAsybtakyCty5V7e3AZVQPWIlQfh78F4Sv8sLvURwrhTDZFgL0GP4z7lkQH4QqEZs8RrOt3yvQ5c5uaBGZbcdSJ9+GuI4IRoaHh0kkZ07F+YKdmNsiR+dDeKkdUB770SRf+cem5Ru83Cg5/jxYp/5b2MBl0r8HcEOtk+m53b6KKJWqyppncdGYyhmTOyCDrx010aYO12ssukNoan02Uh86Arjr8+wuyrwNObZX3LgGihriBBRGSgeBf3GkNqQgUD5Rna/mgLeLwIsVpuM9J5ZMH+gNdRVr0FECy12Y1TL76rgzAhiOjyml7nCD5GgVV+RtJUBdAdYZKiNUFbg2R55XkPiNqJoMgcjP8iIbMeJAcnNZDXcXxJsca33za8vkUzQtMyY7/fxGKaawrjxwQc0C3glxUmcnIRvI34IV+7qQveZ5it8H1s/h+k47I+r1pfzcQBEuSodi6zWYjpKUOR0kcYb/CbsnGDUvsMoPpApzoaAknD8+4JhGfoygl1vb1uOMVvt+GmGwkYANuT8JrabYl/e4oEqIhabqfAbCVihuE/RONbHbhiipwiKuuWR9wuWAhwoga5s7Dw61xxFPx8iTnrhEdtbpzZ8yoyA1AsRHsmzACR62IBwJezhVEZzBzVlKe/UJYEizR9WP5rO5WixMaKWrg2L4WQeZSvjeqUHdRTcdAUhEPpc+FxV0K0JiCsBRck1fFeFCYFaCkyavQnQqp6ivLkZflfS9at9yyUVSQTBlmHSk1DKoOHRuP0S13MED3DXwPgXvjkk98aktixN0d669vuSJGs5QDqElZfSMeTt1nFImti3wQSX8lz4W/EpGTHNwktUhxsO6eX+Cg/drD4uw146m2JgZddUikpQl3DpW95rbWM5QUoRh4QQwRJIBYjheToNlqXfXN5zrepOla67R3faIUbo01TRT9J5DanUdeFR24LljqKjhfMmB2cx/qWPfWX7Q0V5i+TWY2+N0HnVsSKc/9TNLsVoUoL2x/4qW6ggcSGyHSaphzkO6z7VrJvszWbt4bmlvpuFqUl20uXJcA3T1jAgT7Cm30V0UhLsHz23D+evWi41CNwqhp4//vvlAKd/mE5Oh5m+QlsZeu7ZaYMi29NgYLT9i5FUMVO+y1JUD7EEIUkcKKdE7WneGxnNiwYYqsUDl6Q65+5hxW+KFbYjhE/ey4FPZOEmDX2zFLF7X3MBIyWmNuHD87ObnHKPpfaiyX1EEJXc4s++6AU9DCpMOfdfuN152lsn1+QBCcZCpts3T1PP9KjJKbHimyAFzgRd5hc0n3OLoAAAAAAAAAAAAAAAAAAAAAAAAAAcSGRwgJA== +dk = bAGN4EvIWO1CmMwcWEx+ClqOA9shcM1p8BUuNpkYAYrXTn4zNrxad5gw56ohp16Ex+at/mCwTxGcA3jXh7dd3TA+AgEBBDA3Wu1NfbkJsFkD2SePk7Yu6bBJp2nKqXdHe7xBMxRyPAG8vUUDArpB/k0xEy5wtWKgBwYFK4EEACI= +dk_pkcs8 = MIGSAgEAMAoGCCsGAQUFBwY/BIGAbAGN4EvIWO1CmMwcWEx+ClqOA9shcM1p8BUuNpkYAYrXTn4zNrxad5gw56ohp16Ex+at/mCwTxGcA3jXh7dd3TA+AgEBBDA3Wu1NfbkJsFkD2SePk7Yu6bBJp2nKqXdHe7xBMxRyPAG8vUUDArpB/k0xEy5wtWKgBwYFK4EEACI= +c = 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 +k = 6toa/ILKlMJoq93MfPd5UQHFeUiH7AbFVstF0oRSbN0= + +[Draft-test-vectors-id-MLKEM1024-ECDH-brainpoolP384r1-SHA3-256] +tcId = id-MLKEM1024-ECDH-brainpoolP384r1-SHA3-256 +ek = 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 +x5c = MIIUijCCB4egAwIBAgIUSt1laR3T2N0y8caa9aFiuBc0fygwCwYJYIZIAWUDBAMSMD0xDTALBgNVBAoMBElFVEYxDjAMBgNVBAsMBUxBTVBTMRwwGgYDVQQDDBNDb21wb3NpdGUgTUwtS0VNIENBMB4XDTI2MDExNDEyMTUzN1oXDTM2MDExNTEyMTUzN1owVDENMAsGA1UECgwESUVURjEOMAwGA1UECwwFTEFNUFMxMzAxBgNVBAMMKmlkLU1MS0VNMTAyNC1FQ0RILWJyYWlucG9vbFAzODRyMS1TSEEzLTI1NjCCBpIwCgYIKwYBBQUHBkADggaCAMuIUj7krsGlUMVKDdGgdzhaxJpKEobyjLXBgddcICayitXTUIQHBphVtOuAdmJUeOuCAnBYq8xXCRTRYyTpUJkibO5DUlXZuKLSqcGiWZ1sH7lGLHY5bE4qJ5FTxC6CfBojiGCJYvdij8bCUDIMkVZqsLMEdq9ikdEzpd5jXFIDkHGoAGwLP3aMENF2SQtzMMaKmM/jBhMAhd1bmfNifiRMaQkJv0nhTw2DJ/FHul+GYuGFhIfpAw8IH2m6Y2usRMLJcZvlytkYeiJbtEaDCFpBrA1YOv94tWeELVxhvGqzmZALv7uhpGlkOUWjdwuUot6cC/h8z/iWLr4Xrm4cHzq2c5x3QVJsFOrZQkPcdiEWyIDJWvqTJqEDzXdck+BhbEXgmEx4yD5yFVMUZACwH9v3EYf5p5j8PYaZLI1nUj8sJcaXRyCaxfwSSWMnEdHDZDJnYCZDNy7nMkcUY3G5dDoxQnlXmszgWn+GTwZ8W6qLJMw0e2HMasuZo7DxHYOkT2JiSgRigLJ6MjpIhq70idupBYGlnJ6FHB+LRAqMEa90WXm2yuVjqkm7NCw7iA2le2kRvJ4kBTlqVK92eS1kccOAeVyGwAflooFcsZs2jiw1q7jbbzz7PvMmwRnpfCj6zTI1BsQFV7+3oVQgls9oaQfHoRGypHVggBvGr3F5SUlMIUwTO3xFe1o2QekbisSXOEhwi79gtZJ4a+2UpX2nDYMTAME7PO8GhlWKhFKQRz+kIE6bBzsxuny1AyWHg5QbOF7MLLIJWr1iaIf1HT5Bar6hTfYki4HrfX7YLkNSmKvJBoIKPa0DZe1ZACfqdKtGO013yEDUqvdwzdTbNE3Ui36TwxzryGJ0K1Z7wbs1h4BCnYacQIA0Lv2yPP8yeEiMrez8GIaJGG/BJ7UZhOn5xHWnL8qzTKeczGobPAGZaDNBdwzKHtfpaBsRdMg0NHURUxO4jj1CxAwanpCXsH9ak6KUBiaQsJg5Wfc4pkQoEGBgj3yjce5LkAUbYI/zqI4avV4bRNiZTO9ZybfkD3bUvWTifCwmmTPZy6cMaTsKgeaIY+hHnbdFTIbIs+ObBhwwruBLXD/WYz7srPupirrCk08JyeqCYtowIqykEvqIkJB6fDqUxrj1b/VswiRRaa+VLQPwzaxskJu6LgXsyaumFLHWFRTCvIRLFhvUXlu2XWCbNp/ATAr3APPRu20qBJGSfL0DVV+wXnVGkczTuXKHIHyMBCyUfaqhcS3zsZdomCW1UzL2Ew4Fe1hklLwjzdtEcTfkswMXz8kXaot6Cm0FuibxJagKEd53as2TIiGWR4vXjJhBBb+THsqVH5yzLPdKbLzSxsCBqLt4ZXTryihLv0aRRX28T+YiQcFChzDrAIBLWXzVwV3okc4wfEm6UO0zkCoTX3FaQhe6lILoF5nYK0cGf2cZvpLKDilgnlnETJ1JBBjGo8GZNCOKyseHqfLZlfyjaGWadDd4km5Iy2zCfORoDh7YK40JrxQjsg3Bs4spmcUYKD56ODTGQEQzYYALObmbEqO4FHZlk3CSNRT4WqAWpjq1lGP7REAxomK6QIeJQFYLG90MnM3CXQh3lIusC333VXUJ0B1yOarFY9Lgxd5IXfkzuU9YBOoxDDJMi8dZyUDbwvnmp9+gagKJP+bDKD+2eTmYlMUlYtTUiW/3uIF8QdTbSDHRE9DppYo0SL2GMX5Chz/bh4CWYPtibyBDorurjn5laBjDIQuokd8SlxsZmHrky/nCM7nAx3QkrzXaUc8lW1HjI0jYlcj5n7NcAwBIrYSSoQcUYJWgOkFyhzyID9NIjGuFM991Enl1K/ZbVewACsyAZWjjhOWbc7Kkuz+LFAS3kYt4UMaJr/OWpFvWhRg2KBkBgn90OR1VJfpny2MmHCvIukViuMT6qltEfyo1HU5iDWb6OlpqtGilFFLgetGYRRXxE7RKjaXkcsncXramxVa8pryYyuHBVRzBi0UaEJNYAOahRvPalrecCUbDXlJFYHe8bE1Yw0Wpzl5FXzj7HKXBJ5vHzNSWhP1zgolp3uX7oSMb5h0kVEAjeBiYFRSAvunw8l+uuBu9Kmc6BGACGvpU7Pt8PjAE/2+62n37KZY+KUlq36Q0B43HS++EZStJDqtKhJgsQso57m0d5WQOKlwj9kQ7C9XjBfYf3yf8+35OJ4Ghqh0JiwuFxTJ1KTiSUq6keOgGrrjlOGJI8qMSMBAwDgYDVR0PAQH/BAQDAgUgMAsGCWCGSAFlAwQDEgOCDO4AWYGWvM1I5cSsI0YGf17ATGsvnP1LyQPDonCAE1jUZmee8bnSNP2dzgdRsGjECv2oTJawov7eoR1vT2mMGg+dPICmMhUoyx/tirpVMSGMQuMGMJtpNYOvQODWFpXUyORa8/mSppFLvxLQFx9KoYZj4Olg5nEHErxrJtbMbTLIU63aT/+n6jCGozswFDeZP7EOe6fZ5hHYEkprlGyNkip3J7mUCaofc6ddKfIbRv8A2cvXg2Q16MTOV/7K29T2EYI9m5KTAmoN2TiwM8Y/B4aWqHhJOyd3EZHJYWj/WryIzjdWu2DUYRJXXsYPkVqOPtJ/j4DfrW1mbajKi0nCmXEdjIf+Osbgw6BB8wgFZRIMEyvPcEIFgQbC8/QRQdymnRASgW4nUkF8DaYHCzw9aifuKtkDnJo/8d80hQZenigfvnXQ7OGbls9MbxZuDnWy6b3xWKZPHMGPUyp5DQbypNun3bSiqwDefoKk1YvRjmFYcSCVEkZrwEtWNLSu8idzfmkpm7Te5Pl3PbvZmXxZABZBMfDTkfPuZkcqXWfqfkGXmfDia+8IcfOBM0CBusipmcLJNNxoZvxvUi7zZq2/1IUzXlX4PCNcX4bFtOXcUk6wVu9fl4VwVK4ETCrlo+EZp2Ek13w3EwZtYcpH8Qk4V0ZOhA2aQI7nMpgVcV1dgH7MZG8SepyyL65gCp6psXKUwWoBsdKnGpJroK96ohJCWOhPT/Us0pZWb1ariaIHLzl6NWrl/PyS3DOMyl0Zx43yqP2P9PVJ4Yd2FLC79nBod2Lkv0FGDIsQw6E6BM03BFEQ/rSIsnYq79DYuGrYkKjVXMrtm37lMSQJUDXiw6fvFA9eBnvywbTajdE75ydVYPCA2lFfrhGzRlldQbrVLz18hrf1f5MwrPO1AVMv3W+Tct91fAuiiLO61RCKwUzq8/tY+NwoK6aw7NRCDMasq5bkp0osJoq0cB1CIIc6iQzYj2SBWLtoGNu09zlJpFPmkq2Fnc4q/wp8H+d8zyKjeZS9COm/+4jdzB/sBS0cRZmEG1wCxJe3RR3uRLSBpU0k2OvoAJ7r+qfHkA/M3hmjacVKDkuC1oJVelHL2JOPmmLvsp9qFuzpBQFoIOeHeVArDUZAcHKejzlhYWGUuB4+ARgrswx8DLmuN41e4+RWzcJR1sXqslhz+3bjcCrTEZjSZOvuKytmKE25ZMK8kw5XTbkeORkacCeoh7EK0V9dVmrUDZ8SkZJIweg7Vo6zn+oPbr1enUqh5h+D5q/aXxFGKFbTUfqKwsTWUZB3Vnf360JoT8uU9uy27Ybb4ZTjwyhHxw0PI5GZtbfoEoRZePwFWx6DGVP8gf5TJDhI7Gbgm2hdScqwfZagM4dhUZ8xZlIOHnGW9HKKBGpRhyqNsMYP9PUsX3xKcp4pKSJDJbN/XrFSXnUNYCBZyM1m2G2D3HrLE4YOIcMdoFoMGsGWtz5oLQ2L8qyT5CITw8fOpllftgiC2ilnxhhofWPc5CWNGqQrvh8gwA2l5VGqn9eKJqNAA3LPWhOXZrBlQLGneuAhGiZY+7oIxOiixfMWjIzZRWHoMQRDNuiqg2QNNTRmzd9FYLurxoG/Ar2XwkYmmaXwiholC14pDV2qEHVzZh6elg3fctLxb43ZwaG1SSukg9NZxdWQ8iEPMP/bcUfrhqhtNk71WjrlZqRp76F7xer2rDehn+/3cpnGUA/GfR3ASgJ+axg1Zrb6ImhOvR03l5HQLi3/R8jTvEfglG/VhrzrqGP3Th49Z9MCU4vyRgQNiITcHMwlbU0Am4kTVzYFfbETC84x60VYByJcYiGoq2Ks13mMi7cNHGc/acL0Q+m68q0ikWx+gB74bOehA/NE9OF8QlejDwwVc/Zecn8OlT4WaaaOELSKzQEEs5LvOBgj9vsNqfhCa8DgjXnGXb8ODw4xr1EhSp2dMnhJVGpacYKr1IFuwK3ShKyOWIPjxKGcpBb6OpuLBJ6Q9y/sBIDT9tSa4jyZz6itUCl8PnGT/Ul8LTtYfAILalbl1CxKxddHD4lkrf3VuCYOCpF9w7DZmL5zFXPqK+2qwFaO/GlTgLNOGHUXinnO1oMvq6P0r6eyGgopYAvbkUeTPNTs3n3UWKCgdIkqhUsfzKIKEzhqPt4IT6/7Uo2EJBl+O5UHOP3S3jcKZBYh2rmi6ZFG+peAyVsDZ1AiUC5v7Od8PXFw/kOETkic3RQvE2wNsosA/w9iJDlHqEzeuqIPbLtLS21z+ympsS61NLKBbZsi64RYdZdH+IoZmp1VB9c0hR6kRHbb20R4ua9Bq9uT4HRT/Wt95VrNQ4O4dHxNVViXipHhNjrTMAfbL1g++p0RZPT5pcR5a+Kd1We543mM7/7QIRJ86CFOE6QI7pSMANxW7RmnjpdNYRCQFNdGWULlgJIf3lI+I4D+GPfb1oWM0YxrpIGqWWocVYFXdZYnrsII3KUvLFNb/QhqQ73EV9FSaf1T0JE4hyAMn6VWbtLo8k0KUMq8se7bNxh1qZoO+E28zZYthTKgGGjZO8An6mdezen1/EUaztem/AAM8OuAH46Sigzmp+8sZCBguIJKlTag9GDJZZPnOWszXn0SlTQmxFfdhdaZVgRDSrPK4rEmcTxHBTnYIOUWcsOQGGddB6B5W05oaaRy+wtaKgbUFDy0DtQDyE2qF+sC1d/8HsBsAc8Qk7A4T3w5Ub3MQFraFc5o0T9pSqQ4haeYL6uX27qemgGldqB+R/SRPo1fTVL4+z5sY/lqX2ZnVb2UO+u2CI+nrY9rYYKiH6jwoF27XX3wbzy53YL8LVsBlFEDDfrAI6LHQmJd3n3YEKCJJcwf+rtxc51XuOnDZHLyUSz0IZEFX5BBeHIcC0Jz8C5LTtZ7S7wwF7WMl5yBkcEirBvMWo+67meQIHOhX5vjKbARonEnyZ+MD8TuK3mZjApEzTgu+EGkBGSvhVQvYmGzWn8QH9oKI2663z27WuyZtMg5rjX5nEWsksUBxy40AneL9beNm5SivaSqUd7Ntysjgj7nNDq155mwLdisdcE5MVmM4JDnz33Q4gdLMR5s+bZy71/JULqI05NTjstGoldut2NqSbNRuMdzOatw0KQsTdy+So/LIwsAWZSLYz7LZ9VHuFbM0PrnyRCS7OtON0bkYzyVNMy/C4Tpq0GEGKNOVOoC0Y4Ye52LVfPnKKlL8uEhsxP7L2CpK9IAOhOo5q9Bq9W12gLTH89m9V6VLuESkIh6Z+u2JMCc/CzbkVXbC1zmQ4rSKTPjg97UOMcX9i9Yvm9ez4UI9D/r58cM+oP/QdMQKoMnzFJgd4orT8fYIacz6nTVlA885drtxY4F2tZnxUzmTURBTyTquMlbACD96xI8+B6forTt9R/IhTcX+/ItbV7bga1oaFqc2FY7aQVdRLqUDzlNgrvSuysY1vnCieeICf3F9pD8WsT/ggqR5SCUL7BkKdJsahcjJ0pM9QW492nY+2JvyRiRQjyp8ZwLKvyQSkfjYv29cWSChtMj/JlOAvwd8OE2N31j8Y64ZLtmc2z04wwWU7b48XRlH1bv3jr0m2N8eVDn+s1xsRVQPfyquK796n0kwgcD93kWIqahwz0RpAhQYKJ55nF3irHzt4unpaAjJkwtNMQqesFtXpGRE1YbcxfXsADeMndaJNDoPkvFyxEx9oKM6IlINJt43FD0BauZDrFF7y4klYQWFRUUEEVzxEiuJE3gt/oRHXvnizF+V+1m6mDQgcKMDwAWkTzkHBv5fh/BaGF2yaAJwazHjn+6OK1pdnIv2EguBVqpWFrh138axkpQBZoY5akGE78ZH+Mwi+fKqV+iPTYXCYDzk0y0oe1KDvlWgXIyYCOTErjghM4N9e5MeQoZgG7ufz+b15f0z9Z//t7zDtQQdaDAGw1PFRyMZazjvqIrKHVcbjMENaYlgp/clX829xHWnJiSAnAfGYQRYGXClOxtkywGQRJg8SuPjMauZznHDqfKP1vJNrVB+Nrf7GOWQQV7VtpCNW45nDlsRiedGUOV7DzhFNc37AHCgMCKB3W2ir8o8A1SGc8aROtu5SLlxuqRVIo9v55k7b0yI7MpEIg1pWTbIDTmwcOkwC+29wS0ZVJRX74opgM3vm1DcsY/72U0qHiz8NrcBbyF235gGjrtPTTElmiTafFZ1FLIWOGl0kuNjJhPUku9Jzihg69z9sfylobEHhmCWCrwao0ygG52nbaxvG9O76b62huxu3ZwWbT+JXcU1FfCNJDnbOta7n2wsJIiqQG8oAu35ln1ky3goNhtpx3hzx7O3sqRfTtpxoJ3T80ooCOjmQ1apsnUA/vwMeEdyZMiY2uGweUFNztWdJPUbY6ttdcGdcBMtMTY/S84QW6Hj+vuAAAAAAAAAAAAAAAAAAAAAAAAAAAABg0SFRoi +dk = Ed0PvmXmlhs+I3QccuViehbtzV1l140dmzkMFMQe/ZgYiOUOCpWCaNHi2VHnEJIfYf6WXcqPWmPzqEa1X0nkFDBCAgEBBDBmwwGIebU6/YDE04L8+YYdu1T4BF58rV6NGvA2p0dhuTh7nbPhCpJLQDg/OIvg1negCwYJKyQDAwIIAQEL +dk_pkcs8 = MIGWAgEAMAoGCCsGAQUFBwZABIGEEd0PvmXmlhs+I3QccuViehbtzV1l140dmzkMFMQe/ZgYiOUOCpWCaNHi2VHnEJIfYf6WXcqPWmPzqEa1X0nkFDBCAgEBBDBmwwGIebU6/YDE04L8+YYdu1T4BF58rV6NGvA2p0dhuTh7nbPhCpJLQDg/OIvg1negCwYJKyQDAwIIAQEL +c = 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 +k = JvbA5d3ZDGmKagVZo2Mpv3vsYLLRKmpHAzkBFZnrdUQ= + +[Draft-test-vectors-id-MLKEM1024-X448-SHA3-256] +tcId = id-MLKEM1024-X448-SHA3-256 +ek = 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 +x5c = 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 +dk = oRfW/hdTbZc4zxGSdDOWXsnU51ACbv0m5S3E3RfA55+x5SOlymf3pnHf8cQpq3nQ/RFVESMGs21r5JBx7TMiIqDiL6AFEHokW2Sgeyq67FAVk1nmfOZFiJZ7ws9zEsUlqFmZWJZs7MOwa+6lCf7dmMxI90O0aj/h +dk_pkcs8 = MIGJAgEAMAoGCCsGAQUFBwZBBHihF9b+F1NtlzjPEZJ0M5ZeydTnUAJu/SblLcTdF8Dnn7HlI6XKZ/emcd/xxCmredD9EVURIwazbWvkkHHtMyIioOIvoAUQeiRbZKB7KrrsUBWTWeZ85kWIlnvCz3MSxSWoWZlYlmzsw7Br7qUJ/t2YzEj3Q7RqP+E= +c = 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 +k = VBbnpxt8pkjcDi9Pj2GrSs4yJM3ZeAq6n9A7DJTq+Fs= + +[Draft-test-vectors-id-MLKEM1024-ECDH-P521-SHA3-256] +tcId = id-MLKEM1024-ECDH-P521-SHA3-256 +ek = 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 +x5c = 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 +dk = u4YgUmpfvWLQPC3hn+pLKM2eWoKvO6jjAoxp66F2EJ7Gga3F5nttGEvskQK8TXckzon4VlZYKLXmfw29nDXnpTBQAgEBBEIB0OYX4ibRxumR3zjRFnT4dDrmuEMln3dnrSM31x+VldFf3tOd8dmMW8aovGPYNcHkc0m6/hnPR8dZVz9lfVG98IugBwYFK4EEACM= +dk_pkcs8 = MIGkAgEAMAoGCCsGAQUFBwZCBIGSu4YgUmpfvWLQPC3hn+pLKM2eWoKvO6jjAoxp66F2EJ7Gga3F5nttGEvskQK8TXckzon4VlZYKLXmfw29nDXnpTBQAgEBBEIB0OYX4ibRxumR3zjRFnT4dDrmuEMln3dnrSM31x+VldFf3tOd8dmMW8aovGPYNcHkc0m6/hnPR8dZVz9lfVG98IugBwYFK4EEACM= +c = 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 +k = h66EY21eGjvyrtSZ8a9tVDmBQvf2ENWVi1sss1ne9v4= diff --git a/src/tests/test_ecdh.cpp b/src/tests/test_ecdh.cpp index 77c2133425a..f315c9d04b1 100644 --- a/src/tests/test_ecdh.cpp +++ b/src/tests/test_ecdh.cpp @@ -8,6 +8,7 @@ #if defined(BOTAN_HAS_ECDH) #include "test_pubkey.h" + #include #include #include #include @@ -134,9 +135,50 @@ class ECDH_AllGroups_Tests : public Test { } }; +/** + * @brief Testing PK key decoding + */ +class ECC_Private_Key_Param_Decoding_Test : public Text_Based_Test { + public: + ECC_Private_Key_Param_Decoding_Test() : Text_Based_Test("pubkey/ecc-key-and-param.vec", "key,param,valid") {} + + protected: + Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) final { + const auto key_bin = vars.get_req_bin("key"); + const auto param_str = vars.get_req_str("param"); + const auto valid_pair = vars.get_req_bool("valid"); + + Test::Result result("ECC Private Key Decoding with external AlgorithmIdentifier parameter"); + try { + const auto alg_id = [&]() { + const auto oid_ecdh = Botan::OID("1.3.132.1.12"); + if(param_str.empty()) { + return Botan::AlgorithmIdentifier(oid_ecdh, + Botan::AlgorithmIdentifier::Encoding_Option::USE_EMPTY_PARAM); + } + const auto enc_param = Botan::OID(param_str).BER_encode(); + return Botan::AlgorithmIdentifier(oid_ecdh, enc_param); + }; + const auto create_key = [&]() { const Botan::ECDH_PrivateKey priv_key(alg_id(), key_bin); }; + if(valid_pair) { + create_key(); + result.test_success("deserialize valid combination of ECC private key and AlgorithmIdentifier"); + } else { + result.test_throws( + "exception when decoding invalid pair of private key group parameters and AlgorithmIdentifier", + [&]() { create_key(); }); + } + } catch(Botan::Exception& e) { + result.test_failure("Failed to deserialize key", e.what()); + } + return result; + } +}; + BOTAN_REGISTER_TEST("pubkey", "ecdh_kat", ECDH_KAT_Tests); BOTAN_REGISTER_TEST("pubkey", "ecdh_keygen", ECDH_Keygen_Tests); BOTAN_REGISTER_TEST("pubkey", "ecdh_all_groups", ECDH_AllGroups_Tests); +BOTAN_REGISTER_TEST("pubkey", "ecc_key_and_params", ECC_Private_Key_Param_Decoding_Test); #endif diff --git a/src/tests/test_ffi.cpp b/src/tests/test_ffi.cpp index fdc379c5140..705fc8d67ca 100644 --- a/src/tests/test_ffi.cpp +++ b/src/tests/test_ffi.cpp @@ -25,6 +25,10 @@ #include #endif +#if BOTAN_HAS_MLKEM_COMPOSITE + #include +#endif + #if defined(BOTAN_HAS_X509) #include #include @@ -4789,6 +4793,33 @@ class FFI_ML_KEM_Test final : public FFI_KEM_Roundtrip_Test { std::vector modes() const override { return {"ML-KEM-512", "ML-KEM-768", "ML-KEM-1024"}; } }; +class FFI_MLKEM_Composite_Test final : public FFI_KEM_Roundtrip_Test { + public: + std::string name() const override { return "FFI MLKEM-composite"; } + + private: + const char* algo() const override { return "ML-KEM-Composite"; } + + privkey_loader_fn_t private_key_load_function() const override { return botan_privkey_load_mlkem_composite; } + + pubkey_loader_fn_t public_key_load_function() const override { return botan_pubkey_load_mlkem_composite; } + + /* the type const char in the returned vector is not a good choice since it makes it impossible to dynamically generate the result */ + std::vector modes() const override { + return { + #if defined(BOTAN_HASH_RSA) + "MLKEM768-RSA2048-SHA3-256", + #endif + #if defined(BOTAN_HAS_X25519) + "MLKEM768-X25519-SHA3-256", + #endif + #if defined(BOTAN_HASH_ECDH) && defined(BOTAN_HAS_PCURVES_SECP256R1) + "MLKEM768-ECDH-P256-SHA3-256", + #endif + }; + } +}; + class FFI_FrodoKEM_Test final : public FFI_KEM_Roundtrip_Test { public: std::string name() const override { return "FFI FrodoKEM"; } @@ -5755,6 +5786,7 @@ BOTAN_REGISTER_TEST("ffi", "ffi_kyber512", FFI_Kyber512_Test); BOTAN_REGISTER_TEST("ffi", "ffi_kyber768", FFI_Kyber768_Test); BOTAN_REGISTER_TEST("ffi", "ffi_kyber1024", FFI_Kyber1024_Test); BOTAN_REGISTER_TEST("ffi", "ffi_ml_kem", FFI_ML_KEM_Test); +BOTAN_REGISTER_TEST("ffi", "ffi_mlkem_composite", FFI_MLKEM_Composite_Test); BOTAN_REGISTER_TEST("ffi", "ffi_ml_dsa", FFI_ML_DSA_Test); BOTAN_REGISTER_TEST("ffi", "ffi_slh_dsa", FFI_SLH_DSA_Test); BOTAN_REGISTER_TEST("ffi", "ffi_frodokem", FFI_FrodoKEM_Test); diff --git a/src/tests/test_mlkem_composite.cpp b/src/tests/test_mlkem_composite.cpp new file mode 100644 index 00000000000..37634929986 --- /dev/null +++ b/src/tests/test_mlkem_composite.cpp @@ -0,0 +1,455 @@ + +/* + * ML-KEM Composite KEM tests + * (C) 2026 Falko Strenzke, MTG AG + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#include "test_pubkey.h" +#include "tests.h" + +#if defined(BOTAN_HAS_MLKEM_COMPOSITE) + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #if defined(BOTAN_HAS_X509_CERTIFICATES) + #include + #include + #endif + +#endif + +#include +#include +#include +#include + +#if defined(BOTAN_HAS_MLKEM_COMPOSITE) +namespace Botan_Tests { + + #if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) +namespace { +std::vector decode_var_base64(const VarMap& vars, std::string_view var) { + const auto var_b64 = vars.get_req_str(var); + const auto var_sv = Botan::base64_decode(var_b64); + return std::vector(var_sv.begin(), var_sv.end()); +} + +enum mlkem_comp_artifact_e : uint8_t { Publickey, Privatekey, Ciphertext }; + +enum artifact_modification_e : uint8_t { + truncate_before_boundary, + truncate_on_boundary, + truncate_after_boundary, + manipulate_mlkem, + manipulate_traditional +}; + +std::vector manipulate_mlkem_comp_artifact(std::span in, + mlkem_comp_artifact_e artifact_type, + const Botan::MLKEM_Composite_Param& param, + artifact_modification_e mod_type, + size_t index_offset_for_manipulation, + uint8_t xor_for_manipulation) { + const std::string id_str = param.id_str(); + size_t index = 0; + xor_for_manipulation = (xor_for_manipulation == 0) ? 1 : xor_for_manipulation; + if(artifact_type == mlkem_comp_artifact_e::Privatekey) { + index = 64; + } else if(id_str.find("MLKEM768") != std::string::npos) { + switch(artifact_type) { + case Publickey: + index = 1184; + break; + case Ciphertext: + index = 1088; + break; + default: + throw Test_Error("error in test code"); + } + } else if(id_str.find("MLKEM1024") != std::string::npos) { + index = 1568; // for both Publickey and Ciphertext + } + const size_t truncation_offset = index_offset_for_manipulation; + std::vector result(in.begin(), in.end()); + switch(mod_type) { + case truncate_before_boundary: + return std::vector(in.begin(), in.begin() + index - truncation_offset); + case truncate_on_boundary: + return std::vector(in.begin(), in.begin() + index); + case truncate_after_boundary: + return std::vector(in.begin(), in.begin() + index + truncation_offset); + case manipulate_mlkem: + result[10] ^= xor_for_manipulation; + return result; + case manipulate_traditional: + result[index + 10] ^= xor_for_manipulation; + return result; + } + throw Test_Error("unreachable code"); +} + +std::vector> some_manipulations(std::span in, + mlkem_comp_artifact_e artifact_type, + const Botan::MLKEM_Composite_Param& param, + bool run_long_tests) { + static const artifact_modification_e list_of_mods[] = {truncate_before_boundary, + truncate_on_boundary, + truncate_after_boundary, + manipulate_mlkem, + manipulate_traditional}; + std::vector> result; + for(auto mod : list_of_mods) { + result.push_back(manipulate_mlkem_comp_artifact(in, artifact_type, param, mod, 10, 2)); + if(run_long_tests) { + result.push_back(manipulate_mlkem_comp_artifact(in, artifact_type, param, mod, 1, 4)); + result.push_back(manipulate_mlkem_comp_artifact(in, artifact_type, param, mod, 2, 8)); + result.push_back(manipulate_mlkem_comp_artifact(in, artifact_type, param, mod, 3, 8)); + result.push_back(manipulate_mlkem_comp_artifact(in, artifact_type, param, mod, 8, 0x0F)); + result.push_back(manipulate_mlkem_comp_artifact(in, artifact_type, param, mod, 20, 0xFE)); + } + } + return result; +} + +void encrypt_and_decrypt(const Botan::Private_Key& privkey, + const Botan::Public_Key& pubkey, + Botan::RandomNumberGenerator& rng, + Test::Result& test_result, + std::string_view test_context) { + Botan::PK_KEM_Decryptor decryptor(privkey, rng, "", ""); + const Botan::secure_vector shared_key(32); + + Botan::PK_KEM_Encryptor encryptor(pubkey, "", ""); + Botan::secure_vector ss_rt(32); + Botan::secure_vector ct_rt(encryptor.encapsulated_key_length()); + encryptor.encrypt(ct_rt, ss_rt, rng, 32); + Botan::secure_vector ss_rt_2(32); + decryptor.decrypt(ss_rt_2, ct_rt, 32); + test_result.test_bin_eq(test_context, ss_rt, ss_rt_2); +} +} // namespace + +class MLKEM_Composite_KAT_Tests : public Text_Based_Test { + public: + MLKEM_Composite_KAT_Tests() : Text_Based_Test("pubkey/mlkem_composite.vec", "tcId,ek,x5c,dk,dk_pkcs8,c,k") {} + + Test::Result run_one_test(const std::string& name, const VarMap& vars) override { + bool pubkey_valid = true; + bool privkey_valid = true; + bool exc_during_pubkey_decoding = false; + bool exc_during_privkey_decoding = false; + if(name.ends_with("pubkey-invalid")) { + pubkey_valid = false; + } + if(name.ends_with("privkey-invalid")) { + privkey_valid = false; + } + Test::Result result(name); + auto tcId = vars.get_req_str("tcId"); + if(tcId.starts_with("id-")) { + tcId = tcId.substr(3); + } + + auto rng = Test::new_rng(name); + const auto pk = decode_var_base64(vars, "ek"); + const auto sk = decode_var_base64(vars, "dk"); + + const auto ct_vec = decode_var_base64(vars, "c"); + const auto ss_vec = decode_var_base64(vars, "k"); + + const auto comp_parm_opt = Botan::MLKEM_Composite_Param::from_id_str(tcId); + // support of composite algorithms also depends on whether Botan's build configuration supports the individual traditional component algorithm. + if(!comp_parm_opt.has_value() or !comp_parm_opt.value().is_supported()) { + return result; + } + + auto comp_parm = comp_parm_opt.value(); + + std::unique_ptr pubkey; + std::unique_ptr privkey; + + try { + privkey = std::make_unique(comp_parm.id(), sk); + } catch(const Botan::Exception&) { + exc_during_privkey_decoding = true; + } + result.test_bool_eq("privkey decoding OK", !exc_during_privkey_decoding, privkey_valid); + if(exc_during_privkey_decoding) { + return result; + } + + try { + pubkey = std::make_unique(comp_parm.id(), pk); + } catch(const Botan::Exception&) { + exc_during_pubkey_decoding = true; + } + result.test_bool_eq("pubkey decoding OK", !exc_during_pubkey_decoding, pubkey_valid); + if(exc_during_pubkey_decoding) { + return result; + } + const size_t limit = ((options().run_long_tests() == true) ? 100 : 1); + for(size_t i = 0; i < limit; i++) { + Botan::PK_KEM_Decryptor decryptor(*privkey, *rng, "", ""); + { + Botan::secure_vector shared_key(32); + decryptor.decrypt(shared_key, ct_vec, shared_key.size()); + result.test_bin_eq("decryption of valid KAT ciphertext", shared_key, ss_vec); + + Botan::PK_KEM_Encryptor encryptor(*pubkey, "", ""); + Botan::secure_vector ss_rt(32); + Botan::secure_vector ct_rt(ct_vec.size()); + encryptor.encrypt(ct_rt, ss_rt, *rng, 32); + Botan::secure_vector ss_rt_2(32); + decryptor.decrypt(ss_rt_2, ct_rt, 32); + result.test_bin_eq( + std::string("decryption of valid roundtrip ciphertext (#") + std::to_string(i) + ")", ss_rt, ss_rt_2); + } + + #if defined(BOTAN_HAS_X509_CERTIFICATES) + const std::vector x5c = decode_var_base64(vars, "x5c"); + std::unique_ptr pub_key_from_cert; + if(comp_parm_opt.has_value() and comp_parm_opt.value().is_supported()) { + const Botan::X509_Certificate cert(x5c); + pub_key_from_cert = cert.subject_public_key(); + Botan::PK_KEM_Encryptor encryptor_cert(*pub_key_from_cert, "", ""); + Botan::secure_vector ss_rt_crt(32); + Botan::secure_vector ct_rt_crt(ct_vec.size()); + encryptor_cert.encrypt(ct_rt_crt, ss_rt_crt, *rng, 32); + Botan::secure_vector ss_rt_2_crt(32); + decryptor.decrypt(ss_rt_2_crt, ct_rt_crt, 32); + result.test_bin_eq( + std::string( + "decryption of valid roundtrip ciphertext encrypted with public key from certificate (#") + + std::to_string(i) + ")", + ss_rt_crt, + ss_rt_2_crt); + } + + #endif + } + + return result; + } + + private: +}; + +BOTAN_REGISTER_TEST("pubkey", "mlkem_composite_kat", MLKEM_Composite_KAT_Tests); + +class MLKEM_Composite_RT_Tests : public Test { + public: + static Test::Result run_detail_test(Botan::MLKEM_Composite_Param::id_t id) { + auto param = Botan::MLKEM_Composite_Param::from_id_supported_or_throw(id); + const std::string test_name = std::string("MLKEM_Composite_round_trip_") + param.id_str(); + Test::Result result(test_name); + + auto rng = Test::new_rng(test_name); + if(!param.is_supported()) { + result.test_throws("create MLKEM-composite private key for non-supported parameter", + [&]() { Botan::create_private_key(param.id_str(), *rng); }); + return result; + } + + const uint64_t rep_cnt = options().run_long_tests() ? 20 : 1; + for(uint64_t i = 0; i < rep_cnt; i++) { + auto priv_key_generated = + Botan::create_private_key(Botan::MLKEM_Composite_Param::generic_algo_name, *rng, param.id_str()); + if(nullptr == priv_key_generated) { + result.test_bool_eq("generated private key non-null", false, true); + } else { + auto pub_key_generated = priv_key_generated->public_key(); + if(nullptr == pub_key_generated) { + result.test_bool_eq("generated pub key key non-null", false, true); + } else { + encrypt_and_decrypt( + *priv_key_generated, *pub_key_generated, *rng, result, "produced with generated key"); + } + } + Botan::secure_vector private_enc = priv_key_generated->private_key_bits(); + if(test_name.find("ECDH") != std::string::npos) { + check_encoded_ecdh_private_key(private_enc, result); + } + std::vector public_enc = priv_key_generated->public_key_bits(); + const Botan::MLKEM_Composite_PrivateKey priv_key_redec(priv_key_generated->algorithm_identifier(), + private_enc); + const Botan::MLKEM_Composite_PublicKey pub_key_redec(priv_key_generated->algorithm_identifier(), + public_enc); + encrypt_and_decrypt(priv_key_redec, pub_key_redec, *rng, result, "produced with re-decoded key"); + } + return result; + } + + std::vector run() override { + auto all_params = Botan::MLKEM_Composite_Param::all_supported_param_sets(); + std::vector result; + result.reserve(all_params.size()); + for(const auto& param : all_params) { + result.push_back(run_detail_test(param.id())); + } + return result; + } + + private: + // possibly merge with same routine for MLDSA-composite: + static void check_encoded_ecdh_private_key(std::span composite_private_key, Test::Result& result) { + const size_t mlkem_private_key_size = 64; + Botan::OID key_parameters; + Botan::secure_vector private_key_bits; + const Botan::secure_vector public_key_bits; + if(composite_private_key.size() < 33) { + result.test_failure("encoded ECDH component private key is too short"); + } + const std::vector ecc_private_enc(composite_private_key.begin() + mlkem_private_key_size, + composite_private_key.end()); + try { + Botan::BER_Decoder(ecc_private_enc) + .start_sequence() + .decode_and_check(1, "Unknown version code for ECC key") + .decode(private_key_bits, Botan::ASN1_Type::OctetString) + .decode_optional(key_parameters, Botan::ASN1_Type(0), Botan::ASN1_Class::ExplicitContextSpecific) + .end_cons() + .verify_end(); + } catch(const Botan::Exception& e) { + result.test_failure(std::string("verify ECC private format decoding: ") + e.what()); + } + } +}; + +BOTAN_REGISTER_TEST("pubkey", "mlkem_composite_roundtrips", MLKEM_Composite_RT_Tests); + +class MLKEM_Composite_KAT_Invalid_Tests : public Text_Based_Test { + public: + MLKEM_Composite_KAT_Invalid_Tests() : + Text_Based_Test("pubkey/mlkem_composite.vec", "tcId,ek,x5c,dk,dk_pkcs8,c,k") {} + + Test::Result run_one_test(const std::string& name, const VarMap& vars) override { + const auto pk = decode_var_base64(vars, "ek"); + const auto sk = decode_var_base64(vars, "dk"); + + const auto ct_vec = decode_var_base64(vars, "c"); + const auto ss_vec = decode_var_base64(vars, "k"); + + Test::Result result(name); + auto tcId = vars.get_req_str("tcId"); + if(tcId.starts_with("id-")) { + tcId = tcId.substr(3); + } + + auto rng = Test::new_rng(name); + const auto comp_parm_opt = Botan::MLKEM_Composite_Param::from_id_str(tcId); + // support of composite algorithms also depends on whether Botan's build configuration supports the individual traditional component algorithm. + if(!comp_parm_opt.has_value() or !comp_parm_opt.value().is_supported()) { + return result; + } + + auto comp_parm = comp_parm_opt.value(); + + const std::vector> invalid_private_keys = + some_manipulations(sk, mlkem_comp_artifact_e::Privatekey, comp_parm, options().run_long_tests()); + const std::vector> invalid_public_keys = + some_manipulations(pk, mlkem_comp_artifact_e::Publickey, comp_parm, options().run_long_tests()); + const std::vector> invalid_ciphertexts = + some_manipulations(ct_vec, mlkem_comp_artifact_e::Ciphertext, comp_parm, options().run_long_tests()); + for(const auto& invalid_dk : invalid_private_keys) { + execute_invalid_test(comp_parm, *rng, invalid_dk, pk, ct_vec, ss_vec, false, true, true, result); + } + for(const auto& invalid_ek : invalid_public_keys) { + execute_invalid_test(comp_parm, *rng, sk, invalid_ek, ct_vec, ss_vec, true, false, true, result); + } + for(const auto& invalid_ct : invalid_ciphertexts) { + execute_invalid_test(comp_parm, *rng, sk, pk, invalid_ct, ss_vec, true, true, false, result); + } + return result; + } + + private: + void execute_invalid_test(const Botan::MLKEM_Composite_Param& comp_param, + Botan::RandomNumberGenerator& rng, + std::span private_key, + std::span public_key, + std::span ciphertext, + std::span expected_ss, + bool privkey_valid, + bool pubkey_valid, + bool ciphertext_valid, + Test::Result& result) { + std::unique_ptr pubkey; + std::unique_ptr privkey; + + try { + privkey = std::make_unique(comp_param.id(), private_key); + } catch(const Botan::Exception&) { + // No need to check if the private key was invalid, since this case is covered by the normal (positive) KAT tests + result.test_success("exception during private key decoding"); + return; + } + + try { + pubkey = std::make_unique(comp_param.id(), public_key); + } catch(const Botan::Exception&) { + // No need to check if the public key was invalid, since this case is covered by the normal (positive) KAT tests + result.test_success("exception during public key decoding"); + return; + } + // It can happen that the invalid keys only take effect during the operations. + bool exc_during_decryption = false; + Botan::PK_KEM_Decryptor decryptor(*privkey, rng, "", ""); + Botan::secure_vector shared_key(32); + try { + decryptor.decrypt(shared_key, ciphertext, shared_key.size()); + } catch(const Botan::Exception&) { + exc_during_decryption = true; + } + if(exc_during_decryption or + !std::equal(shared_key.begin(), shared_key.end(), expected_ss.begin(), expected_ss.end())) { + result.test_is_true( + "decryption failure due to exception or implicit rejection during decapsulation as expected for invalid private key or ciphertext", + !privkey_valid or !ciphertext_valid); + return; + } else { + // successful decryption. the manipulated public key was not involved in this test. + result.test_is_true("decryption went OK expectedly for valid private key and valid ciphertext", + privkey_valid and ciphertext_valid); + // we continue in this case to test the encapsulation. + } + + //result.test_bin_eq("decryption of valid KAT ciphertext", shared_key, ss_vec); + + Botan::PK_KEM_Encryptor encryptor(*pubkey, "", ""); + Botan::secure_vector ss_rt(32); + Botan::secure_vector ct_rt(encryptor.encapsulated_key_length()); + try { + encryptor.encrypt(ct_rt, ss_rt, rng, 32); + } catch(Botan::Exception&) { + result.test_is_true("error during encryption for invalid public key", !pubkey_valid); + return; + } + Botan::secure_vector ss_rt_2(32); + try { + decryptor.decrypt(ss_rt_2, ct_rt, 32); + } catch(Botan::Exception&) { + result.test_is_true("error during decryption for invalid public key", !pubkey_valid); + return; + } + result.test_bin_ne("decryption of roundtrip ciphertext for invalid public key", ss_rt, ss_rt_2); + } +}; + +BOTAN_REGISTER_TEST("pubkey", "mlkem_composite_kat_invalid", MLKEM_Composite_KAT_Invalid_Tests); + + #endif +} // namespace Botan_Tests +#endif