From 6056c16cfa1d92f0851be934712cd5baad5bf174 Mon Sep 17 00:00:00 2001 From: AntiochP <30642645+antiochp@users.noreply.github.com> Date: Sat, 9 Sep 2017 13:48:26 -0400 Subject: [PATCH] unit tests around Commitment summing (#118) * unit tests around Commitment summing * add a more complete test example with a commit_value to cover the excess --- secp256k1zkp/src/pedersen.rs | 161 +++++++++++++++++++++++++++++++++-- 1 file changed, 153 insertions(+), 8 deletions(-) diff --git a/secp256k1zkp/src/pedersen.rs b/secp256k1zkp/src/pedersen.rs index 47e4a03af..f11731688 100644 --- a/secp256k1zkp/src/pedersen.rs +++ b/secp256k1zkp/src/pedersen.rs @@ -37,19 +37,21 @@ impl_pretty_debug!(Commitment); impl Commitment { - /// Builds a Hash from a byte vector. If the vector is too short, it will be - /// completed by zeroes. If it's too long, it will be truncated. - pub fn from_vec(v: Vec) -> Commitment { - let mut h = [0; constants::PEDERSEN_COMMITMENT_SIZE]; - for i in 0..min(v.len(), constants::PEDERSEN_COMMITMENT_SIZE) { - h[i] = v[i]; + /// Builds a Hash from a byte vector. If the vector is too short, it will be + /// completed by zeroes. If it's too long, it will be truncated. + pub fn from_vec(v: Vec) -> Commitment { + let mut h = [0; constants::PEDERSEN_COMMITMENT_SIZE]; + for i in 0..min(v.len(), constants::PEDERSEN_COMMITMENT_SIZE) { + h[i] = v[i]; + } + Commitment(h) } - Commitment(h) - } + /// Uninitialized commitment, use with caution unsafe fn blank() -> Commitment { mem::uninitialized() } + /// Converts a commitment to a public key pub fn to_pubkey(&self, secp: &Secp256k1) -> Result { key::PublicKey::from_slice(secp, &self.0) @@ -441,3 +443,146 @@ impl Secp256k1 { } } } + +#[cfg(test)] +mod tests { + use Secp256k1; + use super::Commitment; + use ContextFlag; + use key::{ONE_KEY, ZERO_KEY, SecretKey}; + + use rand::os::OsRng; + + #[test] + fn test_verify_commit_sum_zero_keys() { + let secp = Secp256k1::with_caps(ContextFlag::Commit); + + fn commit(value: u64) -> Commitment { + let secp = Secp256k1::with_caps(ContextFlag::Commit); + let blinding = ZERO_KEY; + secp.commit(value, blinding).unwrap() + } + + assert!(secp.verify_commit_sum( + vec![], + vec![], + 0 + )); + + assert!(secp.verify_commit_sum( + vec![commit(5)], + vec![commit(5)], + 0 + )); + + assert!(secp.verify_commit_sum( + vec![commit(5)], + vec![commit(3)], + 2 + )); + + assert!(secp.verify_commit_sum( + vec![commit(3), commit(2)], + vec![commit(5)], + 0 + )); + + assert!(secp.verify_commit_sum( + vec![commit(2), commit(4)], + vec![commit(3), commit(2)], + 1 + )); + } + + #[test] + fn test_verify_commit_sum_one_keys() { + let secp = Secp256k1::with_caps(ContextFlag::Commit); + + fn commit(value: u64, blinding: SecretKey) -> Commitment { + let secp = Secp256k1::with_caps(ContextFlag::Commit); + secp.commit(value, blinding).unwrap() + + } + + assert!(secp.verify_commit_sum( + vec![commit(5, ONE_KEY)], + vec![commit(5, ONE_KEY)], + 0 + )); + + // we expect this not to verify + // even though the values add up to 0 + // the keys themselves do not add to 0 + assert_eq!(secp.verify_commit_sum( + vec![commit(3, ONE_KEY), commit(2, ONE_KEY)], + vec![commit(5, ONE_KEY)], + 0 + ), false); + + // to get these to verify we need to + // use the same "sum" of blinding factors on both sides + let two_key = secp.blind_sum(vec![ONE_KEY, ONE_KEY], vec![]).unwrap(); + assert!(secp.verify_commit_sum( + vec![commit(3, ONE_KEY), commit(2, ONE_KEY)], + vec![commit(5, two_key)], + 0 + )); + + // similarly here - with the blinding factors cancelling out + // the excess is simply the difference between + // the positive values and the negative values + assert!(secp.verify_commit_sum( + vec![commit(3, ONE_KEY), commit(2, ONE_KEY)], + vec![commit(4, two_key)], + 1 + )); + } + + #[test] + fn test_verify_commit_sum_random_keys() { + let secp = Secp256k1::with_caps(ContextFlag::Commit); + + fn commit(value: u64, blinding: SecretKey) -> Commitment { + let secp = Secp256k1::with_caps(ContextFlag::Commit); + secp.commit(value, blinding).unwrap() + } + + fn commit_value(value: u64) -> Commitment { + let secp = Secp256k1::with_caps(ContextFlag::Commit); + secp.commit_value(value).unwrap() + } + + let blind_pos = SecretKey::new(&secp, &mut OsRng::new().unwrap()); + let blind_neg = SecretKey::new(&secp, &mut OsRng::new().unwrap()); + + // now construct blinding factor to net out appropriately + let blind_sum = secp.blind_sum(vec![blind_pos], vec![blind_neg]).unwrap(); + + assert!(secp.verify_commit_sum( + vec![commit(5, blind_pos)], + vec![commit(3, blind_neg), commit(2, blind_sum)], + 0 + )); + + assert!(secp.verify_commit_sum( + vec![commit(6, blind_pos)], + vec![commit(3, blind_neg), commit(2, blind_sum)], + 1 + )); + + assert!(secp.verify_commit_sum( + vec![commit(5, blind_pos)], + vec![commit(4, blind_neg), commit(2, blind_sum)], + -1 + )); + + // now a more realistic example + // blinding factors net out, + // values net out except for a single excess commitment (with zero blinding factor) + assert!(secp.verify_commit_sum( + vec![commit(5, blind_pos), commit_value(1001)], + vec![commit(3, blind_neg), commit(2, blind_sum)], + 1001 + )); + } +}