From 62fb89a46a9ca83b77441d78a7206e9d0cfaffa6 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Thu, 9 Jul 2026 17:03:32 -0400 Subject: [PATCH 1/5] Upgrade to HPKE v0.14 --- Cargo.toml | 20 ++++++++++---------- src/base_mode_seal.rs | 3 +-- src/keypair.rs | 2 +- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8bbddb38449..f9196b89303 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,24 +16,24 @@ serde = ["serde_crate"] algo-all = ["aead-all", "kdf-all", "kem-all"] default = ["algo-all", "base-mode-seal", "base-mode-open"] aead-all = ["aead-aes-gcm-128", "aead-aes-gcm-256", "aead-chacha-20-poly-1305"] -aead-aes-gcm-128 = [] -aead-aes-gcm-256 = [] -aead-chacha-20-poly-1305 = [] +aead-aes-gcm-128 = ["hpke/aes"] +aead-aes-gcm-256 = ["hpke/aes"] +aead-chacha-20-poly-1305 = ["hpke/chacha"] kdf-all = ["kdf-sha256", "kdf-sha384", "kdf-sha512"] -kdf-sha256 = [] -kdf-sha384 = [] -kdf-sha512 = [] +kdf-sha256 = ["hpke/hkdfsha2"] +kdf-sha384 = ["hpke/hkdfsha2"] +kdf-sha512 = ["hpke/hkdfsha2"] kem-all = ["kem-dh-p256-hkdf-sha256", "kem-dh-p384-hkdf-sha384", "kem-dh-p521-hkdf-sha512", "kem-x25519-hkdf-sha256"] -kem-dh-p256-hkdf-sha256 = ["hpke/p256"] -kem-dh-p384-hkdf-sha384 = ["hpke/p384"] -kem-dh-p521-hkdf-sha512 = ["hpke/p521"] +kem-dh-p256-hkdf-sha256 = ["hpke/nistp"] +kem-dh-p384-hkdf-sha384 = ["hpke/nistp"] +kem-dh-p521-hkdf-sha512 = ["hpke/nistp"] kem-x25519-hkdf-sha256 = ["hpke/x25519"] [dependencies] rand = "0.9.2" num_enum = "0.7.0" cfg-if = "1.0.0" -hpke = { version = "0.13.0", default-features = false, features = ["std"] } +hpke = "0.14" zeroize = "1.6" [dependencies.serde_crate] diff --git a/src/base_mode_seal.rs b/src/base_mode_seal.rs index 8917e927728..796f61ff910 100644 --- a/src/base_mode_seal.rs +++ b/src/base_mode_seal.rs @@ -42,13 +42,12 @@ where KdfT: hpke::kdf::Kdf, KemT: hpke::kem::Kem, { - let (encapped_key, ciphertext) = hpke::single_shot_seal::( + let (encapped_key, ciphertext) = hpke::single_shot_seal::( &hpke::OpModeS::Base, &from_bytes(recipient_public_key)?, info, plaintext, aad, - &mut rand::rng(), )?; Ok(EncappedKeyAndCiphertext { diff --git a/src/keypair.rs b/src/keypair.rs index 962348b9b1a..09c339a7e70 100644 --- a/src/keypair.rs +++ b/src/keypair.rs @@ -46,7 +46,7 @@ pub fn gen_keypair(kem: Kem) -> Keypair { } fn gen_kp() -> Keypair { - let (private_key, public_key) = KemT::gen_keypair(&mut rand::rng()); + let (private_key, public_key) = KemT::gen_keypair(); let public_key = public_key.to_bytes().to_vec(); let private_key = private_key.to_bytes().to_vec(); From a44475f3f70f421d0ddeac061b752e0c530e9ed5 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Fri, 10 Jul 2026 22:34:02 -0400 Subject: [PATCH 2/5] Migrate feature flags to mirror hpke feature flags --- Cargo.toml | 25 +++++++++++-------------- src/aead.rs | 18 +++++++++--------- src/kdf.rs | 18 +++++++++--------- src/kem.rs | 24 ++++++++++++------------ src/keypair.rs | 8 ++++---- src/lib.rs | 15 +++------------ src/macros.rs | 20 ++++++++++---------- 7 files changed, 58 insertions(+), 70 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f9196b89303..9562bfb823f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,25 +15,22 @@ base-mode-seal = [] serde = ["serde_crate"] algo-all = ["aead-all", "kdf-all", "kem-all"] default = ["algo-all", "base-mode-seal", "base-mode-open"] -aead-all = ["aead-aes-gcm-128", "aead-aes-gcm-256", "aead-chacha-20-poly-1305"] -aead-aes-gcm-128 = ["hpke/aes"] -aead-aes-gcm-256 = ["hpke/aes"] -aead-chacha-20-poly-1305 = ["hpke/chacha"] -kdf-all = ["kdf-sha256", "kdf-sha384", "kdf-sha512"] -kdf-sha256 = ["hpke/hkdfsha2"] -kdf-sha384 = ["hpke/hkdfsha2"] -kdf-sha512 = ["hpke/hkdfsha2"] -kem-all = ["kem-dh-p256-hkdf-sha256", "kem-dh-p384-hkdf-sha384", "kem-dh-p521-hkdf-sha512", "kem-x25519-hkdf-sha256"] -kem-dh-p256-hkdf-sha256 = ["hpke/nistp"] -kem-dh-p384-hkdf-sha384 = ["hpke/nistp"] -kem-dh-p521-hkdf-sha512 = ["hpke/nistp"] -kem-x25519-hkdf-sha256 = ["hpke/x25519"] +aead-all = ["aead-aes", "aead-chacha"] +aead-aes = ["hpke/aes"] +aead-chacha = ["hpke/chacha"] +kdf-all = ["kdf-hkdfsha2", "kdf-shake"] +kdf-hkdfsha2 = ["hpke/hkdfsha2"] +kdf-shake = ["hpke/shake"] +kem-all = ["kem-x25519", "kem-nistp", "kem-mlkem"] +kem-x25519 = ["hpke/x25519"] +kem-nistp = ["hpke/nistp"] +kem-mlkem = ["hpke/mlkem"] [dependencies] rand = "0.9.2" num_enum = "0.7.0" cfg-if = "1.0.0" -hpke = "0.14" +hpke = { version = "0.14", default-features = false, features = ["getrandom", "alloc"] } zeroize = "1.6" [dependencies.serde_crate] diff --git a/src/aead.rs b/src/aead.rs index 97e45ffb3ae..1379f6ca039 100644 --- a/src/aead.rs +++ b/src/aead.rs @@ -15,13 +15,13 @@ encryption function, as per [RFC9180§7.3](https://www.rfc-editor.org/rfc/rfc918 )] #[cfg_attr(feature = "serde", serde(crate = "serde_crate"))] pub enum Aead { - #[cfg(feature = "aead-aes-gcm-128")] + #[cfg(feature = "aead-aes")] /// AES-128-GCM [GCM](https://doi.org/10.6028/nist.sp.800-38d) AesGcm128 = 1, - #[cfg(feature = "aead-aes-gcm-256")] + #[cfg(feature = "aead-aes")] /// AES-256-GCM [GCM](https://doi.org/10.6028/nist.sp.800-38d) AesGcm256 = 2, - #[cfg(feature = "aead-chacha-20-poly-1305")] + #[cfg(feature = "aead-chacha")] /// ChaCha20Poly1305 [RFC8439](https://www.rfc-editor.org/info/rfc8439) ChaCha20Poly1305 = 3, } @@ -31,11 +31,11 @@ impl FromStr for Aead { fn from_str(s: &str) -> Result { match &*s.to_lowercase().replace('-', "") { - #[cfg(feature = "aead-aes-gcm-128")] + #[cfg(feature = "aead-aes")] "aesgcm128" | "aes128gcm" => Ok(Self::AesGcm128), - #[cfg(feature = "aead-aes-gcm-256")] + #[cfg(feature = "aead-aes")] "aesgcm256" | "aes256gcm" => Ok(Self::AesGcm256), - #[cfg(feature = "aead-chacha-20-poly-1305")] + #[cfg(feature = "aead-chacha")] "chacha20poly1305" => Ok(Self::ChaCha20Poly1305), _ => Err(IdLookupError("aead not recognized")), } @@ -44,10 +44,10 @@ impl FromStr for Aead { /// An iterable slice of [`Aead`] variants pub const AEAD_ALL: &[Aead] = &[ - #[cfg(feature = "aead-aes-gcm-128")] + #[cfg(feature = "aead-aes")] Aead::AesGcm128, - #[cfg(feature = "aead-aes-gcm-256")] + #[cfg(feature = "aead-aes")] Aead::AesGcm256, - #[cfg(feature = "aead-chacha-20-poly-1305")] + #[cfg(feature = "aead-chacha")] Aead::ChaCha20Poly1305, ]; diff --git a/src/kdf.rs b/src/kdf.rs index 932ffa9d103..446947316a0 100644 --- a/src/kdf.rs +++ b/src/kdf.rs @@ -15,13 +15,13 @@ Kdf represents an key derivation function, as per )] #[cfg_attr(feature = "serde", serde(crate = "serde_crate"))] pub enum Kdf { - #[cfg(feature = "kdf-sha256")] + #[cfg(feature = "kdf-hkdfsha2")] /// Sha256 [RFC5869](https://www.rfc-editor.org/info/rfc5869) Sha256 = 1, - #[cfg(feature = "kdf-sha384")] + #[cfg(feature = "kdf-hkdfsha2")] /// Sha384 [RFC5869](https://www.rfc-editor.org/info/rfc5869) Sha384 = 2, - #[cfg(feature = "kdf-sha512")] + #[cfg(feature = "kdf-hkdfsha2")] /// Sha512 [RFC5869](https://www.rfc-editor.org/info/rfc5869) Sha512 = 3, } @@ -31,11 +31,11 @@ impl FromStr for Kdf { fn from_str(s: &str) -> Result { match &*s.to_lowercase().replace('-', "") { - #[cfg(feature = "kdf-sha256")] + #[cfg(feature = "kdf-hkdfsha2")] "hkdfsha256" | "sha256" => Ok(Self::Sha256), - #[cfg(feature = "kdf-sha384")] + #[cfg(feature = "kdf-hkdfsha2")] "hkdfsha384" | "sha384" => Ok(Self::Sha384), - #[cfg(feature = "kdf-sha512")] + #[cfg(feature = "kdf-hkdfsha2")] "hkdfsha512" | "sha512" => Ok(Self::Sha512), _ => Err(IdLookupError("kdf not recognized")), } @@ -44,10 +44,10 @@ impl FromStr for Kdf { /// An iterable slice of [`Kdf`] variants pub const KDF_ALL: &[Kdf] = &[ - #[cfg(feature = "kdf-sha256")] + #[cfg(feature = "kdf-hkdfsha2")] Kdf::Sha256, - #[cfg(feature = "kdf-sha384")] + #[cfg(feature = "kdf-hkdfsha2")] Kdf::Sha384, - #[cfg(feature = "kdf-sha512")] + #[cfg(feature = "kdf-hkdfsha2")] Kdf::Sha512, ]; diff --git a/src/kem.rs b/src/kem.rs index 43ad1c49d66..64bdea546ac 100644 --- a/src/kem.rs +++ b/src/kem.rs @@ -19,19 +19,19 @@ the hpke draft are available. #[cfg_attr(feature = "serde", serde(crate = "serde_crate"))] pub enum Kem { /// DHKEM(P-256, HKDF-SHA256) [NISTCurves](https://doi.org/10.6028/nist.fips.186-4) - #[cfg(feature = "kem-dh-p256-hkdf-sha256")] + #[cfg(feature = "kem-nistp")] DhP256HkdfSha256 = 16, /// DHKEM(P-384, HKDF-SHA384) [NISTCurves](https://doi.org/10.6028/nist.fips.186-4) - #[cfg(feature = "kem-dh-p384-hkdf-sha384")] + #[cfg(feature = "kem-nistp")] DhP384HkdfSha384 = 17, /// DHKEM(P-521, HKDF-SHA512) [NISTCurves](https://doi.org/10.6028/nist.fips.186-4) - #[cfg(feature = "kem-dh-p521-hkdf-sha512")] + #[cfg(feature = "kem-nistp")] DhP521HkdfSha512 = 18, /// DHKEM(X25519, HKDF-SHA256) [RFC7748](https://www.rfc-editor.org/info/rfc7748) - #[cfg(feature = "kem-x25519-hkdf-sha256")] + #[cfg(feature = "kem-x25519")] X25519HkdfSha256 = 32, } @@ -40,19 +40,19 @@ impl FromStr for Kem { fn from_str(s: &str) -> Result { match &*s.to_lowercase().replace('-', "") { - #[cfg(feature = "kem-dh-p256-hkdf-sha256")] + #[cfg(feature = "kem-nistp")] "p256sha256" | "dhkemp256hkdfsha256" | "p256hkdfsha256" | "dhkem(p256, hkdfsha256)" => { Ok(Self::DhP256HkdfSha256) } - #[cfg(feature = "kem-dh-p384-hkdf-sha384")] + #[cfg(feature = "kem-nistp")] "p384sha384" | "dhkemp384hkdfsha384" | "p384hkdfsha384" | "dhkem(p384, hkdfsha384)" => { Ok(Self::DhP384HkdfSha384) } - #[cfg(feature = "kem-dh-p521-hkdf-sha512")] + #[cfg(feature = "kem-nistp")] "p521sha512" | "dhkemp521hkdfsha512" | "p521hkdfsha512" | "dhkem(p521, hkdfsha512)" => { Ok(Self::DhP521HkdfSha512) } - #[cfg(feature = "kem-x25519-hkdf-sha256")] + #[cfg(feature = "kem-x25519")] "x25519sha256" | "dhkemx25519hkdfsha256" | "x25519hkdfsha256" @@ -72,12 +72,12 @@ impl Kem { /// An iterable slice of [`Kem`] variants pub const KEM_ALL: &[Kem] = &[ - #[cfg(feature = "kem-dh-p256-hkdf-sha256")] + #[cfg(feature = "kem-nistp")] Kem::DhP256HkdfSha256, - #[cfg(feature = "kem-dh-p384-hkdf-sha384")] + #[cfg(feature = "kem-nistp")] Kem::DhP384HkdfSha384, - #[cfg(feature = "kem-dh-p521-hkdf-sha512")] + #[cfg(feature = "kem-nistp")] Kem::DhP521HkdfSha512, - #[cfg(feature = "kem-x25519-hkdf-sha256")] + #[cfg(feature = "kem-x25519")] Kem::X25519HkdfSha256, ]; diff --git a/src/keypair.rs b/src/keypair.rs index 09c339a7e70..b68db3a2377 100644 --- a/src/keypair.rs +++ b/src/keypair.rs @@ -31,16 +31,16 @@ impl Keypair { #[must_use] pub fn gen_keypair(kem: Kem) -> Keypair { match kem { - #[cfg(feature = "kem-dh-p256-hkdf-sha256")] + #[cfg(feature = "kem-nistp")] Kem::DhP256HkdfSha256 => gen_kp::(), - #[cfg(feature = "kem-dh-p384-hkdf-sha384")] + #[cfg(feature = "kem-nistp")] Kem::DhP384HkdfSha384 => gen_kp::(), - #[cfg(feature = "kem-dh-p521-hkdf-sha512")] + #[cfg(feature = "kem-nistp")] Kem::DhP521HkdfSha512 => gen_kp::(), - #[cfg(feature = "kem-x25519-hkdf-sha256")] + #[cfg(feature = "kem-x25519")] Kem::X25519HkdfSha256 => gen_kp::(), } } diff --git a/src/lib.rs b/src/lib.rs index 0d02871490b..7e3fd7f3f50 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,18 +16,9 @@ #![doc = include_str!("../README.md")] #![cfg(all( any(feature = "base-mode-open", feature = "base-mode-seal"), - any( - feature = "aead-aes-gcm-128", - feature = "aead-aes-gcm-256", - feature = "aead-chacha-20-poly-1305", - ), - any(feature = "kdf-sha256", feature = "kdf-sha384", feature = "kdf-sha512"), - any( - feature = "kem-dh-p256-hkdf-sha256", - feature = "kem-dh-p384-hkdf-sha384", - feature = "kem-dh-p521-hkdf-sha512", - feature = "kem-x25519-hkdf-sha256", - ), + any(feature = "aead-aes", feature = "aead-chacha",), + any(feature = "kdf-hkdfsha2", feature = "kdf-shake"), + any(feature = "kem-nistp", feature = "kem-x25519", feature = "kem-mlkem",), ))] use hpke::{Deserializable, HpkeError}; diff --git a/src/macros.rs b/src/macros.rs index 86bfa740324..d493287bd6f 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -5,11 +5,11 @@ macro_rules! match_algo { (@aead, $aead:ident, $kdf:ident, $kem:ident, $fn:ident) => { match $aead { - #[cfg(feature = "aead-aes-gcm-128")] + #[cfg(feature = "aead-aes")] $crate::Aead::AesGcm128 => match_algo!(@kdf, hpke::aead::AesGcm128, $kdf, $kem, $fn), - #[cfg(feature = "aead-aes-gcm-256")] + #[cfg(feature = "aead-aes")] $crate::Aead::AesGcm256 => match_algo!(@kdf, hpke::aead::AesGcm256, $kdf, $kem, $fn), - #[cfg(feature = "aead-chacha-20-poly-1305")] + #[cfg(feature = "aead-chacha")] $crate::Aead::ChaCha20Poly1305 => { match_algo!(@kdf, hpke::aead::ChaCha20Poly1305, $kdf, $kem, $fn) } @@ -18,24 +18,24 @@ macro_rules! match_algo { (@kdf, $aead:ty, $kdf:expr, $kem:expr, $fn:ident) => { match $kdf { - #[cfg(feature = "kdf-sha256")] + #[cfg(feature = "kdf-hkdfsha2")] $crate::Kdf::Sha256 => match_algo!(@kem, $aead, hpke::kdf::HkdfSha256, $kem, $fn), - #[cfg(feature = "kdf-sha384")] + #[cfg(feature = "kdf-hkdfsha2")] $crate::Kdf::Sha384 => match_algo!(@kem, $aead, hpke::kdf::HkdfSha384, $kem, $fn), - #[cfg(feature = "kdf-sha512")] + #[cfg(feature = "kdf-hkdfsha2")] $crate::Kdf::Sha512 => match_algo!(@kem, $aead, hpke::kdf::HkdfSha512, $kem, $fn), } }; (@kem, $aead:ty, $kdf:ty, $kem:expr, $fn:ident) => { match $kem { - #[cfg(feature = "kem-dh-p256-hkdf-sha256")] + #[cfg(feature = "kem-nistp")] $crate::Kem::DhP256HkdfSha256 => $fn::<$aead, $kdf, hpke::kem::DhP256HkdfSha256>, - #[cfg(feature = "kem-dh-p384-hkdf-sha384")] + #[cfg(feature = "kem-nistp")] $crate::Kem::DhP384HkdfSha384 => $fn::<$aead, $kdf, hpke::kem::DhP384HkdfSha384>, - #[cfg(feature = "kem-dh-p521-hkdf-sha512")] + #[cfg(feature = "kem-nistp")] $crate::Kem::DhP521HkdfSha512 => $fn::<$aead, $kdf, hpke::kem::DhP521HkdfSha512>, - #[cfg(feature = "kem-x25519-hkdf-sha256")] + #[cfg(feature = "kem-x25519")] $crate::Kem::X25519HkdfSha256 => $fn::<$aead, $kdf, hpke::kem::X25519HkdfSha256>, } }; From 6ba4896f3c0e9fd02a601216490ef30be8440d16 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Fri, 10 Jul 2026 22:41:44 -0400 Subject: [PATCH 3/5] Add new KDFs --- src/kdf.rs | 35 +++++++++++++++++++++++++++++++---- src/macros.rs | 8 ++++++++ 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/kdf.rs b/src/kdf.rs index 446947316a0..991ba16760e 100644 --- a/src/kdf.rs +++ b/src/kdf.rs @@ -3,8 +3,10 @@ use num_enum::TryFromPrimitive; use std::str::FromStr; /** -Kdf represents an key derivation function, as per +Kdf represents a key derivation function, as per [RFC9180§7.2](https://www.rfc-editor.org/rfc/rfc9180.html#section-7.2) +and +https://www.ietf.org/archive/id/draft-ietf-hpke-pq-05.html#table-1 */ #[non_exhaustive] #[repr(u16)] @@ -17,13 +19,22 @@ Kdf represents an key derivation function, as per pub enum Kdf { #[cfg(feature = "kdf-hkdfsha2")] /// Sha256 [RFC5869](https://www.rfc-editor.org/info/rfc5869) - Sha256 = 1, + Sha256 = 0x0001, #[cfg(feature = "kdf-hkdfsha2")] /// Sha384 [RFC5869](https://www.rfc-editor.org/info/rfc5869) - Sha384 = 2, + Sha384 = 0x0002, #[cfg(feature = "kdf-hkdfsha2")] /// Sha512 [RFC5869](https://www.rfc-editor.org/info/rfc5869) - Sha512 = 3, + Sha512 = 0x0003, + #[cfg(feature = "kdf-shake")] + /// SHAKE128 [RFC 9861](https://www.rfc-editor.org/info/rfc9861/) + Shake128 = 0x0010, + /// SHAKE256 [RFC 9861](https://www.rfc-editor.org/info/rfc9861/) + Shake256 = 0x0011, + /// TurboSHAKE128 [RFC 9861](https://www.rfc-editor.org/info/rfc9861/) + TurboShake128 = 0x0012, + /// TurboSHAKE256 [RFC 9861](https://www.rfc-editor.org/info/rfc9861/) + TurboShake256 = 0x0013, } impl FromStr for Kdf { @@ -37,6 +48,14 @@ impl FromStr for Kdf { "hkdfsha384" | "sha384" => Ok(Self::Sha384), #[cfg(feature = "kdf-hkdfsha2")] "hkdfsha512" | "sha512" => Ok(Self::Sha512), + #[cfg(feature = "kdf-shake")] + "shake128" => Ok(Self::Shake128), + #[cfg(feature = "kdf-shake")] + "shake256" => Ok(Self::Shake256), + #[cfg(feature = "kdf-shake")] + "turboshake128" => Ok(Self::TurboShake128), + #[cfg(feature = "kdf-shake")] + "turboshake256" => Ok(Self::TurboShake256), _ => Err(IdLookupError("kdf not recognized")), } } @@ -50,4 +69,12 @@ pub const KDF_ALL: &[Kdf] = &[ Kdf::Sha384, #[cfg(feature = "kdf-hkdfsha2")] Kdf::Sha512, + #[cfg(feature = "kdf-shake")] + Kdf::Shake128, + #[cfg(feature = "kdf-shake")] + Kdf::Shake256, + #[cfg(feature = "kdf-shake")] + Kdf::TurboShake128, + #[cfg(feature = "kdf-shake")] + Kdf::TurboShake256, ]; diff --git a/src/macros.rs b/src/macros.rs index d493287bd6f..2d4f58d8416 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -24,6 +24,14 @@ macro_rules! match_algo { $crate::Kdf::Sha384 => match_algo!(@kem, $aead, hpke::kdf::HkdfSha384, $kem, $fn), #[cfg(feature = "kdf-hkdfsha2")] $crate::Kdf::Sha512 => match_algo!(@kem, $aead, hpke::kdf::HkdfSha512, $kem, $fn), + #[cfg(feature = "kdf-shake")] + $crate::Kdf::Shake128 => match_algo!(@kem, $aead, hpke::kdf::KdfShake128, $kem, $fn), + #[cfg(feature = "kdf-shake")] + $crate::Kdf::Shake256 => match_algo!(@kem, $aead, hpke::kdf::KdfShake256, $kem, $fn), + #[cfg(feature = "kdf-shake")] + $crate::Kdf::TurboShake128 => match_algo!(@kem, $aead, hpke::kdf::KdfTurboShake128, $kem, $fn), + #[cfg(feature = "kdf-shake")] + $crate::Kdf::TurboShake256 => match_algo!(@kem, $aead, hpke::kdf::KdfTurboShake256, $kem, $fn), } }; From 432a2ec2f551773d840ebea958e3d96851f60795 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Fri, 10 Jul 2026 23:06:47 -0400 Subject: [PATCH 4/5] Add new KEMs --- src/kem.rs | 55 ++++++++++++++++++++++++++++++++++++++++++-------- src/keypair.rs | 15 ++++++++++++++ src/macros.rs | 10 +++++++++ 3 files changed, 72 insertions(+), 8 deletions(-) diff --git a/src/kem.rs b/src/kem.rs index 64bdea546ac..8be0ec890df 100644 --- a/src/kem.rs +++ b/src/kem.rs @@ -4,10 +4,9 @@ use std::str::FromStr; /** Kem represents an asymmetric key encapsulation mechanism, as per -[RFC9180§7.1][section-7.1]. Currently only four of the options listed in -the hpke draft are available. - -[section-7.1]: https://www.rfc-editor.org/rfc/rfc9180.html#section-7.1 +[RFC9180§7.1](https://www.rfc-editor.org/rfc/rfc9180.html#section-7.1) +and +https://www.ietf.org/archive/id/draft-ietf-hpke-pq-05.html#name-updated-ml-kem-entries-for- */ #[non_exhaustive] #[repr(u16)] @@ -20,19 +19,39 @@ the hpke draft are available. pub enum Kem { /// DHKEM(P-256, HKDF-SHA256) [NISTCurves](https://doi.org/10.6028/nist.fips.186-4) #[cfg(feature = "kem-nistp")] - DhP256HkdfSha256 = 16, + DhP256HkdfSha256 = 0x0010, /// DHKEM(P-384, HKDF-SHA384) [NISTCurves](https://doi.org/10.6028/nist.fips.186-4) #[cfg(feature = "kem-nistp")] - DhP384HkdfSha384 = 17, + DhP384HkdfSha384 = 0x0011, /// DHKEM(P-521, HKDF-SHA512) [NISTCurves](https://doi.org/10.6028/nist.fips.186-4) #[cfg(feature = "kem-nistp")] - DhP521HkdfSha512 = 18, + DhP521HkdfSha512 = 0x0012, /// DHKEM(X25519, HKDF-SHA256) [RFC7748](https://www.rfc-editor.org/info/rfc7748) #[cfg(feature = "kem-x25519")] - X25519HkdfSha256 = 32, + X25519HkdfSha256 = 0x0020, + + /// MLKEM-768 [FIPS 203](https://csrc.nist.gov/pubs/fips/203/final) + #[cfg(feature = "kem-mlkem")] + MlKem768 = 0x0041, + + /// MLKEM-1024 [FIPS 203](https://csrc.nist.gov/pubs/fips/203/final) + #[cfg(feature = "kem-mlkem")] + MlKem1024 = 0x0042, + + /// X-Wing (MLKEM768-X25519) + #[cfg(all(feature = "kem-mlkem", feature = "kem-x25519"))] + XWing = 0x647a, + + /// MLKEM768-P256 + #[cfg(all(feature = "kem-mlkem", feature = "kem-nistp"))] + MlKem768P256 = 0x0050, + + /// MLKEM1024-P384 + #[cfg(all(feature = "kem-mlkem", feature = "kem-nistp"))] + MlKem1024P384 = 0x0051, } impl FromStr for Kem { @@ -57,6 +76,16 @@ impl FromStr for Kem { | "dhkemx25519hkdfsha256" | "x25519hkdfsha256" | "dhkem(x25519, hkdfsha256)" => Ok(Self::X25519HkdfSha256), + #[cfg(feature = "kem-mlkem")] + "mlkem768" => Ok(Self::MlKem768), + #[cfg(feature = "kem-mlkem")] + "mlkem1024" => Ok(Self::MlKem1024), + #[cfg(all(feature = "kem-mlkem", feature = "kem-x25519"))] + "xwing" | "mlkem768x25119" | "mlkem768-x25119" => Ok(Self::XWing), + #[cfg(all(feature = "kem-mlkem", feature = "kem-nistp"))] + "mlkem768p256" | "mlkem768-p256" => Ok(Self::MlKem768P256), + #[cfg(all(feature = "kem-mlkem", feature = "kem-nistp"))] + "mlkem1024p384" | "mlkem1024-p384" => Ok(Self::MlKem1024P384), _ => Err(IdLookupError("kem not recognized")), } } @@ -80,4 +109,14 @@ pub const KEM_ALL: &[Kem] = &[ Kem::DhP521HkdfSha512, #[cfg(feature = "kem-x25519")] Kem::X25519HkdfSha256, + #[cfg(feature = "kem-mlkem")] + Kem::MlKem768, + #[cfg(feature = "kem-mlkem")] + Kem::MlKem1024, + #[cfg(all(feature = "kem-mlkem", feature = "kem-x25519"))] + Kem::XWing, + #[cfg(all(feature = "kem-mlkem", feature = "kem-nistp"))] + Kem::MlKem768P256, + #[cfg(all(feature = "kem-mlkem", feature = "kem-nistp"))] + Kem::MlKem1024P384, ]; diff --git a/src/keypair.rs b/src/keypair.rs index b68db3a2377..83469735635 100644 --- a/src/keypair.rs +++ b/src/keypair.rs @@ -42,6 +42,21 @@ pub fn gen_keypair(kem: Kem) -> Keypair { #[cfg(feature = "kem-x25519")] Kem::X25519HkdfSha256 => gen_kp::(), + + #[cfg(feature = "kem-mlkem")] + Kem::MlKem768 => gen_kp::(), + + #[cfg(feature = "kem-mlkem")] + Kem::MlKem1024 => gen_kp::(), + + #[cfg(all(feature = "kem-mlkem", feature = "kem-x25519"))] + Kem::XWing => gen_kp::(), + + #[cfg(all(feature = "kem-mlkem", feature = "kem-nistp"))] + Kem::MlKem768P256 => gen_kp::(), + + #[cfg(all(feature = "kem-mlkem", feature = "kem-nistp"))] + Kem::MlKem1024P384 => gen_kp::(), } } diff --git a/src/macros.rs b/src/macros.rs index 2d4f58d8416..c599f3379f4 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -45,6 +45,16 @@ macro_rules! match_algo { $crate::Kem::DhP521HkdfSha512 => $fn::<$aead, $kdf, hpke::kem::DhP521HkdfSha512>, #[cfg(feature = "kem-x25519")] $crate::Kem::X25519HkdfSha256 => $fn::<$aead, $kdf, hpke::kem::X25519HkdfSha256>, + #[cfg(feature = "kem-mlkem")] + $crate::Kem::MlKem768 => $fn::<$aead, $kdf, hpke::kem::MlKem768>, + #[cfg(feature = "kem-mlkem")] + $crate::Kem::MlKem1024 => $fn::<$aead, $kdf, hpke::kem::MlKem1024>, + #[cfg(all(feature = "kem-mlkem", feature = "kem-x25519"))] + $crate::Kem::XWing => $fn::<$aead, $kdf, hpke::kem::XWing>, + #[cfg(all(feature = "kem-mlkem", feature = "kem-nistp"))] + $crate::Kem::MlKem768P256 => $fn::<$aead, $kdf, hpke::kem::MlKem768P256>, + #[cfg(all(feature = "kem-mlkem", feature = "kem-nistp"))] + $crate::Kem::MlKem1024P384 => $fn::<$aead, $kdf, hpke::kem::MlKem1024P384>, } }; } From 96eaaa12a4d843411c1a3cc8d27d1b3c3a8699df Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Fri, 10 Jul 2026 23:17:20 -0400 Subject: [PATCH 5/5] Remove unnecesasry deps --- Cargo.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9562bfb823f..59a969ecb88 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,9 +27,7 @@ kem-nistp = ["hpke/nistp"] kem-mlkem = ["hpke/mlkem"] [dependencies] -rand = "0.9.2" num_enum = "0.7.0" -cfg-if = "1.0.0" hpke = { version = "0.14", default-features = false, features = ["getrandom", "alloc"] } zeroize = "1.6"