From ef0867a7e7dddd70ac58b4ac08bfdb02da3da329 Mon Sep 17 00:00:00 2001 From: aniampio Date: Mon, 28 Mar 2022 17:36:40 +0100 Subject: [PATCH] Move spend and spec vfy as functions associated with wallet and payment --- .../src/proofs/proof_spend.rs | 3 +- .../nym-compact-ecash/src/scheme/identify.rs | 4 +- common/nym-compact-ecash/src/scheme/mod.rs | 174 ++++++++++++++++- common/nym-compact-ecash/src/scheme/spend.rs | 181 ------------------ common/nym-compact-ecash/src/tests/e2e.rs | 6 +- 5 files changed, 179 insertions(+), 189 deletions(-) diff --git a/common/nym-compact-ecash/src/proofs/proof_spend.rs b/common/nym-compact-ecash/src/proofs/proof_spend.rs index e1d1f1419c..bc7957dd03 100644 --- a/common/nym-compact-ecash/src/proofs/proof_spend.rs +++ b/common/nym-compact-ecash/src/proofs/proof_spend.rs @@ -271,10 +271,11 @@ mod tests { use rand::thread_rng; use crate::proofs::proof_spend::{SpendInstance, SpendProof, SpendWitness}; + use crate::scheme::{pseudorandom_fgt, pseudorandom_fgv}; use crate::scheme::aggregation::aggregate_verification_keys; use crate::scheme::keygen::{PublicKeyUser, ttp_keygen, VerificationKeyAuth}; + use crate::scheme::PayInfo; use crate::scheme::setup::Parameters; - use crate::scheme::spend::{PayInfo, pseudorandom_fgt, pseudorandom_fgv}; use crate::utils::hash_to_scalar; #[test] diff --git a/common/nym-compact-ecash/src/scheme/identify.rs b/common/nym-compact-ecash/src/scheme/identify.rs index 8f7195483a..6a4fa280e8 100644 --- a/common/nym-compact-ecash/src/scheme/identify.rs +++ b/common/nym-compact-ecash/src/scheme/identify.rs @@ -1,12 +1,12 @@ use std::convert::TryFrom; use crate::error::Result; +use crate::scheme::{PayInfo, Payment}; use crate::scheme::keygen::PublicKeyUser; use crate::scheme::setup::Parameters; -use crate::scheme::spend::{PayInfo, Payment}; pub fn identify(params: &Parameters, pay1: Payment, pay2: Payment, payInfo1: PayInfo, payInfo2: PayInfo) -> Result { // TODO: We had to include checks for S1, S2 and payinfo1 and payinfo2 let pkUser = (pay2.T * pay1.R - pay1.T * pay2.R) * (pay1.R - pay2.R).invert().unwrap(); Ok(PublicKeyUser { pk: pkUser }) -} \ No newline at end of file +} diff --git a/common/nym-compact-ecash/src/scheme/mod.rs b/common/nym-compact-ecash/src/scheme/mod.rs index 73ff4f2e55..eca086e67e 100644 --- a/common/nym-compact-ecash/src/scheme/mod.rs +++ b/common/nym-compact-ecash/src/scheme/mod.rs @@ -2,13 +2,16 @@ use std::cell::Cell; use std::convert::TryFrom; use std::convert::TryInto; -use bls12_381::{G1Projective, 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::keygen::{SecretKeyUser, VerificationKeyAuth}; use crate::scheme::setup::Parameters; use crate::traits::Bytable; -use crate::utils::try_deserialize_g1_projective; +use crate::utils::{check_bilinear_pairing, hash_to_scalar, try_deserialize_g1_projective}; pub mod aggregation; pub mod keygen; @@ -146,7 +149,174 @@ impl Wallet { pub fn v(&self) -> Scalar { self.v } pub fn t(&self) -> Scalar { self.t } pub fn l(&self) -> u64 { self.l.get() } + fn up(&self) { self.l.set(self.l.get() + 1); } + + pub fn spend(&self, params: &Parameters, verification_key: &VerificationKeyAuth, skUser: &SecretKeyUser, payInfo: &PayInfo) -> Result<(Payment, &Self)> { + if self.l() > params.L() { + return Err(CompactEcashError::Spend( + "The counter l is higher than max L".to_string(), + )); + } + + // randomize signature in the wallet + let (signature_prime, sign_blinding_factor) = self.signature().randomise(params); + // construct kappa i.e., blinded attributes for show + let attributes = vec![skUser.sk, self.v(), self.t()]; + let kappa = compute_kappa(¶ms, &verification_key, &attributes, sign_blinding_factor); + + // pick random openings o_a, o_c, o_d + let o_a = params.random_scalar(); + let o_c = params.random_scalar(); + let o_d = params.random_scalar(); + + // compute commitments A, C, D + let A = params.gen1() * o_a + params.gamma1().unwrap() * Scalar::from(self.l()); + let C = params.gen1() * o_c + params.gamma1().unwrap() * self.v(); + let D = params.gen1() * o_d + params.gamma1().unwrap() * self.t(); + + // compute hash of the payment info + let R = hash_to_scalar(payInfo.info); + + // evaluate the pseudorandom functions + let S = pseudorandom_fgv(¶ms, self.v(), self.l()); + let T = params.gen1() * skUser.sk + pseudorandom_fgt(¶ms, self.t(), self.l()) * R; + + // compute values mu, o_mu, lambda, o_lambda + let mu: Scalar = (self.v() + Scalar::from(self.l()) + Scalar::from(1)).invert().unwrap(); + let o_mu = ((o_a + o_c) * mu).neg(); + let lambda = (self.t() + Scalar::from(self.l()) + Scalar::from(1)).invert().unwrap(); + let o_lambda = ((o_a + o_d) * lambda).neg(); + + // construct the zkp proof + let spendInstance = SpendInstance { + kappa, + A, + C, + D, + S, + T, + }; + let spendWitness = SpendWitness { + attributes, + r: sign_blinding_factor, + l: Scalar::from(self.l()), + o_a, + o_c, + o_d, + mu, + lambda, + o_mu, + o_lambda, + }; + 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, + }; + + self.up(); + + Ok((pay, self)) + } +} + +pub fn pseudorandom_fgv(params: &Parameters, v: Scalar, l: u64) -> G1Projective { + let pow = (v + Scalar::from(l) + Scalar::from(1)).neg(); + params.gen1() * pow +} + +pub fn pseudorandom_fgt(params: &Parameters, t: Scalar, l: u64) -> G1Projective { + let pow = (t + Scalar::from(l) + Scalar::from(1)).neg(); + params.gen1() * pow +} + +pub fn compute_kappa( + params: &Parameters, + verification_key: &VerificationKeyAuth, + attributes: &[Attribute], + blinding_factor: Scalar, +) -> G2Projective { + params.gen2() * blinding_factor + + verification_key.alpha + + attributes + .iter() + .zip(verification_key.beta_g2.iter()) + .map(|(priv_attr, beta_i)| beta_i * priv_attr) + .sum::() +} + +pub struct PayInfo { + pub(crate) info: [u8; 32], +} + +pub struct Payment { + pub kappa: G2Projective, + pub sig: Signature, + pub S: G1Projective, + pub T: G1Projective, + pub A: G1Projective, + pub C: G1Projective, + pub D: G1Projective, + pub R: Scalar, + pub zk_proof: SpendProof, +} + +impl Payment { + pub fn spend_verify(&self, params: &Parameters, verification_key: &VerificationKeyAuth, payinfo: &PayInfo) -> Result { + if bool::from(self.sig.0.is_identity()) { + return Err(CompactEcashError::Spend( + "The element h of the signature equals the identity".to_string(), + )); + } + + if !check_bilinear_pairing( + &self.sig.0.to_affine(), + &G2Prepared::from(self.kappa.to_affine()), + &self.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 !(self.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: self.kappa, + A: self.A, + C: self.C, + D: self.D, + S: self.S, + T: self.T, + }; + + if !self.zk_proof.verify(¶ms, &instance, &verification_key, self.R) { + return Err(CompactEcashError::Spend( + "ZkProof verification failed".to_string(), + )); + } + + Ok(true) + } } \ No newline at end of file diff --git a/common/nym-compact-ecash/src/scheme/spend.rs b/common/nym-compact-ecash/src/scheme/spend.rs index fc4353f6e4..e69de29bb2 100644 --- a/common/nym-compact-ecash/src/scheme/spend.rs +++ b/common/nym-compact-ecash/src/scheme/spend.rs @@ -1,181 +0,0 @@ -use std::cell::Cell; -use std::convert::TryInto; - -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::utils::{check_bilinear_pairing, hash_to_scalar}; - -pub struct PayInfo { - pub(crate) info: [u8; 32], -} - -pub struct Payment { - pub kappa: G2Projective, - pub sig: Signature, - pub S: G1Projective, - pub T: G1Projective, - pub A: G1Projective, - pub C: G1Projective, - pub D: G1Projective, - pub R: Scalar, - pub 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 -} - -pub fn pseudorandom_fgt(params: &Parameters, t: Scalar, l: u64) -> G1Projective { - let pow = (t + Scalar::from(l) + Scalar::from(1)).neg(); - params.gen1() * pow -} - -pub fn compute_kappa( - params: &Parameters, - verification_key: &VerificationKeyAuth, - attributes: &[Attribute], - blinding_factor: Scalar, -) -> G2Projective { - params.gen2() * blinding_factor - + verification_key.alpha - + attributes - .iter() - .zip(verification_key.beta_g2.iter()) - .map(|(priv_attr, beta_i)| beta_i * priv_attr) - .sum::() -} - -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(), - )); - } - - // randomize signature in the wallet - let (signature_prime, sign_blinding_factor) = wallet.signature().randomise(params); - // construct kappa i.e., blinded attributes for show - let attributes = vec![skUser.sk, wallet.v(), wallet.t()]; - let kappa = compute_kappa(¶ms, &verification_key, &attributes, sign_blinding_factor); - - // pick random openings o_a, o_c, o_d - let o_a = params.random_scalar(); - let o_c = params.random_scalar(); - let o_d = params.random_scalar(); - - // compute commitments A, C, D - let A = params.gen1() * o_a + params.gamma1().unwrap() * Scalar::from(wallet.l()); - let C = params.gen1() * o_c + params.gamma1().unwrap() * wallet.v(); - let D = params.gen1() * o_d + params.gamma1().unwrap() * wallet.t(); - - // compute hash of the payment info - let R = hash_to_scalar(payInfo.info); - - // evaluate the pseudorandom functions - let S = pseudorandom_fgv(¶ms, wallet.v(), wallet.l()); - let T = params.gen1() * skUser.sk + pseudorandom_fgt(¶ms, wallet.t(), wallet.l()) * R; - - // compute values mu, o_mu, lambda, o_lambda - let mu: Scalar = (wallet.v() + Scalar::from(wallet.l()) + Scalar::from(1)).neg(); - let o_mu = ((o_a + o_c) * mu).neg(); - let lambda = (wallet.t() + Scalar::from(wallet.l()) + Scalar::from(1)).neg(); - let o_lambda = ((o_a + o_d) * lambda).neg(); - - // construct the zkp proof - let spendInstance = SpendInstance { - kappa, - A, - C, - D, - S, - T, - }; - let spendWitness = SpendWitness { - attributes, - r: sign_blinding_factor, - l: Scalar::from(wallet.l()), - o_a, - o_c, - o_d, - mu, - lambda, - o_mu, - o_lambda, - }; - 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((pay, wallet_upd)) -} - -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) -} diff --git a/common/nym-compact-ecash/src/tests/e2e.rs b/common/nym-compact-ecash/src/tests/e2e.rs index ce17d5bb69..e8d22ca078 100644 --- a/common/nym-compact-ecash/src/tests/e2e.rs +++ b/common/nym-compact-ecash/src/tests/e2e.rs @@ -6,8 +6,8 @@ use crate::scheme::aggregation::{aggregate_signature_shares, aggregate_verificat use crate::scheme::keygen::{ generate_keypair_user, PublicKeyUser, SecretKeyUser, ttp_keygen, VerificationKeyAuth, }; +use crate::scheme::PayInfo; use crate::scheme::setup::Parameters; -use crate::scheme::spend::{PayInfo, spend, spend_verify}; use crate::scheme::withdrawal::{issue_verify, issue_wallet, withdrawal_request}; #[test] @@ -51,9 +51,9 @@ fn main() -> Result<(), CompactEcashError> { info: [6u8; 32], }; - let (payment, upd_wallet) = spend(¶ms, &aggr_wallet, &verification_key, &user_keypair.secret_key(), &payInfo)?; + let (payment, upd_wallet) = aggr_wallet.spend(¶ms, &verification_key, &user_keypair.secret_key(), &payInfo)?; - assert!(spend_verify(¶ms, &verification_key, &payment, &payInfo).unwrap()); + assert!(payment.spend_verify(¶ms, &verification_key, &payInfo).unwrap()); Ok(()) }