Add ML-KEM-768 option for HPKE.
Use the IANA identifier:
https://www.iana.org/assignments/hpke/hpke.xhtml#hpke-kem-ids.
It was originally proposed by
https://datatracker.ietf.org/doc/draft-connolly-cfrg-hpke-mlkem/04/
which is now superceded by
https://datatracker.ietf.org/doc/draft-ietf-hpke-pq/.
Change-Id: Ifa387be8d347f845b398e0d7b68ad8b4649b409a
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/82327
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 321f9db..ecaab3b 100644
--- a/crypto/hpke/hpke.cc
+++ b/crypto/hpke/hpke.cc
@@ -26,10 +26,12 @@
#include <openssl/evp_errors.h>
#include <openssl/hkdf.h>
#include <openssl/mem.h>
+#include <openssl/mlkem.h>
#include <openssl/rand.h>
#include <openssl/sha2.h>
#include <openssl/xwing.h>
+#include "../fipsmodule/bcm_interface.h"
#include "../fipsmodule/ec/internal.h"
#include "../internal.h"
@@ -718,6 +720,125 @@
return &kKEM;
}
+#define MLKEM768_PRIVATE_KEY_LEN MLKEM_SEED_BYTES
+#define MLKEM768_PUBLIC_KEY_LEN MLKEM768_PUBLIC_KEY_BYTES
+#define MLKEM768_PUBLIC_VALUE_LEN MLKEM768_CIPHERTEXT_BYTES
+#define MLKEM768_SEED_LEN BCM_MLKEM_ENCAP_ENTROPY
+#define MLKEM768_SHARED_KEY_LEN MLKEM_SHARED_SECRET_BYTES
+
+static int mlkem768_init_key(EVP_HPKE_KEY *key, const uint8_t *priv_key,
+ size_t priv_key_len) {
+ MLKEM768_private_key expanded_private_key;
+ if (!MLKEM768_private_key_from_seed(&expanded_private_key, priv_key,
+ priv_key_len)) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
+ return 0;
+ }
+ MLKEM768_public_key public_key;
+ MLKEM768_public_from_private(&public_key, &expanded_private_key);
+ CBB cbb;
+ static_assert(sizeof(key->public_key) >= MLKEM768_PUBLIC_KEY_LEN,
+ "EVP_HPKE_KEY public_key is too small for ML-KEM-768.");
+ if (!CBB_init_fixed(&cbb, key->public_key, MLKEM768_PUBLIC_KEY_LEN) ||
+ !MLKEM768_marshal_public_key(&cbb, &public_key)) {
+ return 0;
+ }
+
+ static_assert(sizeof(key->private_key) >= MLKEM768_PRIVATE_KEY_LEN,
+ "EVP_HPKE_KEY private_key is too small for ML-KEM-768");
+ OPENSSL_memcpy(key->private_key, priv_key, priv_key_len);
+ return 1;
+}
+
+static int mlkem768_generate_key(EVP_HPKE_KEY *key) {
+ static_assert(sizeof(key->public_key) >= MLKEM768_PUBLIC_KEY_LEN,
+ "EVP_HPKE_KEY public_key is too small for ML-KEM-768.");
+ static_assert(sizeof(key->private_key) >= MLKEM768_PRIVATE_KEY_LEN,
+ "EVP_HPKE_KEY private_key is too small for ML-KEM-768");
+ MLKEM768_private_key expanded_private_key;
+ MLKEM768_generate_key(key->public_key, key->private_key,
+ &expanded_private_key);
+
+ return 1;
+}
+
+static int mlkem768_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 < MLKEM768_PUBLIC_VALUE_LEN) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_BUFFER_SIZE);
+ return 0;
+ }
+ if (peer_public_key_len != MLKEM768_PUBLIC_KEY_LEN ||
+ seed_len != MLKEM768_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_mlkem768_public_key public_key;
+ if (!bcm_success(BCM_mlkem768_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_mlkem768_encap_external_entropy(out_enc, out_shared_secret, &public_key,
+ seed);
+
+ *out_enc_len = MLKEM768_PUBLIC_VALUE_LEN;
+ *out_shared_secret_len = MLKEM768_SHARED_KEY_LEN;
+ return 1;
+}
+
+static int mlkem768_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 != MLKEM768_PUBLIC_VALUE_LEN) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
+ return 0;
+ }
+
+ MLKEM768_private_key private_key;
+ if (!MLKEM768_private_key_from_seed(&private_key, key->private_key,
+ MLKEM768_PRIVATE_KEY_LEN)) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
+ return 0;
+ }
+
+ if (!MLKEM768_decap(out_shared_secret, enc, enc_len, &private_key)) {
+ OPENSSL_PUT_ERROR(EVP, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ *out_shared_secret_len = MLKEM768_SHARED_KEY_LEN;
+ return 1;
+}
+
+const EVP_HPKE_KEM *EVP_hpke_mlkem768(void) {
+ static const EVP_HPKE_KEM kKEM = {
+ /*id=*/EVP_HPKE_MLKEM768,
+ /*public_key_len=*/MLKEM768_PUBLIC_KEY_LEN,
+ /*private_key_len=*/MLKEM768_PRIVATE_KEY_LEN,
+ /*seed_len=*/MLKEM768_SEED_LEN,
+ /*enc_len=*/MLKEM768_PUBLIC_VALUE_LEN,
+ mlkem768_init_key,
+ mlkem768_generate_key,
+ mlkem768_encap_with_seed,
+ mlkem768_decap,
+ // MLKEM768 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; }
size_t EVP_HPKE_KEM_public_key_len(const EVP_HPKE_KEM *kem) {
diff --git a/crypto/hpke/hpke_test.cc b/crypto/hpke/hpke_test.cc
index 91263d2..e4a276d 100644
--- a/crypto/hpke/hpke_test.cc
+++ b/crypto/hpke/hpke_test.cc
@@ -38,10 +38,8 @@
namespace {
const decltype(&EVP_hpke_x25519_hkdf_sha256) kAllKEMs[] = {
- &EVP_hpke_p256_hkdf_sha256,
- &EVP_hpke_x25519_hkdf_sha256,
- &EVP_hpke_xwing
-};
+ &EVP_hpke_p256_hkdf_sha256, &EVP_hpke_x25519_hkdf_sha256, &EVP_hpke_xwing,
+ &EVP_hpke_mlkem768};
const decltype(&EVP_hpke_aes_128_gcm) kAllAEADs[] = {
&EVP_hpke_aes_128_gcm,
@@ -445,8 +443,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)
- {
+ if (EVP_HPKE_KEM_id(kem()) != EVP_HPKE_XWING &&
+ EVP_HPKE_KEM_id(kem()) != EVP_HPKE_MLKEM768) {
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 6bba28a..5c6b824 100644
--- a/crypto/hpke/hpke_test_vectors.txt
+++ b/crypto/hpke/hpke_test_vectors.txt
@@ -12725,3 +12725,75 @@
exporter_context = 54657374436f6e74657874
L = 32
exported_value = 5fd0d16475885903b6c533a789e2dbe1f8a6088b8424534f9b0922314dd2ae4e
+
+mode = 0
+kem_id = 65
+kdf_id = 1
+aead_id = 1
+info = b254a656608933b934b3f81e8f810214c8135eda92a0614c2b926c4a3075b9f939e6a3c61309f53e
+skRm = 7c9935a0b07694aa0c6d10e4db6b1add2fd81a25ccb148032dcd739936737f2d8626ed79d451140800e03b59b956f8210e556067407d13dc90fa9e8b872bfb8f
+skEm = 147c03f7a5bebba406c8fae1874d7f13c80efe79a3a9a874cc09fe76f6997615
+pkRm = a8e651a1e685f22478a8954f007bc7711b930772c78f092e82878e3e937f367967532913a8d53dfdf4bfb1f8846746596705cf345142b972a3f16325c40c2952a37b25897e5ef35fbaeb73a4acbeb6a0b89942ceb195531cfc0a07993954483e6cbc87c06aa74ff0cac5207e535b260aa98d1198c07da605c4d11020f6c9f7bb68bb3456c73a01b710bc99d17739a51716aa01660c8b628b2f5602ba65f07ea993336e896e83f2c5731bbf03460c5b6c8afecb748ee391e98934a2c57d4d069f50d88b30d6966f38c37bc649b82634ce7722645ccd625063364646d6d699db57b45eb67465e16de4d406a818b9eae1ca916a2594489708a43cea88b02a4c03d09b44815c97101caf5048bbcb247ae2366cdc254ba22129f45b3b0eb399ca91a303402830ec01db7b2ca480cf350409b216094b7b0c3ae33ce10a9124e89651ab901ea253c8415bd7825f02bb229369af972028f22875ea55af16d3bc69f70c2ee8b75f28b47dd391f989ade314729c331fa04c1917b278c3eb602868512821adc825c64577ce1e63b1d9644a612948a3483c7f1b9a258000e30196944a403627609c76c7ea6b5de01764d24379117b9ea29848dc555c454bceae1ba5cc72c74ab96b9c91b910d26b88b25639d4778ae26c7c6151a19c6cd7938454372465e4c5ec29245acb3db5379de3dabfa629a7c04a8353a8530c95acb732bb4bb81932bb2ca7a848cd366801444abe23c83b366a87d6a3cf360924c002bae90af65c48060b3752f2badf1ab2722072554a5059753594e6a702761fc97684c8c4a7540a6b07fbc9de87c974aa8809d928c7f4cbbf8045aea5bc667825fd05a521f1a4bf539210c7113bc37b3e58b0cbfc53c841cbb0371de2e511b989cb7c70c023366d78f9c37ef047f8720be1c759a8d96b93f65a94114ffaf60d9a81795e995c71152a4691a5a602a9e1f3599e37c768c7bc108994c0669f3adc957d46b4b6256968e290d7892ea85464ee7a750f39c5e3152c2dfc56d8b0c924ba8a959a68096547f66423c838982a5794b9e1533771331a9a656c28828beb9126a60e95e8c5d906832c7710705576b1fb9507269ddaf8c95ce9719b2ca8dd112be10bcc9f4a37bd1b1eeeb33ecda76ae9f69a5d4b2923a86957671d619335be1c4c2c77ce87c41f98a8cc466460fa300aaf5b301f0a1d09c88e65da4d8ee64f68c02189bbb3584baff716c85db654048a004333489393a07427cd3e217e6a345f6c2c2b13c27b337271c0b27b2dbaa00d237600b5b594e8cf2dd625ea76cf0ed899122c9796b4b0187004258049a477cd11d68c49b9a0e7b00bce8cac7864cbb375140084744c93062694ca795c4f40e7acc9c5a1884072d8c38dafb501ee4184dd5a819ec24ec1651261f962b17a7215aa4a748c15836c389137678204838d7195a85b4f98a1b574c4cd7909cd1f833effd1485543229d3748d9b5cd6c17b9b3b84aef8bce13e683733659c79542d615782a71cdeee792bab51bdc4bbfe8308e663144ede8491830ad98b4634f64aba8b9c042272653920f380c1a17ca87ced7aac41c82888793181a6f76e197b7b90ef90943bb3844912911d8551e5466c5767ab0bc61a1a3f736162ec098a900b12dd8fabbfb3fe8cb1dc4e8315f2af0d32f0017ae136e19f028
+pkEm = c8391085b8d3ea9794212541b2914f08964d33521d3f67ad66096ebfb1f706424b49558f755b5625bae236f2e0079601c766f7d960808f7e2bb0c7a5e066ed346de628f8c57eebabbb0c22d911548463693ef3ce52a53f7ff415f00e657ae1c5a48fa5ec6e4be5cf462daffc84d2f6d5ff55dc9bbe8bb0d725ec64fd4cd4bd8dba0a844e8b5ce4b6a28934d7f7a050991fe185b506b451dabfad52d52cb2114ca7d9a5cf986c8fdc1bc10ec0c1869e50c03c55a76192a1049aca636ba9020bdaa8d0f58c763b0b89845ca06d4c4ddc21433e16b9c62e44871fdbc05ba218af871fdd7dcfa464e60faa5265264ce1391bd9a8c5faa7626d5f159b9805b975710a3503a0b858a11c6a647cc0e19ac88b1be9056c95b4d2087d0951d1d2f4992491117e6347794ba54571ec49bba71af3413d38a30bf5872248d1f6d07c86baf782e73d2637f043d341a00921857d8b21ddf3e1d6310036ed27af49e5de1b900fe4de79808ff29f9570859612b15adc01fbb265b305b1e3a12ae419da5b74261fa284c101da3d8dca8b2e4521aca571ef44a058e844ff32b16d5aaea05f7f3af8e2ab16222e347662eddfb891d0ecc2a55c5638f9dde92d9a3d544a5f901ac501acd1ea6a010201fcb10ad702c425a94bdf5890d500a2a147eee1d1fcba8c3abe7c2dfe70f346f033d816a0b2791b4f0b2d956d9ee5971715399a5688302495e2e07c1c8c01527184bcd0c208bc159f2e13318c0bb3dd24a6a7fc849f83385ed4dba07fe1d7bd5640cc9ed5ccfdd68763cb0d0edf61b292177fc1d2d3c11dd0495056bcb12558aebcfddef9feb4aebc57afd9023c65cfe65a24e33f1b00111e92e63e011eaf0b212cf95743cd07f5189ece1f205b7f6fcb2e6b1961b5404cebe47c8cd13b8599d5b49e6d87eeda36e9b8fc4c00635896aa2b75896e336d1b612ee13db811e1f07e61748d920f4865f3f11741399dc6162c91ca168a02329dff821d58198712dd558abb099b3a0baf9da1b730b2aa73bcf58d74f357b06f7211c804b6c8af16ff3509fad1d35b14bfdced7db8a6a25c48e5956480724daa057cd660b67ee3e472574182679d485838a6476eac02141075c812af7967ba7c9185cc2abd2a4545b80f3d3104d58d654a57792dcfabbe9c0715e8de2ef81ef404c8168fd7a43efab3d448e686a088efd26a26159948926723d7eccc39e3c1b719cf8becb7be7e964f22cd8cb1b7e25e800ea97d60a64cc0bbd9cb407a3ab9f88f5e29169eeafd4e0322fde6590ae093ce8feeae98b622caa7556ff426c9e7a404ce69355830a7a67767a76c7d9a97b84bfcf50a02f75c235d2f9c671138049ffc7c8055926c03eb3fb87f9695185a42eca9a41655873d30a6b3bf428b246223484a8ff61ee3eeafff10e99c2c13a76284d063e56ab711a35a85b5383df81da23490f66e8ea3fcba067f5530c6541c2b8f74717c35023e7b9b3956c3ee2ff84ba03ccf4b4b5321b9240895481bc6d63c1693c1847852f8e97f50a133532ac3ee1e52d464
+ikmE =
+ikmR =
+# encryptions[0]
+aad = c7a312a03e4b00
+ct = 098a79728a9e35e661db9e25c80ca6dd0443730194d42d6848f09268c864a8d1c6d67bc7d73efc7fece9b312ea2ea0017df500c66968fa882c6e3d4648f0fed32899b40e046c960011861824b6fab3056a
+pt = 86526d8f8d975a50785055b1f6120e6e76e1088730919310d486016a1c62b9a797c5f8842c16260f959c1620d43632975a6c3f309b6891398c8c5a4d31481180de
+# encryptions[1]
+aad = c7a312a03e4b01
+ct = 9b09a60f7aea41de7a8563f2af25b5df03752e2dad1a8c593899722af1e266816c235880cba00777e9e8a4beab5b9f549ee158caf6365aa54ac608bfab597c24cc38338bf7bc6a345bb7267964a17314
+pt = d3106368d37c989c379a046c3b655513d6648795550a2e3794178f83060c5f2b8f88856238128f62363116828987178c120c8f13d33010178c160a0a8f108d0e
+# encryptions[2]
+aad = c7a312a03e4b02
+ct = 758659e23d60717c4245d23a6194058fd1ab0bfadb6cbc47534f01ba4f62f8b9e0661c4ed1637a77df77c4eacad369827f5d76b6a47d239f240d1e1bcafc2f524657121ec364d9c098f4ec438ee90632
+pt = 85b0d0150b069d3110969d95958285818d3635950a31969292830b3511110b809d85959196150a1195159d950a969632119d859d0b830a359d96859591859585
+# enryptions[3]
+aad = c7a312a03e4b03
+ct = 9775aa0ae523d1afc9de7e94b39167ce5ef9ac50fac3f5462a1bd45f07521e97e1522f02cc77ccb4952febe9a8638e47d4a37e92a36c1170d95b6530754581f492061ada3c97b1606b9596a290b699ecab
+pt = 2440620601004163474620064700010100466363012547012541400125410141252541412563462520464601404147012520252540004147402501460141474041
+# encryptions[4]
+aad = c7a312a03e4b04
+ct = 79fa98da734ff4eb12597da08ac7d8890798960fc54e65a984f9ff0cd805be40a76b51c72c5a183f312bee7cda3d993d23e2300aeff67122f77047dfdba736fbc22c3b8316a178d5e460e032ec95e7d657a1
+pt = 9d1a8c889d89161a1215161988891619161215888d1d8816891d161d8c1d1d898d8919191d8d19881d191d191d121d1d8d1d161d19198d1d19191d881d121d1d1d1d
+# encryptions[5]
+aad = c7a312a03e4b05
+ct = e736aa97c2777b419b9775ba8017799fc65a87971b5062a10a194947fd02984d2e50c9c909d1d6f7594ea2ceb6c87a0725b0d5257c6c2ae1a58692501b36289e023fa5e9e317e3170d50524d60c494906b
+pt = 4b3b1875154378783478144b1979484b79154b79154b15157979187915151515147815781515151515151515157815151515151515151515151515151515151515
+# encryptions[6]
+aad = c7a312a03e4b06
+ct = 4cf6aab1758f4b306f1c7349d691c89c9a19bf7ea5f0736cd7626b48537c0eeae873e53d21892ed50a51b24d21f151933c90e4ee3b60505cfa07a714d13c8e07c38ad0f514610dd146d321a8e42da1504c
+pt = a720bd26a427bf20bf20a4a72626bebe202020be20a7bebebea4be20a7202020a7a72020be2020202020202020202020be20202020202020202020202020202020
+# encryptions[7]
+aad = c7a312a03e4b07
+ct = 445001b7d916de50a874cb14d3af1fa63a6c97944a5b9dafeb7e63677d53f56d2636368c7971c9fa04c57eefa0a5275fec5ada112000bc9ee1a433d7937d0e922b9f48d2db1ddf17d572a1f45bfbbd8a8be5
+pt = 52656365697665643a2066726f6d206d61696c65722d6461656d6f6e2e676f6f676c652e636f6d20285b323030313a343836303a343836343a3a383838385d206279
+# encryptions[8]
+aad = c7a312a03e4b08
+ct = 68e45d57346e386767d6902c7b1abdfda6f8092a026f031b154eb326e93dd9124e4fca9234b46e447b1adcdb58aeb79c46a85c234ed06582dd1223dff3bc0aac0e05c5da031bb0a142ca248ef7422cc3abf409
+pt = 206c7832312e696d61702d6578702e676f6f676c652e636f6d20776974682045534d545053412069642079313933736931363737303034346c6a6b2e35323220666f72
+# encryptions[9]
+aad = c7a312a03e4b09
+ct = b6b25aec3e74302f834dbed8be599f446aaee33db38c439875b319958330aa33214b98010fc21996672232d3ea8a5537edd57547ea6edc47aa8c1c40da02efb491d9862e06033a10c0b3b920c255d4a105
+pt = 203c737570706f7274406578616d706c652e636f6d3e3b0d0a095475652c2032332053657020323032352031363a34373a3433202d303430302028454454290d0a
+# exports[0]
+exporter_context = e6b783f915c4d02e19a8b13e30
+L = 32
+exported_value = a6c6493b83c0b91b2f9c4d8566e37b6056e5eecf12a48f77fda8236299ce5024
+# exports[1]
+exporter_context = e6b783f915c4d02e19a8b13e31
+L = 32
+exported_value = 2faede908e025d8d4c842b83cde5051e2dfcd2ee41b320ff951ec6ce3b1ef754
+# exports[2]
+exporter_context = e6b783f915c4d02e19a8b13e32
+L = 32
+exported_value = 4677efc20345ac8197ac0ba21d6c7bf148b8fa79ee310eab6008143e81fce4a4
+# exports[3]
+exporter_context = e6b783f915c4d02e19a8b13e33
+L = 32
+exported_value = b66ec3c6c1cf7bd8ecfc043e4ec9a24b914a40a6a66ac2181420262665d91714
+# exports[4]
+exporter_context = e6b783f915c4d02e19a8b13e34
+L = 32
+exported_value = af7244e36e7efaaee17a130cf2faf8323e5139b44d899a2e91bc33fb09d82a13
diff --git a/include/openssl/hpke.h b/include/openssl/hpke.h
index 7ccc6c6..b4df51e 100644
--- a/include/openssl/hpke.h
+++ b/include/openssl/hpke.h
@@ -43,6 +43,7 @@
#define EVP_HPKE_DHKEM_P256_HKDF_SHA256 0x0010
#define EVP_HPKE_DHKEM_X25519_HKDF_SHA256 0x0020
#define EVP_HPKE_XWING 0x647a
+#define EVP_HPKE_MLKEM768 0x0041
// 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
@@ -50,6 +51,7 @@
OPENSSL_EXPORT const EVP_HPKE_KEM *EVP_hpke_x25519_hkdf_sha256(void);
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);
// EVP_HPKE_KEM_id returns the HPKE KEM identifier for |kem|, which
// will be one of the |EVP_HPKE_KEM_*| constants.
@@ -65,7 +67,7 @@
// EVP_HPKE_MAX_PRIVATE_KEY_LENGTH is the maximum length of an encoded private
// key for all KEMs currently supported by this library.
-#define EVP_HPKE_MAX_PRIVATE_KEY_LENGTH 32
+#define EVP_HPKE_MAX_PRIVATE_KEY_LENGTH 64
// EVP_HPKE_KEM_private_key_len returns the length of a private key for |kem|.
// This value will be at most |EVP_HPKE_MAX_PRIVATE_KEY_LENGTH|.