Merge pull request #8 from poma/wasm

WASM compatibility
This commit is contained in:
Alexander 2019-03-31 16:34:46 +03:00 committed by GitHub
commit 219929ee33
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 125 additions and 51 deletions

@ -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"]

@ -1,4 +1,4 @@
use super::super::verbose_flag;
use crate::log::Stopwatch;
use rand::Rng;
@ -187,8 +187,6 @@ pub fn generate_parameters<E, C>(
) -> Result<Parameters<E>, SynthesisError>
where E: Engine, C: Circuit<E>
{
let verbose = verbose_flag();
let mut assembly = KeypairAssembly {
num_inputs: 0,
num_aux: 0,
@ -217,7 +215,7 @@ pub fn generate_parameters<E, C>(
);
}
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>(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<E, C>(
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<E, C>(
}
});
}
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<E, C>(
});
}
});
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<E: Engine>(
// wNAF window tables
@ -475,7 +472,7 @@ pub fn generate_parameters<E, C>(
&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<E, C>(
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,

@ -1,4 +1,4 @@
use super::super::verbose_flag;
use crate::log::Stopwatch;
use rand::Rng;
@ -164,20 +164,18 @@ impl<E:Engine> PreparedProver<E> {
s: E::Fr
) -> Result<Proof<E>, 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<E:Engine> PreparedProver<E> {
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<E:Engine> PreparedProver<E> {
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<E:Engine> PreparedProver<E> {
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<E, C, P: ParameterSource<E>>(
) -> Result<Proof<E>, SynthesisError>
where E: Engine, C: Circuit<E>
{
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<E, C, P: ParameterSource<E>>(
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<E, C, P: ParameterSource<E>>(
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<E, C, P: ParameterSource<E>>(
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(),

@ -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;

70
src/log.rs Normal file

@ -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
}
}
}
}

@ -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,
}