use core::fmt;
use subtle::ConstantTimeEq;
use zeroize::Zeroize;
use crate::Error;
use crate::suite::sealed::{Bytes as _, Group as _};
use crate::suite::{Bytes, Group, Point, Suite};
fn sized<B: Bytes>(bytes: &[u8]) -> Result<B, Error> {
B::try_from(bytes).map_err(|_| Error::Length {
expected: size_of::<B>(),
actual: bytes.len(),
})
}
pub(crate) trait SharePoint<S: Suite> {
fn point(&self) -> Result<Point<S>, Error>;
}
macro_rules! share {
($(#[$doc:meta])* $name:ident) => {
$(#[$doc])*
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct $name<S: Suite>(S::Share);
impl<S: Suite> $name<S> {
pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
let share: S::Share = sized(bytes)?;
Group::<S>::decode(share.as_ref()).ok_or(Error::InvalidPoint)?;
Ok(Self(share))
}
#[must_use]
pub fn as_bytes(&self) -> &S::Share {
&self.0
}
pub(crate) fn from_point(point: &Point<S>) -> Result<Self, Error> {
let mut share = S::Share::zeroed();
Group::<S>::encode(point, share.as_mut()).ok_or(Error::DegenerateShare)?;
Ok(Self(share))
}
}
impl<S: Suite> SharePoint<S> for $name<S> {
fn point(&self) -> Result<Point<S>, Error> {
Group::<S>::decode(self.0.as_ref()).ok_or(Error::InvalidPoint)
}
}
impl<S: Suite> AsRef<[u8]> for $name<S> {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
};
}
share!(
ShareP
);
share!(
ShareV
);
macro_rules! confirmation {
($(#[$doc:meta])* $name:ident) => {
$(#[$doc])*
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct $name<S: Suite>(S::Confirmation);
impl<S: Suite> $name<S> {
pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
sized(bytes).map(Self)
}
#[must_use]
pub fn as_bytes(&self) -> &S::Confirmation {
&self.0
}
pub(crate) fn new(tag: S::Confirmation) -> Self {
Self(tag)
}
pub(crate) fn check(&self, expected: &S::Confirmation) -> Result<(), Error> {
if bool::from(self.0.as_ref().ct_eq(expected.as_ref())) {
Ok(())
} else {
Err(Error::ConfirmationFailed)
}
}
}
impl<S: Suite> AsRef<[u8]> for $name<S> {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
};
}
confirmation!(
ConfirmP
);
confirmation!(
ConfirmV
);
pub struct SharedKey<S: Suite>(S::SharedKey);
impl<S: Suite> SharedKey<S> {
pub(crate) fn new(key: S::SharedKey) -> Self {
Self(key)
}
#[must_use]
pub fn as_bytes(&self) -> &S::SharedKey {
&self.0
}
}
impl<S: Suite> Drop for SharedKey<S> {
fn drop(&mut self) {
self.0.zeroize();
}
}
impl<S: Suite> fmt::Debug for SharedKey<S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("SharedKey(..)")
}
}