use crate::Secret;
use crate::generics::sealed::Sealed;
use crate::{
errors::UnknownCryptoError,
hazardous::{
hash::sha3::shake256::Shake256,
hpke::suite::private::{HpkeAuthKem, HpkeKem},
kem::{x25519_hkdf_sha256, xwing},
},
};
pub(crate) const VERSION_ID: &[u8; 7] = b"HPKE-v1";
pub(crate) fn length_prefix(input: &[u8]) -> Result<[u8; 2], UnknownCryptoError> {
let len: u16 = input.len().try_into().map_err(|_| UnknownCryptoError)?;
Ok(len.to_be_bytes())
}
#[derive(Debug, Clone, Copy)]
pub struct DhKemX25519HkdfSha256 {}
impl Sealed for DhKemX25519HkdfSha256 {}
impl HpkeKem for DhKemX25519HkdfSha256 {
const KEM_ID: [u8; 2] = 0x0020u16.to_be_bytes();
const NSECRET: usize = 32;
const NENC: usize = 32;
const NPK: usize = 32;
const NSK: usize = 32;
type PrivateKey = x25519_hkdf_sha256::PrivateKey;
type PublicKey = x25519_hkdf_sha256::PublicKey;
type EncapsulatedKey = x25519_hkdf_sha256::PublicKey;
type EphemeralSecret = x25519_hkdf_sha256::PrivateKey;
type SharedSecretSpec = x25519_hkdf_sha256::DhKemSharedSecret;
type KeyPair = x25519_hkdf_sha256::KeyPair;
fn derive_keypair(ikm: &[u8]) -> Result<Self::KeyPair, UnknownCryptoError> {
x25519_hkdf_sha256::KeyPair::derive(ikm)
}
#[cfg(feature = "safe_api")]
fn encap(
pubkey_r: &Self::PublicKey,
) -> Result<(Secret<Self::SharedSecretSpec>, Self::EncapsulatedKey), UnknownCryptoError> {
x25519_hkdf_sha256::KeyPair::encap(pubkey_r)
}
fn encap_deterministic(
pubkey_r: &Self::PublicKey,
secret_ephemeral: Self::EphemeralSecret,
) -> Result<(Secret<Self::SharedSecretSpec>, Self::EncapsulatedKey), UnknownCryptoError> {
x25519_hkdf_sha256::KeyPair::encap_deterministic(pubkey_r, secret_ephemeral)
}
fn decap(
enc: &Self::EncapsulatedKey,
secret_key_r: &Self::PrivateKey,
) -> Result<Secret<Self::SharedSecretSpec>, UnknownCryptoError> {
x25519_hkdf_sha256::KeyPair::decap(enc, secret_key_r)
}
}
impl HpkeAuthKem for DhKemX25519HkdfSha256 {
#[cfg(feature = "safe_api")]
fn auth_encap(
pubkey_r: &Self::PublicKey,
secret_key_s: &Self::PrivateKey,
) -> Result<(Secret<Self::SharedSecretSpec>, Self::EncapsulatedKey), UnknownCryptoError> {
x25519_hkdf_sha256::KeyPair::auth_encap(pubkey_r, secret_key_s)
}
fn auth_encap_deterministic(
pubkey_r: &Self::PublicKey,
secret_key_s: &Self::PrivateKey,
secret_ephemeral: Self::EphemeralSecret,
) -> Result<(Secret<Self::SharedSecretSpec>, Self::EncapsulatedKey), UnknownCryptoError> {
x25519_hkdf_sha256::KeyPair::auth_encap_deterministic(
pubkey_r,
secret_key_s,
secret_ephemeral,
)
}
fn auth_decap(
enc: &Self::EncapsulatedKey,
secret_key_r: &Self::PrivateKey,
pubkey_s: &Self::PublicKey,
) -> Result<Secret<Self::SharedSecretSpec>, UnknownCryptoError> {
x25519_hkdf_sha256::KeyPair::auth_decap(enc, secret_key_r, pubkey_s)
}
}
#[derive(Debug, Clone, Copy)]
pub struct MlKem768X25519 {}
impl Sealed for MlKem768X25519 {}
impl MlKem768X25519 {
const DKP_LABEL: &[u8; 13] = b"DeriveKeyPair";
}
impl HpkeKem for MlKem768X25519 {
const KEM_ID: [u8; 2] = 0x647au16.to_be_bytes();
const NSECRET: usize = xwing::SHARED_SECRET_SIZE;
const NENC: usize = xwing::CIPHERTEXT_SIZE;
const NPK: usize = xwing::EK_SIZE;
const NSK: usize = xwing::DK_SIZE;
type PrivateKey = xwing::DecapsulationKey;
type PublicKey = xwing::EncapsulationKey;
type EncapsulatedKey = xwing::Ciphertext;
type EphemeralSecret = xwing::Eseed;
type SharedSecretSpec = xwing::XWingSharedSecret;
type KeyPair = xwing::KeyPair;
fn derive_keypair(ikm: &[u8]) -> Result<Self::KeyPair, UnknownCryptoError> {
if ikm.len() < Self::NSK {
return Err(UnknownCryptoError);
}
let mut shake = Shake256::new();
shake.absorb(ikm)?;
shake.absorb(VERSION_ID)?;
shake.absorb(b"KEM")?;
shake.absorb(&Self::KEM_ID)?;
shake.absorb(&length_prefix(Self::DKP_LABEL)?)?;
shake.absorb(Self::DKP_LABEL)?;
shake.absorb(&(Self::NSK as u16).to_be_bytes())?;
let mut seed = zeroize_wrap!([0u8; xwing::DK_SIZE]);
shake.squeeze(seed.as_mut())?;
xwing::KeyPair::try_from(&xwing::DecapsulationKey::try_from(seed.as_ref())?)
}
#[cfg(feature = "safe_api")]
fn encap(
pubkey_r: &Self::PublicKey,
) -> Result<(Secret<Self::SharedSecretSpec>, Self::EncapsulatedKey), UnknownCryptoError> {
pubkey_r.encap()
}
fn encap_deterministic(
pubkey_r: &Self::PublicKey,
secret_ephemeral: Self::EphemeralSecret,
) -> Result<(Secret<Self::SharedSecretSpec>, Self::EncapsulatedKey), UnknownCryptoError> {
pubkey_r.encap_deterministic(&secret_ephemeral)
}
fn decap(
enc: &Self::EncapsulatedKey,
secret_key_r: &Self::PrivateKey,
) -> Result<Secret<Self::SharedSecretSpec>, UnknownCryptoError> {
secret_key_r.decap(enc)
}
}