Merge pull request #7 from boltlabs-inc/nizk

Nizk updates
This commit is contained in:
J. Ayo Akinyele 2019-07-21 11:07:47 -04:00 committed by GitHub
commit ddbae8980e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 589 additions and 397 deletions

View File

@ -10,7 +10,7 @@ extern crate rand;
use rand::{thread_rng, Rng};
use super::*;
use cl::{KeyPair, Signature, PublicParams, setup, BlindKeyPair, ProofState, SignatureProof};
use ped92::{CSParams, Commitment};
use ped92::{Commitment, CSMultiParams};
use pairing::{Engine, CurveProjective};
use ff::PrimeField;
use std::collections::HashMap;
@ -26,29 +26,47 @@ This must be computed in a trusted setup.
struct ParamsUL<E: Engine> {
pub mpk: PublicParams<E>,
pub signatures: HashMap<String, Signature<E>>,
pub com: CSParams<E>,
pub csParams: CSMultiParams<E>,
kp: BlindKeyPair<E>,
// u determines the amount of signatures we need in the public params.
// Each signature can be compressed to just 1 field element of 256 bits.
// Then the parameters have minimum size equal to 256*u bits.
u: i64,
u: i32,
// l determines how many pairings we need to compute, then in order to improve
// verifier`s performance we want to minize it.
// Namely, we have 2*l pairings for the prover and 3*l for the verifier.
l: i64,
l: i32,
}
#[derive(Clone)]
pub struct ProofULState<E: Engine> {
pub decx: Vec<i32>,
pub proofStates: Vec<ProofState<E>>,
pub V: Vec<Signature<E>>,
pub D: E::G1,
pub m: E::Fr,
pub s: Vec<E::Fr>,
}
/**
proofUL contains the necessary elements for the ZK range proof with range [0,u^l).
*/
#[derive(Clone)]
struct ProofUL<E: Engine> {
V: Vec<Signature<E>>,
D: E::G2,
comm: Commitment<E>,
sigProofs: Vec<SignatureProof<E>>,
ch: E::Fr,
zr: E::Fr,
pub struct ProofUL<E: Engine> {
pub V: Vec<Signature<E>>,
pub D: E::G1,
pub comm: Commitment<E>,
pub sigProofs: Vec<SignatureProof<E>>,
pub zr: E::Fr,
pub zs: Vec<E::Fr>,
}
#[derive(Clone)]
pub struct RangeProofState<E: Engine> {
pub com1: Commitment<E>,
pub ps1: ProofULState<E>,
pub com2: Commitment<E>,
pub ps2: ProofULState<E>,
}
/**
@ -56,8 +74,8 @@ RangeProof contains the necessary elements for the ZK range proof.
*/
#[derive(Clone)]
pub struct RangeProof<E: Engine> {
p1: ProofUL<E>,
p2: ProofUL<E>,
pub p1: ProofUL<E>,
pub p2: ProofUL<E>,
}
/**
@ -67,8 +85,8 @@ This must be computed in a trusted setup.
#[derive(Clone)]
pub struct RPPublicParams<E: Engine> {
p: ParamsUL<E>,
a: i64,
b: i64,
a: i32,
b: i32,
}
impl<E: Engine> ParamsUL<E> {
@ -77,7 +95,7 @@ impl<E: Engine> ParamsUL<E> {
The value of u should be roughly b/log(b), but we can choose smaller values in
order to get smaller parameters, at the cost of having worse performance.
*/
pub fn setup_ul<R: Rng>(rng: &mut R, u: i64, l: i64) -> Self {
pub fn setup_ul<R: Rng>(rng: &mut R, u: i32, l: i32, csParams: CSMultiParams<E>) -> Self {
let mpk = setup(rng);
let kp = BlindKeyPair::<E>::generate(rng, &mpk, 1);
@ -87,123 +105,166 @@ impl<E: Engine> ParamsUL<E> {
signatures.insert(i.to_string(), sig_i);
}
let com = CSParams::setup(rng);
return ParamsUL { mpk, signatures, com, kp, u, l };
return ParamsUL { mpk, signatures, csParams, kp, u, l };
}
/**
prove_ul method is used to produce the ZKRP proof that secret x belongs to the interval [0,U^L).
*/
pub fn prove_ul<R: Rng>(&self, rng: &mut R, x: i64, r: E::Fr) -> ProofUL<E> {
pub fn prove_ul<R: Rng>(&self, rng: &mut R, x: i32, r: E::Fr, C: Commitment<E>, k: usize, otherM: Vec<E::Fr>) -> ProofUL<E> {
let proofUlState = self.prove_ul_commitment(rng, x, k);
// Fiat-Shamir heuristic
let mut a = Vec::<E::Fqk>::with_capacity(self.l as usize);
for state in proofUlState.proofStates.clone() {
a.push(state.a);
}
let c = hash::<E>(a, vec!(proofUlState.D.clone()));
self.prove_ul_response(r, C, &proofUlState, c, k, otherM)
}
fn prove_ul_commitment<R: Rng>(&self, rng: &mut R, x: i32, k: usize) -> ProofULState<E> {
if x > self.u.pow(self.l as u32) || x < 0 {
panic!("x is not within the range.");
}
let decx = decompose(x, self.u, self.l);
let modx = E::Fr::from_str(&(x.to_string())).unwrap();
// Initialize variables
let mut proofStates = Vec::<ProofState<E>>::with_capacity(self.l as usize);
let mut sigProofs = Vec::<SignatureProof<E>>::with_capacity(self.l as usize);
let mut V = Vec::<Signature<E>>::with_capacity(self.l as usize);
let mut D = E::G2::zero();
let mut s = Vec::<E::Fr>::with_capacity(self.csParams.pub_bases.len() - 2);
let mut D = E::G1::zero();
let m = E::Fr::rand(rng);
// D = H^m
let mut hm = self.com.h2.clone();
let mut hm = self.csParams.pub_bases[0].clone();
hm.mul_assign(m);
for i in 0..self.l as usize {
let signature = self.signatures.get(&decx[i].to_string()).unwrap();
let proofState = self.kp.prove_commitment(rng, &self.mpk, &signature);
let proofState = self.kp.prove_commitment(rng, &self.mpk, &signature, None, None);
V.push(proofState.blindSig.clone());
proofStates.push(proofState);
let ui = self.u.pow(i as u32);
let mut aux = self.com.g2.clone();
for j in 0..self.kp.public.Y2.len() {
let mut aux = self.csParams.pub_bases[k].clone();
for j in 0..self.kp.public.Y1.len() {
let mut muiti = proofStates[i].t[j].clone();
muiti.mul_assign(&E::Fr::from_str(&ui.to_string()).unwrap());
aux.mul_assign(muiti);
}
D.add_assign(&aux);
}
D.add_assign(&hm);
let C = self.com.commit(rng, modx, Some(r));
// Fiat-Shamir heuristic
let mut a = Vec::<E::Fqk>::with_capacity(self.l as usize);
for state in proofStates.clone() {
a.push(state.a);
for i in 1..self.csParams.pub_bases.len() {
if i != k {
let mut g = self.csParams.pub_bases[i].clone();
let s1 = E::Fr::rand(rng);
s.push(s1);
g.mul_assign(s1);
D.add_assign(&g);
}
}
let c = hash::<E>(a, D.clone());
let mut zr = m.clone();
D.add_assign(&hm);
ProofULState { decx, proofStates, V, D, m, s }
}
fn prove_ul_response(&self, r: E::Fr, C: Commitment<E>, proofUlState: &ProofULState<E>, c: E::Fr, k: usize, otherM: Vec<E::Fr>) -> ProofUL<E> {
let mut sigProofs = Vec::<SignatureProof<E>>::with_capacity(self.l as usize);
let mut zr = proofUlState.m.clone();
let mut rc = r.clone();
rc.mul_assign(&c);
zr.add_assign(&rc);
for i in 0..self.l as usize {
let mut dx = E::Fr::from_str(&decx[i].to_string()).unwrap();
let mut dx = E::Fr::from_str(&proofUlState.decx[i].to_string()).unwrap();
let proof = self.kp.prove_response(&proofStates[i].clone(), c, &mut vec! {dx});
let proof = self.kp.prove_response(&proofUlState.proofStates[i].clone(), c, &mut vec! {dx});
sigProofs.push(proof);
}
return ProofUL { V, D, comm: C, sigProofs, ch: c, zr };
let mut zs = Vec::<E::Fr>::with_capacity(self.csParams.pub_bases.len() - 2);
for i in 1..self.csParams.pub_bases.len() {
let mut j: usize;
if i < k {
j = i - 1;
} else if i > k {
j = i - 2;
} else {
continue;
}
let mut mc = otherM[j].clone();
mc.mul_assign(&c);
let mut s = proofUlState.s[j].clone();
s.add_assign(&mc);
zs.push(s);
}
ProofUL { V: proofUlState.V.clone(), D: proofUlState.D.clone(), comm: C, sigProofs, zr, zs }
}
/**
verify_ul is used to validate the ZKRP proof. It returns true iff the proof is valid.
*/
pub fn verify_ul(&self, proof: &ProofUL<E>) -> bool {
// D == C^c.h^ zr.g^zsig ?
let r = self.verify_challenge(&proof);
let r1 = self.verify_part1(&proof);
let r2 = self.verify_part2(&proof);
r && r1 && r2
pub fn verify_ul(&self, proof: &ProofUL<E>, ch: E::Fr, k: usize) -> bool {
let r1 = self.verify_part1(&proof, ch.clone(), k);
let r2 = self.verify_part2(&proof, ch.clone());
r1 && r2
}
fn verify_challenge(&self, proof: &ProofUL<E>) -> bool {
fn compute_challenge(&self, proof: &ProofUL<E>) -> E::Fr {
let mut a = Vec::<E::Fqk>::with_capacity(self.l as usize);
for sigProof in proof.sigProofs.clone() {
a.push(sigProof.a);
}
let c = hash::<E>(a, proof.D.clone());
proof.ch == c
hash::<E>(a, vec!(proof.D.clone()))
}
fn verify_part2(&self, proof: &ProofUL<E>) -> bool {
fn verify_part2(&self, proof: &ProofUL<E>, challenge: E::Fr) -> bool {
let mut r2 = true;
for i in 0..self.l as usize {
let subResult = self.kp.public.verify_proof(&self.mpk, proof.V[i].clone(), proof.sigProofs[i].clone(), proof.ch);
let subResult = self.kp.public.verify_proof(&self.mpk, proof.V[i].clone(), proof.sigProofs[i].clone(), challenge);
r2 = r2 && subResult;
}
r2
}
fn verify_part1(&self, proof: &ProofUL<E>) -> bool {
let mut D = proof.comm.c2.clone();
D.mul_assign(proof.ch);
fn verify_part1(&self, proof: &ProofUL<E>, challenge: E::Fr, k: usize) -> bool {
let mut D = proof.comm.c.clone();
D.mul_assign(challenge);
D.negate();
let mut hzr = self.com.h2.clone();
let mut hzr = self.csParams.pub_bases[0].clone();
hzr.mul_assign(proof.zr);
D.add_assign(&hzr);
for i in 0..self.l as usize {
let ui = self.u.pow(i as u32);
let mut aux = self.com.g2.clone();
for j in 0..self.kp.public.Y2.len() {
let mut aux = self.csParams.pub_bases[k].clone();
for j in 0..self.kp.public.Y1.len() {
let mut muizsigi = proof.sigProofs[i].zsig[j];
muizsigi.mul_assign(&E::Fr::from_str(&ui.to_string()).unwrap());
aux.mul_assign(muizsigi);
}
D.add_assign(&aux);
}
for i in 1..self.csParams.pub_bases.len() {
let mut j: usize;
if i < k {
j = i - 1;
} else if i > k {
j = i - 2;
} else {
continue;
}
let mut g = self.csParams.pub_bases[i].clone();
g.mul_assign(proof.zs[j].into_repr());
D.add_assign(&g);
}
D == proof.D
}
}
fn hash<E: Engine>(a: Vec<E::Fqk>, D: E::G2) -> E::Fr {
fn hash<E: Engine>(a: Vec<E::Fqk>, D: Vec<E::G1>) -> E::Fr {
// create a Sha256 object
let mut a_vec: Vec<u8> = Vec::new();
for a_el in a {
@ -211,7 +272,9 @@ fn hash<E: Engine>(a: Vec<E::Fqk>, D: E::G2) -> E::Fr {
}
let mut x_vec: Vec<u8> = Vec::new();
x_vec.extend(format!("{}", D).bytes());
for d_el in D {
x_vec.extend(format!("{}", d_el).bytes());
}
a_vec.extend(x_vec);
util::hash_to_fr::<E>(a_vec)
@ -221,7 +284,7 @@ fn hash<E: Engine>(a: Vec<E::Fqk>, D: E::G2) -> E::Fr {
Decompose receives as input an integer x and outputs an array of integers such that
x = sum(xi.u^i), i.e. it returns the decomposition of x into base u.
*/
fn decompose(x: i64, u: i64, l: i64) -> Vec<i64> {
fn decompose(x: i32, u: i32, l: i32) -> Vec<i32> {
let mut result = Vec::with_capacity(l as usize);
let mut decomposer = x.clone();
for _i in 0..l {
@ -235,21 +298,22 @@ impl<E: Engine> RPPublicParams<E> {
/**
Setup receives integers a and b, and configures the parameters for the rangeproof scheme.
*/
pub fn setup<R: Rng>(rng: &mut R, a: i64, b: i64) -> Self {
pub fn setup<R: Rng>(rng: &mut R, a: i32, b: i32, csParams: CSMultiParams<E>) -> Self {
// Compute optimal values for u and l
if a > b {
panic!("a must be less than or equal to b");
}
//TODO: optimize u?
let logb = (b as f64).log2();
let logb = (b as f32).log2();
let loglogb = logb.log2();
if loglogb > 0.0 {
let mut u = (logb / loglogb) as i64;
let mut u = (logb / loglogb) as i32;
if u < 2 {
u = 2;
}
let l = (b as f64).log(u as f64).ceil() as i64;
let params_out: ParamsUL<E> = ParamsUL::<E>::setup_ul(rng, u, l);
let l = (b as f32).log(u as f32).ceil() as i32;
let params_out: ParamsUL<E> = ParamsUL::<E>::setup_ul(rng, u, l, csParams.clone());
return RPPublicParams { p: params_out, a, b };
} else {
panic!("log(log(b)) is zero");
@ -259,31 +323,70 @@ impl<E: Engine> RPPublicParams<E> {
/**
Prove method is responsible for generating the zero knowledge range proof.
*/
pub fn prove<R: Rng>(&self, rng: &mut R, x: i64) -> RangeProof<E> {
pub fn prove<R: Rng>(&self, rng: &mut R, x: i32, C: Commitment<E>, r: E::Fr, k: usize, otherM: Vec<E::Fr>) -> RangeProof<E> {
let rpState = self.prove_commitment(rng, x, C, k);
let mut a = Vec::<E::Fqk>::with_capacity(self.p.l as usize);
for i in 0..rpState.ps1.proofStates.len() {
a.push(rpState.ps1.proofStates[i].a);
a.push(rpState.ps2.proofStates[i].a);
}
let ch = hash::<E>(a, vec!(rpState.ps1.D.clone(), rpState.ps2.D.clone()));
self.prove_response(r, &rpState, ch, k, otherM)
}
pub fn prove_commitment<R: Rng>(&self, rng: &mut R, x: i32, C: Commitment<E>, k: usize) -> RangeProofState<E> {
if x > self.b || x < self.a {
panic!("x is not within the range.");
}
let ul = self.p.u.pow(self.p.l as u32);
let r = E::Fr::rand(rng);
// x - b + ul
let xb = x - self.b + ul;
let first = self.p.prove_ul(rng, xb, r);
let mut gb = self.p.csParams.pub_bases[k].clone();
let mut b = E::Fr::from_str(&(self.b.to_string())).unwrap();
b.negate();
gb.mul_assign(b.into_repr());
let mut gul = self.p.csParams.pub_bases[k].clone();
gul.mul_assign(E::Fr::from_str(&(ul.to_string())).unwrap().into_repr());
let mut comXB = C.clone();
comXB.c.add_assign(&gb);
comXB.c.add_assign(&gul);
let firstState = self.p.prove_ul_commitment(rng, xb, k);
// x - a
let xa = x - self.a;
let second = self.p.prove_ul(rng, xa, r);
let mut ga = self.p.csParams.pub_bases[k].clone();
let mut a = E::Fr::from_str(&(self.a.to_string())).unwrap();
a.negate();
ga.mul_assign(a.into_repr());
let mut comXA = C.clone();
comXA.c.add_assign(&ga);
let secondState = self.p.prove_ul_commitment(rng, xa, k);
RangeProofState { com1: comXB, ps1: firstState, com2: comXA, ps2: secondState }
}
return RangeProof { p1: first, p2: second };
pub fn prove_response(&self, r: E::Fr, rpState: &RangeProofState<E>, ch: E::Fr, k: usize, otherM: Vec<E::Fr>) -> RangeProof<E> {
let first = self.p.prove_ul_response(r.clone(), rpState.com1.clone(), &rpState.ps1, ch.clone(), k, otherM.clone());
let second = self.p.prove_ul_response(r.clone(), rpState.com2.clone(), &rpState.ps2, ch.clone(), k, otherM.clone());
RangeProof { p1: first, p2: second }
}
/**
Verify is responsible for validating the range proof.
*/
pub fn verify(&self, proof: RangeProof<E>) -> bool {
let first = self.p.verify_ul(&proof.p1);
let second = self.p.verify_ul(&proof.p2);
return first && second;
pub fn verify(&self, proof: RangeProof<E>, ch: E::Fr, k: usize) -> bool {
let first = self.p.verify_ul(&proof.p1, ch.clone(), k);
let second = self.p.verify_ul(&proof.p2, ch.clone(), k);
first & &second
}
fn compute_challenge(&self, proof: &RangeProof<E>) -> E::Fr {
let mut a = Vec::<E::Fqk>::with_capacity(self.p.l as usize);
for i in 0..proof.p1.sigProofs.len() {
a.push(proof.p1.sigProofs[i].a);
a.push(proof.p2.sigProofs[i].a);
}
hash::<E>(a, vec!(proof.p1.D.clone(), proof.p2.D.clone()))
}
}
@ -291,7 +394,7 @@ impl<E: Engine> RPPublicParams<E> {
#[cfg(test)]
mod tests {
use super::*;
use pairing::bls12_381::{Bls12, G1, G2, Fq12, Fr};
use pairing::bls12_381::{Bls12, G1, Fq12, Fr};
use time::PreciseTime;
use std::ops::Add;
use core::mem;
@ -300,7 +403,9 @@ mod tests {
#[test]
fn setup_ul_works() {
let rng = &mut rand::thread_rng();
let params = ParamsUL::<Bls12>::setup_ul(rng, 2, 3);
let csParams = CSMultiParams::setup_gen_params(rng, 1);
let params = ParamsUL::<Bls12>::setup_ul(rng, 2, 3, csParams.clone());
assert_eq!(params.signatures.len(), 2);
for (m, s) in params.signatures {
assert_eq!(params.kp.verify(&params.mpk, &vec! {Fr::from_str(m.to_string().as_str()).unwrap()}, &Fr::zero(), &s), true);
@ -310,9 +415,13 @@ mod tests {
#[test]
fn prove_ul_works() {
let rng = &mut rand::thread_rng();
let params = ParamsUL::<Bls12>::setup_ul(rng, 2, 4);
let csParams = CSMultiParams::setup_gen_params(rng, 1);
let params = ParamsUL::<Bls12>::setup_ul(rng, 2, 4, csParams.clone());
let fr = Fr::rand(rng);
let proof = params.prove_ul(rng, 10, fr);
let modx = Fr::from_str(&(10.to_string())).unwrap();
let C = csParams.commit(&vec!(modx), &fr.clone());
let proof = params.prove_ul(rng, 10, fr, C, 1, vec!{});
assert_eq!(proof.V.len(), 4);
assert_eq!(proof.sigProofs.len(), 4);
}
@ -321,52 +430,108 @@ mod tests {
#[should_panic(expected = "x is not within the range")]
fn prove_ul_not_in_range() {
let rng = &mut rand::thread_rng();
let params = ParamsUL::<Bls12>::setup_ul(rng, 2, 3);
let csParams = CSMultiParams::setup_gen_params(rng, 1);
let params = ParamsUL::<Bls12>::setup_ul(rng, 2, 3, csParams.clone());
let fr = Fr::rand(rng);
params.prove_ul(rng, 100, fr);
let modx = Fr::from_str(&(100.to_string())).unwrap();
let C = csParams.commit(&vec!(modx), &fr.clone());
params.prove_ul(rng, 100, fr, C, 1, vec!{});
}
#[test]
fn prove_and_verify_part1_ul_works() {
let rng = &mut rand::thread_rng();
let params = ParamsUL::<Bls12>::setup_ul(rng, 2, 4);
let csParams = CSMultiParams::setup_gen_params(rng, 1);
let params = ParamsUL::<Bls12>::setup_ul(rng, 2, 4, csParams.clone());
let fr = Fr::rand(rng);
let proof = params.prove_ul(rng, 10, fr);
assert_eq!(params.verify_part1(&proof), true);
let modx = Fr::from_str(&(10.to_string())).unwrap();
let C = csParams.commit(&vec!(modx), &fr.clone());
let proof = params.prove_ul(rng, 10, fr, C, 1, vec!{});
let ch = params.compute_challenge(&proof);
assert_eq!(params.verify_part1(&proof, ch, 1), true);
}
#[test]
fn prove_and_verify_part2_ul_works() {
let rng = &mut rand::thread_rng();
let params = ParamsUL::<Bls12>::setup_ul(rng, 2, 4);
let csParams = CSMultiParams::setup_gen_params(rng, 1);
let params = ParamsUL::<Bls12>::setup_ul(rng, 2, 4, csParams.clone());
let fr = Fr::rand(rng);
let proof = params.prove_ul(rng, 10, fr);
assert_eq!(params.verify_part2(&proof), true);
let modx = Fr::from_str(&(10.to_string())).unwrap();
let C = csParams.commit(&vec!(modx), &fr.clone());
let proof = params.prove_ul(rng, 10, fr, C, 1, vec!{});
let ch = params.compute_challenge(&proof);
assert_eq!(params.verify_part2(&proof, ch), true);
}
#[test]
fn prove_and_verify_ul_works() {
let rng = &mut rand::thread_rng();
let params = ParamsUL::<Bls12>::setup_ul(rng, 2, 4);
let csParams = CSMultiParams::setup_gen_params(rng, 1);
let params = ParamsUL::<Bls12>::setup_ul(rng, 2, 4, csParams.clone());
let fr = Fr::rand(rng);
let proof = params.prove_ul(rng, 10, fr);
assert_eq!(params.verify_ul(&proof), true);
let modx = Fr::from_str(&(10.to_string())).unwrap();
let C = csParams.commit(&vec!(modx), &fr.clone());
let proof = params.prove_ul(rng, 10, fr, C, 1, vec!{});
let ch = params.compute_challenge(&proof);
assert_eq!(params.verify_ul(&proof, ch, 1), true);
}
#[test]
fn prove_and_verify_ul_bigger_commit_works() {
let rng = &mut rand::thread_rng();
let csParams = CSMultiParams::setup_gen_params(rng, 3);
let params = ParamsUL::<Bls12>::setup_ul(rng, 2, 4, csParams.clone());
let fr = Fr::rand(rng);
let modx = Fr::from_str(&(10.to_string())).unwrap();
let fr1 = Fr::rand(rng);
let fr2 = Fr::rand(rng);
let C = csParams.commit(&vec!(fr1, modx, fr2), &fr.clone());
let proof = params.prove_ul(rng, 10, fr, C, 2, vec!{fr1, fr2});
let ch = params.compute_challenge(&proof);
assert_eq!(params.verify_ul(&proof, ch, 2), true);
}
#[test]
fn prove_and_verify_works() {
let rng = &mut rand::thread_rng();
let params = RPPublicParams::<Bls12>::setup(rng, 2, 25);
let proof = params.prove(rng, 10);
assert_eq!(params.verify(proof), true);
let csParams = CSMultiParams::setup_gen_params(rng, 1);
let params = RPPublicParams::<Bls12>::setup(rng, 2, 25, csParams.clone());
let fr = Fr::rand(rng);
let modx = Fr::from_str(&(10.to_string())).unwrap();
let C = csParams.commit(&vec!(modx), &fr.clone());
let proof = params.prove(rng, 10, C, fr, 1, vec!{});
let ch = params.compute_challenge(&proof);
assert_eq!(params.verify(proof, ch, 1), true);
}
#[test]
fn prove_and_verify_bigger_commit_works() {
let rng = &mut rand::thread_rng();
let csParams = CSMultiParams::setup_gen_params(rng, 3);
let params = RPPublicParams::<Bls12>::setup(rng, 2, 25, csParams.clone());
let fr = Fr::rand(rng);
let modx = Fr::from_str(&(10.to_string())).unwrap();
let fr1 = Fr::rand(rng);
let fr2 = Fr::rand(rng);
let C = csParams.commit(&vec!(fr1, modx, fr2), &fr.clone());
let proof = params.prove(rng, 10, C, fr, 2, vec!{fr1, fr2});
let ch = params.compute_challenge(&proof);
assert_eq!(params.verify(proof, ch, 2), true);
}
#[test]
#[should_panic(expected = "x is not within the range")]
fn prove_not_in_range() {
let rng = &mut rand::thread_rng();
let params = RPPublicParams::<Bls12>::setup(rng, 2, 25);
let proof = params.prove(rng, 26);
let csParams = CSMultiParams::setup_gen_params(rng, 1);
let params = RPPublicParams::<Bls12>::setup(rng, 2, 25, csParams.clone());
let fr = Fr::rand(rng);
let modx = Fr::from_str(&(26.to_string())).unwrap();
let C = csParams.commit(&vec!(modx), &fr.clone());
params.prove(rng, 26, C, fr, 1, vec!{});
}
#[test]
@ -385,17 +550,22 @@ mod tests {
let x = rng.gen_range(a, b);
let sSetup = PreciseTime::now();
let params = RPPublicParams::<Bls12>::setup(rng, a, b);
let csParams = CSMultiParams::setup_gen_params(rng, 1);
let params = RPPublicParams::<Bls12>::setup(rng, a, b, csParams.clone());
averageSetup = averageSetup.add(sSetup.to(PreciseTime::now()));
averageSetupSize += mem::size_of_val(&params);
let sProve = PreciseTime::now();
let proof = params.prove(rng, x);
let fr = Fr::rand(rng);
let modx = Fr::from_str(&(x.to_string())).unwrap();
let C = csParams.commit(&vec!(modx), &fr.clone());
let proof = params.prove(rng, x, C, fr, 1, vec!{});
averageProve = averageProve.add(sProve.to(PreciseTime::now()));
averageProofSize += mem::size_of_val(&proof);
let sVerify = PreciseTime::now();
params.verify(proof);
let ch = params.compute_challenge(&proof);
params.verify(proof, ch, 1);
averageVerify = averageVerify.add(sVerify.to(PreciseTime::now()));
}
print!("Setup: {}\n", averageSetup.num_milliseconds() / iter);
@ -419,14 +589,14 @@ mod tests {
let vec1 = decompose(25, 3, 5);
let mut result = 0;
for i in 0..5 {
result += vec1[i] * 3i64.pow(i as u32);
result += vec1[i] * 3i32.pow(i as u32);
}
assert_eq!(result, 25);
let vec1 = decompose(143225, 6, 7);
let mut result = 0;
for i in 0..7 {
result += vec1[i] * 6i64.pow(i as u32);
result += vec1[i] * 6i32.pow(i as u32);
}
assert_eq!(result, 143225);
}
@ -434,7 +604,8 @@ mod tests {
#[test]
fn setup_works() {
let rng = &mut rand::thread_rng();
let public_params = RPPublicParams::<Bls12>::setup(rng, 2, 10);
let csParams = CSMultiParams::setup_gen_params(rng, 1);
let public_params = RPPublicParams::<Bls12>::setup(rng, 2, 10, csParams);
assert_eq!(public_params.a, 2);
assert_eq!(public_params.b, 10);
assert_eq!(public_params.p.signatures.len(), 2);
@ -449,36 +620,38 @@ mod tests {
#[should_panic(expected = "a must be less than or equal to b")]
fn setup_wrong_a_and_b() {
let rng = &mut rand::thread_rng();
RPPublicParams::<Bls12>::setup(rng, 10, 2);
let csParams = CSMultiParams::setup_gen_params(rng, 1);
RPPublicParams::<Bls12>::setup(rng, 10, 2, csParams);
}
#[test]
#[should_panic(expected = "log(log(b)) is zero")]
fn setup_wrong_logb() {
let rng = &mut rand::thread_rng();
RPPublicParams::<Bls12>::setup(rng, -2, -1);
let csParams = CSMultiParams::setup_gen_params(rng, 1);
RPPublicParams::<Bls12>::setup(rng, -2, -1, csParams);
}
#[test]
fn hash_works() {
let rng = &mut rand::thread_rng();
let D = G2::rand(rng);
let D2 = G2::rand(rng);
let D = G1::rand(rng);
let D2 = G1::rand(rng);
let params = setup::<ThreadRng, Bls12>(rng);
let kp = BlindKeyPair::generate(rng, &params, 2);
let m1 = Fr::rand(rng);
let m2 = Fr::rand(rng);
let sig = kp.sign(rng, &vec! {m1, m2});
let state = kp.prove_commitment(rng, &params, &sig);
let state1 = kp.prove_commitment(rng, &params, &sig);
let state2 = kp.prove_commitment(rng, &params, &sig);
let state3 = kp.prove_commitment(rng, &params, &sig);
let state4 = kp.prove_commitment(rng, &params, &sig);
let state = kp.prove_commitment(rng, &params, &sig, None, None);
let state1 = kp.prove_commitment(rng, &params, &sig, None, None);
let state2 = kp.prove_commitment(rng, &params, &sig, None, None);
let state3 = kp.prove_commitment(rng, &params, &sig, None, None);
let state4 = kp.prove_commitment(rng, &params, &sig, None, None);
let a = vec! {state.a, state1.a, state2.a};
let a2 = vec! {state3.a, state4.a};
assert_eq!(hash::<Bls12>(a.clone(), D.clone()).is_zero(), false);
assert_ne!(hash::<Bls12>(a2.clone(), D.clone()), hash::<Bls12>(a.clone(), D.clone()));
assert_ne!(hash::<Bls12>(a.clone(), D2.clone()), hash::<Bls12>(a.clone(), D.clone()));
assert_ne!(hash::<Bls12>(a2.clone(), D2.clone()), hash::<Bls12>(a.clone(), D.clone()));
assert_eq!(hash::<Bls12>(a.clone(), vec!(D.clone())).is_zero(), false);
assert_ne!(hash::<Bls12>(a2.clone(), vec!(D.clone())), hash::<Bls12>(a.clone(), vec!(D.clone())));
assert_ne!(hash::<Bls12>(a.clone(), vec!(D2.clone())), hash::<Bls12>(a.clone(), vec!(D.clone())));
assert_ne!(hash::<Bls12>(a2.clone(), vec!(D2.clone())), hash::<Bls12>(a.clone(), vec!(D.clone())))
}
}

View File

@ -192,7 +192,7 @@ impl<E: Engine> CustomerWallet<E> {
// generate nizk proof of knowledge of commitment opening
pub fn generate_proof<R: Rng>(&mut self, csprng: &mut R, channel_token: &ChannelToken<E>) -> CommitmentProof<E> {
return CommitmentProof::<E>::new(csprng, &channel_token.comParams, &self.w_com.c1, &self.w_vec, &self.r);
return CommitmentProof::<E>::new(csprng, &channel_token.comParams, &self.w_com.c, &self.w_vec, &self.r);
}
}
@ -237,7 +237,7 @@ impl<E: Engine> MerchantWallet<E> {
}
pub fn verify_proof<R: Rng>(&self, csprng: &mut R, channel: &ChannelState<E>, com: &Commitment<E>, com_proof: &CommitmentProof<E>) -> Signature<E> {
let is_valid = util::verify(&self.comParams, &com.c1, &com_proof);
let is_valid = util::verify(&self.comParams, &com.c, &com_proof);
let cp = channel.cp.as_ref().unwrap();
if is_valid {
println!("Commitment PoK is valid!");

View File

@ -13,13 +13,13 @@ use std::fmt::LowerHex;
#[derive(Clone)]
pub struct PublicParams<E: Engine> {
pub g1: E::G1,
pub g2: E::G2
pub g2: E::G2,
}
#[derive(Clone)]
pub struct SecretKey<E: Engine> {
pub x: E::Fr,
pub y: Vec<E::Fr>
pub y: Vec<E::Fr>,
}
#[derive(Clone, Serialize, Deserialize)]
@ -61,19 +61,19 @@ pub struct BlindPublicKey<E: Engine> {
#[derive(Clone)]
pub struct Signature<E: Engine> {
pub h: E::G1,
pub H: E::G1
pub H: E::G1,
}
#[derive(Clone)]
pub struct KeyPair<E: Engine> {
pub secret: SecretKey<E>,
pub public: PublicKey<E>
pub public: PublicKey<E>,
}
#[derive(Clone)]
pub struct BlindKeyPair<E: Engine> {
pub secret: SecretKey<E>,
pub public: BlindPublicKey<E>
pub public: BlindPublicKey<E>,
}
#[derive(Clone)]
@ -83,7 +83,7 @@ pub struct ProofState<E: Engine> {
pub t: Vec<E::Fr>,
pub tt: E::Fr,
pub a: E::Fqk,
pub blindSig: Signature<E>
pub blindSig: Signature<E>,
}
#[derive(Clone)]
@ -91,7 +91,7 @@ pub struct SignatureProof<E: Engine> {
pub zx: E::Fr,
pub zsig: Vec<E::Fr>,
pub zv: E::Fr,
pub a: E::Fqk
pub a: E::Fqk,
}
@ -143,7 +143,6 @@ impl<E: Engine> SecretKey<E> {
H1.mul_assign(r);
Signature { h: h1, H: H1 }
}
}
@ -197,7 +196,7 @@ impl<E: Engine> PublicKey<E> {
X.mul_assign(secret.x);
PublicKey {
X: X,
Y: Y
Y: Y,
}
}
@ -241,7 +240,7 @@ impl<E: Engine> BlindPublicKey<E> {
X1: X1,
X2: X2,
Y1: Y1,
Y2: Y2
Y2: Y2,
}
}
@ -288,11 +287,9 @@ impl<E: Engine> BlindPublicKey<E> {
g.mul_assign(&p.a);
gx == g
}
}
pub fn setup<R: Rng, E: Engine>(csprng: &mut R) -> PublicParams<E> {
let g1 = E::G1::rand(csprng);
let g2 = E::G2::rand(csprng);
@ -332,13 +329,10 @@ impl<E: Engine> BlindKeyPair<E> {
}
pub fn generate_cs_multi_params(&self, mpk: &PublicParams<E>) -> CSMultiParams<E> {
let mut com_bases1 = vec! {mpk.g1};
com_bases1.append(&mut self.public.Y1.clone());
let mut com_bases = vec! {mpk.g1};
com_bases.append(&mut self.public.Y1.clone());
let mut com_bases2 = vec! {mpk.g2};
com_bases2.append(&mut self.public.Y2.clone());
CSMultiParams { pub_bases1: com_bases1, pub_bases2: com_bases2}
CSMultiParams { pub_bases: com_bases }
}
/// extract unblinded public key
@ -357,7 +351,7 @@ impl<E: Engine> BlindKeyPair<E> {
let mut h1 = mpk.g1;
h1.mul_assign(u); // g1 ^ u
let mut com1 = com.c1.clone();
let mut com1 = com.c.clone();
let mut H1 = self.public.X1.clone();
H1.add_assign(&com1); // (X * com)
H1.mul_assign(u); // (X * com) ^ u (blinding factor)
@ -394,16 +388,19 @@ impl<E: Engine> BlindKeyPair<E> {
/// prove knowledge of a signature: commitment phase
/// returns the proof state, including commitment a and a blind signature blindSig
pub fn prove_commitment<R: Rng>(&self, rng: &mut R, mpk: &PublicParams<E>, signature: &Signature<E>) -> ProofState<E> {
pub fn prove_commitment<R: Rng>(&self, rng: &mut R, mpk: &PublicParams<E>, signature: &Signature<E>,
tOptional: Option<Vec<E::Fr>>, ttOptional: Option<E::Fr>) -> ProofState<E> {
let v = E::Fr::rand(rng);
let blindSig = self.blind(rng, &v, signature);
let s = E::Fr::rand(rng);
let mut t = Vec::<E::Fr>::with_capacity(self.public.Y2.len());
let tt = E::Fr::rand(rng);
let mut t = tOptional.unwrap_or(Vec::<E::Fr>::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());
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);
@ -461,7 +458,7 @@ mod tests {
use ff::Rand;
use pairing::bls12_381::{Bls12, Fr};
use rand::{SeedableRng};
use rand::SeedableRng;
use rand_xorshift::XorShiftRng;
use ped92::CSMultiParams;
@ -604,12 +601,11 @@ mod tests {
}
let sig = keypair.sign(&mut rng, &message1);
let proof_state = keypair.prove_commitment(rng, &mpk, &sig);
let proof_state = keypair.prove_commitment(rng, &mpk, &sig, None, None);
let challenge = Fr::rand(&mut rng);
let proof = keypair.prove_response(&proof_state.clone(), challenge, &mut message1);
assert_eq!(keypair.public.verify_proof(&mpk, proof_state.blindSig, proof, challenge), true);
}
}

View File

@ -73,6 +73,7 @@ pub mod clproto;
pub mod serialization_wrappers;
pub mod nizk;
pub mod util;
pub mod wallet;
const E_MIN: i32 = 1;
const E_MAX: i32 = 255; // TODO: should be 2^32 - 1

View File

@ -9,36 +9,56 @@ use pairing::{Engine, CurveProjective};
use ff::PrimeField;
use util::hash_g2_to_fr;
use commit_scheme::commit;
use wallet::Wallet;
use ccs08::{RPPublicParams, RangeProof};
#[derive(Clone)]
struct Proof<E: Engine> {
sig: Signature<E>,
sigProof: SignatureProof<E>,
T: E::G2,
D: E::G2,
z: Vec<E::Fr>,
pub struct Proof<E: Engine> {
pub sig: Signature<E>,
pub sigProof: SignatureProof<E>,
pub T: E::G1,
pub D: E::G1,
pub z: Vec<E::Fr>,
pub rpBC: RangeProof<E>,
pub rpBM: RangeProof<E>,
}
fn prove<R: Rng, E: Engine>(rng: &mut R, comParams: &CSMultiParams<E>, com1: &Commitment<E>, r: E::Fr,
oldWallet: Vec<E::Fr>, newWallet: Vec<E::Fr>, rPrime: E::Fr, paymentToken: &Signature<E>,
mpk: &PublicParams<E>, kp: &BlindKeyPair<E>) -> Proof<E> {
#[derive(Clone)]
pub struct NIZKPublicParams<E: Engine> {
pub mpk: PublicParams<E>,
pub keypair: BlindKeyPair<E>,
pub comParams: CSMultiParams<E>,
pub rpParamsBC: RPPublicParams<E>,
pub rpParamsBM: RPPublicParams<E>,
}
impl<E: Engine> NIZKPublicParams<E> {
pub fn setup<R: Rng>(rng: &mut R) -> Self {
let mpk = setup(rng);
let keypair = BlindKeyPair::<E>::generate(rng, &mpk, 4);
let comParams = keypair.generate_cs_multi_params(&mpk);
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}
}
pub fn prove<R: Rng>(&self, rng: &mut R, r: E::Fr, oldWallet: Wallet<E>, newWallet: Wallet<E>,
newWalletCom: Commitment<E>, rPrime: E::Fr, paymentToken: &Signature<E>, ) -> Proof<E> {
//Commitment phase
//Commit linear relationship
let mut T = comParams.pub_bases2[2].clone();
let mut T = self.comParams.pub_bases[2].clone();
let t1 = E::Fr::rand(rng);
T.mul_assign(t1);
let mut h = comParams.pub_bases2[0].clone();
let mut h = self.comParams.pub_bases[0].clone();
let t2 = E::Fr::rand(rng);
h.mul_assign(t2);
T.add_assign(&h);
//commit signature
let proofState = kp.prove_commitment(rng, &mpk, &paymentToken);
//commit commitment
let mut D = E::G2::zero();
let mut t = Vec::<E::Fr>::with_capacity(comParams.pub_bases2.len() - 1);
for g in comParams.pub_bases2.clone() {
let mut D = E::G1::zero();
let mut t = Vec::<E::Fr>::with_capacity(self.comParams.pub_bases.len() - 1);
for g in self.comParams.pub_bases.clone() {
let ti = E::Fr::rand(rng);
t.push(ti);
let mut gt = g.clone();
@ -46,16 +66,24 @@ fn prove<R: Rng, E: Engine>(rng: &mut R, comParams: &CSMultiParams<E>, com1: &Co
D.add_assign(&gt);
}
//commit signature
let proofState = self.keypair.prove_commitment(rng, &self.mpk, &paymentToken, Some(t[1..].to_vec()), Some(t[0].clone()));
//commit range proof
let rpStateBC = self.rpParamsBC.prove_commitment(rng, newWallet.bc.clone(), newWalletCom.clone(), 3);
let rpStateBM = self.rpParamsBM.prove_commitment(rng, newWallet.bm.clone(), newWalletCom.clone(), 4);
//Compute challenge
let challenge = hash::<E>(proofState.a, T, D);
let challenge = NIZKPublicParams::<E>::hash(proofState.a, vec! {T, D, rpStateBC.ps1.D, rpStateBC.ps2.D, rpStateBM.ps1.D, rpStateBM.ps2.D});
//Response phase
//response for signature
let sigProof = kp.prove_response(&proofState, challenge, &mut oldWallet.clone());
let oldWalletVec = oldWallet.as_fr_vec();
let sigProof = self.keypair.prove_response(&proofState, challenge, &mut oldWalletVec.clone());
//response linear relationship
let mut z = Vec::<E::Fr>::with_capacity(t.len() + 2);
let mut z1 = newWallet[1].clone();
let mut z1 = newWallet.wpk.clone();
z1.negate();
z1.mul_assign(&challenge);
z1.add_assign(&t1);
@ -71,74 +99,84 @@ fn prove<R: Rng, E: Engine>(rng: &mut R, comParams: &CSMultiParams<E>, com1: &Co
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 = newWallet[i-1].clone();
let mut zi = newWalletVec[i - 1].clone();
zi.mul_assign(&challenge);
zi.add_assign(&t[i]);
z.push(zi);
}
Proof { sig: proofState.blindSig, sigProof, T, D, z }
//response range proof
let rpBC = self.rpParamsBC.prove_response(rPrime.clone(), &rpStateBC, challenge.clone(), 3, vec! {newWalletVec[0], newWalletVec[1], newWalletVec[3]});
let rpBM = self.rpParamsBM.prove_response(rPrime.clone(), &rpStateBM, challenge.clone(), 4, vec! {newWalletVec[0], newWalletVec[1], newWalletVec[2]});
Proof { sig: proofState.blindSig, sigProof, T, D, z, rpBC, rpBM }
}
fn verify<E: Engine>(proof: Proof<E>, epsilon: E::Fr, com1: &Commitment<E>, com2: &Commitment<E>,
wpk: E::Fr, comParams: &CSMultiParams<E>, mpk: &PublicParams<E>, pk: &BlindPublicKey<E>) -> bool {
pub fn verify(&self, proof: Proof<E>, epsilon: E::Fr, com1: &Commitment<E>, com2: &Commitment<E>, wpk: E::Fr) -> bool {
//compute challenge
let challenge = hash::<E>(proof.sigProof.a, proof.T, proof.D);
let challenge = NIZKPublicParams::<E>::hash(proof.sigProof.a, vec! {proof.T, proof.D, proof.rpBC.p1.D, proof.rpBC.p2.D, proof.rpBM.p1.D, proof.rpBM.p2.D});
//verify linear relationship
let mut gWpk = comParams.pub_bases2[2].clone();
let mut gWpk = self.comParams.pub_bases[2].clone();
let mut minWpk = wpk.clone();
minWpk.negate();
gWpk.mul_assign(minWpk.into_repr());
let mut gEps = comParams.pub_bases2[4].clone();
let mut gEps = self.comParams.pub_bases[4].clone();
gEps.mul_assign(epsilon.into_repr());
let mut gMinEps = comParams.pub_bases2[3].clone();
let mut gMinEps = self.comParams.pub_bases[3].clone();
let mut mineps = epsilon.clone();
mineps.negate();
gMinEps.mul_assign(mineps.into_repr());
let mut commitment = com1.c2.clone();
commitment.sub_assign(&com2.c2.clone());
let mut commitment = com1.c.clone();
commitment.sub_assign(&com2.c.clone());
commitment.add_assign(&gWpk);
commitment.add_assign(&gEps);
commitment.add_assign(&gMinEps);
commitment.mul_assign(challenge.into_repr());
commitment.add_assign(&proof.T);
let mut g2 = comParams.pub_bases2[2].clone();
let mut g2 = self.comParams.pub_bases[2].clone();
g2.mul_assign(proof.z[0].into_repr());
let mut h = comParams.pub_bases2[0].clone();
let mut h = self.comParams.pub_bases[0].clone();
h.mul_assign(proof.z[1].into_repr());
g2.add_assign(&h);
let r = commitment == g2;
//verify knowledge of signature
let r1 = pk.verify_proof(&mpk, proof.sig, proof.sigProof, challenge);
let r1 = self.keypair.public.verify_proof(&self.mpk, proof.sig, proof.sigProof, challenge);
//verify knowledge of commitment
let mut comc = com2.c2.clone();
let mut comc = com2.c.clone();
comc.mul_assign(challenge.into_repr());
comc.add_assign(&proof.D.clone());
let mut x = E::G2::zero();
let mut x = E::G1::zero();
for i in 2..proof.z.len() {
let mut base = comParams.pub_bases2[i - 2].clone();
let mut base = self.comParams.pub_bases[i - 2].clone();
base.mul_assign(proof.z[i].into_repr());
x.add_assign(&base);
}
let r3 = x == comc;
let r2 = x == comc;
r && r1 && r3
//verify range proofs
let r3 = self.rpParamsBC.verify(proof.rpBC, challenge.clone(), 3);
let r4 = self.rpParamsBM.verify(proof.rpBM, challenge.clone(), 4);
r && r1 && r2 && r3 && r4
}
fn hash<E: Engine>(a: E::Fqk, T: E::G2, D: E::G2) -> E::Fr {
fn hash(a: E::Fqk, T: Vec<E::G1>) -> E::Fr {
let mut x_vec: Vec<u8> = Vec::new();
x_vec.extend(format!("{}", a).bytes());
x_vec.extend(format!("{}", T).bytes());
x_vec.extend(format!("{}", D).bytes());
for t in T {
x_vec.extend(format!("{}", t).bytes());
}
util::hash_to_fr::<E>(x_vec)
}
}
#[cfg(test)]
mod tests {
@ -151,29 +189,29 @@ mod tests {
let pkc = Fr::rand(rng);
let wpk = Fr::rand(rng);
let wpkprime = Fr::rand(rng);
let bc = Fr::rand(rng);
let bc = rng.gen_range(100, 1000);
let mut bc2 = bc.clone();
let bm = Fr::rand(rng);
let bm = rng.gen_range(100, 1000);
let mut bm2 = bm.clone();
let epsilon = &Fr::rand(rng);
bc2.sub_assign(epsilon);
bm2.add_assign(epsilon);
let epsilon = &rng.gen_range(1, 100);
bc2 -= epsilon;
bm2 += epsilon;
let r = Fr::rand(rng);
let rprime = Fr::rand(rng);
let mpk = setup(rng);
let keypair = BlindKeyPair::<Bls12>::generate(rng, &mpk, 4);
let comParams = keypair.generate_cs_multi_params(&mpk);
let wallet1 = vec! {pkc, wpk, bc, bm};
let commitment1 = comParams.commit(&wallet1, &r);
let wallet2 = vec! {pkc, wpkprime, bc2, bm2};
let commitment2 = comParams.commit(&wallet2, &rprime);
let blindPaymentToken = keypair.sign_blind(rng, &mpk, commitment1.clone());
let paymentToken = keypair.unblind(&r, &blindPaymentToken);
let pubParams = NIZKPublicParams::<Bls12>::setup(rng);
let wallet1 = Wallet { pkc, wpk, bc, bm };
let commitment1 = pubParams.comParams.commit(&wallet1.as_fr_vec(), &r);
let wallet2 = Wallet { pkc, wpk: wpkprime, bc: bc2, bm: bm2 };
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 = prove(rng, &comParams, &commitment1, r, wallet1, wallet2, rprime, &paymentToken, &mpk, &keypair);
let proof = pubParams.prove(rng, r, wallet1, wallet2,
commitment2.clone(), rprime, &paymentToken);
assert_eq!(verify(proof, *epsilon, &commitment1, &commitment2, wpk, &comParams, &mpk, &keypair.public), true);
assert_eq!(pubParams.verify(proof, Fr::from_str(&epsilon.to_string()).unwrap(), &commitment1,
&commitment2, wpk), true);
}
#[test]
@ -182,41 +220,38 @@ mod tests {
let pkc = Fr::rand(rng);
let wpk = Fr::rand(rng);
let wpkprime = Fr::rand(rng);
let bc = Fr::rand(rng);
let bc = rng.gen_range(100, 1000);
let mut bc2 = bc.clone();
let bm = Fr::rand(rng);
let bm = rng.gen_range(100, 1000);
let mut bm2 = bm.clone();
let epsilon = &Fr::rand(rng);
bc2.sub_assign(epsilon);
bm2.add_assign(epsilon);
let epsilon = &rng.gen_range(1, 100);
bc2 -= epsilon;
bm2 += epsilon;
let r = Fr::rand(rng);
let rprime = Fr::rand(rng);
let mpk = setup(rng);
let keypair = BlindKeyPair::<Bls12>::generate(rng, &mpk, 4);
let comParams = keypair.generate_cs_multi_params(&mpk);
let wallet1 = vec! {pkc, wpk, bc, bm};
let wallet2 = vec! {pkc, wpkprime, bc2, bm2};
let pubParams = NIZKPublicParams::<Bls12>::setup(rng);
let wallet1 = Wallet { pkc, wpk, bc, bm };
let wallet2 = Wallet::<Bls12> { pkc, wpk: wpkprime, bc: bc2, bm: bm2 };
let mut bc2Prime = bc.clone();
let wallet3 = vec! {pkc, wpkprime, bc2Prime, bm2};
let commitment1 = comParams.commit(&wallet1.clone(), &r);
let commitment2 = comParams.commit(&wallet3, &rprime);
let blindPaymentToken = keypair.sign_blind(rng, &mpk, commitment1.clone());
let paymentToken = keypair.unblind(&r, &blindPaymentToken);
let proof = prove(rng, &comParams, &commitment1, r, wallet1.clone(), wallet3, rprime, &paymentToken, &mpk, &keypair);
assert_eq!(verify(proof, *epsilon, &commitment1, &commitment2, wpk, &comParams, &mpk, &keypair.public), false);
let wallet3 = Wallet { pkc, wpk: wpkprime, bc: bc2Prime, bm: bm2 };
let commitment1 = pubParams.comParams.commit(&wallet1.as_fr_vec().clone(), &r);
let commitment2 = pubParams.comParams.commit(&wallet3.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.clone(), wallet3, commitment2.clone(), rprime, &paymentToken);
assert_eq!(pubParams.verify(proof, Fr::from_str(&epsilon.to_string()).unwrap(), &commitment1, &commitment2, wpk), false);
let mut bm2Prime = bm.clone();
let wallet4 = vec! {pkc, wpkprime, bc2, bm2Prime};
let commitment2 = comParams.commit(&wallet4, &rprime);
let proof = prove(rng, &comParams, &commitment1, r, wallet1.clone(), wallet4, rprime, &paymentToken, &mpk, &keypair);
assert_eq!(verify(proof, *epsilon, &commitment1, &commitment2, wpk, &comParams, &mpk, &keypair.public), false);
let wallet5 = vec! {Fr::rand(rng), wpkprime, bc2, bm2};
let commitment2 = comParams.commit(&wallet5, &rprime);
let proof = prove(rng, &comParams, &commitment1, r, wallet1.clone(), wallet5, rprime, &paymentToken, &mpk, &keypair);
assert_eq!(verify(proof, *epsilon, &commitment1, &commitment2, wpk, &comParams, &mpk, &keypair.public), false);
let wallet4 = Wallet { pkc, wpk: wpkprime, bc: bc2, bm: bm2Prime };
let commitment2 = pubParams.comParams.commit(&wallet4.as_fr_vec(), &rprime);
let proof = pubParams.prove(rng, r, wallet1.clone(), wallet4, commitment2.clone(), rprime, &paymentToken);
assert_eq!(pubParams.verify(proof, Fr::from_str(&epsilon.to_string()).unwrap(), &commitment1, &commitment2, wpk), false);
let wallet5 = Wallet { pkc: Fr::rand(rng), wpk: wpkprime, bc: bc2, bm: bm2 };
let commitment2 = pubParams.comParams.commit(&wallet5.as_fr_vec(), &rprime);
let proof = pubParams.prove(rng, r, wallet1.clone(), wallet5, commitment2.clone(), rprime, &paymentToken);
assert_eq!(pubParams.verify(proof, Fr::from_str(&epsilon.to_string()).unwrap(), &commitment1, &commitment2, wpk), false);
}
}

View File

@ -5,22 +5,18 @@ use ff::Rand;
#[derive(Clone)]
pub struct CSParams<E: Engine> {
pub g1: E::G1,
pub g2: E::G2,
pub h1: E::G1,
pub h2: E::G2,
pub g: E::G1,
pub h: E::G1,
}
#[derive(Clone)]
pub struct Commitment<E: Engine> {
pub c1: E::G1,
pub c2: E::G2
pub c: E::G1,
}
#[derive(Clone)]
pub struct CSMultiParams<E: Engine> {
pub pub_bases1: Vec<E::G1>,
pub pub_bases2: Vec<E::G2>
pub pub_bases: Vec<E::G1>,
}
//impl<E: Engine> fmt::Display for CSParams<E> {
@ -63,12 +59,9 @@ impl<E: Engine> CSParams<E> {
Implements the setup algorithm for the Pedersen92 commitment scheme
*/
pub fn setup<R: Rng>(rng: &mut R) -> Self {
let g1 = E::G1::rand(rng);
let g2 = E::G2::rand(rng);
let h1 = E::G1::rand(rng);
let h2 = E::G2::rand(rng);
let csp = CSParams { g1, g2, h1, h2 };
return csp;
let g = E::G1::rand(rng);
let h = E::G1::rand(rng);
CSParams { g, h }
}
/*
@ -81,20 +74,13 @@ commit(pk, msg) -> cm where
let r = R.unwrap_or(E::Fr::rand(rng));
// c = g^m * h^r
let mut c1 = self.g1.clone();
c1.mul_assign(m.clone());
let mut h1 = self.h1.clone();
h1.mul_assign(r.clone());
c1.add_assign(&h1);
let mut c = self.g.clone();
c.mul_assign(m.clone());
let mut h = self.h.clone();
h.mul_assign(r.clone());
c.add_assign(&h);
// c = g^m * h^r
let mut c2 = self.g2.clone();
c2.mul_assign(m);
let mut h2 = self.h2.clone();
h2.mul_assign(r);
c2.add_assign(&h2);
Commitment { c1, c2 }
Commitment { c }
}
/*
@ -104,18 +90,12 @@ decommit(csp, cm, msg) -> bool where
- outputs T/F for whether the cm is a valid commitment to the msg
*/
pub fn decommit(&self, cm: &Commitment<E>, m: &E::Fr, r: &E::Fr) -> bool {
let mut dm1 = self.g1.clone();
dm1.mul_assign(m.clone());
let mut h1 = self.h1.clone();
h1.mul_assign(r.clone());
dm1.add_assign(&h1);
let mut dm2 = self.g2.clone();
dm2.mul_assign(m.clone());
let mut h2 = self.h2.clone();
h2.mul_assign(r.clone());
dm2.add_assign(&h2);
return dm2 == cm.c2 && dm1 == cm.c1;
let mut dm = self.g.clone();
dm.mul_assign(m.clone());
let mut h = self.h.clone();
h.mul_assign(r.clone());
dm.add_assign(&h);
dm == cm.c
}
}
@ -126,49 +106,37 @@ impl<E: Engine> CSMultiParams<E> {
a vector of messages of length len.
*/
pub fn setup_gen_params<R: Rng>(rng: &mut R, len: usize) -> Self {
let mut p1: Vec<E::G1> = Vec::new();
let mut p2: Vec<E::G2> = Vec::new();
let mut p: Vec<E::G1> = Vec::new();
// 1 extra base element for the random parameter
for i in 0..len + 1 {
p1.push(E::G1::rand(rng));
p2.push(E::G2::rand(rng));
p.push(E::G1::rand(rng));
}
return CSMultiParams { pub_bases1: p1, pub_bases2: p2 };
CSMultiParams { pub_bases: p }
}
pub fn commit(&self, x: &Vec<E::Fr>, r: &E::Fr) -> Commitment<E> {
// c = g1^m1 * ... * gn^mn * h^r
let mut c1 = self.pub_bases1[0].clone();
let mut c2 = self.pub_bases2[0].clone();
c1.mul_assign(r.clone());
c2.mul_assign(r.clone());
let mut c = self.pub_bases[0].clone();
c.mul_assign(r.clone());
for i in 0..x.len() {
let mut basis1 = self.pub_bases1[i+1];
basis1.mul_assign(x[i]);
c1.add_assign(&basis1);
let mut basis2 = self.pub_bases2[i+1];
basis2.mul_assign(x[i]);
c2.add_assign(&basis2);
let mut basis = self.pub_bases[i+1];
basis.mul_assign(x[i]);
c.add_assign(&basis);
}
Commitment { c1, c2 }
Commitment { c }
}
pub fn decommit(&self, cm: &Commitment<E>, x: &Vec<E::Fr>, r: &E::Fr) -> bool {
let l = x.len();
// pub_base[0] => h, x[0] => r
let mut dc1 = self.pub_bases1[0].clone();
let mut dc2 = self.pub_bases2[0].clone();
dc1.mul_assign(r.clone());
dc2.mul_assign(r.clone());
let mut dc = self.pub_bases[0].clone();
dc.mul_assign(r.clone());
for i in 0..l {
let mut basis1 = self.pub_bases1[i+1];
basis1.mul_assign(x[i]);
dc1.add_assign(&basis1);
let mut basis2 = self.pub_bases2[i+1];
basis2.mul_assign(x[i]);
dc2.add_assign(&basis2);
let mut basis = self.pub_bases[i+1];
basis.mul_assign(x[i]);
dc.add_assign(&basis);
}
return dc2 == cm.c2 && dc1 == cm.c1;
return dc == cm.c;
}
}

View File

@ -70,8 +70,8 @@ pub struct CommitmentProof<E: Engine> {
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) -> Self {
let mut Tvals = E::G1::zero();
let mut t = Vec::<E::Fr>::with_capacity(com_params.pub_bases1.len() - 1);
for g in com_params.pub_bases1.clone() {
let mut t = Vec::<E::Fr>::with_capacity(com_params.pub_bases.len() - 1);
for g in com_params.pub_bases.clone() {
let ti = E::Fr::rand(csprng);
t.push(ti);
let mut gt = g.clone();
@ -118,7 +118,7 @@ pub fn verify<E: Engine>(com_params: &CSMultiParams<E>, com: &E::G1, proof: &Com
let mut x = E::G1::zero();
for i in 0..proof.z.len() {
let mut base = com_params.pub_bases1[i].clone();
let mut base = com_params.pub_bases[i].clone();
base.mul_assign(proof.z[i].into_repr());
x.add_assign(&base);
}

19
src/wallet.rs Normal file
View File

@ -0,0 +1,19 @@
extern crate pairing;
use super::*;
use pairing::{Engine, CurveProjective};
use ff::PrimeField;
#[derive(Clone)]
pub struct Wallet<E: Engine> {
pub pkc: E::Fr,
pub wpk: E::Fr,
pub bc: i32,
pub bm: i32,
}
impl<E: Engine> Wallet<E> {
pub fn as_fr_vec(&self) -> Vec<E::Fr> {
vec!(self.pkc, self.wpk, E::Fr::from_str(&self.bc.to_string()).unwrap(), E::Fr::from_str(&self.bm.to_string()).unwrap())
}
}