use amplify::Bytes32;
use sha2::Sha256;
use strict_encoding::{StrictEncode, StrictWriter};
use crate::digest::DigestExt;
use crate::CommitmentProtocol;
pub trait CommitVerify<Msg, Protocol: CommitmentProtocol>
where Self: Eq + Sized
{
fn commit(msg: &Msg) -> Self;
#[inline]
fn verify(&self, msg: &Msg) -> bool { Self::commit(msg) == *self }
}
pub trait TryCommitVerify<Msg, Protocol: CommitmentProtocol>
where Self: Eq + Sized
{
type Error: std::error::Error;
fn try_commit(msg: &Msg) -> Result<Self, Self::Error>;
#[inline]
fn try_verify(&self, msg: &Msg) -> Result<bool, Self::Error> {
Ok(Self::try_commit(msg)? == *self)
}
}
pub struct StrictEncodedProtocol;
impl CommitmentProtocol for StrictEncodedProtocol {}
impl<T> CommitVerify<T, StrictEncodedProtocol> for Bytes32
where T: StrictEncode
{
fn commit(msg: &T) -> Self {
let mut engine = Sha256::from_tag(*b"urn:lnpbp:lnpbp0007:strict:v01#A");
let w = StrictWriter::with(u32::MAX as usize, &mut engine);
msg.strict_encode(w).ok();
engine.finish().into()
}
}
#[cfg(test)]
pub(crate) mod test_helpers {
use core::fmt::Debug;
use core::hash::Hash;
use std::collections::HashSet;
use super::*;
use crate::UntaggedProtocol;
pub fn commit_verify_suite<Msg, Cmt>(messages: Vec<Msg>)
where
Msg: AsRef<[u8]> + Eq,
Cmt: CommitVerify<Msg, UntaggedProtocol> + Eq + Hash + Debug,
{
messages
.iter()
.fold(HashSet::<Cmt>::with_capacity(messages.len()), |mut acc, msg| {
let commitment = Cmt::commit(msg);
(1..10).for_each(|_| {
assert_eq!(Cmt::commit(msg), commitment);
});
assert!(commitment.verify(msg));
messages.iter().for_each(|m| {
assert_eq!(commitment.verify(m), m == msg);
});
acc.iter().for_each(|cmt| {
assert!(!cmt.verify(msg));
});
assert!(acc.insert(commitment));
acc
});
}
}
#[cfg(test)]
mod test {
use core::fmt::Debug;
use core::hash::Hash;
use amplify::confinement::SmallVec;
use sha2::Digest;
use super::test_helpers::*;
use super::*;
use crate::test_helpers::gen_messages;
use crate::UntaggedProtocol;
#[derive(Debug, Display, Error)]
#[display(Debug)]
struct Error;
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
struct DummyHashCommitment([u8; 32]);
impl<T> CommitVerify<T, UntaggedProtocol> for DummyHashCommitment
where T: AsRef<[u8]>
{
fn commit(msg: &T) -> Self { Self(Sha256::digest(msg.as_ref()).into()) }
}
#[test]
fn test_commit_verify() {
commit_verify_suite::<SmallVec<u8>, DummyHashCommitment>(gen_messages());
}
}