#![no_std]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![doc = include_str!("../README.md")]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
)]
mod error;
mod expander;
pub use crate::{
error::Error,
expander::{EagerHash, Expander, HpkeKemId, InvalidLength},
};
pub use kem::{self, Ciphertext, Decapsulator, Encapsulate, Generate, Kem, TryDecapsulate};
use rand_core::CryptoRng;
#[cfg(feature = "ecdh")]
mod ecdh_kem;
#[cfg(feature = "x25519")]
mod x25519_kem;
#[cfg(feature = "ecdh")]
pub use ecdh_kem::*;
#[cfg(feature = "x25519")]
pub use x25519_kem::*;
#[cfg(feature = "zeroize")]
use zeroize::{Zeroize, ZeroizeOnDrop};
#[derive(Clone, Copy, Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Default)]
pub struct DecapsulationKey<DK, EK> {
dk: DK,
ek: EncapsulationKey<EK>,
}
impl<DK, EK> DecapsulationKey<DK, EK> {
pub fn decapsulate_and_expand<D>(
&self,
salt: &[u8],
label: &[u8],
ciphertext: &Ciphertext<<Self as Decapsulator>::Kem>,
) -> Result<Expander<D>, Error>
where
Self: TryDecapsulate<Error = Error> + Decapsulator<Kem: HpkeKemId>,
D: EagerHash,
{
let ikm = self.try_decapsulate(ciphertext)?;
let ex = Expander::new_labeled_hpke::<<Self as Decapsulator>::Kem>(salt, label, &ikm)?;
Ok(ex)
}
pub fn into_inner(self) -> DK {
self.dk
}
}
impl<DK, EK> AsRef<EncapsulationKey<EK>> for DecapsulationKey<DK, EK> {
fn as_ref(&self) -> &EncapsulationKey<EK> {
&self.ek
}
}
impl<DK, EK> From<DK> for DecapsulationKey<DK, EK>
where
EK: for<'a> From<&'a DK>,
{
fn from(dk: DK) -> Self {
let ek = EncapsulationKey(EK::from(&dk));
Self { dk, ek }
}
}
#[derive(Clone, Copy, Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Default)]
pub struct EncapsulationKey<EK>(EK);
impl<EK> EncapsulationKey<EK> {
pub fn into_inner(self) -> EK {
self.0
}
}
impl<EK> EncapsulationKey<EK>
where
Self: Encapsulate<Kem: HpkeKemId>,
{
#[cfg(feature = "getrandom")]
pub fn encapsulate_and_expand<D: EagerHash>(
&self,
salt: &[u8],
label: &[u8],
) -> Result<(Ciphertext<<Self as Encapsulate>::Kem>, Expander<D>), InvalidLength> {
let (ct, ikm) = self.encapsulate();
let expander = Expander::new_labeled_hpke::<<Self as Encapsulate>::Kem>(salt, label, &ikm)?;
Ok((ct, expander))
}
pub fn encapsulate_with_rng_and_expand<D: EagerHash, R: CryptoRng + ?Sized>(
&self,
rng: &mut R,
salt: &[u8],
label: &[u8],
) -> Result<(Ciphertext<<Self as Encapsulate>::Kem>, Expander<D>), InvalidLength> {
let (ct, ikm) = self.encapsulate_with_rng(rng);
let expander = Expander::new_labeled_hpke::<<Self as Encapsulate>::Kem>(salt, label, &ikm)?;
Ok((ct, expander))
}
}
impl<EK> From<EK> for EncapsulationKey<EK> {
fn from(inner: EK) -> Self {
Self(inner)
}
}
#[cfg(feature = "zeroize")]
impl<DK: Zeroize, EK> Zeroize for DecapsulationKey<DK, EK> {
fn zeroize(&mut self) {
self.dk.zeroize();
}
}
#[cfg(feature = "zeroize")]
impl<DK: ZeroizeOnDrop, EK> ZeroizeOnDrop for DecapsulationKey<DK, EK> {}