Add partial reveal for NIZK during establish and unit tests for commit opening

This commit is contained in:
J. Ayo Akinyele 2019-08-19 18:29:26 -04:00
parent aaaccaeba0
commit 498263a9cc
4 changed files with 178 additions and 94 deletions

View File

@ -15,13 +15,13 @@ use pairing::bls12_381::{Bls12};
use ff::PrimeField;
use cl::{BlindKeyPair, KeyPair, Signature, PublicParams, setup};
use ped92::{CSParams, Commitment, CSMultiParams};
use util::{hash_pubkey_to_fr, convert_int_to_fr, hash_to_fr, CommitmentProof, RevokedMessage};
use util::{hash_pubkey_to_fr, convert_int_to_fr, hash_to_fr, RevokedMessage};
use rand::Rng;
use std::collections::HashMap;
use std::fmt::Display;
use serde::{Serialize, Deserialize};
use std::ptr::hash;
use nizk::{NIZKPublicParams, Proof};
use nizk::{NIZKPublicParams, CommitmentProof, Proof};
use wallet::Wallet;
use std::error::Error;
use std::fmt;
@ -275,7 +275,8 @@ impl<E: Engine> CustomerState<E> {
// generate nizk proof of knowledge of commitment opening
pub fn generate_proof<R: Rng>(&self, csprng: &mut R, channel_token: &ChannelToken<E>) -> CommitmentProof<E> {
return CommitmentProof::<E>::new(csprng, &channel_token.comParams, &self.w_com.c, &self.wallet.as_fr_vec(), &self.t, &vec![]);
// generate proof and do a partial reveal of pkc and bc/bm (init balances)
return CommitmentProof::<E>::new(csprng, &channel_token.comParams, &self.w_com.c, &self.wallet.as_fr_vec(), &self.t, &vec![1, 3, 4]);
}
pub fn verify_close_token(&mut self, channel: &ChannelState<E>, close_token: &Signature<E>) -> bool {
@ -509,7 +510,7 @@ impl<E: Engine> MerchantState<E> {
}
pub fn verify_proof<R: Rng>(&self, csprng: &mut R, channel: &ChannelState<E>, com: &Commitment<E>, com_proof: &CommitmentProof<E>) -> ResultBoltSig<(Signature<E>, Signature<E>)> {
let is_valid = util::verify(&self.comParams, &com.c, &com_proof);
let is_valid = nizk::verify_opening(&self.comParams, &com.c, &com_proof);
let cp = channel.cp.as_ref().unwrap();
if is_valid {
println!("Commitment PoK is valid!");

View File

@ -132,8 +132,7 @@ pub mod bidirectional {
pub use cl::{PublicKey, Signature};
pub use BoltResult;
pub use channels::{ChannelState, ChannelToken, CustomerState, MerchantState, PubKeyMap, ChannelParams, BoltError, ResultBoltSig};
pub use nizk::Proof;
pub use util::CommitmentProof;
pub use nizk::{CommitmentProof, Proof};
#[derive(Clone, Serialize, Deserialize)]
#[serde(bound(serialize = "<E as ff::ScalarEngine>::Fr: serde::Serialize, \

View File

@ -10,6 +10,7 @@ use ff::PrimeField;
use wallet::Wallet;
use ccs08::{RPPublicParams, RangeProof};
use serde::{Serialize, Deserialize};
use util;
#[derive(Clone, Serialize, Deserialize)]
#[serde(bound(serialize = "<E as ff::ScalarEngine>::Fr: serde::Serialize, \
@ -185,6 +186,132 @@ impl<E: Engine> NIZKPublicParams<E> {
}
}
#[derive(Clone, Serialize, Deserialize, Debug)]
#[serde(bound(serialize = "<E as ff::ScalarEngine>::Fr: serde::Serialize, \
<E as pairing::Engine>::G1: serde::Serialize, \
<E as pairing::Engine>::G2: serde::Serialize"
))]
#[serde(bound(deserialize = "<E as ff::ScalarEngine>::Fr: serde::Deserialize<'de>, \
<E as pairing::Engine>::G1: serde::Deserialize<'de>, \
<E as pairing::Engine>::G2: serde::Deserialize<'de>"
))]
pub struct CommitmentProof<E: Engine> {
pub T: E::G1,
pub z: Vec<E::Fr>,
pub t: Vec<E::Fr>,
pub index: Vec<usize>,
pub reveal: Vec<E::Fr>
}
impl<E: Engine> CommitmentProof<E> {
pub fn new<R: Rng>(csprng: &mut R, com_params: &CSMultiParams<E>, com: &E::G1, wallet: &Vec<E::Fr>, r: &E::Fr, reveal_index: &Vec<usize>) -> Self {
let mut Tvals = E::G1::zero();
assert!(wallet.len() <= com_params.pub_bases.len());
let mut t = Vec::<E::Fr>::with_capacity( wallet.len()+1 );
let mut rt: Vec<E::Fr> = Vec::new(); // t values that will be revealed
let mut reveal_wallet: Vec<E::Fr> = 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(&gt);
}
// compute the challenge
let x: Vec<E::G1> = vec![Tvals, com.clone()];
let challenge = util::hash_g1_to_fr::<E>(&x);
// compute the response
let mut z: Vec<E::Fr> = 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
///
pub fn verify_opening<E: Engine>(com_params: &CSMultiParams<E>, com: &E::G1, proof: &CommitmentProof<E>) -> bool {
let mut comc = com.clone();
let T = proof.T.clone();
let xvec: Vec<E::G1> = vec![T, comc];
let challenge = util::hash_g1_to_fr::<E>(&xvec);
// compute the
comc.mul_assign(challenge.into_repr());
comc.add_assign(&T);
let mut x = E::G1::zero();
let mut z: Vec<E::Fr> = Vec::new();
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) {
println!("verify_opening - doing any partial reveals?");
return false;
}
// verify linear relationshps
// pkc: index = 1
let mut s1 = proof.reveal[1].clone();
s1.mul_assign(&challenge);
s1.add_assign(&proof.t[1]);
let pkc_equal = (s1 == proof.z[1]);
// cust init balances: index = 3
let mut s3 = proof.reveal[3].clone();
s3.mul_assign(&challenge);
s3.add_assign(&proof.t[3]);
let bc_equal = (s3 == proof.z[3]);
// merch init balances: index = 4
let mut s4 = proof.reveal[4].clone();
s4.mul_assign(&challenge);
s4.add_assign(&proof.t[4]);
let bm_equal = (s4 == proof.z[4]);
return comc == x && pkc_equal && bc_equal && bm_equal;
}
#[cfg(test)]
mod tests {
use super::*;
@ -333,6 +460,51 @@ mod tests {
assert_eq!(pubParams.verify(proof, Fr::from_str(&epsilon.to_string()).unwrap(), &commitment2, wpk), false);
}
#[test]
fn nizk_proof_commitment_opening_works() {
let rng = &mut rand::thread_rng();
let pkc = Fr::rand(rng);
let wpk = Fr::rand(rng);
let t = Fr::rand(rng);
let bc = rng.gen_range(100, 1000);
let bm = rng.gen_range(100, 1000);
let wallet = Wallet::<Bls12> { pkc: pkc, wpk: wpk, bc: bc, bm: bm, close: None };
let pubParams = NIZKPublicParams::<Bls12>::setup(rng, 4);
let com = pubParams.comParams.commit(&wallet.as_fr_vec().clone(), &t);
let com_proof = CommitmentProof::<Bls12>::new(rng, &pubParams.comParams,
&com.c, &wallet.as_fr_vec(), &t, &vec![1, 3, 4]);
assert!(verify_opening(&pubParams.comParams, &com.c, &com_proof));
}
#[test]
fn nizk_proof_false_commitment() {
let rng = &mut rand::thread_rng();
let pkc = Fr::rand(rng);
let wpk = Fr::rand(rng);
let t = Fr::rand(rng);
let bc = rng.gen_range(100, 1000);
let bc2 = rng.gen_range(100, 1000);
let bm = rng.gen_range(100, 1000);
let wallet1 = Wallet::<Bls12> { pkc: pkc, wpk: wpk, bc: bc, bm: bm, close: None };
let wallet2 = Wallet::<Bls12> { pkc: pkc, wpk: wpk, bc: bc2, bm: bm, close: None };
let pubParams = NIZKPublicParams::<Bls12>::setup(rng, 4);
let com1 = pubParams.comParams.commit(&wallet1.as_fr_vec().clone(), &t);
let com2 = pubParams.comParams.commit(&wallet2.as_fr_vec().clone(), &t);
let com1_proof = CommitmentProof::<Bls12>::new(rng, &pubParams.comParams,
&com1.c, &wallet1.as_fr_vec(), &t, &vec![1, 3, 4]);
assert!(verify_opening(&pubParams.comParams, &com1.c, &com1_proof));
assert!(!verify_opening(&pubParams.comParams, &com2.c, &com1_proof));
}
#[test]
fn test_nizk_serialization() {
let mut rng = &mut rand::thread_rng();

View File

@ -100,94 +100,6 @@ pub fn compute_pub_key_fingerprint(wpk: &secp256k1::PublicKey) -> String {
return h;
}
#[derive(Clone, Serialize, Deserialize, Debug)]
#[serde(bound(serialize = "<E as ff::ScalarEngine>::Fr: serde::Serialize, \
<E as pairing::Engine>::G1: serde::Serialize, \
<E as pairing::Engine>::G2: serde::Serialize"
))]
#[serde(bound(deserialize = "<E as ff::ScalarEngine>::Fr: serde::Deserialize<'de>, \
<E as pairing::Engine>::G1: serde::Deserialize<'de>, \
<E as pairing::Engine>::G2: serde::Deserialize<'de>"
))]
pub struct CommitmentProof<E: Engine> {
pub T: E::G1,
pub z: Vec<E::Fr>
}
impl<E: Engine> CommitmentProof<E> {
pub fn new<R: Rng>(csprng: &mut R, com_params: &CSMultiParams<E>, com: &E::G1, wallet: &Vec<E::Fr>, r: &E::Fr, reveal_index: &Vec<usize>) -> Self {
let mut Tvals = E::G1::zero();
assert!(wallet.len() <= com_params.pub_bases.len());
let mut t = Vec::<E::Fr>::with_capacity( wallet.len()+1 );
for i in 0..wallet.len()+1 {
let ti = E::Fr::rand(csprng);
t.push(ti);
let mut gt = com_params.pub_bases[i].clone();
gt.mul_assign(ti.into_repr());
Tvals.add_assign(&gt);
}
// compute the challenge
let x: Vec<E::G1> = vec![Tvals, com.clone()];
let challenge = hash_g1_to_fr::<E>(&x);
// compute the response
let mut z: Vec<E::Fr> = Vec::new();
let mut z0 = r.clone();
z0.mul_assign(&challenge);
z0.add_assign(&t[0]);
// check if we are revealing this index
if (reveal_index.contains(&0)) {
z.push(E::Fr::zero());
} else {
z.push(z0);
}
for i in 1..t.len() {
let mut zi = wallet[i-1].clone();
zi.mul_assign(&challenge);
zi.add_assign(&t[i]);
if (reveal_index.contains(&i)) {
z.push(E::Fr::zero());
} else {
z.push(zi);
}
}
CommitmentProof {
T: Tvals, z: z
}
}
}
///
/// Verify PoK for the opening of a commitment
///
pub fn verify<E: Engine>(com_params: &CSMultiParams<E>, com: &E::G1, proof: &CommitmentProof<E>) -> bool {
let mut comc = com.clone();
let T = proof.T.clone();
let xvec: Vec<E::G1> = vec![T, comc];
let challenge = hash_g1_to_fr::<E>(&xvec);
// compute the
comc.mul_assign(challenge.into_repr());
comc.add_assign(&T);
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);
}
return comc == x;
}
pub fn hash_buffer_to_fr<'a, E: Engine>(prefix: &'a str, buf: &[u8; 64]) -> E::Fr {
let mut input_buf = Vec::new();
input_buf.extend_from_slice(prefix.as_bytes());