ccs08: basics for ccs08 implementation
This commit is contained in:
parent
47135a1a12
commit
37ab55bc72
|
@ -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(¶ms_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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue