use bitcoin_hashes::{
hash160, ripemd160, sha1, sha256, sha256d, sha256t, sha512, siphash24, Hash,
};
use crate::{CommitmentProtocol, PrehashedProtocol};
pub trait CommitVerify<Msg, Protocol>
where
Self: Eq + Sized,
Protocol: CommitmentProtocol,
{
fn commit(msg: &Msg) -> Self;
#[inline]
fn verify(&self, msg: &Msg) -> bool { Self::commit(msg) == *self }
}
pub trait TryCommitVerify<Msg, Protocol>
where
Self: Eq + Sized,
Protocol: CommitmentProtocol,
{
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)
}
}
impl<Msg> CommitVerify<Msg, PrehashedProtocol> for sha1::Hash
where
Msg: AsRef<[u8]>,
{
#[inline]
fn commit(msg: &Msg) -> sha1::Hash { sha1::Hash::hash(msg.as_ref()) }
}
impl<Msg> CommitVerify<Msg, PrehashedProtocol> for ripemd160::Hash
where
Msg: AsRef<[u8]>,
{
#[inline]
fn commit(msg: &Msg) -> ripemd160::Hash {
ripemd160::Hash::hash(msg.as_ref())
}
}
impl<Msg> CommitVerify<Msg, PrehashedProtocol> for hash160::Hash
where
Msg: AsRef<[u8]>,
{
#[inline]
fn commit(msg: &Msg) -> hash160::Hash { hash160::Hash::hash(msg.as_ref()) }
}
impl<Msg> CommitVerify<Msg, PrehashedProtocol> for sha256::Hash
where
Msg: AsRef<[u8]>,
{
#[inline]
fn commit(msg: &Msg) -> sha256::Hash { sha256::Hash::hash(msg.as_ref()) }
}
impl<Msg> CommitVerify<Msg, PrehashedProtocol> for sha256d::Hash
where
Msg: AsRef<[u8]>,
{
#[inline]
fn commit(msg: &Msg) -> sha256d::Hash { sha256d::Hash::hash(msg.as_ref()) }
}
impl<Msg, T> CommitVerify<Msg, PrehashedProtocol> for sha256t::Hash<T>
where
Msg: AsRef<[u8]>,
T: sha256t::Tag,
{
#[inline]
fn commit(msg: &Msg) -> sha256t::Hash<T> {
sha256t::Hash::hash(msg.as_ref())
}
}
impl<Msg> CommitVerify<Msg, PrehashedProtocol> for siphash24::Hash
where
Msg: AsRef<[u8]>,
{
#[inline]
fn commit(msg: &Msg) -> siphash24::Hash {
siphash24::Hash::hash(msg.as_ref())
}
}
impl<Msg> CommitVerify<Msg, PrehashedProtocol> for sha512::Hash
where
Msg: AsRef<[u8]>,
{
#[inline]
fn commit(msg: &Msg) -> sha512::Hash { sha512::Hash::hash(msg.as_ref()) }
}
#[cfg(test)]
pub mod test_helpers {
use core::fmt::Debug;
use core::hash::Hash;
use std::collections::HashSet;
use bitcoin_hashes::hex::FromHex;
use super::*;
pub fn gen_messages() -> Vec<Vec<u8>> {
vec![
b"".to_vec(),
b"\x00".to_vec(),
b"test".to_vec(),
b"test*".to_vec(),
Vec::from_hex("deadbeef").unwrap(),
Vec::from_hex("deadbeef00").unwrap(),
Vec::from_hex("00deadbeef").unwrap(),
b"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798".to_vec(),
Vec::from_hex("0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798")
.unwrap(),
Vec::from_hex("02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9")
.unwrap(),
]
}
pub fn commit_verify_suite<Msg, Cmt>(messages: Vec<Msg>)
where
Msg: AsRef<[u8]> + Eq,
Cmt: CommitVerify<Msg, PrehashedProtocol> + 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 bitcoin_hashes::*;
use super::test_helpers::*;
use super::*;
#[derive(Debug, Display, Error)]
#[display(Debug)]
struct Error;
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
struct DummyHashCommitment(sha256d::Hash);
impl<T> CommitVerify<T, PrehashedProtocol> for DummyHashCommitment
where
T: AsRef<[u8]>,
{
fn commit(msg: &T) -> Self {
Self(bitcoin_hashes::Hash::hash(msg.as_ref()))
}
}
#[test]
fn test_commit_verify() {
commit_verify_suite::<Vec<u8>, DummyHashCommitment>(gen_messages());
}
#[test]
fn test_sha256_commitment() {
commit_verify_suite::<Vec<u8>, sha256::Hash>(gen_messages());
}
#[test]
fn test_sha256d_commitment() {
commit_verify_suite::<Vec<u8>, sha256d::Hash>(gen_messages());
}
#[test]
fn test_ripemd160_commitment() {
commit_verify_suite::<Vec<u8>, ripemd160::Hash>(gen_messages());
}
#[test]
fn test_hash160_commitment() {
commit_verify_suite::<Vec<u8>, hash160::Hash>(gen_messages());
}
#[test]
fn test_sha1_commitment() {
commit_verify_suite::<Vec<u8>, sha1::Hash>(gen_messages());
}
#[test]
fn test_sha512_commitment() {
commit_verify_suite::<Vec<u8>, sha512::Hash>(gen_messages());
}
#[test]
fn test_siphash24_commitment() {
commit_verify_suite::<Vec<u8>, siphash24::Hash>(gen_messages());
}
}