Add bilinear equations into the zk proof; the last eq passes the tests

This commit is contained in:
aniampio
2022-05-24 21:16:43 +01:00
committed by durch
parent 2ec2613a89
commit aa018769c2
6 changed files with 529 additions and 72 deletions
Generated
+63 -5
View File
@@ -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",
]
@@ -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
@@ -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<u8> {
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::<G2Projective>();
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::<ChallengeDigest, _, _>(
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::<G2Projective>();
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::<ChallengeDigest, _, _>(
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(&params, 2, 3).unwrap();
let verification_keys_auth: Vec<VerificationKeyAuth> = 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::<G2Projective>();
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(), &params_a.get_ith_delta((vv - 1) as usize).to_affine());
let pg_psi0_delta = pairing(&psi_g1.to_affine(), &params_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(), &params_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(), &params_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(&params, &instance, &witness, &verification_key, vv);
assert!(zk_proof.verify(&params, &instance, &verification_key, vv))
}
}
@@ -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<u8> {
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<u8> {
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(), &params_a.get_ith_delta((vv - 1) as usize).to_affine());
let pg_psi0_delta = pairing(&psi0.to_affine(), &params_a.get_ith_delta((vv - 1) as usize).to_affine());
let pg_psi0_delta = pairing(&psi_g1.to_affine(), &params_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(), &params_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(), &params_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,
};
@@ -17,6 +17,7 @@ pub struct GroupParameters {
_g2_prepared_miller: G2Prepared,
}
impl GroupParameters {
pub fn new() -> Result<GroupParameters> {
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<G2Projective> = 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<G1Projective>,
psi1: G1Projective,
psi2: G2Projective,
psi_g1: G1Projective,
psi_g2: G2Projective,
eta: G1Projective,
omega: G1Projective,
etas: Vec<G1Projective>,
@@ -156,9 +156,9 @@ pub struct ParametersUser {
impl ParametersUser {
pub(crate) fn get_gammas(&self) -> &Vec<G1Projective> { &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 }
@@ -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 {