ccs08: basics for ccs08 implementation

This commit is contained in:
Gijs Van Laer 2019-06-14 18:14:06 -04:00
parent 47135a1a12
commit 37ab55bc72
2 changed files with 250 additions and 0 deletions

249
src/ccs08.rs Normal file
View File

@ -0,0 +1,249 @@
/*
Implementation of the ZK Range Proof scheme, based on:
Efficient Protocols for Set Membership and Range Proofs
Jan Camenisch, Rafik Chaabouni, and abhi shelat
Asiacrypt 2008
*/
extern crate pairing;
extern crate rand;
use super::*;
use cl::{KeyPair, Signature, PublicParams, setup};
use pairing::Engine;
use std::collections::HashMap;
use rand::Rng;
use ff::PrimeField;
use commit_scheme::{ped92_setup, ped92_commit, ped92_decommit, Commitment};
/*
paramsUL contains elements generated by the verifier, which are necessary for the prover.
This must be computed in a trusted setup.
*/
#[derive(Clone)]
struct ParamsUL<E: Engine> {
pub mpk: PublicParams<E>,
pub signatures: Vec<(i64, Signature<E>)>,
pub h: E::G2,
kp: KeyPair<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,
// 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,
}
/*
proofUL contains the necessary elements for the ZK range proof.
*/
#[derive(Clone)]
struct ProofUL<E: Engine> {
v: Vec<E::G2>,
d: E::G2,
comm: Commitment,
a: Vec<E::Fqk>,
s: Vec<E::Fr>,
t: Vec<E::Fr>,
zsig: Vec<E::Fr>,
zv: Vec<E::Fr>,
ch: E::Fr,
m: E::Fr,
zr: E::Fr,
}
#[derive(Clone)]
pub struct RangeProof<E: Engine> {
p1: ProofUL<E>,
p2: ProofUL<E>,
}
/*
params contains elements generated by the verifier, which are necessary for the prover.
This must be computed in a trusted setup.
*/
#[derive(Clone)]
pub struct RPPublicParams<E: Engine> {
p: ParamsUL<E>,
a: i64,
b: i64,
}
/*
setup_ul generates the signature for the interval [0,u^l).
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.
*/
fn setup_ul<E: Engine>(u: i64, l: i64) -> ParamsUL<E> {
let mut rng = &mut rand::thread_rng();
let mpk = setup(&mut rng);
let kp = KeyPair::<E>::generate(&mut rng, &mpk, 1);
let mut signatures: Vec<(i64, Signature<E>)> = Vec::new();
for i in 0..u {
let sig_i = kp.sign(&mut rng, &vec! {E::Fr::from_str(i.to_string().as_str()).unwrap()});
signatures.push((i, sig_i));
}
let h = E::G2::rand(rng);
return ParamsUL { mpk, signatures, h, kp, u, l };
}
/*
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) -> Vec<i64> {
let l = (x as f64).log(u as f64).ceil() as usize;
let mut result = Vec::with_capacity(l as usize);
let mut decomposer = x.clone();
for i in 0..l {
result.push(decomposer % u);
decomposer = decomposer / u;
}
return result;
}
///*
//prove_ul method is used to produce the ZKRP proof that secret x belongs to the interval [0,U^L].
//*/
//fn prove_ul<E: Engine>(x: E::Fr, r: E::Fr, p: ParamsUL<E>) -> ProofUL<E> {
// let decx = decompose(x, p.u);
//
//// Initialize variables
// let mut v = Vec::<i64>::with_capacity(p.l as usize);
// let mut V = Vec::<E::G2>::with_capacity(p.l as usize);
// let mut a = Vec::<E::Fqk>::with_capacity(p.l as usize);
// let mut s = Vec::<i64>::with_capacity(p.l as usize);
// let mut t = Vec::<i64>::with_capacity(p.l as usize);
// let mut zsig = Vec::<i64>::with_capacity(p.l as usize);
// let mut zv = Vec::<i64>::with_capacity(p.l as usize);
// let mut one: E::G2::one();
// let mut D = E::G2::zero().add_assign(one.negate());
// let mut m = rand.Int(rand.Reader, bn256.Order);
//
//// D = H^m
// D = new(bn256.G2).ScalarMult(p.H, proof_out.m);
// for i in 0..p.l {
// v.push(rand.Int(rand.Reader, bn256.Order));
// let A = p.signatures[strconv.FormatInt(decx[i], 10)];
// V.push(new(bn256.G2).ScalarMult(A, v[i]));
// s.push(rand.Int(rand.Reader, bn256.Order));
// t.push(rand.Int(rand.Reader, bn256.Order));
// a.push(bn256.Pair(G1, proof_out.V[i]));
// a[i].ScalarMult(proof_out.a[i], proof_out.s[i]);
// a[i].Invert(proof_out.a[i]);
// a[i].Add(proof_out.a[i], new(bn256.GT).ScalarMult(E, proof_out.t[i]));
//
// let ui = new(big.Int).Exp(new(big.Int).SetInt64(p.u), new(big.Int).SetInt64(i), nil);
// let mut muisi = new(big.Int).Mul(proof_out.s[i], ui);
// muisi = Mod(muisi, bn256.Order);
// let aux = new(bn256.G2).ScalarBaseMult(muisi);
// D.Add(D, aux);
// }
// proof_out.D.Add(proof_out.D, D);
//
//// Consider passing C as input,
//// so that it is possible to delegate the commitment computation to an external party.
// let C = ped92_commit(p.H, x, r); //TODO: commit
//// Fiat-Shamir heuristic
// let mut c = Hash(proof_out.a, proof_out.D);
// c = Mod(proof_out.c, bn256.Order);
//
// let mut zr = Sub(proof_out.m, Multiply(r, proof_out.c));
// zr = Mod(proof_out.zr, bn256.Order);
// for i in 0..p.l {
// proof_out.zsig[i] = Sub(proof_out.s[i], Multiply(new(big.Int).SetInt64(decx[i]), proof_out.c));
// proof_out.zsig[i] = Mod(proof_out.zsig[i], bn256.Order);
// proof_out.zv[i] = Sub(proof_out.t[i], Multiply(v[i], proof_out.c));
// proof_out.zv[i] = Mod(proof_out.zv[i], bn256.Order);
// }
// return ProofUL {v, d: D, comm: C, a, s, t, zsig, zv, ch: c, m, zr};
//}
/*
Setup receives integers a and b, and configures the parameters for the rangeproof scheme.
*/
pub fn ccs08_setup<E: Engine>(a: i64, b: i64) -> RPPublicParams<E> {
// Compute optimal values for u and l
if a > b {
panic!("a must be less than or equal to b");
}
let p: PublicParams<E>;
let logb = (b as f64).log10();
if logb != 0.0 {
let u = b / logb as i64;
if u != 0 {
let l = (b as f64).log(u as f64).ceil() as i64;
let params_out: ParamsUL<E> = setup_ul(u, l);
return RPPublicParams { p: params_out, a, b };
} else {
panic!("u is zero");
}
} else {
panic!("log(b) is zero");
}
}
#[cfg(test)]
mod tests {
use super::*;
use pairing::bls12_381::{Bls12, Fr};
#[test]
fn setup_ul_works() {
let mut rng = &mut rand::thread_rng();
let params_set = setup_ul::<Bls12>(2, 3);
assert_eq!(2, params_set.signatures.len());
for (m, s) in params_set.signatures {
assert_eq!(true, params_set.kp.verify(&params_set.mpk, &vec! {Fr::from_str(m.to_string().as_str()).unwrap()}, &s));
}
}
#[test]
fn decompose_works() {
assert_eq!(vec! {1, 2, 2}, decompose(25, 3));
assert_eq!(vec! {0, 6, 6}, decompose(336, 7));
assert_eq!(vec! {5, 3, 4}, decompose(285, 8));
assert_eq!(vec! {8, 9}, decompose(125, 13));
assert_eq!(vec! {5, 2, 0, 3, 2, 0, 3}, decompose(143225, 6));
}
#[test]
fn setup_works() {
let mut rng = &mut rand::thread_rng();
let public_params = ccs08_setup::<Bls12>(2, 10);
assert_eq!(2, public_params.a);
assert_eq!(10, public_params.b);
assert_eq!(10, public_params.p.signatures.len());
assert_eq!(10 / ((10 as f64).log10() as i64), public_params.p.u);
assert_eq!(((10 / (10 / ((10 as f64).log10() as i64))) as f64).ceil() as i64, public_params.p.l);
for (m, s) in public_params.p.signatures {
assert_eq!(true, public_params.p.kp.verify(&public_params.p.mpk, &vec! {Fr::from_str(m.to_string().as_str()).unwrap()}, &s));
}
}
#[test]
#[should_panic(expected = "a must be less than or equal to b")]
fn setup_wrong_a_and_b() {
let mut rng = &mut rand::thread_rng();
let public_params = ccs08_setup::<Bls12>(10, 2);
}
#[test]
#[should_panic(expected = "u is zero")]
fn setup_wrong_b() {
let mut rng = &mut rand::thread_rng();
let public_params = ccs08_setup::<Bls12>(-1, 0);
}
#[test]
#[should_panic(expected = "log(b) is zero")]
fn setup_wrong_logb() {
let mut rng = &mut rand::thread_rng();
let public_params = ccs08_setup::<Bls12>(-1, 1);
}
}

View File

@ -64,6 +64,7 @@ pub mod sym;
pub mod ote;
pub mod cl;
pub mod clsigs;
pub mod ccs08;
pub mod commit_scheme;
pub mod clproto;
pub mod serialization_wrappers;