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 5c70e8b922..e0fad6b857 100644 --- a/common/nym_offline_divisible_ecash/src/proofs/proof_spend.rs +++ b/common/nym_offline_divisible_ecash/src/proofs/proof_spend.rs @@ -1,4 +1,4 @@ -use bls12_381::{G1Projective, G2Projective, Scalar}; +use bls12_381::{G1Projective, G2Projective, Gt, Scalar}; use crate::scheme::{Phi, VarPhi}; use crate::scheme::keygen::{SecretKeyUser, VerificationKeyAuth}; @@ -7,25 +7,59 @@ use crate::scheme::setup::Parameters; pub struct SpendInstance { pub kappa: G2Projective, pub phi: Phi, - pub var_phi: VarPhi, + pub varphi: VarPhi, pub rr: G1Projective, pub ss: G1Projective, - pub tt: G1Projective, + pub tt: G2Projective, + pub pg_varsigpr1_delta: Gt, + 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, } pub struct SpendWitness { - sk_u: SecretKeyUser, - v: Scalar, - r: Scalar, - r1: Scalar, - r2: Scalar, + pub sk_u: SecretKeyUser, + pub v: Scalar, + pub r: Scalar, + pub r1: Scalar, + pub r2: Scalar, + pub r_varsig1: Scalar, + pub r_theta1: Scalar, + pub r_varsig2: Scalar, + pub r_theta2: Scalar, + pub r_rr: Scalar, + pub r_ss: Scalar, + pub r_tt: Scalar, + pub rho1: Scalar, + pub rho2: Scalar, + pub rho3: Scalar, } #[derive(Debug, Clone)] pub struct SpendProof {} impl SpendProof { - pub fn construct() {} + pub fn construct( + params: &Parameters, + instance: &SpendInstance, + witness: &SpendWitness) -> Self { + SpendProof {} + } } diff --git a/common/nym_offline_divisible_ecash/src/scheme/mod.rs b/common/nym_offline_divisible_ecash/src/scheme/mod.rs index 5a2c8bf665..35e7e5640d 100644 --- a/common/nym_offline_divisible_ecash/src/scheme/mod.rs +++ b/common/nym_offline_divisible_ecash/src/scheme/mod.rs @@ -1,12 +1,12 @@ use std::cell::Cell; -use bls12_381::{G1Projective, G2Prepared, G2Projective, Scalar}; +use bls12_381::{G1Projective, G2Prepared, G2Projective, pairing, Scalar}; use group::Curve; use crate::Attribute; use crate::constants::L; use crate::error::{DivisibleEcashError, Result}; -use crate::proofs::proof_spend::SpendProof; +use crate::proofs::proof_spend::{SpendInstance, SpendProof, SpendWitness}; use crate::scheme::keygen::{SecretKeyUser, VerificationKeyAuth}; use crate::scheme::setup::{GroupParameters, Parameters}; use crate::utils::{check_bilinear_pairing, hash_to_scalar, Signature, SignerIndex}; @@ -33,10 +33,10 @@ pub fn compute_kappa( .sum::() } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] pub struct Phi(pub(crate) G1Projective, pub(crate) G1Projective); -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] pub struct VarPhi(pub(crate) G1Projective, pub(crate) G1Projective); @@ -104,6 +104,7 @@ impl Wallet { let grp = params.get_grp(); let params_u = params.get_params_u(); + let params_a = params.get_params_a(); // randomize signature in the wallet let (signature_prime, sign_blinding_factor) = self.signature().randomise(grp); // construct kappa i.e., blinded attributes for show @@ -123,8 +124,102 @@ impl Wallet { // compute hash of the payment info let rr = hash_to_scalar(pay_info.info); let varphi = VarPhi(grp.gen1() * r2, (grp.gen1() * rr) * sk_user.sk + params_u.get_ith_theta(self.l.get() as usize) * self.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 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 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_varsigpr2_gen2 = pairing(&varsig_prime2.to_affine(), grp.gen2()); + let pg_psi0_gen2 = pairing(&psi0.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 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_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_thetapr2_ww2 = pairing(&theta_prime1.to_affine(), &ww2.to_affine()); + let pg_psi0_ww2 = pairing(&psi0.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_gen1_gen2 = pairing(grp.gen1(), grp.gen2()); + + let instance = SpendInstance { + kappa, + phi, + varphi, + rr: rr_prime, + ss: ss_prime, + tt: tt_prime, + pg_varsigpr1_delta, + 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 { + sk_u: sk_user.clone(), + v: self.v, + r: sign_blinding_factor, + r1, + r2, + r_varsig1, + r_theta1, + r_varsig2, + r_theta2, + r_rr, + r_ss, + r_tt, + rho1, + rho2, + rho3, + }; + // compute the zk proof - let zkproof = SpendProof {}; + let zkproof = SpendProof::construct(params, &instance, &witness); // output pay and updated wallet let pay = Payment { diff --git a/common/nym_offline_divisible_ecash/src/scheme/setup.rs b/common/nym_offline_divisible_ecash/src/scheme/setup.rs index def5f2de32..2ad5731953 100644 --- a/common/nym_offline_divisible_ecash/src/scheme/setup.rs +++ b/common/nym_offline_divisible_ecash/src/scheme/setup.rs @@ -5,7 +5,7 @@ use rand::thread_rng; use crate::constants::L; use crate::error::Result; use crate::scheme::structure_preserving_signature::{SPSKeyPair, SPSSignature, SPSVerificationKey}; -use crate::utils::hash_g1; +use crate::utils::{hash_g1, hash_g2}; #[derive(Debug, Clone)] pub struct GroupParameters { @@ -67,7 +67,7 @@ impl Parameters { let g1 = grp.gen1(); let g2 = grp.gen2(); let psi1 = hash_g1("psi1"); - let psi2 = hash_g1("psi2"); + let psi2 = hash_g2("psi2"); let gamma1 = hash_g1("gamma1"); let gamma2 = hash_g1("gamma2"); let eta = hash_g1("eta"); @@ -115,7 +115,8 @@ impl Parameters { // Compute signature for each pair sigma, theta let params_u = ParametersUser { gammas: vec![gamma1, gamma2], - psi: vec![psi1, psi2], + psi1, + psi2, eta, omega, etas: etas_u, @@ -141,7 +142,8 @@ impl Parameters { #[derive(Debug, Clone)] pub struct ParametersUser { gammas: Vec, - psi: Vec, + psi1: G1Projective, + psi2: G2Projective, eta: G1Projective, omega: G1Projective, etas: Vec, @@ -154,7 +156,9 @@ pub struct ParametersUser { impl ParametersUser { pub(crate) fn get_gammas(&self) -> &Vec { &self.gammas } - pub(crate) fn get_psi(&self) -> &Vec { &self.psi } + pub(crate) fn get_psi0(&self) -> &G1Projective { &self.psi1 } + + pub(crate) fn get_psi1(&self) -> &G2Projective { &self.psi2 } pub(crate) fn get_eta(&self) -> &G1Projective { &self.eta } @@ -188,5 +192,9 @@ pub struct ParametersAuthority { impl ParametersAuthority { pub(crate) fn get_deltas(&self) -> &[G2Projective] { &self.deltas } + pub(crate) fn get_ith_delta(&self, idx: usize) -> &G2Projective { self.deltas.get(idx).unwrap() } + pub(crate) fn get_etas(&self) -> &[G2Projective] { &self.etas } + + pub(crate) fn get_ith_eta(&self, idx: usize) -> &G2Projective { self.etas.get(idx).unwrap() } } diff --git a/common/nym_offline_divisible_ecash/src/scheme/structure_preserving_signature.rs b/common/nym_offline_divisible_ecash/src/scheme/structure_preserving_signature.rs index e7f1012e7c..fe323cbaba 100644 --- a/common/nym_offline_divisible_ecash/src/scheme/structure_preserving_signature.rs +++ b/common/nym_offline_divisible_ecash/src/scheme/structure_preserving_signature.rs @@ -72,6 +72,12 @@ impl SPSVerificationKey { pub fn verify() -> bool { return true; } + + pub fn get_ith_ww(&self, idx: usize) -> &G2Projective { return self.wws.get(idx).unwrap(); } + + pub fn get_zz(&self) -> &G2Projective { return &self.zz; } + + pub fn get_yy(&self) -> &G2Projective { return &self.yy; } } pub struct SPSKeyPair { @@ -110,7 +116,7 @@ impl SPSKeyPair { #[derive(Debug, Clone)] pub struct SPSSignature { - rr: G1Projective, - ss: G1Projective, - tt: G2Projective, + pub rr: G1Projective, + pub ss: G1Projective, + pub tt: G2Projective, } diff --git a/common/nym_offline_divisible_ecash/src/utils.rs b/common/nym_offline_divisible_ecash/src/utils.rs index 95da93d921..f2c69f0e1b 100644 --- a/common/nym_offline_divisible_ecash/src/utils.rs +++ b/common/nym_offline_divisible_ecash/src/utils.rs @@ -6,10 +6,10 @@ use core::ops::Mul; use std::convert::{TryFrom, TryInto}; use std::ops::Neg; -use bls12_381::hash_to_curve::{ExpandMsgXmd, HashToCurve, HashToField}; use bls12_381::{ - multi_miller_loop, G1Affine, G1Projective, G2Affine, G2Prepared, G2Projective, Scalar, + G1Affine, G1Projective, G2Affine, G2Prepared, G2Projective, multi_miller_loop, Scalar, }; +use bls12_381::hash_to_curve::{ExpandMsgXmd, HashToCurve, HashToField}; use ff::Field; use group::{Curve, Group}; @@ -85,9 +85,9 @@ pub(crate) fn perform_lagrangian_interpolation_at_origin( points: &[SignerIndex], values: &[T], ) -> Result -where - T: Sum, - for<'a> &'a T: Mul, + where + T: Sum, + for<'a> &'a T: Mul, { if points.is_empty() || values.is_empty() { return Err(DivisibleEcashError::Interpolation( @@ -123,6 +123,9 @@ where // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#appendix-J.9.1 const G1_HASH_DOMAIN: &[u8] = b"QUUX-V01-CS02-with-BLS12381G1_XMD:SHA-256_SSWU_RO_"; +// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#appendix-J.10.1 +const G2_HASH_DOMAIN: &[u8] = b"QUUX-V01-CS02-with-BLS12381G2_XMD:SHA-256_SSWU_RO_"; + // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#appendix-K.1 const SCALAR_HASH_DOMAIN: &[u8] = b"QUUX-V01-CS02-with-expander"; @@ -130,6 +133,10 @@ pub fn hash_g1>(msg: M) -> G1Projective { >>::hash_to_curve(msg, G1_HASH_DOMAIN) } +pub fn hash_g2>(msg: M) -> G2Projective { + >>::hash_to_curve(msg, G2_HASH_DOMAIN) +} + pub fn hash_to_scalar>(msg: M) -> Scalar { let mut output = vec![Scalar::zero()];