use crate::errors::UnknownCryptoError;
use crate::generics::data::sealed::{Data, Sealed, TryFromBytes};
use core::fmt::Debug;
use core::marker::PhantomData;
use subtle::ConstantTimeEq;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
pub trait TypeSpec: Sealed + Sized {
#[doc(hidden)]
const NAME: &'static str;
type TypeData: Data + TryFromBytes;
#[doc(hidden)]
fn parse_bytes(bytes: &[u8]) -> Result<Self::TypeData, UnknownCryptoError> {
Self::TypeData::try_from_bytes(bytes)
}
#[doc(hidden)]
fn len(datatype: &Self::TypeData) -> usize {
datatype.len()
}
#[doc(hidden)]
fn is_empty(datatype: &Self::TypeData) -> bool {
datatype.len() == 0
}
#[doc(hidden)]
fn ct_partial_eq(lhs: &Self::TypeData, rhs: &[u8]) -> bool {
lhs.as_ref().ct_eq(rhs).into()
}
#[doc(hidden)]
fn vartime_partial_eq(lhs: &Self::TypeData, rhs: &[u8]) -> bool {
lhs.as_ref() == rhs
}
}
pub trait UnprotectedAsRef<T: ?Sized>: Sealed {
fn unprotected_as_ref(&self) -> &T;
}
impl<D: Data> UnprotectedAsRef<[u8]> for D {
fn unprotected_as_ref(&self) -> &[u8] {
self.as_ref()
}
}
pub trait GenerateSecret: TypeSpec {
#[cfg(feature = "safe_api")]
#[cfg_attr(docsrs, doc(cfg(feature = "safe_api")))]
#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
fn generate() -> Result<Secret<Self>, UnknownCryptoError>;
}
impl<T: TypeSpec + GenerateSecret> Secret<T> {
#[cfg(feature = "safe_api")]
#[cfg_attr(docsrs, doc(cfg(feature = "safe_api")))]
#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
pub fn generate() -> Result<Self, UnknownCryptoError> {
T::generate()
}
}
pub trait GeneratePublic: TypeSpec {
#[cfg(feature = "safe_api")]
#[cfg_attr(docsrs, doc(cfg(feature = "safe_api")))]
#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
fn generate() -> Result<Public<Self>, UnknownCryptoError>;
}
impl<T: TypeSpec + GeneratePublic> Public<T> {
#[cfg(feature = "safe_api")]
#[cfg_attr(docsrs, doc(cfg(feature = "safe_api")))]
#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
pub fn generate() -> Result<Self, UnknownCryptoError> {
T::generate()
}
}
pub trait KP<PrivT: TypeSpec, PubT: TypeSpec>: Debug {
fn private(&self) -> &Secret<PrivT>;
fn public(&self) -> &Public<PubT>;
}
#[derive(Clone)]
pub struct Public<T: TypeSpec> {
pub(crate) data: T::TypeData,
pub(crate) _spec: PhantomData<T>,
}
#[derive(Clone)] pub struct Secret<T: TypeSpec> {
pub(crate) data: T::TypeData,
pub(crate) _spec: PhantomData<T>,
}
impl<T: TypeSpec> Public<T> {
pub(crate) fn from_data(data: T::TypeData) -> Self {
Public {
data,
_spec: PhantomData,
}
}
pub fn len(&self) -> usize {
T::len(&self.data)
}
pub fn is_empty(&self) -> bool {
T::is_empty(&self.data)
}
}
impl<T: TypeSpec> Secret<T> {
pub(crate) fn from_data(data: T::TypeData) -> Self {
Secret {
data,
_spec: PhantomData,
}
}
pub fn len(&self) -> usize {
T::len(&self.data)
}
pub fn is_empty(&self) -> bool {
T::is_empty(&self.data)
}
pub fn unprotected_as_ref<O: ?Sized>(&self) -> &O
where
T::TypeData: UnprotectedAsRef<O>,
{
UnprotectedAsRef::unprotected_as_ref(&self.data)
}
}
impl<T: TypeSpec> PartialEq for Public<T> {
fn eq(&self, other: &Self) -> bool {
T::vartime_partial_eq(&self.data, other.data.as_ref())
}
}
impl<T: TypeSpec> Eq for Public<T> {}
impl<T: TypeSpec> PartialEq<[u8]> for Public<T> {
fn eq(&self, other: &[u8]) -> bool {
T::vartime_partial_eq(&self.data, other)
}
}
impl<T: TypeSpec> PartialEq<&[u8]> for Public<T> {
fn eq(&self, other: &&[u8]) -> bool {
T::vartime_partial_eq(&self.data, other)
}
}
impl<const N: usize, T: TypeSpec> PartialEq<&[u8; N]> for Public<T> {
fn eq(&self, other: &&[u8; N]) -> bool {
T::vartime_partial_eq(&self.data, *other)
}
}
impl<T: TypeSpec> Debug for Public<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{} {:?}", T::NAME, self.data.as_ref())
}
}
impl<T: TypeSpec> AsRef<[u8]> for Public<T> {
fn as_ref(&self) -> &[u8] {
self.data.as_ref()
}
}
impl<T: TypeSpec> TryFrom<&[u8]> for Public<T> {
type Error = UnknownCryptoError;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
Ok(Public::from_data(T::parse_bytes(bytes)?))
}
}
impl<const N: usize, T: TypeSpec> TryFrom<&[u8; N]> for Public<T> {
type Error = UnknownCryptoError;
fn try_from(bytes: &[u8; N]) -> Result<Self, Self::Error> {
Ok(Public::from_data(T::parse_bytes(bytes)?))
}
}
#[cfg(any(feature = "safe_api", feature = "alloc"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "safe_api", feature = "alloc"))))]
impl<T: TypeSpec> TryFrom<&Vec<u8>> for Public<T> {
type Error = UnknownCryptoError;
fn try_from(bytes: &Vec<u8>) -> Result<Self, Self::Error> {
Self::try_from(bytes.as_slice())
}
}
#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
impl<T: TypeSpec> serde::Serialize for Public<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{
let bytes: &[u8] = self.data.as_ref();
bytes.serialize(serializer)
}
}
#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
impl<'de, T: TypeSpec> serde::Deserialize<'de> for Public<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::de::Deserializer<'de>,
{
let bytes = Vec::<u8>::deserialize(deserializer)?;
TryFrom::try_from(bytes.as_slice()).map_err(serde::de::Error::custom)
}
}
impl<T: TypeSpec> Drop for Secret<T> {
fn drop(&mut self) {
#[cfg(feature = "zeroize")]
{
self.data.memzero();
}
}
}
impl<T: TypeSpec> PartialEq for Secret<T> {
fn eq(&self, other: &Self) -> bool {
T::ct_partial_eq(&self.data, other.data.as_ref())
}
}
impl<T: TypeSpec> Eq for Secret<T> {}
impl<T: TypeSpec> PartialEq<[u8]> for Secret<T> {
fn eq(&self, other: &[u8]) -> bool {
T::ct_partial_eq(&self.data, other)
}
}
impl<T: TypeSpec> PartialEq<&[u8]> for Secret<T> {
fn eq(&self, other: &&[u8]) -> bool {
T::ct_partial_eq(&self.data, other)
}
}
impl<const N: usize, T: TypeSpec> PartialEq<&[u8; N]> for Secret<T> {
fn eq(&self, other: &&[u8; N]) -> bool {
T::ct_partial_eq(&self.data, *other)
}
}
impl<T: TypeSpec> Debug for Secret<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{} {{***OMITTED***}}", T::NAME)
}
}
impl<T: TypeSpec> TryFrom<&[u8]> for Secret<T> {
type Error = UnknownCryptoError;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
Ok(Secret::from_data(T::parse_bytes(bytes)?))
}
}
impl<const N: usize, T: TypeSpec> TryFrom<&[u8; N]> for Secret<T> {
type Error = UnknownCryptoError;
fn try_from(bytes: &[u8; N]) -> Result<Self, Self::Error> {
Ok(Secret::from_data(T::parse_bytes(bytes)?))
}
}
#[cfg(any(feature = "safe_api", feature = "alloc"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "safe_api", feature = "alloc"))))]
impl<T: TypeSpec> TryFrom<&Vec<u8>> for Secret<T> {
type Error = UnknownCryptoError;
fn try_from(bytes: &Vec<u8>) -> Result<Self, Self::Error> {
Self::try_from(bytes.as_slice())
}
}