diff --git a/Cargo.toml b/Cargo.toml index b97cbf9..2ff1eb8 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" } @@ -26,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" @@ -34,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 690219a..f730ec4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,16 @@ #![allow(unused_imports)] +#![allow(unused_macros)] +#[macro_use] +extern crate cfg_if; extern crate pairing as pairing_import; extern crate rand; extern crate bit_vec; extern crate byteorder; +#[macro_use] +mod log; + pub mod domain; pub mod groth16; @@ -20,18 +26,21 @@ mod multiexp; #[cfg(test)] mod tests; -#[cfg(feature = "multicore")] -mod multicore; +cfg_if! { + if #[cfg(feature = "multicore")] { + #[cfg(feature = "wasm")] + compile_error!("Multicore feature is not yet compatible with wasm target arch"); -#[cfg(feature = "singlecore")] -mod singlecore; - -mod worker { - #[cfg(feature = "multicore")] - pub use crate::multicore::*; - - #[cfg(feature = "singlecore")] - pub use crate::singlecore::*; + mod multicore; + mod worker { + pub use crate::multicore::*; + } + } else { + mod singlecore; + mod worker { + pub use crate::singlecore::*; + } + } } pub mod pairing { @@ -41,6 +50,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..b912a16 --- /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!($($t)*)) + } + + macro_rules! elog { + ($($t:tt)*) => (eprintln!($($t)*)) + } + + macro_rules! log_verbose { + ($($t:tt)*) => (if $crate::verbose_flag() { println!($($t)*) }) + } + + macro_rules! elog_verbose { + ($($t:tt)*) => (if $crate::verbose_flag() { eprintln!($($t)*) }) + } + + 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 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, }