diff --git a/src/multicore.rs b/src/multicore.rs index 84055d7..14fab7a 100644 --- a/src/multicore.rs +++ b/src/multicore.rs @@ -35,6 +35,10 @@ impl Worker { log2_floor(self.cpus) } + pub(crate) fn num_cpus(&self) -> usize { + self.cpus + } + pub fn compute( &self, f: F ) -> WorkerFuture diff --git a/src/sonic/helped/batch.rs b/src/sonic/helped/batch.rs index 3a7e23a..9af97c2 100644 --- a/src/sonic/helped/batch.rs +++ b/src/sonic/helped/batch.rs @@ -16,6 +16,8 @@ use crate::SynthesisError; use crate::sonic::cs::{Backend, SynthesisDriver}; use crate::sonic::cs::{Circuit}; +use super::parameters::VerifyingKey; + use crate::sonic::srs::SRS; use crate::sonic::util::multiexp; @@ -83,6 +85,25 @@ impl Batch { } } + pub fn new_from_key(vk: &VerifyingKey) -> Self { + Batch { + alpha_x: vec![], + alpha_x_precomp: vk.alpha_x.prepare(), + + alpha: vec![], + alpha_precomp: vk.alpha.prepare(), + + neg_h: vec![], + neg_h_precomp: vk.neg_h.prepare(), + + neg_x_n_minus_d: vec![], + neg_x_n_minus_d_precomp: vk.neg_x_n_minus_d.prepare(), + + value: E::Fr::zero(), + g: E::G1Affine::one(), + } + } + pub fn add_opening(&mut self, p: E::G1Affine, mut r: E::Fr, point: E::Fr) { self.alpha_x.push((p, r)); r.mul_assign(&point); diff --git a/src/sonic/helped/generator.rs b/src/sonic/helped/generator.rs index 7b88823..230ff89 100644 --- a/src/sonic/helped/generator.rs +++ b/src/sonic/helped/generator.rs @@ -452,15 +452,7 @@ pub fn generate_parameters_on_srs_and_information( Ok(Parameters{ vk: vk, - d: trimmed_srs.d, - g_negative_x: Arc::new(trimmed_srs.g_negative_x), - g_positive_x: Arc::new(trimmed_srs.g_positive_x), - h_negative_x: Arc::new(trimmed_srs.h_negative_x), - h_positive_x: Arc::new(trimmed_srs.h_positive_x), - g_negative_x_alpha: Arc::new(trimmed_srs.g_negative_x_alpha), - g_positive_x_alpha: Arc::new(trimmed_srs.g_positive_x_alpha), - h_negative_x_alpha: Arc::new(trimmed_srs.h_negative_x_alpha), - h_positive_x_alpha: Arc::new(trimmed_srs.h_positive_x_alpha) + srs: trimmed_srs }) } diff --git a/src/sonic/helped/mod.rs b/src/sonic/helped/mod.rs index 2a81c7b..8cfda80 100644 --- a/src/sonic/helped/mod.rs +++ b/src/sonic/helped/mod.rs @@ -16,7 +16,13 @@ mod generator; pub use self::batch::{Batch}; pub use self::helper::{Aggregate, create_aggregate}; pub use self::verifier::{MultiVerifier}; -pub use self::prover::{create_proof, create_advice}; +pub use self::prover::{ + create_advice, + create_advice_on_information_and_srs, + create_advice_on_srs, + create_proof +}; + pub use self::generator::{ CircuitParameters, generate_parameters, diff --git a/src/sonic/helped/parameters.rs b/src/sonic/helped/parameters.rs index edb7361..255899c 100644 --- a/src/sonic/helped/parameters.rs +++ b/src/sonic/helped/parameters.rs @@ -300,45 +300,38 @@ pub struct PreparedVerifyingKey { pub struct Parameters { pub vk: VerifyingKey, - pub d: usize, + pub srs: SRS, + // pub d: usize, - // g^{x^0}, g^{x^{-1}}, g^{x^{-2}}, ..., g^{x^{-d}} - pub g_negative_x: Arc>, + // // g^{x^0}, g^{x^{-1}}, g^{x^{-2}}, ..., g^{x^{-d}} + // pub g_negative_x: Arc>, - // g^{x^0}, g^{x^{1}}, g^{x^{2}}, ..., g^{x^{d}} - pub g_positive_x: Arc>, + // // g^{x^0}, g^{x^{1}}, g^{x^{2}}, ..., g^{x^{d}} + // pub g_positive_x: Arc>, - // g^{x^0}, g^{x^{-1}}, g^{x^{-2}}, ..., g^{x^{-d}} - pub h_negative_x: Arc>, + // // g^{x^0}, g^{x^{-1}}, g^{x^{-2}}, ..., g^{x^{-d}} + // pub h_negative_x: Arc>, - // g^{x^0}, g^{x^{1}}, g^{x^{2}}, ..., g^{x^{d}} - pub h_positive_x: Arc>, + // // g^{x^0}, g^{x^{1}}, g^{x^{2}}, ..., g^{x^{d}} + // pub h_positive_x: Arc>, - // alpha*(g^{x^{-1}}, g^{x^{-2}}, ..., g^{x^{-d}}) - pub g_negative_x_alpha: Arc>, + // // alpha*(g^{x^{-1}}, g^{x^{-2}}, ..., g^{x^{-d}}) + // pub g_negative_x_alpha: Arc>, - // alpha*(g^{x^{1}}, g^{x^{2}}, ..., g^{x^{d}}) - pub g_positive_x_alpha: Arc>, + // // alpha*(g^{x^{1}}, g^{x^{2}}, ..., g^{x^{d}}) + // pub g_positive_x_alpha: Arc>, - // alpha*(h^{x^0}, h^{x^{-1}}, g^{x^{-2}}, ..., g^{x^{-d}}) - pub h_negative_x_alpha: Arc>, + // // alpha*(h^{x^0}, h^{x^{-1}}, g^{x^{-2}}, ..., g^{x^{-d}}) + // pub h_negative_x_alpha: Arc>, - // alpha*(h^{x^0}, g^{x^{1}}, g^{x^{2}}, ..., g^{x^{d}}) - pub h_positive_x_alpha: Arc>, + // // alpha*(h^{x^0}, g^{x^{1}}, g^{x^{2}}, ..., g^{x^{d}}) + // pub h_positive_x_alpha: Arc>, } impl PartialEq for Parameters { fn eq(&self, other: &Parameters) -> bool { self.vk == other.vk && - self.d == other.d && - self.g_negative_x == other.g_negative_x && - self.g_positive_x == other.g_positive_x && - self.h_negative_x == other.h_negative_x && - self.h_positive_x == other.h_positive_x && - self.g_negative_x_alpha == other.g_negative_x_alpha && - self.g_positive_x_alpha == other.g_positive_x_alpha && - self.h_negative_x_alpha == other.h_negative_x_alpha && - self.h_positive_x_alpha == other.h_positive_x_alpha + self.srs == other.srs } } @@ -349,48 +342,7 @@ impl Parameters { ) -> io::Result<()> { self.vk.write(&mut writer)?; - - assert_eq!(self.d + 1, self.g_negative_x.len()); - assert_eq!(self.d + 1, self.g_positive_x.len()); - - assert_eq!(self.d + 1, self.h_negative_x.len()); - assert_eq!(self.d + 1, self.h_positive_x.len()); - - assert_eq!(self.d, self.g_negative_x_alpha.len()); - assert_eq!(self.d, self.g_positive_x_alpha.len()); - - assert_eq!(self.d + 1, self.h_negative_x_alpha.len()); - assert_eq!(self.d + 1, self.h_positive_x_alpha.len()); - - writer.write_u32::(self.d as u32)?; - - for g in &self.g_negative_x[..] { - writer.write_all(g.into_uncompressed().as_ref())?; - } - for g in &self.g_positive_x[..] { - writer.write_all(g.into_uncompressed().as_ref())?; - } - - for g in &self.h_negative_x[..] { - writer.write_all(g.into_uncompressed().as_ref())?; - } - for g in &self.h_positive_x[..] { - writer.write_all(g.into_uncompressed().as_ref())?; - } - - for g in &self.g_negative_x_alpha[..] { - writer.write_all(g.into_uncompressed().as_ref())?; - } - for g in &self.g_positive_x_alpha[..] { - writer.write_all(g.into_uncompressed().as_ref())?; - } - - for g in &self.h_negative_x_alpha[..] { - writer.write_all(g.into_uncompressed().as_ref())?; - } - for g in &self.h_positive_x_alpha[..] { - writer.write_all(g.into_uncompressed().as_ref())?; - } + self.srs.write(&mut writer)?; Ok(()) } @@ -400,107 +352,12 @@ impl Parameters { checked: bool ) -> io::Result { - let read_g1 = |reader: &mut R| -> io::Result { - let mut repr = ::Uncompressed::empty(); - reader.read_exact(repr.as_mut())?; - - if checked { - repr - .into_affine() - } else { - repr - .into_affine_unchecked() - } - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| if e.is_zero() { - Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) - } else { - Ok(e) - }) - }; - - let read_g2 = |reader: &mut R| -> io::Result { - let mut repr = ::Uncompressed::empty(); - reader.read_exact(repr.as_mut())?; - - if checked { - repr - .into_affine() - } else { - repr - .into_affine_unchecked() - } - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| if e.is_zero() { - Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) - } else { - Ok(e) - }) - }; - let vk = VerifyingKey::::read(&mut reader)?; + let srs = SRS::::read(&mut reader, checked)?; - let mut g_negative_x = vec![]; - let mut g_positive_x = vec![]; - - let mut h_negative_x = vec![]; - let mut h_positive_x = vec![]; - - let mut g_negative_x_alpha = vec![]; - let mut g_positive_x_alpha = vec![]; - - let mut h_negative_x_alpha = vec![]; - let mut h_positive_x_alpha = vec![]; - - let d = reader.read_u32::()? as usize; - - { - for _ in 0..(d+1) { - g_negative_x.push(read_g1(&mut reader)?); - } - for _ in 0..(d+1) { - g_positive_x.push(read_g1(&mut reader)?); - } - } - - { - for _ in 0..(d+1) { - h_negative_x.push(read_g2(&mut reader)?); - } - for _ in 0..(d+1) { - h_positive_x.push(read_g2(&mut reader)?); - } - } - - { - for _ in 0..d { - g_negative_x_alpha.push(read_g1(&mut reader)?); - } - for _ in 0..d { - g_positive_x_alpha.push(read_g1(&mut reader)?); - } - } - - { - for _ in 0..(d+1) { - h_negative_x_alpha.push(read_g2(&mut reader)?); - } - for _ in 0..(d+1) { - h_positive_x_alpha.push(read_g2(&mut reader)?); - } - } - Ok(Parameters { vk: vk, - d: d, - g_negative_x: Arc::new(g_negative_x), - g_positive_x: Arc::new(g_positive_x), - h_negative_x: Arc::new(h_negative_x), - h_positive_x: Arc::new(h_positive_x), - g_negative_x_alpha: Arc::new(g_negative_x_alpha), - g_positive_x_alpha: Arc::new(g_positive_x_alpha), - h_negative_x_alpha: Arc::new(h_negative_x_alpha), - h_positive_x_alpha: Arc::new(h_positive_x_alpha) + srs: srs }) } } diff --git a/src/sonic/helped/prover.rs b/src/sonic/helped/prover.rs index 65a29fa..2ae45ec 100644 --- a/src/sonic/helped/prover.rs +++ b/src/sonic/helped/prover.rs @@ -5,6 +5,7 @@ use std::marker::PhantomData; use super::{Proof, SxyAdvice}; use super::batch::Batch; use super::poly::{SxEval, SyEval}; +use super::parameters::{Parameters}; use crate::SynthesisError; @@ -14,31 +15,13 @@ use crate::sonic::cs::{Backend, SynthesisDriver}; use crate::sonic::cs::{Circuit, Variable, Coeff}; use crate::sonic::srs::SRS; -pub fn create_advice, S: SynthesisDriver>( +pub fn create_advice_on_information_and_srs, S: SynthesisDriver>( circuit: &C, proof: &Proof, - srs: &SRS + srs: &SRS, + n: usize ) -> SxyAdvice { - // annoying, but we need n to compute s(z, y), and this isn't - // precomputed anywhere yet - let n = { - struct CountN { - n: usize - } - - impl<'a, E: Engine> Backend for &'a mut CountN { - fn new_multiplication_gate(&mut self) { - self.n += 1; - } - } - - let mut tmp = CountN{n:0}; - S::synthesize(&mut tmp, circuit).unwrap(); // TODO - - tmp.n - }; - let z: E::Fr; let y: E::Fr; { @@ -111,6 +94,44 @@ pub fn create_advice, S: SynthesisDriver>( } } +pub fn create_advice, S: SynthesisDriver>( + circuit: &C, + proof: &Proof, + parameters: &Parameters, +) -> SxyAdvice +{ + let n = parameters.vk.n; + create_advice_on_information_and_srs::(circuit, proof, ¶meters.srs, n) +} + +pub fn create_advice_on_srs, S: SynthesisDriver>( + circuit: &C, + proof: &Proof, + srs: &SRS +) -> SxyAdvice +{ + // annoying, but we need n to compute s(z, y), and this isn't + // precomputed anywhere yet + let n = { + struct CountN { + n: usize + } + + impl<'a, E: Engine> Backend for &'a mut CountN { + fn new_multiplication_gate(&mut self) { + self.n += 1; + } + } + + let mut tmp = CountN{n:0}; + S::synthesize(&mut tmp, circuit).unwrap(); // TODO + + tmp.n + }; + + create_advice_on_information_and_srs::(circuit, proof, srs, n) +} + pub fn create_proof, S: SynthesisDriver>( circuit: &C, srs: &SRS diff --git a/src/sonic/util.rs b/src/sonic/util.rs index 0903ec6..2bc2850 100644 --- a/src/sonic/util.rs +++ b/src/sonic/util.rs @@ -71,6 +71,118 @@ where } } +extern crate crossbeam; +use self::crossbeam::channel::{unbounded, RecvError}; + +pub fn evaluate_at_consequitive_powers<'a, F: Field> ( + coeffs: &[F], + first_power: F, + base: F +) -> F + { + use crate::multicore::Worker; + + let (s, r) = unbounded(); + + let worker = Worker::new(); + + worker.scope(coeffs.len(), |scope, chunk| { + for (i, coeffs) in coeffs.chunks(chunk).enumerate() + { + let s = s.clone(); + scope.spawn(move |_| { + let mut current_power = base.pow(&[(i*chunk) as u64]); + current_power.mul_assign(&first_power); + + let mut acc = F::zero(); + + for p in coeffs { + let mut tmp = *p; + tmp.mul_assign(¤t_power); + acc.add_assign(&tmp); + + current_power.mul_assign(&base); + } + + s.send(acc).expect("must send"); + }); + } + }); + + drop(s); + + // all threads in a scope have done working, so we can safely read + let mut result = F::zero(); + + loop { + let v = r.recv(); + match v { + Ok(value) => { + result.add_assign(&value); + }, + Err(RecvError) => { + break; + } + } + } + + result +} + +pub fn mut_evaluate_at_consequitive_powers<'a, F: Field> ( + coeffs: &mut [F], + first_power: F, + base: F +) -> F + { + use crate::multicore::Worker; + + let (s, r) = unbounded(); + + let worker = Worker::new(); + + worker.scope(coeffs.len(), |scope, chunk| { + for (i, coeffs) in coeffs.chunks_mut(chunk).enumerate() + { + let s = s.clone(); + scope.spawn(move |_| { + let mut current_power = base.pow(&[(i*chunk) as u64]); + current_power.mul_assign(&first_power); + + let mut acc = F::zero(); + + for mut p in coeffs { + p.mul_assign(¤t_power); + acc.add_assign(&p); + + current_power.mul_assign(&base); + } + + s.send(acc).expect("must send"); + }); + } + }); + + drop(s); + + // all threads in a scope have done working, so we can safely read + let mut result = F::zero(); + + loop { + let v = r.recv(); + match v { + Ok(value) => { + result.add_assign(&value); + }, + Err(RecvError) => { + break; + } + } + } + + result +} + pub fn multiexp< 'a, G: CurveAffine, @@ -420,4 +532,69 @@ fn test_mul() { assert_eq!(serial_res.len(), parallel_res.len()); assert_eq!(serial_res, parallel_res); +} + +#[test] +fn test_eval_at_powers() { + use rand::{self, Rand, Rng}; + use pairing::bls12_381::Bls12; + use pairing::bls12_381::Fr; + + const SAMPLES: usize = 100000; + + let rng = &mut rand::thread_rng(); + let a = (0..SAMPLES).map(|_| Fr::rand(rng)).collect::>(); + let x: Fr = rng.gen(); + let n: u32 = rng.gen(); + + let mut acc = Fr::zero(); + + { + let mut tmp = x.pow(&[n as u64]); + + for coeff in a.iter() { + let mut c = *coeff; + c.mul_assign(&tmp); + acc.add_assign(&c); + tmp.mul_assign(&x); + } + } + + let first_power = x.pow(&[n as u64]); + let acc_parallel = evaluate_at_consequitive_powers(&a[..], first_power, x); + + assert_eq!(acc_parallel, acc); +} + +#[test] +fn test_mut_eval_at_powers() { + use rand::{self, Rand, Rng}; + use pairing::bls12_381::Bls12; + use pairing::bls12_381::Fr; + + const SAMPLES: usize = 100000; + + let rng = &mut rand::thread_rng(); + let mut a = (0..SAMPLES).map(|_| Fr::rand(rng)).collect::>(); + let mut b = a.clone(); + let x: Fr = rng.gen(); + let n: u32 = rng.gen(); + + let mut acc = Fr::zero(); + + { + let mut tmp = x.pow(&[n as u64]); + + for mut coeff in a.iter_mut() { + coeff.mul_assign(&tmp); + acc.add_assign(&coeff); + tmp.mul_assign(&x); + } + } + + let first_power = x.pow(&[n as u64]); + let acc_parallel = mut_evaluate_at_consequitive_powers(&mut b[..], first_power, x); + + assert_eq!(acc_parallel, acc); + assert!(a == b); } \ No newline at end of file diff --git a/tests/mimc.rs b/tests/mimc.rs index 9d6e24f..7d569a4 100644 --- a/tests/mimc.rs +++ b/tests/mimc.rs @@ -479,7 +479,7 @@ fn test_sonic_mimc() { use bellman::sonic::cs::Basic; use bellman::sonic::sonic::AdaptorCircuit; - use bellman::sonic::helped::{create_proof, create_advice, create_aggregate, MultiVerifier}; + use bellman::sonic::helped::{create_proof, create_advice, create_aggregate, MultiVerifier, create_advice_on_srs}; println!("creating proof"); let start = Instant::now(); @@ -488,7 +488,7 @@ fn test_sonic_mimc() { println!("creating advice"); let start = Instant::now(); - let advice = create_advice::(&AdaptorCircuit(circuit.clone()), &proof, &srs); + let advice = create_advice_on_srs::(&AdaptorCircuit(circuit.clone()), &proof, &srs); println!("done in {:?}", start.elapsed()); println!("creating aggregate for {} proofs", samples); @@ -578,7 +578,7 @@ fn test_inputs_into_sonic_mimc() { use bellman::sonic::cs::Basic; use bellman::sonic::sonic::AdaptorCircuit; - use bellman::sonic::helped::{create_proof, get_circuit_parameters, create_advice, create_aggregate, MultiVerifier}; + use bellman::sonic::helped::{create_proof, get_circuit_parameters, create_advice, create_aggregate, MultiVerifier, create_advice_on_srs}; let info = get_circuit_parameters::(circuit.clone()).expect("Must get circuit info"); println!("{:?}", info); @@ -590,7 +590,7 @@ fn test_inputs_into_sonic_mimc() { println!("creating advice"); let start = Instant::now(); - let advice = create_advice::(&AdaptorCircuit(circuit.clone()), &proof, &srs); + let advice = create_advice_on_srs::(&AdaptorCircuit(circuit.clone()), &proof, &srs); println!("done in {:?}", start.elapsed()); println!("creating aggregate for {} proofs", samples);