use crate::{CommitEncode, CommitmentProtocol};
pub trait VerifyEq {
fn verify_eq(&self, other: &Self) -> bool;
}
impl<T> VerifyEq for T
where
T: Eq,
{
fn verify_eq(&self, other: &Self) -> bool { self == other }
}
pub trait EmbedCommitProof<Msg, Container, Protocol>
where
Self: Sized + VerifyEq,
Container: EmbedCommitVerify<Msg, Protocol>,
Msg: CommitEncode,
Protocol: CommitmentProtocol,
{
fn restore_original_container(
&self,
commit_container: &Container,
) -> Result<Container, Container::VerifyError>;
}
pub trait EmbedCommitVerify<Msg, Protocol>
where
Self: Sized,
Msg: CommitEncode,
Protocol: CommitmentProtocol,
{
type Proof: EmbedCommitProof<Msg, Self, Protocol>;
type CommitError: std::error::Error;
type VerifyError: std::error::Error + From<Self::CommitError>;
fn embed_commit(
&mut self,
msg: &Msg,
) -> Result<Self::Proof, Self::CommitError>;
#[inline]
fn verify(
&self,
msg: &Msg,
proof: Self::Proof,
) -> Result<bool, Self::VerifyError>
where
Self: VerifyEq,
Self::Proof: VerifyEq,
{
let mut container_prime = proof.restore_original_container(self)?;
let proof_prime = container_prime.embed_commit(msg)?;
Ok(proof_prime.verify_eq(&proof) && self.verify_eq(&container_prime))
}
#[doc(hidden)]
fn _phantom(_: Protocol) {
unimplemented!(
"EmbedCommitVerify::_phantom is a marker method which must not be \
used"
)
}
}
#[cfg(test)]
pub mod test_helpers {
use core::fmt::Debug;
use core::hash::Hash;
use std::collections::HashSet;
use bitcoin_hashes::sha256::Midstate;
use super::*;
use crate::convolve_commit::{ConvolveCommitProof, ConvolveCommitVerify};
pub enum TestProtocol {}
impl CommitmentProtocol for TestProtocol {
const HASH_TAG_MIDSTATE: Option<Midstate> = Some(Midstate([0u8; 32]));
}
pub const SUPPLEMENT: [u8; 32] = [0xFFu8; 32];
pub fn embed_commit_verify_suite<Msg, Container>(
messages: Vec<Msg>,
container: Container,
) where
Msg: AsRef<[u8]> + CommitEncode + Eq + Clone,
Container:
EmbedCommitVerify<Msg, TestProtocol> + Eq + Hash + Debug + Clone,
Container::Proof: Clone,
{
messages.iter().fold(
HashSet::<Container>::with_capacity(messages.len()),
|mut acc, msg| {
let mut commitment = container.clone();
let proof = commitment.embed_commit(msg).unwrap();
(1..10).for_each(|_| {
let mut commitment_prime = container.clone();
commitment_prime.embed_commit(msg).unwrap();
assert_eq!(commitment_prime, commitment);
});
assert!(commitment.clone().verify(msg, proof.clone()).unwrap());
messages.iter().for_each(|m| {
assert_eq!(
commitment.clone().verify(m, proof.clone()).unwrap(),
m == msg
);
});
acc.iter().for_each(|cmt| {
assert!(!cmt.clone().verify(msg, proof.clone()).unwrap());
});
assert!(acc.insert(commitment));
acc
},
);
}
pub fn convolve_commit_verify_suite<Msg, Source>(
messages: Vec<Msg>,
container: Source,
) where
Msg: AsRef<[u8]> + CommitEncode + Eq + Clone,
Source: ConvolveCommitVerify<Msg, [u8; 32], TestProtocol>
+ VerifyEq
+ Eq
+ Hash
+ Debug
+ Clone,
Source::Commitment: Clone + Debug + Hash + VerifyEq + Eq,
[u8; 32]:
ConvolveCommitProof<Msg, Source, TestProtocol, Suppl = [u8; 32]>,
{
messages.iter().fold(
HashSet::<Source::Commitment>::with_capacity(messages.len()),
|mut acc, msg| {
let (commitment, _) =
container.convolve_commit(&SUPPLEMENT, msg).unwrap();
(1..10).for_each(|_| {
let (commitment_prime, _) =
container.convolve_commit(&SUPPLEMENT, msg).unwrap();
assert_eq!(commitment_prime, commitment);
});
assert!(SUPPLEMENT.verify(msg, commitment.clone()).unwrap());
messages.iter().for_each(|m| {
assert_eq!(
SUPPLEMENT.verify(m, commitment.clone()).unwrap(),
m == msg
);
});
acc.iter().for_each(|commitment| {
assert!(!SUPPLEMENT
.verify(msg, commitment.clone())
.unwrap());
});
assert!(acc.insert(commitment));
acc
},
);
}
}
#[cfg(test)]
mod test {
use core::fmt::Debug;
use bitcoin_hashes::{sha256, Hash, HashEngine};
use super::test_helpers::*;
use super::*;
use crate::commit_verify::test_helpers::gen_messages;
use crate::convolve_commit::{ConvolveCommitProof, ConvolveCommitVerify};
#[derive(Clone, PartialEq, Eq, Debug, Hash, Error, Display)]
#[display("error")]
struct Error;
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
struct DummyVec(Vec<u8>);
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
struct DummyProof(Vec<u8>);
impl<T> EmbedCommitProof<T, DummyVec, TestProtocol> for DummyProof
where
T: AsRef<[u8]> + Clone + CommitEncode,
{
fn restore_original_container(
&self,
_: &DummyVec,
) -> Result<DummyVec, Error> {
Ok(DummyVec(self.0.clone()))
}
}
impl<T> EmbedCommitVerify<T, TestProtocol> for DummyVec
where
T: AsRef<[u8]> + Clone + CommitEncode,
{
type Proof = DummyProof;
type CommitError = Error;
type VerifyError = Error;
fn embed_commit(
&mut self,
msg: &T,
) -> Result<Self::Proof, Self::CommitError> {
let proof = self.0.clone();
let result = &mut self.0;
result.extend(msg.as_ref());
Ok(DummyProof(proof))
}
}
impl<T> ConvolveCommitVerify<T, [u8; 32], TestProtocol> for DummyVec
where
T: AsRef<[u8]> + Clone + CommitEncode,
{
type Commitment = sha256::Hash;
type CommitError = Error;
fn convolve_commit(
&self,
supplement: &[u8; 32],
msg: &T,
) -> Result<(Self::Commitment, [u8; 32]), Self::CommitError> {
let mut engine = sha256::Hash::engine();
engine.input(TestProtocol::HASH_TAG_MIDSTATE.unwrap().as_ref());
engine.input(supplement);
engine.input(msg.as_ref());
Ok((sha256::Hash::from_engine(engine), *supplement))
}
}
impl<T> ConvolveCommitProof<T, DummyVec, TestProtocol> for [u8; 32]
where
T: AsRef<[u8]> + Clone + CommitEncode,
{
type Suppl = [u8; 32];
fn restore_original(&self, _: &sha256::Hash) -> DummyVec {
DummyVec(vec![])
}
fn extract_supplement(&self) -> &Self::Suppl { self }
}
#[test]
fn test_embed_commit() {
embed_commit_verify_suite::<Vec<u8>, DummyVec>(
gen_messages(),
DummyVec(vec![]),
);
}
#[test]
fn test_convolve_commit() {
convolve_commit_verify_suite::<Vec<u8>, DummyVec>(
gen_messages(),
DummyVec(vec![0xC0; 15]),
);
}
}