From 87cd0e5c587dcdbf9a49111dd33a700a7b57f9d8 Mon Sep 17 00:00:00 2001 From: AntiochP <30642645+antiochp@users.noreply.github.com> Date: Sun, 10 Sep 2017 14:31:41 -0400 Subject: [PATCH] added basic tests around range_proof (#121) Pass nonce in to range_proof (we need it for rewind_range_proof, at least for testing) --- core/src/core/block.rs | 3 +- core/src/core/build.rs | 6 ++- pool/src/graph.rs | 2 +- pool/src/pool.rs | 2 +- secp256k1zkp/src/pedersen.rs | 89 ++++++++++++++++++++++++++++++++---- 5 files changed, 87 insertions(+), 15 deletions(-) diff --git a/core/src/core/block.rs b/core/src/core/block.rs index 9fb015e16..790f7944d 100644 --- a/core/src/core/block.rs +++ b/core/src/core/block.rs @@ -458,7 +458,8 @@ impl Block { let sig = try!(secp.sign(&msg, &skey)); let commit = secp.commit(REWARD, skey).unwrap(); //let switch_commit = secp.switch_commit(skey).unwrap(); - let rproof = secp.range_proof(0, REWARD, skey, commit); + let nonce = secp.nonce(); + let rproof = secp.range_proof(0, REWARD, skey, commit, nonce); let output = Output { features: COINBASE_OUTPUT, diff --git a/core/src/core/build.rs b/core/src/core/build.rs index f88b49285..060053152 100644 --- a/core/src/core/build.rs +++ b/core/src/core/build.rs @@ -110,7 +110,8 @@ pub fn input_rand(value: u64) -> Box { pub fn output(value: u64, blinding: SecretKey) -> Box { Box::new(move |build, (tx, sum)| -> (Transaction, BlindSum) { let commit = build.secp.commit(value, blinding).unwrap(); - let rproof = build.secp.range_proof(0, value, blinding, commit); + let nonce = build.secp.nonce(); + let rproof = build.secp.range_proof(0, value, blinding, commit, nonce); (tx.with_output(Output { features: DEFAULT_OUTPUT, commit: commit, @@ -127,7 +128,8 @@ pub fn output_rand(value: u64) -> Box { Box::new(move |build, (tx, sum)| -> (Transaction, BlindSum) { let blinding = SecretKey::new(&build.secp, &mut build.rng); let commit = build.secp.commit(value, blinding).unwrap(); - let rproof = build.secp.range_proof(0, value, blinding, commit); + let nonce = build.secp.nonce(); + let rproof = build.secp.range_proof(0, value, blinding, commit, nonce); (tx.with_output(Output { features: DEFAULT_OUTPUT, commit: commit, diff --git a/pool/src/graph.rs b/pool/src/graph.rs index 7c81c5cf8..0b68bbab2 100644 --- a/pool/src/graph.rs +++ b/pool/src/graph.rs @@ -233,7 +233,7 @@ mod tests { let outputs = vec![core::transaction::Output{ features: core::transaction::DEFAULT_OUTPUT, commit: output_commit, - proof: ec.range_proof(0, 100, key::ZERO_KEY, output_commit)}]; + proof: ec.range_proof(0, 100, key::ZERO_KEY, output_commit, ec.nonce())}]; let test_transaction = core::transaction::Transaction::new(inputs, outputs, 5); diff --git a/pool/src/pool.rs b/pool/src/pool.rs index ebf588be6..de1ae8b0f 100644 --- a/pool/src/pool.rs +++ b/pool/src/pool.rs @@ -892,7 +892,7 @@ mod tests { transaction::Output{ features: transaction::DEFAULT_OUTPUT, commit: output_commitment, - proof: ec.range_proof(0, value, output_key, output_commitment)} + proof: ec.range_proof(0, value, output_key, output_commitment, ec.nonce())} } /// Makes a SecretKey from a single u64 diff --git a/secp256k1zkp/src/pedersen.rs b/secp256k1zkp/src/pedersen.rs index f11731688..1708ba611 100644 --- a/secp256k1zkp/src/pedersen.rs +++ b/secp256k1zkp/src/pedersen.rs @@ -163,6 +163,7 @@ impl RangeProof { } /// The range that was proven +#[derive(Debug)] pub struct ProofRange { /// Min value that was proven pub min: u64, @@ -306,20 +307,25 @@ impl Secp256k1 { SecretKey::from_slice(self, &ret) } + /// Convenience function for generating a random nonce for a range proof. + /// We will need the nonce later if we want to rewind the range proof. + pub fn nonce(&self) -> [u8; 32] { + let mut rng = OsRng::new().unwrap(); + let mut nonce = [0u8; 32]; + rng.fill_bytes(&mut nonce); + nonce + } + /// Produces a range proof for the provided value, using min and max /// bounds, relying /// on the blinding factor and commitment. pub fn range_proof(&self, - min: u64, - value: u64, - blind: SecretKey, - commit: Commitment) - -> RangeProof { - - let mut rng = OsRng::new().unwrap(); - let mut nonce = [0u8; 32]; - rng.fill_bytes(&mut nonce); - + min: u64, + value: u64, + blind: SecretKey, + commit: Commitment, + nonce: [u8; 32]) + -> RangeProof { let mut retried = false; let mut proof = [0; constants::MAX_PROOF_SIZE]; let mut plen = constants::MAX_PROOF_SIZE as i32; @@ -585,4 +591,67 @@ mod tests { 1001 )); } + + #[test] + fn test_commit_sum() { + 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() + } + + let blind_a = SecretKey::new(&secp, &mut OsRng::new().unwrap()); + let blind_b = SecretKey::new(&secp, &mut OsRng::new().unwrap()); + + let commit_a = commit(3, blind_a); + let commit_b = commit(2, blind_b); + + let blind_c = secp.blind_sum(vec![blind_a, blind_b], vec![]).unwrap(); + + let commit_c = commit(3 + 2, blind_c); + + let commit_d = secp.commit_sum(vec![commit_a, commit_b], vec![]).unwrap(); + assert_eq!(commit_c, commit_d); + } + + #[test] + fn test_range_proof() { + let secp = Secp256k1::with_caps(ContextFlag::Commit); + let blinding = SecretKey::new(&secp, &mut OsRng::new().unwrap()); + + let commit = secp.commit(7, blinding).unwrap(); + let nonce = secp.nonce(); + let range_proof = secp.range_proof(0, 7, blinding, commit, nonce); + let proof_range = secp.verify_range_proof(commit, range_proof).unwrap(); + + assert_eq!(proof_range.min, 0); + + let proof_info = secp.range_proof_info(range_proof); + assert!(proof_info.success); + assert_eq!(proof_info.min, 0); + // check we get no information back for the value here + assert_eq!(proof_info.value, 0); + + let proof_info = secp.rewind_range_proof(commit, range_proof, nonce); + assert!(proof_info.success); + assert_eq!(proof_info.min, 0); + assert_eq!(proof_info.value, 7); + + // check we cannot rewind a range proof without the original nonce + let bad_nonce = secp.nonce(); + let bad_info = secp.rewind_range_proof(commit, range_proof, bad_nonce); + assert_eq!(bad_info.success, false); + assert_eq!(bad_info.value, 0); + + // check we can construct and verify a range proof on value 0 + let commit = secp.commit(0, blinding).unwrap(); + let nonce = secp.nonce(); + let range_proof = secp.range_proof(0, 0, blinding, commit, nonce); + let proof_range = secp.verify_range_proof(commit, range_proof).unwrap(); + let proof_info = secp.rewind_range_proof(commit, range_proof, nonce); + assert!(proof_info.success); + assert_eq!(proof_info.min, 0); + assert_eq!(proof_info.value, 0); + } }