1
0
Fork 0
mirror of synced 2025-09-23 12:18:44 +00:00

Implement support for WASM helpers

This commit is contained in:
Guillaume Ballet 2018-12-04 15:42:35 +01:00
parent 78a8c33b72
commit 163f2b42f4
7 changed files with 463 additions and 12 deletions

51
Cargo.lock generated
View file

@ -273,6 +273,16 @@ name = "memoffset"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "memory_units"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "nan-preserving-float"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "nodrop"
version = "0.1.13"
@ -335,6 +345,22 @@ dependencies = [
"libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "parity-wasm"
version = "0.31.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "parity-wasm"
version = "0.35.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "proc-macro2"
version = "0.4.24"
@ -456,6 +482,11 @@ name = "rustc-demangle"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rustc-hex"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ryu"
version = "0.2.7"
@ -618,6 +649,17 @@ dependencies = [
"winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "wasmi"
version = "0.3.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)",
"memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"nan-preserving-float 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-wasm 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi"
version = "0.3.6"
@ -674,11 +716,14 @@ dependencies = [
"libc 0.2.46 (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)",
"parity-wasm 0.35.7 (registry+https://github.com/rust-lang/crates.io-index)",
"reduce 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmi 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"zokrates_field 0.3.0",
]
@ -735,6 +780,8 @@ version = "0.3.2"
"checksum libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)" = "023a4cd09b2ff695f9734c1934145a315594b7986398496841c7031a5a1bbdbd"
"checksum memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "db4c41318937f6e76648f42826b1d9ade5c09cafb5aef7e351240a70f39206e9"
"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
"checksum memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882"
"checksum nan-preserving-float 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34d4f00fcc2f4c9efa8cc971db0da9e28290e28e97af47585e48691ef10ff31f"
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
"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"
@ -743,6 +790,8 @@ version = "0.3.2"
"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 num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5a69d464bdc213aaaff628444e99578ede64e9c854025aa43b9796530afa9238"
"checksum parity-wasm 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)" = "511379a8194230c2395d2f5fa627a5a7e108a9f976656ce723ae68fca4097bfc"
"checksum parity-wasm 0.35.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3e1e076c4e01399b6cd0793a8df42f90bba3ae424671ef421d1608a943155d93"
"checksum proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)" = "77619697826f31a02ae974457af0b29b723e5619e113e9397b8b82c6bd253f09"
"checksum pulldown-cmark 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eef52fac62d0ea7b9b4dc7da092aa64ea7ec3d90af6679422d3d7e0e14b6ee15"
"checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c"
@ -758,6 +807,7 @@ version = "0.3.2"
"checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7"
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
"checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619"
"checksum rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0ceb8ce7a5e520de349e1fa172baeba4a9e8d5ef06c47471863530bc4972ee1e"
"checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7"
"checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267"
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
@ -780,6 +830,7 @@ version = "0.3.2"
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1"
"checksum wasmi 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b4a6d379e9332b1b1f52c5a87f2481c85c7c931d8ec411963dfb8f26b1ec1e3"
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "afc5508759c5bf4285e61feb862b6083c8480aec864fa17a81fdec6f69b461ab"

View file

@ -24,6 +24,9 @@ bincode = "0.8.0"
regex = "0.2"
bimap = "0.1"
zokrates_field = { version = "0.3.0", path = "../zokrates_field" }
wasmi = "0.3.0"
parity-wasm = "0.35.3"
rustc-hex = "1.0"
[dev-dependencies]
glob = "0.2.11"
@ -31,4 +34,4 @@ assert_cli = "0.5"
[build-dependencies]
cc = { version = "1.0", features = ["parallel"] }
cmake = "0.1.31"
cmake = "0.1.31"

View file

@ -1,10 +1,13 @@
#[cfg(feature = "libsnark")]
mod libsnark_gadget;
mod rust;
// #[cfg(feature = "wasm")]
mod wasm;
#[cfg(feature = "libsnark")]
pub use self::libsnark_gadget::LibsnarkGadgetHelper;
pub use self::rust::RustHelper;
pub use self::wasm::WasmHelper;
use flat_absy::{FlatExpression, FlatVariable};
use std::fmt;
use zokrates_field::field::Field;
@ -58,6 +61,8 @@ pub enum Helper {
#[cfg(feature = "libsnark")]
LibsnarkGadget(LibsnarkGadgetHelper),
Rust(RustHelper),
// #[cfg(feature = "wasm")]
Wasm(WasmHelper)
}
impl fmt::Display for Helper {
@ -66,6 +71,7 @@ impl fmt::Display for Helper {
#[cfg(feature = "libsnark")]
Helper::LibsnarkGadget(ref h) => write!(f, "LibsnarkGadget::{}", h),
Helper::Rust(ref h) => write!(f, "Rust::{}", h),
Helper::Wasm(ref h) => write!(f, "Wasm::{}", h),
}
}
}
@ -87,6 +93,7 @@ impl<T: Field> Executable<T> for Helper {
#[cfg(feature = "libsnark")]
Helper::LibsnarkGadget(helper) => helper.execute(inputs),
Helper::Rust(helper) => helper.execute(inputs),
Helper::Wasm(helper) => helper.execute(inputs)
};
match result {
@ -107,6 +114,7 @@ impl Signed for Helper {
#[cfg(feature = "libsnark")]
Helper::LibsnarkGadget(helper) => helper.get_signature(),
Helper::Rust(helper) => helper.get_signature(),
Helper::Wasm(helper) => helper.get_signature()
}
}
}

View file

@ -0,0 +1,385 @@
use std::fmt;
use std::fs::File;
use helpers::{Signed, Executable};
use field::Field;
use std::panic;
use wasmi::{Module, ModuleInstance, ImportsBuilder, NopExternals, ModuleRef};
use rustc_hex::FromHex;
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
pub enum WasmHelper {
File(String),
Code(String),
}
impl WasmHelper {
/* Hand-coded assembly for identity */
pub const IDENTITY_WASM : &'static str = "0061736d010000000105016000017f030302000005030100010615047f0041010b7f0041010b7f0041200b7f0141000b074b06066d656d6f727902000e6765745f696e707574735f6f6666000105736f6c766500000a6d696e5f696e7075747303000b6d696e5f6f75747075747303010a6669656c645f73697a6503020a2c0225000340412023036a410023036a280200360200230341016a240323032302470d000b41200b040041000b0b4b020041000b20ffffffff000000000000000000000000ffffffff0000000000000000000000000041200b20deadbeef000000000000000000000000deadbeef000000000000000000000000";
/* Generated from C code, normalized and cleaned up by hand */
pub const BITS_WASM : &'static str = "0061736d01000000010c026000017f60037f7f7f017f0304030000010405017001010105030100020626067f0141f0c7040b7f0041f0c7040b7f0041f0c7000b7f0041200b7f0041010b7f0041fe010b074b06066d656d6f727902000e6765745f696e707574735f6f6666000005736f6c766500010a6669656c645f73697a6503030a6d696e5f696e7075747303040b6d696e5f6f75747075747303050901000ad5030305004190080b4f01027f41b008210041b008410041c03f10021a4100210103402000410120014107717420014103764190086a2d0000714100473a0000200041206a2100200141016a220141fe01470d000b41b0080bfc0202037f017e02402002450d00200020013a0000200020026a2203417f6a20013a000020024103490d00200020013a0002200020013a00012003417d6a20013a00002003417e6a20013a000020024107490d00200020013a00032003417c6a20013a000020024109490d002000410020006b41037122046a2203200141ff017141818284086c22013602002003200220046b417c7122046a2202417c6a200136020020044109490d002003200136020820032001360204200241786a2001360200200241746a200136020020044119490d00200320013602102003200136020c2003200136021420032001360218200241686a2001360200200241646a20013602002002416c6a2001360200200241706a20013602002004200341047141187222056b22024120490d002001ad22064220862006842106200320056a2101034020012006370300200141086a2006370300200141106a2006370300200141186a2006370300200141206a2101200241606a2202411f4b0d000b0b20000b";
pub fn new_file<U: Into<String>>(u: U) -> Self {
WasmHelper::File(u.into())
}
pub fn new_code<U: Into<String>>(u: U) -> Self {
WasmHelper::Code(u.into())
}
}
impl fmt::Display for WasmHelper {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
WasmHelper::File(fname) => write!(f, "File(\"{}\")", fname),
WasmHelper::Code(hex_code) => write!(f, "Code(\"{}\")", hex_code)
}
}
}
fn load_from_file(filename: &str) -> Module {
use std::io::prelude::*;
let mut file = File::open(filename).unwrap();
let mut buf = Vec::new();
file.read_to_end(&mut buf).unwrap();
Module::from_buffer(buf).unwrap()
}
fn get_i32_export(varname: &str, modinst : &ModuleRef) -> Result<i32, String> {
let no = modinst.export_by_name(varname)
.ok_or(&format!("Could not find exported symbol `{}` in module", varname)[..])?
.as_global()
.ok_or(format!("Error getting {} from the list of globals", varname))?
.get()
.try_into::<i32>()
.ok_or(format!("Error converting `{}` to i32", varname))?;
return Ok(no);
}
impl Signed for WasmHelper {
fn get_signature(&self) -> (usize, usize) {
// Check that the module has the following exports:
// * min_inputs = the (minimum) number of inputs
// * min_outputs = the (minimum) number of outputs
let loaded_module = match self {
WasmHelper::File(fname) => load_from_file(&fname[..]),
WasmHelper::Code(code_hex) => {
let code = match FromHex::from_hex(&code_hex[..]) {
Ok(x) => x,
Err(e) => panic!("invalid bytecode: {}", e)
};
Module::from_buffer(&code).unwrap()
},
};
let modinst = ModuleInstance::new(&loaded_module, &ImportsBuilder::default())
.expect("Failed to instantiate module")
.assert_no_start();
let ni = get_i32_export("min_inputs", &modinst).unwrap();
let no = get_i32_export("min_outputs", &modinst).unwrap();
(ni as usize, no as usize)
}
}
impl<T: Field> Executable<T> for WasmHelper {
fn execute(&self, inputs: &Vec<T>) -> Result<Vec<T>, String> {
let loaded_module = match self {
WasmHelper::File(fname) => load_from_file(&fname[..]),
WasmHelper::Code(code_hex) => {
let code = FromHex::from_hex(&code_hex[..]).map_err(|e| e.to_string())?;
Module::from_buffer(&code).map_err(|e| e.to_string())?
},
};
let modinst = ModuleInstance::new(&loaded_module, &ImportsBuilder::default())
.map_err(|e| format!("Error creating module instance: {}", e.to_string()))?
.assert_no_start();
let field_size = get_i32_export("field_size", &modinst)? as usize;
let ninputs = get_i32_export("min_inputs", &modinst)? as usize;
if ninputs != inputs.len() {
return Err(format!("`solve` expected {} inputs, received {}", ninputs, inputs.len()));
}
/* Prepare the inputs */
let input_offset = modinst.invoke_export("get_inputs_off", &[], &mut NopExternals)
.map_err(|e| format!("Error getting the input offset: {}", e.to_string()))?
.ok_or("`get_inputs_off` did not return any value")?
.try_into::<i32>()
.ok_or("`get_inputs_off` returned the wrong type")?;
let mem = modinst.export_by_name("memory")
.ok_or("Module didn't export its memory section")?
.as_memory()
.unwrap()
.clone();
for (index, input) in inputs.iter().enumerate() {
// Get the field's bytes and check they correspond to
// the value that the module expects.
let mut bv = input.into_byte_vector();
if bv.len() > field_size {
return Err(format!("Input #{} is stored on {} bytes which is greater than the field size of {}", index, bv.len(), field_size));
} else {
bv.resize(field_size, 0);
}
let addr = (input_offset as u32)+(index as u32)*(field_size as u32);
mem.set(addr, &bv[..])
.map_err(|_e| format!("Could not write at memory address {}", addr))?;
}
let output_offset = modinst.invoke_export("solve", &[], &mut NopExternals)
.map_err(|e| format!("Error solving the problem: {}", e.to_string()))?
.ok_or("`solve` did not return any value")?
.try_into::<i32>()
.ok_or("`solve returned the wrong type`")?;
// NOTE: The question regarding the way that an error code is
// returned is still open.
//
// The current model considers that 2GB is more than enough
// to store the output data.
//
// This being said this approach is tacky and I am considering
// others at this point:
//
// 1. Use a 64 bit return code, values greater than 32-bits
// are considered error codes.
// 2. Export an extra global called `errno` which contains
// the error code.
// 3. 32-bit alignment gives a 2-bit error field
// 4. Return a pointer to a structure that contains
// the error code just before the output data.
//
// Experimenting with other languages will help decide what
// is the better approach.
if output_offset > 0 {
let mut outputs = Vec::new();
let noutputs = get_i32_export("min_outputs", &modinst)?;
for i in 0..noutputs {
let index = i as u32;
let fs = field_size as u32;
let value = mem.get(output_offset as u32 + fs * index, field_size)
.map_err(|e| format!("Could not retreive the output offset: {}", e))?;
outputs.push(T::from_byte_vector(value));
}
Ok(outputs)
} else {
Err(format!("`solve` returned error code {}", output_offset))
}
}
}
#[cfg(test)]
mod tests {
use field::FieldPrime;
use super::*;
#[test]
fn check_signatures() {
let h1 = WasmHelper::new_code(WasmHelper::IDENTITY_WASM);
assert_eq!(h1.get_signature(), (1, 1));
}
#[test]
fn check_signature_bytecode() {
let result = panic::catch_unwind(|| {
let x = WasmHelper::new_code("invalid bytecode");
x.get_signature();
});
assert!(result.is_err());
}
#[test]
fn check_signature_exports() {
/* Code is the same as identity, without the `min_inputs` export */
let result = panic::catch_unwind(|| {
let id = WasmHelper::new_code("0061736d010000000105016000017f030302000005030100010615047f0041010b7f0041010b7f0041200b7f0141000b073e05066d656d6f727902000e6765745f696e707574735f6f6666000105736f6c766500000b6d696e5f6f75747075747303010a6669656c645f73697a6503020a2c0225000340412023036a410023036a280200360200230341016a240323032302470d000b41200b040041000b0b4b020041000b20ffffffff000000000000000000000000ffffffff0000000000000000000000000041200b20deadbeef000000000000000000000000deadbeef000000000000000000000000");
id.get_signature();
});
assert!(result.is_err());
/* Code is the same as identity, without the `min_outputs` export */
let result = panic::catch_unwind(|| {
let id = WasmHelper::new_code("0061736d010000000105016000017f030302000005030100010615047f0041010b7f0041010b7f0041200b7f0141000b073d05066d656d6f727902000e6765745f696e707574735f6f6666000105736f6c766500000a6d696e5f696e7075747303000a6669656c645f73697a6503020a2c0225000340412023036a410023036a280200360200230341016a240323032302470d000b41200b040041000b0b4b020041000b20ffffffff000000000000000000000000ffffffff0000000000000000000000000041200b20deadbeef000000000000000000000000deadbeef000000000000000000000000");
id.get_signature();
});
assert!(result.is_err());
}
#[test]
fn check_invalid_bytecode_fails() {
let id = WasmHelper::new_code("invalid bytecode");
let input = vec![FieldPrime::from(1)];
let outputs = id.execute(&input);
assert_eq!(outputs, Err(String::from("Invalid character \'i\' at position 0")));
let id = WasmHelper::new_code(&WasmHelper::IDENTITY_WASM[..20]);
let input = vec![FieldPrime::from(1)];
let outputs = id.execute(&input);
assert_eq!(outputs, Err(String::from("Validation: I/O Error: UnexpectedEof")));
}
#[test]
fn validate_exports() {
/* Code is the same as identity, without the `solve` export */
let id = WasmHelper::new_code("0061736d010000000105016000017f030302000005030100010615047f0041010b7f0041010b7f0041200b7f0141000b074305066d656d6f727902000e6765745f696e707574735f6f666600010a6d696e5f696e7075747303000b6d696e5f6f75747075747303010a6669656c645f73697a6503020a2c0225000340412023036a410023036a280200360200230341016a240323032302470d000b41200b040041000b0b4b020041000b20ffffffff000000000000000000000000ffffffff0000000000000000000000000041200b20deadbeef000000000000000000000000deadbeef000000000000000000000000");
let input = vec![FieldPrime::from(1)];
let outputs = id.execute(&input);
assert_eq!(outputs, Err(String::from("Error solving the problem: Function: Module doesn\'t have export solve")));
/* Code is the same as identity, without the `get_inputs_off` export */
let id = WasmHelper::new_code("0061736d010000000105016000017f030302000005030100010615047f0041010b7f0041010b7f0041200b7f0141000b073a05066d656d6f7279020005736f6c766500000a6d696e5f696e7075747303000b6d696e5f6f75747075747303010a6669656c645f73697a6503020a2c0225000340412023036a410023036a280200360200230341016a240323032302470d000b41200b040041000b0b4b020041000b20ffffffff000000000000000000000000ffffffff0000000000000000000000000041200b20deadbeef000000000000000000000000deadbeef000000000000000000000000");
let input = vec![FieldPrime::from(1)];
let outputs = id.execute(&input);
assert_eq!(outputs, Err(String::from("Error getting the input offset: Function: Module doesn\'t have export get_inputs_off")));
/* Code is the same as identity, without the `min_inputs` export */
let id = WasmHelper::new_code("0061736d010000000105016000017f030302000005030100010615047f0041010b7f0041010b7f0041200b7f0141000b073e05066d656d6f727902000e6765745f696e707574735f6f6666000105736f6c766500000b6d696e5f6f75747075747303010a6669656c645f73697a6503020a2c0225000340412023036a410023036a280200360200230341016a240323032302470d000b41200b040041000b0b4b020041000b20ffffffff000000000000000000000000ffffffff0000000000000000000000000041200b20deadbeef000000000000000000000000deadbeef000000000000000000000000");
let input = vec![FieldPrime::from(1)];
let outputs = id.execute(&input);
assert_eq!(outputs, Err(String::from("Could not find exported symbol `min_inputs` in module")));
/* Code is the same as identity, without the `min_outputs` export */
let id = WasmHelper::new_code("0061736d010000000105016000017f030302000005030100010615047f0041010b7f0041010b7f0041200b7f0141000b073d05066d656d6f727902000e6765745f696e707574735f6f6666000105736f6c766500000a6d696e5f696e7075747303000a6669656c645f73697a6503020a2c0225000340412023036a410023036a280200360200230341016a240323032302470d000b41200b040041000b0b4b020041000b20ffffffff000000000000000000000000ffffffff0000000000000000000000000041200b20deadbeef000000000000000000000000deadbeef000000000000000000000000");
let input = vec![FieldPrime::from(1)];
let outputs = id.execute(&input);
assert_eq!(outputs, Err(String::from("Could not find exported symbol `min_outputs` in module")));
/* Code is the same as identity, without the `field_size` export */
let id = WasmHelper::new_code("0061736d010000000105016000017f030302000005030100010615047f0041010b7f0041010b7f0041200b7f0141000b073e05066d656d6f727902000e6765745f696e707574735f6f6666000105736f6c766500000a6d696e5f696e7075747303000b6d696e5f6f75747075747303010a2c0225000340412023036a410023036a280200360200230341016a240323032302470d000b41200b040041000b0b4b020041000b20ffffffff000000000000000000000000ffffffff0000000000000000000000000041200b20deadbeef000000000000000000000000deadbeef000000000000000000000000");
let input = vec![FieldPrime::from(1)];
let outputs = id.execute(&input);
assert_eq!(outputs, Err(String::from("Could not find exported symbol `field_size` in module")));
/* Code is the same as identity, without the `memory` export */
let id = WasmHelper::new_code("0061736d010000000105016000017f030302000005030100010615047f0041010b7f0041010b7f0041200b7f0141000b0742050e6765745f696e707574735f6f6666000105736f6c766500000a6d696e5f696e7075747303000b6d696e5f6f75747075747303010a6669656c645f73697a6503020a2c0225000340412023036a410023036a280200360200230341016a240323032302470d000b41200b040041000b0b4b020041000b20ffffffff000000000000000000000000ffffffff0000000000000000000000000041200b20deadbeef000000000000000000000000deadbeef000000000000000000000000");
let input = vec![FieldPrime::from(1)];
let outputs = id.execute(&input);
assert_eq!(outputs, Err(String::from("Module didn\'t export its memory section")));
}
#[test]
fn check_invalid_function_type() {
/* Code is the same as indentity, with a different function return type */
let id = WasmHelper::new_code("0061736d010000000105016000017e030302000005030100010615047f0041010b7f0041010b7f0041200b7f0141000b074b06066d656d6f727902000e6765745f696e707574735f6f6666000105736f6c766500000a6d696e5f696e7075747303000b6d696e5f6f75747075747303010a6669656c645f73697a6503020a2c0225000340412023036a410023036a280200360200230341016a240323032302470d000b42200b040042000b0b4b020041000b20ffffffff000000000000000000000000ffffffff0000000000000000000000000041200b20deadbeef000000000000000000000000deadbeef000000000000000000000000");
let input = vec![FieldPrime::from(1)];
let outputs = id.execute(&input);
assert_eq!(outputs, Err(String::from("`get_inputs_off` returned the wrong type")));
/* Code is the same as indentity, with no return type for function */
let id = WasmHelper::new_code("0061736d010000000108026000017f600000030302000105030100010615047f0041010b7f0041010b7f0041200b7f0141000b074b06066d656d6f727902000e6765745f696e707574735f6f6666000105736f6c766500000a6d696e5f696e7075747303000b6d696e5f6f75747075747303010a6669656c645f73697a6503020a2b0225000340412023036a410023036a280200360200230341016a240323032302470d000b41200b0300010b0b4b020041000b20ffffffff000000000000000000000000ffffffff0000000000000000000000000041200b20deadbeef000000000000000000000000deadbeef000000000000000000000000");
let input = vec![FieldPrime::from(1)];
let outputs = id.execute(&input);
assert_eq!(outputs, Err(String::from("`get_inputs_off` did not return any value")));
/* Code is the same as indentity, with extra parameter for function */
let id = WasmHelper::new_code("0061736d010000000109026000017f60017f00030302000105030100010615047f0041010b7f0041010b7f0041200b7f0141000b074b06066d656d6f727902000e6765745f696e707574735f6f6666000105736f6c766500000a6d696e5f696e7075747303000b6d696e5f6f75747075747303010a6669656c645f73697a6503020a2b0225000340412023036a410023036a280200360200230341016a240323032302470d000b41200b0300010b0b4b020041000b20ffffffff000000000000000000000000ffffffff0000000000000000000000000041200b20deadbeef000000000000000000000000deadbeef000000000000000000000000");
let input = vec![FieldPrime::from(1)];
let outputs = id.execute(&input);
assert_eq!(outputs, Err(String::from("Error getting the input offset: Function: not enough arguments, given 0 but expected: 1")));
}
#[test]
fn check_invalid_field_size() {
/* Code is the same as indentity, with 1-byte filed size */
let id = WasmHelper::new_code("0061736d010000000105016000017f030302000005030100010615047f0041010b7f0041010b7f0041010b7f0141000b074b06066d656d6f727902000e6765745f696e707574735f6f6666000105736f6c766500000a6d696e5f696e7075747303000b6d696e5f6f75747075747303010a6669656c645f73697a6503020a2c0225000340412023036a410023036a280200360200230341016a240323032302470d000b41200b040041000b0b4b020041000b20ffffffff000000000000000000000000ffffffff0000000000000000000000000041200b20deadbeef000000000000000000000000deadbeef000000000000000000000000");
let input = vec![FieldPrime::from(65536)];
let outputs = id.execute(&input);
assert_eq!(outputs, Err(String::from("Input #0 is stored on 3 bytes which is greater than the field size of 1")));
/* Code is the same as identity, tweaked so that field_size is a f32 */
let id = WasmHelper::new_code("0061736d010000000105016000017f030302000005030100010618047f0041010b7f0041010b7d0043000000000b7f0141000b074b06066d656d6f727902000e6765745f696e707574735f6f6666000105736f6c766500000a6d696e5f696e7075747303000b6d696e5f6f75747075747303010a6669656c645f73697a6503020a2f0228000340412023036a410023036a280200360200230341016a2403430000000023025c0d000b41200b040041000b0b4b020041000b20ffffffff000000000000000000000000ffffffff0000000000000000000000000041200b20deadbeef000000000000000000000000deadbeef000000000000000000000000");
let input = vec![FieldPrime::from(65536)];
let outputs = id.execute(&input);
assert_eq!(outputs, Err(String::from("Error converting `field_size` to i32")));
}
#[test]
fn check_identity() {
let id = WasmHelper::new_code(WasmHelper::IDENTITY_WASM);
let input = vec![FieldPrime::from(1)];
let outputs = id.execute(&input).expect("Identity call failed");
assert_eq!(outputs, input);
let id = WasmHelper::new_code(WasmHelper::IDENTITY_WASM);
let input = vec![FieldPrime::from(0)];
let outputs = id.execute(&input).expect("Identity call failed");
assert_eq!(outputs, input);
}
#[test]
fn check_identity_3_bytes() {
let id = WasmHelper::new_code(WasmHelper::IDENTITY_WASM);
let input = vec![FieldPrime::from(16777216)];
let outputs = id.execute(&input).expect("Identity call failed");
assert_eq!(outputs, input);
}
#[test]
fn check_invalid_arg_number() {
let id = WasmHelper::new_code(WasmHelper::IDENTITY_WASM);
let input = vec![FieldPrime::from(1)];
let outputs = id.execute(&input).expect("Identity call failed");
assert_eq!(outputs, input);
}
#[test]
fn check_memory_boundaries() {
/* Check that input writes are boundary-checked */
let id = WasmHelper::new_code("0061736d010000000105016000017f030302000005030100010615047f0041010b7f0041010b7f0041200b7f0141000b074b06066d656d6f727902000e6765745f696e707574735f6f6666000105736f6c766500000a6d696e5f696e7075747303000b6d696e5f6f75747075747303010a6669656c645f73697a6503020a2e0225000340412023036a410023036a280200360200230341016a240323032302470d000b41200b0600418080040b0b4b020041000b20ffffffff000000000000000000000000ffffffff0000000000000000000000000041200b20deadbeef000000000000000000000000deadbeef000000000000000000000000");
let input = vec![FieldPrime::from(65536)];
let outputs = id.execute(&input);
assert_eq!(outputs, Err(String::from("Could not write at memory address 65536")));
/* Check that output writes are boundary-checked */
let id = WasmHelper::new_code("0061736d010000000105016000017f030302000005030100010615047f0041010b7f0041010b7f0041200b7f0141000b074b06066d656d6f727902000e6765745f696e707574735f6f6666000105736f6c766500000a6d696e5f696e7075747303000b6d696e5f6f75747075747303010a6669656c645f73697a6503020a2e0227000340412023036a410023036a280200360200230341016a240323032302470d000b418080040b040041000b0b4b020041000b20ffffffff000000000000000000000000ffffffff0000000000000000000000000041200b20deadbeef000000000000000000000000deadbeef000000000000000000000000");
let input = vec![FieldPrime::from(65536)];
let outputs = id.execute(&input);
assert_eq!(outputs, Err(String::from("Could not retreive the output offset: Memory: trying to access region [65536..65568] in memory [0..65536]")));
}
#[test]
fn check_negative_output_value() {
let id = WasmHelper::new_code("0061736d010000000105016000017f030302000005030100010615047f0041010b7f0041010b7f0041200b7f0141000b074b06066d656d6f727902000e6765745f696e707574735f6f6666000105736f6c766500000a6d696e5f696e7075747303000b6d696e5f6f75747075747303010a6669656c645f73697a6503020a2c0225000340412023036a410023036a280200360200230341016a240323032302470d000b417f0b040041000b0b4b020041000b20ffffffff000000000000000000000000ffffffff0000000000000000000000000041200b20deadbeef000000000000000000000000deadbeef000000000000000000000000");
let input = vec![FieldPrime::from(1)];
let outputs = id.execute(&input);
assert_eq!(outputs, Err(String::from("`solve` returned error code -1")));
}
#[test]
fn check_file_exists() {
let result = panic::catch_unwind(|| {
let noname = WasmHelper::new_file("noname.wasm");
let input = vec![FieldPrime::from(7 /* Lucky number, maybe it'll work? ;) */)];
let _outputs = noname.execute(&input).unwrap();
});
/* Nope :( */
assert!(result.is_err());
}
#[test]
fn check_bits() {
let bits = WasmHelper::new_code(WasmHelper::BITS_WASM);
let input = vec![FieldPrime::from(0xdeadbeef as u32)];
let outputs = bits.execute(&input).unwrap();
assert_eq!(254, outputs.len());
for i in 0..32 {
let bitval = (0xdeadbeef as i64 >> i) & 1;
assert_eq!(outputs[i as usize], FieldPrime::from(bitval as i32));
}
for i in 32..254 {
assert_eq!(outputs[i as usize], FieldPrime::from(0));
}
}
}

View file

@ -45,17 +45,17 @@ impl Error {
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.message)
}
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.message)
}
}
impl From<io::Error> for Error {
fn from(error: io::Error) -> Self {
Error {
message: format!("I/O Error: {:?}", error),
}
}
fn from(error: io::Error) -> Self {
Error {
message: format!("I/O Error: {:?}", error)
}
}
}
#[derive(PartialEq, Clone, Serialize, Deserialize)]

View file

@ -10,6 +10,9 @@ extern crate serde_derive;
extern crate bimap;
extern crate bincode;
extern crate regex;
extern crate parity_wasm;
extern crate wasmi;
extern crate rustc_hex;
extern crate zokrates_field;
mod flatten;

View file

@ -1,8 +1,9 @@
use bimap::BiMap;
use types::Type;
use flat_absy::flat_parameter::FlatParameter;
use flat_absy::flat_variable::FlatVariable;
use flat_absy::*;
use helpers::{DirectiveStatement, Helper, RustHelper};
use helpers::{Helper, RustHelper, DirectiveStatement, WasmHelper};
use reduce::Reduce;
use types::constraints::Constraint;
use types::signature::Signature;
@ -313,7 +314,7 @@ mod tests {
f2b.statements[0],
FlatStatement::Directive(DirectiveStatement::new(
vec![FlatVariable::new(1)],
Helper::Rust(RustHelper::Identity),
Helper::Wasm(WasmHelper::from_hex(WasmHelper::IDENTITY_WASM)),
vec![FlatVariable::new(0)]
))
);
@ -339,7 +340,7 @@ mod tests {
b2f.statements[0],
FlatStatement::Directive(DirectiveStatement::new(
vec![FlatVariable::new(1)],
Helper::Rust(RustHelper::Identity),
Helper::Wasm(WasmHelper::from_hex(WasmHelper::IDENTITY_WASM)),
vec![FlatVariable::new(0)]
))
);