From aa018769c2d1d752e69f81b2d0c7bf757d0b8241 Mon Sep 17 00:00:00 2001 From: aniampio Date: Tue, 24 May 2022 21:16:43 +0100 Subject: [PATCH] Add bilinear equations into the zk proof; the last eq passes the tests --- Cargo.lock | 68 ++- common/nym_offline_divisible_ecash/Cargo.toml | 6 +- .../src/proofs/proof_spend.rs | 414 +++++++++++++++++- .../src/scheme/mod.rs | 91 ++-- .../src/scheme/setup.rs | 20 +- .../nym_offline_divisible_ecash/src/utils.rs | 2 +- 6 files changed, 529 insertions(+), 72 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 084abfdc37..b82fa5b7a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -995,7 +995,11 @@ dependencies = [ "ff 0.10.1", "group 0.10.0", "pairing 0.20.0", +<<<<<<< HEAD "rand_core 0.6.4", +======= + "rand_core 0.6.3", +>>>>>>> b6a43787b (Add bilinear equations into the zk proof; the last eq passes the tests) "subtle 2.4.1", ] @@ -1005,15 +1009,23 @@ version = "0.6.0" source = "git+https://github.com/jstuczyn/bls12_381?branch=gt-serialisation#10fb6f700bfda17c8475af3bfd31e3fec15f2278" dependencies = [ "digest 0.9.0", +<<<<<<< HEAD "ff 0.11.1", "group 0.11.0", "pairing 0.21.0", "rand_core 0.6.4", +======= + "ff 0.11.0", + "group 0.11.0", + "pairing 0.21.0", + "rand_core 0.6.3", +>>>>>>> b6a43787b (Add bilinear equations into the zk proof; the last eq passes the tests) "subtle 2.4.1", "zeroize", ] [[package]] +<<<<<<< HEAD name = "bnum" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1041,6 +1053,8 @@ dependencies = [ ] [[package]] +======= +>>>>>>> b6a43787b (Add bilinear equations into the zk proof; the last eq passes the tests) name = "bs58" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1812,6 +1826,22 @@ dependencies = [ ] [[package]] +<<<<<<< HEAD +======= +name = "credentials" +version = "0.1.0" +dependencies = [ + "bls12_381 0.5.0", + "coconut-interface", + "crypto", + "network-defaults", + "thiserror", + "url", + "validator-client", +] + +[[package]] +>>>>>>> b6a43787b (Add bilinear equations into the zk proof; the last eq passes the tests) name = "criterion" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3606,6 +3636,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89" dependencies = [ "byteorder", +<<<<<<< HEAD "ff 0.11.1", "rand_core 0.6.4", "subtle 2.4.1", @@ -3630,6 +3661,10 @@ checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff 0.13.0", "rand_core 0.6.4", +======= + "ff 0.11.0", + "rand_core 0.6.3", +>>>>>>> b6a43787b (Add bilinear equations into the zk proof; the last eq passes the tests) "subtle 2.4.1", ] @@ -7686,8 +7721,13 @@ name = "nym_compact_ecash" version = "0.1.0" dependencies = [ "bls12_381 0.5.0", +<<<<<<< HEAD "bs58 0.4.0", "criterion 0.3.6", +======= + "bs58", + "criterion", +>>>>>>> b6a43787b (Add bilinear equations into the zk proof; the last eq passes the tests) "digest 0.9.0", "ff 0.10.1", "group 0.10.0", @@ -7704,12 +7744,12 @@ name = "nymvisor" name = "nym_offline_divisible_ecash" version = "0.1.0" dependencies = [ - "bls12_381", + "bls12_381 0.6.0", "bs58", "criterion", "digest 0.9.0", - "ff 0.10.1", - "group 0.10.0", + "ff 0.11.0", + "group 0.11.0", "itertools", "rand 0.8.5", "sha2", @@ -7720,7 +7760,7 @@ dependencies = [ name = "nym_online_divisible_ecash" version = "0.1.0" dependencies = [ - "bls12_381", + "bls12_381 0.5.0", "bs58", "criterion", "digest 0.9.0", @@ -7737,7 +7777,7 @@ name = "nymcoconut" version = "0.5.0" dependencies = [ "bincode", - "bls12_381", + "bls12_381 0.5.0", "bs58", "criterion", "digest 0.9.0", @@ -8145,6 +8185,18 @@ dependencies = [ [[package]] name = "pairing" version = "0.21.0" +<<<<<<< HEAD +======= +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2e415e349a3006dd7d9482cdab1c980a845bed1377777d768cb693a44540b42" +dependencies = [ + "group 0.11.0", +] + +[[package]] +name = "parity-scale-codec" +version = "2.3.1" +>>>>>>> b6a43787b (Add bilinear equations into the zk proof; the last eq passes the tests) source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2e415e349a3006dd7d9482cdab1c980a845bed1377777d768cb693a44540b42" dependencies = [ @@ -12945,9 +12997,15 @@ dependencies = [ [[package]] name = "zeroize" +<<<<<<< HEAD version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +======= +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d68d9dcec5f9b43a30d38c49f91dfedfaac384cb8f085faca366c26207dd1619" +>>>>>>> b6a43787b (Add bilinear equations into the zk proof; the last eq passes the tests) dependencies = [ "zeroize_derive", ] diff --git a/common/nym_offline_divisible_ecash/Cargo.toml b/common/nym_offline_divisible_ecash/Cargo.toml index 36a0021643..3dffaceb9c 100644 --- a/common/nym_offline_divisible_ecash/Cargo.toml +++ b/common/nym_offline_divisible_ecash/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -bls12_381 = { version = "0.5", default-features = false, features = ["pairings", "alloc", "experimental"] } +bls12_381 = { git = "https://github.com/jstuczyn/bls12_381", branch = "gt-serialisation", default-features = false, features = ["alloc", "pairings", "experimental", "zeroize"] } itertools = "0.10" digest = "0.9" rand = "0.8" @@ -19,9 +19,9 @@ bs58 = "0.4.0" criterion = { version = "0.3", features = ["html_reports"] } [dependencies.ff] -version = "0.10" +version = "0.11" default-features = false [dependencies.group] -version = "0.10" +version = "0.11" default-features = false \ No newline at end of file diff --git a/common/nym_offline_divisible_ecash/src/proofs/proof_spend.rs b/common/nym_offline_divisible_ecash/src/proofs/proof_spend.rs index e0fad6b857..118c4174b8 100644 --- a/common/nym_offline_divisible_ecash/src/proofs/proof_spend.rs +++ b/common/nym_offline_divisible_ecash/src/proofs/proof_spend.rs @@ -1,6 +1,11 @@ -use bls12_381::{G1Projective, G2Projective, Gt, Scalar}; +use std::convert::TryFrom; +use std::ops::Neg; -use crate::scheme::{Phi, VarPhi}; +use bls12_381::{G1Projective, G2Projective, Gt, Scalar}; +use group::GroupEncoding; + +use crate::proofs::{ChallengeDigest, compute_challenge, produce_response, produce_responses}; +use crate::scheme::{Phi, VarPhi, Wallet}; use crate::scheme::keygen::{SecretKeyUser, VerificationKeyAuth}; use crate::scheme::setup::Parameters; @@ -8,28 +13,57 @@ pub struct SpendInstance { pub kappa: G2Projective, pub phi: Phi, pub varphi: VarPhi, - pub rr: G1Projective, + pub rr: Scalar, + pub rr_prime: G1Projective, pub ss: G1Projective, pub tt: G2Projective, - pub pg_varsigpr1_delta: Gt, + pub varsig_prime1: G1Projective, + pub theta_prime1: G1Projective, + pub pg_eq1: Gt, + pub pg_eq2: Gt, + pub pg_eq3: Gt, + pub pg_eq4: Gt, + pub psi_g1: G1Projective, + pub psi_g2: G2Projective, pub pg_psi0_delta: Gt, - pub pg_varsigpr2_gen2: Gt, pub pg_psi0_gen2: Gt, - pub pg_thetapr1_delta: Gt, - pub pg_thetapr2_gen2: Gt, - pub pg_rr_yy: Gt, pub pg_psi0_yy: Gt, - pub pg_ssprime_gen2: Gt, - pub pg_varsigpr2_ww1: Gt, pub pg_psi0_ww1: Gt, - pub pg_thetapr2_ww2: Gt, pub pg_psi0_ww2: Gt, - pub pg_gen1_zz: Gt, - pub pg_rr_tt: Gt, pub pg_rr_psi1: Gt, pub pg_psi0_tt: Gt, pub pg_psi0_psi1: Gt, - pub pg_gen1_gen2: Gt, +} + +impl SpendInstance { + pub(crate) fn to_bytes(&self) -> Vec { + let mut bytes = Vec::with_capacity(96 + 96 + 3 * 96 + 5 * 48 + 12 * 288); + bytes.extend_from_slice(self.kappa.to_bytes().as_ref()); + bytes.extend_from_slice(self.phi.to_bytes().as_ref()); + bytes.extend_from_slice(self.varphi.to_bytes().as_ref()); + bytes.extend_from_slice(self.rr.to_bytes().as_ref()); + bytes.extend_from_slice(self.rr_prime.to_bytes().as_ref()); + bytes.extend_from_slice(self.ss.to_bytes().as_ref()); + bytes.extend_from_slice(self.tt.to_bytes().as_ref()); + bytes.extend_from_slice(self.varsig_prime1.to_bytes().as_ref()); + bytes.extend_from_slice(self.theta_prime1.to_bytes().as_ref()); + bytes.extend_from_slice(self.pg_eq1.to_compressed().as_ref()); + bytes.extend_from_slice(self.pg_eq2.to_compressed().as_ref()); + bytes.extend_from_slice(self.pg_eq3.to_compressed().as_ref()); + bytes.extend_from_slice(self.pg_eq4.to_compressed().as_ref()); + bytes.extend_from_slice(self.psi_g1.to_bytes().as_ref()); + bytes.extend_from_slice(self.psi_g2.to_bytes().as_ref()); + bytes.extend_from_slice(self.pg_psi0_delta.to_compressed().as_ref()); + bytes.extend_from_slice(self.pg_psi0_gen2.to_compressed().as_ref()); + bytes.extend_from_slice(self.pg_psi0_yy.to_compressed().as_ref()); + bytes.extend_from_slice(self.pg_psi0_ww1.to_compressed().as_ref()); + bytes.extend_from_slice(self.pg_psi0_ww2.to_compressed().as_ref()); + bytes.extend_from_slice(self.pg_rr_psi1.to_compressed().as_ref()); + bytes.extend_from_slice(self.pg_psi0_tt.to_compressed().as_ref()); + bytes.extend_from_slice(self.pg_psi0_psi1.to_compressed().as_ref()); + + bytes + } } pub struct SpendWitness { @@ -51,16 +85,360 @@ pub struct SpendWitness { } #[derive(Debug, Clone)] -pub struct SpendProof {} +pub struct SpendProof { + challenge: Scalar, + response_r: Scalar, + response_r_sk_u: Scalar, + response_r_v: Scalar, + response_r_r: Scalar, + response_r_r1: Scalar, + response_r_r2: Scalar, + response_r_varsig1: Scalar, + response_r_theta1: Scalar, + response_r_varsig2: Scalar, + response_r_theta2: Scalar, + response_r_rr: Scalar, + response_r_ss: Scalar, + response_r_tt: Scalar, + response_r_rho1: Scalar, + response_r_rho2: Scalar, + response_r_rho3: Scalar, +} impl SpendProof { pub fn construct( params: &Parameters, instance: &SpendInstance, - witness: &SpendWitness) -> Self { - SpendProof {} + witness: &SpendWitness, + verification_key: &VerificationKeyAuth, + vv: u64) -> Self { + let grp = params.get_grp(); + let params_u = params.get_params_u(); + let params_a = params.get_params_a(); + + // generate random values to replace each witness + let r_attributes = grp.n_random_scalars(2); + let r_sk_u = r_attributes[0]; + let r_v = r_attributes[1]; + let r_r = grp.random_scalar(); + let r_r1 = grp.random_scalar(); + let r_r2 = grp.random_scalar(); + let r_r_varsig1 = grp.random_scalar(); + let r_r_theta1 = grp.random_scalar(); + let r_r_varsig2 = grp.random_scalar(); + let r_r_theta2 = grp.random_scalar(); + let r_r_rr = grp.random_scalar(); + let r_r_ss = grp.random_scalar(); + let r_r_tt = grp.random_scalar(); + let r_rho1 = grp.random_scalar(); + let r_rho2 = grp.random_scalar(); + let r_rho3 = grp.random_scalar(); + + let g1 = grp.gen1(); + + // compute zkp commitment for each instance + let zkcm_kappa = grp.gen2() * r_r + + verification_key.alpha + + r_attributes + .iter() + .zip(verification_key.beta_g2.iter()) + .map(|(attr, beta_i)| beta_i * attr) + .sum::(); + + let zkcm_phi0 = g1 * r_r1; + let zkcm_phi1 = instance.varsig_prime1 * r_v + instance.psi_g1 * r_rho1 + params_u.get_ith_eta(vv as usize) * r_r1; + let zkcm_varphi0 = g1 * r_r2; + let zkcm_varphi1 = (g1 * instance.rr) * r_sk_u + instance.theta_prime1 * r_v + instance.psi_g1 * r_rho2 + params_u.get_ith_eta(vv as usize) * r_r2; + let zkcm_pg_eq1 = instance.pg_psi0_delta * r_r_varsig1 + instance.pg_psi0_gen2 * r_r_varsig2.neg(); + let zkcm_pg_eq2 = instance.pg_psi0_delta * r_r_theta1 + instance.pg_psi0_gen2 * r_r_theta2.neg(); + let zkcm_pg_eq3 = instance.pg_psi0_yy * r_r_rr + instance.pg_psi0_gen2 * r_r_ss + instance.pg_psi0_ww1 * r_r_varsig2 + instance.pg_psi0_ww2 * r_r_theta2; + let zkcm_pg_eq4 = instance.pg_rr_psi1 * r_r_tt + instance.pg_psi0_tt * r_r_rr + instance.pg_psi0_psi1 * r_rho3.neg(); + + + let challenge = compute_challenge::( + std::iter::once(g1.to_bytes().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_phi0.to_bytes().as_ref())) + .chain(std::iter::once(zkcm_phi1.to_bytes().as_ref())) + .chain(std::iter::once(zkcm_varphi0.to_bytes().as_ref())) + .chain(std::iter::once(zkcm_varphi1.to_bytes().as_ref())) + // .chain(std::iter::once(zkcm_pg_eq1.to_compressed().as_ref())) + // .chain(std::iter::once(zkcm_pg_eq2.to_compressed().as_ref())) + // .chain(std::iter::once(zkcm_pg_eq3.to_compressed().as_ref())) + .chain(std::iter::once(zkcm_pg_eq4.to_compressed().as_ref())) + ); + + // compute response for each witness + let response_r = produce_response(&r_r, &challenge, &witness.r); + let response_r_sk_u = produce_response(&r_sk_u, &challenge, &witness.sk_u.sk); + let response_r_v = produce_response(&r_v, &challenge, &witness.v); + let response_r_r = produce_response(&r_r, &challenge, &witness.r); + let response_r_r1 = produce_response(&r_r1, &challenge, &witness.r1); + let response_r_r2 = produce_response(&r_r2, &challenge, &witness.r2); + let response_r_varsig1 = produce_response(&r_r_varsig1, &challenge, &witness.r_varsig1); + let response_r_theta1 = produce_response(&r_r_theta1, &challenge, &witness.r_theta1); + let response_r_varsig2 = produce_response(&r_r_varsig2, &challenge, &witness.r_varsig2); + let response_r_theta2 = produce_response(&r_r_theta2, &challenge, &witness.r_theta2); + let response_r_rr = produce_response(&r_r_rr, &challenge, &witness.r_rr); + let response_r_ss = produce_response(&r_r_ss, &challenge, &witness.r_ss); + let response_r_tt = produce_response(&r_r_tt, &challenge, &witness.r_tt); + let response_r_rho1 = produce_response(&r_rho1, &challenge, &witness.rho1); + let response_r_rho2 = produce_response(&r_rho2, &challenge, &witness.rho2); + let response_r_rho3 = produce_response(&r_rho3, &challenge, &witness.rho3); + + + SpendProof { + challenge, + response_r, + response_r_sk_u, + response_r_v, + response_r_r, + response_r_r1, + response_r_r2, + response_r_varsig1, + response_r_theta1, + response_r_varsig2, + response_r_theta2, + response_r_rr, + response_r_ss, + response_r_tt, + response_r_rho1, + response_r_rho2, + response_r_rho3, + } + } + + pub fn verify( + &self, + params: &Parameters, + instance: &SpendInstance, + verification_key: &VerificationKeyAuth, + vv: u64, + ) -> bool { + let grp = params.get_grp(); + let params_u = params.get_params_u(); + let params_a = params.get_params_a(); + let g1 = grp.gen1(); + + // re-compute each zkp commitment + let zkcm_kappa = instance.kappa * self.challenge + + grp.gen2() * self.response_r + + verification_key.alpha * (Scalar::one() - self.challenge) + + [self.response_r_sk_u, self.response_r_v] + .iter() + .zip(verification_key.beta_g2.iter()) + .map(|(attr, beta_i)| beta_i * attr) + .sum::(); + + let zkcm_phi0 = g1 * self.response_r_r1 + instance.phi.0 * self.challenge; + let zkcm_phi1 = instance.varsig_prime1 * self.response_r_v + + instance.psi_g1 * self.response_r_rho1 + + params_u.get_ith_eta(vv as usize) * self.response_r_r1 + + instance.phi.1 * self.challenge; + let zkcm_varphi0 = g1 * self.response_r_r2 + instance.varphi.0 * self.challenge; + let zkcm_varphi1 = (g1 * instance.rr) * self.response_r_sk_u + + instance.theta_prime1 * self.response_r_v + + instance.psi_g1 * self.response_r_rho2 + + params_u.get_ith_eta(vv as usize) * self.response_r_r2 + + instance.varphi.1 * self.challenge; + let zkcm_pg_eq1 = instance.pg_psi0_delta * self.response_r_varsig1 + + instance.pg_psi0_gen2 * self.response_r_varsig2.neg() + + instance.pg_eq1 * self.challenge; + let zkcm_pg_eq2 = instance.pg_psi0_delta * self.response_r_theta1 + + instance.pg_psi0_gen2 * self.response_r_theta2.neg() + + instance.pg_eq2 * self.challenge; + + + let zkcm_pg_eq3 = instance.pg_psi0_yy * self.response_r_rr + + instance.pg_psi0_gen2 * self.response_r_ss + + instance.pg_psi0_ww1 * self.response_r_varsig2 + + instance.pg_psi0_ww2 * self.response_r_theta2 + + instance.pg_eq3 * self.challenge; + + let zkcm_pg_eq4 = instance.pg_rr_psi1 * self.response_r_tt + + instance.pg_psi0_tt * self.response_r_rr + + instance.pg_psi0_psi1 * self.response_r_rho3.neg() + + instance.pg_eq4 * self.challenge; + + // re-compute the challenge + let challenge = compute_challenge::( + std::iter::once(g1.to_bytes().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_phi0.to_bytes().as_ref())) + .chain(std::iter::once(zkcm_phi1.to_bytes().as_ref())) + .chain(std::iter::once(zkcm_varphi0.to_bytes().as_ref())) + .chain(std::iter::once(zkcm_varphi1.to_bytes().as_ref())) + // .chain(std::iter::once(zkcm_pg_eq1.to_compressed().as_ref())) + // .chain(std::iter::once(zkcm_pg_eq2.to_compressed().as_ref())) + // .chain(std::iter::once(zkcm_pg_eq3.to_compressed().as_ref())) + .chain(std::iter::once(zkcm_pg_eq4.to_compressed().as_ref())) + ); + + challenge == self.challenge + } +} + +#[cfg(test)] +mod tests { + use std::ops::Neg; + + use bls12_381::{G2Projective, pairing}; + use group::Curve; + use rand::thread_rng; + + use crate::proofs::proof_spend::{SpendInstance, SpendProof, SpendWitness}; + use crate::scheme::{PayInfo, Phi, VarPhi}; + use crate::scheme::aggregation::aggregate_verification_keys; + use crate::scheme::keygen::{PublicKeyUser, SecretKeyUser, ttp_keygen_authorities, VerificationKeyAuth}; + use crate::scheme::setup::{GroupParameters, Parameters}; + use crate::utils::hash_to_scalar; + + #[test] + fn spend_proof_construct_and_verify() { + let rng = thread_rng(); + let grp = GroupParameters::new().unwrap(); + let params = Parameters::new(grp.clone()); + let params_u = params.get_params_u(); + let params_a = params.get_params_a(); + + let sk = grp.random_scalar(); + let pk_user = PublicKeyUser { + pk: grp.gen1() * sk, + }; + let v = grp.random_scalar(); + let attributes = vec![sk, v]; + let l: usize = 10; + let vv: u64 = 20; + + let authorities_keypairs = ttp_keygen_authorities(¶ms, 2, 3).unwrap(); + let verification_keys_auth: Vec = authorities_keypairs + .iter() + .map(|keypair| keypair.verification_key()) + .collect(); + + let verification_key = + aggregate_verification_keys(&verification_keys_auth, Some(&[1, 2, 3])).unwrap(); + + let r = grp.random_scalar(); + let kappa = grp.gen2() * r + + verification_key.alpha + + attributes + .iter() + .zip(verification_key.beta_g2.iter()) + .map(|(priv_attr, beta_i)| beta_i * priv_attr) + .sum::(); + + let r1 = grp.random_scalar(); + let r2 = grp.random_scalar(); + let phi = Phi(grp.gen1() * r1, params_u.get_ith_sigma(l as usize) * v + params_u.get_ith_eta(vv as usize) * r1); + + let pay_info = PayInfo { info: [78u8; 32] }; + let rr = hash_to_scalar(pay_info.info); + let varphi = VarPhi(grp.gen1() * r2, (grp.gen1() * rr) * sk + params_u.get_ith_theta(l as usize) * v + params_u.get_ith_eta(vv as usize) * r2); + + // random value used to compute blinded bases + let r_varsig1 = grp.random_scalar(); + let r_theta1 = grp.random_scalar(); + let r_varsig2 = grp.random_scalar(); + let r_theta2 = grp.random_scalar(); + let r_rr = grp.random_scalar(); + let r_ss = grp.random_scalar(); + let r_tt = grp.random_scalar(); + + + // compute blinded bases + let psi_g1 = params_u.get_psi_g1(); + let psi_g2 = params_u.get_psi_g2(); + let varsig_prime1 = params_u.get_ith_sigma(l as usize) + (psi_g1 * r_varsig1); + let theta_prime1 = params_u.get_ith_theta(l as usize) + (psi_g1 * r_theta1); + let varsig_prime2 = params_u.get_ith_sigma(l as usize + vv as usize - 1) + (psi_g1 * r_varsig2); + let theta_prime2 = params_u.get_ith_sigma(l as usize + vv as usize - 1) + (psi_g1 * r_theta2); + let rr_prime = params_u.get_ith_sps_sign(l as usize + vv as usize - 1).rr + (psi_g1 * r_rr); + let ss_prime = params_u.get_ith_sps_sign(l as usize + vv as usize - 1).ss + (psi_g1 * r_ss); + let tt_prime = params_u.get_ith_sps_sign(l as usize + vv as usize - 1).tt + (psi_g2 * r_tt); + + let rho1 = v.neg() * r_varsig1; + let rho2 = v.neg() * r_theta1; + let rho3 = r_rr * r_tt; + + let pg_varsigpr1_delta = pairing(&varsig_prime1.to_affine(), ¶ms_a.get_ith_delta((vv - 1) as usize).to_affine()); + let pg_psi0_delta = pairing(&psi_g1.to_affine(), ¶ms_a.get_ith_delta((vv - 1) as usize).to_affine()); + let pg_varsigpr2_gen2 = pairing(&varsig_prime2.to_affine(), grp.gen2()); + let pg_psi0_gen2 = pairing(&psi_g1.to_affine(), grp.gen2()); + let pg_thetapr1_delta = pairing(&theta_prime1.to_affine(), ¶ms_a.get_ith_delta((vv - 1) as usize).to_affine()); + let pg_thetapr2_gen2 = pairing(&theta_prime2.to_affine(), grp.gen2()); + let yy = params_u.get_sps_pk().get_yy(); + let pg_rrprime_yy = pairing(&rr_prime.to_affine(), &yy.to_affine()); + let pg_psi0_yy = pairing(&psi_g1.to_affine(), &yy.to_affine()); + let pg_ssprime_gen2 = pairing(&ss_prime.to_affine(), grp.gen2()); + let ww1 = params_u.get_sps_pk().get_ith_ww(0); + let ww2 = params_u.get_sps_pk().get_ith_ww(1); + let pg_varsigpr2_ww1 = pairing(&varsig_prime2.to_affine(), &ww1.to_affine()); + let pg_psi0_ww1 = pairing(&psi_g1.to_affine(), &ww1.to_affine()); + let pg_thetapr2_ww2 = pairing(&theta_prime1.to_affine(), &ww2.to_affine()); + let pg_psi0_ww2 = pairing(&psi_g1.to_affine(), &ww2.to_affine()); + let pg_gen1_zz = pairing(grp.gen1(), ¶ms_u.get_sps_pk().get_zz().to_affine()); + let pg_rr_tt = pairing(&rr_prime.to_affine(), &tt_prime.to_affine()); + let pg_rr_psi1 = pairing(&rr_prime.to_affine(), &psi_g2.to_affine()); + let pg_psi0_tt = pairing(&psi_g1.to_affine(), &tt_prime.to_affine()); + let pg_psi0_psi1 = pairing(&psi_g1.to_affine(), &psi_g2.to_affine()); + let pg_gen1_gen2 = pairing(grp.gen1(), grp.gen2()); + + let pg_eq1 = pg_varsigpr1_delta - pg_varsigpr2_gen2; + let pg_eq2 = pg_thetapr1_delta - pg_thetapr2_gen2; + let pg_eq3 = pg_rrprime_yy + pg_ssprime_gen2 + pg_varsigpr2_ww1 + pg_thetapr2_ww2 + pg_gen1_zz.neg(); + let pg_eq4 = pg_rr_tt - pg_gen1_gen2; + + let instance = SpendInstance { + kappa, + phi, + varphi, + rr, + rr_prime, + ss: ss_prime, + tt: tt_prime, + varsig_prime1, + theta_prime1, + pg_eq1, + pg_eq2, + pg_eq3, + pg_eq4, + psi_g1: *psi_g1, + psi_g2: *psi_g2, + pg_psi0_delta, + pg_psi0_gen2, + pg_psi0_yy, + pg_psi0_ww1, + pg_psi0_ww2, + pg_rr_psi1, + pg_psi0_tt, + pg_psi0_psi1, + }; + + let witness = SpendWitness { + sk_u: SecretKeyUser { sk }, + v, + r, + r1, + r2, + r_varsig1, + r_theta1, + r_varsig2, + r_theta2, + r_rr, + r_ss, + r_tt, + rho1, + rho2, + rho3, + }; + + // compute the zk proof + let zk_proof = SpendProof::construct(¶ms, &instance, &witness, &verification_key, vv); + assert!(zk_proof.verify(¶ms, &instance, &verification_key, vv)) } } - diff --git a/common/nym_offline_divisible_ecash/src/scheme/mod.rs b/common/nym_offline_divisible_ecash/src/scheme/mod.rs index 35e7e5640d..90948324ce 100644 --- a/common/nym_offline_divisible_ecash/src/scheme/mod.rs +++ b/common/nym_offline_divisible_ecash/src/scheme/mod.rs @@ -1,7 +1,8 @@ use std::cell::Cell; +use std::ops::Neg; use bls12_381::{G1Projective, G2Prepared, G2Projective, pairing, Scalar}; -use group::Curve; +use group::{Curve, GroupEncoding}; use crate::Attribute; use crate::constants::L; @@ -36,9 +37,26 @@ pub fn compute_kappa( #[derive(Debug, Clone, Copy)] pub struct Phi(pub(crate) G1Projective, pub(crate) G1Projective); +impl Phi { + pub(crate) fn to_bytes(&self) -> Vec { + let mut bytes = Vec::with_capacity(48 + 48); + bytes.extend_from_slice(self.0.to_bytes().as_ref()); + bytes.extend_from_slice(self.1.to_bytes().as_ref()); + bytes + } +} + #[derive(Debug, Clone, Copy)] pub struct VarPhi(pub(crate) G1Projective, pub(crate) G1Projective); +impl VarPhi { + pub(crate) fn to_bytes(&self) -> Vec { + let mut bytes = Vec::with_capacity(48 + 48); + bytes.extend_from_slice(self.0.to_bytes().as_ref()); + bytes.extend_from_slice(self.1.to_bytes().as_ref()); + bytes + } +} pub struct PayInfo { pub info: [u8; 32], @@ -51,7 +69,7 @@ pub struct Payment { phi: Phi, varphi: VarPhi, rr: Scalar, - zkproof: SpendProof, + zk_proof: SpendProof, vv: u64, } @@ -135,69 +153,72 @@ impl Wallet { let r_tt = grp.random_scalar(); // compute blinded bases - let psi0 = params_u.get_psi0(); - let psi1 = params_u.get_psi1(); - let varsig_prime1 = params_u.get_ith_sigma(self.l() as usize) + (psi0 * r_varsig1); - let theta_prime1 = params_u.get_ith_theta(self.l() as usize) + (psi0 * r_theta1); - let varsig_prime2 = params_u.get_ith_sigma(self.l() as usize + vv as usize - 1) + (psi0 * r_varsig2); - let theta_prime2 = params_u.get_ith_sigma(self.l() as usize + vv as usize - 1) + (psi0 * r_theta2); - let rr_prime = params_u.get_ith_sps_sign(self.l() as usize + vv as usize - 1).rr + (psi0 * r_rr); - let ss_prime = params_u.get_ith_sps_sign(self.l() as usize + vv as usize - 1).ss + (psi0 * r_ss); - let tt_prime = params_u.get_ith_sps_sign(self.l() as usize + vv as usize - 1).tt + (psi1 * r_tt); + let psi_g1 = params_u.get_psi_g1(); + let psi_g2 = params_u.get_psi_g2(); + let varsig_prime1 = params_u.get_ith_sigma(self.l() as usize) + (psi_g1 * r_varsig1); + let theta_prime1 = params_u.get_ith_theta(self.l() as usize) + (psi_g1 * r_theta1); + let varsig_prime2 = params_u.get_ith_sigma(self.l() as usize + vv as usize - 1) + (psi_g1 * r_varsig2); + let theta_prime2 = params_u.get_ith_sigma(self.l() as usize + vv as usize - 1) + (psi_g1 * r_theta2); + let rr_prime = params_u.get_ith_sps_sign(self.l() as usize + vv as usize - 1).rr + (psi_g1 * r_rr); + let ss_prime = params_u.get_ith_sps_sign(self.l() as usize + vv as usize - 1).ss + (psi_g1 * r_ss); + let tt_prime = params_u.get_ith_sps_sign(self.l() as usize + vv as usize - 1).tt + (psi_g2 * r_tt); let rho1 = self.v.neg() * r_varsig1; let rho2 = self.v.neg() * r_theta1; let rho3 = r_rr * r_tt; let pg_varsigpr1_delta = pairing(&varsig_prime1.to_affine(), ¶ms_a.get_ith_delta((vv - 1) as usize).to_affine()); - let pg_psi0_delta = pairing(&psi0.to_affine(), ¶ms_a.get_ith_delta((vv - 1) as usize).to_affine()); + let pg_psi0_delta = pairing(&psi_g1.to_affine(), ¶ms_a.get_ith_delta((vv - 1) as usize).to_affine()); let pg_varsigpr2_gen2 = pairing(&varsig_prime2.to_affine(), grp.gen2()); - let pg_psi0_gen2 = pairing(&psi0.to_affine(), grp.gen2()); + let pg_psi0_gen2 = pairing(&psi_g1.to_affine(), grp.gen2()); let pg_thetapr1_delta = pairing(&theta_prime1.to_affine(), ¶ms_a.get_ith_delta((vv - 1) as usize).to_affine()); - let pg_thetapr2_gen2 = pairing(&theta_prime1.to_affine(), grp.gen2()); + let pg_thetapr2_gen2 = pairing(&theta_prime2.to_affine(), grp.gen2()); let yy = params_u.get_sps_pk().get_yy(); - let pg_rr_yy = pairing(&rr_prime.to_affine(), &yy.to_affine()); - let pg_psi0_yy = pairing(&psi0.to_affine(), &yy.to_affine()); + let pg_rrprime_yy = pairing(&rr_prime.to_affine(), &yy.to_affine()); + let pg_psi0_yy = pairing(&psi_g1.to_affine(), &yy.to_affine()); let pg_ssprime_gen2 = pairing(&ss_prime.to_affine(), grp.gen2()); let ww1 = params_u.get_sps_pk().get_ith_ww(0); let ww2 = params_u.get_sps_pk().get_ith_ww(1); let pg_varsigpr2_ww1 = pairing(&varsig_prime2.to_affine(), &ww1.to_affine()); - let pg_psi0_ww1 = pairing(&psi0.to_affine(), &ww1.to_affine()); + let pg_psi0_ww1 = pairing(&psi_g1.to_affine(), &ww1.to_affine()); let pg_thetapr2_ww2 = pairing(&theta_prime1.to_affine(), &ww2.to_affine()); - let pg_psi0_ww2 = pairing(&psi0.to_affine(), &ww2.to_affine()); + let pg_psi0_ww2 = pairing(&psi_g1.to_affine(), &ww2.to_affine()); let pg_gen1_zz = pairing(grp.gen1(), ¶ms_u.get_sps_pk().get_zz().to_affine()); let pg_rr_tt = pairing(&rr_prime.to_affine(), &tt_prime.to_affine()); - let pg_rr_psi1 = pairing(&rr_prime.to_affine(), &psi1.to_affine()); - let pg_psi0_tt = pairing(&psi0.to_affine(), &tt_prime.to_affine()); - let pg_psi0_psi1 = pairing(&psi0.to_affine(), &psi1.to_affine()); + let pg_rr_psi1 = pairing(&rr_prime.to_affine(), &psi_g2.to_affine()); + let pg_psi0_tt = pairing(&psi_g1.to_affine(), &tt_prime.to_affine()); + let pg_psi0_psi1 = pairing(&psi_g1.to_affine(), &psi_g2.to_affine()); let pg_gen1_gen2 = pairing(grp.gen1(), grp.gen2()); + let pg_eq1 = pg_varsigpr1_delta - pg_varsigpr2_gen2; + let pg_eq2 = pg_thetapr1_delta - pg_thetapr2_gen2; + let pg_eq3 = pg_rrprime_yy + pg_ssprime_gen2 + pg_varsigpr2_ww1 + pg_thetapr2_ww2 + pg_gen1_zz.neg(); + let pg_eq4 = pg_rr_tt - pg_gen1_gen2; + let instance = SpendInstance { kappa, phi, varphi, - rr: rr_prime, + rr, + rr_prime, ss: ss_prime, tt: tt_prime, - pg_varsigpr1_delta, + varsig_prime1, + theta_prime1, + pg_eq1, + pg_eq2, + pg_eq3, + pg_eq4, + psi_g1: *psi_g1, + psi_g2: *psi_g2, pg_psi0_delta, - pg_varsigpr2_gen2, pg_psi0_gen2, - pg_thetapr1_delta, - pg_thetapr2_gen2, - pg_rr_yy, pg_psi0_yy, - pg_ssprime_gen2, - pg_varsigpr2_ww1, pg_psi0_ww1, - pg_thetapr2_ww2, pg_psi0_ww2, - pg_gen1_zz, - pg_rr_tt, pg_rr_psi1, pg_psi0_tt, pg_psi0_psi1, - pg_gen1_gen2, }; let witness = SpendWitness { @@ -219,7 +240,7 @@ impl Wallet { }; // compute the zk proof - let zkproof = SpendProof::construct(params, &instance, &witness); + let zk_proof = SpendProof::construct(params, &instance, &witness, &verification_key, vv); // output pay and updated wallet let pay = Payment { @@ -228,7 +249,7 @@ impl Wallet { phi, varphi, rr, - zkproof, + zk_proof, vv, }; diff --git a/common/nym_offline_divisible_ecash/src/scheme/setup.rs b/common/nym_offline_divisible_ecash/src/scheme/setup.rs index 2ad5731953..452b2c5da6 100644 --- a/common/nym_offline_divisible_ecash/src/scheme/setup.rs +++ b/common/nym_offline_divisible_ecash/src/scheme/setup.rs @@ -17,6 +17,7 @@ pub struct GroupParameters { _g2_prepared_miller: G2Prepared, } + impl GroupParameters { pub fn new() -> Result { Ok(GroupParameters { @@ -66,8 +67,9 @@ impl Parameters { pub fn new(grp: GroupParameters) -> Parameters { let g1 = grp.gen1(); let g2 = grp.gen2(); - let psi1 = hash_g1("psi1"); - let psi2 = hash_g2("psi2"); + + let psi_g1 = hash_g1("psi1"); + let psi_g2 = hash_g2("psi2"); let gamma1 = hash_g1("gamma1"); let gamma2 = hash_g1("gamma2"); let eta = hash_g1("eta"); @@ -96,9 +98,7 @@ impl Parameters { let mut etas_a: Vec = Default::default(); for l in 1..=L { - println!("l = {:?}", l); for k in 0..=l - 1 { - println!("k = {:?}", k); etas_a.push(g2 * (vec_a[l as usize - 1].neg() * (y * Scalar::from(k)))); } } @@ -115,8 +115,8 @@ impl Parameters { // Compute signature for each pair sigma, theta let params_u = ParametersUser { gammas: vec![gamma1, gamma2], - psi1, - psi2, + psi_g1, + psi_g2, eta, omega, etas: etas_u, @@ -142,8 +142,8 @@ impl Parameters { #[derive(Debug, Clone)] pub struct ParametersUser { gammas: Vec, - psi1: G1Projective, - psi2: G2Projective, + psi_g1: G1Projective, + psi_g2: G2Projective, eta: G1Projective, omega: G1Projective, etas: Vec, @@ -156,9 +156,9 @@ pub struct ParametersUser { impl ParametersUser { pub(crate) fn get_gammas(&self) -> &Vec { &self.gammas } - pub(crate) fn get_psi0(&self) -> &G1Projective { &self.psi1 } + pub(crate) fn get_psi_g1(&self) -> &G1Projective { &self.psi_g1 } - pub(crate) fn get_psi1(&self) -> &G2Projective { &self.psi2 } + pub(crate) fn get_psi_g2(&self) -> &G2Projective { &self.psi_g2 } pub(crate) fn get_eta(&self) -> &G1Projective { &self.eta } diff --git a/common/nym_offline_divisible_ecash/src/utils.rs b/common/nym_offline_divisible_ecash/src/utils.rs index f2c69f0e1b..14d4066f8a 100644 --- a/common/nym_offline_divisible_ecash/src/utils.rs +++ b/common/nym_offline_divisible_ecash/src/utils.rs @@ -36,7 +36,7 @@ impl Polynomial { Scalar::zero() // if x is zero then we can ignore most of the expensive computation and // just return the last term of the polynomial - } else if x.is_zero() { + } else if x.is_zero().unwrap_u8() == 1 { // we checked that coefficients are not empty so unwrap here is fine *self.coefficients.first().unwrap() } else {