From cc21fd21beeae218e8d898467fdc4ac430a6b67c Mon Sep 17 00:00:00 2001 From: Guillaume Ballet Date: Thu, 3 Jan 2019 15:30:08 +0100 Subject: [PATCH] Add a repo to support the WASM version of partial_eq --- plugins/partialeq_wasm/.gitignore | 2 + plugins/partialeq_wasm/Cargo.lock | 152 +++++++++++++++++++ plugins/partialeq_wasm/Cargo.toml | 10 ++ plugins/partialeq_wasm/src/main.rs | 33 +++++ zokrates_core/Cargo.toml | 1 + zokrates_core/build.rs | 229 +++++++++++++++++++++++++++++ zokrates_core/src/helpers/mod.rs | 1 + zokrates_field/Cargo.toml | 1 - 8 files changed, 428 insertions(+), 1 deletion(-) create mode 100644 plugins/partialeq_wasm/.gitignore create mode 100644 plugins/partialeq_wasm/Cargo.lock create mode 100644 plugins/partialeq_wasm/Cargo.toml create mode 100644 plugins/partialeq_wasm/src/main.rs diff --git a/plugins/partialeq_wasm/.gitignore b/plugins/partialeq_wasm/.gitignore new file mode 100644 index 00000000..53eaa219 --- /dev/null +++ b/plugins/partialeq_wasm/.gitignore @@ -0,0 +1,2 @@ +/target +**/*.rs.bk diff --git a/plugins/partialeq_wasm/Cargo.lock b/plugins/partialeq_wasm/Cargo.lock new file mode 100644 index 00000000..790bd044 --- /dev/null +++ b/plugins/partialeq_wasm/Cargo.lock @@ -0,0 +1,152 @@ +[[package]] +name = "bincode" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "byteorder" +version = "1.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lazy_static" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "num" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-bigint" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-integer" +version = "0.1.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-iter" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "partialeq_wasm" +version = "0.1.0" +dependencies = [ + "lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "zokrates_field 0.3.0", +] + +[[package]] +name = "proc-macro2" +version = "0.4.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde_derive" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syn" +version = "0.15.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "zokrates_field" +version = "0.3.0" +dependencies = [ + "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "num-bigint 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[metadata] +"checksum bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e103c8b299b28a9c6990458b7013dc4a8356a9b854c51b9883241f5866fac36e" +"checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d" +"checksum lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "cf186d1a8aa5f5bee5fd662bc9c1b949e0259e1bcc379d1f006847b0080c7417" +"checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" +"checksum num-bigint 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "e63899ad0da84ce718c14936262a41cee2c79c981fc0a0e7c7beb47d5a07e8c1" +"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" +"checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124" +"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" +"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" +"checksum proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)" = "77619697826f31a02ae974457af0b29b723e5619e113e9397b8b82c6bd253f09" +"checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c" +"checksum serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)" = "6fa52f19aee12441d5ad11c9a00459122bd8f98707cadf9778c540674f1935b6" +"checksum serde_derive 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)" = "96a7f9496ac65a2db5929afa087b54f8fc5008dcfbe48a8874ed20049b0d6154" +"checksum syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)" = "9545a6a093a3f0bd59adb472700acc08cad3776f860f16a897dfce8c88721cbc" +"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" diff --git a/plugins/partialeq_wasm/Cargo.toml b/plugins/partialeq_wasm/Cargo.toml new file mode 100644 index 00000000..aef11b65 --- /dev/null +++ b/plugins/partialeq_wasm/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "partialeq_wasm" +version = "0.1.0" +authors = ["Guillaume Ballet "] +edition = "2018" + +[dependencies] +num = {version = "0.1.36", default-features = false} +lazy_static = "0.1.*" +zokrates_field = {version = "0.3", path = "../../zokrates_field" } \ No newline at end of file diff --git a/plugins/partialeq_wasm/src/main.rs b/plugins/partialeq_wasm/src/main.rs new file mode 100644 index 00000000..58b5b71b --- /dev/null +++ b/plugins/partialeq_wasm/src/main.rs @@ -0,0 +1,33 @@ +extern crate zokrates_field; +extern crate num; +use zokrates_field::field::{Field, FieldPrime}; +use num::{Zero, One}; + +static INPUT_BUFFER : [u8;32] = [0u8;32]; +static mut OUTPUT_BUFFER : [u8;64] = [0u8;64]; + +#[no_mangle] +pub extern "C" fn get_inputs_off() -> *const u8 { + return &INPUT_BUFFER as *const u8; +} + +#[no_mangle] +pub unsafe extern "C" fn solve() -> *const u8 { + // Transform the input bytes into output + let input = FieldPrime::from_byte_vector(Vec::from(&INPUT_BUFFER[..])); + + let (output0, output1) = if input.is_zero() { + (FieldPrime::zero(), FieldPrime::one()) + } else { + (FieldPrime::one(), FieldPrime::one() / input) + }; + + // Transform outputs back into bytes + &OUTPUT_BUFFER[..32].copy_from_slice(&output0.into_byte_vector()[..]); + &OUTPUT_BUFFER[32..].copy_from_slice(&output1.into_byte_vector()[..]); + + return &OUTPUT_BUFFER as *const u8; +} + +fn main() { +} diff --git a/zokrates_core/Cargo.toml b/zokrates_core/Cargo.toml index 0edc9277..1cf4c0ac 100644 --- a/zokrates_core/Cargo.toml +++ b/zokrates_core/Cargo.toml @@ -36,3 +36,4 @@ assert_cli = "0.5" [build-dependencies] cc = { version = "1.0", features = ["parallel"] } cmake = "0.1.31" +parity-wasm = "0.35.3" \ No newline at end of file diff --git a/zokrates_core/build.rs b/zokrates_core/build.rs index 31d1af06..76354484 100644 --- a/zokrates_core/build.rs +++ b/zokrates_core/build.rs @@ -60,4 +60,233 @@ fn main() { println!("cargo:rustc-link-lib=static=ff"); } } + + // #[cfg(feature = "wasm")] + { + extern crate parity_wasm; + + use std::env; + use std::path::Path; + use std::process::Command; + use std::io::prelude::*; + + fn has_symbol(symbol : &str, + exports : &[parity_wasm::elements::ExportEntry], funcs: &[parity_wasm::elements::Func], types: &[parity_wasm::elements::Type]) -> Result<(), String> { + match exports.iter().find(|ref export| export.field() == symbol) { + Some(export) => { + match export.internal() { + &parity_wasm::elements::Internal::Function(fidx) => { + let tidx = funcs[fidx as usize].type_ref(); + let parity_wasm::elements::Type::Function(t) = &types[tidx as usize]; + match t.return_type() { + Some(parity_wasm::elements::ValueType::I32) => {} + _ => return Err(format!("Invalid return type for `{}", symbol)) + } + let params = t.params(); + if params.len() != 0 { + Err(format!("Invalid number of parameters for `{}`", symbol)) + } else { + Ok(()) + } + } + _ => return Err(format!("Module has a `{}` export that is not a function", symbol)) + } + } + None => Err(format!("Module is missing a `{}` export", symbol)) + } + } + + fn validate>(input : U) -> Result { + let fname = input.into(); + + let module = parity_wasm::deserialize_file(fname.clone()) + .map_err(|e| e.to_string())?; + + let functions = module.function_section() + .ok_or("Module has no function section")? + .entries(); + let types = module.type_section() + .ok_or("Module has no function section")? + .types(); + let exports = module.export_section() + .ok_or("Module has no export section")? + .entries(); + + /* Look for `get_input_offs` */ + has_symbol("get_inputs_off", exports, functions, types)?; + + /* Look for `solve` */ + has_symbol("solve", exports, functions, types)?; + + Ok(module.clone()) + } + + fn add_global(symbol : &str, module : &parity_wasm::elements::Module, value : i32) -> Result { + let nglobals = module + .global_section() + .unwrap() + .entries() + .len(); + println!("Adding global at index {}", nglobals); + let nm = parity_wasm::builder::from_module(module.clone()) + .global() + .value_type().i32() + .init_expr(parity_wasm::elements::Instruction::I32Const(value)) + .build() + .export() + .field(symbol) + .internal() + .global(nglobals as u32) + .build() + .build(); + Ok(nm) + } + + fn add_global_if_missing(symbol : &str, module : &parity_wasm::elements::Module, expected_type : parity_wasm::elements::ValueType, value : i32, _force : bool) -> Result { + let global_section = module.global_section() + .ok_or("Could not get globals section")? + .entries() + .clone(); + let exports = module + .export_section() + .ok_or("Could not get exports section")? + .entries(); + + let mut found = false; + + if let Some(export) = exports.iter().find(|ref export| export.field() == symbol) { + found = true; + + // Export already exists, check its type and return it if said + // type is correct. + if let &parity_wasm::elements::Internal::Global(gidx) = export.internal() { + let global_type = global_section[gidx as usize] + .global_type(); + if !global_type.is_mutable() && expected_type == global_type.content_type() { + return Ok(module.clone()); + } + } + } + + /* overwrite only if asked with the -f switch */ + if !found { + add_global(symbol, module, value) + } else { + Err(format!("Symbol {} is already present with a different type in module", symbol)) + } + } + + /* Regenerate if files have changed */ + println!("cargo:rerun-if-changed=./plugins"); + + /* Build the WASM helpers and turn them into files */ + let status = Command::new("cargo") + .current_dir("../plugins/partialeq_wasm") + .args(&["build", "--target", "wasm32-unknown-unknown", "--release"]) + .status() + .unwrap(); + if !status.success() { + panic!("Error building WASM helpers"); + } + + /* Turn the output binary into a source file for zokrates_core */ + let fname = + "../plugins/partialeq_wasm/target/wasm32-unknown-unknown/release/partialeq_wasm.wasm"; + match validate(fname) { + Ok(module) => { + let out_dir = env::var("OUT_DIR").unwrap(); + let dest_path = Path::new(&out_dir).join("partialeq_wasm.rs"); + let m0 = module.clone(); + let m1 = add_global_if_missing( + "min_inputs", + &m0, + parity_wasm::elements::ValueType::I32, + 1, + false, + ) + .unwrap(); + let m2 = add_global_if_missing( + "min_outputs", + &m1, + parity_wasm::elements::ValueType::I32, + 2, + false, + ) + .unwrap(); + let m3 = add_global_if_missing( + "field_size", + &m2, + parity_wasm::elements::ValueType::I32, + 32, + false, + ) + .unwrap(); + let buf = parity_wasm::serialize(m3).unwrap(); + std::fs::File::create(dest_path) + .unwrap() + .write_all( + format!( + " + pub const PARTIALEQ_WASM : &'static [u8] = &{:?}; + ", + buf + ) + .as_bytes(), + ) + .unwrap(); + } + Err(e) => panic!(format!("Module validation error: {}", e.to_string())), + } + } +} } + + /* Turn the output binary into a source file for zokrates_core */ + let fname = + "../plugins/partialeq_wasm/target/wasm32-unknown-unknown/release/partialeq_wasm.wasm"; + match validate(fname) { + Ok(module) => { + let out_dir = env::var("OUT_DIR").unwrap(); + let dest_path = Path::new(&out_dir).join("partialeq_wasm.rs"); + let m0 = module.clone(); + let m1 = add_global_if_missing( + "min_inputs", + &m0, + parity_wasm::elements::ValueType::I32, + 1, + false, + ) + .unwrap(); + let m2 = add_global_if_missing( + "min_outputs", + &m1, + parity_wasm::elements::ValueType::I32, + 2, + false, + ) + .unwrap(); + let m3 = add_global_if_missing( + "field_size", + &m2, + parity_wasm::elements::ValueType::I32, + 32, + false, + ) + .unwrap(); + let buf = parity_wasm::serialize(m3).unwrap(); + std::fs::File::create(dest_path) + .unwrap() + .write_all( + format!( + " + pub const PARTIALEQ_WASM : &'static [u8] = &{:?}; + ", + buf + ) + .as_bytes(), + ) + .unwrap(); + } + Err(e) => panic!(format!("Module validation error: {}", e.to_string())), + } + } } diff --git a/zokrates_core/src/helpers/mod.rs b/zokrates_core/src/helpers/mod.rs index 50e9527b..4a8940f2 100644 --- a/zokrates_core/src/helpers/mod.rs +++ b/zokrates_core/src/helpers/mod.rs @@ -11,6 +11,7 @@ pub use self::wasm::WasmHelper; use flat_absy::{FlatExpression, FlatVariable}; use std::fmt; use zokrates_field::field::Field; +include!(concat!(env!("OUT_DIR"), "/partialeq_wasm.rs")); #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] pub struct DirectiveStatement { diff --git a/zokrates_field/Cargo.toml b/zokrates_field/Cargo.toml index 0f3f4db5..42829ddc 100644 --- a/zokrates_field/Cargo.toml +++ b/zokrates_field/Cargo.toml @@ -5,7 +5,6 @@ authors = ["Guillaume Ballet "] edition = "2018" [dependencies] - serde = "1.0" serde_derive = "1.0" lazy_static = "0.1.*"