use crate::{DecapsulationKey, EncapsulationKey};
use kem::{
Decapsulate, Decapsulator, Encapsulate, Generate, InvalidKey, Kem, Key, KeyExport, KeyInit,
KeySizeUser, TryKeyInit,
common::array::{Array, sizes::U32},
};
use rand_core::{CryptoRng, TryCryptoRng};
use x25519::{PublicKey, StaticSecret};
#[cfg(doc)]
use crate::Expander;
type Ciphertext = Array<u8, U32>;
type SharedKey = Array<u8, U32>;
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, PartialOrd, Ord)]
pub struct X25519Kem;
impl Kem for X25519Kem {
type DecapsulationKey = X25519DecapsulationKey;
type EncapsulationKey = X25519EncapsulationKey;
type CiphertextSize = U32;
type SharedKeySize = U32;
}
pub type X25519DecapsulationKey = DecapsulationKey<StaticSecret, PublicKey>;
impl Decapsulator for X25519DecapsulationKey {
type Kem = X25519Kem;
fn encapsulation_key(&self) -> &X25519EncapsulationKey {
&self.ek
}
}
impl KeySizeUser for X25519DecapsulationKey {
type KeySize = U32;
}
impl KeyInit for X25519DecapsulationKey {
fn new(key: &Key<Self>) -> Self {
StaticSecret::from(key.0).into()
}
}
impl KeyExport for X25519DecapsulationKey {
fn to_bytes(&self) -> Key<Self> {
self.dk.to_bytes().into()
}
}
impl Generate for X25519DecapsulationKey {
fn try_generate_from_rng<R: TryCryptoRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
let key = Key::<Self>::try_generate_from_rng(rng)?;
Ok(StaticSecret::from(key.0).into())
}
}
impl Decapsulate for X25519DecapsulationKey {
fn decapsulate(&self, encapsulated_key: &Ciphertext) -> SharedKey {
let public_key = PublicKey::from(encapsulated_key.0);
self.dk.diffie_hellman(&public_key).to_bytes().into()
}
}
pub type X25519EncapsulationKey = EncapsulationKey<PublicKey>;
impl KeySizeUser for X25519EncapsulationKey {
type KeySize = U32;
}
impl TryKeyInit for X25519EncapsulationKey {
fn new(encapsulation_key: &Key<Self>) -> Result<Self, InvalidKey> {
Ok(Self(PublicKey::from(encapsulation_key.0)))
}
}
impl KeyExport for X25519EncapsulationKey {
fn to_bytes(&self) -> Key<Self> {
self.0.to_bytes().into()
}
}
impl Encapsulate for X25519EncapsulationKey {
type Kem = X25519Kem;
fn encapsulate_with_rng<R>(&self, rng: &mut R) -> (Ciphertext, SharedKey)
where
R: CryptoRng + ?Sized,
{
let sk = StaticSecret::random_from_rng(rng);
let pk = PublicKey::from(&sk);
let ss = sk.diffie_hellman(&self.0);
(pk.to_bytes().into(), ss.to_bytes().into())
}
}