From 703fe282c134f4db149d54e61b3001b2f1eed12a Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Wed, 23 Mar 2022 21:33:36 -0700 Subject: [PATCH 1/4] Construct module directly from bytes --- Cargo.toml | 4 ++-- src/circuit.rs | 21 +++++++++------------ 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 44dac89..4706a4b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ required-features = [ "bench", "proptest" ] [dependencies] ark-bn254 = { version = "0.3.0" } -ark-circom = { git = "https://github.com/gakonst/ark-circom", features=["circom-2"] } +ark-circom = { git = "https://github.com/gakonst/ark-circom", rev="a93c8b0", features=["circom-2"] } ark-ec = { version = "0.3.0", default-features = false, features = ["parallel"] } ark-ff = { version = "0.3.0", default-features = false, features = ["parallel", "asm"] } ark-groth16 = { git = "https://github.com/arkworks-rs/groth16", rev = "765817f", features = ["parallel"] } @@ -46,9 +46,9 @@ rand = "0.8.4" rayon = "1.5.1" serde = "1.0" sha2 = "0.10.1" -tempfile = "3.3.0" thiserror = "1.0.0" tiny-keccak = { version = "2.0.2" } +wasmer = "2.0" zkp-u256 = { version = "0.2", optional = true } # TODO: Remove # Use the same `ethers-core` version as ark-circom diff --git a/src/circuit.rs b/src/circuit.rs index 455c49f..94e04d3 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -4,11 +4,8 @@ use ark_groth16::ProvingKey; use ark_relations::r1cs::ConstraintMatrices; use core::include_bytes; use once_cell::sync::Lazy; -use std::{ - io::{Cursor, Write}, - sync::Mutex, -}; -use tempfile::NamedTempFile; +use std::{io::Cursor, sync::Mutex}; +use wasmer::{Module, Store}; const ZKEY_BYTES: &[u8] = include_bytes!("../semaphore/build/snark/semaphore_final.zkey"); const WASM: &[u8] = include_bytes!("../semaphore/build/snark/semaphore.wasm"); @@ -19,12 +16,12 @@ pub static ZKEY: Lazy<(ProvingKey, ConstraintMatrices)> = Lazy::new(| }); pub static WITNESS_CALCULATOR: Lazy> = Lazy::new(|| { - // HACK: ark-circom requires a file, so we make one! - let mut tmpfile = NamedTempFile::new().expect("Failed to create temp file"); - let written = tmpfile.write(WASM).expect("Failed to write to temp file"); - assert_eq!(written, WASM.len()); - let path = tmpfile.into_temp_path(); - let result = WitnessCalculator::new(&path).expect("Failed to create witness calculator"); - path.close().expect("Could not remove tempfile"); + // Create Wasm module + let store = Store::default(); + let module = Module::from_binary(&store, WASM).expect("wasm should be valid"); + + // Create witness calculator + let result = + WitnessCalculator::from_module(module).expect("Failed to create witness calculator"); Mutex::new(result) }); From b84941f767264fb084884c0be8ba85a9cc969d05 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Wed, 23 Mar 2022 21:50:39 -0700 Subject: [PATCH 2/4] Add dylib support with compile time env path --- Cargo.toml | 5 +---- src/circuit.rs | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4706a4b..0d30c9f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,7 +48,7 @@ serde = "1.0" sha2 = "0.10.1" thiserror = "1.0.0" tiny-keccak = { version = "2.0.2" } -wasmer = "2.0" +wasmer = { version = "2.0", features = [ "dylib" ] } zkp-u256 = { version = "0.2", optional = true } # TODO: Remove # Use the same `ethers-core` version as ark-circom @@ -64,9 +64,6 @@ tempfile = "3.0" tiny-keccak = "2.0.2" tracing-test = "0.2" -# [patch.crates-io] -# wasmer = { git = 'https://github.com/philsippl/wasmer', rev = "e776616"} - [profile.release] codegen-units = 1 lto = true diff --git a/src/circuit.rs b/src/circuit.rs index 94e04d3..b83a9e5 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -5,9 +5,10 @@ use ark_relations::r1cs::ConstraintMatrices; use core::include_bytes; use once_cell::sync::Lazy; use std::{io::Cursor, sync::Mutex}; -use wasmer::{Module, Store}; +use wasmer::{Dylib, Module, Store}; const ZKEY_BYTES: &[u8] = include_bytes!("../semaphore/build/snark/semaphore_final.zkey"); + const WASM: &[u8] = include_bytes!("../semaphore/build/snark/semaphore.wasm"); pub static ZKEY: Lazy<(ProvingKey, ConstraintMatrices)> = Lazy::new(|| { @@ -17,8 +18,16 @@ pub static ZKEY: Lazy<(ProvingKey, ConstraintMatrices)> = Lazy::new(| pub static WITNESS_CALCULATOR: Lazy> = Lazy::new(|| { // Create Wasm module - let store = Store::default(); - let module = Module::from_binary(&store, WASM).expect("wasm should be valid"); + let module = if let Some(path) = option_env!("CIRCUIT_WASM_DYLIB") { + let store = Store::new(&Dylib::headless().engine()); + // The module must be exported using [`Module::serialize`]. + unsafe { + Module::deserialize_from_file(&store, path).expect("Failed to load wasm dylib module") + } + } else { + let store = Store::default(); + Module::from_binary(&store, WASM).expect("wasm should be valid") + }; // Create witness calculator let result = From 56719b11cd1de24be379475243fd40a94d3b02fb Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Wed, 23 Mar 2022 22:05:30 -0700 Subject: [PATCH 3/4] Dylib compiler example --- Cargo.toml | 3 +++ examples/dylib.rs | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 examples/dylib.rs diff --git a/Cargo.toml b/Cargo.toml index 0d30c9f..f869ff1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -64,6 +64,9 @@ tempfile = "3.0" tiny-keccak = "2.0.2" tracing-test = "0.2" +wasmer-engine-dylib = "2.2.1" +wasmer-compiler-cranelift = "2.2.1" + [profile.release] codegen-units = 1 lto = true diff --git a/examples/dylib.rs b/examples/dylib.rs new file mode 100644 index 0000000..39fb607 --- /dev/null +++ b/examples/dylib.rs @@ -0,0 +1,40 @@ +use wasmer::{Module, Store}; +use wasmer_compiler_cranelift::Cranelift; +use wasmer_engine_dylib::Dylib; + +const PATH: &str = "../semaphore/build/snark/semaphore.wasm"; + +fn main() -> Result<(), Box> { + // Define a compiler configuration. + // + // In this situation, the compiler is + // `wasmer_compiler_cranelift`. The compiler is responsible to + // compile the Wasm module into executable code. + let compiler_config = Cranelift::default(); + + println!("Creating Dylib engine..."); + // Define the engine that will drive everything. + // + // In this case, the engine is `wasmer_engine_dylib` which means + // that a shared object is going to be generated. + let engine = Dylib::new(compiler_config).engine(); + + // Create a store, that holds the engine. + let store = Store::new(&engine); + + println!("Compiling module..."); + // Here we go. + // + // Let's compile the Wasm module. It is at this step that the Wasm + // text is transformed into Wasm bytes (if necessary), and then + // compiled to executable code by the compiler, which is then + // stored into a shared object by the engine. + let module = Module::from_file(&store, "../semaphore/build/snark/semaphore.wasm")?; + + println!("Storing as \"{}\"", PATH); + module.serialize_to_file(PATH)?; + + println!("Done! you can now compile with CIRCUIT_WASM_DYLIB=\"{}\"", PATH); + + Ok(()) +} From 23ea7447e4f92738d6d043e4c592775099cdb8ac Mon Sep 17 00:00:00 2001 From: psippl Date: Thu, 24 Mar 2022 13:42:46 +0100 Subject: [PATCH 4/4] script to build dylib for given target --- examples/dylib_ios.rs | 63 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 examples/dylib_ios.rs diff --git a/examples/dylib_ios.rs b/examples/dylib_ios.rs new file mode 100644 index 0000000..c6ff09f --- /dev/null +++ b/examples/dylib_ios.rs @@ -0,0 +1,63 @@ +//! This builds the wasm file into a dylib for a given target platform. +//! +//! ```shell +//! cargo run --example dylib_ios aarch64-apple-ios semaphore/build/snark/semaphore.wasm semaphore/build/snark/semaphore.dylib +//! ``` +//! +//! Ready? + + +use std::{str::FromStr}; + +use wasmer::{Module, Store, Triple, RuntimeError, CpuFeature, Target}; +use wasmer_compiler_cranelift::Cranelift; +use wasmer_engine_dylib::Dylib; + +fn main() -> Result<(), Box> { + + // to build for ios: aarch64-apple-ios, aarch64-apple-ios-sim, x86_64-apple-ios + let target_os = std::env::args().nth(1).expect("no target given"); + let wasm_path = std::env::args().nth(2).expect("no wasm path given"); + let dylib_path = std::env::args().nth(3).expect("no dylib path given"); + + // Define a compiler configuration. + // + // In this situation, the compiler is + // `wasmer_compiler_cranelift`. The compiler is responsible to + // compile the Wasm module into executable code. + let compiler_config = Cranelift::default(); + + let triple = Triple::from_str(&target_os) + .map_err(|error| RuntimeError::new(error.to_string()))?; + + // Let's build the target. + let mut cpu_feature = CpuFeature::set(); + cpu_feature.insert(CpuFeature::from_str("sse2")?); + let target = Target::new(triple, cpu_feature); + println!("Chosen target: {:?}", target); + + println!("Creating Dylib engine..."); + // Define the engine that will drive everything. + // + // In this case, the engine is `wasmer_engine_dylib` which means + // that a shared object is going to be generated. + let engine = Dylib::new(compiler_config).target(target).engine(); + + // Create a store, that holds the engine. + let store = Store::new(&engine); + + println!("Compiling module..."); + // Here we go. + // + // Let's compile the Wasm module. It is at this step that the Wasm + // text is transformed into Wasm bytes (if necessary), and then + // compiled to executable code by the compiler, which is then + // stored into a shared object by the engine. + let module = Module::from_file(&store, &wasm_path)?; + + module.serialize_to_file(&dylib_path)?; + + println!("Done! you can now compile with CIRCUIT_WASM_DYLIB=\"{}\"", &dylib_path); + + Ok(()) +}