use bincode::Result;
use serde::Serialize;
use sha2::{Digest, Sha256};
pub trait HashCommitmentScheme<T: Serialize> {
fn commit(&self) -> Result<Vec<u8>>;
fn verify(&self, com: &[u8], s: &T, r: &[u8]) -> Result<bool>;
}
pub struct SHA256Commitment<'a, T: 'a + Serialize> {
s: &'a T,
r: &'a [u8],
}
impl<'a, T: 'a + Serialize> SHA256Commitment<'a, T> {
pub fn new(s: &'a T, r: &'a [u8]) -> SHA256Commitment<'a, T> {
SHA256Commitment { s, r }
}
fn forge_commitment(&self, s: &T, r: &[u8]) -> Result<Vec<u8>> {
let binary_encoded_s = bincode::serialize(s)?;
let hash = Sha256::new()
.chain_update(binary_encoded_s.as_slice())
.chain_update(r)
.finalize();
Ok(hash.as_slice().to_vec())
}
}
impl<'a, T: 'a + Serialize> HashCommitmentScheme<T> for SHA256Commitment<'a, T> {
fn commit(&self) -> Result<Vec<u8>> {
self.forge_commitment(self.s, self.r)
}
fn verify(&self, com: &[u8], s: &T, r: &[u8]) -> Result<bool> {
let expected_commitment = self.forge_commitment(s, r)?;
Ok(expected_commitment == com)
}
}
#[cfg(test)]
mod tests {
use super::{HashCommitmentScheme, SHA256Commitment};
use hex_literal::hex;
#[test]
fn it_commits_correctly() {
let s: [u8; 4] = [52, 50, 52, 50]; let r: [u8; 4] = [50, 52, 50, 52];
let party = SHA256Commitment::new(&s, &r);
let commit = party.commit();
assert_eq!(commit.is_ok(), true);
assert_eq!(
commit.unwrap().as_slice(),
hex!("f4417d2878a0e2da0393e604b24a98627fd22506089baa83c165f9ac7b336fe9")
)
}
#[test]
fn it_verifies_valid_commitment() {
let s: [u8; 4] = [52, 50, 52, 50]; let r: [u8; 4] = [50, 52, 50, 52];
let party = SHA256Commitment::new(&s, &r);
let commit = party.commit();
let verification = party.verify(&commit.unwrap(), &s, &r);
assert_eq!(verification.is_ok(), true);
assert_eq!(verification.unwrap(), true)
}
#[test]
fn it_fails_to_verify_due_to_invalid_random() {
let s: [u8; 4] = [52, 50, 52, 50]; let r: [u8; 4] = [50, 52, 50, 52];
let party = SHA256Commitment::new(&s, &r);
let commit = party.commit();
let fake_r: [u8; 4] = [66, 68, 66, 68];
let verification = party.verify(&commit.unwrap(), &s, &fake_r);
assert_eq!(verification.is_ok(), true);
assert_eq!(verification.unwrap(), false)
}
#[test]
fn it_fails_to_verify_due_to_invalid_secret() {
let s: [u8; 4] = [52, 50, 52, 50]; let r: [u8; 4] = [50, 52, 50, 52];
let party = SHA256Commitment::new(&s, &r);
let commit = party.commit();
let fake_s: [u8; 4] = [66, 68, 66, 68];
let verification = party.verify(&commit.unwrap(), &fake_s, &r);
assert_eq!(verification.is_ok(), true);
assert_eq!(verification.unwrap(), false)
}
}