use crate::generated::signatures::Signature;
use crate::generated::signatures::{DelegatedSignature, SignatureSet};
#[derive(thiserror::Error, Debug)]
pub enum SigRuntimeError {
#[error("delegation depth exceeded (max 5)")]
DelegationDepthExceeded,
#[error("invalid signature set threshold")]
InvalidSignatureSetThreshold,
#[error("verification failed")]
VerificationFailed,
}
pub fn delegated_depth(sig: &Signature) -> usize {
match sig {
Signature::Delegated(inner) => 1 + delegated_depth(&inner.signature),
_ => 0,
}
}
pub fn enforce_delegated_depth(sig: &Signature) -> Result<(), SigRuntimeError> {
if delegated_depth(sig) > 5 {
Err(SigRuntimeError::DelegationDepthExceeded)
} else {
Ok(())
}
}
impl DelegatedSignature {
pub fn new_enforced(signature: Box<Signature>, delegator: String) -> Result<Self, SigRuntimeError> {
let wrapper = Signature::Delegated(DelegatedSignature {
signature: signature.clone(),
delegator: delegator.clone()
});
enforce_delegated_depth(&wrapper)?;
Ok(DelegatedSignature { signature, delegator })
}
}
#[derive(Debug, Clone)]
pub struct SignatureSetWithThreshold {
pub inner: SignatureSet,
pub threshold: u32,
}
impl SignatureSetWithThreshold {
pub fn new(inner: SignatureSet, threshold: u32) -> Result<Self, SigRuntimeError> {
if threshold == 0 || (threshold as usize) > inner.signatures.len() {
return Err(SigRuntimeError::InvalidSignatureSetThreshold);
}
Ok(Self { inner, threshold })
}
}
pub fn count_valid_sigs(sigs: &[Box<Signature>], message: &[u8]) -> usize {
sigs.iter()
.filter(|s| {
use crate::generated::signatures::AccSignature;
match s.as_ref() {
Signature::ED25519(sig) => sig.verify(message).unwrap_or(false),
Signature::LegacyED25519(sig) => sig.verify(message).unwrap_or(false),
Signature::RCD1(sig) => sig.verify(message).unwrap_or(false),
Signature::BTC(sig) => sig.verify(message).unwrap_or(false),
Signature::BTCLegacy(sig) => sig.verify(message).unwrap_or(false),
Signature::ETH(sig) => sig.verify(message).unwrap_or(false),
Signature::RsaSha256(sig) => sig.verify(message).unwrap_or(false),
Signature::EcdsaSha256(sig) => sig.verify(message).unwrap_or(false),
Signature::TypedData(sig) => sig.verify(message).unwrap_or(false),
Signature::Receipt(sig) => sig.verify(message).unwrap_or(false),
Signature::Partition(sig) => sig.verify(message).unwrap_or(false),
Signature::Set(sig) => sig.verify(message).unwrap_or(false),
Signature::Remote(sig) => sig.verify(message).unwrap_or(false),
Signature::Delegated(sig) => sig.verify(message).unwrap_or(false),
Signature::Internal(sig) => sig.verify(message).unwrap_or(false),
Signature::Authority(sig) => sig.verify(message).unwrap_or(false),
}
})
.count()
}
pub fn evaluate_signature_set(set: &SignatureSetWithThreshold, message: &[u8]) -> Result<bool, SigRuntimeError> {
let n = set.inner.signatures.len();
if set.threshold == 0 || (set.threshold as usize) > n {
return Err(SigRuntimeError::InvalidSignatureSetThreshold);
}
let valid = count_valid_sigs(&set.inner.signatures, message) as u32;
Ok(valid >= set.threshold)
}