use crate::constants::{
HPKE_AEAD_AES_128_GCM, HPKE_AEAD_AES_256_GCM, HPKE_AEAD_CHACHA20_POLY1305,
HPKE_AEAD_EXPORT_ONLY, HPKE_AEAD_TAG_LEN, HPKE_KDF_HKDF_SHA256, HPKE_KDF_HKDF_SHA384,
HPKE_KDF_HKDF_SHA512, HPKE_KDF_SHAKE128, HPKE_KDF_SHAKE256, HPKE_KDF_TURBO_SHAKE128,
HPKE_KDF_TURBO_SHAKE256, HPKE_KEM_DHKEM_CP256_HKDF_SHA256, HPKE_KEM_DHKEM_CP384_HKDF_SHA384,
HPKE_KEM_DHKEM_CP521_HKDF_SHA512, HPKE_KEM_DHKEM_P256_HKDF_SHA256,
HPKE_KEM_DHKEM_P384_HKDF_SHA384, HPKE_KEM_DHKEM_P521_HKDF_SHA512,
HPKE_KEM_DHKEM_SECP256K1_HKDF_SHA256, HPKE_KEM_DHKEM_X25519_ELLIGATOR_HKDF_SHA256,
HPKE_KEM_DHKEM_X25519_HKDF_SHA256, HPKE_KEM_DHKEM_X448_HKDF_SHA512, HPKE_KEM_ML_KEM_1024,
HPKE_KEM_ML_KEM_1024_P384, HPKE_KEM_ML_KEM_512, HPKE_KEM_ML_KEM_768, HPKE_KEM_ML_KEM_768_P256,
HPKE_KEM_X25519_KYBER768_DRAFT00, HPKE_KEM_X_WING,
};
use crate::error::HpkeError;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HpkeComponentSupport {
Executable,
RegisteredUnavailable,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u16)]
pub enum HpkeKemId {
DhKemP256HkdfSha256 = HPKE_KEM_DHKEM_P256_HKDF_SHA256,
DhKemP384HkdfSha384 = HPKE_KEM_DHKEM_P384_HKDF_SHA384,
DhKemP521HkdfSha512 = HPKE_KEM_DHKEM_P521_HKDF_SHA512,
DhKemCp256HkdfSha256 = HPKE_KEM_DHKEM_CP256_HKDF_SHA256,
DhKemCp384HkdfSha384 = HPKE_KEM_DHKEM_CP384_HKDF_SHA384,
DhKemCp521HkdfSha512 = HPKE_KEM_DHKEM_CP521_HKDF_SHA512,
DhKemSecp256k1HkdfSha256 = HPKE_KEM_DHKEM_SECP256K1_HKDF_SHA256,
DhKemX25519HkdfSha256 = HPKE_KEM_DHKEM_X25519_HKDF_SHA256,
DhKemX448HkdfSha512 = HPKE_KEM_DHKEM_X448_HKDF_SHA512,
DhKemX25519ElligatorHkdfSha256 = HPKE_KEM_DHKEM_X25519_ELLIGATOR_HKDF_SHA256,
X25519Kyber768Draft00 = HPKE_KEM_X25519_KYBER768_DRAFT00,
MlKem512 = HPKE_KEM_ML_KEM_512,
MlKem768 = HPKE_KEM_ML_KEM_768,
MlKem1024 = HPKE_KEM_ML_KEM_1024,
MlKem768P256 = HPKE_KEM_ML_KEM_768_P256,
MlKem1024P384 = HPKE_KEM_ML_KEM_1024_P384,
XWing = HPKE_KEM_X_WING,
}
impl HpkeKemId {
pub const fn support(self) -> HpkeComponentSupport {
match self {
Self::DhKemP256HkdfSha256 if cfg!(feature = "kem-dh-p256") => {
HpkeComponentSupport::Executable
}
Self::DhKemP384HkdfSha384 if cfg!(feature = "kem-dh-p384") => {
HpkeComponentSupport::Executable
}
Self::DhKemP521HkdfSha512 if cfg!(feature = "kem-dh-p521") => {
HpkeComponentSupport::Executable
}
Self::DhKemSecp256k1HkdfSha256 if cfg!(feature = "kem-secp256k1") => {
HpkeComponentSupport::Executable
}
Self::DhKemX25519HkdfSha256 if cfg!(feature = "kem-x25519") => {
HpkeComponentSupport::Executable
}
Self::DhKemX448HkdfSha512 if cfg!(feature = "kem-x448") => {
HpkeComponentSupport::Executable
}
Self::MlKem512 if cfg!(feature = "kem-ml-kem-512") => HpkeComponentSupport::Executable,
Self::MlKem768 if cfg!(feature = "kem-ml-kem-768") => HpkeComponentSupport::Executable,
Self::MlKem1024 if cfg!(feature = "kem-ml-kem-1024") => {
HpkeComponentSupport::Executable
}
Self::MlKem768P256 if cfg!(feature = "kem-ml-kem-768-p256") => {
HpkeComponentSupport::Executable
}
Self::MlKem1024P384 if cfg!(feature = "kem-ml-kem-1024-p384") => {
HpkeComponentSupport::Executable
}
Self::XWing if cfg!(feature = "kem-x-wing") => HpkeComponentSupport::Executable,
Self::DhKemCp256HkdfSha256
| Self::DhKemCp384HkdfSha384
| Self::DhKemCp521HkdfSha512
| Self::DhKemX25519ElligatorHkdfSha256
| Self::X25519Kyber768Draft00
| Self::DhKemP256HkdfSha256
| Self::DhKemP384HkdfSha384
| Self::DhKemP521HkdfSha512
| Self::DhKemSecp256k1HkdfSha256
| Self::DhKemX25519HkdfSha256
| Self::DhKemX448HkdfSha512
| Self::MlKem512
| Self::MlKem768
| Self::MlKem1024
| Self::MlKem768P256
| Self::MlKem1024P384
| Self::XWing => HpkeComponentSupport::RegisteredUnavailable,
}
}
}
impl TryFrom<u16> for HpkeKemId {
type Error = HpkeError;
fn try_from(value: u16) -> Result<Self, Self::Error> {
match value {
HPKE_KEM_DHKEM_P256_HKDF_SHA256 => Ok(Self::DhKemP256HkdfSha256),
HPKE_KEM_DHKEM_P384_HKDF_SHA384 => Ok(Self::DhKemP384HkdfSha384),
HPKE_KEM_DHKEM_P521_HKDF_SHA512 => Ok(Self::DhKemP521HkdfSha512),
HPKE_KEM_DHKEM_CP256_HKDF_SHA256 => Ok(Self::DhKemCp256HkdfSha256),
HPKE_KEM_DHKEM_CP384_HKDF_SHA384 => Ok(Self::DhKemCp384HkdfSha384),
HPKE_KEM_DHKEM_CP521_HKDF_SHA512 => Ok(Self::DhKemCp521HkdfSha512),
HPKE_KEM_DHKEM_SECP256K1_HKDF_SHA256 => Ok(Self::DhKemSecp256k1HkdfSha256),
HPKE_KEM_DHKEM_X25519_HKDF_SHA256 => Ok(Self::DhKemX25519HkdfSha256),
HPKE_KEM_DHKEM_X448_HKDF_SHA512 => Ok(Self::DhKemX448HkdfSha512),
HPKE_KEM_DHKEM_X25519_ELLIGATOR_HKDF_SHA256 => Ok(Self::DhKemX25519ElligatorHkdfSha256),
HPKE_KEM_X25519_KYBER768_DRAFT00 => Ok(Self::X25519Kyber768Draft00),
HPKE_KEM_ML_KEM_512 => Ok(Self::MlKem512),
HPKE_KEM_ML_KEM_768 => Ok(Self::MlKem768),
HPKE_KEM_ML_KEM_1024 => Ok(Self::MlKem1024),
HPKE_KEM_ML_KEM_768_P256 => Ok(Self::MlKem768P256),
HPKE_KEM_ML_KEM_1024_P384 => Ok(Self::MlKem1024P384),
HPKE_KEM_X_WING => Ok(Self::XWing),
_ => Err(HpkeError::UnsupportedKem),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u16)]
pub enum HpkeKdfId {
HkdfSha256 = HPKE_KDF_HKDF_SHA256,
HkdfSha384 = HPKE_KDF_HKDF_SHA384,
HkdfSha512 = HPKE_KDF_HKDF_SHA512,
Shake128 = HPKE_KDF_SHAKE128,
Shake256 = HPKE_KDF_SHAKE256,
TurboShake128 = HPKE_KDF_TURBO_SHAKE128,
TurboShake256 = HPKE_KDF_TURBO_SHAKE256,
}
impl HpkeKdfId {
pub const fn support(self) -> HpkeComponentSupport {
match self {
Self::HkdfSha256 if cfg!(feature = "kdf-hkdf-sha256") => {
HpkeComponentSupport::Executable
}
Self::HkdfSha384 if cfg!(feature = "kdf-hkdf-sha384") => {
HpkeComponentSupport::Executable
}
Self::HkdfSha512 if cfg!(feature = "kdf-hkdf-sha512") => {
HpkeComponentSupport::Executable
}
Self::Shake256 if cfg!(feature = "kdf-shake256") => HpkeComponentSupport::Executable,
Self::HkdfSha256
| Self::HkdfSha384
| Self::HkdfSha512
| Self::Shake128
| Self::Shake256
| Self::TurboShake128
| Self::TurboShake256 => HpkeComponentSupport::RegisteredUnavailable,
}
}
}
impl TryFrom<u16> for HpkeKdfId {
type Error = HpkeError;
fn try_from(value: u16) -> Result<Self, Self::Error> {
match value {
HPKE_KDF_HKDF_SHA256 => Ok(Self::HkdfSha256),
HPKE_KDF_HKDF_SHA384 => Ok(Self::HkdfSha384),
HPKE_KDF_HKDF_SHA512 => Ok(Self::HkdfSha512),
HPKE_KDF_SHAKE128 => Ok(Self::Shake128),
HPKE_KDF_SHAKE256 => Ok(Self::Shake256),
HPKE_KDF_TURBO_SHAKE128 => Ok(Self::TurboShake128),
HPKE_KDF_TURBO_SHAKE256 => Ok(Self::TurboShake256),
_ => Err(HpkeError::UnsupportedKdf),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u16)]
pub enum HpkeAeadId {
Aes128Gcm = HPKE_AEAD_AES_128_GCM,
Aes256Gcm = HPKE_AEAD_AES_256_GCM,
ChaCha20Poly1305 = HPKE_AEAD_CHACHA20_POLY1305,
ExportOnly = HPKE_AEAD_EXPORT_ONLY,
}
impl HpkeAeadId {
pub const fn support(self) -> HpkeComponentSupport {
match self {
Self::Aes128Gcm if cfg!(feature = "aead-aes128-gcm") => {
HpkeComponentSupport::Executable
}
Self::Aes256Gcm if cfg!(feature = "aead-aes256-gcm") => {
HpkeComponentSupport::Executable
}
Self::ChaCha20Poly1305 if cfg!(feature = "aead-chacha20-poly1305") => {
HpkeComponentSupport::Executable
}
Self::ExportOnly if cfg!(feature = "aead-export-only") => {
HpkeComponentSupport::Executable
}
Self::Aes128Gcm | Self::Aes256Gcm | Self::ChaCha20Poly1305 | Self::ExportOnly => {
HpkeComponentSupport::RegisteredUnavailable
}
}
}
}
pub const HPKE_REGISTERED_KEMS: [HpkeKemId; 17] = [
HpkeKemId::DhKemP256HkdfSha256,
HpkeKemId::DhKemP384HkdfSha384,
HpkeKemId::DhKemP521HkdfSha512,
HpkeKemId::DhKemCp256HkdfSha256,
HpkeKemId::DhKemCp384HkdfSha384,
HpkeKemId::DhKemCp521HkdfSha512,
HpkeKemId::DhKemSecp256k1HkdfSha256,
HpkeKemId::DhKemX25519HkdfSha256,
HpkeKemId::DhKemX448HkdfSha512,
HpkeKemId::DhKemX25519ElligatorHkdfSha256,
HpkeKemId::X25519Kyber768Draft00,
HpkeKemId::MlKem512,
HpkeKemId::MlKem768,
HpkeKemId::MlKem1024,
HpkeKemId::MlKem768P256,
HpkeKemId::MlKem1024P384,
HpkeKemId::XWing,
];
pub const HPKE_REGISTERED_KDFS: [HpkeKdfId; 7] = [
HpkeKdfId::HkdfSha256,
HpkeKdfId::HkdfSha384,
HpkeKdfId::HkdfSha512,
HpkeKdfId::Shake128,
HpkeKdfId::Shake256,
HpkeKdfId::TurboShake128,
HpkeKdfId::TurboShake256,
];
pub const HPKE_REGISTERED_AEADS: [HpkeAeadId; 4] = [
HpkeAeadId::Aes128Gcm,
HpkeAeadId::Aes256Gcm,
HpkeAeadId::ChaCha20Poly1305,
HpkeAeadId::ExportOnly,
];
impl TryFrom<u16> for HpkeAeadId {
type Error = HpkeError;
fn try_from(value: u16) -> Result<Self, Self::Error> {
match value {
HPKE_AEAD_AES_128_GCM => Ok(Self::Aes128Gcm),
HPKE_AEAD_AES_256_GCM => Ok(Self::Aes256Gcm),
HPKE_AEAD_CHACHA20_POLY1305 => Ok(Self::ChaCha20Poly1305),
HPKE_AEAD_EXPORT_ONLY => Ok(Self::ExportOnly),
_ => Err(HpkeError::UnsupportedAead),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct HpkeSuite {
pub kem: HpkeKemId,
pub kdf: HpkeKdfId,
pub aead: HpkeAeadId,
}
impl HpkeSuite {
pub const fn new(kem: HpkeKemId, kdf: HpkeKdfId, aead: HpkeAeadId) -> Self {
Self { kem, kdf, aead }
}
pub const fn kem_id(self) -> u16 {
self.kem as u16
}
pub const fn kdf_id(self) -> u16 {
self.kdf as u16
}
pub const fn aead_id(self) -> u16 {
self.aead as u16
}
pub const fn tag_len(self) -> usize {
match self.aead {
HpkeAeadId::ExportOnly => 0,
HpkeAeadId::Aes128Gcm | HpkeAeadId::Aes256Gcm | HpkeAeadId::ChaCha20Poly1305 => {
HPKE_AEAD_TAG_LEN
}
}
}
}
pub const HPKE_DHKEM_P256_HKDF_SHA256_AES128GCM: HpkeSuite = HpkeSuite::new(
HpkeKemId::DhKemP256HkdfSha256,
HpkeKdfId::HkdfSha256,
HpkeAeadId::Aes128Gcm,
);
pub const HPKE_DHKEM_P256_HKDF_SHA256_AES256GCM: HpkeSuite = HpkeSuite::new(
HpkeKemId::DhKemP256HkdfSha256,
HpkeKdfId::HkdfSha256,
HpkeAeadId::Aes256Gcm,
);
pub const HPKE_DHKEM_P384_HKDF_SHA384_AES256GCM: HpkeSuite = HpkeSuite::new(
HpkeKemId::DhKemP384HkdfSha384,
HpkeKdfId::HkdfSha384,
HpkeAeadId::Aes256Gcm,
);
pub const HPKE_DHKEM_P521_HKDF_SHA512_AES256GCM: HpkeSuite = HpkeSuite::new(
HpkeKemId::DhKemP521HkdfSha512,
HpkeKdfId::HkdfSha512,
HpkeAeadId::Aes256Gcm,
);
pub const HPKE_DHKEM_X25519_HKDF_SHA256_AES128GCM: HpkeSuite = HpkeSuite::new(
HpkeKemId::DhKemX25519HkdfSha256,
HpkeKdfId::HkdfSha256,
HpkeAeadId::Aes128Gcm,
);
pub const HPKE_DHKEM_X25519_HKDF_SHA256_CHACHA20POLY1305: HpkeSuite = HpkeSuite::new(
HpkeKemId::DhKemX25519HkdfSha256,
HpkeKdfId::HkdfSha256,
HpkeAeadId::ChaCha20Poly1305,
);
pub const HPKE_MLKEM512_HKDF_SHA256_AES128GCM: HpkeSuite = HpkeSuite::new(
HpkeKemId::MlKem512,
HpkeKdfId::HkdfSha256,
HpkeAeadId::Aes128Gcm,
);
pub const HPKE_XWING_HKDF_SHA256_CHACHA20POLY1305: HpkeSuite = HpkeSuite::new(
HpkeKemId::XWing,
HpkeKdfId::HkdfSha256,
HpkeAeadId::ChaCha20Poly1305,
);
pub const HPKE_XWING_HKDF_SHA384_AES256GCM: HpkeSuite = HpkeSuite::new(
HpkeKemId::XWing,
HpkeKdfId::HkdfSha384,
HpkeAeadId::Aes256Gcm,
);
pub const HPKE_MLKEM768_SHAKE256_AES256GCM: HpkeSuite = HpkeSuite::new(
HpkeKemId::MlKem768,
HpkeKdfId::Shake256,
HpkeAeadId::Aes256Gcm,
);
pub const HPKE_MLKEM768_HKDF_SHA384_AES256GCM: HpkeSuite = HpkeSuite::new(
HpkeKemId::MlKem768,
HpkeKdfId::HkdfSha384,
HpkeAeadId::Aes256Gcm,
);
pub const HPKE_MLKEM1024_SHAKE256_AES256GCM: HpkeSuite = HpkeSuite::new(
HpkeKemId::MlKem1024,
HpkeKdfId::Shake256,
HpkeAeadId::Aes256Gcm,
);
pub const HPKE_MLKEM1024_HKDF_SHA384_AES256GCM: HpkeSuite = HpkeSuite::new(
HpkeKemId::MlKem1024,
HpkeKdfId::HkdfSha384,
HpkeAeadId::Aes256Gcm,
);
pub const HPKE_MLKEM768P256_SHAKE256_AES256GCM: HpkeSuite = HpkeSuite::new(
HpkeKemId::MlKem768P256,
HpkeKdfId::Shake256,
HpkeAeadId::Aes256Gcm,
);
pub const HPKE_MLKEM1024P384_SHAKE256_AES256GCM: HpkeSuite = HpkeSuite::new(
HpkeKemId::MlKem1024P384,
HpkeKdfId::Shake256,
HpkeAeadId::Aes256Gcm,
);
pub const HPKE_MLKEM1024P384_HKDF_SHA384_AES256GCM: HpkeSuite = HpkeSuite::new(
HpkeKemId::MlKem1024P384,
HpkeKdfId::HkdfSha384,
HpkeAeadId::Aes256Gcm,
);
pub const MLS_192_MLKEM1024_AES256GCM_SHA384_P384: HpkeSuite = HPKE_MLKEM1024_HKDF_SHA384_AES256GCM;
pub const MLS_256_MLKEM1024_AES256GCM_SHA384_MLDSA87: HpkeSuite =
HPKE_MLKEM1024_HKDF_SHA384_AES256GCM;
pub const MLS_192_MLKEM1024P384_AES256GCM_SHA384_P384: HpkeSuite =
HPKE_MLKEM1024P384_HKDF_SHA384_AES256GCM;
pub const MLS_192_MLKEM768_AES256GCM_SHA384_MLDSA65: HpkeSuite =
HPKE_MLKEM768_HKDF_SHA384_AES256GCM;
#[allow(non_upper_case_globals)] pub const MLS_128_MLKEM768X25519_AES256GCM_SHA384_Ed25519: HpkeSuite =
HPKE_XWING_HKDF_SHA384_AES256GCM;