diff --git a/src/channels.rs b/src/channels.rs index 910247d..c9f6409 100644 --- a/src/channels.rs +++ b/src/channels.rs @@ -14,14 +14,14 @@ use pairing::{Engine, CurveProjective}; use pairing::bls12_381::{Bls12}; use ff::PrimeField; use cl::{BlindKeyPair, KeyPair, Signature, PublicParams, setup}; -use ped92::{CSParams, Commitment, CSMultiParams}; +use ped92::{CSParams, Commitment, CSMultiParams, CommitmentProof}; use util::{hash_pubkey_to_fr, convert_int_to_fr, hash_to_fr, RevokedMessage, hash_to_slice}; use rand::Rng; use std::collections::HashMap; use std::fmt::Display; use serde::{Serialize, Deserialize}; use std::ptr::hash; -use nizk::{NIZKPublicParams, CommitmentProof, Proof}; +use nizk::{NIZKPublicParams, NIZKProof}; use wallet::Wallet; use std::error::Error; use std::fmt; @@ -330,7 +330,7 @@ impl CustomerState { } // for channel pay - pub fn generate_payment(&self, csprng: &mut R, channel: &ChannelState, amount: i32) -> (Proof, Commitment, secp256k1::PublicKey, CustomerState) { + pub fn generate_payment(&self, csprng: &mut R, channel: &ChannelState, amount: i32) -> (NIZKProof, Commitment, secp256k1::PublicKey, CustomerState) { // 1 - chooose new wpk/wsk pair let mut kp = secp256k1::Secp256k1::new(); kp.randomize(csprng); @@ -557,7 +557,7 @@ impl MerchantState { return self.pay_tokens.get(&wpk_str).unwrap().clone(); } - pub fn verify_payment(&mut self, csprng: &mut R, channel: &ChannelState, proof: &Proof, com: &Commitment, wpk: &secp256k1::PublicKey, amount: i32) -> ResultBoltSig> { + pub fn verify_payment(&mut self, csprng: &mut R, channel: &ChannelState, proof: &NIZKProof, com: &Commitment, wpk: &secp256k1::PublicKey, amount: i32) -> ResultBoltSig> { let cp = channel.cp.as_ref().unwrap(); let pay_proof = proof.clone(); let prev_wpk = hash_pubkey_to_fr::(&wpk); diff --git a/src/lib.rs b/src/lib.rs index ee09afe..59ced12 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -130,9 +130,10 @@ pub mod bidirectional { pub use BoltResult; pub use channels::{ChannelState, ChannelToken, CustomerState, MerchantState, ChannelcloseM, PubKeyMap, ChannelParams, BoltError, ResultBoltSig}; - pub use nizk::{CommitmentProof, Proof}; + pub use nizk::NIZKProof; pub use wallet::Wallet; pub use cl::PublicParams; + pub use ped92::CommitmentProof; #[derive(Clone, Serialize, Deserialize)] #[serde(bound(serialize = "::Fr: serde::Serialize, \ @@ -157,7 +158,7 @@ pub mod bidirectional { ::Fqk: serde::Deserialize<'de>" ))] pub struct Payment { - proof: Proof, + proof: NIZKProof, com: Commitment, wpk: secp256k1::PublicKey, amount: i32, diff --git a/src/nizk.rs b/src/nizk.rs index 4488de9..6858698 100644 --- a/src/nizk.rs +++ b/src/nizk.rs @@ -4,14 +4,16 @@ extern crate rand; use super::*; use rand::Rng; use cl::{KeyPair, Signature, PublicParams, setup, BlindKeyPair, ProofState, SignatureProof, BlindPublicKey}; -use ped92::{CSParams, Commitment, CSMultiParams}; +use ped92::{CSParams, Commitment, CSMultiParams, CommitmentProof}; use pairing::{Engine, CurveProjective}; use ff::PrimeField; use wallet::Wallet; use ccs08::{RPPublicParams, RangeProof}; use serde::{Serialize, Deserialize}; use util; +use std::borrow::BorrowMut; +/// NIZKProof is the object that represents the NIZK Proof of Knowledge during the payment and closing protocol #[derive(Clone, Serialize, Deserialize)] #[serde(bound(serialize = "::Fr: serde::Serialize, \ ::G1: serde::Serialize, \ @@ -23,15 +25,15 @@ use util; ::G2: serde::Deserialize<'de>, \ ::Fqk: serde::Deserialize<'de>" ))] -pub struct Proof { +pub struct NIZKProof { pub sig: Signature, pub sigProof: SignatureProof, - pub D: E::G1, - pub z: Vec, + pub comProof: CommitmentProof, pub rpBC: RangeProof, pub rpBM: RangeProof, } +/// NIZKPublicParams are public parameters to perform a NIZK Proof of Knowledge during the payment and closing protocol #[derive(Clone, Serialize, Deserialize)] #[serde(bound(serialize = "::Fr: serde::Serialize, \ ::G1: serde::Serialize, \ @@ -50,6 +52,8 @@ pub struct NIZKPublicParams { } impl NIZKPublicParams { + /// Basic setup for the NIZKPublicParams + /// Takes as input a random generator and the length of the message which should be 4 during payment protocol and 5 for the closing protocol pub fn setup(rng: &mut R, messageLength: usize) -> Self { let mpk = setup(rng); let keypair = BlindKeyPair::::generate(rng, &mpk, messageLength); @@ -57,14 +61,25 @@ impl NIZKPublicParams { let rpParamsBC = RPPublicParams::setup(rng, 0, std::i16::MAX as i32, comParams.clone()); let rpParamsBM = RPPublicParams::setup(rng, 0, std::i16::MAX as i32, comParams.clone()); - NIZKPublicParams{mpk, keypair, comParams, rpParamsBC, rpParamsBM} + NIZKPublicParams { mpk, keypair, comParams, rpParamsBC, rpParamsBM } } + /** This method can be called to create the proof during the payment and closing protocol + Input: + rng: random generator + r: randomness of commitment of old wallet (TODO: still necessary?) + oldWallet: This is the wallet before payment occurs + newWallet: This is the new state of the wallet after payment + newWalletCom: A commitment of the new wallet + rPrime: randomness of commitment of new wallet + paymentToken: A blind signature on the old wallet + Output: + NIZKProof: a proof that can be verified by the merchant during payment or closing protocol + */ pub fn prove(&self, rng: &mut R, r: E::Fr, oldWallet: Wallet, newWallet: Wallet, - newWalletCom: Commitment, rPrime: E::Fr, paymentToken: &Signature) -> Proof { + newWalletCom: Commitment, rPrime: E::Fr, paymentToken: &Signature) -> NIZKProof { //Commitment phase //commit commitment - 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 { @@ -72,14 +87,7 @@ impl NIZKPublicParams { false => self.comParams.pub_bases.len() }; - let mut t = Vec::::with_capacity(max ); - for i in 0 .. max { - let ti = E::Fr::rand(rng); - t.push(ti); - let mut gt = self.comParams.pub_bases[i].clone(); - gt.mul_assign(ti.into_repr()); - D.add_assign(>); - } + let (D, t, rt, mut reveal_wallet) = CommitmentProof::::prove_commitment(rng, &self.comParams, &newWallet.as_fr_vec(), &vec! {}); //commit signature let zero = E::Fr::zero(); @@ -102,18 +110,8 @@ impl NIZKPublicParams { let sigProof = self.keypair.prove_response(&proofState, challenge, &mut oldWalletVec.clone()); //response commitment - let mut z = Vec::::with_capacity(t.len()); - let mut z0 = rPrime.clone(); - z0.mul_assign(&challenge); - z0.add_assign(&t[0]); - z.push(z0); let newWalletVec = newWallet.as_fr_vec(); - for i in 1..t.len() { - let mut zi = newWalletVec[i - 1].clone(); - zi.mul_assign(&challenge); - zi.add_assign(&t[i]); - z.push(zi); - } + let comProof = CommitmentProof::::prove_response(&newWalletVec, &rPrime, &vec! {}, D, &t, rt, reveal_wallet.borrow_mut(), &challenge); //response range proof let mut vec01 = newWalletVec[0..2].to_vec(); @@ -121,7 +119,7 @@ impl NIZKPublicParams { let mut vec3 = newWalletVec[3..].to_vec(); vecWithout2.append(&mut vec3); let vec2 = newWalletVec[2].clone(); - vec01.push( vec2); + vec01.push(vec2); if newWalletVec.len() > 4 { let mut vec4 = newWalletVec[4..].to_vec(); vec01.append(&mut vec4); @@ -129,15 +127,23 @@ impl NIZKPublicParams { let rpBC = self.rpParamsBC.prove_response(rPrime.clone(), &rpStateBC, challenge.clone(), 3, vecWithout2.to_vec()); let rpBM = self.rpParamsBM.prove_response(rPrime.clone(), &rpStateBM, challenge.clone(), 4, vec01.to_vec()); - Proof { sig: proofState.blindSig, sigProof, D, z, rpBC, rpBM } + NIZKProof { sig: proofState.blindSig, sigProof, comProof, rpBC, rpBM } } - pub fn verify(&self, proof: Proof, epsilon: E::Fr, com2: &Commitment, wpk: E::Fr) -> bool { + /** + Verify a NIZK Proof of Knowledge during payment or closing protocl + Input: + proof: A NIZK proof created by the Customer + epsilon: The transaction amount of the payment + com: Commitment of the new wallet that needs to be signed + wpk: reveal of wallet public key of the old wallet. + */ + pub fn verify(&self, proof: NIZKProof, epsilon: E::Fr, com: &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}); + let challenge = NIZKPublicParams::::hash(proof.sigProof.a, vec! {proof.comProof.T, proof.rpBC.p1.D, proof.rpBC.p2.D, proof.rpBM.p1.D, proof.rpBM.p2.D}); //verify knowledge of signature let mut r1 = self.keypair.public.verify_proof(&self.mpk, proof.sig, proof.sigProof.clone(), challenge); @@ -146,31 +152,22 @@ impl NIZKPublicParams { r1 = r1 && proof.sigProof.zsig[1] == wpkc; //verify knowledge of commitment - let mut comc = com2.c.clone(); - comc.mul_assign(challenge.into_repr()); - comc.add_assign(&proof.D.clone()); - let mut x = E::G1::zero(); - for i in 0..proof.z.len() { - let mut base = self.comParams.pub_bases[i].clone(); - base.mul_assign(proof.z[i].into_repr()); - x.add_assign(&base); - } - let r2 = x == comc; + let r2 = proof.comProof.verify_proof(&self.comParams, &com.c.clone(), &challenge); //verify range proofs let r3 = self.rpParamsBC.verify(proof.rpBC.clone(), challenge.clone(), 3); let r4 = self.rpParamsBM.verify(proof.rpBM.clone(), challenge.clone(), 4); //verify linear relationship - let mut r5 = proof.z[1] == proof.sigProof.zsig[0]; + let mut r5 = proof.comProof.z[1] == proof.sigProof.zsig[0]; let mut zsig2 = proof.sigProof.zsig[2].clone(); let mut epsC = epsilon.clone(); epsC.mul_assign(&challenge.clone()); zsig2.sub_assign(&epsC.clone()); - r5 = r5 && proof.z[3] == zsig2; + r5 = r5 && proof.comProof.z[3] == zsig2; let mut zsig3 = proof.sigProof.zsig[3].clone(); zsig3.add_assign(&epsC.clone()); - r5 = r5 && proof.z[4] == zsig3; + r5 = r5 && proof.comProof.z[4] == zsig3; r0 && r1 && r2 && r3 && r4 && r5 } @@ -186,104 +183,17 @@ impl NIZKPublicParams { } } -#[derive(Clone, Serialize, Deserialize, Debug)] -#[serde(bound(serialize = "::Fr: serde::Serialize, \ -::G1: serde::Serialize, \ -::G2: serde::Serialize" -))] -#[serde(bound(deserialize = "::Fr: serde::Deserialize<'de>, \ -::G1: serde::Deserialize<'de>, \ -::G2: serde::Deserialize<'de>" -))] -pub struct CommitmentProof { - pub T: E::G1, - pub z: Vec, - pub t: Vec, - pub index: Vec, - pub reveal: Vec -} - -impl CommitmentProof { - pub fn new(csprng: &mut R, com_params: &CSMultiParams, com: &E::G1, wallet: &Vec, r: &E::Fr, reveal_index: &Vec) -> Self { - let mut Tvals = E::G1::zero(); - assert!(wallet.len() <= com_params.pub_bases.len()); - - let mut t = Vec::::with_capacity( wallet.len()+1 ); - let mut rt: Vec = Vec::new(); // t values that will be revealed - let mut reveal_wallet: Vec = Vec::new(); // aspects of wallet being revealed - - for i in 0..wallet.len()+1 { - let ti = E::Fr::rand(csprng); - t.push(ti); - // check if we are revealing this index - if (reveal_index.contains(&i)) { - rt.push(ti); - } else { - rt.push( E::Fr::zero()); - } - let mut gt = com_params.pub_bases[i].clone(); - gt.mul_assign(ti.into_repr()); - Tvals.add_assign(>); - } - - // compute the challenge - let x: Vec = vec![Tvals, com.clone()]; - let challenge = util::hash_g1_to_fr::(&x); - - // compute the response - let mut z: Vec = Vec::new(); - let mut z0 = r.clone(); - z0.mul_assign(&challenge); - z0.add_assign(&t[0]); - z.push(z0); - reveal_wallet.push( E::Fr::zero()); - - for i in 1..t.len() { - let mut zi = wallet[i-1].clone(); - zi.mul_assign(&challenge); - zi.add_assign(&t[i]); - z.push(zi); - // check if we are revealing this index - if (reveal_index.contains(&i)) { - reveal_wallet.push(wallet[i-1].clone() ); - } else { - reveal_wallet.push( E::Fr::zero()); - } - } - - CommitmentProof { - T: Tvals, // commitment challenge - z: z, // response values - t: rt, // randomness for verifying partial reveals - index: reveal_index.clone(), - reveal: reveal_wallet - } - } -} - /// -/// Verify PoK for the opening of a commitment +/// Verify PoK for the opening of a commitment during the establishment protocol /// pub fn verify_opening(com_params: &CSMultiParams, com: &E::G1, proof: &CommitmentProof, init_cust: i32, init_merch: i32) -> bool { - - let mut comc = com.clone(); - let T = proof.T.clone(); - - let xvec: Vec = vec![T, comc]; + let xvec: Vec = vec![proof.T.clone(), com.clone()]; let challenge = util::hash_g1_to_fr::(&xvec); // compute the - comc.mul_assign(challenge.into_repr()); - comc.add_assign(&T); + let com_equal = proof.verify_proof(com_params, com, &challenge); - let mut x = E::G1::zero(); - for i in 0..proof.z.len() { - let mut base = com_params.pub_bases[i].clone(); - base.mul_assign(proof.z[i].into_repr()); - x.add_assign(&base); - } - - if (proof.index.len() == 0) { + if proof.index.len() == 0 { println!("verify_opening - doing any partial reveals?"); return false; } @@ -309,7 +219,7 @@ pub fn verify_opening(com_params: &CSMultiParams, com: &E::G1, pro let init_m = util::convert_int_to_fr::(init_merch); let bm_equal = (s4 == proof.z[4]) && (proof.reveal[4] == init_m); - return comc == x && pkc_equal && bc_equal && bm_equal; + return com_equal && pkc_equal && bc_equal && bm_equal; } @@ -344,7 +254,7 @@ mod tests { let paymentToken = pubParams.keypair.unblind(&r, &blindPaymentToken); let proof = pubParams.prove(rng, r, wallet1, wallet2, - commitment2.clone(), rprime, &paymentToken); + commitment2.clone(), rprime, &paymentToken); let fr = convert_int_to_fr::(*epsilon); assert_eq!(pubParams.verify(proof, fr, &commitment2, wpk), true); } @@ -499,7 +409,7 @@ mod tests { let com2 = pubParams.comParams.commit(&wallet2.as_fr_vec().clone(), &t); let com1_proof = CommitmentProof::::new(rng, &pubParams.comParams, - &com1.c, &wallet1.as_fr_vec(), &t, &vec![1, 3, 4]); + &com1.c, &wallet1.as_fr_vec(), &t, &vec![1, 3, 4]); assert!(verify_opening(&pubParams.comParams, &com1.c, &com1_proof, bc, bm)); assert!(!verify_opening(&pubParams.comParams, &com2.c, &com1_proof, bc2, bm)); @@ -524,5 +434,4 @@ mod tests { // deserialize } - } diff --git a/src/ped92.rs b/src/ped92.rs index 380c408..fc53585 100644 --- a/src/ped92.rs +++ b/src/ped92.rs @@ -1,10 +1,12 @@ // ped92.rs use rand::{thread_rng, Rng}; use pairing::{Engine, CurveProjective}; -use ff::Rand; +use ff::{Rand, Field, PrimeField}; use std::fmt; use util::is_vec_g1_equal; use serde::{Serialize, Deserialize}; +use util; +use std::borrow::BorrowMut; #[derive(Clone)] pub struct CSParams { @@ -173,6 +175,103 @@ impl CSMultiParams { } } +#[derive(Clone, Serialize, Deserialize, Debug)] +#[serde(bound(serialize = "::Fr: serde::Serialize, \ +::G1: serde::Serialize, \ +::G2: serde::Serialize" +))] +#[serde(bound(deserialize = "::Fr: serde::Deserialize<'de>, \ +::G1: serde::Deserialize<'de>, \ +::G2: serde::Deserialize<'de>" +))] +pub struct CommitmentProof { + pub T: E::G1, + pub z: Vec, + pub t: Vec, + pub index: Vec, + pub reveal: Vec +} + +impl CommitmentProof { + pub fn new(csprng: &mut R, com_params: &CSMultiParams, com: &E::G1, wallet: &Vec, r: &E::Fr, reveal_index: &Vec) -> Self { + let (Tvals, t, rt, mut reveal_wallet) = CommitmentProof::::prove_commitment::(csprng, com_params, wallet, reveal_index); + + // compute the challenge + let x: Vec = vec![Tvals, com.clone()]; + let challenge = util::hash_g1_to_fr::(&x); + + // compute the response + CommitmentProof::::prove_response(wallet, r, reveal_index, Tvals, &t, rt, reveal_wallet.borrow_mut(), &challenge) + } + + pub fn prove_commitment(csprng: &mut R, com_params: &CSMultiParams, wallet: &Vec, reveal_index: &Vec) -> (E::G1, Vec, Vec, Vec) { + let mut Tvals = E::G1::zero(); + assert!(wallet.len() <= com_params.pub_bases.len()); + let mut t = Vec::::with_capacity(wallet.len() + 1); + let mut rt: Vec = Vec::new(); + // t values that will be revealed + let mut reveal_wallet: Vec = Vec::new(); + // aspects of wallet being revealed + for i in 0..wallet.len() + 1 { + let ti = E::Fr::rand(csprng); + t.push(ti); + // check if we are revealing this index + if reveal_index.contains(&i) { + rt.push(ti); + } else { + rt.push(E::Fr::zero()); + } + let mut gt = com_params.pub_bases[i].clone(); + gt.mul_assign(ti.into_repr()); + Tvals.add_assign(>); + } + (Tvals, t, rt, reveal_wallet) + } + + pub fn prove_response(wallet: &Vec, r: &E::Fr, reveal_index: &Vec, Tvals: E::G1, t: &Vec, rt: Vec, reveal_wallet: &mut Vec, challenge: &E::Fr) -> CommitmentProof { + let mut z: Vec = Vec::new(); + let mut z0 = r.clone(); + z0.mul_assign(&challenge); + z0.add_assign(&t[0]); + z.push(z0); + reveal_wallet.push(E::Fr::zero()); + for i in 1..t.len() { + let mut zi = wallet[i - 1].clone(); + zi.mul_assign(&challenge); + zi.add_assign(&t[i]); + z.push(zi); + // check if we are revealing this index + if reveal_index.contains(&i) { + reveal_wallet.push(wallet[i - 1].clone()); + } else { + reveal_wallet.push(E::Fr::zero()); + } + } + + CommitmentProof { + T: Tvals, // commitment challenge + z: z, // response values + t: rt, // randomness for verifying partial reveals + index: reveal_index.clone(), + reveal: reveal_wallet.clone() + } + } + + pub fn verify_proof(&self, com_params: &CSMultiParams, com: &::G1, challenge: &E::Fr) -> bool { + let mut comc = com.clone(); + let T = self.T.clone(); + comc.mul_assign(challenge.into_repr()); + comc.add_assign(&T); + let mut x = E::G1::zero(); + for i in 0..self.z.len() { + let mut base = com_params.pub_bases[i].clone(); + base.mul_assign(self.z[i].into_repr()); + x.add_assign(&base); + } + comc == x + } +} + #[cfg(test)] mod tests { use super::*;