libbolt/src/ccs08.rs

324 lines
11 KiB
Rust
Raw Normal View History

2019-06-14 15:14:06 -07:00
/*
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;
2019-06-16 13:29:48 -07:00
use rand::{thread_rng, Rng};
2019-06-14 15:14:06 -07:00
use super::*;
use cl::{KeyPair, Signature, PublicParams, setup};
2019-06-16 09:27:35 -07:00
use ped92::{CSPublicKey, Commitment};
use pairing::{Engine, CurveProjective};
2019-06-14 15:14:06 -07:00
use ff::PrimeField;
2019-06-16 09:27:35 -07:00
use std::collections::HashMap;
use std::fmt::Display;
2019-06-16 12:38:07 -07:00
use std::mem::transmute;
2019-06-14 15:14:06 -07:00
/*
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>,
2019-06-16 09:27:35 -07:00
pub signatures: HashMap<String, Signature<E>>,
pub com: CSPublicKey<E>,
2019-06-14 15:14:06 -07:00
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> {
2019-06-16 09:27:35 -07:00
v: Vec<E::G1>,
2019-06-14 15:14:06 -07:00
d: E::G2,
2019-06-16 09:27:35 -07:00
comm: Commitment<E>,
2019-06-14 15:14:06 -07:00
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,
}
2019-06-16 13:29:48 -07:00
impl<E: Engine> ParamsUL<E> {
/*
2019-06-14 15:14:06 -07:00
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.
*/
2019-06-16 13:29:48 -07:00
pub fn setup_ul<R: Rng>(rng: &mut R, u: i64, l: i64) -> ParamsUL<E> {
let mpk = setup(rng);
let kp = KeyPair::<E>::generate(rng, &mpk, 1);
2019-06-14 15:14:06 -07:00
2019-06-16 13:29:48 -07:00
let mut signatures: HashMap<String, Signature<E>> = HashMap::new();
for i in 0..u {
let sig_i = kp.sign(rng, &vec! {E::Fr::from_str(i.to_string().as_str()).unwrap()});
signatures.insert(i.to_string(), sig_i);
}
2019-06-14 15:14:06 -07:00
2019-06-16 13:29:48 -07:00
let com = CSPublicKey::setup(rng);
return ParamsUL { mpk, signatures, com, kp, u, l };
2019-06-14 15:14:06 -07:00
}
2019-06-16 13:29:48 -07:00
/*
2019-06-16 09:27:35 -07:00
prove_ul method is used to produce the ZKRP proof that secret x belongs to the interval [0,U^L].
*/
2019-06-16 13:29:48 -07:00
pub fn prove_ul<R: Rng>(&self, rng: &mut R, x: i64, r: E::Fr) -> ProofUL<E> {
let mut mutr = r.clone();
2019-06-16 09:27:35 -07:00
2019-06-16 13:29:48 -07:00
let decx = decompose(x, self.u);
let modx = E::Fr::from_str(&(x.to_string())).unwrap();
2019-06-16 09:27:35 -07:00
// Initialize variables
2019-06-16 13:29:48 -07:00
let mut v = Vec::<E::Fr>::with_capacity(self.l as usize);
let mut V = Vec::<E::G1>::with_capacity(self.l as usize);
let mut a = Vec::<E::Fqk>::with_capacity(self.l as usize);
let mut s = Vec::<E::Fr>::with_capacity(self.l as usize);
let mut t = Vec::<E::Fr>::with_capacity(self.l as usize);
let mut zsig = Vec::<E::Fr>::with_capacity(self.l as usize);
let mut zv = Vec::<E::Fr>::with_capacity(self.l as usize);
let mut one = E::G2::one();
let mut D = E::G2::zero();
one.negate();
D.add_assign(&one);
let mut m = E::Fr::rand(rng);
2019-06-16 09:27:35 -07:00
// D = H^m
2019-06-16 13:29:48 -07:00
let mut Dnew = self.com.h;
Dnew.mul_assign(m);
for i in 0..self.l as usize {
v.push(E::Fr::rand(rng));
let mut A = self.signatures.get(&decx[i].to_string()).unwrap().H;
A.mul_assign(v[i]);
V.push(A);
s.push(E::Fr::rand(rng));
t.push(E::Fr::rand(rng));
a.push(E::pairing(V[i], self.mpk.g2));
a[i].pow(s[i].into_repr());
a[i] = a[i].inverse().unwrap();
let mut E = E::pairing(self.mpk.g1, self.mpk.g2);
E.pow(t[i].into_repr());
a[i].add_assign(&E);
2019-06-16 09:27:35 -07:00
2019-06-16 13:29:48 -07:00
let ui = self.u.pow(i as u32);
let mut muisi = s[i].clone();
muisi.mul_assign(&E::Fr::from_str(&ui.to_string()).unwrap());
let mut aux = self.mpk.g2.clone();
aux.mul_assign(muisi);
D.add_assign(&aux);
}
D.add_assign(&Dnew);
let C = self.com.commit(rng, modx, Some(mutr));
2019-06-16 09:27:35 -07:00
// Fiat-Shamir heuristic
2019-06-16 13:29:48 -07:00
let c = Hash::<E>(a.clone(), D.clone());
let mut zr = m.clone();
mutr.mul_assign(&c);
zr.sub_assign(&mutr);
for i in 0..self.l as usize {
zsig.push(s[i].clone());
let mut dx = E::Fr::from_str(&decx[i].to_string()).unwrap();
dx.mul_assign(&c);
zsig[i].sub_assign(&dx);
let mut vi = v[i].clone();
vi.mul_assign(&c);
let mut ti = t[i].clone();
ti.sub_assign(&vi);
zv.push(ti.clone());
}
return ProofUL { v: V, d: D, comm: C, a, s, t, zsig, zv, ch: c, m, zr };
2019-06-16 09:27:35 -07:00
}
}
fn Hash<E: Engine>(a: Vec<E::Fqk>, D: E::G2) -> E::Fr {
// create a Sha256 object
let mut a_vec: Vec<u8> = Vec::new();
for a_el in a {
a_vec.extend(format!("{}", a_el).bytes());
}
let mut x_vec: Vec<u8> = Vec::new();
x_vec.extend(format!("{}", D).bytes());
a_vec.extend(x_vec);
let sha2_digest = sha512::hash(a_vec.as_slice());
let mut hash_buf: [u8; 64] = [0; 64];
hash_buf.copy_from_slice(&sha2_digest[0..64]);
2019-06-16 12:38:07 -07:00
let mut hexresult = fmt_bytes_to_int(hash_buf);
let result = E::Fr::from_str(&hexresult);
return result.unwrap();
2019-06-16 09:27:35 -07:00
}
2019-06-14 15:14:06 -07:00
2019-06-16 13:29:48 -07:00
/*
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;
}
2019-06-16 12:38:07 -07:00
fn fmt_bytes_to_int(bytearray: [u8; 64]) -> String {
let mut result: String = "".to_string();
for byte in bytearray.iter() {
// Decide if you want upper- or lowercase results,
// padding the values to two characters, spaces
// between bytes, etc.
result = result + &format!("{}", *byte as u8);
2019-06-14 15:14:06 -07:00
}
2019-06-16 12:38:07 -07:00
result.to_string()
}
impl<E: Engine> RPPublicParams<E> {
/*
Setup receives integers a and b, and configures the parameters for the rangeproof scheme.
*/
2019-06-16 13:29:48 -07:00
pub fn setup<R: Rng>(rng: &mut R, a: i64, b: i64) -> RPPublicParams<E> {
2019-06-16 12:38:07 -07:00
// 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;
2019-06-16 13:29:48 -07:00
let params_out: ParamsUL<E> = ParamsUL::<E>::setup_ul(rng, u, l);
2019-06-16 12:38:07 -07:00
return RPPublicParams { p: params_out, a, b };
} else {
panic!("u is zero");
}
2019-06-14 15:14:06 -07:00
} else {
2019-06-16 12:38:07 -07:00
panic!("log(b) is zero");
2019-06-14 15:14:06 -07:00
}
}
}
#[cfg(test)]
mod tests {
use super::*;
2019-06-16 12:38:07 -07:00
use pairing::bls12_381::{Bls12, G2, Fq12, Fr};
2019-06-14 15:14:06 -07:00
#[test]
fn setup_ul_works() {
2019-06-16 13:29:48 -07:00
let rng = &mut rand::thread_rng();
let params = ParamsUL::<Bls12>::setup_ul(rng, 2, 3);
assert_eq!(2, params.signatures.len());
for (m, s) in params.signatures {
assert_eq!(true, params.kp.verify(&params.mpk, &vec! {Fr::from_str(m.to_string().as_str()).unwrap()}, &s));
2019-06-14 15:14:06 -07:00
}
}
2019-06-16 13:29:48 -07:00
#[test]
fn prove_ul_works() {
let rng = &mut rand::thread_rng();
let params = ParamsUL::<Bls12>::setup_ul(rng, 2, 3);
let fr = Fr::rand(rng);
let proof = params.prove_ul(rng, 10, fr);
}
2019-06-14 15:14:06 -07:00
#[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() {
2019-06-16 13:29:48 -07:00
let rng = &mut rand::thread_rng();
let public_params = RPPublicParams::<Bls12>::setup(rng, 2, 10);
2019-06-14 15:14:06 -07:00
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() {
2019-06-16 13:29:48 -07:00
let rng = &mut rand::thread_rng();
let public_params = RPPublicParams::<Bls12>::setup(rng, 10, 2);
2019-06-14 15:14:06 -07:00
}
#[test]
#[should_panic(expected = "u is zero")]
fn setup_wrong_b() {
2019-06-16 13:29:48 -07:00
let rng = &mut rand::thread_rng();
let public_params = RPPublicParams::<Bls12>::setup(rng, -1, 0);
2019-06-14 15:14:06 -07:00
}
#[test]
#[should_panic(expected = "log(b) is zero")]
fn setup_wrong_logb() {
2019-06-16 13:29:48 -07:00
let rng = &mut rand::thread_rng();
let public_params = RPPublicParams::<Bls12>::setup(rng, -1, 1);
2019-06-16 12:38:07 -07:00
}
#[test]
fn fmt_byte_to_int_works() {
assert_eq!("122352312313431223523123134312235231231343122352312313431223523123134312235231231343122352312313431223523123134312235231231343122352312313431223523123",
2019-06-16 13:29:48 -07:00
fmt_bytes_to_int([12, 235, 23, 123, 13, 43, 12, 235, 23, 123, 13, 43, 12, 235, 23, 123, 13, 43, 12, 235, 23, 123, 13, 43, 12, 235, 23, 123, 13, 43, 12, 235, 23, 123, 13, 43, 12, 235, 23, 123, 13, 43, 12, 235, 23, 123, 13, 43, 12, 235, 23, 123, 13, 43, 12, 235, 23, 123, 13, 43, 12, 235, 23, 123]));
2019-06-16 12:38:07 -07:00
}
#[test]
fn hash_works() {
2019-06-16 13:29:48 -07:00
let rng = &mut rand::thread_rng();
2019-06-16 12:38:07 -07:00
let D = G2::rand(rng);
let D2 = G2::rand(rng);
let a = vec! {Fq12::rand(rng), Fq12::rand(rng), Fq12::rand(rng)};
let a2 = vec! {Fq12::rand(rng), Fq12::rand(rng), Fq12::rand(rng)};
assert_eq!(false, Hash::<Bls12>(a.clone(), D.clone()).is_zero());
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()));
2019-06-14 15:14:06 -07:00
}
}