From 9819e9e08b6f0642dd3590b50db3f0632ecfb1d3 Mon Sep 17 00:00:00 2001 From: poma Date: Sun, 24 Mar 2019 07:47:47 +0300 Subject: [PATCH 1/5] Merge singlecore and multicore configs --- Cargo.toml | 1 + src/lib.rs | 26 ++++++++++++++------------ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b97cbf9..9d6f61c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ crate-type = ["cdylib", "lib", "staticlib"] rand = "0.4" bit-vec = "0.4.4" futures = "0.1" +cfg-if = "0.1.7" pairing = { git = 'https://github.com/matterinc/pairing', tag = "0.16.2" } #pairing = { path = "../pairing" } diff --git a/src/lib.rs b/src/lib.rs index 690219a..23ca127 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,7 @@ #![allow(unused_imports)] +#[macro_use] +extern crate cfg_if; extern crate pairing as pairing_import; extern crate rand; extern crate bit_vec; @@ -20,18 +22,18 @@ mod multiexp; #[cfg(test)] mod tests; -#[cfg(feature = "multicore")] -mod multicore; - -#[cfg(feature = "singlecore")] -mod singlecore; - -mod worker { - #[cfg(feature = "multicore")] - pub use crate::multicore::*; - - #[cfg(feature = "singlecore")] - pub use crate::singlecore::*; +cfg_if! { + if #[cfg(feature = "multicore")] { + mod multicore; + mod worker { + pub use crate::multicore::*; + } + } else { + mod singlecore; + mod worker { + pub use crate::singlecore::*; + } + } } pub mod pairing { From 4ed859e151c96ad71bd7780de372dbfdae7975b2 Mon Sep 17 00:00:00 2001 From: poma Date: Sun, 24 Mar 2019 09:28:54 +0300 Subject: [PATCH 2/5] WASM compatibility Extracted all logs and timers calls to a separate file Added WASM specific logging and profiling --- Cargo.toml | 5 +-- src/groth16/generator.rs | 35 +++++++++----------- src/groth16/prover.rs | 31 ++++++++---------- src/lib.rs | 5 +++ src/log.rs | 70 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 107 insertions(+), 39 deletions(-) create mode 100644 src/log.rs diff --git a/Cargo.toml b/Cargo.toml index 9d6f61c..2ff1eb8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ num_cpus = {version = "1", optional = true} crossbeam = {version = "0.7.1", optional = true} tiny-keccak = {version = "1.4.2", optional = true} +web-sys = {version = "0.3.17", optional = true, features = ["console", "Performance", "Window"]} [dependencies.blake2-rfc] git = "https://github.com/gtank/blake2-rfc" @@ -35,8 +36,8 @@ rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9" [features] default = ["multicore"] #default = ["multicore", "gm17", "sonic"] -#default = ["singlecore"] +#default = ["wasm"] multicore = ["futures-cpupool", "num_cpus", "crossbeam"] sonic = ["tiny-keccak"] gm17 = [] -singlecore = [] +wasm = ["web-sys"] diff --git a/src/groth16/generator.rs b/src/groth16/generator.rs index 3d4cb1f..961696a 100644 --- a/src/groth16/generator.rs +++ b/src/groth16/generator.rs @@ -1,4 +1,4 @@ -use super::super::verbose_flag; +use crate::log::Stopwatch; use rand::Rng; @@ -187,8 +187,6 @@ pub fn generate_parameters( ) -> Result, SynthesisError> where E: Engine, C: Circuit { - let verbose = verbose_flag(); - let mut assembly = KeypairAssembly { num_inputs: 0, num_aux: 0, @@ -217,7 +215,7 @@ pub fn generate_parameters( ); } - if verbose {eprintln!("Making {} powers of tau", assembly.num_constraints)}; + elog_verbose!("Making {} powers of tau", assembly.num_constraints); // Create bases for blind evaluation of polynomials at tau let powers_of_tau = vec![Scalar::(E::Fr::zero()); assembly.num_constraints]; let mut powers_of_tau = EvaluationDomain::from_coeffs(powers_of_tau)?; @@ -250,9 +248,9 @@ pub fn generate_parameters( let mut h = vec![E::G1::zero(); powers_of_tau.as_ref().len() - 1]; { // Compute powers of tau - if verbose {eprintln!("computing powers of tau...")}; + elog_verbose!("computing powers of tau..."); - let start = std::time::Instant::now(); + let stopwatch = Stopwatch::new(); { let powers_of_tau = powers_of_tau.as_mut(); @@ -270,15 +268,15 @@ pub fn generate_parameters( } }); } - if verbose {eprintln!("powers of tau stage 1 done in {} s", start.elapsed().as_millis() as f64 / 1000.0);}; + elog_verbose!("powers of tau stage 1 done in {} s", stopwatch.elapsed()); // coeff = t(x) / delta let mut coeff = powers_of_tau.z(&tau); coeff.mul_assign(&delta_inverse); - if verbose {eprintln!("computing the H query with multiple threads...")}; + elog_verbose!("computing the H query with multiple threads..."); - let start = std::time::Instant::now(); + let stopwatch = Stopwatch::new(); // Compute the H query with multiple threads worker.scope(h.len(), |scope, chunk| { @@ -302,27 +300,26 @@ pub fn generate_parameters( }); } }); - if verbose {eprintln!("computing the H query done in {} s", start.elapsed().as_millis() as f64 / 1000.0);}; + elog_verbose!("computing the H query done in {} s", stopwatch.elapsed()); } - if verbose {eprintln!("using inverse FFT to convert powers of tau to Lagrange coefficients...")}; - - let start = std::time::Instant::now(); + elog_verbose!("using inverse FFT to convert powers of tau to Lagrange coefficients..."); + + let stopwatch = Stopwatch::new(); // Use inverse FFT to convert powers of tau to Lagrange coefficients powers_of_tau.ifft(&worker); let powers_of_tau = powers_of_tau.into_coeffs(); - if verbose {eprintln!("powers of tau stage 2 done in {} s", start.elapsed().as_millis() as f64 / 1000.0)}; - + elog_verbose!("powers of tau stage 2 done in {} s", stopwatch.elapsed()); let mut a = vec![E::G1::zero(); assembly.num_inputs + assembly.num_aux]; let mut b_g1 = vec![E::G1::zero(); assembly.num_inputs + assembly.num_aux]; let mut b_g2 = vec![E::G2::zero(); assembly.num_inputs + assembly.num_aux]; let mut ic = vec![E::G1::zero(); assembly.num_inputs]; let mut l = vec![E::G1::zero(); assembly.num_aux]; - if verbose {eprintln!("evaluating polynomials...")}; - let start = std::time::Instant::now(); + elog_verbose!("evaluating polynomials..."); + let stopwatch = Stopwatch::new(); fn eval( // wNAF window tables @@ -475,7 +472,7 @@ pub fn generate_parameters( &worker ); - if verbose {eprintln!("evaluating polynomials done in {} s", start.elapsed().as_millis() as f64 / 1000.0);}; + elog_verbose!("evaluating polynomials done in {} s", stopwatch.elapsed()); // Don't allow any elements be unconstrained, so that // the L query is always fully dense. @@ -498,7 +495,7 @@ pub fn generate_parameters( ic: ic.into_iter().map(|e| e.into_affine()).collect() }; - println!("Has generated {} points", a.len()); + log!("Has generated {} points", a.len()); Ok(Parameters { vk: vk, diff --git a/src/groth16/prover.rs b/src/groth16/prover.rs index 3c7412c..86981e2 100644 --- a/src/groth16/prover.rs +++ b/src/groth16/prover.rs @@ -1,4 +1,4 @@ -use super::super::verbose_flag; +use crate::log::Stopwatch; use rand::Rng; @@ -164,20 +164,18 @@ impl PreparedProver { s: E::Fr ) -> Result, SynthesisError> { - let verbose = verbose_flag(); - let prover = self.assignment.clone(); let worker = Worker::new(); let vk = params.get_vk(self.assignment.input_assignment.len())?; - let start = std::time::Instant::now(); + let stopwatch = Stopwatch::new(); let h = { let mut a = EvaluationDomain::from_coeffs(prover.a)?; let mut b = EvaluationDomain::from_coeffs(prover.b)?; let mut c = EvaluationDomain::from_coeffs(prover.c)?; - if verbose {eprintln!("H query domain size is {}", a.as_ref().len())}; + elog_verbose!("H query domain size is {}", a.as_ref().len()); // here a coset is a domain where denominator (z) does not vanish // inverse FFT is an interpolation @@ -209,9 +207,9 @@ impl PreparedProver { multiexp(&worker, params.get_h(a.len())?, FullDensity, a) }; - if verbose {eprintln!("{} seconds for prover for H evaluation (mostly FFT)", start.elapsed().as_millis() as f64 / 1000.0)}; + elog_verbose!("{} seconds for prover for H evaluation (mostly FFT)", stopwatch.elapsed()); - let start = std::time::Instant::now(); + let stopwatch = Stopwatch::new(); // TODO: Check that difference in operations for different chunks is small @@ -222,9 +220,8 @@ impl PreparedProver { let input_len = input_assignment.len(); let aux_len = aux_assignment.len(); - if verbose {eprintln!("H query is dense in G1,\nOther queries are {} elements in G1 and {} elements in G2", - 2*(input_len + aux_len) + aux_len, input_len + aux_len) - }; + elog_verbose!("H query is dense in G1,\nOther queries are {} elements in G1 and {} elements in G2", + 2*(input_len + aux_len) + aux_len, input_len + aux_len); // Run a dedicated process for dense vector let l = multiexp(&worker, params.get_l(aux_assignment.len())?, FullDensity, aux_assignment.clone()); @@ -287,7 +284,7 @@ impl PreparedProver { g_c.add_assign(&h.wait()?); g_c.add_assign(&l.wait()?); - if verbose {eprintln!("{} seconds for prover for point multiplication", start.elapsed().as_millis() as f64 / 1000.0)}; + elog_verbose!("{} seconds for prover for point multiplication", stopwatch.elapsed()); Ok(Proof { a: g_a.into_affine(), @@ -411,8 +408,6 @@ pub fn create_proof>( ) -> Result, SynthesisError> where E: Engine, C: Circuit { - let verbose = verbose_flag(); - let mut prover = ProvingAssignment { a_aux_density: DensityTracker::new(), b_input_density: DensityTracker::new(), @@ -440,13 +435,13 @@ pub fn create_proof>( let vk = params.get_vk(prover.input_assignment.len())?; - let start = std::time::Instant::now(); + let stopwatch = Stopwatch::new(); let h = { let mut a = EvaluationDomain::from_coeffs(prover.a)?; let mut b = EvaluationDomain::from_coeffs(prover.b)?; let mut c = EvaluationDomain::from_coeffs(prover.c)?; - if verbose {eprintln!("H query domain size is {}", a.as_ref().len())}; + elog_verbose!("H query domain size is {}", a.as_ref().len()); // here a coset is a domain where denominator (z) does not vanish // inverse FFT is an interpolation a.ifft(&worker); @@ -477,9 +472,9 @@ pub fn create_proof>( multiexp(&worker, params.get_h(a.len())?, FullDensity, a) }; - if verbose {eprintln!("{} seconds for prover for H evaluation (mostly FFT)", start.elapsed().as_millis() as f64 / 1000.0)}; + elog_verbose!("{} seconds for prover for H evaluation (mostly FFT)", stopwatch.elapsed()); - let start = std::time::Instant::now(); + let stopwatch = Stopwatch::new(); // TODO: Check that difference in operations for different chunks is small @@ -549,7 +544,7 @@ pub fn create_proof>( g_c.add_assign(&h.wait()?); g_c.add_assign(&l.wait()?); - if verbose {eprintln!("{} seconds for prover for point multiplication", start.elapsed().as_millis() as f64 / 1000.0)}; + elog_verbose!("{} seconds for prover for point multiplication", stopwatch.elapsed()); Ok(Proof { a: g_a.into_affine(), diff --git a/src/lib.rs b/src/lib.rs index 23ca127..5273763 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ #![allow(unused_imports)] +#![allow(unused_macros)] #[macro_use] extern crate cfg_if; @@ -7,6 +8,9 @@ extern crate rand; extern crate bit_vec; extern crate byteorder; +#[macro_use] +mod log; + pub mod domain; pub mod groth16; @@ -43,6 +47,7 @@ pub mod pairing { mod cs; pub use self::cs::*; +// todo move to log module after removing all references static mut VERBOSE_SWITCH: i8 = -1; use std::str::FromStr; diff --git a/src/log.rs b/src/log.rs new file mode 100644 index 0000000..da1ef7d --- /dev/null +++ b/src/log.rs @@ -0,0 +1,70 @@ +#[allow(unused_macros)] + +cfg_if! { + if #[cfg(feature = "wasm")] { + use web_sys; + use web_sys::Performance; + + macro_rules! log { + ($($t:tt)*) => (web_sys::console::log_1(&format_args!($($t)*).to_string().into())) + } + + macro_rules! elog { + ($($t:tt)*) => (web_sys::console::log_1(&format_args!($($t)*).to_string().into())) + } + + macro_rules! log_verbose { + ($($t:tt)*) => (if $crate::verbose_flag() { web_sys::console::log_1(&format_args!($($t)*).to_string().into()) }) + } + + macro_rules! elog_verbose { + ($($t:tt)*) => (if $crate::verbose_flag() { web_sys::console::log_1(&format_args!($($t)*).to_string().into()) }) + } + + pub struct Stopwatch { + start: f64, + perf: Performance + } + + impl Stopwatch { + pub fn new() -> Stopwatch { + let perf = web_sys::window().unwrap().performance().unwrap(); + Stopwatch { start: perf.now(), perf } + } + + pub fn elapsed(&self) -> f64 { + (self.perf.now() - self.start) / 1000.0 + } + } + } else { + macro_rules! log { + ($($t:tt)*) => (println!("{}", &format_args!($($t)*).to_string())) + } + + macro_rules! elog { + ($($t:tt)*) => (println!("{}", &format_args!($($t)*).to_string())) + } + + macro_rules! log_verbose { + ($($t:tt)*) => (if $crate::verbose_flag() { println!("{}", &format_args!($($t)*).to_string()) }) + } + + macro_rules! elog_verbose { + ($($t:tt)*) => (if $crate::verbose_flag() { println!("{}", &format_args!($($t)*).to_string()) }) + } + + pub struct Stopwatch { + start: std::time::Instant + } + + impl Stopwatch { + pub fn new() -> Stopwatch { + Stopwatch { start: std::time::Instant::now() } + } + + pub fn elapsed(&self) -> f64 { + self.start.elapsed().as_millis() as f64 / 1000.0 + } + } + } +} \ No newline at end of file From 4aad6f3fdfffeda6e395caa47ba277ce4e5cbdbd Mon Sep 17 00:00:00 2001 From: poma Date: Sun, 24 Mar 2019 09:29:07 +0300 Subject: [PATCH 3/5] Fix singlecore warning --- src/singlecore.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/singlecore.rs b/src/singlecore.rs index df73c80..816ceef 100644 --- a/src/singlecore.rs +++ b/src/singlecore.rs @@ -16,7 +16,7 @@ impl Worker { // We don't expose this outside the library so that // all `Worker` instances have the same number of // CPUs configured. - pub(crate) fn new_with_cpus(cpus: usize) -> Worker { + pub(crate) fn new_with_cpus(_cpus: usize) -> Worker { Worker { cpus: 1, } From afa9326c819c1fb80795a8a81c2431344c7640d1 Mon Sep 17 00:00:00 2001 From: poma Date: Sun, 24 Mar 2019 11:43:42 +0300 Subject: [PATCH 4/5] fix log macros --- src/log.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/log.rs b/src/log.rs index da1ef7d..b912a16 100644 --- a/src/log.rs +++ b/src/log.rs @@ -38,19 +38,19 @@ cfg_if! { } } else { macro_rules! log { - ($($t:tt)*) => (println!("{}", &format_args!($($t)*).to_string())) + ($($t:tt)*) => (println!($($t)*)) } macro_rules! elog { - ($($t:tt)*) => (println!("{}", &format_args!($($t)*).to_string())) + ($($t:tt)*) => (eprintln!($($t)*)) } macro_rules! log_verbose { - ($($t:tt)*) => (if $crate::verbose_flag() { println!("{}", &format_args!($($t)*).to_string()) }) + ($($t:tt)*) => (if $crate::verbose_flag() { println!($($t)*) }) } macro_rules! elog_verbose { - ($($t:tt)*) => (if $crate::verbose_flag() { println!("{}", &format_args!($($t)*).to_string()) }) + ($($t:tt)*) => (if $crate::verbose_flag() { eprintln!($($t)*) }) } pub struct Stopwatch { From 04a69f9e1d1c4e7930b263cb0c61beb00064d616 Mon Sep 17 00:00:00 2001 From: poma Date: Tue, 26 Mar 2019 10:20:20 +0300 Subject: [PATCH 5/5] add compile error --- src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 5273763..f730ec4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,6 +28,9 @@ mod tests; cfg_if! { if #[cfg(feature = "multicore")] { + #[cfg(feature = "wasm")] + compile_error!("Multicore feature is not yet compatible with wasm target arch"); + mod multicore; mod worker { pub use crate::multicore::*;