From e561fbc25a1bbdb35e67cdd5ed4efaeb8d52d094 Mon Sep 17 00:00:00 2001 From: Sam Kim Date: Thu, 23 Dec 2021 10:55:57 -0500 Subject: [PATCH] feat: add test for fee proof --- zk-token-sdk/src/sigma_proofs/fee_proof.rs | 205 ++++++++++++--------- 1 file changed, 121 insertions(+), 84 deletions(-) diff --git a/zk-token-sdk/src/sigma_proofs/fee_proof.rs b/zk-token-sdk/src/sigma_proofs/fee_proof.rs index 2f909a6d7..eacae1ff3 100644 --- a/zk-token-sdk/src/sigma_proofs/fee_proof.rs +++ b/zk-token-sdk/src/sigma_proofs/fee_proof.rs @@ -28,12 +28,12 @@ impl FeeProof { pub fn new( amount_fee: u64, max_fee: u64, - commitment_fee: PedersenCommitment, - opening_fee: PedersenOpening, - commitment_delta_real: PedersenCommitment, - opening_delta_real: PedersenOpening, - commitment_delta_claimed: PedersenCommitment, - opening_delta_claimed: PedersenOpening, + commitment_fee: &PedersenCommitment, + opening_fee: &PedersenOpening, + commitment_delta_real: &PedersenCommitment, + opening_delta_real: &PedersenOpening, + commitment_delta_claimed: &PedersenCommitment, + opening_delta_claimed: &PedersenOpening, transcript: &mut Transcript, ) -> Self { // extract the relevant scalar and Ristretto points from the input @@ -46,11 +46,11 @@ impl FeeProof { let C_max = commitment_fee.get_point(); let r_max = opening_fee.get_scalar(); - let C_delta_real = commitment_fee.get_point(); - let r_delta_real = opening_fee.get_scalar(); + let C_delta_real = commitment_delta_real.get_point(); + let r_delta_real = opening_delta_real.get_scalar(); - let C_delta_claimed = commitment_fee.get_point(); - let r_delta_claimed = opening_fee.get_scalar(); + let C_delta_claimed = commitment_delta_claimed.get_point(); + let r_delta_claimed = opening_delta_claimed.get_scalar(); // record public values in transcript // @@ -61,17 +61,19 @@ impl FeeProof { // generate z values depending on whether the fee exceeds max fee or not // - // TODO: use constant time conditional + // TODO: must implement this for constant time if amount_fee < max_fee { // simulate max proof let z_max = Scalar::random(&mut OsRng); let c_max = Scalar::random(&mut OsRng); let Y_max = - RistrettoPoint::multiscalar_mul(vec![z_max, c_max, c_max * x], vec![H, C_max, G]) + RistrettoPoint::multiscalar_mul(vec![z_max, -c_max, c_max * m], vec![H, C_max, G]) .compress(); let fee_max_proof = FeeMaxProof { - Y_max, z_max, + Y_max, + z_max, + c_max, }; // generate equality proof @@ -92,8 +94,8 @@ impl FeeProof { let c_equality = c - c_max; let z_x = c_equality * x + y_x; - let z_delta_real = c_equality * x + y_delta_real; - let z_delta_claimed = c_equality * x + y_delta_claimed; + let z_delta_real = c_equality * r_delta_real + y_delta_real; + let z_delta_claimed = c_equality * r_delta_claimed + y_delta_claimed; let fee_equality_proof = FeeEqualityProof { Y_delta_real, @@ -107,7 +109,6 @@ impl FeeProof { fee_max_proof, fee_equality_proof, } - } else { // simulate equality proof let z_x = Scalar::random(&mut OsRng); @@ -149,7 +150,9 @@ impl FeeProof { let z_max = c_max * r_max + y_max; let fee_max_proof = FeeMaxProof { - Y_max, z_max, + Y_max, + z_max, + c_max, }; Self { @@ -158,6 +161,76 @@ impl FeeProof { } } } + + pub fn verify( + self, + max_fee: u64, + commitment_fee: PedersenCommitment, + commitment_delta_real: PedersenCommitment, + commitment_delta_claimed: PedersenCommitment, + transcript: &mut Transcript, + ) -> Result<(), ProofError> { + // extract the relevant scalar and Ristretto points from the input + let G = PedersenBase::default().G; + let H = PedersenBase::default().H; + + let m = Scalar::from(max_fee); + + let C_max = commitment_fee.get_point(); + let C_delta_real = commitment_delta_real.get_point(); + let C_delta_claimed = commitment_delta_claimed.get_point(); + + // record public values in transcript + // + // TODO: consider committing to these points outside this method + transcript.validate_and_append_point(b"C_max", &C_max.compress())?; + transcript.validate_and_append_point(b"C_delta_real", &C_delta_real.compress())?; + transcript.validate_and_append_point(b"C_delta_claimed", &C_delta_claimed.compress())?; + + transcript.validate_and_append_point(b"Y_max", &self.fee_max_proof.Y_max)?; + transcript + .validate_and_append_point(b"Y_delta_real", &self.fee_equality_proof.Y_delta_real)?; + transcript.validate_and_append_point( + b"Y_delta_claimed", + &self.fee_equality_proof.Y_delta_claimed, + )?; + + let Y_max = self + .fee_max_proof + .Y_max + .decompress() + .ok_or(ProofError::VerificationError)?; + let z_max = self.fee_max_proof.z_max; + + let Y_delta_real = self + .fee_equality_proof + .Y_delta_real + .decompress() + .ok_or(ProofError::VerificationError)?; + let Y_delta_claimed = self + .fee_equality_proof + .Y_delta_claimed + .decompress() + .ok_or(ProofError::VerificationError)?; + let z_x = self.fee_equality_proof.z_x; + let z_delta_real = self.fee_equality_proof.z_delta_real; + let z_delta_claimed = self.fee_equality_proof.z_delta_claimed; + + let c = transcript.challenge_scalar(b"c"); + let c_max = self.fee_max_proof.c_max; + let c_equality = c - c_max; + + let check = RistrettoPoint::vartime_multiscalar_mul( + vec![c_max, -c_max * m, -z_max, Scalar::one()], + vec![C_max, G, H, Y_max], + ); + + if check.is_identity() { + Ok(()) + } else { + Err(ProofError::VerificationError) + } + } } #[allow(non_snake_case)] @@ -165,6 +238,7 @@ impl FeeProof { pub struct FeeMaxProof { pub Y_max: CompressedRistretto, pub z_max: Scalar, + pub c_max: Scalar, } #[allow(non_snake_case)] @@ -177,90 +251,53 @@ pub struct FeeEqualityProof { pub z_delta_claimed: Scalar, } -#[allow(non_snake_case, dead_code)] -#[cfg(not(target_arch = "bpf"))] -impl FeeProof { - - pub fn verify( - self, - fee_authority_elgamal_pubkey: &ElGamalPubkey, - fee_ciphertext: &ElGamalCiphertext, - max_fee: u64, - transcript: &mut Transcript, - ) -> Result<(), ProofError> { - // extract the relevant scalar and Ristretto points from the inputs - let G = PedersenBase::default().G; - let H = PedersenBase::default().H; - let P = fee_authority_elgamal_pubkey.get_point(); - - let m = Scalar::from(max_fee); - let C = fee_ciphertext.message_comm.get_point() - m * G; - let D = fee_ciphertext.decrypt_handle.get_point(); - - // record public values in transcript - transcript.append_point(b"P", &P.compress()); - transcript.append_point(b"C", &C.compress()); - transcript.append_point(b"D", &D.compress()); - - transcript.validate_and_append_point(b"Y_H", &self.Y_H)?; - transcript.validate_and_append_point(b"Y_P", &self.Y_P)?; - - // extract challenge scalars - let c = transcript.challenge_scalar(b"c"); - let w = transcript.challenge_scalar(b"w"); - - println!("verifier c: {:?}", c); - - // check that the required algebraic condition holds - let Y_H = self.Y_H.decompress().ok_or(ProofError::VerificationError)?; - let Y_P = self.Y_P.decompress().ok_or(ProofError::VerificationError)?; - - let check = RistrettoPoint::vartime_multiscalar_mul( - vec![self.z, -c, -Scalar::one(), w * self.z, -w * c, -w], - vec![H, C, Y_H, P, D, Y_P], - ); - - if check.is_identity() { - Ok(()) - } else { - Err(ProofError::VerificationError) - } - } -} - - #[cfg(test)] mod test { use super::*; - use crate::encryption::elgamal::ElGamalKeypair; + use crate::encryption::pedersen::Pedersen; #[test] fn test_fee_proof() { - // success case - let fee_authority_keypair = ElGamalKeypair::default(); - let fee_authority_pubkey = fee_authority_keypair.public; - let max_fee: u64 = 55; + let transfer_amount: u64 = 55; + let max_fee: u64 = 77; - let opening = PedersenOpening::random(&mut OsRng); - let fee_ciphertext = fee_authority_pubkey.encrypt_with(max_fee, &opening); + let rate_fee: u16 = 555; // 5.55% + let amount_fee = 3; + let delta_fee: u64 = 525; - let mut transcript_prover = Transcript::new(b"Test"); - let mut transcript_verifier = Transcript::new(b"Test"); + let (commitment_transfer, opening_transfer) = Pedersen::new(transfer_amount); + let (commitment_fee, opening_fee) = Pedersen::new(amount_fee); + + let scalar_rate = Scalar::from(rate_fee); + let commitment_delta_real = + commitment_transfer * scalar_rate - commitment_fee * Scalar::from(10000_u64); + let opening_delta_real = + opening_transfer * scalar_rate - opening_fee.clone() * Scalar::from(10000_u64); + + let (commitment_delta_claimed, opening_delta_claimed) = Pedersen::new(delta_fee); + + let mut transcript_prover = Transcript::new(b"test"); + let mut transcript_verifier = Transcript::new(b"test"); let proof = FeeProof::new( - &fee_authority_pubkey, - &fee_ciphertext, + amount_fee, max_fee, - &opening, + &commitment_fee, + &opening_fee, + &commitment_delta_real, + &opening_delta_real, + &commitment_delta_claimed, + &opening_delta_claimed, &mut transcript_prover, ); assert!(proof .verify( - &fee_authority_pubkey, - &fee_ciphertext, max_fee, - &mut transcript_verifier + commitment_fee, + commitment_delta_real, + commitment_delta_claimed, + &mut transcript_verifier, ) .is_ok()); }