Add partial reveal for NIZK during establish and unit tests for commit opening
This commit is contained in:
parent
aaaccaeba0
commit
498263a9cc
|
@ -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!");
|
||||
|
|
|
@ -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, \
|
||||
|
|
172
src/nizk.rs
172
src/nizk.rs
|
@ -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(>);
|
||||
}
|
||||
|
||||
// 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();
|
||||
|
|
88
src/util.rs
88
src/util.rs
|
@ -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(>);
|
||||
}
|
||||
|
||||
// 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());
|
||||
|
|
Loading…
Reference in New Issue