WebAssembly compatibility

This commit is contained in:
poma 2020-01-13 13:10:00 +07:00
parent 9bdbe85480
commit 1fa63c9d3d
No known key found for this signature in database
GPG Key ID: BA20CB01FE165657
4 changed files with 115 additions and 11 deletions

@ -8,13 +8,13 @@ homepage = "https://github.com/ebfull/phase2"
license = "MIT/Apache-2.0"
repository = "https://github.com/ebfull/phase2"
[lib]
crate-type = ["cdylib", "lib"]
[dependencies]
rand = "0.4"
bellman_ce = { path = "../bellman" }
byteorder = "1"
exitcode = "1.1.2"
num_cpus = "1"
crossbeam = "0.3"
blake2-rfc = "0.2"
blake2 = "0.6.1"
serde = { version = "1.0", features = ["derive"] }
@ -22,5 +22,20 @@ serde_json = "1.0"
num-bigint = "0.2.3"
num-traits = "0.2.8"
itertools = "0.8.1"
rust-crypto = "0.2"
hex = "0.4.0"
cfg-if = "0.1.10"
bellman_ce = { path = "../bellman", default-features = false } # active features depend on build type
# needed for native only but don't break wasm if present
num_cpus = "1"
crossbeam = "0.3"
# needed for wasm only
wasm-bindgen = { version = "0.2.58", optional = true }
js-sys = { version = "0.3.35", optional = true }
web-sys = { version = "0.3.35", features = ["console"], optional = true }
console_error_panic_hook = { version = "0.1.6", optional = true }
[features]
default = ["bellman_ce/multicore"]
wasm = ["wasm-bindgen", "js-sys", "web-sys", "console_error_panic_hook", "bellman_ce/wasm"]

@ -2,6 +2,28 @@
This library is still under development.
## WebAssembly how-to
Build wasm package using `wasm-pack build --release -- --no-default-features --features wasm`
this will generate `./pkg` directory with wasm file and js bindings. After that you
can use this package in your browser application like so:
```js
async function main() {
const phase2 = await import("./pkg/phase2.js")
let data = await fetch('params')
data = await data.arrayBuffer()
data = new Uint8Array(data)
console.log('Source params', data)
const result = phase2.contribute(data)
console.log('Updated params', result)
// upload updated params
}
main().catch(console.error)
```
## [Documentation](https://docs.rs/phase2/)
## Security Warnings

@ -1,15 +1,15 @@
#![allow(unused_imports)]
#[macro_use]
extern crate serde;
extern crate bellman_ce;
extern crate rand;
extern crate byteorder;
extern crate blake2_rfc;
extern crate num_cpus;
extern crate crossbeam;
#[macro_use]
extern crate serde;
extern crate serde_json;
extern crate cfg_if;
use cfg_if::cfg_if;
pub mod keypair;
pub mod keypair_assembly;
@ -17,3 +17,45 @@ pub mod hash_writer;
pub mod parameters;
pub mod utils;
pub mod circom_circuit;
cfg_if! {
if #[cfg(feature = "wasm")] {
extern crate serde_json;
extern crate js_sys;
extern crate web_sys;
extern crate wasm_bindgen;
extern crate console_error_panic_hook;
extern crate itertools;
use wasm_bindgen::prelude::*;
use itertools::Itertools;
use parameters::MPCParameters;
use std::io::{
Read,
Write,
};
macro_rules! log {
($($t:tt)*) => (web_sys::console::log_1(&format_args!($($t)*).to_string().into()))
}
#[wasm_bindgen]
pub fn contribute(params: Vec<u8>) -> Result<Vec<u8>, JsValue> {
console_error_panic_hook::set_once();
let disallow_points_at_infinity = false;
log!("Initializing phase2");
let mut rng = &mut rand::XorShiftRng::new_unseeded(); // TODO: change this unsafe unseeded random (!)
let mut params = MPCParameters::read(&*params, disallow_points_at_infinity, true).expect("unable to read params");
log!("Contributing...");
let hash = params.contribute(&mut rng);
log!("Contribution hash: 0x{:02x}", hash.iter().format(""));
let mut output: Vec<u8> = vec![];
params.write(&mut output).expect("failed to write updated parameters");
log!("Returning parameters");
Ok(output)
}
}
}

@ -4,6 +4,11 @@ extern crate byteorder;
extern crate num_cpus;
extern crate crossbeam;
#[cfg(feature = "wasm")]
use bellman_ce::singlecore::Worker;
#[cfg(not(feature = "wasm"))]
use bellman_ce::multicore::Worker;
use byteorder::{
BigEndian,
ReadBytesExt,
@ -46,8 +51,6 @@ use bellman_ce::pairing::{
}
};
pub use bellman_ce::multicore::*;
use bellman_ce::{
Circuit,
SynthesisError,
@ -415,6 +418,7 @@ impl MPCParameters {
// Generate a keypair
let (pubkey, privkey) = keypair(rng, self);
#[cfg(not(feature = "wasm"))]
fn batch_exp<C: CurveAffine>(bases: &mut [C], coeff: C::Scalar) {
let coeff = coeff.into_repr();
@ -459,6 +463,27 @@ impl MPCParameters {
}
}
#[cfg(feature = "wasm")]
fn batch_exp<C: CurveAffine>(bases: &mut [C], coeff: C::Scalar) {
let coeff = coeff.into_repr();
let mut projective = vec![C::Projective::zero(); bases.len()];
// Perform wNAF, placing results into `projective`.
let mut wnaf = Wnaf::new();
for (base, projective) in bases.iter_mut().zip(projective.iter_mut()) {
*projective = wnaf.base(base.into_projective(), 1).scalar(coeff);
}
// Perform batch normalization
C::Projective::batch_normalization(&mut projective);
// Turn it all back into affine points
for (projective, affine) in projective.iter().zip(bases.iter_mut()) {
*affine = projective.into_affine();
}
}
let delta_inv = privkey.delta.inverse().expect("nonzero");
let mut l = (&self.params.l[..]).to_vec();
let mut h = (&self.params.h[..]).to_vec();