use commonware_codec::{FixedSize, Read, ReadExt, Write};
use rand_core::CryptoRngCore;
use zeroize::ZeroizeOnDrop;
#[derive(ZeroizeOnDrop)]
pub struct SharedSecret {
inner: x25519_dalek::SharedSecret,
}
impl AsRef<[u8]> for SharedSecret {
fn as_ref(&self) -> &[u8] {
self.inner.as_bytes().as_slice()
}
}
#[cfg_attr(test, derive(PartialEq))]
pub struct EphemeralPublicKey {
inner: x25519_dalek::PublicKey,
}
impl Write for EphemeralPublicKey {
fn write(&self, buf: &mut impl bytes::BufMut) {
buf.put_slice(self.inner.as_bytes());
}
}
impl FixedSize for EphemeralPublicKey {
const SIZE: usize = 32;
}
impl Read for EphemeralPublicKey {
type Cfg = ();
fn read_cfg(
buf: &mut impl bytes::Buf,
_cfg: &Self::Cfg,
) -> Result<Self, commonware_codec::Error> {
let bytes: [u8; 32] = ReadExt::read(buf)?;
Ok(Self {
inner: bytes.into(),
})
}
}
pub struct SecretKey {
inner: x25519_dalek::EphemeralSecret,
}
impl SecretKey {
pub fn new(rng: impl CryptoRngCore) -> Self {
Self {
inner: x25519_dalek::EphemeralSecret::random_from_rng(rng),
}
}
pub fn public(&self) -> EphemeralPublicKey {
EphemeralPublicKey {
inner: (&self.inner).into(),
}
}
pub fn exchange(self, other: &EphemeralPublicKey) -> Option<SharedSecret> {
let out = self.inner.diffie_hellman(&other.inner);
if !out.was_contributory() {
return None;
}
Some(SharedSecret { inner: out })
}
}