Add ML-KEM-1024 option for HPKE.

Similar to change-id: Ifa387be8d347f845b398e0d7b68ad8b4649b409a.

Change-Id: Ie1e8c785440d6d5d95c03476553669694fc58615
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/82428
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
diff --git a/crypto/hpke/hpke.cc b/crypto/hpke/hpke.cc
index 0a905af..d49882a 100644
--- a/crypto/hpke/hpke.cc
+++ b/crypto/hpke/hpke.cc
@@ -777,7 +777,6 @@
     return 0;
   }
 
-
   CBS cbs;
   CBS_init(&cbs, peer_public_key, peer_public_key_len);
   BCM_mlkem768_public_key public_key;
@@ -838,6 +837,122 @@
   return &kKEM;
 }
 
+#define MLKEM1024_PRIVATE_KEY_LEN MLKEM_SEED_BYTES
+#define MLKEM1024_PUBLIC_KEY_LEN MLKEM1024_PUBLIC_KEY_BYTES
+#define MLKEM1024_PUBLIC_VALUE_LEN MLKEM1024_CIPHERTEXT_BYTES
+#define MLKEM1024_SEED_LEN BCM_MLKEM_ENCAP_ENTROPY
+#define MLKEM1024_SHARED_KEY_LEN MLKEM_SHARED_SECRET_BYTES
+
+static int mlkem1024_init_key(EVP_HPKE_KEY *key, const uint8_t *priv_key,
+                              size_t priv_key_len) {
+  MLKEM1024_private_key expanded_private_key;
+  if (!MLKEM1024_private_key_from_seed(&expanded_private_key, priv_key,
+                                       priv_key_len)) {
+    OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
+    return 0;
+  }
+  MLKEM1024_public_key public_key;
+  MLKEM1024_public_from_private(&public_key, &expanded_private_key);
+  CBB cbb;
+  static_assert(sizeof(key->public_key) >= MLKEM1024_PUBLIC_KEY_LEN,
+                "EVP_HPKE_KEY public_key is too small for ML-KEM-1024.");
+  if (!CBB_init_fixed(&cbb, key->public_key, MLKEM1024_PUBLIC_KEY_LEN) ||
+      !MLKEM1024_marshal_public_key(&cbb, &public_key)) {
+    return 0;
+  }
+
+  static_assert(sizeof(key->private_key) >= MLKEM1024_PRIVATE_KEY_LEN,
+                "EVP_HPKE_KEY private_key is too small for ML-KEM-1024");
+  OPENSSL_memcpy(key->private_key, priv_key, priv_key_len);
+  return 1;
+}
+
+static int mlkem1024_generate_key(EVP_HPKE_KEY *key) {
+  static_assert(sizeof(key->public_key) >= MLKEM1024_PUBLIC_KEY_LEN,
+                "EVP_HPKE_KEY public_key is too small for ML-KEM-1024.");
+  static_assert(sizeof(key->private_key) >= MLKEM1024_PRIVATE_KEY_LEN,
+                "EVP_HPKE_KEY private_key is too small for ML-KEM-1024");
+  MLKEM1024_private_key expanded_private_key;
+  MLKEM1024_generate_key(key->public_key, key->private_key,
+                         &expanded_private_key);
+
+  return 1;
+}
+
+static int mlkem1024_encap_with_seed(
+    const EVP_HPKE_KEM *kem, uint8_t *out_shared_secret,
+    size_t *out_shared_secret_len, uint8_t *out_enc, size_t *out_enc_len,
+    size_t max_enc, const uint8_t *peer_public_key, size_t peer_public_key_len,
+    const uint8_t *seed, size_t seed_len) {
+  if (max_enc < MLKEM1024_PUBLIC_VALUE_LEN) {
+    OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_BUFFER_SIZE);
+    return 0;
+  }
+  if (peer_public_key_len != MLKEM1024_PUBLIC_KEY_LEN ||
+      seed_len != MLKEM1024_SEED_LEN) {
+    OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
+    return 0;
+  }
+
+  CBS cbs;
+  CBS_init(&cbs, peer_public_key, peer_public_key_len);
+  BCM_mlkem1024_public_key public_key;
+  if (!bcm_success(BCM_mlkem1024_parse_public_key(&public_key, &cbs))) {
+    OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
+    return 0;
+  }
+  // The public ML-KEM interface doesn't support providing the encap entropy so
+  // the BCM function is used here.
+  BCM_mlkem1024_encap_external_entropy(out_enc, out_shared_secret, &public_key,
+                                       seed);
+
+  *out_enc_len = MLKEM1024_PUBLIC_VALUE_LEN;
+  *out_shared_secret_len = MLKEM1024_SHARED_KEY_LEN;
+  return 1;
+}
+
+static int mlkem1024_decap(const EVP_HPKE_KEY *key, uint8_t *out_shared_secret,
+                           size_t *out_shared_secret_len, const uint8_t *enc,
+                           size_t enc_len) {
+  if (enc_len != MLKEM1024_PUBLIC_VALUE_LEN) {
+    OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
+    return 0;
+  }
+
+  MLKEM1024_private_key private_key;
+  if (!MLKEM1024_private_key_from_seed(&private_key, key->private_key,
+                                       MLKEM1024_PRIVATE_KEY_LEN)) {
+    OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
+    return 0;
+  }
+
+  if (!MLKEM1024_decap(out_shared_secret, enc, enc_len, &private_key)) {
+    OPENSSL_PUT_ERROR(EVP, ERR_R_INTERNAL_ERROR);
+    return 0;
+  }
+
+  *out_shared_secret_len = MLKEM1024_SHARED_KEY_LEN;
+  return 1;
+}
+
+const EVP_HPKE_KEM *EVP_hpke_mlkem1024(void) {
+  static const EVP_HPKE_KEM kKEM = {
+      /*id=*/EVP_HPKE_MLKEM1024,
+      /*public_key_len=*/MLKEM1024_PUBLIC_KEY_LEN,
+      /*private_key_len=*/MLKEM1024_PRIVATE_KEY_LEN,
+      /*seed_len=*/MLKEM1024_SEED_LEN,
+      /*enc_len=*/MLKEM1024_PUBLIC_VALUE_LEN,
+      mlkem1024_init_key,
+      mlkem1024_generate_key,
+      mlkem1024_encap_with_seed,
+      mlkem1024_decap,
+      // MLKEM1024 doesn't support authenticated encapsulation/decapsulation:
+      // https://datatracker.ietf.org/doc/draft-ietf-hpke-pq/01/
+      /* auth_encap_with_seed= */ nullptr,
+      /* auth_decap= */ nullptr,
+  };
+  return &kKEM;
+}
 
 uint16_t EVP_HPKE_KEM_id(const EVP_HPKE_KEM *kem) { return kem->id; }
 
diff --git a/crypto/hpke/hpke_test.cc b/crypto/hpke/hpke_test.cc
index e4a276d..3e445be 100644
--- a/crypto/hpke/hpke_test.cc
+++ b/crypto/hpke/hpke_test.cc
@@ -39,7 +39,7 @@
 
 const decltype(&EVP_hpke_x25519_hkdf_sha256) kAllKEMs[] = {
     &EVP_hpke_p256_hkdf_sha256, &EVP_hpke_x25519_hkdf_sha256, &EVP_hpke_xwing,
-    &EVP_hpke_mlkem768};
+    &EVP_hpke_mlkem768, &EVP_hpke_mlkem1024};
 
 const decltype(&EVP_hpke_aes_128_gcm) kAllAEADs[] = {
     &EVP_hpke_aes_128_gcm,
@@ -444,7 +444,8 @@
             // Test the auth mode.
             // We skip X-Wing here since it does not support auth mode.
             if (EVP_HPKE_KEM_id(kem()) != EVP_HPKE_XWING &&
-                EVP_HPKE_KEM_id(kem()) != EVP_HPKE_MLKEM768) {
+                EVP_HPKE_KEM_id(kem()) != EVP_HPKE_MLKEM768 &&
+                EVP_HPKE_KEM_id(kem()) != EVP_HPKE_MLKEM1024) {
               ScopedEVP_HPKE_CTX sender_ctx;
               uint8_t enc[EVP_HPKE_MAX_PUBLIC_KEY_LENGTH];
               size_t enc_len;
diff --git a/crypto/hpke/hpke_test_vectors.txt b/crypto/hpke/hpke_test_vectors.txt
index 5c6b824..63d6a58 100644
--- a/crypto/hpke/hpke_test_vectors.txt
+++ b/crypto/hpke/hpke_test_vectors.txt
@@ -12797,3 +12797,75 @@
 exporter_context = e6b783f915c4d02e19a8b13e34
 L = 32
 exported_value = af7244e36e7efaaee17a130cf2faf8323e5139b44d899a2e91bc33fb09d82a13
+
+mode = 0
+kem_id = 66
+kdf_id = 1
+aead_id = 2
+info = b9e8c67f3a2d1e0c4b59f7d6a5c3b2e18d9f0a786e5c4d3b2a1f0987e6d5c4b3
+skRm = 7c9935a0b07694aa0c6d10e4db6b1add2fd81a25ccb148032dcd739936737f2d8626ed79d451140800e03b59b956f8210e556067407d13dc90fa9e8b872bfb8f
+skEm = 147c03f7a5bebba406c8fae1874d7f13c80efe79a3a9a874cc09fe76f6997615
+pkRm = 537911957c125148a87f41589cb222d0d19229e2cb55e1a044791e7ca61192a46460c3183d2bcd6de08a5e7651603acc349ca16cba18abb23a3e8c330d7421598a6278ec7ebfabca0ef488b2290554753499c0452e453815309955b8150fa1a1e393386dc12fdb27b38c6745f2944016ec457f39b18d604a07a1abe07bc844050ffa8a06fa154a49d88fac775452d6a7c0e589bfb5c370c2c4b6201dda80c9ab2076ecc08b44522fda3326f033806dd2693f319739f40c4f42b24aca7098fb8ff5f9ac20292d02b56ac746801acccc84863dee32878497b69438bf991776286650482c8d9d9587bc6a55b85c4d7fa74d02656b421c9e23e03a48d4b74425c26e4a20dd9562a4da0793f3a352ccc0f18217d868c7f5002abe768b1fc73f05744e7cc28f10344062c10e08eccced3c1f7d392c01d979dd718d8398374665a16a9870585c39d5589a50e133389c9b9a276c024260d9fc7711c81b6337b57da3c376d0cd74e14c73727b276656b9d8a4eb71896ff589d4b893e7110f3bb948ece291dd86c0b7468a678c746980c12aa6b95e2b0cbe4331bb24a33a270153aa472c47312382ca365c5f35259d025746fc6595fe636c767510a69c1e8a176b7949958f2697399497a2fc7364a12c8198295239c826cb5082086077282ed628651fc04c639b438522a9de309b14b086d6e923c551623bd72a733cb0dabc54a9416a99e72c9fda1cb3fb9ba06b8adb2422d68cadc553c98202a17656478ac044ef3456378abce9991e0141ba79094fa8f77a300805d2d32ffc62bf0ca4554c330c2bb7042db35102f68b1a0062583865381c74dd913af70b26cf0923d0c4cb971692222552a8f4b788b4afd1341a9df415cf203900f5ccf7f65988949a75580d049639853100854b21f4018003502bb1ba95f556a5d67c7eb52410eba288a6d0635ca8a4f6d696d0a020c826938d34943c3808c79cc007768533216bc1b29da6c812eff3340baa8d2e65344f09bd47894f5a3a4118715b3c5020679327f9189f7e10856b238bb9b0ab4ca85abf4b21f5c76bccd71850b22e045928276a0f2e951db0707c6a116dc19113fa762dc5f20bd5d2ab5be71744dc9cbdb51ea757963aac56a90a0d8023bed1f5cae8a64da047279b353a096a835b0b2b023b6aa048989233079aeb467e522fa27a5822921e5c551b4f537536e46f3a6a97e72c3b063104e09a040598940d872f6d871f5ef9b4355073b54769e45454e6a0819599408621ab4413b35507b0df578ce2d511d52058d5749df38b29d6cc58870caf92f69a75161406e71c5ff92451a77522b8b2967a2d58a49a81661aa65ac09b08c9fe45abc3851f99c730c45003aca2bf0f8424a19b7408a537d541c16f5682bfe3a7faea564f1298611a7f5f60922ba19de73b1917f1853273555199a649318b50773345c997460856972acb43fc81ab6321b1c33c2bb5098bd489d696a0f70679c1213873d08bdad42844927216047205633212310ee9a06cb10016c805503c341a36d87e56072eabe23731e34af7e2328f85cdb370ccaf00515b64c9c54bc837578447aacfaed5969aa351e7da4efa7b115c4c51f4a699779850295ca72d781ad41bc680532b89e710e2189eb3c50817ba255c7474c95ca9110cc43b8ba8e682c7fb7b0fdc265c0483a65ca4514ee4b832aac5800c3b08e74f563951c1fbb210353efa1aa866856bc1e034733b0485dab1d020c6bf765ff60b3b801984a90c2fe970bf1de97004a6cf44b4984ab58258b4af71221cd17530a700c32959c9436344b5316f09ccca7029a230d639dcb022d8ba79ba91cd6ab12ae1579c50c7bb10e30301a65cae3101d40c7ba927bb553148d1647024d4a06c8166d0b0b81269b7d5f4b34fb022f69152f514004a7c685368552343bb60360fbb9945edf446d345bdcaa7455c74ba0a551e184620fef97688773d50b6433ca7a7ac5cb6b7f671a15376e5a6747a623fa7bc6630373f5b1b512690a661377870a60a7a189683f9b0cf0466e1f750762631c4ab09f505c42dd28633569472735442851e321616d4009810777b6bd46fa7224461a5cc27405dfbac0d39b002cab33433f2a86eb8ce91c134a6386f860a1994eb4b6875a46d195581d173854b53d2293df3e9a822756cd8f212b325ca29b4f9f8cfbadf2e41869abfbad10738ad04cc752bc20c394746850e0c4847db
+pkEm = c9bead6b0c1114389bd4761c73ab9095b5809daac9f659bb564af226173052a4a3e7f2e5fd47d2b02aaeb5189e06b9f4ae98b619cb63efbdf3989a94b36e8ea0d700633b950a0ae2a78ed92e85c85c70e13e626fb263fac9681521c3ab22fdab29173c9616a2b037083ff7b2e019b5bcde068fac257ef8f12798411693c1bdcc65420997a513a8a69502620be8e4ce7362e412a76cf51c1f2433f1ab64ce0e5d2f56d7c9ade994d0e35d0aeef3ac515b482437664d8c1d25e5a5507cf80f970d3ea7226aacdc457cbf88a0560aa35bb2c5c455867e2159910a35810befe3aa10eb04d8d57147cb8f66d2b070bac43d1f1ffdd57a9399951f64965727bcb9f66ad42309dafc799c1c540af1af93eff68a86d61f5115db662dee7ac9a362677762b6a164a0fa0a4d859e4b8c8dbdb4e183f5e6808fc52229650caf7cf3e16de3d895d148c35448ab8c2753c9831b24bd4921497eaa192565cabfd83c0c68dfe7d392abf5e5e6f84bb9f5af4b7118c0b558105f9c10c9b6d70682e1de6e0689d7106a6374bd34aed7229e6cb356f2ea65e680ce7b1e2c3704e116a38542826e8a001141baf2e34de37a03040986d4c0cd5d57f0701ce930986fd9525b58e2e59f45b8dd04c0f35b0f47970cc67079618eb9e6d91e9b0f8c6d2e165cf448a2c1ebf71b6537e0f375185dfafef698b6239bb35580b315bcb5ed408c357f192def89bc1b75cdd6aae8b5faf0c3e13803f6bdfa76fb407fcbda790c329b3ee42fd3d3b03bd5003f0bc432f7ba39631112452dfd12140433ff8980eb6a526ba85ef99477378b4dc76635a5cd5040e43b8c1fe4ee5e158e423bfc0c893c1d5613bed08da719c9073184eeb36fd357380fb1873d8cbd36e2255e985b1b76819743a6584a9b3a580996c9c2eed9bbbfff78a6204b5e5eeae5f4efd2660078b37f0754ab5da862e666b145b5f23f3d0977799929dfa2aedda53d152eda1d0d0e4ea43f6ed889bb965eefe0a7c685bb36770eaa874242c0e229cf6ce56defa5aeae64d0c40dda8aa26eaeb31458f070a3bc72e1619ee9b5f642291c56df5b7e43db6c802fc74f4f3f9b5c0d355c3aae520aa31229d12f3e7cc5d48e691191a36b283765f4133f0ff1fe2f01c6648b2798a74eb5d842a248f524a7e7f8974211297b44f0dd19f386e86be6ba782de77fde887226f37a1c77bc5eddeee5bf46b67fb7478d559865f262caa84d64a8ce59e4df0818e14861526acd3483600f3dae7959d35d8181ca6a81ce791be00752da7759446a2cfbe00b8248b93491debd520220b755416d2fc6b7c8af2ff75e5bcbb8e7537380a5721c77484957a69271d8bafce0f166735ff869232de5d381afbf0e44d69172b79a35191949de09703b94222b13c385c6081e6d2ede1e57fe184ef8f60196b9a3a7b7eff7497191ca8741b5a01e79cb69a61142e6f5d080fbb3e566f79e146f75c8a1097860841b4747df604dba954e4a8d9e0dccc1f609d05cf8d31219ecd60c312de684552f09227cb829291c645732c5f5d4d711639f42a23080aa34fe1420f219bd6bcf4e3b29b9d02293b2da81383e0a51d2bb186c7b0a211a0cd63acbfc0210401e985d436b3803d5601c24136afd1562522e45b457cb439178be4a87cce40346d34ae0f3c39103c8a3ebc9c86c8db8fc5561eb0f3a143d4e9fe93a5cba6f6fcae5650d3f43d2668a5956c922893b816647ded0afc052a6c3d9d01a3d3af0f1ba807ff10491e131dc15e165cfd0650a1f2c313d7956141edcc61cb90e9e7abf2fe35fc9dc1bde88939fa11f7bbe3eb4d8ffa643b074d74f45113586e9bb12060003d71941f2da098dc0e96cad3255cf328ea2d3308c1f4585e89c613c426b7e798e1ec4e98fe6c71e7491f5eca0cd05115861bd160e3fe73a58a026ba538e0e256b92f1d7a2497570594856860ffd06b601ac575592f4ac612b5de7866042123ebc60c55768e3a7600a3260551f2bea22bbf6b6c8246e80f9125c4bb9db354dd64ae695c15f5071f4abb9639207cac7331b310f69a05f54b995de529a023f033b055db95287a14ba30a7cc526bb724c417fba290636a996f286e3e9e939e4fe1c398b5c6599959d0b4445a327ec469a1653cfaea7552cecec085ccaa68938ae4ac3c424f7e480439ebd2c992b5f6f95ec244b657dbdeaa9ae110aaf4d68bf4e27410d43ceef3e88e9c717dd44c9ee
+ikmE =
+ikmR =
+# encryptions[0]
+aad = d35b1f8a9e4c20
+ct = ac74bab5b38ff861ae142eadd79fae5413fcabade436df3b12556feb766c3e14c45bdefddb0914dc2f7f243e5bcf4665dea93cc6c5d808e6a582465cc0a4b06d06217093b2b13896bc9cf2f8
+pt = c8a4153f9b7e2d06c5478f1a3e6d9c0b25748f3e9a6c1b4d8e7f5a2b0d9e8c1f7a4b6d3e9f2a7c5b8e1d4f0a3c7b8e2d5f1a4c9b8d2e6f3a7c1b5d9e
+# encryptions[1]
+aad = d35b1f8a9e4c21
+ct = db5b7152974d5804ff685329d17c5fe3d89adcda9eef4da168f2e7a24560cd6a78e91e06bf67f13c79d0f3a7c9a2ee152f6929e30c1c7783d331ddcaec572e34b628adf4ed91d5
+pt = 5f9b1d8e4a7c2b0d3f6a9c8b5e2d1f0a7c4b9d3e6f2a8c5b1d9e4f0a7c3b8d6e2f1a5c9b8d4e7f2a6c1b0d5e3f9a7c2b8d1e4f5a9c8b7d
+# encryptions[2]
+aad = d35b1f8a9e4c22
+ct = ed90b68ce56055d58767f3f4165ca88ca8458c98dc5788ffae0065b78bf31b551779dc16af5eedb74905a6c890f7e46d5043da005f3205550b54e0b75c93d10d04c582d4f1f2cf
+pt = 81b9d4c7f0e3a6b2d5c8f1e4a7b0d3c6f9e2a5b8d1c4f7e0a3b6d9c2f5e8a1b4d7c0f3e6a9b2d5c8f1e4a7b0d3c6f9e2a5b8d1c4f7e0a3
+# enryptions[3]
+aad = d35b1f8a9e4c23
+ct = f63c3ba03f5cb7db8d61b2a42615e0f6a2ce640dce4f7b7ec46da70aedab7722601ce86c333c7c2f272488fe7d4d3dca9c0e86e9de64c29fc8d2c2053762adc3f6217f4ac31682d5
+pt = 0d3b6a9c2f5e81b4d7c0f3e6a9b2d5c8f1e4a7b0d3c6f9e2a5b8d1c4f7e0a3b6d9c2f5e8a1b4d7c0f3e6a9b2d5c8f1e4a7b0d3c6f9e2a5b8
+# encryptions[4]
+aad = d35b1f8a9e4c24
+ct = 67dcd57f4212413a3601ec016b8eaa804fac3964203b9a244be01d4d6eef58d4b5ef417ca7a2d6cb33838a906e28e5c14524949dd2f5befcdff42b91f23aa28da7a29c0c8cece40c
+pt = e6b2a5d8f1c4e7b0a3d6c9f2e5b8d1c4f7e0a3b6d9c2f5e8a1b4d7c0f3e6a9b2d5c8f1e4a7b0d3c6f9e2a5b8d1c4f7e0a3b6d9c2f5e8a1b4
+# encryptions[5]
+aad = d35b1f8a9e4c25
+ct = 80f28407f0342ce0de83c21eb7cd1a12945cbd3b6a15b91fb95835eba9b005cd5cb57efefcd9db8ab91c629b1a220da518a4c739b626059b9db5d2f4d890a5039516e461136389
+pt = 4b8d1f6a9c3e7b0d2f5a8c1e4b7d0f3a6c9b2d5e8f1a4c7b0d3e6f9a2c5b8d1e4f7a0c3b6d9e2f5a8c1b4d7e0f3a6c9b2d5e8f1a4c7b0d
+# encryptions[6]
+aad = d35b1f8a9e4c26
+ct = cfd593aa0197ec081e3e0f6195a64f568aca3d574ea8f837e781fa5f2ffc7673240a22a38ee411d40f1e29a15f487f8f4818b8bcab34e371d013377c833dced0d4f3117238b6b151df43
+pt = e9c3b7a5d1f862409e5c1b8f6d2a7043b9e5c1b8f6d2a7043b9e5c1b8f6d2a7043b9e5c1b8f6d2a7043b9e5c1b8f6d2a7043b9e5c1b8f6d2a704
+# encryptions[7]
+aad = d35b1f8a9e4c27
+ct = 8cabc8bdfdbd7893389031c20198ce3052255bca74eade6b35d389c96bb673e16992179ba24843f760a6fb6e6b2ee41dc94e81bdaf59d9eff4a4369aaea54d04813b6383aa7f06b4da35
+pt = 1a4f7c3e9b6d28051a4f7c3e9b6d28051a4f7c3e9b6d28051a4f7c3e9b6d28051a4f7c3e9b6d28051a4f7c3e9b6d28051a4f7c3e9b6d28051a4f
+# encryptions[8]
+aad = d35b1f8a9e4c28
+ct = 0e6ccff281919cb3829fd50b191b17a3cdbac92d7ade5f13a806e8bfd8f49039b63aeff0bc4c937161def4eef7ebbd8095fdcdd18a51f84f24d2a9d3d41a138c94f63efb77e9bb33d50f8a
+pt = 75ba9e3c1f86d20475ba9e3c1f86d20475ba9e3c1f86d20475ba9e3c1f86d20475ba9e3c1f86d20475ba9e3c1f86d20475ba9e3c1f86d20475ba9e
+# encryptions[9]
+aad = d35b1f8a9e4c29
+ct = f9ad0a0c88df46b72737b2e238a5b69b7b2e1e16e1a706dc0470a5b98d3964df8d8e7de74f857643c3ec3bdf90cf640820b736a97caa5a5d462bde1b3459d9215c7a8f7f949764c6bdf7f5
+pt = f0d6b29874503e1cf0d6b29874503e1cf0d6b29874503e1cf0d6b29874503e1cf0d6b29874503e1cf0d6b29874503e1cf0d6b29874503e1cf0d6b2
+# exports[0]
+exporter_context = b8f4e2d7c06399b8a4fde25c20
+L = 32
+exported_value = e166fafd5983c1195a476ce1c78a731e5f958ac07d256a74fe4f75c729b8fb43
+# exports[1]
+exporter_context = b8f4e2d7c06399b8a4fde25c21
+L = 32
+exported_value = 00df22113c678fddebe28ab48c5a769b2dfa0ecf8ae67c1cae1223c016995e3b
+# exports[2]
+exporter_context = b8f4e2d7c06399b8a4fde25c22
+L = 32
+exported_value = 2f9183c7b2cedd7fe17c54b3209c44ac4424d821b049fdca1c27027abc1e9f62
+# exports[3]
+exporter_context = b8f4e2d7c06399b8a4fde25c23
+L = 32
+exported_value = b32997f20747bf25eb77bbd460c7054bf8ceff4d06e7dbf233c412286840aaa7
+# exports[4]
+exporter_context = b8f4e2d7c06399b8a4fde25c24
+L = 32
+exported_value = 604d5a795f46f657743c8eae7ad87301a8f8f829647ae38825d93cf723bac8b6
diff --git a/include/openssl/hpke.h b/include/openssl/hpke.h
index b4df51e..5336211 100644
--- a/include/openssl/hpke.h
+++ b/include/openssl/hpke.h
@@ -44,6 +44,7 @@
 #define EVP_HPKE_DHKEM_X25519_HKDF_SHA256 0x0020
 #define EVP_HPKE_XWING 0x647a
 #define EVP_HPKE_MLKEM768 0x0041
+#define EVP_HPKE_MLKEM1024 0x0042
 
 // The following functions are KEM algorithms which may be used with HPKE. Note
 // that, while some HPKE KEMs use KDFs internally, this is separate from the
@@ -52,6 +53,7 @@
 OPENSSL_EXPORT const EVP_HPKE_KEM *EVP_hpke_p256_hkdf_sha256(void);
 OPENSSL_EXPORT const EVP_HPKE_KEM *EVP_hpke_xwing(void);
 OPENSSL_EXPORT const EVP_HPKE_KEM *EVP_hpke_mlkem768(void);
+OPENSSL_EXPORT const EVP_HPKE_KEM *EVP_hpke_mlkem1024(void);
 
 // EVP_HPKE_KEM_id returns the HPKE KEM identifier for |kem|, which
 // will be one of the |EVP_HPKE_KEM_*| constants.
@@ -59,7 +61,7 @@
 
 // EVP_HPKE_MAX_PUBLIC_KEY_LENGTH is the maximum length of an encoded public key
 // for all KEMs currently supported by this library.
-#define EVP_HPKE_MAX_PUBLIC_KEY_LENGTH 1216
+#define EVP_HPKE_MAX_PUBLIC_KEY_LENGTH 1568
 
 // EVP_HPKE_KEM_public_key_len returns the length of a public key for |kem|.
 // This value will be at most |EVP_HPKE_MAX_PUBLIC_KEY_LENGTH|.
@@ -75,7 +77,7 @@
 
 // EVP_HPKE_MAX_ENC_LENGTH is the maximum length of "enc", the encapsulated
 // shared secret, for all KEMs currently supported by this library.
-#define EVP_HPKE_MAX_ENC_LENGTH 1120
+#define EVP_HPKE_MAX_ENC_LENGTH 1568
 
 // EVP_HPKE_KEM_enc_len returns the length of the "enc", the encapsulated shared
 // secret, for |kem|. This value will be at most |EVP_HPKE_MAX_ENC_LENGTH|.