use core::cmp::Ordering;
use sedimentree_core::codec::{
decode::Decode, encode::EncodeFields, error::DecodeError, schema::Schema,
};
use crate::signed::{Signed, VerificationError};
#[derive(Clone, Debug)]
pub struct VerifiedSignature<T: Schema + EncodeFields + Decode> {
signed: Signed<T>,
payload: T,
}
impl<T: Schema + EncodeFields + Decode> VerifiedSignature<T> {
#[must_use = "verification result should not be discarded"]
pub fn try_from_signed(signed: &Signed<T>) -> Result<Self, VerificationError> {
signed
.issuer()
.verify_strict(signed.payload_bytes(), signed.signature())
.map_err(|_| VerificationError::InvalidSignature)?;
let payload = T::try_decode_fields(signed.fields_bytes())?;
Ok(Self {
signed: signed.clone(),
payload,
})
}
pub(crate) const fn from_parts(signed: Signed<T>, payload: T) -> Self {
Self { signed, payload }
}
#[must_use]
pub const fn issuer(&self) -> ed25519_dalek::VerifyingKey {
self.signed.issuer()
}
#[must_use]
pub const fn payload(&self) -> &T {
&self.payload
}
#[must_use]
pub fn into_payload(self) -> T {
self.payload
}
#[must_use]
pub const fn signed(&self) -> &Signed<T> {
&self.signed
}
#[must_use]
pub fn into_signed(self) -> Signed<T> {
self.signed
}
#[must_use]
pub fn into_parts(self) -> (Signed<T>, T) {
(self.signed, self.payload)
}
#[must_use = "decoded payload should not be discarded"]
pub fn try_from_trusted(signed: Signed<T>) -> Result<Self, DecodeError> {
let payload = signed.try_decode_trusted_payload()?;
Ok(Self { signed, payload })
}
}
impl<T: Schema + EncodeFields + Decode + PartialEq> PartialEq for VerifiedSignature<T> {
fn eq(&self, other: &Self) -> bool {
self.signed == other.signed
}
}
impl<T: Schema + EncodeFields + Decode + Eq> Eq for VerifiedSignature<T> {}
impl<T: Schema + EncodeFields + Decode + core::hash::Hash> core::hash::Hash
for VerifiedSignature<T>
{
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.signed.hash(state);
}
}
impl<T: Schema + EncodeFields + Decode + PartialOrd> PartialOrd for VerifiedSignature<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
match self.payload.partial_cmp(&other.payload) {
Some(Ordering::Equal) => self
.signed
.issuer()
.as_bytes()
.partial_cmp(other.signed.issuer().as_bytes()),
ord => ord,
}
}
}
#[allow(clippy::non_canonical_partial_ord_impl)]
impl<T: Schema + EncodeFields + Decode + Ord> Ord for VerifiedSignature<T> {
fn cmp(&self, other: &Self) -> Ordering {
match self.payload.cmp(&other.payload) {
Ordering::Equal => self
.signed
.issuer()
.as_bytes()
.cmp(other.signed.issuer().as_bytes()),
ord @ (Ordering::Less | Ordering::Greater) => ord,
}
}
}