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

resolve lock conflict...

This commit is contained in:
schaeff 2019-01-21 13:59:47 +01:00
commit dc554fc036
14 changed files with 718 additions and 23 deletions

View file

@ -18,6 +18,9 @@ jobs:
- run:
name: Check format
command: rustup component add rustfmt-preview; cargo fmt --all -- --check
- run:
name: Download wasm32 target
command: rustup target add wasm32-unknown-unknown
- run:
name: Build libsnark
command: LIBSNARK_SOURCE_PATH=$HOME/libsnark ./build_libsnark.sh
@ -27,6 +30,9 @@ jobs:
- run:
name: Run tests
command: WITH_LIBSNARK=1 LIBSNARK_SOURCE_PATH=$HOME/libsnark RUSTFLAGS="-D warnings" cargo test --release -- --test-threads=1
- run:
name: Run tests with WASM enabled
command: cd zokrates_core && cargo test --release --features wasm -- --test-threads=1
- run:
name: Run integration tests
command: WITH_LIBSNARK=1 LIBSNARK_SOURCE_PATH=$HOME/libsnark RUSTFLAGS="-D warnings" cargo test --release -- --ignored

54
Cargo.lock generated
View file

@ -272,6 +272,11 @@ 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 = "nodrop"
version = "0.1.13"
@ -344,6 +349,22 @@ dependencies = [
"libc 0.2.47 (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.3.0 (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.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "proc-macro2"
version = "0.4.26"
@ -465,6 +486,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"
@ -502,6 +528,14 @@ name = "serde"
version = "1.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde_bytes"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_derive"
version = "1.0.85"
@ -622,6 +656,16 @@ dependencies = [
"winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "wasmi"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"memory_units 0.3.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"
@ -678,11 +722,15 @@ dependencies = [
"libc 0.2.47 (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.85 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmi 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"zokrates_field 0.3.1",
]
@ -741,6 +789,7 @@ version = "0.3.2"
"checksum libc 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)" = "48450664a984b25d5b479554c29cc04e3150c97aa4c01da5604a2d4ed9151476"
"checksum memchr 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e1dd4eaac298c32ce07eb6ed9242eda7d82955b9170b7d6db59b2e02cc63fcb8"
"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 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"
@ -750,6 +799,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.26 (registry+https://github.com/rust-lang/crates.io-index)" = "38fddd23d98b2144d197c0eca5705632d4fe2667d14a6be5df8934f8d74f1978"
"checksum pulldown-cmark 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eef52fac62d0ea7b9b4dc7da092aa64ea7ec3d90af6679422d3d7e0e14b6ee15"
"checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1"
@ -765,12 +816,14 @@ 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"
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)" = "534b8b91a95e0f71bca3ed5824752d558da048d4248c91af873b63bd60519752"
"checksum serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)" = "adb6e51a6b3696b301bc221d785f898b4457c619b51d7ce195a6d20baecb37b3"
"checksum serde_derive 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)" = "a915306b0f1ac5607797697148c223bedeaa36bcc2e28a01441cd638cc6567b4"
"checksum serde_json 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)" = "574378d957d6dcdf1bbb5d562a15cbd5e644159432f84634b94e485267abbcc7"
"checksum skeptic 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6fb8ed853fdc19ce09752d63f3a2e5b5158aeb261520cd75eb618bd60305165"
@ -786,6 +839,7 @@ version = "0.3.2"
"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737"
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1"
"checksum wasmi 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21ef487a11df1ed468cf613c78798c26282da5c30e9d49f824872d4c77b47d1d"
"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

@ -0,0 +1,9 @@
[package]
name = "zokrates_wasm_plugin"
version = "0.1.0"
authors = ["Guillaume Ballet <gballet@gmail.com>"]
edition = "2018"
[dependencies]
parity-wasm = "0.35.3"
clap = "2.32.0"

View file

@ -30,7 +30,7 @@ First, create the text-file `root.code` and implement your program. In this exam
```zokrates
def main(private field a, field b) -> (field):
field result = if a * a == b then 1 else 0
field result = if a * a == b then 1 else 0 fi
return result
```
@ -53,4 +53,4 @@ Then run the different phases of the protocol:
./zokrates export-verifier
```
The CLI commands are explained in more detail in the [CLI reference](reference/cli.html).
The CLI commands are explained in more detail in the [CLI reference](reference/cli.html).

View file

@ -649,6 +649,7 @@ mod tests {
}
#[test]
#[should_panic]
fn examples_with_input_failure() {
//these examples should compile but not run
for p in glob("./examples/runtime_errors/*.code").expect("Failed to read glob pattern") {
@ -675,12 +676,9 @@ mod tests {
let (..) = r1cs_program(program_flattened.clone());
let result = std::panic::catch_unwind(|| {
let _ = program_flattened
.execute(&vec![FieldPrime::from(0)])
.unwrap();
});
assert!(result.is_err());
let _ = program_flattened
.execute(&vec![FieldPrime::from(0)])
.unwrap();
}
}
}

View file

@ -9,6 +9,7 @@ build = "build.rs"
[features]
default = []
libsnark = []
wasm = []
[dependencies]
libc = "0.2.0"
@ -20,10 +21,14 @@ reduce = "0.1.1"
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
serde_bytes = "0.10"
bincode = "0.8.0"
regex = "0.2"
bimap = "0.1"
zokrates_field = { version = "0.3.0", path = "../zokrates_field" }
wasmi = "0.4.2"
parity-wasm = "0.35.3"
rustc-hex = "1.0"
[dev-dependencies]
glob = "0.2.11"
@ -31,4 +36,5 @@ assert_cli = "0.5"
[build-dependencies]
cc = { version = "1.0", features = ["parallel"] }
cmake = "0.1.31"
cmake = "0.1.31"
parity-wasm = "0.35.3"

View file

@ -169,7 +169,7 @@ impl Flattener {
// add a directive to get the bits
statements_flattened.push(FlatStatement::Directive(DirectiveStatement::new(
lhs_bits.clone(),
Helper::Rust(RustHelper::Bits),
Helper::bits(),
vec![lhs_id],
)));
@ -216,7 +216,7 @@ impl Flattener {
// add a directive to get the bits
statements_flattened.push(FlatStatement::Directive(DirectiveStatement::new(
rhs_bits.clone(),
Helper::Rust(RustHelper::Bits),
Helper::bits(),
vec![rhs_id],
)));
@ -273,7 +273,7 @@ impl Flattener {
// add a directive to get the bits
statements_flattened.push(FlatStatement::Directive(DirectiveStatement::new(
sub_bits.clone(),
Helper::Rust(RustHelper::Bits),
Helper::bits(),
vec![subtraction_result_id],
)));

View file

@ -1,10 +1,14 @@
#[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;
#[cfg(feature = "wasm")]
pub use self::wasm::WasmHelper;
use flat_absy::{FlatExpression, FlatVariable};
use std::fmt;
use zokrates_field::field::Field;
@ -58,6 +62,30 @@ pub enum Helper {
#[cfg(feature = "libsnark")]
LibsnarkGadget(LibsnarkGadgetHelper),
Rust(RustHelper),
#[cfg(feature = "wasm")]
Wasm(WasmHelper),
}
#[cfg(feature = "wasm")]
impl Helper {
pub fn identity() -> Self {
Helper::Wasm(WasmHelper::from_hex(WasmHelper::IDENTITY_WASM))
}
pub fn bits() -> Self {
Helper::Wasm(WasmHelper::from(WasmHelper::BITS_WASM))
}
}
#[cfg(not(feature = "wasm"))]
impl Helper {
pub fn identity() -> Self {
Helper::Rust(RustHelper::Identity)
}
pub fn bits() -> Self {
Helper::Rust(RustHelper::Bits)
}
}
impl fmt::Display for Helper {
@ -66,6 +94,8 @@ impl fmt::Display for Helper {
#[cfg(feature = "libsnark")]
Helper::LibsnarkGadget(ref h) => write!(f, "LibsnarkGadget::{}", h),
Helper::Rust(ref h) => write!(f, "Rust::{}", h),
#[cfg(feature = "wasm")]
Helper::Wasm(ref h) => write!(f, "Wasm::{}", h),
}
}
}
@ -87,6 +117,8 @@ impl<T: Field> Executable<T> for Helper {
#[cfg(feature = "libsnark")]
Helper::LibsnarkGadget(helper) => helper.execute(inputs),
Helper::Rust(helper) => helper.execute(inputs),
#[cfg(feature = "wasm")]
Helper::Wasm(helper) => helper.execute(inputs),
};
match result {
@ -107,6 +139,8 @@ impl Signed for Helper {
#[cfg(feature = "libsnark")]
Helper::LibsnarkGadget(helper) => helper.get_signature(),
Helper::Rust(helper) => helper.get_signature(),
#[cfg(feature = "wasm")]
Helper::Wasm(helper) => helper.get_signature(),
}
}
}

View file

@ -0,0 +1,581 @@
use helpers::{Executable, Signed};
use std::fmt;
use rustc_hex::FromHex;
use serde::{Deserialize, Deserializer};
use std::rc::Rc;
use wasmi::{ImportsBuilder, ModuleInstance, ModuleRef, NopExternals};
use zokrates_field::field::Field;
#[derive(Clone, Debug, Serialize)]
pub struct WasmHelper(
#[serde(skip)] std::rc::Rc<ModuleRef>,
#[serde(serialize_with = "serde_bytes::serialize")] Vec<u8>,
);
impl WasmHelper {
// Hand-coded assembly for identity.
// Source available at https://gist.github.com/gballet/f14d11053d8f846bfbb3687581b0eecb#file-identity-wast
pub const IDENTITY_WASM: &'static str = "0061736d010000000105016000017f030302000005030100010615047f0041010b7f0041010b7f0041200b7f0141000b074b06066d656d6f727902000e6765745f696e707574735f6f6666000105736f6c766500000a6d696e5f696e7075747303000b6d696e5f6f75747075747303010a6669656c645f73697a6503020a2c0225000340412023036a410023036a280200360200230341016a240323032302470d000b41200b040041000b0b4b020041000b20ffffffff000000000000000000000000ffffffff0000000000000000000000000041200b20deadbeef000000000000000000000000deadbeef000000000000000000000000";
// Generated from C code, normalized and cleaned up by hand.
// Source available at https://gist.github.com/gballet/f14d11053d8f846bfbb3687581b0eecb#file-bits_v2-c
pub const BITS_WASM: &'static [u8] = &[
0, 97, 115, 109, 1, 0, 0, 0, 1, 8, 2, 96, 0, 0, 96, 0, 1, 127, 3, 5, 4, 0, 1, 1, 1, 4, 5,
1, 112, 1, 1, 1, 5, 3, 1, 0, 2, 6, 38, 6, 127, 1, 65, 240, 199, 4, 11, 127, 0, 65, 240,
199, 4, 11, 127, 0, 65, 240, 199, 0, 11, 127, 0, 65, 32, 11, 127, 0, 65, 1, 11, 127, 0, 65,
254, 1, 11, 7, 109, 9, 6, 109, 101, 109, 111, 114, 121, 2, 0, 11, 95, 95, 104, 101, 97,
112, 95, 98, 97, 115, 101, 3, 1, 10, 95, 95, 100, 97, 116, 97, 95, 101, 110, 100, 3, 2, 14,
103, 101, 116, 95, 105, 110, 112, 117, 116, 115, 95, 111, 102, 102, 0, 1, 5, 115, 111, 108,
118, 101, 0, 2, 4, 109, 97, 105, 110, 0, 3, 10, 102, 105, 101, 108, 100, 95, 115, 105, 122,
101, 3, 3, 10, 109, 105, 110, 95, 105, 110, 112, 117, 116, 115, 3, 4, 11, 109, 105, 110,
95, 111, 117, 116, 112, 117, 116, 115, 3, 5, 9, 1, 0, 10, 85, 4, 3, 0, 1, 11, 5, 0, 65,
144, 8, 11, 68, 1, 2, 127, 65, 253, 1, 33, 0, 65, 176, 8, 33, 1, 3, 64, 32, 1, 65, 1, 32,
0, 65, 7, 113, 116, 32, 0, 65, 3, 118, 65, 144, 8, 106, 45, 0, 0, 113, 65, 0, 71, 58, 0, 0,
32, 1, 65, 32, 106, 33, 1, 32, 0, 65, 127, 106, 34, 0, 65, 127, 71, 13, 0, 11, 65, 176, 8,
11, 4, 0, 65, 0, 11, 11, 19, 1, 0, 65, 128, 8, 11, 12, 32, 0, 0, 0, 1, 0, 0, 0, 254, 0, 0,
0,
];
pub fn from_hex<U: Into<String>>(u: U) -> Self {
let code_hex = u.into();
let code = FromHex::from_hex(&code_hex[..])
.expect(format!("invalid bytecode: {}", code_hex).as_str());
WasmHelper::from(code)
}
}
impl<U: Into<Vec<u8>>> From<U> for WasmHelper {
fn from(code: U) -> Self {
let code_vec = code.into();
let module = wasmi::Module::from_buffer(code_vec.clone()).expect("Error decoding buffer");
let modinst = ModuleInstance::new(&module, &ImportsBuilder::default())
.expect("Failed to instantiate module")
.assert_no_start();
WasmHelper(Rc::new(modinst), code_vec)
}
}
impl<'de> Deserialize<'de> for WasmHelper {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let hex: Vec<u8> = serde_bytes::deserialize(deserializer)?;
Ok(WasmHelper::from(hex))
}
}
impl PartialEq for WasmHelper {
fn eq(&self, other: &WasmHelper) -> bool {
self.1 == other.1
}
}
impl fmt::Display for WasmHelper {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Hex(\"{:?}\")", &self.1[..])
}
}
fn get_export<T: wasmi::FromRuntimeValue>(varname: &str, modref: &ModuleRef) -> Result<T, String> {
modref
.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::<T>()
.ok_or(format!("Error converting `{}` to i32", varname))
}
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 ni = get_export::<i32>("min_inputs", self.0.as_ref()).unwrap();
let no = get_export::<i32>("min_outputs", self.0.as_ref()).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 field_size = get_export::<i32>("field_size", self.0.as_ref())? as usize;
let ninputs = get_export::<i32>("min_inputs", self.0.as_ref())? as usize;
if ninputs != inputs.len() {
return Err(format!(
"`solve` expected {} inputs, received {}",
ninputs,
inputs.len()
));
}
/* Prepare the inputs */
let input_offset = self
.0
.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 = self
.0
.as_ref()
.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 = self
.0
.as_ref()
.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_export::<i32>("min_outputs", self.0.as_ref())?;
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 retrieve 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 super::*;
use parity_wasm::builder::*;
use parity_wasm::elements::{Instruction, Instructions, ValueType};
use std::panic;
use zokrates_field::field::FieldPrime;
fn remove_export(code: &str, symbol: &str) -> Vec<u8> {
let code = FromHex::from_hex(code).unwrap();
let mut idmod: parity_wasm::elements::Module = parity_wasm::deserialize_buffer(&code[..])
.expect("Could not deserialize Identity module");
idmod
.export_section_mut()
.expect("Could not get export section")
.entries_mut()
.retain(|ref export| export.field() != symbol);
parity_wasm::serialize(idmod).expect("Could not serialize buffer")
}
fn replace_function(
code: &str,
symbol: &str,
params: Vec<ValueType>,
ret: Option<ValueType>,
instr: Vec<Instruction>,
) -> Vec<u8> {
/* Deserialize to parity_wasm format */
let code = FromHex::from_hex(code).unwrap();
let mut pwmod: parity_wasm::elements::Module = parity_wasm::deserialize_buffer(&code[..])
.expect("Could not deserialize Identity module");
/* Remove export, if it exists */
pwmod
.export_section_mut()
.expect("Could not get export section")
.entries_mut()
.retain(|ref export| export.field() != symbol);
/* Add a new function and give it the export name */
let wmod: parity_wasm::elements::Module = from_module(pwmod)
.function()
.signature()
.with_params(params)
.with_return_type(ret)
.build()
.body()
.with_instructions(Instructions::new(instr))
.build()
.build()
.export()
.field(symbol)
.internal()
.func(2)
.build()
.build();
parity_wasm::serialize(wmod).expect("Could not serialize buffer")
}
fn replace_global(code: &str, symbol: &str, value: i32) -> Vec<u8> {
/* Deserialize to parity_wasm format */
let code = FromHex::from_hex(code).unwrap();
let mut pwmod: parity_wasm::elements::Module = parity_wasm::deserialize_buffer(&code[..])
.expect("Could not deserialize Identity module");
/* Remove export, if it exists */
pwmod
.export_section_mut()
.expect("Could not get export section")
.entries_mut()
.retain(|ref export| export.field() != symbol);
/* Add a new function and give it the export name */
let wmod: parity_wasm::elements::Module = from_module(pwmod)
.global()
.value_type()
.i32()
.init_expr(Instruction::I32Const(value))
.build()
.export()
.field(symbol)
.internal()
.global(4)
.build()
.build();
parity_wasm::serialize(wmod).expect("Could not serialize buffer")
}
fn replace_global_type(code: &str, symbol: &str) -> Vec<u8> {
/* Deserialize to parity_wasm format */
let code = FromHex::from_hex(code).unwrap();
let mut pwmod: parity_wasm::elements::Module = parity_wasm::deserialize_buffer(&code[..])
.expect("Could not deserialize Identity module");
/* Remove export, if it exists */
pwmod
.export_section_mut()
.expect("Could not get export section")
.entries_mut()
.retain(|ref export| export.field() != symbol);
/* Add a new function and give it the export name */
let wmod: parity_wasm::elements::Module = from_module(pwmod)
.global()
.value_type()
.f32()
.init_expr(Instruction::F32Const(0))
.build()
.export()
.field(symbol)
.internal()
.global(4)
.build()
.build();
parity_wasm::serialize(wmod).expect("Could not serialize buffer")
}
#[test]
fn check_signatures() {
let h1 = WasmHelper::from_hex(WasmHelper::IDENTITY_WASM);
assert_eq!(h1.get_signature(), (1, 1));
}
#[test]
#[should_panic(
expected = "invalid bytecode: invalid bytecode: Invalid character 'i' at position 0"
)]
fn check_invalid_bytecode_fails() {
WasmHelper::from_hex("invalid bytecode");
}
#[test]
#[should_panic(expected = "Error decoding buffer: Validation(\"I/O Error: UnexpectedEof\")")]
fn check_truncated_bytecode_fails() {
WasmHelper::from_hex(&WasmHelper::IDENTITY_WASM[..20]);
}
#[test]
fn validate_exports() {
/* Test identity without the `solve` export */
let id = WasmHelper::from(remove_export(WasmHelper::IDENTITY_WASM, "solve"));
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",
))
);
/* Test identity, without the `get_inputs_off` export */
let id = WasmHelper::from(remove_export(WasmHelper::IDENTITY_WASM, "get_inputs_off"));
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",
))
);
/* Test identity, without the `min_inputs` export */
let id = WasmHelper::from(remove_export(WasmHelper::IDENTITY_WASM, "min_inputs"));
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",
))
);
/* Test identity, without the `min_outputs` export */
let id = WasmHelper::from(remove_export(WasmHelper::IDENTITY_WASM, "min_outputs"));
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",
))
);
/* Test identity, without the `field_size` export */
let id = WasmHelper::from(remove_export(WasmHelper::IDENTITY_WASM, "field_size"));
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",
))
);
/* Test identity, without the `memory` export */
let id = WasmHelper::from(remove_export(WasmHelper::IDENTITY_WASM, "memory"));
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() {
/* Test identity, with a different function return type */
let id = WasmHelper::from(replace_function(
WasmHelper::IDENTITY_WASM,
"get_inputs_off",
Vec::new(),
Some(ValueType::I64),
vec![Instruction::I64Const(0), Instruction::End],
));
let input = vec![FieldPrime::from(1)];
let outputs = id.execute(&input);
assert_eq!(
outputs,
Err(String::from("`get_inputs_off` returned the wrong type"))
);
/* Test identity, with no return type for function */
let id = WasmHelper::from(replace_function(
WasmHelper::IDENTITY_WASM,
"get_inputs_off",
Vec::new(),
None,
vec![Instruction::Nop, Instruction::End],
));
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"))
);
/* Test identity, with extra parameter for function */
let id = WasmHelper::from(replace_function(
WasmHelper::IDENTITY_WASM,
"get_inputs_off",
vec![ValueType::I64],
Some(ValueType::I32),
vec![Instruction::I32Const(0), Instruction::End],
));
let input = vec![FieldPrime::from(1)];
let outputs = id.execute(&input);
assert_eq!(
outputs,
Err(String::from(
"Error getting the input offset: Trap: Trap { kind: UnexpectedSignature }",
))
);
}
#[test]
fn check_invalid_field_size() {
/* Test identity, with 1-byte filed size */
let id = WasmHelper::from(replace_global(WasmHelper::IDENTITY_WASM, "field_size", 1));
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",
))
);
/* Test identity, tweaked so that field_size is a f32 */
let id = WasmHelper::from(replace_global_type(WasmHelper::IDENTITY_WASM, "field_size"));
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::from_hex(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::from_hex(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::from_hex(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::from_hex(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: same as identity, but
// get_inputs_off returns an OOB offset.
let id = WasmHelper::from(replace_function(
WasmHelper::IDENTITY_WASM,
"get_inputs_off",
Vec::new(),
Some(ValueType::I32),
vec![Instruction::I32Const(65536), Instruction::End],
));
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 */
// Check that input writes are boundary-checked: same as identity, but
// solve returns an OOB offset.
let id = WasmHelper::from(replace_function(
WasmHelper::IDENTITY_WASM,
"solve",
Vec::new(),
Some(ValueType::I32),
vec![Instruction::I32Const(65536), Instruction::End],
));
let input = vec![FieldPrime::from(65536)];
let outputs = id.execute(&input);
assert_eq!(
outputs,
Err(String::from(
"Could not retrieve the output offset: Memory: trying to access region [65536..65568] in memory [0..64]",
))
);
}
#[test]
fn check_negative_output_value() {
/* Same as identity, but `solve` returns -1 */
let id = WasmHelper::from(replace_function(
WasmHelper::IDENTITY_WASM,
"solve",
Vec::new(),
Some(ValueType::I32),
vec![Instruction::I32Const(-1), Instruction::End],
));
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_bits() {
let bits = WasmHelper::from(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[(253 - i) as usize], FieldPrime::from(bitval as i32));
}
for i in 32..254 {
assert_eq!(outputs[(253 - i) as usize], FieldPrime::from(0));
}
}
}

View file

@ -9,7 +9,15 @@ extern crate serde_json;
extern crate serde_derive;
extern crate bimap;
extern crate bincode;
#[cfg(feature = "wasm")]
extern crate parity_wasm;
extern crate regex;
#[cfg(feature = "wasm")]
extern crate rustc_hex;
#[cfg(feature = "wasm")]
extern crate serde_bytes;
#[cfg(feature = "wasm")]
extern crate wasmi;
extern crate zokrates_field;
mod flatten;

View file

@ -2,7 +2,7 @@ use bimap::BiMap;
use flat_absy::flat_parameter::FlatParameter;
use flat_absy::flat_variable::FlatVariable;
use flat_absy::*;
use helpers::{DirectiveStatement, Helper, RustHelper};
use helpers::{DirectiveStatement, Helper};
use reduce::Reduce;
use types::constraints::Constraint;
use types::signature::Signature;
@ -85,7 +85,7 @@ pub fn unpack<T: Field>(nbits: usize) -> FlatProg<T> {
.map(|index| use_variable(&mut bijection, format!("o{}", index), &mut counter))
.collect();
let helper = Helper::Rust(RustHelper::Bits);
let helper = Helper::bits();
let signature = Signature {
inputs: vec![Type::FieldElement],
@ -253,8 +253,8 @@ pub fn cast<T: Field>(from: &Type, to: &Type) -> FlatFunction<T> {
.collect();
let helper = match (from, to) {
(Type::Boolean, Type::FieldElement) => Helper::Rust(RustHelper::Identity),
(Type::FieldElement, Type::Boolean) => Helper::Rust(RustHelper::Identity),
(Type::Boolean, Type::FieldElement) => Helper::identity(),
(Type::FieldElement, Type::Boolean) => Helper::identity(),
_ => panic!(format!("can't cast {} to {}", from, to)),
};
@ -313,7 +313,7 @@ mod tests {
f2b.statements[0],
FlatStatement::Directive(DirectiveStatement::new(
vec![FlatVariable::new(1)],
Helper::Rust(RustHelper::Identity),
Helper::identity(),
vec![FlatVariable::new(0)]
))
);
@ -339,7 +339,7 @@ mod tests {
b2f.statements[0],
FlatStatement::Directive(DirectiveStatement::new(
vec![FlatVariable::new(1)],
Helper::Rust(RustHelper::Identity),
Helper::identity(),
vec![FlatVariable::new(0)]
))
);
@ -376,7 +376,7 @@ mod tests {
(0..FieldPrime::get_required_bits())
.map(|i| FlatVariable::new(i + 1))
.collect(),
Helper::Rust(RustHelper::Bits),
Helper::bits(),
vec![FlatVariable::new(0)]
))
);

View file

@ -1,8 +1,8 @@
extern crate serde_json;
extern crate zokrates_core;
extern crate zokrates_field;
#[macro_use]
extern crate serde_derive;
extern crate zokrates_core;
extern crate zokrates_field;
#[macro_use]
mod utils;

View file

@ -90,7 +90,7 @@ macro_rules! zokrates_test {
#[test]
fn $name() {
use zokrates_field::field::{FieldPrime, Field};
use zokrates_field::field::{Field, FieldPrime};
let code_string = $crate::utils::read_file(&format!("./{}.code", stringify!($name)));
let test_string = $crate::utils::read_file(&format!("./{}.json", stringify!($name)));

View file

@ -5,7 +5,6 @@ authors = ["Guillaume Ballet <gballet@gmail.com>"]
edition = "2018"
[dependencies]
serde = "1.0"
serde_derive = "1.0"
lazy_static = "0.1.*"