From a4377bf1a67dff3e2d1a9b953c9e55d101c14f99 Mon Sep 17 00:00:00 2001 From: aniampio Date: Mon, 28 Mar 2022 13:26:29 +0100 Subject: [PATCH] Add spendVfy function --- .../src/proofs/proof_spend.rs | 66 +++++++------- .../nym-compact-ecash/src/scheme/identify.rs | 0 common/nym-compact-ecash/src/scheme/spend.rs | 89 +++++++++++++++++-- 3 files changed, 117 insertions(+), 38 deletions(-) create mode 100644 common/nym-compact-ecash/src/scheme/identify.rs diff --git a/common/nym-compact-ecash/src/proofs/proof_spend.rs b/common/nym-compact-ecash/src/proofs/proof_spend.rs index 76bd3d77ea..e1d1f1419c 100644 --- a/common/nym-compact-ecash/src/proofs/proof_spend.rs +++ b/common/nym-compact-ecash/src/proofs/proof_spend.rs @@ -64,6 +64,7 @@ impl TryFrom<&[u8]> for SpendInstance { &T_bytes, CompactEcashError::Deserialization("Failed to deserialize T".to_string()), )?; + Ok(SpendInstance { kappa, A, @@ -131,9 +132,9 @@ impl SpendProof { let r_o_a = params.random_scalar(); let r_o_c = params.random_scalar(); let r_o_d = params.random_scalar(); - let r_mu = params.random_scalar(); + let r_mu = (r_attributes[1] + r_l + Scalar::from(1)).invert().unwrap(); let r_lambda = params.random_scalar(); - let r_o_mu = params.random_scalar(); + let r_o_mu = ((r_o_a + r_o_c) * r_mu).neg(); let r_o_lambda = params.random_scalar(); let g1 = params.gen1(); @@ -154,11 +155,10 @@ impl SpendProof { .sum::(); let zkcm_A = g1 * r_o_a + gamma1 * r_l; - let zkcm_C = g1 * r_o_c + gamma1 * r_attributes[1]; let zkcm_D = g1 * r_o_d + gamma1 * r_attributes[2]; let zkcm_S = g1 * r_mu; - let zkcm_gamma11 = (instance.A + instance.C + gamma1) * r_mu + g1 * r_o_mu; + let zkcm_gamma11 = (g1 * r_o_a + gamma1 * r_l + g1 * r_o_c + gamma1 * r_attributes[1] + gamma1) * r_mu + g1 * r_o_mu; let zkcm_T = g1 * r_attributes[0] + (g1 * R) * r_lambda; let zkcm_gamma12 = (instance.A + instance.D + gamma1) * r_lambda + g1 * r_o_lambda; @@ -172,9 +172,9 @@ impl SpendProof { .chain(beta2_bytes.iter().map(|b| b.as_ref())) .chain(std::iter::once(instance.to_bytes().as_ref())) .chain(std::iter::once(zkcm_kappa.to_bytes().as_ref())) - // .chain(std::iter::once(zkcm_A.to_bytes().as_ref())) - // .chain(std::iter::once(zkcm_C.to_bytes().as_ref())) - // .chain(std::iter::once(zkcm_D.to_bytes().as_ref())) + .chain(std::iter::once(zkcm_A.to_bytes().as_ref())) + .chain(std::iter::once(zkcm_C.to_bytes().as_ref())) + .chain(std::iter::once(zkcm_D.to_bytes().as_ref())) // .chain(std::iter::once(zkcm_S.to_bytes().as_ref())) // .chain(std::iter::once(zkcm_gamma11.to_bytes().as_ref())) // .chain(std::iter::once(zkcm_T.to_bytes().as_ref())) @@ -182,20 +182,22 @@ impl SpendProof { ); // compute response for each witness - let response_r = produce_response(&r_r, &challenge, &witness.r); - let response_l = produce_response(&r_l, &challenge, &witness.l); - let response_o_a = produce_response(&r_o_a, &challenge, &witness.o_a); - let response_o_c = produce_response(&r_o_c, &challenge, &witness.o_c); - let response_o_d = produce_response(&r_o_d, &challenge, &witness.o_d); - let response_mu = produce_response(&r_mu, &challenge, &witness.mu); - let response_lambda = produce_response(&r_lambda, &challenge, &witness.lambda); - let response_o_mu = produce_response(&r_o_mu, &challenge, &witness.o_mu); - let response_o_lambda = produce_response(&r_o_lambda, &challenge, &witness.o_lambda); let response_attributes = produce_responses( &r_attributes, &challenge, &witness.attributes.iter().collect::>(), ); + let response_r = produce_response(&r_r, &challenge, &witness.r); + let response_l = produce_response(&r_l, &challenge, &witness.l); + let response_o_a = produce_response(&r_o_a, &challenge, &witness.o_a); + let response_o_c = produce_response(&r_o_c, &challenge, &witness.o_c); + let response_o_d = produce_response(&r_o_d, &challenge, &witness.o_d); + // let response_mu = produce_response(&r_mu, &challenge, &witness.mu); + let response_mu = (response_attributes[1] + response_l + Scalar::from(1)).invert().unwrap(); + let response_lambda = produce_response(&r_lambda, &challenge, &witness.lambda); + // let response_o_mu = produce_response(&r_o_mu, &challenge, &witness.o_mu); + let response_o_mu = ((response_o_a + response_o_c) * response_mu).neg(); + let response_o_lambda = produce_response(&r_o_lambda, &challenge, &witness.o_lambda); SpendProof { challenge, @@ -238,7 +240,7 @@ impl SpendProof { let zkcm_C = g1 * self.response_o_c + gamma1 * self.response_attributes[1] + instance.C * self.challenge; let zkcm_D = g1 * self.response_o_d + gamma1 * self.response_attributes[2] + instance.D * self.challenge; let zkcm_S = g1 * self.response_mu + instance.S * self.challenge; - let zkcm_gamma11 = (instance.A + instance.C + gamma1) * self.response_mu + g1 * self.response_o_mu + gamma1 * self.challenge; + let zkcm_gamma11 = (g1 * self.response_o_a + gamma1 * self.response_l + g1 * self.response_o_c + gamma1 * self.response_attributes[1] + gamma1) * self.response_mu + g1 * self.response_o_mu + gamma1 * self.challenge; let zkcm_T = g1 * self.response_attributes[0] + (g1 * R) * self.response_lambda + instance.T * self.challenge; let zkcm_gamma12 = (instance.A + instance.D + gamma1) * self.response_lambda + g1 * self.response_o_lambda + gamma1 * self.challenge; @@ -250,9 +252,9 @@ impl SpendProof { .chain(beta2_bytes.iter().map(|b| b.as_ref())) .chain(std::iter::once(instance.to_bytes().as_ref())) .chain(std::iter::once(zkcm_kappa.to_bytes().as_ref())) - // .chain(std::iter::once(zkcm_A.to_bytes().as_ref())) - // .chain(std::iter::once(zkcm_C.to_bytes().as_ref())) - // .chain(std::iter::once(zkcm_D.to_bytes().as_ref())) + .chain(std::iter::once(zkcm_A.to_bytes().as_ref())) + .chain(std::iter::once(zkcm_C.to_bytes().as_ref())) + .chain(std::iter::once(zkcm_D.to_bytes().as_ref())) // .chain(std::iter::once(zkcm_S.to_bytes().as_ref())) // .chain(std::iter::once(zkcm_gamma11.to_bytes().as_ref())) // .chain(std::iter::once(zkcm_T.to_bytes().as_ref())) @@ -295,6 +297,8 @@ mod tests { let t = params.random_scalar(); let attributes = vec![sk, v, t]; let l = 5; + let gamma1 = params.gamma1().unwrap(); + let g1 = params.gen1(); let r = params.random_scalar(); let kappa = params.gen2() * r @@ -310,9 +314,9 @@ mod tests { let o_d = params.random_scalar(); // compute commitments A, C, D - let A = params.gen1() * o_a + params.gamma1().unwrap() * Scalar::from(l); - let C = params.gen1() * o_c + params.gamma1().unwrap() * v; - let D = params.gen1() * o_d + params.gamma1().unwrap() * t; + let A = g1 * o_a + gamma1 * Scalar::from(l); + let C = g1 * o_c + gamma1 * v; + let D = g1 * o_d + gamma1 * t; // compute hash of the payment info let payInfo = PayInfo { info: [5u8; 32] }; @@ -320,21 +324,21 @@ mod tests { // evaluate the pseudorandom functions let S = pseudorandom_fgv(¶ms, v, l); - let T = params.gen1() * sk + pseudorandom_fgt(¶ms, t, l) * R; + let T = g1 * sk + pseudorandom_fgt(¶ms, t, l) * R; // compute values mu, o_mu, lambda, o_lambda - let mu: Scalar = (v + Scalar::from(l) + Scalar::from(1)).neg(); + let mu: Scalar = (v + Scalar::from(l) + Scalar::from(1)).invert().unwrap(); let o_mu = ((o_a + o_c) * mu).neg(); - let lambda = (t + Scalar::from(l) + Scalar::from(1)).neg(); + let lambda = (t + Scalar::from(l) + Scalar::from(1)).invert().unwrap(); let o_lambda = ((o_a + o_d) * lambda).neg(); let instance = SpendInstance { kappa, - A: Default::default(), - C: Default::default(), - D: Default::default(), - S: Default::default(), - T: Default::default(), + A, + C, + D, + S, + T, }; let witness = SpendWitness { diff --git a/common/nym-compact-ecash/src/scheme/identify.rs b/common/nym-compact-ecash/src/scheme/identify.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/common/nym-compact-ecash/src/scheme/spend.rs b/common/nym-compact-ecash/src/scheme/spend.rs index 999a718d00..03a9e2d634 100644 --- a/common/nym-compact-ecash/src/scheme/spend.rs +++ b/common/nym-compact-ecash/src/scheme/spend.rs @@ -1,19 +1,33 @@ +use std::cell::Cell; use std::convert::TryInto; -use bls12_381::{G1Projective, G2Projective, Scalar}; +use bls12_381::{G1Projective, G2Prepared, G2Projective, Scalar}; +use group::Curve; use crate::Attribute; use crate::error::{CompactEcashError, Result}; use crate::proofs::proof_spend::{SpendInstance, SpendProof, SpendWitness}; +use crate::scheme::{Signature, Wallet}; use crate::scheme::keygen::{SecretKeyUser, VerificationKeyAuth}; use crate::scheme::setup::Parameters; -use crate::scheme::Wallet; -use crate::utils::hash_to_scalar; +use crate::utils::{check_bilinear_pairing, hash_to_scalar}; pub struct PayInfo { pub(crate) info: [u8; 32], } +pub struct Payment { + kappa: G2Projective, + sig: Signature, + S: G1Projective, + T: G1Projective, + A: G1Projective, + C: G1Projective, + D: G1Projective, + R: Scalar, + zk_proof: SpendProof, +} + pub fn pseudorandom_fgv(params: &Parameters, v: Scalar, l: u64) -> G1Projective { let pow = (v + Scalar::from(l) + Scalar::from(1)).neg(); params.gen1() * pow @@ -39,7 +53,7 @@ pub fn compute_kappa( .sum::() } -pub fn spend(params: &Parameters, wallet: &Wallet, verification_key: &VerificationKeyAuth, skUser: &SecretKeyUser, payInfo: &PayInfo) -> Result<()> { +pub fn spend(params: &Parameters, wallet: &Wallet, verification_key: &VerificationKeyAuth, skUser: &SecretKeyUser, payInfo: &PayInfo) -> Result<(Payment, Wallet)> { if wallet.l() > params.L() { return Err(CompactEcashError::Spend( "The counter l is higher than max L".to_string(), @@ -96,11 +110,72 @@ pub fn spend(params: &Parameters, wallet: &Wallet, verification_key: &Verificati o_mu, o_lambda, }; - let zkp = SpendProof::construct(¶ms, &spendInstance, &spendWitness, &verification_key, R); + let zk_proof = SpendProof::construct(¶ms, &spendInstance, &spendWitness, &verification_key, R); // output pay and updated wallet + let pay = Payment { + kappa, + sig: signature_prime, + S, + T, + A, + C, + D, + R, + zk_proof, + }; + let wallet_upd = Wallet { + sig: wallet.sig, + v: wallet.v, + t: wallet.t, + l: Cell::new(wallet.l.get() + 1), + }; - Ok(()) + Ok((pay, wallet_upd)) } -pub fn spend_verify() {} +pub fn spend_verify(params: &Parameters, verification_key: VerificationKeyAuth, pay: Payment, payinfo: PayInfo) -> Result { + if bool::from(pay.sig.0.is_identity()) { + return Err(CompactEcashError::Spend( + "The element h of the signature equals the identity".to_string(), + )); + } + + if !check_bilinear_pairing( + &pay.sig.0.to_affine(), + &G2Prepared::from(pay.kappa.to_affine()), + &pay.sig.1.to_affine(), + params.prepared_miller_g2(), + ) { + return Err(CompactEcashError::Spend( + "The bilinear check for kappa failed".to_string(), + )); + } + + // verify integrity of R + if !(pay.R == hash_to_scalar(payinfo.info)) { + return Err(CompactEcashError::Spend( + "Integrity of R does not hold".to_string(), + )); + } + + //TODO: verify whether payinfo contains merchent's identifier + + // verify the zk proof + let instance = SpendInstance { + kappa: pay.kappa, + A: pay.A, + C: pay.C, + D: pay.D, + S: pay.S, + T: pay.T, + }; + + if !pay.zk_proof.verify(¶ms, &instance, &verification_key, pay.R) { + return Err(CompactEcashError::Spend( + "ZkProof verification failed".to_string(), + )); + } + + Ok(true) +}