diff --git a/Cargo.toml b/Cargo.toml index e6d8e54..fc2a135 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,8 @@ rustc-serialize = "0.3" secp256k1 = { version = "0.15.0", features = ["rand", "serde"] } curve25519-dalek = { version = "1", features = ["serde"] } merlin = "1.0.0" -bulletproofs = { git = "https://github.com/dalek-cryptography/bulletproofs", branch = "main" } +#bulletproofs = { git = "https://github.com/dalek-cryptography/bulletproofs", branch = "main" } +bulletproofs = { git = "https://github.com/dalek-cryptography/bulletproofs", tag = "1.0.2" } sha2 = { version = "0.8", default-features = false } [dev-dependencies.bincode] diff --git a/src/cl.rs b/src/cl.rs index 84f8512..1a0b62a 100644 --- a/src/cl.rs +++ b/src/cl.rs @@ -167,7 +167,6 @@ pub struct BlindKeyPair { #[derive(Clone)] pub struct ProofState { pub v: E::Fr, - pub s: E::Fr, pub t: Vec, pub tt: E::Fr, pub a: E::Fqk, @@ -186,7 +185,6 @@ pub struct ProofState { ::Fqk: serde::Deserialize<'de>" ))] pub struct SignatureProof { - pub zx: E::Fr, pub zsig: Vec, pub zv: E::Fr, pub a: E::Fqk, @@ -363,7 +361,7 @@ impl BlindPublicKey { /// outputs: boolean pub fn verify_proof(&self, mpk: &PublicParams, blindSig: Signature, p: SignatureProof, challenge: E::Fr) -> bool { let mut gx = E::pairing(blindSig.h, self.X2); - gx = gx.pow(p.zx.into_repr()); + gx = gx.pow(challenge.into_repr()); for j in 0..self.Y2.len() { let mut gy = E::pairing(blindSig.h, self.Y2[j]); gy = gy.pow(p.zsig[j].into_repr()); @@ -492,23 +490,21 @@ impl BlindKeyPair { tOptional: Option>, ttOptional: Option) -> ProofState { let v = E::Fr::rand(rng); let blindSig = self.blind(rng, &v, signature); - let s = E::Fr::rand(rng); let mut t = tOptional.unwrap_or(Vec::::with_capacity(self.public.Y2.len())); let tt = ttOptional.unwrap_or(E::Fr::rand(rng)); - let mut gx = E::pairing(blindSig.h, self.public.X2); - gx = gx.pow(s.into_repr()); + let mut a = E::Fqk::one(); for j in 0..self.public.Y2.len() { if t.len() == j { t.push(E::Fr::rand(rng)); } let mut gy = E::pairing(blindSig.h, self.public.Y2[j]); gy = gy.pow(t[j].into_repr()); - gx.mul_assign(&gy); + a.mul_assign(&gy); } let mut h = E::pairing(blindSig.h, mpk.g2); h = h.pow(tt.into_repr()); - gx.mul_assign(&h); - ProofState { v, s, t, tt, a: gx, blindSig } + a.mul_assign(&h); + ProofState { v, t, tt, a, blindSig } } /// prove knowledge of a signature: response phase @@ -525,13 +521,11 @@ impl BlindKeyPair { } } - let mut zx = ps.s.clone(); - zx.add_assign(&challenge); let mut zv = ps.tt.clone(); let mut vic = ps.v.clone(); vic.mul_assign(&challenge); zv.add_assign(&vic); - SignatureProof { zsig, zx, zv, a: ps.a } + SignatureProof { zsig, zv, a: ps.a } } } diff --git a/src/nizk.rs b/src/nizk.rs index a196c33..26a6570 100644 --- a/src/nizk.rs +++ b/src/nizk.rs @@ -7,7 +7,6 @@ use cl::{KeyPair, Signature, PublicParams, setup, BlindKeyPair, ProofState, Sign use ped92::{CSParams, Commitment, CSMultiParams}; use pairing::{Engine, CurveProjective}; use ff::PrimeField; -use util::hash_g2_to_fr; use commit_scheme::commit; use wallet::Wallet; use ccs08::{RPPublicParams, RangeProof}; @@ -68,7 +67,7 @@ impl NIZKPublicParams { let mut D = E::G1::zero(); let w_len = newWallet.as_fr_vec().len(); let diff = self.comParams.pub_bases.len() - w_len; - let max = match (diff > 1) { + let max = match diff > 1 { true => w_len, false => self.comParams.pub_bases.len() }; @@ -83,16 +82,16 @@ impl NIZKPublicParams { } //commit signature - let fr1 = E::Fr::rand(rng); - let tOptional = match (max > 4) { - true => Some(vec!(t[1], fr1, t[3].clone(), t[4].clone())), - false => Some(vec!(t[1], fr1, t[3].clone())) + let zero = E::Fr::zero(); + let tOptional = match max > 4 { + true => Some(vec!(t[1], zero, t[3].clone(), t[4].clone())), + false => Some(vec!(t[1], zero, t[3].clone())) }; let proofState = self.keypair.prove_commitment(rng, &self.mpk, &paymentToken, tOptional, None); //commit range proof - let rpStateBC = self.rpParamsBC.prove_commitment(rng, newWallet.bc.clone(), newWalletCom.clone(), 3, Some(t[1..].to_vec()), Some(t[0].clone())); - let rpStateBM = self.rpParamsBM.prove_commitment(rng, newWallet.bm.clone(), newWalletCom.clone(), 4, Some(t[1..].to_vec()), Some(t[0].clone())); + let rpStateBC = self.rpParamsBC.prove_commitment(rng, newWallet.bc.clone(), newWalletCom.clone(), 3, None, None); + let rpStateBM = self.rpParamsBM.prove_commitment(rng, newWallet.bm.clone(), newWalletCom.clone(), 4, None, None); //Compute challenge let challenge = NIZKPublicParams::::hash(proofState.a, vec! {D, rpStateBC.ps1.D, rpStateBC.ps2.D, rpStateBM.ps1.D, rpStateBM.ps2.D}); @@ -136,11 +135,17 @@ impl NIZKPublicParams { } pub fn verify(&self, proof: Proof, epsilon: E::Fr, com2: &Commitment, wpk: E::Fr) -> bool { + //verify signature is not the identity + let r0 = proof.sig.h != E::G1::one(); + //compute challenge let challenge = NIZKPublicParams::::hash(proof.sigProof.a, vec! {proof.D, proof.rpBC.p1.D, proof.rpBC.p2.D, proof.rpBM.p1.D, proof.rpBM.p2.D}); //verify knowledge of signature - let r1 = self.keypair.public.verify_proof(&self.mpk, proof.sig, proof.sigProof.clone(), challenge); + let mut r1 = self.keypair.public.verify_proof(&self.mpk, proof.sig, proof.sigProof.clone(), challenge); + let mut wpkc = wpk.clone(); + wpkc.mul_assign(&challenge.clone()); + r1 = r1 && proof.sigProof.zsig[1] == wpkc; //verify knowledge of commitment let mut comc = com2.c.clone(); @@ -169,26 +174,7 @@ impl NIZKPublicParams { zsig3.add_assign(&epsC.clone()); r5 = r5 && proof.z[4] == zsig3; - r5 = r5 && proof.z[0] == proof.rpBC.p1.zr; - r5 = r5 && proof.z[0] == proof.rpBC.p2.zr; - r5 = r5 && proof.z[0] == proof.rpBM.p1.zr; - r5 = r5 && proof.z[0] == proof.rpBM.p2.zr; - for i in 1..proof.z.len() { - if i == 3 { - r5 = r5 && proof.z[i] == proof.rpBM.p1.zs[i-1]; - r5 = r5 && proof.z[i] == proof.rpBM.p2.zs[i-1].clone(); - } else if i >= 4 { - r5 = r5 && proof.z[i] == proof.rpBC.p1.zs[i-2].clone(); - r5 = r5 && proof.z[i] == proof.rpBC.p2.zs[i-2].clone(); - } else { - r5 = r5 && proof.z[i] == proof.rpBC.p1.zs[i-1].clone(); - r5 = r5 && proof.z[i] == proof.rpBC.p2.zs[i-1].clone(); - r5 = r5 && proof.z[i] == proof.rpBM.p1.zs[i-1].clone(); - r5 = r5 && proof.z[i] == proof.rpBM.p2.zs[i-1].clone(); - } - } - - r1 && r2 && r3 && r4 && r5 + r0 && r1 && r2 && r3 && r4 && r5 } fn hash(a: E::Fqk, T: Vec) -> E::Fr { @@ -206,6 +192,7 @@ impl NIZKPublicParams { mod tests { use super::*; use pairing::bls12_381::{Bls12, Fr}; + use util::convert_int_to_fr; #[test] fn nizk_proof_works() { @@ -233,8 +220,38 @@ mod tests { let proof = pubParams.prove(rng, r, wallet1, wallet2, commitment2.clone(), rprime, &paymentToken); + let fr = convert_int_to_fr::(*epsilon); + assert_eq!(pubParams.verify(proof, fr, &commitment2, wpk), true); + } - assert_eq!(pubParams.verify(proof, Fr::from_str(&epsilon.to_string()).unwrap(), &commitment2, wpk), true); + #[test] + fn nizk_proof_negative_value_works() { + let rng = &mut rand::thread_rng(); + let pkc = Fr::rand(rng); + let wpk = Fr::rand(rng); + let wpkprime = Fr::rand(rng); + let bc = rng.gen_range(100, 1000); + let mut bc2 = bc.clone(); + let bm = rng.gen_range(100, 1000); + let mut bm2 = bm.clone(); + let epsilon = &rng.gen_range(-100, -1); + bc2 -= epsilon; + bm2 += epsilon; + let r = Fr::rand(rng); + let rprime = Fr::rand(rng); + + let pubParams = NIZKPublicParams::::setup(rng, 4); + let wallet1 = Wallet { pkc, wpk, bc, bm, close: None }; + let commitment1 = pubParams.comParams.commit(&wallet1.as_fr_vec(), &r); + let wallet2 = Wallet { pkc, wpk: wpkprime, bc: bc2, bm: bm2, close: None }; + let commitment2 = pubParams.comParams.commit(&wallet2.as_fr_vec(), &rprime); + let blindPaymentToken = pubParams.keypair.sign_blind(rng, &pubParams.mpk, commitment1.clone()); + let paymentToken = pubParams.keypair.unblind(&r, &blindPaymentToken); + + let proof = pubParams.prove(rng, r, wallet1, wallet2, + commitment2.clone(), rprime, &paymentToken); + let fr = convert_int_to_fr::(*epsilon); + assert_eq!(pubParams.verify(proof, fr, &commitment2, wpk), true); } #[test] diff --git a/src/util.rs b/src/util.rs index 5f71e24..75eb8ad 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,7 +1,7 @@ use super::*; use sodiumoxide::crypto::hash::sha512; use pairing::{Engine, CurveProjective}; -use ff::PrimeField; +use ff::{PrimeField}; use rand::Rng; use ped92::CSMultiParams; use secp256k1::{Signature, PublicKey}; @@ -81,7 +81,9 @@ pub fn convert_int_to_fr(value: i32) -> E::Fr { } else { // negative value let value2 = value * -1; - let res = E::Fr::from_str(value2.to_string().as_str()).unwrap(); + let mut res = E::Fr::zero(); + let val = E::Fr::from_str(value2.to_string().as_str()).unwrap(); + res.sub_assign(&val); // TODO: look at how to do negation return res; } @@ -258,4 +260,14 @@ mod tests { assert_eq!(fmt_bytes_to_int([12, 235, 23, 123, 13, 43, 12, 235, 23, 123, 13, 43, 12, 235, 23, 123, 13, 43, 12, 235, 23, 123, 13, 43, 12, 235, 23, 123, 13, 43, 12, 235, 23, 123, 13, 43, 12, 235, 23, 123, 13, 43, 12, 235, 23, 123, 13, 43, 12, 235, 23, 123, 13, 43, 12, 235, 23, 123, 13, 43, 12, 235, 23, 123]), "122352312313431223523123134312235231231343122352312313431223523123134312235231231343122352312313431223523123134312235231231343122352312313431223523123"); } + + #[test] + fn convert_int_to_fr_works() { + assert_eq!(format!("{}", convert_int_to_fr::(1).into_repr()), + "0x0000000000000000000000000000000000000000000000000000000000000001"); + assert_eq!(format!("{}", convert_int_to_fr::(-1).into_repr()), + "0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000"); + assert_eq!(format!("{}", convert_int_to_fr::(365).into_repr()), + "0x000000000000000000000000000000000000000000000000000000000000016d"); + } }