merge develop, format
This commit is contained in:
commit
5bf7f9cb49
62 changed files with 6534 additions and 5327 deletions
36
.circleci/config.yml
Normal file
36
.circleci/config.yml
Normal file
|
@ -0,0 +1,36 @@
|
|||
version: 2
|
||||
|
||||
jobs:
|
||||
build:
|
||||
docker:
|
||||
- image: rustlang/rust:nightly-slim
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Version information
|
||||
command: rustc --version; cargo --version; rustup --version
|
||||
- run:
|
||||
name: Calculate dependencies
|
||||
command: cargo generate-lockfile
|
||||
- restore_cache:
|
||||
keys:
|
||||
- v4-cargo-cache-{{ arch }}-{{ checksum "Cargo.lock" }}
|
||||
- run:
|
||||
name: Check format
|
||||
command: rustup component add rustfmt-preview; cargo fmt --all -- --check
|
||||
- run:
|
||||
name: Build libsnark
|
||||
command: LIBSNARK_SOURCE_PATH=$HOME/libsnark ./build_libsnark.sh
|
||||
- run:
|
||||
name: Build
|
||||
command: WITH_LIBSNARK=1 LIBSNARK_SOURCE_PATH=$HOME/libsnark ./build.sh
|
||||
- run:
|
||||
name: Run tests
|
||||
command: LIBSNARK_SOURCE_PATH=$HOME/libsnark cargo test --release
|
||||
- save_cache:
|
||||
paths:
|
||||
- /usr/local/cargo/registry
|
||||
- target/debug/.fingerprint
|
||||
- target/debug/build
|
||||
- target/debug/deps
|
||||
key: v4-cargo-cache-{{ arch }}-{{ checksum "Cargo.lock" }}
|
271
Cargo.lock
generated
271
Cargo.lock
generated
|
@ -1,9 +1,9 @@
|
|||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.6.8"
|
||||
version = "0.6.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"memchr 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -11,7 +11,15 @@ name = "ansi_term"
|
|||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -23,7 +31,7 @@ dependencies = [
|
|||
"difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"environment 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"skeptic 0.13.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -34,7 +42,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
dependencies = [
|
||||
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -43,10 +51,10 @@ version = "0.3.9"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -68,9 +76,9 @@ name = "bincode"
|
|||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"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.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -90,7 +98,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.2.6"
|
||||
version = "1.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
@ -100,19 +108,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
dependencies = [
|
||||
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.5"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
@ -131,7 +142,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cmake"
|
||||
version = "0.1.34"
|
||||
version = "0.1.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -142,7 +153,38 @@ name = "colored"
|
|||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -150,6 +192,11 @@ name = "difference"
|
|||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "environment"
|
||||
version = "0.1.1"
|
||||
|
@ -177,11 +224,6 @@ name = "fuchsia-zircon-sys"
|
|||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "gcc"
|
||||
version = "0.3.54"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.2.11"
|
||||
|
@ -199,11 +241,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.1.0"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
|
@ -212,12 +251,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.0.2"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "nodrop"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "num"
|
||||
version = "0.1.42"
|
||||
|
@ -267,9 +318,17 @@ name = "num-traits"
|
|||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "0.4.19"
|
||||
version = "0.4.21"
|
||||
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)",
|
||||
|
@ -285,10 +344,10 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "0.6.8"
|
||||
version = "0.6.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -298,7 +357,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
dependencies = [
|
||||
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -324,11 +404,11 @@ name = "regex"
|
|||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"aho-corasick 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"utf8-ranges 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -336,7 +416,7 @@ name = "regex-syntax"
|
|||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ucd-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -344,7 +424,7 @@ name = "remove_dir_all"
|
|||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -359,19 +439,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.3"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -381,27 +466,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.79"
|
||||
version = "1.0.80"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.79"
|
||||
version = "1.0.80"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.21 (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.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.27"
|
||||
version = "1.0.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -414,9 +499,9 @@ dependencies = [
|
|||
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"walkdir 2.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"walkdir 2.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -426,11 +511,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.15.4"
|
||||
version = "0.15.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.21 (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)",
|
||||
]
|
||||
|
||||
|
@ -466,12 +551,12 @@ name = "thread_local"
|
|||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ucd-util"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
@ -486,7 +571,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "utf8-ranges"
|
||||
version = "1.0.1"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
@ -496,22 +581,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.1.4"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.2.5"
|
||||
version = "2.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"same-file 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.5"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -528,7 +613,7 @@ name = "winapi-util"
|
|||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -538,27 +623,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "zokrates_cli"
|
||||
version = "0.2.0"
|
||||
version = "0.3.1"
|
||||
dependencies = [
|
||||
"assert_cli 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"zokrates_core 0.2.0",
|
||||
"zokrates_fs_resolver 0.1.0",
|
||||
"serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"zokrates_core 0.3.1",
|
||||
"zokrates_fs_resolver 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zokrates_core"
|
||||
version = "0.2.0"
|
||||
version = "0.3.1"
|
||||
dependencies = [
|
||||
"assert_cli 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bimap 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cmake 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cmake 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -566,18 +651,19 @@ dependencies = [
|
|||
"num-bigint 0.1.44 (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)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zokrates_fs_resolver"
|
||||
version = "0.1.0"
|
||||
version = "0.3.1"
|
||||
|
||||
[metadata]
|
||||
"checksum aho-corasick 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "68f56c7353e5a9547cbd76ed90f7bb5ffc3ba09d4ea9bd1d8c06c8b1142eeb5a"
|
||||
"checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e"
|
||||
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"
|
||||
"checksum assert_cli 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "72342c21057a3cb5f7c2d849bf7999a83795434dd36d74fa8c24680581bd1930"
|
||||
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
|
||||
"checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a"
|
||||
|
@ -587,35 +673,43 @@ version = "0.1.0"
|
|||
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
|
||||
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
||||
"checksum bytecount 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f861d9ce359f56dbcb6e0c2a1cb84e52ad732cadb57b806adeb3c7668caccbd8"
|
||||
"checksum byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "90492c5858dd7d2e78691cfb89f90d273a2800fc11d98f60786e5d87e2f83781"
|
||||
"checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d"
|
||||
"checksum cargo_metadata 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1efca0b863ca03ed4c109fb1c55e0bc4bbeb221d3e103d86251046b06a526bd0"
|
||||
"checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16"
|
||||
"checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3"
|
||||
"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
|
||||
"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
|
||||
"checksum cmake 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "848b314ea70f48f0e13828c5554e34200952ce5720d6d3aa466b4d983af6c70e"
|
||||
"checksum cmake 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "6ec65ee4f9c9d16f335091d23693457ed4928657ba4982289d7fafee03bc614a"
|
||||
"checksum colored 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc0a60679001b62fb628c4da80e574b9645ab4646056d7c9018885efffe45533"
|
||||
"checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3"
|
||||
"checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150"
|
||||
"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9"
|
||||
"checksum difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3304d19798a8e067e48d8e69b2c37f0b5e9b4e462504ad9e27e9f3fce02bba8"
|
||||
"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
|
||||
"checksum environment 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f4b14e20978669064c33b4c1e0fb4083412e40fe56cbea2eae80fd7591503ee"
|
||||
"checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3"
|
||||
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb"
|
||||
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
|
||||
"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
|
||||
"checksum lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "cf186d1a8aa5f5bee5fd662bc9c1b949e0259e1bcc379d1f006847b0080c7417"
|
||||
"checksum lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca488b89a5657b0a2ecd45b95609b3e848cf1755da332a0da46e2b2b1cb371a7"
|
||||
"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
|
||||
"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d"
|
||||
"checksum memchr 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a3b4142ab8738a78c51896f704f83c11df047ff1bda9a92a661aa6361552d93d"
|
||||
"checksum memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0a3eb002f0535929f1199681417029ebea04aadc0c7a4224b46be99c7f5d6a16"
|
||||
"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
|
||||
"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2"
|
||||
"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.19 (registry+https://github.com/rust-lang/crates.io-index)" = "ffe022fb8c8bd254524b0b3305906c1921fa37a84a644e29079a9e62200c3901"
|
||||
"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30"
|
||||
"checksum proc-macro2 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)" = "ab2fc21ba78ac73e4ff6b3818ece00be4e175ffbef4d0a717d978b48b24150c4"
|
||||
"checksum pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d6fdf85cda6cadfae5428a54661d431330b312bc767ddbc57adbedc24da66e32"
|
||||
"checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5"
|
||||
"checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c"
|
||||
"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd"
|
||||
"checksum rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "373814f27745b2686b350dd261bfd24576a6fb0e2c5919b3a2b6005f820b0473"
|
||||
"checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356"
|
||||
"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1"
|
||||
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
|
||||
"checksum reduce 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f77b717415291f4d7929a111402316b272c566ae9d4b75a61507dba88ecbd89"
|
||||
|
@ -624,27 +718,28 @@ version = "0.1.0"
|
|||
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
|
||||
"checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395"
|
||||
"checksum ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7153dd96dade874ab973e098cb62fcdbb89a03682e46b144fd09550998d4a4a7"
|
||||
"checksum same-file 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "10f7794e2fda7f594866840e95f5c5962e886e228e68b6505885811a94dd728c"
|
||||
"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.79 (registry+https://github.com/rust-lang/crates.io-index)" = "84257ccd054dc351472528c8587b4de2dbf0dc0fe2e634030c1a90bfdacebaa9"
|
||||
"checksum serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)" = "31569d901045afbff7a9479f793177fe9259819aff10ab4f89ef69bbc5f567fe"
|
||||
"checksum serde_json 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "59790990c5115d16027f00913e2e66de23a51f70422e549d2ad68c8c5f268f1c"
|
||||
"checksum serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "15c141fc7027dd265a47c090bf864cf62b42c4d228bbcf4e51a0c9e2b0d3f7ef"
|
||||
"checksum serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "225de307c6302bec3898c51ca302fc94a7a1697ef0845fcee6448f33c032249c"
|
||||
"checksum serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)" = "c37ccd6be3ed1fdf419ee848f7c758eb31b054d7cd3ae3600e3bae0adf569811"
|
||||
"checksum skeptic 0.13.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c4474d6da9593171bcb086890fc344a3a12783cb24e5b141f8a5d0e43561f4b6"
|
||||
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
|
||||
"checksum syn 0.15.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9056ebe7f2d6a38bc63171816fd1d3430da5a43896de21676dc5c0a4b8274a11"
|
||||
"checksum syn 0.15.18 (registry+https://github.com/rust-lang/crates.io-index)" = "90c39a061e2f412a9f869540471ab679e85e50c6b05604daf28bc3060f75c430"
|
||||
"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
|
||||
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
|
||||
"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
|
||||
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
|
||||
"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d"
|
||||
"checksum ucd-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d0f8bfa9ff0cadcd210129ad9d2c5f145c13e9ced3d3e5d948a6213487d52444"
|
||||
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
|
||||
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
||||
"checksum utf8-ranges 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd70f467df6810094968e2fce0ee1bd0e87157aceb026a8c083bcf5e25b9efe4"
|
||||
"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 version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7716c242968ee87e5542f8021178248f267f295a5c4803beae8b8b7fd9bc6051"
|
||||
"checksum walkdir 2.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "af464bc7be7b785c7ac72e266a6b67c4c9070155606f51655a650a6686204e35"
|
||||
"checksum winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "773ef9dcc5f24b7d850d0ff101e542ff24c3b090a9768e03ff889fdef41f00fd"
|
||||
"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
|
||||
"checksum walkdir 2.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0ffb549f212c31e19f3667c55a7f515b983a84aef10fd0a4d1f9c125425115f3"
|
||||
"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"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
|
14
Jenkinsfile
vendored
14
Jenkinsfile
vendored
|
@ -31,6 +31,19 @@ pipeline {
|
|||
}
|
||||
}
|
||||
}
|
||||
stage('Format') {
|
||||
agent {
|
||||
docker {
|
||||
image 'rustlang/rust:nightly'
|
||||
}
|
||||
}
|
||||
steps {
|
||||
script {
|
||||
sh "rustup component add rustfmt-preview"
|
||||
sh "cargo fmt --all -- --check"
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Build') {
|
||||
steps {
|
||||
script {
|
||||
|
@ -79,7 +92,6 @@ pipeline {
|
|||
steps {
|
||||
script {
|
||||
ansiColor('xterm') {
|
||||
// currently not run due to bug in Jenkins Docker Plugin.
|
||||
// prodImage = docker.build("zokrates/zokrates")
|
||||
// docker.withRegistry('https://registry.hub.docker.com', 'dockerhub-kyroy') {
|
||||
// prodImage.push(patchVersion)
|
||||
|
|
18
README.md
18
README.md
|
@ -125,9 +125,19 @@ Verifier.at(<verifier contract address>).verifyTx(A, A_p, B, B_p, C, C_p, H, K,
|
|||
|
||||
Where `A, ..., K` are defined as above (adding brackets and quotes: `A = ["0x123", "0x345"]`), `publicInputs` are the public inputs supplied to witness generation and `outputs` are the results of the computation.
|
||||
|
||||
# Testing
|
||||
# Contributing
|
||||
|
||||
Run normal tests with
|
||||
Want to contribute to ZoKrates? Great!
|
||||
First, fork this repository.
|
||||
|
||||
Then, install `rustfmt`
|
||||
```
|
||||
rustup component add rustfmt-preview
|
||||
```
|
||||
|
||||
Make sure you're using rust nightly.
|
||||
|
||||
Then, run normal tests with
|
||||
```
|
||||
cargo test
|
||||
```
|
||||
|
@ -135,3 +145,7 @@ and run long and expensive tests with
|
|||
```
|
||||
cargo test -- --ignored
|
||||
```
|
||||
|
||||
Finally, before pushing your changes, make sure to run `cargo +nightly fmt` to format your code.
|
||||
|
||||
Thank you for contributing to ZoKrates!
|
||||
|
|
21
build_libsnark.sh
Executable file
21
build_libsnark.sh
Executable file
|
@ -0,0 +1,21 @@
|
|||
#!/bin/bash
|
||||
|
||||
LIBSNARK_COMMIT=f7c87b88744ecfd008126d415494d9b34c4c1b20
|
||||
|
||||
apt-get update && apt-get install -y --no-install-recommends \
|
||||
ca-certificates \
|
||||
build-essential \
|
||||
cmake \
|
||||
curl \
|
||||
libboost-dev \
|
||||
libboost-program-options-dev \
|
||||
libgmp3-dev \
|
||||
libprocps-dev \
|
||||
libssl-dev \
|
||||
pkg-config \
|
||||
python-markdown \
|
||||
git \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& git clone https://github.com/scipr-lab/libsnark.git $LIBSNARK_SOURCE_PATH \
|
||||
&& git -C $LIBSNARK_SOURCE_PATH checkout $LIBSNARK_COMMIT \
|
||||
&& git -C $LIBSNARK_SOURCE_PATH submodule update --init --recursive \
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "zokrates_cli"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
authors = ["Jacob Eberhardt <jacob.eberhardt@tu-berlin.de>", "Dennis Kuhnert <mail@kyroy.com>", "Thibaut Schaeffer <thibaut@schaeff.fr>"]
|
||||
repository = "https://github.com/JacobEberhardt/ZoKrates.git"
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -4,26 +4,26 @@
|
|||
// @author Dennis Kuhnert <dennis.kuhnert@campus.tu-berlin.de>
|
||||
// @date 2017
|
||||
|
||||
extern crate clap;
|
||||
extern crate bincode;
|
||||
extern crate clap;
|
||||
extern crate regex;
|
||||
extern crate zokrates_core;
|
||||
extern crate zokrates_fs_resolver;
|
||||
|
||||
use std::fs::File;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::io::{BufWriter, Write, BufReader, BufRead, stdin};
|
||||
use bincode::{deserialize_from, serialize_into, Infinite};
|
||||
use clap::{App, AppSettings, Arg, SubCommand};
|
||||
use regex::Regex;
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::io::{stdin, BufRead, BufReader, BufWriter, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::string::String;
|
||||
use zokrates_core::compile::compile;
|
||||
use zokrates_core::field::{Field, FieldPrime};
|
||||
use zokrates_core::r1cs::{r1cs_program};
|
||||
use zokrates_core::flat_absy::FlatProg;
|
||||
use clap::{App, AppSettings, Arg, SubCommand};
|
||||
#[cfg(feature = "libsnark")]
|
||||
use zokrates_core::libsnark::{setup, generate_proof};
|
||||
use bincode::{serialize_into, deserialize_from , Infinite};
|
||||
use regex::Regex;
|
||||
use zokrates_core::libsnark::{generate_proof, setup};
|
||||
use zokrates_core::r1cs::r1cs_program;
|
||||
use zokrates_core::verification::CONTRACT_TEMPLATE;
|
||||
use zokrates_fs_resolver::resolve as fs_resolve;
|
||||
|
||||
|
@ -35,11 +35,11 @@ fn main() {
|
|||
const WITNESS_DEFAULT_PATH: &str = "witness";
|
||||
const VARIABLES_INFORMATION_KEY_DEFAULT_PATH: &str = "variables.inf";
|
||||
const JSON_PROOF_PATH: &str = "proof.json";
|
||||
|
||||
|
||||
// cli specification using clap library
|
||||
let matches = App::new("ZoKrates")
|
||||
.setting(AppSettings::SubcommandRequiredElseHelp)
|
||||
.version("0.3.0")
|
||||
.version("0.3.1")
|
||||
.author("Jacob Eberhardt, Thibaut Schaeffer, Dennis Kuhnert")
|
||||
.about("Supports generation of zkSNARKs from high level language code including Smart Contracts for proof verification on the Ethereum Blockchain.\n'I know that I show nothing!'")
|
||||
.subcommand(SubCommand::with_name("compile")
|
||||
|
@ -200,7 +200,13 @@ fn main() {
|
|||
|
||||
let path = PathBuf::from(sub_matches.value_of("input").unwrap());
|
||||
|
||||
let location = path.parent().unwrap().to_path_buf().into_os_string().into_string().unwrap();
|
||||
let location = path
|
||||
.parent()
|
||||
.unwrap()
|
||||
.to_path_buf()
|
||||
.into_os_string()
|
||||
.into_string()
|
||||
.unwrap();
|
||||
|
||||
let light = sub_matches.occurrences_of("light") > 0;
|
||||
|
||||
|
@ -211,17 +217,21 @@ fn main() {
|
|||
let file = File::open(path.clone()).unwrap();
|
||||
|
||||
let mut reader = BufReader::new(file);
|
||||
|
||||
let program_flattened: FlatProg<FieldPrime> = match compile(&mut reader, Some(location), Some(fs_resolve)) {
|
||||
Ok(p) => p,
|
||||
Err(why) => panic!("Compilation failed: {}", why)
|
||||
};
|
||||
|
||||
let program_flattened: FlatProg<FieldPrime> =
|
||||
match compile(&mut reader, Some(location), Some(fs_resolve)) {
|
||||
Ok(p) => p,
|
||||
Err(why) => panic!("Compilation failed: {}", why),
|
||||
};
|
||||
|
||||
// number of constraints the flattened program will translate to.
|
||||
let num_constraints = &program_flattened.functions
|
||||
.iter()
|
||||
.find(|x| x.id == "main")
|
||||
.unwrap().statements.len();
|
||||
let num_constraints = &program_flattened
|
||||
.functions
|
||||
.iter()
|
||||
.find(|x| x.id == "main")
|
||||
.unwrap()
|
||||
.statements
|
||||
.len();
|
||||
|
||||
// serialize flattened program and write to binary file
|
||||
let mut bin_output_file = match File::create(&bin_output_path) {
|
||||
|
@ -229,7 +239,8 @@ fn main() {
|
|||
Err(why) => panic!("couldn't create {}: {}", bin_output_path.display(), why),
|
||||
};
|
||||
|
||||
serialize_into(&mut bin_output_file, &program_flattened, Infinite).expect("Unable to write data to file.");
|
||||
serialize_into(&mut bin_output_file, &program_flattened, Infinite)
|
||||
.expect("Unable to write data to file.");
|
||||
|
||||
if !light {
|
||||
// write human-readable output file
|
||||
|
@ -239,7 +250,8 @@ fn main() {
|
|||
};
|
||||
|
||||
let mut hrofb = BufWriter::new(hr_output_file);
|
||||
write!(&mut hrofb, "{}\n", program_flattened).expect("Unable to write data to file.");
|
||||
write!(&mut hrofb, "{}\n", program_flattened)
|
||||
.expect("Unable to write data to file.");
|
||||
hrofb.flush().expect("Unable to flush buffer.");
|
||||
}
|
||||
|
||||
|
@ -285,60 +297,78 @@ fn main() {
|
|||
|
||||
// validate #arguments
|
||||
let mut cli_arguments: Vec<FieldPrime> = Vec::new();
|
||||
match sub_matches.values_of("arguments"){
|
||||
match sub_matches.values_of("arguments") {
|
||||
Some(p) => {
|
||||
let arg_strings: Vec<&str> = p.collect();
|
||||
cli_arguments = arg_strings.into_iter().map(|x| FieldPrime::from(x)).collect();
|
||||
},
|
||||
None => {
|
||||
cli_arguments = arg_strings
|
||||
.into_iter()
|
||||
.map(|x| FieldPrime::from(x))
|
||||
.collect();
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
// handle interactive and non-interactive modes
|
||||
let is_interactive = sub_matches.occurrences_of("interactive") > 0;
|
||||
|
||||
// in interactive mode, only public inputs are expected
|
||||
let expected_cli_args_count = main_flattened.arguments.iter().filter(|x| !(x.private && is_interactive)).count();
|
||||
let expected_cli_args_count = main_flattened
|
||||
.arguments
|
||||
.iter()
|
||||
.filter(|x| !(x.private && is_interactive))
|
||||
.count();
|
||||
|
||||
if cli_arguments.len() != expected_cli_args_count {
|
||||
println!("Wrong number of arguments. Given: {}, Required: {}.", cli_arguments.len(), expected_cli_args_count);
|
||||
println!(
|
||||
"Wrong number of arguments. Given: {}, Required: {}.",
|
||||
cli_arguments.len(),
|
||||
expected_cli_args_count
|
||||
);
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
let mut cli_arguments_iter = cli_arguments.into_iter();
|
||||
let arguments = main_flattened.arguments.clone().into_iter().map(|x| {
|
||||
match x.private && is_interactive {
|
||||
// private inputs are passed interactively when the flag is present
|
||||
true => {
|
||||
println!("Please enter a value for {:?}:", x.id);
|
||||
let mut input = String::new();
|
||||
let stdin = stdin();
|
||||
stdin
|
||||
.lock()
|
||||
.read_line(&mut input)
|
||||
.expect("Did not enter a correct String");
|
||||
FieldPrime::from(input.trim())
|
||||
}
|
||||
// otherwise, they are taken from the CLI arguments
|
||||
false => {
|
||||
match cli_arguments_iter.next() {
|
||||
let arguments = main_flattened
|
||||
.arguments
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|x| {
|
||||
match x.private && is_interactive {
|
||||
// private inputs are passed interactively when the flag is present
|
||||
true => {
|
||||
println!("Please enter a value for {:?}:", x.id);
|
||||
let mut input = String::new();
|
||||
let stdin = stdin();
|
||||
stdin
|
||||
.lock()
|
||||
.read_line(&mut input)
|
||||
.expect("Did not enter a correct String");
|
||||
FieldPrime::from(input.trim())
|
||||
}
|
||||
// otherwise, they are taken from the CLI arguments
|
||||
false => match cli_arguments_iter.next() {
|
||||
Some(x) => x,
|
||||
None => {
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}).collect();
|
||||
})
|
||||
.collect();
|
||||
|
||||
let witness_map = main_flattened.get_witness(arguments).unwrap();
|
||||
|
||||
println!("\nWitness: \n\n{}", witness_map
|
||||
.iter()
|
||||
.filter_map(|(variable, value)| match variable {
|
||||
variable if variable.is_output() => Some(format!("{} {}", variable, value)),
|
||||
_ => None
|
||||
}).collect::<Vec<String>>().join("\n"));
|
||||
println!(
|
||||
"\nWitness: \n\n{}",
|
||||
witness_map
|
||||
.iter()
|
||||
.filter_map(|(variable, value)| match variable {
|
||||
variable if variable.is_output() => Some(format!("{} {}", variable, value)),
|
||||
_ => None,
|
||||
})
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n")
|
||||
);
|
||||
|
||||
// write witness to file
|
||||
let output_path = Path::new(sub_matches.value_of("output").unwrap());
|
||||
|
@ -348,7 +378,8 @@ fn main() {
|
|||
};
|
||||
let mut bw = BufWriter::new(output_file);
|
||||
for (var, val) in &witness_map {
|
||||
write!(&mut bw, "{} {}\n", var, val.to_dec_string()).expect("Unable to write data to file.");
|
||||
write!(&mut bw, "{} {}\n", var, val.to_dec_string())
|
||||
.expect("Unable to write data to file.");
|
||||
}
|
||||
bw.flush().expect("Unable to flush buffer.");
|
||||
}
|
||||
|
@ -379,7 +410,7 @@ fn main() {
|
|||
println!("{}", main_flattened);
|
||||
|
||||
// transform to R1CS
|
||||
let (variables, private_inputs_offset, a, b, c) = r1cs_program(&program_ast);
|
||||
let (variables, public_variables_count, a, b, c) = r1cs_program(&program_ast);
|
||||
|
||||
// write variables meta information to file
|
||||
let var_inf_path = Path::new(sub_matches.value_of("meta-information").unwrap());
|
||||
|
@ -388,38 +419,41 @@ fn main() {
|
|||
Err(why) => panic!("couldn't open {}: {}", var_inf_path.display(), why),
|
||||
};
|
||||
let mut bw = BufWriter::new(var_inf_file);
|
||||
write!(&mut bw, "Private inputs offset:\n{}\n", private_inputs_offset).expect("Unable to write data to file.");
|
||||
write!(&mut bw, "R1CS variable order:\n").expect("Unable to write data to file.");
|
||||
|
||||
write!(
|
||||
&mut bw,
|
||||
"Private inputs offset:\n{}\n",
|
||||
public_variables_count
|
||||
)
|
||||
.expect("Unable to write data to file.");
|
||||
write!(&mut bw, "R1CS variable order:\n").expect("Unable to write data to file.");
|
||||
|
||||
for var in &variables {
|
||||
write!(&mut bw, "{} ", var).expect("Unable to write data to file.");
|
||||
}
|
||||
write!(&mut bw, "\n").expect("Unable to write data to file.");
|
||||
bw.flush().expect("Unable to flush buffer.");
|
||||
|
||||
|
||||
// get paths for proving and verification keys
|
||||
let pk_path = sub_matches.value_of("proving-key-path").unwrap();
|
||||
let vk_path = sub_matches.value_of("verification-key-path").unwrap();
|
||||
|
||||
let public_inputs_indices = main_flattened.arguments.iter().enumerate()
|
||||
.filter_map(|(index, x)| match x.private {
|
||||
true => None,
|
||||
false => Some(index),
|
||||
});
|
||||
|
||||
let public_inputs = public_inputs_indices
|
||||
.map(|i| main_flattened.signature.inputs[i].get_primitive_count())
|
||||
.fold(0, |acc, e| acc + e);
|
||||
|
||||
let outputs = main_flattened.signature.outputs.iter().map(|t| t.get_primitive_count())
|
||||
.fold(0, |acc, e| acc + e);
|
||||
|
||||
let num_inputs = public_inputs + outputs;
|
||||
|
||||
// run setup phase
|
||||
#[cfg(feature="libsnark")]{
|
||||
#[cfg(feature = "libsnark")]
|
||||
{
|
||||
// number of inputs in the zkSNARK sense, i.e., input variables + output variables
|
||||
println!("setup successful: {:?}", setup(variables, a, b, c, num_inputs, pk_path, vk_path));
|
||||
println!(
|
||||
"setup successful: {:?}",
|
||||
setup(
|
||||
variables,
|
||||
a,
|
||||
b,
|
||||
c,
|
||||
public_variables_count - 1,
|
||||
pk_path,
|
||||
vk_path
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
("export-verifier", Some(sub_matches)) => {
|
||||
|
@ -434,7 +468,7 @@ fn main() {
|
|||
let mut lines = reader.lines();
|
||||
|
||||
let mut template_text = String::from(CONTRACT_TEMPLATE);
|
||||
let ic_template = String::from("vk.IC[index] = Pairing.G1Point(points);"); //copy this for each entry
|
||||
let ic_template = String::from("vk.IC[index] = Pairing.G1Point(points);"); //copy this for each entry
|
||||
|
||||
//replace things in template
|
||||
let vk_regex = Regex::new(r#"(<%vk_[^i%]*%>)"#).unwrap();
|
||||
|
@ -445,34 +479,55 @@ fn main() {
|
|||
let vk_input_len_regex = Regex::new(r#"(<%vk_input_length%>)"#).unwrap();
|
||||
|
||||
for _ in 0..7 {
|
||||
let current_line: String = lines.next().expect("Unexpected end of file in verification key!").unwrap();
|
||||
let current_line: String = lines
|
||||
.next()
|
||||
.expect("Unexpected end of file in verification key!")
|
||||
.unwrap();
|
||||
let current_line_split: Vec<&str> = current_line.split("=").collect();
|
||||
assert_eq!(current_line_split.len(), 2);
|
||||
template_text = vk_regex.replace(template_text.as_str(), current_line_split[1].trim()).into_owned();
|
||||
template_text = vk_regex
|
||||
.replace(template_text.as_str(), current_line_split[1].trim())
|
||||
.into_owned();
|
||||
}
|
||||
|
||||
let current_line: String = lines.next().expect("Unexpected end of file in verification key!").unwrap();
|
||||
let current_line: String = lines
|
||||
.next()
|
||||
.expect("Unexpected end of file in verification key!")
|
||||
.unwrap();
|
||||
let current_line_split: Vec<&str> = current_line.split("=").collect();
|
||||
assert_eq!(current_line_split.len(), 2);
|
||||
let ic_count: i32 = current_line_split[1].trim().parse().unwrap();
|
||||
|
||||
template_text = vk_ic_len_regex.replace(template_text.as_str(), format!("{}", ic_count).as_str()).into_owned();
|
||||
template_text = vk_input_len_regex.replace(template_text.as_str(), format!("{}", ic_count-1).as_str()).into_owned();
|
||||
template_text = vk_ic_len_regex
|
||||
.replace(template_text.as_str(), format!("{}", ic_count).as_str())
|
||||
.into_owned();
|
||||
template_text = vk_input_len_regex
|
||||
.replace(template_text.as_str(), format!("{}", ic_count - 1).as_str())
|
||||
.into_owned();
|
||||
|
||||
let mut ic_repeat_text = String::new();
|
||||
for x in 0..ic_count {
|
||||
let mut curr_template = ic_template.clone();
|
||||
let current_line: String = lines.next().expect("Unexpected end of file in verification key!").unwrap();
|
||||
let current_line: String = lines
|
||||
.next()
|
||||
.expect("Unexpected end of file in verification key!")
|
||||
.unwrap();
|
||||
let current_line_split: Vec<&str> = current_line.split("=").collect();
|
||||
assert_eq!(current_line_split.len(), 2);
|
||||
curr_template = vk_ic_index_regex.replace(curr_template.as_str(), format!("{}", x).as_str()).into_owned();
|
||||
curr_template = vk_ic_points_regex.replace(curr_template.as_str(), current_line_split[1].trim()).into_owned();
|
||||
curr_template = vk_ic_index_regex
|
||||
.replace(curr_template.as_str(), format!("{}", x).as_str())
|
||||
.into_owned();
|
||||
curr_template = vk_ic_points_regex
|
||||
.replace(curr_template.as_str(), current_line_split[1].trim())
|
||||
.into_owned();
|
||||
ic_repeat_text.push_str(curr_template.as_str());
|
||||
if x < ic_count - 1 {
|
||||
ic_repeat_text.push_str("\n ");
|
||||
}
|
||||
}
|
||||
template_text = vk_ic_repeat_regex.replace(template_text.as_str(), ic_repeat_text.as_str()).into_owned();
|
||||
template_text = vk_ic_repeat_regex
|
||||
.replace(template_text.as_str(), ic_repeat_text.as_str())
|
||||
.into_owned();
|
||||
|
||||
//write output file
|
||||
let output_path = Path::new(sub_matches.value_of("output").unwrap());
|
||||
|
@ -480,7 +535,9 @@ fn main() {
|
|||
Ok(file) => file,
|
||||
Err(why) => panic!("couldn't create {}: {}", output_path.display(), why),
|
||||
};
|
||||
output_file.write_all(&template_text.as_bytes()).expect("Failed writing output to file.");
|
||||
output_file
|
||||
.write_all(&template_text.as_bytes())
|
||||
.expect("Failed writing output to file.");
|
||||
println!("Finished exporting verifier.");
|
||||
}
|
||||
("generate-proof", Some(sub_matches)) => {
|
||||
|
@ -501,8 +558,11 @@ fn main() {
|
|||
match lines.next() {
|
||||
Some(Ok(ref x)) => {
|
||||
let pairs: Vec<&str> = x.split_whitespace().collect();
|
||||
witness_map.insert(pairs[0].to_string(),FieldPrime::from_dec_string(pairs[1].to_string()));
|
||||
},
|
||||
witness_map.insert(
|
||||
pairs[0].to_string(),
|
||||
FieldPrime::from_dec_string(pairs[1].to_string()),
|
||||
);
|
||||
}
|
||||
None => break,
|
||||
Some(Err(err)) => panic!("Error reading witness: {}", err),
|
||||
}
|
||||
|
@ -519,7 +579,8 @@ fn main() {
|
|||
|
||||
// get private inputs offset
|
||||
let private_inputs_offset;
|
||||
if let Some(Ok(ref o)) = var_lines.nth(1){ // consumes first 2 lines
|
||||
if let Some(Ok(ref o)) = var_lines.nth(1) {
|
||||
// consumes first 2 lines
|
||||
private_inputs_offset = o.parse().expect("Failed parsing private inputs offset");
|
||||
} else {
|
||||
panic!("Error reading private inputs offset");
|
||||
|
@ -527,10 +588,10 @@ fn main() {
|
|||
|
||||
// get variables vector
|
||||
let mut variables: Vec<String> = Vec::new();
|
||||
if let Some(Ok(ref v)) = var_lines.nth(1){
|
||||
if let Some(Ok(ref v)) = var_lines.nth(1) {
|
||||
let iter = v.split_whitespace();
|
||||
for i in iter {
|
||||
variables.push(i.to_string());
|
||||
variables.push(i.to_string());
|
||||
}
|
||||
} else {
|
||||
panic!("Error reading variables.");
|
||||
|
@ -541,7 +602,7 @@ fn main() {
|
|||
let witness: Vec<_> = variables.iter().map(|x| witness_map[x].clone()).collect();
|
||||
|
||||
// split witness into public and private inputs at offset
|
||||
let mut public_inputs: Vec<_>= witness.clone();
|
||||
let mut public_inputs: Vec<_> = witness.clone();
|
||||
let private_inputs: Vec<_> = public_inputs.split_off(private_inputs_offset);
|
||||
|
||||
println!("Public inputs: {:?}", public_inputs);
|
||||
|
@ -551,21 +612,23 @@ fn main() {
|
|||
let proof_path = sub_matches.value_of("proofpath").unwrap();
|
||||
|
||||
// run libsnark
|
||||
#[cfg(feature="libsnark")]{
|
||||
println!("generate-proof successful: {:?}", generate_proof(pk_path, proof_path, public_inputs, private_inputs));
|
||||
#[cfg(feature = "libsnark")]
|
||||
{
|
||||
println!(
|
||||
"generate-proof successful: {:?}",
|
||||
generate_proof(pk_path, proof_path, public_inputs, private_inputs)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
_ => unimplemented!(), // Either no subcommand or one not tested for...
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
extern crate glob;
|
||||
use super::*;
|
||||
use self::glob::glob;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn examples() {
|
||||
|
@ -576,7 +639,7 @@ mod tests {
|
|||
};
|
||||
|
||||
if path.to_str().unwrap().contains("error") {
|
||||
continue
|
||||
continue;
|
||||
}
|
||||
|
||||
println!("Testing {:?}", path);
|
||||
|
@ -584,7 +647,13 @@ mod tests {
|
|||
let file = File::open(path.clone()).unwrap();
|
||||
|
||||
let mut reader = BufReader::new(file);
|
||||
let location = path.parent().unwrap().to_path_buf().into_os_string().into_string().unwrap();
|
||||
let location = path
|
||||
.parent()
|
||||
.unwrap()
|
||||
.to_path_buf()
|
||||
.into_os_string()
|
||||
.into_string()
|
||||
.unwrap();
|
||||
|
||||
let program_flattened: FlatProg<FieldPrime> =
|
||||
compile(&mut reader, Some(location), Some(fs_resolve)).unwrap();
|
||||
|
@ -605,16 +674,23 @@ mod tests {
|
|||
|
||||
let file = File::open(path.clone()).unwrap();
|
||||
|
||||
let location = path.parent().unwrap().to_path_buf().into_os_string().into_string().unwrap();
|
||||
let location = path
|
||||
.parent()
|
||||
.unwrap()
|
||||
.to_path_buf()
|
||||
.into_os_string()
|
||||
.into_string()
|
||||
.unwrap();
|
||||
|
||||
let mut reader = BufReader::new(file);
|
||||
|
||||
let program_flattened: FlatProg<FieldPrime> =
|
||||
|
||||
compile(&mut reader, Some(location), Some(fs_resolve)).unwrap();
|
||||
compile(&mut reader, Some(location), Some(fs_resolve)).unwrap();
|
||||
|
||||
let (..) = r1cs_program(&program_flattened);
|
||||
let _ = program_flattened.get_witness(vec![FieldPrime::from(0)]).unwrap();
|
||||
let _ = program_flattened
|
||||
.get_witness(vec![FieldPrime::from(0)])
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -630,18 +706,25 @@ mod tests {
|
|||
|
||||
let file = File::open(path.clone()).unwrap();
|
||||
|
||||
let location = path.parent().unwrap().to_path_buf().into_os_string().into_string().unwrap();
|
||||
let location = path
|
||||
.parent()
|
||||
.unwrap()
|
||||
.to_path_buf()
|
||||
.into_os_string()
|
||||
.into_string()
|
||||
.unwrap();
|
||||
|
||||
let mut reader = BufReader::new(file);
|
||||
|
||||
let program_flattened: FlatProg<FieldPrime> =
|
||||
|
||||
compile(&mut reader, Some(location), Some(fs_resolve)).unwrap();
|
||||
compile(&mut reader, Some(location), Some(fs_resolve)).unwrap();
|
||||
|
||||
let (..) = r1cs_program(&program_flattened);
|
||||
|
||||
let result = std::panic::catch_unwind(|| {
|
||||
let _ = program_flattened.get_witness(vec![FieldPrime::from(0)]).unwrap();
|
||||
let _ = program_flattened
|
||||
.get_witness(vec![FieldPrime::from(0)])
|
||||
.unwrap();
|
||||
});
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
|
1
zokrates_cli/tests/code/return_array.arguments.json
Normal file
1
zokrates_cli/tests/code/return_array.arguments.json
Normal file
|
@ -0,0 +1 @@
|
|||
[1, 1, 1, 2, 2, 3, 4, 4, 4, 4]
|
2
zokrates_cli/tests/code/return_array.code
Normal file
2
zokrates_cli/tests/code/return_array.code
Normal file
|
@ -0,0 +1,2 @@
|
|||
def main(field[3] a, private field[2] b, field c, private field[4] d) -> (field[3], field[4]):
|
||||
return a, d
|
7
zokrates_cli/tests/code/return_array.expected.witness
Normal file
7
zokrates_cli/tests/code/return_array.expected.witness
Normal file
|
@ -0,0 +1,7 @@
|
|||
~out_0 1
|
||||
~out_1 1
|
||||
~out_2 1
|
||||
~out_3 4
|
||||
~out_4 4
|
||||
~out_5 4
|
||||
~out_6 4
|
|
@ -4,13 +4,13 @@ extern crate serde_json;
|
|||
#[cfg(test)]
|
||||
mod integration {
|
||||
use assert_cli;
|
||||
use std::fs::{File};
|
||||
use std::path::Path;
|
||||
use std::io::prelude::*;
|
||||
use std::fs::{self};
|
||||
use std::panic;
|
||||
use serde_json;
|
||||
use serde_json::Value;
|
||||
use std::fs;
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::panic;
|
||||
use std::path::Path;
|
||||
|
||||
fn setup() {
|
||||
fs::create_dir(".tmp").unwrap();
|
||||
|
@ -18,16 +18,15 @@ mod integration {
|
|||
|
||||
fn teardown() {
|
||||
fs::remove_dir_all(".tmp").unwrap();
|
||||
}
|
||||
|
||||
#[test] #[ignore]
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn run_integration_tests() {
|
||||
// see https://medium.com/@ericdreichert/test-setup-and-teardown-in-rust-without-a-framework-ba32d97aa5ab
|
||||
setup();
|
||||
|
||||
let result = panic::catch_unwind(|| {
|
||||
test_compile_and_witness_dir()
|
||||
});
|
||||
let result = panic::catch_unwind(|| test_compile_and_witness_dir());
|
||||
|
||||
teardown();
|
||||
|
||||
|
@ -41,68 +40,111 @@ mod integration {
|
|||
let entry = entry.unwrap();
|
||||
let path = entry.path();
|
||||
if path.extension().unwrap() == "witness" {
|
||||
let program_name = Path::new(Path::new(path.file_stem().unwrap()).file_stem().unwrap());
|
||||
let program_name =
|
||||
Path::new(Path::new(path.file_stem().unwrap()).file_stem().unwrap());
|
||||
let prog = dir.join(program_name).with_extension("code");
|
||||
let witness = dir.join(program_name).with_extension("expected.witness");
|
||||
let args = dir.join(program_name).with_extension("arguments.json");
|
||||
test_compile_and_witness(program_name.to_str().unwrap(), &prog, &args, &witness);
|
||||
test_compile_and_witness(
|
||||
program_name.to_str().unwrap(),
|
||||
&prog,
|
||||
&args,
|
||||
&witness,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn test_compile_and_witness(program_name: &str, program_path: &Path, arguments_path: &Path, expected_witness_path: &Path) {
|
||||
fn test_compile_and_witness(
|
||||
program_name: &str,
|
||||
program_path: &Path,
|
||||
arguments_path: &Path,
|
||||
expected_witness_path: &Path,
|
||||
) {
|
||||
let tmp_base = Path::new(".tmp/");
|
||||
let test_case_path = tmp_base.join(program_name);
|
||||
let flattened_path = tmp_base.join(program_name).join("out");
|
||||
let witness_path = tmp_base.join(program_name).join("witness");
|
||||
let verification_key_path = tmp_base.join(program_name).join("verification").with_extension("key");
|
||||
let proving_key_path = tmp_base.join(program_name).join("proving").with_extension("key");
|
||||
let variable_information_path = tmp_base.join(program_name).join("variables").with_extension("inf");
|
||||
let verification_contract_path = tmp_base.join(program_name).join("verifier").with_extension("sol");
|
||||
let flattened_path = tmp_base.join(program_name).join("out");
|
||||
let witness_path = tmp_base.join(program_name).join("witness");
|
||||
let verification_key_path = tmp_base
|
||||
.join(program_name)
|
||||
.join("verification")
|
||||
.with_extension("key");
|
||||
let proving_key_path = tmp_base
|
||||
.join(program_name)
|
||||
.join("proving")
|
||||
.with_extension("key");
|
||||
let variable_information_path = tmp_base
|
||||
.join(program_name)
|
||||
.join("variables")
|
||||
.with_extension("inf");
|
||||
let verification_contract_path = tmp_base
|
||||
.join(program_name)
|
||||
.join("verifier")
|
||||
.with_extension("sol");
|
||||
|
||||
// create a tmp folder to store artifacts
|
||||
fs::create_dir(test_case_path).unwrap();
|
||||
|
||||
// prepare compile arguments
|
||||
let compile = vec!["../target/release/zokrates", "compile", "-i", program_path.to_str().unwrap(), "-o", flattened_path.to_str().unwrap(), "--light"];
|
||||
let compile = vec![
|
||||
"../target/release/zokrates",
|
||||
"compile",
|
||||
"-i",
|
||||
program_path.to_str().unwrap(),
|
||||
"-o",
|
||||
flattened_path.to_str().unwrap(),
|
||||
"--light",
|
||||
];
|
||||
|
||||
if program_name.contains("libsnark") {
|
||||
// we don't want to test libsnark integrations if libsnark is not available
|
||||
#[cfg(not(feature = "libsnark"))]
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
// compile
|
||||
assert_cli::Assert::command(&compile)
|
||||
.succeeds()
|
||||
.unwrap();
|
||||
// compile
|
||||
assert_cli::Assert::command(&compile).succeeds().unwrap();
|
||||
|
||||
// COMPUTE_WITNESS
|
||||
let arguments: Value = serde_json::from_reader(File::open(arguments_path).unwrap()).unwrap();
|
||||
let arguments: Value =
|
||||
serde_json::from_reader(File::open(arguments_path).unwrap()).unwrap();
|
||||
|
||||
let arguments_str_list: Vec<String> = arguments.as_array().unwrap().iter().map(|i| match *i {
|
||||
Value::Number(ref n) => n.to_string(),
|
||||
_ => panic!(format!("Cannot read arguments. Check {}", arguments_path.to_str().unwrap()))
|
||||
}).collect();
|
||||
let arguments_str_list: Vec<String> = arguments
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|i| match *i {
|
||||
Value::Number(ref n) => n.to_string(),
|
||||
_ => panic!(format!(
|
||||
"Cannot read arguments. Check {}",
|
||||
arguments_path.to_str().unwrap()
|
||||
)),
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut compute = vec!["../target/release/zokrates", "compute-witness",
|
||||
"-i", flattened_path.to_str().unwrap(),
|
||||
"-o", witness_path.to_str().unwrap(),
|
||||
"-a"];
|
||||
let mut compute = vec![
|
||||
"../target/release/zokrates",
|
||||
"compute-witness",
|
||||
"-i",
|
||||
flattened_path.to_str().unwrap(),
|
||||
"-o",
|
||||
witness_path.to_str().unwrap(),
|
||||
"-a",
|
||||
];
|
||||
|
||||
for arg in arguments_str_list.iter() {
|
||||
compute.push(arg);
|
||||
}
|
||||
|
||||
assert_cli::Assert::command(&compute)
|
||||
.succeeds()
|
||||
.unwrap();
|
||||
|
||||
assert_cli::Assert::command(&compute).succeeds().unwrap();
|
||||
|
||||
// load the expected witness
|
||||
let mut expected_witness_file = File::open(&expected_witness_path).unwrap();
|
||||
let mut expected_witness = String::new();
|
||||
expected_witness_file.read_to_string(&mut expected_witness).unwrap();
|
||||
expected_witness_file
|
||||
.read_to_string(&mut expected_witness)
|
||||
.unwrap();
|
||||
|
||||
// load the actual witness
|
||||
let mut witness_file = File::open(&witness_path).unwrap();
|
||||
|
@ -110,34 +152,57 @@ mod integration {
|
|||
witness_file.read_to_string(&mut witness).unwrap();
|
||||
|
||||
for line in expected_witness.as_str().split("\n") {
|
||||
assert!(witness.contains(line), "Witness generation failed for {}\n\nLine \"{}\" not found in witness", program_path.to_str().unwrap(), line);
|
||||
assert!(
|
||||
witness.contains(line),
|
||||
"Witness generation failed for {}\n\nLine \"{}\" not found in witness",
|
||||
program_path.to_str().unwrap(),
|
||||
line
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "libsnark")]
|
||||
{
|
||||
{
|
||||
// SETUP
|
||||
assert_cli::Assert::command(&["../target/release/zokrates", "setup",
|
||||
"-i", flattened_path.to_str().unwrap(),
|
||||
"-p", proving_key_path.to_str().unwrap(),
|
||||
"-v", verification_key_path.to_str().unwrap(),
|
||||
"-m", variable_information_path.to_str().unwrap()])
|
||||
.succeeds()
|
||||
.unwrap();
|
||||
assert_cli::Assert::command(&[
|
||||
"../target/release/zokrates",
|
||||
"setup",
|
||||
"-i",
|
||||
flattened_path.to_str().unwrap(),
|
||||
"-p",
|
||||
proving_key_path.to_str().unwrap(),
|
||||
"-v",
|
||||
verification_key_path.to_str().unwrap(),
|
||||
"-m",
|
||||
variable_information_path.to_str().unwrap(),
|
||||
])
|
||||
.succeeds()
|
||||
.unwrap();
|
||||
|
||||
// EXPORT-VERIFIER
|
||||
assert_cli::Assert::command(&["../target/release/zokrates", "export-verifier",
|
||||
"-i", verification_key_path.to_str().unwrap(),
|
||||
"-o", verification_contract_path.to_str().unwrap()])
|
||||
.succeeds()
|
||||
.unwrap();
|
||||
assert_cli::Assert::command(&[
|
||||
"../target/release/zokrates",
|
||||
"export-verifier",
|
||||
"-i",
|
||||
verification_key_path.to_str().unwrap(),
|
||||
"-o",
|
||||
verification_contract_path.to_str().unwrap(),
|
||||
])
|
||||
.succeeds()
|
||||
.unwrap();
|
||||
|
||||
// GENERATE-PROOF
|
||||
assert_cli::Assert::command(&["../target/release/zokrates", "generate-proof",
|
||||
"-w", witness_path.to_str().unwrap(),
|
||||
"-p", proving_key_path.to_str().unwrap(),
|
||||
"-i", variable_information_path.to_str().unwrap()])
|
||||
.succeeds()
|
||||
.unwrap();
|
||||
assert_cli::Assert::command(&[
|
||||
"../target/release/zokrates",
|
||||
"generate-proof",
|
||||
"-w",
|
||||
witness_path.to_str().unwrap(),
|
||||
"-p",
|
||||
proving_key_path.to_str().unwrap(),
|
||||
"-i",
|
||||
variable_information_path.to_str().unwrap(),
|
||||
])
|
||||
.succeeds()
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "zokrates_core"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
authors = ["Jacob Eberhardt <jacob.eberhardt@tu-berlin.de>", "Dennis Kuhnert <mail@kyroy.com>"]
|
||||
repository = "https://github.com/JacobEberhardt/ZoKrates"
|
||||
readme = "README.md"
|
||||
|
@ -29,5 +29,5 @@ glob = "0.2.11"
|
|||
assert_cli = "0.5"
|
||||
|
||||
[build-dependencies]
|
||||
gcc = "0.3.41"
|
||||
cc = { version = "1.0", features = ["parallel"] }
|
||||
cmake = "0.1.31"
|
|
@ -1,12 +1,13 @@
|
|||
fn main() {
|
||||
#[cfg(feature = "libsnark")]
|
||||
{
|
||||
extern crate gcc;
|
||||
extern crate cc;
|
||||
extern crate cmake;
|
||||
use std::path::Path;
|
||||
use std::env;
|
||||
|
||||
let libsnark_source_path_string = env::var_os("LIBSNARK_SOURCE_PATH").expect("$LIBSNARK_SOURCE_PATH not set");
|
||||
use std::path::Path;
|
||||
|
||||
let libsnark_source_path_string =
|
||||
env::var_os("LIBSNARK_SOURCE_PATH").expect("$LIBSNARK_SOURCE_PATH not set");
|
||||
let libsnark_source_path = Path::new(&libsnark_source_path_string);
|
||||
|
||||
let libsnark = cmake::Config::new(libsnark_source_path)
|
||||
|
@ -17,7 +18,7 @@ fn main() {
|
|||
.define("BINARY_OUTPUT", "ON")
|
||||
.build();
|
||||
|
||||
gcc::Build::new()
|
||||
cc::Build::new()
|
||||
.cpp(true)
|
||||
.debug(cfg!(debug_assertions))
|
||||
.flag("-std=c++11")
|
||||
|
@ -28,7 +29,7 @@ fn main() {
|
|||
.file("lib/wraplibsnark.cpp")
|
||||
.compile("libwraplibsnark.a");
|
||||
|
||||
gcc::Build::new()
|
||||
cc::Build::new()
|
||||
.cpp(true)
|
||||
.flag("-std=c++11")
|
||||
.include(libsnark_source_path)
|
||||
|
@ -46,11 +47,13 @@ fn main() {
|
|||
println!("cargo:rustc-link-lib=gmp");
|
||||
println!("cargo:rustc-link-lib=gmpxx");
|
||||
|
||||
#[cfg(debug_assertions)] {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
println!("cargo:rustc-link-lib=static=snarkd");
|
||||
println!("cargo:rustc-link-lib=static=ffd");
|
||||
}
|
||||
#[cfg(not(debug_assertions))] {
|
||||
#[cfg(not(debug_assertions))]
|
||||
{
|
||||
println!("cargo:rustc-link-lib=static=snark");
|
||||
println!("cargo:rustc-link-lib=static=ff");
|
||||
}
|
||||
|
|
|
@ -38,16 +38,16 @@ std::string HexStringFromLibsnarkBigint(libff::bigint<libff::alt_bn128_r_limbs>
|
|||
uint8_t x[32];
|
||||
for (unsigned i = 0; i < 4; i++)
|
||||
for (unsigned j = 0; j < 8; j++)
|
||||
x[i * 8 + j] = uint8_t(uint64_t(_x.data[3 - i]) >> (8 * (7 - j)));
|
||||
x[i * 8 + j] = uint8_t(uint64_t(_x.data[3 - i]) >> (8 * (7 - j)));
|
||||
|
||||
std::stringstream ss;
|
||||
ss << std::setfill('0');
|
||||
for (unsigned i = 0; i<32; i++) {
|
||||
ss << std::hex << std::setw(2) << (int)x[i];
|
||||
}
|
||||
std::stringstream ss;
|
||||
ss << std::setfill('0');
|
||||
for (unsigned i = 0; i<32; i++) {
|
||||
ss << std::hex << std::setw(2) << (int)x[i];
|
||||
}
|
||||
|
||||
std::string str = ss.str();
|
||||
return str.erase(0, min(str.find_first_not_of('0'), str.size()-1));
|
||||
std::string str = ss.str();
|
||||
return str.erase(0, min(str.find_first_not_of('0'), str.size()-1));
|
||||
}
|
||||
|
||||
std::string outputPointG1AffineAsHex(libff::alt_bn128_G1 _p)
|
||||
|
|
|
@ -8,43 +8,45 @@
|
|||
pub mod parameter;
|
||||
pub mod variable;
|
||||
|
||||
use types::Signature;
|
||||
pub use absy::parameter::Parameter;
|
||||
pub use absy::variable::Variable;
|
||||
use types::Signature;
|
||||
|
||||
use std::fmt;
|
||||
use field::Field;
|
||||
use imports::Import;
|
||||
use flat_absy::*;
|
||||
use imports::Import;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq)]
|
||||
pub struct Prog<T: Field> {
|
||||
/// Functions of the program
|
||||
pub functions: Vec<Function<T>>,
|
||||
pub imports: Vec<Import>,
|
||||
pub imported_functions: Vec<FlatFunction<T>>
|
||||
pub imported_functions: Vec<FlatFunction<T>>,
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Display for Prog<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut res = vec![];
|
||||
res.extend(self.imports
|
||||
res.extend(
|
||||
self.imports
|
||||
.iter()
|
||||
.map(|x| format!("{}", x))
|
||||
.collect::<Vec<_>>());
|
||||
res.extend(self.imported_functions
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
res.extend(
|
||||
self.imported_functions
|
||||
.iter()
|
||||
.map(|x| format!("{}", x))
|
||||
.collect::<Vec<_>>());
|
||||
res.extend(self.functions
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
res.extend(
|
||||
self.functions
|
||||
.iter()
|
||||
.map(|x| format!("{}", x))
|
||||
.collect::<Vec<_>>());
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
res.join("\n")
|
||||
)
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
write!(f, "{}", res.join("\n"))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,7 +125,7 @@ impl<T: Field> fmt::Debug for Function<T> {
|
|||
#[derive(Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum Assignee<T: Field> {
|
||||
Identifier(String),
|
||||
ArrayElement(Box<Assignee<T>>, Box<Expression<T>>)
|
||||
ArrayElement(Box<Assignee<T>>, Box<Expression<T>>),
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Debug for Assignee<T> {
|
||||
|
@ -146,8 +148,8 @@ impl<T: Field> From<Expression<T>> for Assignee<T> {
|
|||
match e {
|
||||
Expression::Select(box Expression::Identifier(id), box e2) => {
|
||||
Assignee::ArrayElement(box Assignee::Identifier(id), box e2)
|
||||
},
|
||||
_ => panic!("only use expression to assignee for elements like foo[bar]")
|
||||
}
|
||||
_ => panic!("only use expression to assignee for elements like foo[bar]"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -184,7 +186,7 @@ impl<T: Field> fmt::Display for Statement<T> {
|
|||
}
|
||||
}
|
||||
write!(f, " = {}", rhs)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -207,7 +209,7 @@ impl<T: Field> fmt::Debug for Statement<T> {
|
|||
}
|
||||
Statement::MultipleDefinition(ref lhs, ref rhs) => {
|
||||
write!(f, "MultipleDefinition({:?}, {:?})", lhs, rhs)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -248,9 +250,7 @@ impl<T: Field> fmt::Display for Expression<T> {
|
|||
Expression::IfElse(ref condition, ref consequent, ref alternative) => write!(
|
||||
f,
|
||||
"if {} then {} else {} fi",
|
||||
condition,
|
||||
consequent,
|
||||
alternative
|
||||
condition, consequent, alternative
|
||||
),
|
||||
Expression::FunctionCall(ref i, ref p) => {
|
||||
try!(write!(f, "{}(", i,));
|
||||
|
@ -261,7 +261,7 @@ impl<T: Field> fmt::Display for Expression<T> {
|
|||
}
|
||||
}
|
||||
write!(f, ")")
|
||||
},
|
||||
}
|
||||
Expression::Lt(ref lhs, ref rhs) => write!(f, "{} < {}", lhs, rhs),
|
||||
Expression::Le(ref lhs, ref rhs) => write!(f, "{} <= {}", lhs, rhs),
|
||||
Expression::Eq(ref lhs, ref rhs) => write!(f, "{} == {}", lhs, rhs),
|
||||
|
@ -278,7 +278,7 @@ impl<T: Field> fmt::Display for Expression<T> {
|
|||
}
|
||||
}
|
||||
write!(f, "]")
|
||||
},
|
||||
}
|
||||
Expression::Select(ref array, ref index) => write!(f, "{}[{}]", array, index),
|
||||
Expression::Or(ref lhs, ref rhs) => write!(f, "{} || {}", lhs, rhs),
|
||||
}
|
||||
|
@ -298,15 +298,13 @@ impl<T: Field> fmt::Debug for Expression<T> {
|
|||
Expression::IfElse(ref condition, ref consequent, ref alternative) => write!(
|
||||
f,
|
||||
"IfElse({:?}, {:?}, {:?})",
|
||||
condition,
|
||||
consequent,
|
||||
alternative
|
||||
condition, consequent, alternative
|
||||
),
|
||||
Expression::FunctionCall(ref i, ref p) => {
|
||||
try!(write!(f, "FunctionCall({:?}, (", i));
|
||||
try!(f.debug_list().entries(p.iter()).finish());
|
||||
write!(f, ")")
|
||||
},
|
||||
}
|
||||
Expression::Lt(ref lhs, ref rhs) => write!(f, "{} < {}", lhs, rhs),
|
||||
Expression::Le(ref lhs, ref rhs) => write!(f, "{} <= {}", lhs, rhs),
|
||||
Expression::Eq(ref lhs, ref rhs) => write!(f, "{} == {}", lhs, rhs),
|
||||
|
@ -318,7 +316,7 @@ impl<T: Field> fmt::Debug for Expression<T> {
|
|||
try!(write!(f, "InlineArray(["));
|
||||
try!(f.debug_list().entries(exprs.iter()).finish());
|
||||
write!(f, "]")
|
||||
},
|
||||
}
|
||||
Expression::Select(ref array, ref index) => write!(f, "{}[{}]", array, index),
|
||||
Expression::Or(ref lhs, ref rhs) => write!(f, "{} || {}", lhs, rhs),
|
||||
}
|
||||
|
@ -327,13 +325,13 @@ impl<T: Field> fmt::Debug for Expression<T> {
|
|||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ExpressionList<T: Field> {
|
||||
pub expressions: Vec<Expression<T>>
|
||||
pub expressions: Vec<Expression<T>>,
|
||||
}
|
||||
|
||||
impl<T: Field> ExpressionList<T> {
|
||||
pub fn new() -> ExpressionList<T> {
|
||||
ExpressionList {
|
||||
expressions: vec![]
|
||||
expressions: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use std::fmt;
|
||||
use absy::Variable;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Parameter {
|
||||
|
@ -8,19 +8,19 @@ pub struct Parameter {
|
|||
}
|
||||
|
||||
impl Parameter {
|
||||
pub fn public(v: Variable) -> Self {
|
||||
Parameter {
|
||||
id: v,
|
||||
private: true
|
||||
}
|
||||
}
|
||||
pub fn public(v: Variable) -> Self {
|
||||
Parameter {
|
||||
id: v,
|
||||
private: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn private(v: Variable) -> Self {
|
||||
Parameter {
|
||||
id: v,
|
||||
private: false
|
||||
}
|
||||
}
|
||||
pub fn private(v: Variable) -> Self {
|
||||
Parameter {
|
||||
id: v,
|
||||
private: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Parameter {
|
||||
|
|
|
@ -4,28 +4,28 @@ use types::Type;
|
|||
#[derive(Serialize, Deserialize, Clone, PartialEq, Hash, Eq)]
|
||||
pub struct Variable {
|
||||
pub id: String,
|
||||
pub _type: Type
|
||||
pub _type: Type,
|
||||
}
|
||||
|
||||
impl Variable {
|
||||
pub fn new<S: Into<String>>(id: S, t: Type) -> Variable {
|
||||
Variable {
|
||||
id: id.into(),
|
||||
_type: t
|
||||
_type: t,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn field_element<S: Into<String>>(id: S) -> Variable {
|
||||
Variable {
|
||||
id: id.into(),
|
||||
_type: Type::FieldElement
|
||||
_type: Type::FieldElement,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn boolean<S: Into<String>>(id: S) -> Variable {
|
||||
Variable {
|
||||
id: id.into(),
|
||||
_type: Type::Boolean
|
||||
_type: Type::Boolean,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,22 +43,12 @@ impl Variable {
|
|||
|
||||
impl fmt::Display for Variable {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{} {}",
|
||||
self._type,
|
||||
self.id,
|
||||
)
|
||||
write!(f, "{} {}", self._type, self.id,)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Variable {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"Variable(type: {:?}, id: {:?})",
|
||||
self._type,
|
||||
self.id,
|
||||
)
|
||||
write!(f, "Variable(type: {:?}, id: {:?})", self._type, self.id,)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,72 +3,84 @@
|
|||
//! @file compile.rs
|
||||
//! @author Thibaut Schaeffer <thibaut@schaeff.fr>
|
||||
//! @date 2018
|
||||
use std::io::{BufRead};
|
||||
use std::fmt;
|
||||
use field::{Field};
|
||||
use absy::{Prog};
|
||||
use flat_absy::{FlatProg};
|
||||
use parser::{self, parse_program};
|
||||
use imports::{self, Importer};
|
||||
use semantics::{self, Checker};
|
||||
use optimizer::{Optimizer};
|
||||
use absy::Prog;
|
||||
use field::Field;
|
||||
use flat_absy::FlatProg;
|
||||
use flatten::Flattener;
|
||||
use std::io::{self};
|
||||
use imports::{self, Importer};
|
||||
use optimizer::Optimizer;
|
||||
use parser::{self, parse_program};
|
||||
use semantics::{self, Checker};
|
||||
use static_analysis::Analyse;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use std::io::BufRead;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CompileError<T: Field> {
|
||||
ParserError(parser::Error<T>),
|
||||
ImportError(imports::Error),
|
||||
SemanticError(semantics::Error),
|
||||
ReadError(io::Error),
|
||||
ParserError(parser::Error<T>),
|
||||
ImportError(imports::Error),
|
||||
SemanticError(semantics::Error),
|
||||
ReadError(io::Error),
|
||||
}
|
||||
|
||||
impl<T: Field> From<parser::Error<T>> for CompileError<T> {
|
||||
fn from(error: parser::Error<T>) -> Self {
|
||||
CompileError::ParserError(error)
|
||||
}
|
||||
fn from(error: parser::Error<T>) -> Self {
|
||||
CompileError::ParserError(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> From<imports::Error> for CompileError<T> {
|
||||
fn from(error: imports::Error) -> Self {
|
||||
CompileError::ImportError(error)
|
||||
}
|
||||
fn from(error: imports::Error) -> Self {
|
||||
CompileError::ImportError(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> From<io::Error> for CompileError<T> {
|
||||
fn from(error: io::Error) -> Self {
|
||||
CompileError::ReadError(error)
|
||||
}
|
||||
fn from(error: io::Error) -> Self {
|
||||
CompileError::ReadError(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> From<semantics::Error> for CompileError<T> {
|
||||
fn from(error: semantics::Error) -> Self {
|
||||
CompileError::SemanticError(error)
|
||||
}
|
||||
fn from(error: semantics::Error) -> Self {
|
||||
CompileError::SemanticError(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Display for CompileError<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let res = match *self {
|
||||
CompileError::ParserError(ref e) => format!("Syntax error: {}", e),
|
||||
CompileError::SemanticError(ref e) => format!("Semantic error: {}", e),
|
||||
CompileError::ReadError(ref e) => format!("Read error: {}", e),
|
||||
CompileError::ImportError(ref e) => format!("Import error: {}", e),
|
||||
};
|
||||
write!(f, "{}", res)
|
||||
}
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let res = match *self {
|
||||
CompileError::ParserError(ref e) => format!("Syntax error: {}", e),
|
||||
CompileError::SemanticError(ref e) => format!("Semantic error: {}", e),
|
||||
CompileError::ReadError(ref e) => format!("Read error: {}", e),
|
||||
CompileError::ImportError(ref e) => format!("Import error: {}", e),
|
||||
};
|
||||
write!(f, "{}", res)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compile<T: Field, R: BufRead, S: BufRead, E: Into<imports::Error>>(reader: &mut R, location: Option<String>, resolve_option: Option<fn(&Option<String>, &String) -> Result<(S, String, String), E>>) -> Result<FlatProg<T>, CompileError<T>> {
|
||||
let compiled = compile_aux(reader, location, resolve_option)?;
|
||||
Ok(Optimizer::new().optimize_program(compiled))
|
||||
pub fn compile<T: Field, R: BufRead, S: BufRead, E: Into<imports::Error>>(
|
||||
reader: &mut R,
|
||||
location: Option<String>,
|
||||
resolve_option: Option<fn(&Option<String>, &String) -> Result<(S, String, String), E>>,
|
||||
) -> Result<FlatProg<T>, CompileError<T>> {
|
||||
let compiled = compile_aux(reader, location, resolve_option)?;
|
||||
Ok(Optimizer::new().optimize_program(compiled))
|
||||
}
|
||||
|
||||
pub fn compile_aux<T: Field, R: BufRead, S: BufRead, E: Into<imports::Error>>(reader: &mut R, location: Option<String>, resolve_option: Option<fn(&Option<String>, &String) -> Result<(S, String, String), E>>) -> Result<FlatProg<T>, CompileError<T>> {
|
||||
pub fn compile_aux<T: Field, R: BufRead, S: BufRead, E: Into<imports::Error>>(
|
||||
reader: &mut R,
|
||||
location: Option<String>,
|
||||
resolve_option: Option<fn(&Option<String>, &String) -> Result<(S, String, String), E>>,
|
||||
) -> Result<FlatProg<T>, CompileError<T>> {
|
||||
let program_ast_without_imports: Prog<T> = parse_program(reader)?;
|
||||
|
||||
let program_ast = Importer::new().apply_imports(program_ast_without_imports, location.clone(), resolve_option)?;
|
||||
|
||||
let program_ast = Importer::new().apply_imports(
|
||||
program_ast_without_imports,
|
||||
location.clone(),
|
||||
resolve_option,
|
||||
)?;
|
||||
|
||||
// check semantics
|
||||
let typed_ast = Checker::new().check_program(program_ast)?;
|
||||
|
@ -77,8 +89,7 @@ pub fn compile_aux<T: Field, R: BufRead, S: BufRead, E: Into<imports::Error>>(re
|
|||
let typed_ast = typed_ast.analyse();
|
||||
|
||||
// flatten input program
|
||||
let program_flattened =
|
||||
Flattener::new(T::get_required_bits()).flatten_program(typed_ast);
|
||||
let program_flattened = Flattener::new(T::get_required_bits()).flatten_program(typed_ast);
|
||||
|
||||
// analyse (constant propagation after call resolution)
|
||||
let program_flattened = program_flattened.analyse();
|
||||
|
@ -88,28 +99,51 @@ pub fn compile_aux<T: Field, R: BufRead, S: BufRead, E: Into<imports::Error>>(re
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use field::FieldPrime;
|
||||
use std::io::{BufReader, Empty};
|
||||
use super::*;
|
||||
use field::FieldPrime;
|
||||
use std::io::{BufReader, Empty};
|
||||
|
||||
#[test]
|
||||
fn no_resolver_with_imports() {
|
||||
let mut r = BufReader::new(r#"
|
||||
#[test]
|
||||
fn no_resolver_with_imports() {
|
||||
let mut r = BufReader::new(
|
||||
r#"
|
||||
import "./path/to/file" as foo
|
||||
def main() -> (field):
|
||||
return foo()
|
||||
"#.as_bytes());
|
||||
let res: Result<FlatProg<FieldPrime>, CompileError<FieldPrime>> = compile(&mut r, Some(String::from("./path/to/file")), None::<fn(&Option<String>, &String) -> Result<(BufReader<Empty>, String, String), io::Error>>);
|
||||
assert_eq!(format!("{}", res.unwrap_err()), "Import error: Can't resolve import without a resolver".to_string());
|
||||
}
|
||||
"#
|
||||
.as_bytes(),
|
||||
);
|
||||
let res: Result<FlatProg<FieldPrime>, CompileError<FieldPrime>> = compile(
|
||||
&mut r,
|
||||
Some(String::from("./path/to/file")),
|
||||
None::<
|
||||
fn(&Option<String>, &String)
|
||||
-> Result<(BufReader<Empty>, String, String), io::Error>,
|
||||
>,
|
||||
);
|
||||
assert_eq!(
|
||||
format!("{}", res.unwrap_err()),
|
||||
"Import error: Can't resolve import without a resolver".to_string()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_resolver_without_imports() {
|
||||
let mut r = BufReader::new(r#"
|
||||
#[test]
|
||||
fn no_resolver_without_imports() {
|
||||
let mut r = BufReader::new(
|
||||
r#"
|
||||
def main() -> (field):
|
||||
return 1
|
||||
"#.as_bytes());
|
||||
let res: Result<FlatProg<FieldPrime>, CompileError<FieldPrime>> = compile(&mut r, Some(String::from("./path/to/file")), None::<fn(&Option<String>, &String) -> Result<(BufReader<Empty>, String, String), io::Error>>);
|
||||
assert!(res.is_ok());
|
||||
}
|
||||
}
|
||||
"#
|
||||
.as_bytes(),
|
||||
);
|
||||
let res: Result<FlatProg<FieldPrime>, CompileError<FieldPrime>> = compile(
|
||||
&mut r,
|
||||
Some(String::from("./path/to/file")),
|
||||
None::<
|
||||
fn(&Option<String>, &String)
|
||||
-> Result<(BufReader<Empty>, String, String), io::Error>,
|
||||
>,
|
||||
);
|
||||
assert!(res.is_ok());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,18 +4,22 @@
|
|||
// @author Jacob Eberhardt <jacob.eberhardt@tu-berlin.de>
|
||||
// @date 2017
|
||||
|
||||
use std::hash::Hash;
|
||||
use num::{Num, Integer, One, Zero};
|
||||
use num::{Integer, Num, One, Zero};
|
||||
use num_bigint::{BigInt, BigUint, Sign, ToBigInt};
|
||||
use serde::de::{Deserialize, Deserializer, Visitor};
|
||||
use serde::{Serialize, Serializer};
|
||||
use std::convert::From;
|
||||
use std::ops::{Add, Div, Mul, Sub};
|
||||
use std::fmt;
|
||||
use std::fmt::{Debug, Display};
|
||||
use serde::{Serialize, Serializer};
|
||||
use serde::de::{Deserialize, Deserializer, Visitor};
|
||||
use std::hash::Hash;
|
||||
use std::ops::{Add, Div, Mul, Sub};
|
||||
|
||||
lazy_static! {
|
||||
static ref P: BigInt = BigInt::parse_bytes(b"21888242871839275222246405745257275088548364400416034343698204186575808495617", 10).unwrap();
|
||||
static ref P: BigInt = BigInt::parse_bytes(
|
||||
b"21888242871839275222246405745257275088548364400416034343698204186575808495617",
|
||||
10
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub trait Pow<RHS> {
|
||||
|
@ -23,8 +27,8 @@ pub trait Pow<RHS> {
|
|||
fn pow(self, RHS) -> Self::Output;
|
||||
}
|
||||
|
||||
pub trait Field
|
||||
: From<i32>
|
||||
pub trait Field:
|
||||
From<i32>
|
||||
+ From<u32>
|
||||
+ From<usize>
|
||||
+ for<'a> From<&'a str>
|
||||
|
@ -47,7 +51,8 @@ pub trait Field
|
|||
+ for<'a> Div<&'a Self, Output = Self>
|
||||
+ Pow<usize, Output = Self>
|
||||
+ Pow<Self, Output = Self>
|
||||
+ for<'a> Pow<&'a Self, Output = Self> {
|
||||
+ for<'a> Pow<&'a Self, Output = Self>
|
||||
{
|
||||
/// Returns this `Field`'s contents as little-endian byte vector
|
||||
fn into_byte_vector(&self) -> Vec<u8>;
|
||||
/// Returns an element of this `Field` from a little-endian byte vector
|
||||
|
@ -81,7 +86,9 @@ impl Field for FieldPrime {
|
|||
|
||||
fn from_byte_vector(bytes: Vec<u8>) -> Self {
|
||||
let uval = BigUint::from_bytes_le(bytes.as_slice());
|
||||
FieldPrime{value: BigInt::from_biguint(Sign::Plus, uval)}
|
||||
FieldPrime {
|
||||
value: BigInt::from_biguint(Sign::Plus, uval),
|
||||
}
|
||||
}
|
||||
|
||||
fn to_dec_string(&self) -> String {
|
||||
|
@ -89,7 +96,9 @@ impl Field for FieldPrime {
|
|||
}
|
||||
|
||||
fn from_dec_string(val: String) -> Self {
|
||||
FieldPrime{value: BigInt::from_str_radix(val.as_str(), 10).unwrap()}
|
||||
FieldPrime {
|
||||
value: BigInt::from_str_radix(val.as_str(), 10).unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
fn inverse_mul(&self) -> FieldPrime {
|
||||
|
@ -309,7 +318,8 @@ impl<'a> Pow<&'a FieldPrime> for FieldPrime {
|
|||
// custom serde serialization
|
||||
impl Serialize for FieldPrime {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: Serializer
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
// serializer.serialize_bytes(&(*self.value.to_biguint().to_bytes_le().as_slice()))
|
||||
serializer.serialize_bytes(&(*self.into_byte_vector().as_slice()))
|
||||
|
@ -322,7 +332,7 @@ struct FieldPrimeVisitor;
|
|||
|
||||
impl FieldPrimeVisitor {
|
||||
fn new() -> Self {
|
||||
FieldPrimeVisitor{}
|
||||
FieldPrimeVisitor {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -335,14 +345,14 @@ impl<'de> Visitor<'de> for FieldPrimeVisitor {
|
|||
|
||||
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E> {
|
||||
let val = BigUint::from_bytes_le(v).to_bigint().unwrap();
|
||||
Ok(FieldPrime{value: val})
|
||||
Ok(FieldPrime { value: val })
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for FieldPrime {
|
||||
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where D: Deserializer<'de>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_bytes(FieldPrimeVisitor::new())
|
||||
}
|
||||
|
@ -380,7 +390,7 @@ mod tests {
|
|||
#[cfg(test)]
|
||||
mod field_prime {
|
||||
use super::*;
|
||||
use bincode::{serialize, deserialize , Infinite};
|
||||
use bincode::{deserialize, serialize, Infinite};
|
||||
|
||||
#[test]
|
||||
fn positive_number() {
|
||||
|
@ -522,9 +532,8 @@ mod tests {
|
|||
.unwrap(),
|
||||
(FieldPrime::from(
|
||||
"21888242871839225222246405785257275088694311157297823662689037894645225727"
|
||||
) *
|
||||
FieldPrime::from("218882428715392752222464057432572755886923"))
|
||||
.value
|
||||
) * FieldPrime::from("218882428715392752222464057432572755886923"))
|
||||
.value
|
||||
);
|
||||
assert_eq!(
|
||||
"6042471409729479866150380306128222617399890671095126975526159292198160466142"
|
||||
|
@ -532,8 +541,7 @@ mod tests {
|
|||
.unwrap(),
|
||||
(FieldPrime::from(
|
||||
"21888242871839225222246405785257275088694311157297823662689037894645225727"
|
||||
) *
|
||||
&FieldPrime::from("218882428715392752222464057432572755886923"))
|
||||
) * &FieldPrime::from("218882428715392752222464057432572755886923"))
|
||||
.value
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use std::collections::HashMap;
|
||||
use flat_absy::flat_variable::FlatVariable;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
|
@ -10,10 +10,7 @@ pub struct FlatParameter {
|
|||
|
||||
impl FlatParameter {
|
||||
fn new(id: FlatVariable, private: bool) -> Self {
|
||||
FlatParameter {
|
||||
id,
|
||||
private
|
||||
}
|
||||
FlatParameter { id, private }
|
||||
}
|
||||
|
||||
pub fn public(v: FlatVariable) -> Self {
|
||||
|
@ -39,10 +36,13 @@ impl fmt::Debug for FlatParameter {
|
|||
}
|
||||
|
||||
impl FlatParameter {
|
||||
pub fn apply_direct_substitution(self, substitution: &HashMap<FlatVariable, FlatVariable>) -> FlatParameter {
|
||||
pub fn apply_direct_substitution(
|
||||
self,
|
||||
substitution: &HashMap<FlatVariable, FlatVariable>,
|
||||
) -> FlatParameter {
|
||||
FlatParameter {
|
||||
id: substitution.get(&self.id).unwrap().clone(),
|
||||
private: self.private
|
||||
private: self.private,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,14 +18,12 @@ impl FlatVariable {
|
|||
}
|
||||
|
||||
pub fn one() -> Self {
|
||||
FlatVariable {
|
||||
id: 0,
|
||||
}
|
||||
FlatVariable { id: 0 }
|
||||
}
|
||||
|
||||
pub fn public(id: usize) -> Self {
|
||||
FlatVariable {
|
||||
id: - (id as isize) - 1,
|
||||
id: -(id as isize) - 1,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,7 +38,7 @@ impl fmt::Display for FlatVariable {
|
|||
match self.id {
|
||||
0 => write!(f, "~one"),
|
||||
i if i > 0 => write!(f, "_{}", i + 1),
|
||||
i => write!(f, "~out_{}", - (i + 1))
|
||||
i => write!(f, "~out_{}", -(i + 1)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,10 +50,14 @@ impl fmt::Debug for FlatVariable {
|
|||
}
|
||||
|
||||
impl FlatVariable {
|
||||
pub fn apply_substitution(self, substitution: &HashMap<FlatVariable, FlatVariable>, should_fallback: bool) -> Self {
|
||||
pub fn apply_substitution(
|
||||
self,
|
||||
substitution: &HashMap<FlatVariable, FlatVariable>,
|
||||
should_fallback: bool,
|
||||
) -> Self {
|
||||
match should_fallback {
|
||||
true => substitution.get(&self).unwrap_or(&self).clone(),
|
||||
false => substitution.get(&self).unwrap().clone()
|
||||
false => substitution.get(&self).unwrap().clone(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,8 +77,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn public() {
|
||||
assert_eq!(FlatVariable::public(0).id, - 1);
|
||||
assert_eq!(FlatVariable::public(42).id, - 43);
|
||||
assert_eq!(FlatVariable::public(0).id, -1);
|
||||
assert_eq!(FlatVariable::public(42).id, -43);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -84,4 +86,4 @@ mod tests {
|
|||
assert_eq!(FlatVariable::new(0).id, 1);
|
||||
assert_eq!(FlatVariable::new(42).id, 43);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,13 +11,13 @@ pub mod flat_variable;
|
|||
pub use self::flat_parameter::FlatParameter;
|
||||
pub use self::flat_variable::FlatVariable;
|
||||
|
||||
use types::Signature;
|
||||
use std::fmt;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use field::Field;
|
||||
use helpers::{DirectiveStatement, Executable};
|
||||
#[cfg(feature = "libsnark")]
|
||||
use standard;
|
||||
use helpers::{DirectiveStatement, Executable};
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::fmt;
|
||||
use types::Signature;
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct FlatProg<T: Field> {
|
||||
|
@ -25,7 +25,6 @@ pub struct FlatProg<T: Field> {
|
|||
pub functions: Vec<FlatFunction<T>>,
|
||||
}
|
||||
|
||||
|
||||
impl<T: Field> FlatProg<T> {
|
||||
// only main flattened function is relevant here, as all other functions are unrolled into it
|
||||
#[allow(dead_code)] // I don't want to remove this
|
||||
|
@ -67,12 +66,11 @@ impl<T: Field> fmt::Debug for FlatProg<T> {
|
|||
impl<T: Field> From<standard::DirectiveR1CS> for FlatProg<T> {
|
||||
fn from(dr1cs: standard::DirectiveR1CS) -> Self {
|
||||
FlatProg {
|
||||
functions: vec![dr1cs.into()]
|
||||
functions: vec![dr1cs.into()],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq)]
|
||||
pub struct FlatFunction<T: Field> {
|
||||
/// Name of the program
|
||||
|
@ -105,28 +103,28 @@ impl<T: Field> FlatFunction<T> {
|
|||
FlatStatement::Definition(ref id, ref expr) => {
|
||||
let s = expr.solve(&mut witness);
|
||||
witness.insert(id.clone(), s);
|
||||
},
|
||||
}
|
||||
FlatStatement::Condition(ref lhs, ref rhs) => {
|
||||
if lhs.solve(&mut witness) != rhs.solve(&mut witness) {
|
||||
return Err(Error {
|
||||
message: format!("Condition not satisfied: {} should equal {}", lhs, rhs)
|
||||
message: format!(
|
||||
"Condition not satisfied: {} should equal {}",
|
||||
lhs, rhs
|
||||
),
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
FlatStatement::Directive(ref d) => {
|
||||
let input_values: Vec<T> = d.inputs.iter().map(|i| i.solve(&mut witness)).collect();
|
||||
let input_values: Vec<T> =
|
||||
d.inputs.iter().map(|i| i.solve(&mut witness)).collect();
|
||||
match d.helper.execute(&input_values) {
|
||||
Ok(res) => {
|
||||
for (i, o) in d.outputs.iter().enumerate() {
|
||||
witness.insert(o.clone(), res[i].clone());
|
||||
}
|
||||
continue;
|
||||
},
|
||||
Err(message) => {
|
||||
return Err(Error {
|
||||
message: message
|
||||
})
|
||||
}
|
||||
Err(message) => return Err(Error { message: message }),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -187,7 +185,7 @@ pub enum FlatStatement<T: Field> {
|
|||
Return(FlatExpressionList<T>),
|
||||
Condition(FlatExpression<T>, FlatExpression<T>),
|
||||
Definition(FlatVariable, FlatExpression<T>),
|
||||
Directive(DirectiveStatement<T>)
|
||||
Directive(DirectiveStatement<T>),
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Display for FlatStatement<T> {
|
||||
|
@ -206,47 +204,63 @@ impl<T: Field> fmt::Debug for FlatStatement<T> {
|
|||
match *self {
|
||||
FlatStatement::Definition(ref lhs, ref rhs) => write!(f, "{} = {}", lhs, rhs),
|
||||
FlatStatement::Return(ref expr) => write!(f, "FlatReturn({:?})", expr),
|
||||
FlatStatement::Condition(ref lhs, ref rhs) => write!(f, "FlatCondition({:?}, {:?})", lhs, rhs),
|
||||
FlatStatement::Condition(ref lhs, ref rhs) => {
|
||||
write!(f, "FlatCondition({:?}, {:?})", lhs, rhs)
|
||||
}
|
||||
FlatStatement::Directive(ref d) => write!(f, "{:?}", d),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> FlatStatement<T> {
|
||||
pub fn apply_recursive_substitution(self, substitution: &HashMap<FlatVariable, FlatVariable>) -> FlatStatement<T> {
|
||||
pub fn apply_recursive_substitution(
|
||||
self,
|
||||
substitution: &HashMap<FlatVariable, FlatVariable>,
|
||||
) -> FlatStatement<T> {
|
||||
self.apply_substitution(substitution, true)
|
||||
}
|
||||
|
||||
pub fn apply_direct_substitution(self, substitution: &HashMap<FlatVariable, FlatVariable>) -> FlatStatement<T> {
|
||||
pub fn apply_direct_substitution(
|
||||
self,
|
||||
substitution: &HashMap<FlatVariable, FlatVariable>,
|
||||
) -> FlatStatement<T> {
|
||||
self.apply_substitution(substitution, false)
|
||||
}
|
||||
|
||||
fn apply_substitution(self, substitution: &HashMap<FlatVariable, FlatVariable>, should_fallback: bool) -> FlatStatement<T> {
|
||||
fn apply_substitution(
|
||||
self,
|
||||
substitution: &HashMap<FlatVariable, FlatVariable>,
|
||||
should_fallback: bool,
|
||||
) -> FlatStatement<T> {
|
||||
match self {
|
||||
FlatStatement::Definition(id, x) => FlatStatement::Definition(
|
||||
id.apply_substitution(substitution, should_fallback),
|
||||
x.apply_substitution(substitution, should_fallback)
|
||||
id.apply_substitution(substitution, should_fallback),
|
||||
x.apply_substitution(substitution, should_fallback),
|
||||
),
|
||||
FlatStatement::Return(x) => FlatStatement::Return(
|
||||
x.apply_substitution(substitution, should_fallback)
|
||||
FlatStatement::Return(x) => {
|
||||
FlatStatement::Return(x.apply_substitution(substitution, should_fallback))
|
||||
}
|
||||
FlatStatement::Condition(x, y) => FlatStatement::Condition(
|
||||
x.apply_substitution(substitution, should_fallback),
|
||||
y.apply_substitution(substitution, should_fallback),
|
||||
),
|
||||
FlatStatement::Condition(x, y) => {
|
||||
FlatStatement::Condition(
|
||||
x.apply_substitution(substitution, should_fallback),
|
||||
y.apply_substitution(substitution, should_fallback)
|
||||
)
|
||||
},
|
||||
FlatStatement::Directive(d) => {
|
||||
let outputs = d.outputs.into_iter().map(|o| o.apply_substitution(substitution, should_fallback)).collect();
|
||||
let inputs = d.inputs.into_iter().map(|i| i.apply_substitution(substitution, should_fallback)).collect();
|
||||
let outputs = d
|
||||
.outputs
|
||||
.into_iter()
|
||||
.map(|o| o.apply_substitution(substitution, should_fallback))
|
||||
.collect();
|
||||
let inputs = d
|
||||
.inputs
|
||||
.into_iter()
|
||||
.map(|i| i.apply_substitution(substitution, should_fallback))
|
||||
.collect();
|
||||
|
||||
FlatStatement::Directive(
|
||||
DirectiveStatement {
|
||||
outputs,
|
||||
inputs,
|
||||
..d
|
||||
}
|
||||
)
|
||||
FlatStatement::Directive(DirectiveStatement {
|
||||
outputs,
|
||||
inputs,
|
||||
..d
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -259,22 +273,34 @@ pub enum FlatExpression<T: Field> {
|
|||
Add(Box<FlatExpression<T>>, Box<FlatExpression<T>>),
|
||||
Sub(Box<FlatExpression<T>>, Box<FlatExpression<T>>),
|
||||
Div(Box<FlatExpression<T>>, Box<FlatExpression<T>>),
|
||||
Mult(Box<FlatExpression<T>>, Box<FlatExpression<T>>)
|
||||
Mult(Box<FlatExpression<T>>, Box<FlatExpression<T>>),
|
||||
}
|
||||
|
||||
impl<T: Field> FlatExpression<T> {
|
||||
pub fn apply_recursive_substitution(self, substitution: &HashMap<FlatVariable, FlatVariable>) -> FlatExpression<T> {
|
||||
pub fn apply_recursive_substitution(
|
||||
self,
|
||||
substitution: &HashMap<FlatVariable, FlatVariable>,
|
||||
) -> FlatExpression<T> {
|
||||
self.apply_substitution(substitution, true)
|
||||
}
|
||||
|
||||
pub fn apply_direct_substitution(self, substitution: &HashMap<FlatVariable, FlatVariable>) -> FlatExpression<T> {
|
||||
pub fn apply_direct_substitution(
|
||||
self,
|
||||
substitution: &HashMap<FlatVariable, FlatVariable>,
|
||||
) -> FlatExpression<T> {
|
||||
self.apply_substitution(substitution, false)
|
||||
}
|
||||
|
||||
fn apply_substitution(self, substitution: &HashMap<FlatVariable, FlatVariable>, should_fallback: bool) -> FlatExpression<T> {
|
||||
fn apply_substitution(
|
||||
self,
|
||||
substitution: &HashMap<FlatVariable, FlatVariable>,
|
||||
should_fallback: bool,
|
||||
) -> FlatExpression<T> {
|
||||
match self {
|
||||
e @ FlatExpression::Number(_) => e,
|
||||
FlatExpression::Identifier(id) => FlatExpression::Identifier(id.apply_substitution(substitution, should_fallback)),
|
||||
FlatExpression::Identifier(id) => {
|
||||
FlatExpression::Identifier(id.apply_substitution(substitution, should_fallback))
|
||||
}
|
||||
FlatExpression::Add(e1, e2) => FlatExpression::Add(
|
||||
box e1.apply_substitution(substitution, should_fallback),
|
||||
box e2.apply_substitution(substitution, should_fallback),
|
||||
|
@ -290,24 +316,17 @@ impl<T: Field> FlatExpression<T> {
|
|||
FlatExpression::Div(e1, e2) => FlatExpression::Div(
|
||||
box e1.apply_substitution(substitution, should_fallback),
|
||||
box e2.apply_substitution(substitution, should_fallback),
|
||||
)
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn solve(&self, inputs: &mut BTreeMap<FlatVariable, T>) -> T {
|
||||
match *self {
|
||||
FlatExpression::Number(ref x) => x.clone(),
|
||||
FlatExpression::Identifier(ref var) => {
|
||||
match inputs.get(var) {
|
||||
Some(v) => v.clone(),
|
||||
None =>
|
||||
panic!(
|
||||
"Variable {:?} is undeclared in witness: {:?}",
|
||||
var,
|
||||
inputs
|
||||
)
|
||||
}
|
||||
}
|
||||
FlatExpression::Identifier(ref var) => match inputs.get(var) {
|
||||
Some(v) => v.clone(),
|
||||
None => panic!("Variable {:?} is undeclared in witness: {:?}", var, inputs),
|
||||
},
|
||||
FlatExpression::Add(ref x, ref y) => x.solve(inputs) + y.solve(inputs),
|
||||
FlatExpression::Sub(ref x, ref y) => x.solve(inputs) - y.solve(inputs),
|
||||
FlatExpression::Mult(ref x, ref y) => x.solve(inputs) * y.solve(inputs),
|
||||
|
@ -323,9 +342,9 @@ impl<T: Field> FlatExpression<T> {
|
|||
}
|
||||
FlatExpression::Mult(ref x, ref y) | FlatExpression::Div(ref x, ref y) => {
|
||||
match (x.clone(), y.clone()) {
|
||||
(box FlatExpression::Number(_), box FlatExpression::Number(_)) |
|
||||
(box FlatExpression::Number(_), box FlatExpression::Identifier(_)) |
|
||||
(box FlatExpression::Identifier(_), box FlatExpression::Number(_)) => true,
|
||||
(box FlatExpression::Number(_), box FlatExpression::Number(_))
|
||||
| (box FlatExpression::Number(_), box FlatExpression::Identifier(_))
|
||||
| (box FlatExpression::Identifier(_), box FlatExpression::Number(_)) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -361,7 +380,7 @@ impl<T: Field> fmt::Debug for FlatExpression<T> {
|
|||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct FlatExpressionList<T: Field> {
|
||||
pub expressions: Vec<FlatExpression<T>>
|
||||
pub expressions: Vec<FlatExpression<T>>,
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Display for FlatExpressionList<T> {
|
||||
|
@ -377,17 +396,31 @@ impl<T: Field> fmt::Display for FlatExpressionList<T> {
|
|||
}
|
||||
|
||||
impl<T: Field> FlatExpressionList<T> {
|
||||
fn apply_substitution(self, substitution: &HashMap<FlatVariable, FlatVariable>, should_fallback: bool) -> FlatExpressionList<T> {
|
||||
fn apply_substitution(
|
||||
self,
|
||||
substitution: &HashMap<FlatVariable, FlatVariable>,
|
||||
should_fallback: bool,
|
||||
) -> FlatExpressionList<T> {
|
||||
FlatExpressionList {
|
||||
expressions: self.expressions.into_iter().map(|e| e.apply_substitution(substitution, should_fallback)).collect()
|
||||
expressions: self
|
||||
.expressions
|
||||
.into_iter()
|
||||
.map(|e| e.apply_substitution(substitution, should_fallback))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply_recursive_substitution(self, substitution: &HashMap<FlatVariable, FlatVariable>) -> FlatExpressionList<T> {
|
||||
pub fn apply_recursive_substitution(
|
||||
self,
|
||||
substitution: &HashMap<FlatVariable, FlatVariable>,
|
||||
) -> FlatExpressionList<T> {
|
||||
self.apply_substitution(substitution, true)
|
||||
}
|
||||
|
||||
pub fn apply_direct_substitution(self, substitution: &HashMap<FlatVariable, FlatVariable>) -> FlatExpressionList<T> {
|
||||
pub fn apply_direct_substitution(
|
||||
self,
|
||||
substitution: &HashMap<FlatVariable, FlatVariable>,
|
||||
) -> FlatExpressionList<T> {
|
||||
self.apply_substitution(substitution, false)
|
||||
}
|
||||
}
|
||||
|
@ -400,7 +433,7 @@ impl<T: Field> fmt::Debug for FlatExpressionList<T> {
|
|||
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub struct Error {
|
||||
message: String
|
||||
message: String,
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,47 +1,54 @@
|
|||
use libsnark::{get_sha256_witness, get_ethsha256_witness};
|
||||
use field::Field;
|
||||
use helpers::{Executable, Signed};
|
||||
use libsnark::{get_ethsha256_witness, get_sha256_witness};
|
||||
use serde_json;
|
||||
use standard;
|
||||
use std::fmt;
|
||||
use field::{Field};
|
||||
use helpers::{Signed, Executable};
|
||||
|
||||
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||
pub enum LibsnarkGadgetHelper {
|
||||
Sha256Compress,
|
||||
Sha256Ethereum,
|
||||
Sha256Compress,
|
||||
Sha256Ethereum,
|
||||
}
|
||||
|
||||
impl fmt::Display for LibsnarkGadgetHelper {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
match *self {
|
||||
LibsnarkGadgetHelper::Sha256Compress => write!(f, "Sha256Compress"),
|
||||
LibsnarkGadgetHelper::Sha256Ethereum => write!(f, "Sha256Ethereum"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> Executable<T> for LibsnarkGadgetHelper {
|
||||
fn execute(&self, inputs: &Vec<T>) -> Result<Vec<T>, String> {
|
||||
fn execute(&self, inputs: &Vec<T>) -> Result<Vec<T>, String> {
|
||||
let witness_result: Result<standard::Witness, serde_json::Error> = match self {
|
||||
LibsnarkGadgetHelper::Sha256Compress =>
|
||||
serde_json::from_str(&get_sha256_witness(inputs)),
|
||||
LibsnarkGadgetHelper::Sha256Ethereum =>
|
||||
serde_json::from_str(&get_ethsha256_witness(inputs)),
|
||||
};
|
||||
LibsnarkGadgetHelper::Sha256Compress => {
|
||||
serde_json::from_str(&get_sha256_witness(inputs))
|
||||
}
|
||||
LibsnarkGadgetHelper::Sha256Ethereum => {
|
||||
serde_json::from_str(&get_ethsha256_witness(inputs))
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(e) = witness_result {
|
||||
return Err(format!("{}", e));
|
||||
}
|
||||
|
||||
Ok(witness_result.unwrap().variables.iter().map(|&i| T::from(i)).collect())
|
||||
}
|
||||
Ok(witness_result
|
||||
.unwrap()
|
||||
.variables
|
||||
.iter()
|
||||
.map(|&i| T::from(i))
|
||||
.collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl Signed for LibsnarkGadgetHelper {
|
||||
fn get_signature(&self) -> (usize, usize) {
|
||||
match self {
|
||||
LibsnarkGadgetHelper::Sha256Compress => (512, 25561),
|
||||
LibsnarkGadgetHelper::Sha256Ethereum => (512, 50610),
|
||||
}
|
||||
}
|
||||
fn get_signature(&self) -> (usize, usize) {
|
||||
match self {
|
||||
LibsnarkGadgetHelper::Sha256Compress => (512, 25561),
|
||||
LibsnarkGadgetHelper::Sha256Ethereum => (512, 50610),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,144 +5,196 @@ mod rust;
|
|||
#[cfg(feature = "libsnark")]
|
||||
pub use self::libsnark_gadget::LibsnarkGadgetHelper;
|
||||
pub use self::rust::RustHelper;
|
||||
use std::fmt;
|
||||
use field::{Field};
|
||||
use field::Field;
|
||||
use flat_absy::{FlatExpression, FlatVariable};
|
||||
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||
pub struct DirectiveStatement<T: Field> {
|
||||
pub inputs: Vec<FlatExpression<T>>,
|
||||
pub outputs: Vec<FlatVariable>,
|
||||
pub helper: Helper
|
||||
pub inputs: Vec<FlatExpression<T>>,
|
||||
pub outputs: Vec<FlatVariable>,
|
||||
pub helper: Helper,
|
||||
}
|
||||
|
||||
impl<T: Field> DirectiveStatement<T> {
|
||||
pub fn new(outputs: Vec<FlatVariable>, helper: Helper, inputs: Vec<FlatVariable>) -> Self {
|
||||
let (in_len, out_len) = helper.get_signature();
|
||||
assert_eq!(in_len, inputs.len());
|
||||
assert_eq!(out_len, outputs.len());
|
||||
DirectiveStatement {
|
||||
helper,
|
||||
inputs: inputs.into_iter().map(|i| FlatExpression::Identifier(i)).collect(),
|
||||
outputs,
|
||||
}
|
||||
}
|
||||
pub fn new(outputs: Vec<FlatVariable>, helper: Helper, inputs: Vec<FlatVariable>) -> Self {
|
||||
let (in_len, out_len) = helper.get_signature();
|
||||
assert_eq!(in_len, inputs.len());
|
||||
assert_eq!(out_len, outputs.len());
|
||||
DirectiveStatement {
|
||||
helper,
|
||||
inputs: inputs
|
||||
.into_iter()
|
||||
.map(|i| FlatExpression::Identifier(i))
|
||||
.collect(),
|
||||
outputs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Display for DirectiveStatement<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "# {} = {}({})",
|
||||
self.outputs.iter().map(|o| o.to_string()).collect::<Vec<String>>().join(", "),
|
||||
self.helper,
|
||||
self.inputs.iter().map(|i| i.to_string()).collect::<Vec<String>>().join(", ")
|
||||
)
|
||||
write!(
|
||||
f,
|
||||
"# {} = {}({})",
|
||||
self.outputs
|
||||
.iter()
|
||||
.map(|o| o.to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join(", "),
|
||||
self.helper,
|
||||
self.inputs
|
||||
.iter()
|
||||
.map(|i| i.to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join(", ")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||
pub enum Helper {
|
||||
#[cfg(feature = "libsnark")]
|
||||
LibsnarkGadget(LibsnarkGadgetHelper),
|
||||
Rust(RustHelper)
|
||||
#[cfg(feature = "libsnark")]
|
||||
LibsnarkGadget(LibsnarkGadgetHelper),
|
||||
Rust(RustHelper),
|
||||
}
|
||||
|
||||
impl fmt::Display for Helper {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
#[cfg(feature = "libsnark")]
|
||||
Helper::LibsnarkGadget(ref h) => write!(f, "LibsnarkGadget::{}", h),
|
||||
Helper::Rust(ref h) => write!(f, "Rust::{}", h)
|
||||
}
|
||||
match *self {
|
||||
#[cfg(feature = "libsnark")]
|
||||
Helper::LibsnarkGadget(ref h) => write!(f, "LibsnarkGadget::{}", h),
|
||||
Helper::Rust(ref h) => write!(f, "Rust::{}", h),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Executable<T: Field>
|
||||
: Signed {
|
||||
fn execute(&self, inputs: &Vec<T>) -> Result<Vec<T>, String>;
|
||||
pub trait Executable<T: Field>: Signed {
|
||||
fn execute(&self, inputs: &Vec<T>) -> Result<Vec<T>, String>;
|
||||
}
|
||||
|
||||
pub trait Signed {
|
||||
fn get_signature(&self) -> (usize, usize);
|
||||
fn get_signature(&self) -> (usize, usize);
|
||||
}
|
||||
|
||||
impl<T: Field> Executable<T> for Helper {
|
||||
fn execute(&self, inputs: &Vec<T>) -> Result<Vec<T>, String> {
|
||||
let (expected_input_count, expected_output_count) = self.get_signature();
|
||||
assert!(inputs.len() == expected_input_count);
|
||||
fn execute(&self, inputs: &Vec<T>) -> Result<Vec<T>, String> {
|
||||
let (expected_input_count, expected_output_count) = self.get_signature();
|
||||
assert!(inputs.len() == expected_input_count);
|
||||
|
||||
let result = match self {
|
||||
#[cfg(feature = "libsnark")]
|
||||
Helper::LibsnarkGadget(helper) => helper.execute(inputs),
|
||||
Helper::Rust(helper) => helper.execute(inputs)
|
||||
};
|
||||
let result = match self {
|
||||
#[cfg(feature = "libsnark")]
|
||||
Helper::LibsnarkGadget(helper) => helper.execute(inputs),
|
||||
Helper::Rust(helper) => helper.execute(inputs),
|
||||
};
|
||||
|
||||
match result {
|
||||
Ok(ref r) if r.len() != expected_output_count => Err(format!("invalid witness size: is {} but should be {}", r.len(), expected_output_count).to_string()),
|
||||
r => r
|
||||
}
|
||||
}
|
||||
match result {
|
||||
Ok(ref r) if r.len() != expected_output_count => Err(format!(
|
||||
"invalid witness size: is {} but should be {}",
|
||||
r.len(),
|
||||
expected_output_count
|
||||
)
|
||||
.to_string()),
|
||||
r => r,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Signed for Helper {
|
||||
fn get_signature(&self) -> (usize, usize) {
|
||||
match self {
|
||||
#[cfg(feature = "libsnark")]
|
||||
Helper::LibsnarkGadget(helper) => helper.get_signature(),
|
||||
Helper::Rust(helper) => helper.get_signature()
|
||||
}
|
||||
}
|
||||
fn get_signature(&self) -> (usize, usize) {
|
||||
match self {
|
||||
#[cfg(feature = "libsnark")]
|
||||
Helper::LibsnarkGadget(helper) => helper.get_signature(),
|
||||
Helper::Rust(helper) => helper.get_signature(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use field::FieldPrime;
|
||||
use super::*;
|
||||
use super::*;
|
||||
use field::FieldPrime;
|
||||
|
||||
#[cfg(feature = "libsnark")]
|
||||
mod sha256libsnark {
|
||||
use super::*;
|
||||
#[cfg(feature = "libsnark")]
|
||||
mod sha256libsnark {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn execute() {
|
||||
let sha = LibsnarkGadgetHelper::Sha256Compress;
|
||||
// second vector here https://homes.esat.kuleuven.be/~nsmart/MPC/sha-256-test.txt
|
||||
let inputs = vec![0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,1,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,1,1,0,0,0,0,0,1,1,1,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0,1,0,0,1,1,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,1,0,0,0,1,0,1,1,0,0,0,0,1,0,1,1,1,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1,0,0,0,1,1,0,1,0,0,0,0,1,1,0,1,1,0,0,0,1,1,1,0,0,0,0,0,1,1,1,0,1,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,1,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,1,0,0,1,0,0,1,0,0,0,0,1,0,0,1,0,1,0,0,1,0,0,1,1,0,0,0,1,0,0,1,1,1,0,0,1,0,1,0,0,0,0,0,1,0,1,0,0,1,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1,1,0,0,1,0,1,1,0,0,0,0,1,0,1,1,0,1,0,0,1,0,1,1,1,0,0,0,1,0,1,1,1,1,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,1,0,0,1,1,0,0,1,0,0,0,1,1,0,0,1,1,0,0,1,1,0,1,0,0,0,0,1,1,0,1,0,1,0,0,1,1,0,1,1,0,0,0,1,1,0,1,1,1,0,0,1,1,1,0,0,0,0,0,1,1,1,0,0,1,0,0,1,1,1,0,1,0,0,0,1,1,1,0,1,1,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,1,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1,1];
|
||||
let r = sha.execute(&inputs.iter().map(|&i| FieldPrime::from(i)).collect()).unwrap();
|
||||
let r1 = &r[513..769]; // index of the result
|
||||
let res: Vec<FieldPrime> = vec![1,1,1,1,1,1,0,0,1,0,0,1,1,0,0,1,1,0,1,0,0,0,1,0,1,1,0,1,1,1,1,1,1,0,0,0,1,0,0,0,1,1,1,1,0,1,0,0,0,0,1,0,1,0,1,0,0,1,1,1,1,0,1,0,0,1,1,1,1,0,1,1,1,0,1,1,1,0,0,1,1,1,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,0,0,0,1,1,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,1,0,1,0,1,1,0,0,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,1,0,0,1,1,1,0,1,0,1,0,1,1,0,1,1,1,0,0,1,1,0,1,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,1,0,1,0,1,0,0,1,1,1,0,0,1,1,0,0,0,0,1,1,0,0,0,1,0,1,0,1,1,0,1,0,1,0,1,1,1,1,1,0,1,0,0,0,0,1,0,0,1,0,1,0,0,1,1,1].iter().map(|&i| FieldPrime::from(i)).collect();
|
||||
assert_eq!(r1, &res[..]);
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn execute() {
|
||||
let sha = LibsnarkGadgetHelper::Sha256Compress;
|
||||
// second vector here https://homes.esat.kuleuven.be/~nsmart/MPC/sha-256-test.txt
|
||||
let inputs = vec![
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0,
|
||||
0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
|
||||
1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1,
|
||||
0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1,
|
||||
0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0,
|
||||
0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1,
|
||||
1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1,
|
||||
0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1,
|
||||
1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0,
|
||||
0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0,
|
||||
0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1,
|
||||
0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
|
||||
1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0,
|
||||
0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1,
|
||||
0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1,
|
||||
0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1,
|
||||
1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0,
|
||||
0, 0, 1, 1, 1, 1, 1, 1,
|
||||
];
|
||||
let r = sha
|
||||
.execute(&inputs.iter().map(|&i| FieldPrime::from(i)).collect())
|
||||
.unwrap();
|
||||
let r1 = &r[513..769]; // index of the result
|
||||
let res: Vec<FieldPrime> = vec![
|
||||
1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1,
|
||||
1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0,
|
||||
0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1,
|
||||
0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1,
|
||||
1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1,
|
||||
0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1,
|
||||
0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1,
|
||||
0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0,
|
||||
0, 1, 1, 1,
|
||||
]
|
||||
.iter()
|
||||
.map(|&i| FieldPrime::from(i))
|
||||
.collect();
|
||||
assert_eq!(r1, &res[..]);
|
||||
}
|
||||
}
|
||||
|
||||
mod eq_condition {
|
||||
|
||||
mod eq_condition {
|
||||
|
||||
// Wanted: (Y = (X != 0) ? 1 : 0)
|
||||
// Wanted: (Y = (X != 0) ? 1 : 0)
|
||||
// # Y = if X == 0 then 0 else 1 fi
|
||||
// # M = if X == 0 then 1 else 1/X fi
|
||||
|
||||
use super::*;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn execute() {
|
||||
let cond_eq = RustHelper::ConditionEq;
|
||||
let inputs = vec![0];
|
||||
let r = cond_eq.execute(&inputs.iter().map(|&i| FieldPrime::from(i)).collect()).unwrap();
|
||||
let res: Vec<FieldPrime> = vec![0, 1].iter().map(|&i| FieldPrime::from(i)).collect();
|
||||
assert_eq!(r, &res[..]);
|
||||
}
|
||||
#[test]
|
||||
fn execute() {
|
||||
let cond_eq = RustHelper::ConditionEq;
|
||||
let inputs = vec![0];
|
||||
let r = cond_eq
|
||||
.execute(&inputs.iter().map(|&i| FieldPrime::from(i)).collect())
|
||||
.unwrap();
|
||||
let res: Vec<FieldPrime> = vec![0, 1].iter().map(|&i| FieldPrime::from(i)).collect();
|
||||
assert_eq!(r, &res[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn execute_non_eq() {
|
||||
let cond_eq = RustHelper::ConditionEq;
|
||||
let inputs = vec![1];
|
||||
let r = cond_eq.execute(&inputs.iter().map(|&i| FieldPrime::from(i)).collect()).unwrap();
|
||||
let res: Vec<FieldPrime> = vec![1, 1].iter().map(|&i| FieldPrime::from(i)).collect();
|
||||
assert_eq!(r, &res[..]);
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn execute_non_eq() {
|
||||
let cond_eq = RustHelper::ConditionEq;
|
||||
let inputs = vec![1];
|
||||
let r = cond_eq
|
||||
.execute(&inputs.iter().map(|&i| FieldPrime::from(i)).collect())
|
||||
.unwrap();
|
||||
let res: Vec<FieldPrime> = vec![1, 1].iter().map(|&i| FieldPrime::from(i)).collect();
|
||||
assert_eq!(r, &res[..]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,48 +1,45 @@
|
|||
use field::Field;
|
||||
use helpers::{Executable, Signed};
|
||||
use std::fmt;
|
||||
use helpers::{Signed, Executable};
|
||||
use field::{Field};
|
||||
|
||||
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||
pub enum RustHelper {
|
||||
Identity,
|
||||
ConditionEq,
|
||||
Bits,
|
||||
Identity,
|
||||
ConditionEq,
|
||||
Bits,
|
||||
}
|
||||
|
||||
impl fmt::Display for RustHelper {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
RustHelper::Identity => write!(f, "Identity"),
|
||||
RustHelper::ConditionEq => write!(f, "ConditionEq"),
|
||||
RustHelper::Bits => write!(f, "Bits"),
|
||||
}
|
||||
match *self {
|
||||
RustHelper::Identity => write!(f, "Identity"),
|
||||
RustHelper::ConditionEq => write!(f, "ConditionEq"),
|
||||
RustHelper::Bits => write!(f, "Bits"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Signed for RustHelper {
|
||||
fn get_signature(&self) -> (usize, usize) {
|
||||
match self {
|
||||
RustHelper::Identity => (1, 1),
|
||||
RustHelper::ConditionEq => (1, 2),
|
||||
RustHelper::Bits => (1, 254),
|
||||
}
|
||||
}
|
||||
fn get_signature(&self) -> (usize, usize) {
|
||||
match self {
|
||||
RustHelper::Identity => (1, 1),
|
||||
RustHelper::ConditionEq => (1, 2),
|
||||
RustHelper::Bits => (1, 254),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<T: Field> Executable<T> for RustHelper {
|
||||
fn execute(&self, inputs: &Vec<T>) -> Result<Vec<T>, String> {
|
||||
match self {
|
||||
RustHelper::Identity => Ok(inputs.clone()),
|
||||
RustHelper::ConditionEq => {
|
||||
match inputs[0].is_zero() {
|
||||
true => Ok(vec![T::zero(), T::one()]),
|
||||
false => Ok(vec![T::one(), T::one() / inputs[0].clone()])
|
||||
}
|
||||
},
|
||||
RustHelper::Bits => {
|
||||
let mut num = inputs[0].clone();
|
||||
let mut res = vec![];
|
||||
fn execute(&self, inputs: &Vec<T>) -> Result<Vec<T>, String> {
|
||||
match self {
|
||||
RustHelper::Identity => Ok(inputs.clone()),
|
||||
RustHelper::ConditionEq => match inputs[0].is_zero() {
|
||||
true => Ok(vec![T::zero(), T::one()]),
|
||||
false => Ok(vec![T::one(), T::one() / inputs[0].clone()]),
|
||||
},
|
||||
RustHelper::Bits => {
|
||||
let mut num = inputs[0].clone();
|
||||
let mut res = vec![];
|
||||
let bits = 254;
|
||||
for i in (0..bits).rev() {
|
||||
if T::from(2).pow(i) <= num {
|
||||
|
@ -55,35 +52,35 @@ impl<T: Field> Executable<T> for RustHelper {
|
|||
assert_eq!(num, T::zero());
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use field::FieldPrime;
|
||||
use super::*;
|
||||
use super::*;
|
||||
use field::FieldPrime;
|
||||
|
||||
#[test]
|
||||
fn bits_of_one() {
|
||||
let inputs = vec![FieldPrime::from(1)];
|
||||
let res = RustHelper::Bits.execute(&inputs).unwrap();
|
||||
assert_eq!(res[253], FieldPrime::from(1));
|
||||
for i in 0..252 {
|
||||
assert_eq!(res[i], FieldPrime::from(0));
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn bits_of_one() {
|
||||
let inputs = vec![FieldPrime::from(1)];
|
||||
let res = RustHelper::Bits.execute(&inputs).unwrap();
|
||||
assert_eq!(res[253], FieldPrime::from(1));
|
||||
for i in 0..252 {
|
||||
assert_eq!(res[i], FieldPrime::from(0));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bits_of_42() {
|
||||
let inputs = vec![FieldPrime::from(42)];
|
||||
let res = RustHelper::Bits.execute(&inputs).unwrap();
|
||||
assert_eq!(res[253], FieldPrime::from(0));
|
||||
assert_eq!(res[252], FieldPrime::from(1));
|
||||
assert_eq!(res[251], FieldPrime::from(0));
|
||||
assert_eq!(res[250], FieldPrime::from(1));
|
||||
assert_eq!(res[249], FieldPrime::from(0));
|
||||
assert_eq!(res[248], FieldPrime::from(1));
|
||||
assert_eq!(res[247], FieldPrime::from(0));
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn bits_of_42() {
|
||||
let inputs = vec![FieldPrime::from(42)];
|
||||
let res = RustHelper::Bits.execute(&inputs).unwrap();
|
||||
assert_eq!(res[253], FieldPrime::from(0));
|
||||
assert_eq!(res[252], FieldPrime::from(1));
|
||||
assert_eq!(res[251], FieldPrime::from(0));
|
||||
assert_eq!(res[250], FieldPrime::from(1));
|
||||
assert_eq!(res[249], FieldPrime::from(0));
|
||||
assert_eq!(res[248], FieldPrime::from(1));
|
||||
assert_eq!(res[247], FieldPrime::from(0));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,238 +4,245 @@
|
|||
//! @author Thibaut Schaeffer <thibaut@schaeff.fr>
|
||||
//! @date 2018
|
||||
|
||||
use compile::CompileError;
|
||||
use std::io::BufRead;
|
||||
use compile::compile_aux;
|
||||
use std::fmt;
|
||||
use absy::*;
|
||||
use flat_absy::*;
|
||||
use compile::compile_aux;
|
||||
use compile::CompileError;
|
||||
use field::Field;
|
||||
use flat_absy::*;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use std::io::BufRead;
|
||||
|
||||
pub struct CompiledImport<T: Field> {
|
||||
pub flat_func: FlatFunction<T>,
|
||||
pub flat_func: FlatFunction<T>,
|
||||
}
|
||||
|
||||
impl<T: Field> CompiledImport<T> {
|
||||
fn new(prog: FlatProg<T>, alias: String) -> CompiledImport<T> {
|
||||
match prog.functions.iter().find(|fun| fun.id == "main") {
|
||||
Some(fun) => {
|
||||
CompiledImport { flat_func:
|
||||
FlatFunction {
|
||||
id: alias,
|
||||
..fun.clone()
|
||||
}
|
||||
}
|
||||
},
|
||||
None => panic!("no main")
|
||||
}
|
||||
fn new(prog: FlatProg<T>, alias: String) -> CompiledImport<T> {
|
||||
match prog.functions.iter().find(|fun| fun.id == "main") {
|
||||
Some(fun) => CompiledImport {
|
||||
flat_func: FlatFunction {
|
||||
id: alias,
|
||||
..fun.clone()
|
||||
},
|
||||
},
|
||||
None => panic!("no main"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub struct Error {
|
||||
message: String
|
||||
message: String,
|
||||
}
|
||||
|
||||
impl Error {
|
||||
pub fn new<T: Into<String>>(message: T) -> Error {
|
||||
Error {
|
||||
message: message.into()
|
||||
}
|
||||
}
|
||||
pub fn new<T: Into<String>>(message: T) -> Error {
|
||||
Error {
|
||||
message: message.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)]
|
||||
pub struct Import {
|
||||
source: String,
|
||||
alias: Option<String>,
|
||||
source: String,
|
||||
alias: Option<String>,
|
||||
}
|
||||
|
||||
impl Import {
|
||||
pub fn new(source: String) -> Import {
|
||||
Import {
|
||||
source: source,
|
||||
alias: None,
|
||||
}
|
||||
}
|
||||
pub fn new(source: String) -> Import {
|
||||
Import {
|
||||
source: source,
|
||||
alias: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_alias(&self) -> &Option<String> {
|
||||
&self.alias
|
||||
}
|
||||
pub fn get_alias(&self) -> &Option<String> {
|
||||
&self.alias
|
||||
}
|
||||
|
||||
pub fn new_with_alias(source: String, alias: &String) -> Import {
|
||||
Import {
|
||||
source: source,
|
||||
alias: Some(alias.clone()),
|
||||
}
|
||||
}
|
||||
pub fn new_with_alias(source: String, alias: &String) -> Import {
|
||||
Import {
|
||||
source: source,
|
||||
alias: Some(alias.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_source(&self) -> &String {
|
||||
&self.source
|
||||
}
|
||||
pub fn get_source(&self) -> &String {
|
||||
&self.source
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Import {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.alias {
|
||||
Some(ref alias) => {
|
||||
write!(f, "import {} as {}", self.source, alias)
|
||||
},
|
||||
None => {
|
||||
write!(f, "import {}", self.source)
|
||||
}
|
||||
}
|
||||
}
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.alias {
|
||||
Some(ref alias) => write!(f, "import {} as {}", self.source, alias),
|
||||
None => write!(f, "import {}", self.source),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Import {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.alias {
|
||||
Some(ref alias) => {
|
||||
write!(f, "import(source: {}, alias: {})", self.source, alias)
|
||||
},
|
||||
None => {
|
||||
write!(f, "import(source: {})", self.source)
|
||||
}
|
||||
}
|
||||
}
|
||||
match self.alias {
|
||||
Some(ref alias) => write!(f, "import(source: {}, alias: {})", self.source, alias),
|
||||
None => write!(f, "import(source: {})", self.source),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Importer {
|
||||
|
||||
}
|
||||
pub struct Importer {}
|
||||
|
||||
impl Importer {
|
||||
pub fn new() -> Importer {
|
||||
Importer {
|
||||
pub fn new() -> Importer {
|
||||
Importer {}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
pub fn apply_imports<T: Field, S: BufRead, E: Into<Error>>(
|
||||
&self,
|
||||
destination: Prog<T>,
|
||||
location: Option<String>,
|
||||
resolve_option: Option<fn(&Option<String>, &String) -> Result<(S, String, String), E>>,
|
||||
) -> Result<Prog<T>, CompileError<T>> {
|
||||
let mut origins: Vec<CompiledImport<T>> = vec![];
|
||||
|
||||
pub fn apply_imports<T: Field, S: BufRead, E: Into<Error>>(&self, destination: Prog<T>, location: Option<String>, resolve_option: Option<fn(&Option<String>, &String) -> Result<(S, String, String), E>>) -> Result<Prog<T>, CompileError<T>> {
|
||||
for import in destination.imports.iter() {
|
||||
// handle the case of special libsnark and packing imports
|
||||
if import.source.starts_with("LIBSNARK") {
|
||||
#[cfg(feature = "libsnark")]
|
||||
{
|
||||
use helpers::LibsnarkGadgetHelper;
|
||||
use libsnark::{get_ethsha256_constraints, get_sha256_constraints};
|
||||
use serde_json::from_str;
|
||||
use standard::{DirectiveR1CS, R1CS};
|
||||
use std::io::BufReader;
|
||||
|
||||
let mut origins: Vec<CompiledImport<T>> = vec![];
|
||||
match import.source.as_ref() {
|
||||
"LIBSNARK/sha256" => {
|
||||
let r1cs: R1CS = from_str(&get_ethsha256_constraints()).unwrap();
|
||||
let dr1cs: DirectiveR1CS = DirectiveR1CS {
|
||||
r1cs,
|
||||
directive: LibsnarkGadgetHelper::Sha256Ethereum,
|
||||
};
|
||||
let compiled = FlatProg::from(dr1cs);
|
||||
let alias = match import.alias {
|
||||
Some(ref alias) => alias.clone(),
|
||||
None => String::from("sha256"),
|
||||
};
|
||||
origins.push(CompiledImport::new(compiled, alias));
|
||||
}
|
||||
"LIBSNARK/sha256compression" => {
|
||||
let r1cs: R1CS = from_str(&get_sha256_constraints()).unwrap();
|
||||
let dr1cs: DirectiveR1CS = DirectiveR1CS {
|
||||
r1cs,
|
||||
directive: LibsnarkGadgetHelper::Sha256Compress,
|
||||
};
|
||||
let compiled = FlatProg::from(dr1cs);
|
||||
let alias = match import.alias {
|
||||
Some(ref alias) => alias.clone(),
|
||||
None => String::from("sha256compression"),
|
||||
};
|
||||
origins.push(CompiledImport::new(compiled, alias));
|
||||
}
|
||||
"LIBSNARK/sha256packed" => {
|
||||
let source = sha_packed_typed();
|
||||
let mut reader = BufReader::new(source.as_bytes());
|
||||
let compiled = compile_aux(
|
||||
&mut reader,
|
||||
None::<String>,
|
||||
None::<
|
||||
fn(&Option<String>, &String) -> Result<(S, String, String), E>,
|
||||
>,
|
||||
)?;
|
||||
let alias = match import.alias {
|
||||
Some(ref alias) => alias.clone(),
|
||||
None => String::from("sha256packed"),
|
||||
};
|
||||
origins.push(CompiledImport::new(compiled, alias));
|
||||
}
|
||||
s => {
|
||||
return Err(CompileError::ImportError(Error::new(format!(
|
||||
"Gadget {} not found",
|
||||
s
|
||||
))))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if import.source.starts_with("PACKING") {
|
||||
use types::conversions::{pack, unpack};
|
||||
|
||||
for import in destination.imports.iter() {
|
||||
// handle the case of special libsnark and packing imports
|
||||
if import.source.starts_with("LIBSNARK") {
|
||||
#[cfg(feature = "libsnark")]
|
||||
{
|
||||
use libsnark::{get_sha256_constraints, get_ethsha256_constraints};
|
||||
use standard::{R1CS, DirectiveR1CS};
|
||||
use serde_json::from_str;
|
||||
use helpers::LibsnarkGadgetHelper;
|
||||
use std::io::BufReader;
|
||||
match import.source.as_ref() {
|
||||
"PACKING/pack128" => {
|
||||
let compiled = pack(128);
|
||||
let alias = match import.alias {
|
||||
Some(ref alias) => alias.clone(),
|
||||
None => String::from("pack128"),
|
||||
};
|
||||
origins.push(CompiledImport::new(compiled, alias));
|
||||
}
|
||||
"PACKING/unpack128" => {
|
||||
let compiled = unpack(128);
|
||||
let alias = match import.alias {
|
||||
Some(ref alias) => alias.clone(),
|
||||
None => String::from("unpack128"),
|
||||
};
|
||||
origins.push(CompiledImport::new(compiled, alias));
|
||||
}
|
||||
s => {
|
||||
return Err(CompileError::ImportError(Error::new(format!(
|
||||
"Packing helper {} not found",
|
||||
s
|
||||
))))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// to resolve imports, we need a resolver
|
||||
match resolve_option {
|
||||
Some(resolve) => match resolve(&location, &import.source) {
|
||||
Ok((mut reader, location, auto_alias)) => {
|
||||
let compiled =
|
||||
compile_aux(&mut reader, Some(location), resolve_option)?;
|
||||
let alias = match import.alias {
|
||||
Some(ref alias) => alias.clone(),
|
||||
None => auto_alias,
|
||||
};
|
||||
origins.push(CompiledImport::new(compiled, alias));
|
||||
}
|
||||
Err(err) => return Err(CompileError::ImportError(err.into())),
|
||||
},
|
||||
None => {
|
||||
return Err(Error::new("Can't resolve import without a resolver").into())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match import.source.as_ref() {
|
||||
"LIBSNARK/sha256" => {
|
||||
let r1cs: R1CS = from_str(&get_ethsha256_constraints()).unwrap();
|
||||
let dr1cs : DirectiveR1CS = DirectiveR1CS { r1cs, directive : LibsnarkGadgetHelper::Sha256Ethereum };
|
||||
let compiled = FlatProg::from(dr1cs);
|
||||
let alias = match import.alias {
|
||||
Some(ref alias) => alias.clone(),
|
||||
None => String::from("sha256")
|
||||
};
|
||||
origins.push(CompiledImport::new(compiled, alias));
|
||||
},
|
||||
"LIBSNARK/sha256compression" => {
|
||||
let r1cs: R1CS = from_str(&get_sha256_constraints()).unwrap();
|
||||
let dr1cs : DirectiveR1CS = DirectiveR1CS { r1cs, directive : LibsnarkGadgetHelper::Sha256Compress };
|
||||
let compiled = FlatProg::from(dr1cs);
|
||||
let alias = match import.alias {
|
||||
Some(ref alias) => alias.clone(),
|
||||
None => String::from("sha256compression")
|
||||
};
|
||||
origins.push(CompiledImport::new(compiled, alias));
|
||||
},
|
||||
"LIBSNARK/sha256packed" => {
|
||||
let source = sha_packed_typed();
|
||||
let mut reader = BufReader::new(source.as_bytes());
|
||||
let compiled = compile_aux(
|
||||
&mut reader,
|
||||
None::<String>,
|
||||
None::<fn(&Option<String>, &String) -> Result<(S, String, String), E>>
|
||||
)?;
|
||||
let alias = match import.alias {
|
||||
Some(ref alias) => alias.clone(),
|
||||
None => String::from("sha256packed")
|
||||
};
|
||||
origins.push(CompiledImport::new(compiled, alias));
|
||||
},
|
||||
s => return Err(CompileError::ImportError(Error::new(format!("Gadget {} not found", s))))
|
||||
}
|
||||
}
|
||||
} else if import.source.starts_with("PACKING") {
|
||||
use types::conversions::{pack, unpack};
|
||||
|
||||
match import.source.as_ref() {
|
||||
"PACKING/pack128" => {
|
||||
let compiled = pack(128);
|
||||
let alias = match import.alias {
|
||||
Some(ref alias) => alias.clone(),
|
||||
None => String::from("pack128")
|
||||
};
|
||||
origins.push(CompiledImport::new(compiled, alias));
|
||||
},
|
||||
"PACKING/unpack128" => {
|
||||
let compiled = unpack(128);
|
||||
let alias = match import.alias {
|
||||
Some(ref alias) => alias.clone(),
|
||||
None => String::from("unpack128")
|
||||
};
|
||||
origins.push(CompiledImport::new(compiled, alias));
|
||||
},
|
||||
s => return Err(CompileError::ImportError(Error::new(format!("Packing helper {} not found", s))))
|
||||
}
|
||||
} else {
|
||||
// to resolve imports, we need a resolver
|
||||
match resolve_option {
|
||||
Some(resolve) => {
|
||||
match resolve(&location, &import.source) {
|
||||
Ok((mut reader, location, auto_alias)) => {
|
||||
let compiled = compile_aux(&mut reader, Some(location), resolve_option)?;
|
||||
let alias = match import.alias {
|
||||
Some(ref alias) => alias.clone(),
|
||||
None => auto_alias
|
||||
};
|
||||
origins.push(CompiledImport::new(compiled, alias));
|
||||
},
|
||||
Err(err) => return Err(CompileError::ImportError(err.into()))
|
||||
}
|
||||
}
|
||||
None => {
|
||||
return Err(Error::new("Can't resolve import without a resolver").into())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Prog {
|
||||
imports: vec![],
|
||||
functions: destination.clone().functions,
|
||||
imported_functions: origins.into_iter().map(|o| o.flat_func).collect()
|
||||
})
|
||||
}
|
||||
Ok(Prog {
|
||||
imports: vec![],
|
||||
functions: destination.clone().functions,
|
||||
imported_functions: origins.into_iter().map(|o| o.flat_func).collect(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "libsnark")]
|
||||
fn sha_packed_typed() -> String {
|
||||
String::from(r#"
|
||||
String::from(r#"
|
||||
import "PACKING/pack128"
|
||||
import "PACKING/unpack128"
|
||||
import "LIBSNARK/sha256"
|
||||
|
@ -258,21 +265,27 @@ fn sha_packed_typed() -> String {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn create_with_no_alias() {
|
||||
assert_eq!(Import::new("./foo/bar/baz.code".to_string()), Import {
|
||||
source: String::from("./foo/bar/baz.code"),
|
||||
alias: None,
|
||||
});
|
||||
}
|
||||
#[test]
|
||||
fn create_with_no_alias() {
|
||||
assert_eq!(
|
||||
Import::new("./foo/bar/baz.code".to_string()),
|
||||
Import {
|
||||
source: String::from("./foo/bar/baz.code"),
|
||||
alias: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_with_alias() {
|
||||
assert_eq!(Import::new_with_alias("./foo/bar/baz.code".to_string(), &"myalias".to_string()), Import {
|
||||
source: String::from("./foo/bar/baz.code"),
|
||||
alias: Some("myalias".to_string()),
|
||||
});
|
||||
}
|
||||
#[test]
|
||||
fn create_with_alias() {
|
||||
assert_eq!(
|
||||
Import::new_with_alias("./foo/bar/baz.code".to_string(), &"myalias".to_string()),
|
||||
Import {
|
||||
source: String::from("./foo/bar/baz.code"),
|
||||
alias: Some("myalias".to_string()),
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,31 +5,31 @@ extern crate lazy_static;
|
|||
extern crate num;
|
||||
extern crate num_bigint;
|
||||
extern crate reduce; // better reduce function than Iter.fold
|
||||
extern crate serde; // serialization deserialization
|
||||
extern crate serde; // serialization deserialization
|
||||
extern crate serde_json;
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
extern crate bimap;
|
||||
extern crate bincode;
|
||||
extern crate regex;
|
||||
extern crate bimap;
|
||||
|
||||
mod parser;
|
||||
mod imports;
|
||||
mod semantics;
|
||||
mod flatten;
|
||||
mod helpers;
|
||||
mod imports;
|
||||
mod optimizer;
|
||||
mod parser;
|
||||
mod semantics;
|
||||
#[cfg(feature = "libsnark")]
|
||||
mod standard;
|
||||
mod helpers;
|
||||
mod types;
|
||||
mod typed_absy;
|
||||
mod static_analysis;
|
||||
mod typed_absy;
|
||||
mod types;
|
||||
|
||||
pub mod absy;
|
||||
pub mod flat_absy;
|
||||
pub mod compile;
|
||||
pub mod r1cs;
|
||||
pub mod field;
|
||||
pub mod verification;
|
||||
pub mod flat_absy;
|
||||
#[cfg(feature = "libsnark")]
|
||||
pub mod libsnark;
|
||||
pub mod libsnark;
|
||||
pub mod r1cs;
|
||||
pub mod verification;
|
||||
|
|
|
@ -6,11 +6,11 @@
|
|||
|
||||
extern crate libc;
|
||||
|
||||
use self::libc::{c_int, c_char, uint8_t};
|
||||
use std::ffi::{CString};
|
||||
use std::cmp::max;
|
||||
use std::string::String;
|
||||
use self::libc::{c_char, c_int, uint8_t};
|
||||
use flat_absy::flat_variable::FlatVariable;
|
||||
use std::cmp::max;
|
||||
use std::ffi::CString;
|
||||
use std::string::String;
|
||||
|
||||
use field::Field;
|
||||
|
||||
|
@ -30,22 +30,23 @@ extern "C" {
|
|||
vk_path: *const c_char,
|
||||
) -> bool;
|
||||
|
||||
fn _generate_proof(pk_path: *const c_char,
|
||||
proof_path: *const c_char,
|
||||
public_inputs: *const uint8_t,
|
||||
public_inputs_length: c_int,
|
||||
private_inputs: *const uint8_t,
|
||||
private_inputs_length: c_int,
|
||||
) -> bool;
|
||||
fn _generate_proof(
|
||||
pk_path: *const c_char,
|
||||
proof_path: *const c_char,
|
||||
public_inputs: *const uint8_t,
|
||||
public_inputs_length: c_int,
|
||||
private_inputs: *const uint8_t,
|
||||
private_inputs_length: c_int,
|
||||
) -> bool;
|
||||
|
||||
fn _sha256Constraints() -> *mut c_char;
|
||||
fn _sha256Witness(inputs: *const uint8_t, inputs_length: c_int) -> *mut c_char;
|
||||
|
||||
|
||||
fn _shaEth256Constraints() -> *mut c_char;
|
||||
fn _shaEth256Witness(inputs: *const uint8_t, inputs_length: c_int) -> *mut c_char;
|
||||
}
|
||||
|
||||
pub fn setup<T: Field> (
|
||||
pub fn setup<T: Field>(
|
||||
variables: Vec<FlatVariable>,
|
||||
a: Vec<Vec<(usize, T)>>,
|
||||
b: Vec<Vec<(usize, T)>>,
|
||||
|
@ -53,8 +54,7 @@ pub fn setup<T: Field> (
|
|||
num_inputs: usize,
|
||||
pk_path: &str,
|
||||
vk_path: &str,
|
||||
) -> bool {
|
||||
|
||||
) -> bool {
|
||||
let num_constraints = a.len();
|
||||
let num_variables = variables.len();
|
||||
|
||||
|
@ -63,15 +63,27 @@ pub fn setup<T: Field> (
|
|||
let mut b_vec = vec![];
|
||||
let mut c_vec = vec![];
|
||||
for row in 0..num_constraints {
|
||||
for &(idx, ref val) in &a[row] {
|
||||
a_vec.push((row as i32, idx as i32, vec_as_u8_32_array(&val.into_byte_vector())));
|
||||
}
|
||||
for &(idx, ref val) in &b[row] {
|
||||
b_vec.push((row as i32, idx as i32, vec_as_u8_32_array(&val.into_byte_vector())));
|
||||
}
|
||||
for &(idx, ref val) in &c[row] {
|
||||
c_vec.push((row as i32, idx as i32, vec_as_u8_32_array(&val.into_byte_vector())));
|
||||
}
|
||||
for &(idx, ref val) in &a[row] {
|
||||
a_vec.push((
|
||||
row as i32,
|
||||
idx as i32,
|
||||
vec_as_u8_32_array(&val.into_byte_vector()),
|
||||
));
|
||||
}
|
||||
for &(idx, ref val) in &b[row] {
|
||||
b_vec.push((
|
||||
row as i32,
|
||||
idx as i32,
|
||||
vec_as_u8_32_array(&val.into_byte_vector()),
|
||||
));
|
||||
}
|
||||
for &(idx, ref val) in &c[row] {
|
||||
c_vec.push((
|
||||
row as i32,
|
||||
idx as i32,
|
||||
vec_as_u8_32_array(&val.into_byte_vector()),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Sizes and offsets in bytes for our struct {row, id, value}
|
||||
|
@ -92,46 +104,46 @@ pub fn setup<T: Field> (
|
|||
let mut c_arr: Vec<u8> = vec![0u8; STRUCT_SIZE * c_vec.len()];
|
||||
use std::mem::transmute;
|
||||
for (id, (row, idx, val)) in a_vec.iter().enumerate() {
|
||||
let row_bytes: [u8; ROW_SIZE] = unsafe { transmute(row.to_le()) };
|
||||
let idx_bytes: [u8; IDX_SIZE] = unsafe { transmute(idx.to_le()) };
|
||||
let row_bytes: [u8; ROW_SIZE] = unsafe { transmute(row.to_le()) };
|
||||
let idx_bytes: [u8; IDX_SIZE] = unsafe { transmute(idx.to_le()) };
|
||||
|
||||
for x in 0..ROW_SIZE {
|
||||
a_arr[id * STRUCT_SIZE + x] = row_bytes[x];
|
||||
}
|
||||
for x in 0..IDX_SIZE {
|
||||
a_arr[id * STRUCT_SIZE + x + IDX_OFFSET] = idx_bytes[x];
|
||||
}
|
||||
for x in 0..VALUE_SIZE {
|
||||
a_arr[id * STRUCT_SIZE + x + VALUE_OFFSET] = val[x];
|
||||
}
|
||||
for x in 0..ROW_SIZE {
|
||||
a_arr[id * STRUCT_SIZE + x] = row_bytes[x];
|
||||
}
|
||||
for x in 0..IDX_SIZE {
|
||||
a_arr[id * STRUCT_SIZE + x + IDX_OFFSET] = idx_bytes[x];
|
||||
}
|
||||
for x in 0..VALUE_SIZE {
|
||||
a_arr[id * STRUCT_SIZE + x + VALUE_OFFSET] = val[x];
|
||||
}
|
||||
}
|
||||
for (id, (row, idx, val)) in b_vec.iter().enumerate() {
|
||||
let row_bytes: [u8; ROW_SIZE] = unsafe { transmute(row.to_le()) };
|
||||
let idx_bytes: [u8; IDX_SIZE] = unsafe { transmute(idx.to_le()) };
|
||||
let row_bytes: [u8; ROW_SIZE] = unsafe { transmute(row.to_le()) };
|
||||
let idx_bytes: [u8; IDX_SIZE] = unsafe { transmute(idx.to_le()) };
|
||||
|
||||
for x in 0..ROW_SIZE {
|
||||
b_arr[id * STRUCT_SIZE + x] = row_bytes[x];
|
||||
}
|
||||
for x in 0..IDX_SIZE {
|
||||
b_arr[id * STRUCT_SIZE + x + IDX_OFFSET] = idx_bytes[x];
|
||||
}
|
||||
for x in 0..VALUE_SIZE {
|
||||
b_arr[id * STRUCT_SIZE + x + VALUE_OFFSET] = val[x];
|
||||
}
|
||||
for x in 0..ROW_SIZE {
|
||||
b_arr[id * STRUCT_SIZE + x] = row_bytes[x];
|
||||
}
|
||||
for x in 0..IDX_SIZE {
|
||||
b_arr[id * STRUCT_SIZE + x + IDX_OFFSET] = idx_bytes[x];
|
||||
}
|
||||
for x in 0..VALUE_SIZE {
|
||||
b_arr[id * STRUCT_SIZE + x + VALUE_OFFSET] = val[x];
|
||||
}
|
||||
}
|
||||
for (id, (row, idx, val)) in c_vec.iter().enumerate() {
|
||||
let row_bytes: [u8; ROW_SIZE] = unsafe { transmute(row.to_le()) };
|
||||
let idx_bytes: [u8; IDX_SIZE] = unsafe { transmute(idx.to_le()) };
|
||||
let row_bytes: [u8; ROW_SIZE] = unsafe { transmute(row.to_le()) };
|
||||
let idx_bytes: [u8; IDX_SIZE] = unsafe { transmute(idx.to_le()) };
|
||||
|
||||
for x in 0..ROW_SIZE {
|
||||
c_arr[id * STRUCT_SIZE + x] = row_bytes[x];
|
||||
}
|
||||
for x in 0..IDX_SIZE {
|
||||
c_arr[id * STRUCT_SIZE + x + IDX_OFFSET] = idx_bytes[x];
|
||||
}
|
||||
for x in 0..VALUE_SIZE {
|
||||
c_arr[id * STRUCT_SIZE + x + VALUE_OFFSET] = val[x];
|
||||
}
|
||||
for x in 0..ROW_SIZE {
|
||||
c_arr[id * STRUCT_SIZE + x] = row_bytes[x];
|
||||
}
|
||||
for x in 0..IDX_SIZE {
|
||||
c_arr[id * STRUCT_SIZE + x + IDX_OFFSET] = idx_bytes[x];
|
||||
}
|
||||
for x in 0..VALUE_SIZE {
|
||||
c_arr[id * STRUCT_SIZE + x + VALUE_OFFSET] = val[x];
|
||||
}
|
||||
}
|
||||
|
||||
// convert String slices to 'CString's
|
||||
|
@ -150,7 +162,7 @@ pub fn setup<T: Field> (
|
|||
num_variables as i32,
|
||||
num_inputs as i32,
|
||||
pk_path_cstring.as_ptr(),
|
||||
vk_path_cstring.as_ptr()
|
||||
vk_path_cstring.as_ptr(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -161,7 +173,6 @@ pub fn generate_proof<T: Field>(
|
|||
public_inputs: Vec<T>,
|
||||
private_inputs: Vec<T>,
|
||||
) -> bool {
|
||||
|
||||
let pk_path_cstring = CString::new(pk_path).unwrap();
|
||||
let proof_path_cstring = CString::new(proof_path).unwrap();
|
||||
|
||||
|
@ -170,7 +181,7 @@ pub fn generate_proof<T: Field>(
|
|||
|
||||
let mut public_inputs_arr: Vec<[u8; 32]> = vec![[0u8; 32]; public_inputs_length];
|
||||
// length must not be zero here, so we apply the max function
|
||||
let mut private_inputs_arr: Vec<[u8; 32]> = vec![[0u8; 32]; max(private_inputs_length,1)];
|
||||
let mut private_inputs_arr: Vec<[u8; 32]> = vec![[0u8; 32]; max(private_inputs_length, 1)];
|
||||
|
||||
//convert inputs
|
||||
for (index, value) in public_inputs.into_iter().enumerate() {
|
||||
|
@ -187,7 +198,7 @@ pub fn generate_proof<T: Field>(
|
|||
public_inputs_arr[0].as_ptr(),
|
||||
public_inputs_length as i32,
|
||||
private_inputs_arr[0].as_ptr(),
|
||||
private_inputs_length as i32
|
||||
private_inputs_length as i32,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -197,14 +208,15 @@ pub fn get_sha256_constraints() -> String {
|
|||
a.into_string().unwrap()
|
||||
}
|
||||
|
||||
pub fn get_sha256_witness<T:Field>(inputs: &Vec<T>) -> String {
|
||||
pub fn get_sha256_witness<T: Field>(inputs: &Vec<T>) -> String {
|
||||
let mut inputs_arr: Vec<[u8; 32]> = vec![[0u8; 32]; inputs.len()];
|
||||
|
||||
for (index, value) in inputs.into_iter().enumerate() {
|
||||
inputs_arr[index] = vec_as_u8_32_array(&value.into_byte_vector());
|
||||
}
|
||||
|
||||
let a = unsafe { CString::from_raw(_sha256Witness(inputs_arr[0].as_ptr(), inputs.len() as i32)) };
|
||||
let a =
|
||||
unsafe { CString::from_raw(_sha256Witness(inputs_arr[0].as_ptr(), inputs.len() as i32)) };
|
||||
a.into_string().unwrap()
|
||||
}
|
||||
|
||||
|
@ -213,18 +225,22 @@ pub fn get_ethsha256_constraints() -> String {
|
|||
a.into_string().unwrap()
|
||||
}
|
||||
|
||||
pub fn get_ethsha256_witness<T:Field>(inputs: &Vec<T>) -> String {
|
||||
pub fn get_ethsha256_witness<T: Field>(inputs: &Vec<T>) -> String {
|
||||
let mut inputs_arr: Vec<[u8; 32]> = vec![[0u8; 32]; inputs.len()];
|
||||
|
||||
for (index, value) in inputs.into_iter().enumerate() {
|
||||
inputs_arr[index] = vec_as_u8_32_array(&value.into_byte_vector());
|
||||
}
|
||||
|
||||
let a = unsafe { CString::from_raw(_shaEth256Witness(inputs_arr[0].as_ptr(), inputs.len() as i32)) };
|
||||
let a = unsafe {
|
||||
CString::from_raw(_shaEth256Witness(
|
||||
inputs_arr[0].as_ptr(),
|
||||
inputs.len() as i32,
|
||||
))
|
||||
};
|
||||
a.into_string().unwrap()
|
||||
}
|
||||
|
||||
|
||||
// utility function. Converts a Fields vector-based byte representation to fixed size array.
|
||||
fn vec_as_u8_32_array(vec: &Vec<u8>) -> [u8; 32] {
|
||||
assert!(vec.len() <= 32);
|
||||
|
@ -239,11 +255,11 @@ fn vec_as_u8_32_array(vec: &Vec<u8>) -> [u8; 32] {
|
|||
mod tests {
|
||||
use super::*;
|
||||
use field::FieldPrime;
|
||||
use flat_absy::*;
|
||||
use helpers;
|
||||
use num_bigint::BigUint;
|
||||
use serde_json;
|
||||
use flat_absy::*;
|
||||
use standard;
|
||||
use helpers;
|
||||
|
||||
#[cfg(test)]
|
||||
mod sha256_gadget {
|
||||
|
@ -264,7 +280,10 @@ mod tests {
|
|||
fn can_generate_flattened_code() {
|
||||
let constraints = get_sha256_constraints();
|
||||
let r1cs: standard::R1CS = serde_json::from_str(&constraints).unwrap();
|
||||
let _prog: FlatProg<FieldPrime> = FlatProg::from(standard::DirectiveR1CS{r1cs, directive: helpers::LibsnarkGadgetHelper::Sha256Compress});
|
||||
let _prog: FlatProg<FieldPrime> = FlatProg::from(standard::DirectiveR1CS {
|
||||
r1cs,
|
||||
directive: helpers::LibsnarkGadgetHelper::Sha256Compress,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -278,11 +297,13 @@ mod tests {
|
|||
BigUint::parse_bytes(
|
||||
b"5472060717959818805561601436314318772174077789324455915672259473661306552146",
|
||||
10
|
||||
).unwrap()
|
||||
.to_bytes_le(),
|
||||
)
|
||||
.unwrap()
|
||||
.to_bytes_le(),
|
||||
FieldPrime::from(
|
||||
"5472060717959818805561601436314318772174077789324455915672259473661306552146"
|
||||
).into_byte_vector()
|
||||
)
|
||||
.into_byte_vector()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -298,7 +319,8 @@ mod tests {
|
|||
fn vec_to_array() {
|
||||
let byte_vector: Vec<u8> = FieldPrime::from(
|
||||
"5472060717959818805561601436314318772174077789324455915672259473661306552146",
|
||||
).into_byte_vector();
|
||||
)
|
||||
.into_byte_vector();
|
||||
let array: [u8; 32] = vec_as_u8_32_array(&byte_vector);
|
||||
for (index, value) in byte_vector.iter().enumerate() {
|
||||
assert_eq!(*value, array[31 - index]);
|
||||
|
|
|
@ -5,221 +5,235 @@
|
|||
//! @author Jacob Eberhardt <jacob.eberhardt@tu-berlin.de>
|
||||
//! @date 2017
|
||||
|
||||
use std::collections::HashMap;
|
||||
use flat_absy::*;
|
||||
use field::Field;
|
||||
use flat_absy::flat_variable::FlatVariable;
|
||||
use flat_absy::*;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub struct Optimizer {
|
||||
/// Map of renamings for reassigned variables while processing the program.
|
||||
substitution: HashMap<FlatVariable, FlatVariable>,
|
||||
/// Index of the next introduced variable while processing the program.
|
||||
next_var_idx: Counter
|
||||
/// Map of renamings for reassigned variables while processing the program.
|
||||
substitution: HashMap<FlatVariable, FlatVariable>,
|
||||
/// Index of the next introduced variable while processing the program.
|
||||
next_var_idx: Counter,
|
||||
}
|
||||
|
||||
pub struct Counter {
|
||||
value: usize
|
||||
value: usize,
|
||||
}
|
||||
|
||||
impl Counter {
|
||||
fn increment(&mut self) -> usize {
|
||||
let index = self.value;
|
||||
self.value = self.value + 1;
|
||||
index
|
||||
}
|
||||
fn increment(&mut self) -> usize {
|
||||
let index = self.value;
|
||||
self.value = self.value + 1;
|
||||
index
|
||||
}
|
||||
}
|
||||
|
||||
impl Optimizer {
|
||||
pub fn new() -> Optimizer {
|
||||
Optimizer {
|
||||
substitution: HashMap::new(),
|
||||
next_var_idx: Counter {
|
||||
value: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn new() -> Optimizer {
|
||||
Optimizer {
|
||||
substitution: HashMap::new(),
|
||||
next_var_idx: Counter { value: 0 },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn optimize_program<T: Field>(&mut self, prog: FlatProg<T>) -> FlatProg<T> {
|
||||
let optimized_program = FlatProg {
|
||||
functions: prog.functions.into_iter().filter_map(|func| {
|
||||
if func.id == "main" {
|
||||
return Some(self.optimize_function(func));
|
||||
}
|
||||
return None;
|
||||
}).collect()
|
||||
};
|
||||
optimized_program
|
||||
}
|
||||
pub fn optimize_program<T: Field>(&mut self, prog: FlatProg<T>) -> FlatProg<T> {
|
||||
let optimized_program = FlatProg {
|
||||
functions: prog
|
||||
.functions
|
||||
.into_iter()
|
||||
.filter_map(|func| {
|
||||
if func.id == "main" {
|
||||
return Some(self.optimize_function(func));
|
||||
}
|
||||
return None;
|
||||
})
|
||||
.collect(),
|
||||
};
|
||||
optimized_program
|
||||
}
|
||||
|
||||
pub fn optimize_function<T: Field>(&mut self, funct: FlatFunction<T>) -> FlatFunction<T> {
|
||||
// Add arguments to substitution map
|
||||
for arg in funct.arguments.clone() {
|
||||
self.substitution.insert(arg.id, FlatVariable::new(self.next_var_idx.increment()));
|
||||
};
|
||||
pub fn optimize_function<T: Field>(&mut self, funct: FlatFunction<T>) -> FlatFunction<T> {
|
||||
// Add arguments to substitution map
|
||||
for arg in funct.arguments.clone() {
|
||||
self.substitution
|
||||
.insert(arg.id, FlatVariable::new(self.next_var_idx.increment()));
|
||||
}
|
||||
|
||||
// generate substitution map
|
||||
//
|
||||
// (b = a, c = b) => ( b -> a, c -> a )
|
||||
// The first variable to appear is used for its synonyms.
|
||||
// generate substitution map
|
||||
//
|
||||
// (b = a, c = b) => ( b -> a, c -> a )
|
||||
// The first variable to appear is used for its synonyms.
|
||||
|
||||
for statement in &funct.statements {
|
||||
match *statement {
|
||||
// Synonym definition
|
||||
// if the right side of the assignment is already being reassigned to `x`,
|
||||
// reassign the left side to `x` as well, otherwise reassign to a new variable
|
||||
FlatStatement::Definition(ref left, FlatExpression::Identifier(ref right)) => {
|
||||
let r = match self.substitution.get(right) {
|
||||
Some(value) => {
|
||||
value.clone()
|
||||
},
|
||||
None => {
|
||||
FlatVariable::new(self.next_var_idx.increment())
|
||||
}
|
||||
};
|
||||
self.substitution.insert(left.clone(), r);
|
||||
},
|
||||
// Other definitions
|
||||
FlatStatement::Definition(ref left, _) => {
|
||||
self.substitution.insert(left.clone(), FlatVariable::new(self.next_var_idx.increment()));
|
||||
},
|
||||
FlatStatement::Directive(ref d) => {
|
||||
for o in d.outputs.iter() {
|
||||
self.substitution.insert(o.clone(), FlatVariable::new(self.next_var_idx.increment()));
|
||||
}
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
for statement in &funct.statements {
|
||||
match *statement {
|
||||
// Synonym definition
|
||||
// if the right side of the assignment is already being reassigned to `x`,
|
||||
// reassign the left side to `x` as well, otherwise reassign to a new variable
|
||||
FlatStatement::Definition(ref left, FlatExpression::Identifier(ref right)) => {
|
||||
let r = match self.substitution.get(right) {
|
||||
Some(value) => value.clone(),
|
||||
None => FlatVariable::new(self.next_var_idx.increment()),
|
||||
};
|
||||
self.substitution.insert(left.clone(), r);
|
||||
}
|
||||
// Other definitions
|
||||
FlatStatement::Definition(ref left, _) => {
|
||||
self.substitution.insert(
|
||||
left.clone(),
|
||||
FlatVariable::new(self.next_var_idx.increment()),
|
||||
);
|
||||
}
|
||||
FlatStatement::Directive(ref d) => {
|
||||
for o in d.outputs.iter() {
|
||||
self.substitution
|
||||
.insert(o.clone(), FlatVariable::new(self.next_var_idx.increment()));
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
// generate optimized statements by removing synonym declarations and renaming variables
|
||||
let optimized_statements = funct.statements.into_iter().filter_map(|statement| {
|
||||
match statement {
|
||||
// filter out synonyms definitions
|
||||
FlatStatement::Definition(_, FlatExpression::Identifier(_)) => {
|
||||
None
|
||||
},
|
||||
// substitute all other statements
|
||||
_ => {
|
||||
Some(statement.apply_direct_substitution(&self.substitution))
|
||||
}
|
||||
}
|
||||
}).collect();
|
||||
// generate optimized statements by removing synonym declarations and renaming variables
|
||||
let optimized_statements = funct
|
||||
.statements
|
||||
.into_iter()
|
||||
.filter_map(|statement| {
|
||||
match statement {
|
||||
// filter out synonyms definitions
|
||||
FlatStatement::Definition(_, FlatExpression::Identifier(_)) => None,
|
||||
// substitute all other statements
|
||||
_ => Some(statement.apply_direct_substitution(&self.substitution)),
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
// generate optimized arguments by renaming them
|
||||
let optimized_arguments = funct.arguments.into_iter().map(|arg| arg.apply_direct_substitution(&self.substitution)).collect();
|
||||
// generate optimized arguments by renaming them
|
||||
let optimized_arguments = funct
|
||||
.arguments
|
||||
.into_iter()
|
||||
.map(|arg| arg.apply_direct_substitution(&self.substitution))
|
||||
.collect();
|
||||
|
||||
FlatFunction {
|
||||
arguments: optimized_arguments,
|
||||
statements: optimized_statements,
|
||||
..funct
|
||||
}
|
||||
}
|
||||
FlatFunction {
|
||||
arguments: optimized_arguments,
|
||||
statements: optimized_statements,
|
||||
..funct
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use types::{Type, Signature};
|
||||
use super::*;
|
||||
use field::FieldPrime;
|
||||
use flat_absy::flat_parameter::FlatParameter;
|
||||
use super::*;
|
||||
use field::FieldPrime;
|
||||
use flat_absy::flat_parameter::FlatParameter;
|
||||
use types::{Signature, Type};
|
||||
|
||||
#[test]
|
||||
fn remove_synonyms() {
|
||||
#[test]
|
||||
fn remove_synonyms() {
|
||||
// def main(x):
|
||||
// y = x
|
||||
// z = y
|
||||
// return z
|
||||
|
||||
// def main(x):
|
||||
// y = x
|
||||
// z = y
|
||||
// return z
|
||||
let x = FlatVariable::new(0);
|
||||
let y = FlatVariable::new(1);
|
||||
let z = FlatVariable::new(2);
|
||||
|
||||
let x = FlatVariable::new(0);
|
||||
let y = FlatVariable::new(1);
|
||||
let z = FlatVariable::new(2);
|
||||
|
||||
let f: FlatFunction<FieldPrime> = FlatFunction {
|
||||
let f: FlatFunction<FieldPrime> = FlatFunction {
|
||||
id: "foo".to_string(),
|
||||
arguments: vec![FlatParameter {id: x, private: false}],
|
||||
arguments: vec![FlatParameter {
|
||||
id: x,
|
||||
private: false,
|
||||
}],
|
||||
statements: vec![
|
||||
FlatStatement::Definition(y, FlatExpression::Identifier(x)),
|
||||
FlatStatement::Definition(z, FlatExpression::Identifier(y)),
|
||||
FlatStatement::Return(FlatExpressionList {
|
||||
expressions: vec![FlatExpression::Identifier(z)]
|
||||
})
|
||||
FlatStatement::Definition(y, FlatExpression::Identifier(x)),
|
||||
FlatStatement::Definition(z, FlatExpression::Identifier(y)),
|
||||
FlatStatement::Return(FlatExpressionList {
|
||||
expressions: vec![FlatExpression::Identifier(z)],
|
||||
}),
|
||||
],
|
||||
signature: Signature {
|
||||
inputs: vec![Type::FieldElement],
|
||||
outputs: vec![Type::FieldElement]
|
||||
}
|
||||
inputs: vec![Type::FieldElement],
|
||||
outputs: vec![Type::FieldElement],
|
||||
},
|
||||
};
|
||||
|
||||
let optimized: FlatFunction<FieldPrime> = FlatFunction {
|
||||
id: "foo".to_string(),
|
||||
arguments: vec![FlatParameter {id: x, private: false}],
|
||||
statements: vec![
|
||||
FlatStatement::Return(FlatExpressionList {
|
||||
expressions: vec![FlatExpression::Identifier(x)]
|
||||
})
|
||||
],
|
||||
signature: Signature {
|
||||
inputs: vec![Type::FieldElement],
|
||||
outputs: vec![Type::FieldElement]
|
||||
}
|
||||
arguments: vec![FlatParameter {
|
||||
id: x,
|
||||
private: false,
|
||||
}],
|
||||
statements: vec![FlatStatement::Return(FlatExpressionList {
|
||||
expressions: vec![FlatExpression::Identifier(x)],
|
||||
})],
|
||||
signature: Signature {
|
||||
inputs: vec![Type::FieldElement],
|
||||
outputs: vec![Type::FieldElement],
|
||||
},
|
||||
};
|
||||
|
||||
let mut optimizer = Optimizer::new();
|
||||
assert_eq!(optimizer.optimize_function(f), optimized);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn remove_multiple_synonyms() {
|
||||
// def main(x):
|
||||
// y = x
|
||||
// t = 1
|
||||
// z = y
|
||||
// w = t
|
||||
// return z, w
|
||||
|
||||
#[test]
|
||||
fn remove_multiple_synonyms() {
|
||||
let x = FlatVariable::new(0);
|
||||
let y = FlatVariable::new(1);
|
||||
let z = FlatVariable::new(2);
|
||||
let t = FlatVariable::new(3);
|
||||
let w = FlatVariable::new(4);
|
||||
|
||||
// def main(x):
|
||||
// y = x
|
||||
// t = 1
|
||||
// z = y
|
||||
// w = t
|
||||
// return z, w
|
||||
|
||||
let x = FlatVariable::new(0);
|
||||
let y = FlatVariable::new(1);
|
||||
let z = FlatVariable::new(2);
|
||||
let t = FlatVariable::new(3);
|
||||
let w = FlatVariable::new(4);
|
||||
|
||||
let f: FlatFunction<FieldPrime> = FlatFunction {
|
||||
let f: FlatFunction<FieldPrime> = FlatFunction {
|
||||
id: "foo".to_string(),
|
||||
arguments: vec![FlatParameter {id: x, private: false}],
|
||||
arguments: vec![FlatParameter {
|
||||
id: x,
|
||||
private: false,
|
||||
}],
|
||||
statements: vec![
|
||||
FlatStatement::Definition(y, FlatExpression::Identifier(x)),
|
||||
FlatStatement::Definition(t, FlatExpression::Number(FieldPrime::from(1))),
|
||||
FlatStatement::Definition(z, FlatExpression::Identifier(y)),
|
||||
FlatStatement::Definition(w, FlatExpression::Identifier(t)),
|
||||
FlatStatement::Return(FlatExpressionList {
|
||||
expressions: vec![FlatExpression::Identifier(z), FlatExpression::Identifier(w)]
|
||||
})
|
||||
FlatStatement::Definition(y, FlatExpression::Identifier(x)),
|
||||
FlatStatement::Definition(t, FlatExpression::Number(FieldPrime::from(1))),
|
||||
FlatStatement::Definition(z, FlatExpression::Identifier(y)),
|
||||
FlatStatement::Definition(w, FlatExpression::Identifier(t)),
|
||||
FlatStatement::Return(FlatExpressionList {
|
||||
expressions: vec![FlatExpression::Identifier(z), FlatExpression::Identifier(w)],
|
||||
}),
|
||||
],
|
||||
signature: Signature {
|
||||
inputs: vec![Type::FieldElement],
|
||||
outputs: vec![Type::FieldElement, Type::FieldElement]
|
||||
}
|
||||
signature: Signature {
|
||||
inputs: vec![Type::FieldElement],
|
||||
outputs: vec![Type::FieldElement, Type::FieldElement],
|
||||
},
|
||||
};
|
||||
|
||||
let optimized: FlatFunction<FieldPrime> = FlatFunction {
|
||||
id: "foo".to_string(),
|
||||
arguments: vec![FlatParameter {id: x, private: false}],
|
||||
statements: vec![
|
||||
FlatStatement::Definition(y, FlatExpression::Number(FieldPrime::from(1))),
|
||||
FlatStatement::Return(FlatExpressionList {
|
||||
expressions: vec![FlatExpression::Identifier(x), FlatExpression::Identifier(y)]
|
||||
})
|
||||
],
|
||||
signature: Signature {
|
||||
inputs: vec![Type::FieldElement],
|
||||
outputs: vec![Type::FieldElement, Type::FieldElement]
|
||||
}
|
||||
arguments: vec![FlatParameter {
|
||||
id: x,
|
||||
private: false,
|
||||
}],
|
||||
statements: vec![
|
||||
FlatStatement::Definition(y, FlatExpression::Number(FieldPrime::from(1))),
|
||||
FlatStatement::Return(FlatExpressionList {
|
||||
expressions: vec![FlatExpression::Identifier(x), FlatExpression::Identifier(y)],
|
||||
}),
|
||||
],
|
||||
signature: Signature {
|
||||
inputs: vec![Type::FieldElement],
|
||||
outputs: vec![Type::FieldElement, Type::FieldElement],
|
||||
},
|
||||
};
|
||||
|
||||
let mut optimizer = Optimizer::new();
|
||||
assert_eq!(optimizer.optimize_function(f), optimized);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,4 +26,4 @@ impl<T: Field> fmt::Debug for Error<T> {
|
|||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
mod tokenize;
|
||||
mod error;
|
||||
mod parse;
|
||||
mod tokenize;
|
||||
|
||||
pub use parser::error::Error;
|
||||
pub use parser::parse::parse_program;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use field::Field;
|
||||
|
||||
use parser::tokenize::{next_token, Position, Token};
|
||||
use parser::Error;
|
||||
use parser::tokenize::{Token, Position, next_token};
|
||||
|
||||
use absy::{Expression};
|
||||
use absy::Expression;
|
||||
|
||||
fn parse_then_else<T: Field>(
|
||||
cond: Expression<T>,
|
||||
|
@ -74,7 +74,7 @@ fn parse_prim_cond<T: Field>(
|
|||
pos: p3,
|
||||
}),
|
||||
},
|
||||
Err(err) => Err(err)
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -177,15 +177,15 @@ fn parse_bexpr<T: Field>(
|
|||
Err(_) => match parse_prim_cond(input, pos) {
|
||||
Ok((e2, s2, p2)) => match parse_bterm1(e2, s2, p2) {
|
||||
Ok((e3, s3, p3)) => parse_bexpr1(e3, s3, p3),
|
||||
Err(err) => Err(err)
|
||||
}
|
||||
Err(err) => Err(err)
|
||||
Err(err) => Err(err),
|
||||
},
|
||||
Err(err) => Err(err),
|
||||
},
|
||||
},
|
||||
(Token::Ide(_), _, _) | (Token::Num(_), _, _) => match parse_prim_cond(input, pos) {
|
||||
Ok((e2, s2, p2)) => match parse_bterm1(e2, s2, p2) {
|
||||
Ok((e3, s3, p3)) => parse_bexpr1(e3, s3, p3),
|
||||
Err(err) => Err(err)
|
||||
Err(err) => Err(err),
|
||||
},
|
||||
Err(err) => Err(err),
|
||||
},
|
||||
|
@ -314,13 +314,11 @@ pub fn parse_expr1<T: Field>(
|
|||
Err(err) => Err(err),
|
||||
},
|
||||
(Token::Pow, s1, p1) => match parse_term(&s1, &p1) {
|
||||
Ok((e, s2, p2)) => {
|
||||
match parse_term1(Expression::Pow(box expr, box e), s2, p2) {
|
||||
Ok((e3, s3, p3)) => parse_expr1(e3, s3, p3),
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
Ok((e, s2, p2)) => match parse_term1(Expression::Pow(box expr, box e), s2, p2) {
|
||||
Ok((e3, s3, p3)) => parse_expr1(e3, s3, p3),
|
||||
Err(err) => Err(err),
|
||||
},
|
||||
Err(err) => Err(err)
|
||||
Err(err) => Err(err),
|
||||
},
|
||||
_ => Ok((expr, input, pos)),
|
||||
}
|
||||
|
@ -431,23 +429,21 @@ pub fn parse_array_select<T: Field>(
|
|||
// array select can have exactly one arg
|
||||
match next_token::<T>(&input, &pos) {
|
||||
(_, _, _) => match parse_expr(&input, &pos) {
|
||||
Ok((e1, s1, p1)) => {
|
||||
match next_token::<T>(&s1, &p1) {
|
||||
(Token::RightBracket, s2, p2) => {
|
||||
match parse_term1(Expression::Select(box Expression::Identifier(ide), box e1), s2, p2) {
|
||||
Ok((e3, s3, p3)) => parse_expr1(e3, s3, p3),
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
(t2, _, p2) => {
|
||||
Err(Error {
|
||||
expected: vec![Token::RightBracket],
|
||||
got: t2,
|
||||
pos: p2,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok((e1, s1, p1)) => match next_token::<T>(&s1, &p1) {
|
||||
(Token::RightBracket, s2, p2) => match parse_term1(
|
||||
Expression::Select(box Expression::Identifier(ide), box e1),
|
||||
s2,
|
||||
p2,
|
||||
) {
|
||||
Ok((e3, s3, p3)) => parse_expr1(e3, s3, p3),
|
||||
Err(err) => Err(err),
|
||||
},
|
||||
(t2, _, p2) => Err(Error {
|
||||
expected: vec![Token::RightBracket],
|
||||
got: t2,
|
||||
pos: p2,
|
||||
}),
|
||||
},
|
||||
Err(err) => Err(err),
|
||||
},
|
||||
}
|
||||
|
@ -519,7 +515,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn parse_boolean_and() {
|
||||
let pos = Position{line: 45, col: 121};
|
||||
let pos = Position { line: 45, col: 121 };
|
||||
let string = String::from("if a < b && 2*a > b && b > a then c else d fi");
|
||||
|
||||
let expr = Expression::IfElse::<FieldPrime>(
|
||||
|
@ -561,7 +557,10 @@ mod tests {
|
|||
let string = String::from("foo[42 + 33]");
|
||||
let expr = Expression::Select::<FieldPrime>(
|
||||
box Expression::Identifier(String::from("foo")),
|
||||
box Expression::Add(box Expression::Number(FieldPrime::from(42)), box Expression::Number(FieldPrime::from(33))),
|
||||
box Expression::Add(
|
||||
box Expression::Number(FieldPrime::from(42)),
|
||||
box Expression::Number(FieldPrime::from(33)),
|
||||
),
|
||||
);
|
||||
assert_eq!(
|
||||
Ok((expr, String::from(""), pos.col(string.len() as isize))),
|
||||
|
@ -585,7 +584,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn parse_boolean_or() {
|
||||
let pos = Position{line: 45, col: 121};
|
||||
let pos = Position { line: 45, col: 121 };
|
||||
let string = String::from("if a < b || 2*a > b then c else d fi");
|
||||
|
||||
let expr = Expression::IfElse::<FieldPrime>(
|
||||
|
@ -612,25 +611,25 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn parse_boolean_operator_associativity(){
|
||||
fn parse_boolean_operator_associativity() {
|
||||
use absy::Expression::*;
|
||||
let pos = Position{line: 45, col: 121};
|
||||
let pos = Position { line: 45, col: 121 };
|
||||
let string = String::from("2 == 3 || 4 == 5 && 6 == 7");
|
||||
let expr = Or::<FieldPrime>(
|
||||
box Eq(
|
||||
box Number(FieldPrime::from(2)),
|
||||
box Number(FieldPrime::from(3))
|
||||
box Number(FieldPrime::from(3)),
|
||||
),
|
||||
box And(
|
||||
box Eq(
|
||||
box Number(FieldPrime::from(4)),
|
||||
box Number(FieldPrime::from(5))
|
||||
box Number(FieldPrime::from(5)),
|
||||
),
|
||||
box Eq(
|
||||
box Number(FieldPrime::from(6)),
|
||||
box Number(FieldPrime::from(7))
|
||||
)
|
||||
)
|
||||
box Number(FieldPrime::from(7)),
|
||||
),
|
||||
),
|
||||
);
|
||||
assert_eq!(
|
||||
Ok((expr, String::from(""), pos.col(string.len() as isize))),
|
||||
|
@ -641,28 +640,38 @@ mod tests {
|
|||
#[test]
|
||||
fn parse_boolean_expr() {
|
||||
use absy::Expression::*;
|
||||
let pos = Position{line: 45, col: 121};
|
||||
let pos = Position { line: 45, col: 121 };
|
||||
let string = String::from("(a + 2 == 3) && (a * 2 + 3 == 2 || a < 3) || 1 < 2");
|
||||
let expr = Or::<FieldPrime>(
|
||||
box And(
|
||||
box Eq(
|
||||
box Add(box Identifier(String::from("a")),
|
||||
box Number(FieldPrime::from(2))),
|
||||
box Number(FieldPrime::from(3))
|
||||
box Add(
|
||||
box Identifier(String::from("a")),
|
||||
box Number(FieldPrime::from(2)),
|
||||
),
|
||||
box Number(FieldPrime::from(3)),
|
||||
),
|
||||
box Or(
|
||||
box Eq(
|
||||
box Add(
|
||||
box Mult(box Identifier(String::from("a")),
|
||||
box Number(FieldPrime::from(2))
|
||||
box Mult(
|
||||
box Identifier(String::from("a")),
|
||||
box Number(FieldPrime::from(2)),
|
||||
),
|
||||
box Number(FieldPrime::from(3))
|
||||
box Number(FieldPrime::from(3)),
|
||||
),
|
||||
box Number(FieldPrime::from(2))),
|
||||
box Lt(box Identifier(String::from("a")), box Number(FieldPrime::from(3)))
|
||||
)
|
||||
box Number(FieldPrime::from(2)),
|
||||
),
|
||||
box Lt(
|
||||
box Identifier(String::from("a")),
|
||||
box Number(FieldPrime::from(3)),
|
||||
),
|
||||
),
|
||||
),
|
||||
box Lt(
|
||||
box Number(FieldPrime::from(1)),
|
||||
box Number(FieldPrime::from(2)),
|
||||
),
|
||||
box Lt(box Number(FieldPrime::from(1)), box Number(FieldPrime::from(2)))
|
||||
);
|
||||
assert_eq!(
|
||||
Ok((expr, String::from(""), pos.col(string.len() as isize))),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use field::Field;
|
||||
|
||||
use parser::tokenize::{next_token, Position, Token};
|
||||
use parser::Error;
|
||||
use parser::tokenize::{Token, Position, next_token};
|
||||
|
||||
use super::expression::parse_expr;
|
||||
|
||||
|
@ -17,34 +17,36 @@ pub fn parse_expression_list<T: Field>(
|
|||
}
|
||||
|
||||
fn parse_comma_separated_expression_list_rec<T: Field>(
|
||||
input: String,
|
||||
input: String,
|
||||
pos: Position,
|
||||
mut acc: &mut ExpressionList<T>
|
||||
mut acc: &mut ExpressionList<T>,
|
||||
) -> Result<(ExpressionList<T>, String, Position), Error<T>> {
|
||||
match parse_expr(&input, &pos) {
|
||||
Ok((e1, s1, p1)) => {
|
||||
acc.expressions.push(e1);
|
||||
match next_token::<T>(&s1, &p1) {
|
||||
(Token::Comma, s2, p2) => parse_comma_separated_expression_list_rec(s2, p2, &mut acc),
|
||||
(Token::Comma, s2, p2) => {
|
||||
parse_comma_separated_expression_list_rec(s2, p2, &mut acc)
|
||||
}
|
||||
(..) => Ok((acc.clone(), s1, p1)),
|
||||
}
|
||||
},
|
||||
Err(err) => Err(err)
|
||||
}
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use field::FieldPrime;
|
||||
use absy::Expression;
|
||||
use field::FieldPrime;
|
||||
|
||||
fn parse_comma_separated_list<T: Field>(
|
||||
input: String,
|
||||
pos: Position
|
||||
) -> Result<(ExpressionList<T>, String, Position), Error<T>> {
|
||||
input: String,
|
||||
pos: Position,
|
||||
) -> Result<(ExpressionList<T>, String, Position), Error<T>> {
|
||||
let mut res = ExpressionList::new();
|
||||
parse_comma_separated_expression_list_rec(input, pos, &mut res)
|
||||
parse_comma_separated_expression_list_rec(input, pos, &mut res)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -52,7 +54,10 @@ mod tests {
|
|||
let pos = Position { line: 45, col: 121 };
|
||||
let string = String::from("b, c");
|
||||
let expr = ExpressionList::<FieldPrime> {
|
||||
expressions: vec![Expression::Identifier(String::from("b")),Expression::Identifier(String::from("c"))]
|
||||
expressions: vec![
|
||||
Expression::Identifier(String::from("b")),
|
||||
Expression::Identifier(String::from("c")),
|
||||
],
|
||||
};
|
||||
assert_eq!(
|
||||
Ok((expr, String::from(""), pos.col(string.len() as isize))),
|
||||
|
@ -65,7 +70,7 @@ mod tests {
|
|||
let pos = Position { line: 45, col: 121 };
|
||||
let string = String::from("a");
|
||||
let exprs = ExpressionList {
|
||||
expressions: vec![Expression::Identifier(String::from("a"))]
|
||||
expressions: vec![Expression::Identifier(String::from("a"))],
|
||||
};
|
||||
assert_eq!(
|
||||
Ok((exprs, String::from(""), pos.col(string.len() as isize))),
|
||||
|
@ -81,12 +86,12 @@ mod tests {
|
|||
expressions: vec![
|
||||
Expression::Identifier(String::from("a")),
|
||||
Expression::Identifier(String::from("b")),
|
||||
Expression::Identifier(String::from("c"))
|
||||
]
|
||||
Expression::Identifier(String::from("c")),
|
||||
],
|
||||
};
|
||||
assert_eq!(
|
||||
Ok((exprs, String::from(""), pos.col(string.len() as isize))),
|
||||
parse_comma_separated_list::<FieldPrime>(string, pos)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,64 +1,52 @@
|
|||
use field::Field;
|
||||
|
||||
use std::io::prelude::*;
|
||||
use std::io::{Lines};
|
||||
use std::io::Lines;
|
||||
|
||||
use parser::tokenize::{next_token, Position, Token};
|
||||
use parser::Error;
|
||||
use parser::tokenize::{Token, Position, next_token};
|
||||
|
||||
use super::statement::parse_statement;
|
||||
|
||||
use absy::{Function, Statement, Variable, Parameter};
|
||||
use types::{Type, Signature};
|
||||
use absy::{Function, Parameter, Statement, Variable};
|
||||
use types::{Signature, Type};
|
||||
|
||||
fn parse_function_identifier<T: Field>(
|
||||
input: &String,
|
||||
pos: &Position
|
||||
pos: &Position,
|
||||
) -> Result<(String, String, Position), Error<T>> {
|
||||
match next_token::<T>(&input, &pos) {
|
||||
(Token::Ide(x), s, p) => {
|
||||
Ok((x, s, p))
|
||||
},
|
||||
(t, _, p) => {
|
||||
Err(Error {
|
||||
expected: vec![Token::Ide(String::from("name"))],
|
||||
got: t,
|
||||
pos: p,
|
||||
})
|
||||
}
|
||||
(Token::Ide(x), s, p) => Ok((x, s, p)),
|
||||
(t, _, p) => Err(Error {
|
||||
expected: vec![Token::Ide(String::from("name"))],
|
||||
got: t,
|
||||
pos: p,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn parse_function_header<T: Field>(
|
||||
input: &String,
|
||||
pos: &Position
|
||||
pos: &Position,
|
||||
) -> Result<(String, Vec<Parameter>, Signature), Error<T>> {
|
||||
// parse function identifier
|
||||
let (id, s, p) = parse_function_identifier(input, pos)?;
|
||||
|
||||
// parse function arguments, enclosed by parentheses
|
||||
let (args, s, p) = match next_token(&s, &p) {
|
||||
(Token::Open, s1, p1) => {
|
||||
match parse_function_arguments(s1, p1) {
|
||||
Ok((args, s2, p2)) => {
|
||||
match next_token::<T>(&s2, &p2) {
|
||||
(Token::Close, s3, p3) => {
|
||||
Ok((args, s3, p3))
|
||||
},
|
||||
(t3, _, p3) => {
|
||||
return Err(Error {
|
||||
expected: vec![Token::Close],
|
||||
got: t3,
|
||||
pos: p3
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
(Token::Open, s1, p1) => match parse_function_arguments(s1, p1) {
|
||||
Ok((args, s2, p2)) => match next_token::<T>(&s2, &p2) {
|
||||
(Token::Close, s3, p3) => Ok((args, s3, p3)),
|
||||
(t3, _, p3) => {
|
||||
return Err(Error {
|
||||
expected: vec![Token::Close],
|
||||
got: t3,
|
||||
pos: p3,
|
||||
})
|
||||
}
|
||||
},
|
||||
Err(e) => return Err(e),
|
||||
},
|
||||
(t1, _, p1) => {
|
||||
return Err(Error {
|
||||
expected: vec![Token::Open],
|
||||
|
@ -70,34 +58,26 @@ fn parse_function_header<T: Field>(
|
|||
|
||||
// parse function return types, enclosed by parentheses
|
||||
let (return_types, s, p) = match next_token(&s, &p) {
|
||||
(Token::Arrow, s0, p0) => {
|
||||
match next_token(&s0, &p0) {
|
||||
(Token::Open, s1, p1) => {
|
||||
match parse_function_return_types(s1, p1) {
|
||||
Ok((types, s2, p2)) => {
|
||||
match next_token::<T>(&s2, &p2) {
|
||||
(Token::Close, s3, p3) => {
|
||||
Ok((types, s3, p3))
|
||||
},
|
||||
(t3, _, p3) => {
|
||||
return Err(Error {
|
||||
expected: vec![Token::Close],
|
||||
got: t3,
|
||||
pos: p3
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(e) => return Err(e),
|
||||
(Token::Arrow, s0, p0) => match next_token(&s0, &p0) {
|
||||
(Token::Open, s1, p1) => match parse_function_return_types(s1, p1) {
|
||||
Ok((types, s2, p2)) => match next_token::<T>(&s2, &p2) {
|
||||
(Token::Close, s3, p3) => Ok((types, s3, p3)),
|
||||
(t3, _, p3) => {
|
||||
return Err(Error {
|
||||
expected: vec![Token::Close],
|
||||
got: t3,
|
||||
pos: p3,
|
||||
})
|
||||
}
|
||||
}
|
||||
(t1, _, p1) => {
|
||||
return Err(Error {
|
||||
expected: vec![Token::Open],
|
||||
got: t1,
|
||||
pos: p1,
|
||||
})
|
||||
}
|
||||
},
|
||||
Err(e) => return Err(e),
|
||||
},
|
||||
(t1, _, p1) => {
|
||||
return Err(Error {
|
||||
expected: vec![Token::Open],
|
||||
got: t1,
|
||||
pos: p1,
|
||||
})
|
||||
}
|
||||
},
|
||||
(t0, _, p0) => {
|
||||
|
@ -111,7 +91,7 @@ fn parse_function_header<T: Field>(
|
|||
|
||||
let sig = Signature {
|
||||
inputs: args.iter().map(|a| a.id.get_type()).collect(),
|
||||
outputs: return_types
|
||||
outputs: return_types,
|
||||
};
|
||||
|
||||
match next_token(&s, &p) {
|
||||
|
@ -138,33 +118,25 @@ fn parse_function_header<T: Field>(
|
|||
|
||||
fn parse_function_argument_variable<T: Field>(
|
||||
input: &String,
|
||||
pos: &Position
|
||||
pos: &Position,
|
||||
) -> Result<(Variable, String, Position), Error<T>> {
|
||||
let s4 = input;
|
||||
let p4 = pos;
|
||||
|
||||
match next_token::<T>(&s4, &p4) {
|
||||
(Token::Type(t), s5, p5) => {
|
||||
match next_token(&s5, &p5) {
|
||||
(Token::Ide(x), s6, p6) => {
|
||||
Ok((Variable::new(x, t), s6, p6))
|
||||
}
|
||||
(t6, _, p6) => {
|
||||
Err(Error {
|
||||
expected: vec![Token::Ide(String::from("identifier"))],
|
||||
got: t6,
|
||||
pos: p6,
|
||||
})
|
||||
}
|
||||
}
|
||||
(Token::Type(t), s5, p5) => match next_token(&s5, &p5) {
|
||||
(Token::Ide(x), s6, p6) => Ok((Variable::new(x, t), s6, p6)),
|
||||
(t6, _, p6) => Err(Error {
|
||||
expected: vec![Token::Ide(String::from("identifier"))],
|
||||
got: t6,
|
||||
pos: p6,
|
||||
}),
|
||||
},
|
||||
(t5, _, p5) => {
|
||||
Err(Error {
|
||||
expected: vec![Token::Type(Type::FieldElement)],
|
||||
got: t5,
|
||||
pos: p5,
|
||||
})
|
||||
}
|
||||
(t5, _, p5) => Err(Error {
|
||||
expected: vec![Token::Type(Type::FieldElement)],
|
||||
got: t5,
|
||||
pos: p5,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,50 +152,54 @@ fn parse_function_arguments<T: Field>(
|
|||
match next_token(&s, &p) {
|
||||
(Token::Private, s1, p1) => {
|
||||
let (var, s2, p2) = parse_function_argument_variable::<T>(&s1, &p1)?;
|
||||
args.push(Parameter { id: var, private: true});
|
||||
args.push(Parameter {
|
||||
id: var,
|
||||
private: true,
|
||||
});
|
||||
match next_token::<T>(&s2, &p2) {
|
||||
(Token::Comma, s3, p3) => {
|
||||
s = s3;
|
||||
p = p3;
|
||||
},
|
||||
(Token::Close, _, _) => {
|
||||
return Ok((args, s2, p2))
|
||||
},
|
||||
}
|
||||
(Token::Close, _, _) => return Ok((args, s2, p2)),
|
||||
(t3, _, p3) => {
|
||||
return Err(Error {
|
||||
expected: vec![Token::Comma, Token::Close],
|
||||
got: t3,
|
||||
pos: p3
|
||||
pos: p3,
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
(Token::Type(_), _, _) => {
|
||||
let (var, s2, p2) = parse_function_argument_variable::<T>(&s, &p)?;
|
||||
args.push(Parameter { id: var, private: false});
|
||||
args.push(Parameter {
|
||||
id: var,
|
||||
private: false,
|
||||
});
|
||||
match next_token::<T>(&s2, &p2) {
|
||||
(Token::Comma, s3, p3) => {
|
||||
s = s3;
|
||||
p = p3;
|
||||
},
|
||||
(Token::Close, _, _) => {
|
||||
return Ok((args, s2, p2))
|
||||
},
|
||||
}
|
||||
(Token::Close, _, _) => return Ok((args, s2, p2)),
|
||||
(t3, _, p3) => {
|
||||
return Err(Error {
|
||||
expected: vec![Token::Comma, Token::Close],
|
||||
got: t3,
|
||||
pos: p3
|
||||
pos: p3,
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
(Token::Close, _, _) => {
|
||||
return Ok((vec![], s, p))
|
||||
},
|
||||
}
|
||||
(Token::Close, _, _) => return Ok((vec![], s, p)),
|
||||
(t4, _, p4) => {
|
||||
return Err(Error {
|
||||
expected: vec![Token::Type(Type::FieldElement), Token::Private, Token::Close],
|
||||
expected: vec![
|
||||
Token::Type(Type::FieldElement),
|
||||
Token::Private,
|
||||
Token::Close,
|
||||
],
|
||||
got: t4,
|
||||
pos: p4,
|
||||
})
|
||||
|
@ -248,25 +224,25 @@ fn parse_function_return_types<T: Field>(
|
|||
(Token::Comma, s3, p3) => {
|
||||
s = s3;
|
||||
p = p3;
|
||||
},
|
||||
(Token::Close, _, _) => {
|
||||
return Ok((types, s1, p1))
|
||||
},
|
||||
}
|
||||
(Token::Close, _, _) => return Ok((types, s1, p1)),
|
||||
(t3, _, p3) => {
|
||||
return Err(Error {
|
||||
expected: vec![Token::Comma, Token::Close],
|
||||
got: t3,
|
||||
pos: p3
|
||||
pos: p3,
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
(Token::Close, _, _) => {
|
||||
return Ok((vec![], s, p))
|
||||
},
|
||||
}
|
||||
(Token::Close, _, _) => return Ok((vec![], s, p)),
|
||||
(t4, _, p4) => {
|
||||
return Err(Error {
|
||||
expected: vec![Token::Type(Type::FieldElement), Token::Private, Token::Close],
|
||||
expected: vec![
|
||||
Token::Type(Type::FieldElement),
|
||||
Token::Private,
|
||||
Token::Close,
|
||||
],
|
||||
got: t4,
|
||||
pos: p4,
|
||||
})
|
||||
|
@ -306,7 +282,7 @@ pub fn parse_function<T: Field, R: BufRead>(
|
|||
match statements[0] {
|
||||
Statement::Return(_) => {
|
||||
break;
|
||||
},
|
||||
}
|
||||
_ => {
|
||||
current_line = pos.line // update the interal line counter to continue where statement ended.
|
||||
}
|
||||
|
@ -331,11 +307,11 @@ pub fn parse_function<T: Field, R: BufRead>(
|
|||
id: id,
|
||||
arguments: args,
|
||||
statements: stats,
|
||||
signature: sig
|
||||
signature: sig,
|
||||
},
|
||||
Position {
|
||||
line: current_line,
|
||||
col: 1,
|
||||
},
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use field::Field;
|
||||
|
||||
use parser::tokenize::{next_token, Position, Token};
|
||||
use parser::Error;
|
||||
use parser::tokenize::{Token, Position, next_token};
|
||||
|
||||
use parser::tokenize::parse_quoted_path;
|
||||
|
||||
|
@ -12,56 +12,43 @@ pub fn parse_import<T: Field>(
|
|||
pos: &Position,
|
||||
) -> Result<(Import, Position), Error<T>> {
|
||||
match next_token(input, pos) {
|
||||
(Token::DoubleQuote, s1, p1) => {
|
||||
match parse_quoted_path(&s1, &p1) {
|
||||
(Token::Path(code_path), s2, p2) => {
|
||||
match next_token::<T>(&s2, &p2) {
|
||||
(Token::As, s3, p3) => {
|
||||
match next_token(&s3, &p3) {
|
||||
(Token::Ide(id), _, p4) => {
|
||||
return Ok((
|
||||
Import::new_with_alias(code_path, &id),
|
||||
p4
|
||||
))
|
||||
},
|
||||
(t4, _, p4) => {
|
||||
return Err(
|
||||
Error {
|
||||
expected: vec![Token::Ide("ide".to_string())],
|
||||
got: t4,
|
||||
pos: p4
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
(Token::Unknown(_), _, p3) => {
|
||||
return Ok((
|
||||
Import::new(code_path),
|
||||
p3
|
||||
))
|
||||
},
|
||||
(t3, _, p3) => {
|
||||
return Err( Error {
|
||||
expected: vec![Token::Ide("id".to_string()), Token::Unknown("".to_string())],
|
||||
got: t3,
|
||||
pos: p3
|
||||
})
|
||||
}
|
||||
(Token::DoubleQuote, s1, p1) => match parse_quoted_path(&s1, &p1) {
|
||||
(Token::Path(code_path), s2, p2) => match next_token::<T>(&s2, &p2) {
|
||||
(Token::As, s3, p3) => match next_token(&s3, &p3) {
|
||||
(Token::Ide(id), _, p4) => {
|
||||
return Ok((Import::new_with_alias(code_path, &id), p4))
|
||||
}
|
||||
(t4, _, p4) => {
|
||||
return Err(Error {
|
||||
expected: vec![Token::Ide("ide".to_string())],
|
||||
got: t4,
|
||||
pos: p4,
|
||||
})
|
||||
}
|
||||
},
|
||||
(t2, _, p2) => Err( Error {
|
||||
expected: vec![Token::Path("./path/to/program.code".to_string())],
|
||||
got: t2,
|
||||
pos: p2
|
||||
})
|
||||
}
|
||||
(Token::Unknown(_), _, p3) => return Ok((Import::new(code_path), p3)),
|
||||
(t3, _, p3) => {
|
||||
return Err(Error {
|
||||
expected: vec![
|
||||
Token::Ide("id".to_string()),
|
||||
Token::Unknown("".to_string()),
|
||||
],
|
||||
got: t3,
|
||||
pos: p3,
|
||||
})
|
||||
}
|
||||
},
|
||||
(t2, _, p2) => Err(Error {
|
||||
expected: vec![Token::Path("./path/to/program.code".to_string())],
|
||||
got: t2,
|
||||
pos: p2,
|
||||
}),
|
||||
},
|
||||
(t1, _, p1) => Err( Error {
|
||||
(t1, _, p1) => Err(Error {
|
||||
expected: vec![Token::DoubleQuote],
|
||||
got: t1,
|
||||
pos: p1
|
||||
})
|
||||
pos: p1,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,7 +86,7 @@ mod tests {
|
|||
let import = Import::new("./foo.code".to_string());
|
||||
let position = Position {
|
||||
line: 45,
|
||||
col: pos.col + 1 + "./foo.code".len() + 1
|
||||
col: pos.col + 1 + "./foo.code".len() + 1,
|
||||
};
|
||||
assert_eq!(
|
||||
Ok((import, position)),
|
||||
|
@ -115,11 +102,11 @@ mod tests {
|
|||
let import = Import::new_with_alias("./foo.code".to_string(), &alias);
|
||||
let position = Position {
|
||||
line: 45,
|
||||
col: pos.col + string.len()
|
||||
col: pos.col + string.len(),
|
||||
};
|
||||
assert_eq!(
|
||||
Ok((import, position)),
|
||||
parse_import::<FieldPrime>(&string, &pos)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
mod program;
|
||||
mod function;
|
||||
mod statement;
|
||||
mod import;
|
||||
mod expression;
|
||||
mod expression_list;
|
||||
mod function;
|
||||
mod import;
|
||||
mod program;
|
||||
mod statement;
|
||||
|
||||
pub use self::program::parse_program;
|
||||
|
|
|
@ -3,10 +3,10 @@ use field::Field;
|
|||
use std::io::prelude::*;
|
||||
|
||||
use parser::error::Error;
|
||||
use parser::tokenize::{Position, Token, next_token};
|
||||
use parser::tokenize::{next_token, Position, Token};
|
||||
|
||||
use super::import::parse_import;
|
||||
use super::function::parse_function;
|
||||
use super::import::parse_import;
|
||||
|
||||
use absy::Prog;
|
||||
|
||||
|
@ -55,5 +55,9 @@ pub fn parse_program<T: Field, R: BufRead>(reader: &mut R) -> Result<Prog<T>, Er
|
|||
}
|
||||
}
|
||||
|
||||
Ok(Prog { functions, imports, imported_functions: vec![] })
|
||||
}
|
||||
Ok(Prog {
|
||||
functions,
|
||||
imports,
|
||||
imported_functions: vec![],
|
||||
})
|
||||
}
|
||||
|
|
|
@ -8,10 +8,12 @@ use parser::Error;
|
|||
|
||||
use parser::tokenize::skip_whitespaces;
|
||||
|
||||
use super::expression::{parse_expr, parse_expr1, parse_function_call, parse_term1, parse_array_select};
|
||||
use super::expression::{
|
||||
parse_array_select, parse_expr, parse_expr1, parse_function_call, parse_term1,
|
||||
};
|
||||
use super::expression_list::parse_expression_list;
|
||||
|
||||
use absy::{Expression, Statement, Variable, Assignee};
|
||||
use absy::{Assignee, Expression, Statement, Variable};
|
||||
use types::Type;
|
||||
|
||||
pub fn parse_statement<T: Field, R: BufRead>(
|
||||
|
@ -170,7 +172,7 @@ pub fn parse_statement<T: Field, R: BufRead>(
|
|||
pos: p2,
|
||||
}),
|
||||
}
|
||||
},
|
||||
}
|
||||
(t0, _, p0) => Err(Error {
|
||||
expected: vec![Token::Type(Type::FieldElement)],
|
||||
got: t0,
|
||||
|
@ -225,29 +227,23 @@ fn parse_definition1<T: Field>(
|
|||
(Token::InlineComment(_), ref s2, _) => {
|
||||
assert_eq!(s2, "");
|
||||
match e1 {
|
||||
e @ Expression::FunctionCall(..) => {
|
||||
Ok((vec![Statement::MultipleDefinition(vec![x], e)], s1, p1))
|
||||
},
|
||||
e => {
|
||||
Ok((vec![Statement::Definition(x, e)], s1, p1))
|
||||
}
|
||||
}
|
||||
e @ Expression::FunctionCall(..) => {
|
||||
Ok((vec![Statement::MultipleDefinition(vec![x], e)], s1, p1))
|
||||
}
|
||||
e => Ok((vec![Statement::Definition(x, e)], s1, p1)),
|
||||
}
|
||||
}
|
||||
(Token::Unknown(ref t2), ref s2, _) if t2 == "" => {
|
||||
assert_eq!(s2, "");
|
||||
match e1 {
|
||||
e @ Expression::FunctionCall(..) => {
|
||||
Ok((vec![Statement::MultipleDefinition(vec![x], e)], s1, p1))
|
||||
},
|
||||
e => {
|
||||
Ok((vec![Statement::Definition(x, e)], s1, p1))
|
||||
}
|
||||
}
|
||||
e => Ok((vec![Statement::Definition(x, e)], s1, p1)),
|
||||
}
|
||||
}
|
||||
(t2, _, p2) => Err(Error {
|
||||
expected: vec![
|
||||
Token::Unknown("".to_string()),
|
||||
],
|
||||
expected: vec![Token::Unknown("".to_string())],
|
||||
got: t2,
|
||||
pos: p2,
|
||||
}),
|
||||
|
@ -268,23 +264,43 @@ fn parse_declaration_definition<T: Field>(
|
|||
(Token::InlineComment(_), ref s3, _) => {
|
||||
assert_eq!(s3, "");
|
||||
match e2 {
|
||||
e @ Expression::FunctionCall(..) => {
|
||||
Ok((vec![Statement::Declaration(Variable::new(x.clone(), t)), Statement::MultipleDefinition(vec![Assignee::Identifier(x)], e)], s2, p2))
|
||||
},
|
||||
e => {
|
||||
Ok((vec![Statement::Declaration(Variable::new(x.clone(), t)), Statement::Definition(Assignee::Identifier(x), e)], s2, p2))
|
||||
}
|
||||
e @ Expression::FunctionCall(..) => Ok((
|
||||
vec![
|
||||
Statement::Declaration(Variable::new(x.clone(), t)),
|
||||
Statement::MultipleDefinition(vec![Assignee::Identifier(x)], e),
|
||||
],
|
||||
s2,
|
||||
p2,
|
||||
)),
|
||||
e => Ok((
|
||||
vec![
|
||||
Statement::Declaration(Variable::new(x.clone(), t)),
|
||||
Statement::Definition(Assignee::Identifier(x), e),
|
||||
],
|
||||
s2,
|
||||
p2,
|
||||
)),
|
||||
}
|
||||
}
|
||||
(Token::Unknown(ref t3), ref s3, _) if t3 == "" => {
|
||||
assert_eq!(s3, "");
|
||||
match e2 {
|
||||
e @ Expression::FunctionCall(..) => {
|
||||
Ok((vec![Statement::Declaration(Variable::new(x.clone(), t)), Statement::MultipleDefinition(vec![Assignee::Identifier(x)], e)], s2, p2))
|
||||
},
|
||||
e => {
|
||||
Ok((vec![Statement::Declaration(Variable::new(x.clone(), t)), Statement::Definition(Assignee::Identifier(x), e)], s2, p2))
|
||||
}
|
||||
e @ Expression::FunctionCall(..) => Ok((
|
||||
vec![
|
||||
Statement::Declaration(Variable::new(x.clone(), t)),
|
||||
Statement::MultipleDefinition(vec![Assignee::Identifier(x)], e),
|
||||
],
|
||||
s2,
|
||||
p2,
|
||||
)),
|
||||
e => Ok((
|
||||
vec![
|
||||
Statement::Declaration(Variable::new(x.clone(), t)),
|
||||
Statement::Definition(Assignee::Identifier(x), e),
|
||||
],
|
||||
s2,
|
||||
p2,
|
||||
)),
|
||||
}
|
||||
}
|
||||
(t3, _, p3) => Err(Error {
|
||||
|
@ -308,8 +324,12 @@ fn parse_declaration_definition<T: Field>(
|
|||
// then we should have an equal sign
|
||||
(Token::Eq, s3, p3) => match parse_expr(&s3, &p3) {
|
||||
Ok((e4, s4, p4)) => {
|
||||
let mut statements: Vec<Statement<T>> = d2.into_iter().map(|v| Statement::Declaration(v)).collect();
|
||||
statements.push(Statement::MultipleDefinition(e2.into_iter().map(|e| Assignee::Identifier(e)).collect(), e4));
|
||||
let mut statements: Vec<Statement<T>> =
|
||||
d2.into_iter().map(|v| Statement::Declaration(v)).collect();
|
||||
statements.push(Statement::MultipleDefinition(
|
||||
e2.into_iter().map(|e| Assignee::Identifier(e)).collect(),
|
||||
e4,
|
||||
));
|
||||
Ok((statements, s4, p4)) // output a multipledefinition with the destructure and the expression
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
|
@ -350,8 +370,12 @@ fn parse_statement1<T: Field>(
|
|||
// then we should have an equal sign
|
||||
(Token::Eq, s3, p3) => match parse_expr(&s3, &p3) {
|
||||
Ok((e4, s4, p4)) => {
|
||||
let mut statements: Vec<Statement<T>> = d2.into_iter().map(|v| Statement::Declaration(v)).collect();
|
||||
statements.push(Statement::MultipleDefinition(e2.into_iter().map(|e| Assignee::Identifier(e)).collect(), e4));
|
||||
let mut statements: Vec<Statement<T>> =
|
||||
d2.into_iter().map(|v| Statement::Declaration(v)).collect();
|
||||
statements.push(Statement::MultipleDefinition(
|
||||
e2.into_iter().map(|e| Assignee::Identifier(e)).collect(),
|
||||
e4,
|
||||
));
|
||||
Ok((statements, s4, p4)) // output a multipledefinition with the destructure and the expression
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
|
@ -433,7 +457,7 @@ fn parse_statement1<T: Field>(
|
|||
pos: p4,
|
||||
}),
|
||||
},
|
||||
Err(err) => Err(err)
|
||||
Err(err) => Err(err),
|
||||
},
|
||||
_ => match parse_term1(Expression::Identifier(ide), input, pos) {
|
||||
Ok((e2, s2, p2)) => match parse_expr1(e2, s2, p2) {
|
||||
|
@ -489,7 +513,7 @@ pub fn parse_identifier_list1<T: Field>(
|
|||
match _type {
|
||||
Some(t) => {
|
||||
decl.push(Variable::new(head, t));
|
||||
},
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
parse_comma_separated_identifier_list_rec(input, pos, &mut res, &mut decl)
|
||||
|
@ -502,24 +526,22 @@ fn parse_comma_separated_identifier_list_rec<T: Field>(
|
|||
mut decl: &mut Vec<Variable>,
|
||||
) -> Result<(Vec<String>, Vec<Variable>, String, Position), Error<T>> {
|
||||
match next_token(&input, &pos) {
|
||||
(Token::Type(t), s1, p1) => {
|
||||
match next_token::<T>(&s1, &p1) {
|
||||
(Token::Ide(id), s2, p2) => {
|
||||
acc.push(id.clone());
|
||||
decl.push(Variable::new(id, t));
|
||||
match next_token::<T>(&s2, &p2) {
|
||||
(Token::Comma, s3, p3) => {
|
||||
parse_comma_separated_identifier_list_rec(s3, p3, &mut acc, &mut decl)
|
||||
}
|
||||
(..) => Ok((acc.to_vec(), decl.to_vec(), s2, p2)),
|
||||
(Token::Type(t), s1, p1) => match next_token::<T>(&s1, &p1) {
|
||||
(Token::Ide(id), s2, p2) => {
|
||||
acc.push(id.clone());
|
||||
decl.push(Variable::new(id, t));
|
||||
match next_token::<T>(&s2, &p2) {
|
||||
(Token::Comma, s3, p3) => {
|
||||
parse_comma_separated_identifier_list_rec(s3, p3, &mut acc, &mut decl)
|
||||
}
|
||||
(..) => Ok((acc.to_vec(), decl.to_vec(), s2, p2)),
|
||||
}
|
||||
(t2, _, p2) => Err(Error {
|
||||
expected: vec![Token::Ide(String::from("ide"))],
|
||||
got: t2,
|
||||
pos: p2,
|
||||
}),
|
||||
}
|
||||
(t2, _, p2) => Err(Error {
|
||||
expected: vec![Token::Ide(String::from("ide"))],
|
||||
got: t2,
|
||||
pos: p2,
|
||||
}),
|
||||
},
|
||||
(Token::Ide(id), s1, p1) => {
|
||||
acc.push(id);
|
||||
|
@ -529,7 +551,7 @@ fn parse_comma_separated_identifier_list_rec<T: Field>(
|
|||
}
|
||||
(..) => Ok((acc.to_vec(), decl.to_vec(), s1, p1)),
|
||||
}
|
||||
},
|
||||
}
|
||||
(t1, _, p1) => Err(Error {
|
||||
expected: vec![Token::Ide(String::from("ide"))],
|
||||
got: t1,
|
||||
|
|
|
@ -4,4 +4,4 @@ mod tokenizer;
|
|||
|
||||
pub use self::position::Position;
|
||||
pub use self::token::Token;
|
||||
pub use self::tokenizer::*;
|
||||
pub use self::tokenizer::*;
|
||||
|
|
|
@ -46,4 +46,4 @@ fn position_col() {
|
|||
col: 235,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use field::Field;
|
||||
use std::fmt;
|
||||
use field::{Field};
|
||||
use types::Type;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
|
|
|
@ -65,7 +65,7 @@ pub fn parse_ide<T: Field>(input: &String, pos: &Position) -> (Token<T>, String,
|
|||
'0'...'9' => size_len += 1,
|
||||
_ => break,
|
||||
},
|
||||
None => break
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
assert!(size_len > 0);
|
||||
|
@ -73,7 +73,11 @@ pub fn parse_ide<T: Field>(input: &String, pos: &Position) -> (Token<T>, String,
|
|||
match input.chars().nth(size_end) {
|
||||
Some(']') => {
|
||||
end = size_end + 1;
|
||||
Token::Type(Type::FieldElementArray(input[size_start..(size_start + size_len)].parse::<usize>().unwrap()))
|
||||
Token::Type(Type::FieldElementArray(
|
||||
input[size_start..(size_start + size_len)]
|
||||
.parse::<usize>()
|
||||
.unwrap(),
|
||||
))
|
||||
}
|
||||
_ => panic!(),
|
||||
}
|
||||
|
@ -249,7 +253,7 @@ pub fn next_token<T: Field>(input: &String, pos: &Position) -> (Token<T>, String
|
|||
input[offset + 2..].to_string(),
|
||||
Position {
|
||||
line: pos.line,
|
||||
col: pos.col + offset + 2
|
||||
col: pos.col + offset + 2,
|
||||
},
|
||||
),
|
||||
_ => (
|
||||
|
@ -259,7 +263,7 @@ pub fn next_token<T: Field>(input: &String, pos: &Position) -> (Token<T>, String
|
|||
line: pos.line,
|
||||
col: pos.col + offset + 1,
|
||||
},
|
||||
),
|
||||
),
|
||||
},
|
||||
Some('+') => (
|
||||
Token::Add,
|
||||
|
@ -409,7 +413,7 @@ mod tests {
|
|||
mod types {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[test]
|
||||
fn field() {
|
||||
let pos = Position { line: 45, col: 121 };
|
||||
assert_eq!(
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
//! @author Jacob Eberhardt <jacob.eberhardt@tu-berlin.de
|
||||
//! @date 2017
|
||||
|
||||
use field::Field;
|
||||
use flat_absy::flat_variable::FlatVariable;
|
||||
use flat_absy::FlatExpression::*;
|
||||
use flat_absy::*;
|
||||
use std::collections::HashMap;
|
||||
use std::mem;
|
||||
use flat_absy::*;
|
||||
use flat_absy::FlatExpression::*;
|
||||
use field::Field;
|
||||
|
||||
/// Returns a vector of summands of the given `FlatExpression`.
|
||||
///
|
||||
|
@ -71,8 +71,8 @@ fn count_variables_add<T: Field>(expr: &FlatExpression<T>) -> HashMap<FlatVariab
|
|||
let num = count.entry(FlatVariable::one()).or_insert(T::zero());
|
||||
*num = num.clone() + x1 + x2;
|
||||
}
|
||||
Mult(box Number(ref x), box Identifier(ref v)) |
|
||||
Mult(box Identifier(ref v), box Number(ref x)) => {
|
||||
Mult(box Number(ref x), box Identifier(ref v))
|
||||
| Mult(box Identifier(ref v), box Number(ref x)) => {
|
||||
let num = count.entry(*v).or_insert(T::zero());
|
||||
*num = num.clone() + x;
|
||||
}
|
||||
|
@ -88,7 +88,10 @@ fn count_variables_add<T: Field>(expr: &FlatExpression<T>) -> HashMap<FlatVariab
|
|||
///
|
||||
/// * `lhs` - Left hand side of the equation
|
||||
/// * `rhs` - Right hand side of the equation
|
||||
fn swap_sub<T: Field>(lhs: &FlatExpression<T>, rhs: &FlatExpression<T>) -> (FlatExpression<T>, FlatExpression<T>) {
|
||||
fn swap_sub<T: Field>(
|
||||
lhs: &FlatExpression<T>,
|
||||
rhs: &FlatExpression<T>,
|
||||
) -> (FlatExpression<T>, FlatExpression<T>) {
|
||||
let mut left = get_summands(lhs);
|
||||
let mut right = get_summands(rhs);
|
||||
let mut run = true;
|
||||
|
@ -169,17 +172,21 @@ fn r1cs_expression<T: Field>(
|
|||
match lhs {
|
||||
box Number(x) => a_row.push((0, x)),
|
||||
box Identifier(x) => a_row.push((provide_variable_idx(variables, &x), T::one())),
|
||||
box e @ Add(..) => for (key, value) in count_variables_add(&e) {
|
||||
a_row.push((provide_variable_idx(variables, &key), value));
|
||||
},
|
||||
box e @ Add(..) => {
|
||||
for (key, value) in count_variables_add(&e) {
|
||||
a_row.push((provide_variable_idx(variables, &key), value));
|
||||
}
|
||||
}
|
||||
e @ _ => panic!("Not flattened: {}", e),
|
||||
};
|
||||
match rhs {
|
||||
box Number(x) => b_row.push((0, x)),
|
||||
box Identifier(x) => b_row.push((provide_variable_idx(variables, &x), T::one())),
|
||||
box e @ Add(..) => for (key, value) in count_variables_add(&e) {
|
||||
b_row.push((provide_variable_idx(variables, &key), value));
|
||||
},
|
||||
box e @ Add(..) => {
|
||||
for (key, value) in count_variables_add(&e) {
|
||||
b_row.push((provide_variable_idx(variables, &key), value));
|
||||
}
|
||||
}
|
||||
e @ _ => panic!("Not flattened: {}", e),
|
||||
};
|
||||
for (key, value) in count_variables_add(&linear_expr) {
|
||||
|
@ -191,9 +198,11 @@ fn r1cs_expression<T: Field>(
|
|||
match lhs {
|
||||
box Number(x) => c_row.push((0, x)),
|
||||
box Identifier(x) => c_row.push((provide_variable_idx(variables, &x), T::one())),
|
||||
box e @ Add(..) => for (key, value) in count_variables_add(&e) {
|
||||
c_row.push((provide_variable_idx(variables, &key), value));
|
||||
},
|
||||
box e @ Add(..) => {
|
||||
for (key, value) in count_variables_add(&e) {
|
||||
c_row.push((provide_variable_idx(variables, &key), value));
|
||||
}
|
||||
}
|
||||
box e @ Sub(..) => {
|
||||
return r1cs_expression(
|
||||
Mult(box linear_expr, rhs),
|
||||
|
@ -207,8 +216,8 @@ fn r1cs_expression<T: Field>(
|
|||
box Mult(box Number(ref x1), box Number(ref x2)) => {
|
||||
c_row.push((0, x1.clone() * x2))
|
||||
}
|
||||
box Mult(box Number(ref x), box Identifier(ref v)) |
|
||||
box Mult(box Identifier(ref v), box Number(ref x)) => {
|
||||
box Mult(box Number(ref x), box Identifier(ref v))
|
||||
| box Mult(box Identifier(ref v), box Number(ref x)) => {
|
||||
c_row.push((provide_variable_idx(variables, v), x.clone()))
|
||||
}
|
||||
e @ _ => panic!("(lhs) not supported: {:?}", e),
|
||||
|
@ -219,8 +228,8 @@ fn r1cs_expression<T: Field>(
|
|||
box Mult(box Number(ref x1), box Number(ref x2)) => {
|
||||
b_row.push((0, x1.clone() * x2))
|
||||
}
|
||||
box Mult(box Number(ref x), box Identifier(ref v)) |
|
||||
box Mult(box Identifier(ref v), box Number(ref x)) => {
|
||||
box Mult(box Number(ref x), box Identifier(ref v))
|
||||
| box Mult(box Identifier(ref v), box Number(ref x)) => {
|
||||
b_row.push((provide_variable_idx(variables, v), x.clone()))
|
||||
}
|
||||
e @ _ => panic!("(rhs) not supported: {:?}", e),
|
||||
|
@ -280,7 +289,9 @@ pub fn r1cs_program<T: Field>(
|
|||
let mut c: Vec<Vec<(usize, T)>> = Vec::new();
|
||||
|
||||
//Only the main function is relevant in this step, since all calls to other functions were resolved during flattening
|
||||
let main = prog.clone().functions
|
||||
let main = prog
|
||||
.clone()
|
||||
.functions
|
||||
.into_iter()
|
||||
.find(|x: &FlatFunction<T>| x.id == "main".to_string())
|
||||
.unwrap();
|
||||
|
@ -291,7 +302,12 @@ pub fn r1cs_program<T: Field>(
|
|||
|
||||
// ~out is added after main's arguments as we want variables (columns)
|
||||
// in the r1cs to be aligned like "public inputs | private inputs"
|
||||
let main_return_count = main.signature.outputs.iter().map(|t| t.get_primitive_count()).fold(0, |acc, x| acc + x);
|
||||
let main_return_count = main
|
||||
.signature
|
||||
.outputs
|
||||
.iter()
|
||||
.map(|t| t.get_primitive_count())
|
||||
.fold(0, |acc, x| acc + x);
|
||||
|
||||
for i in 0..main_return_count {
|
||||
provide_variable_idx(&mut variables, &FlatVariable::public(i));
|
||||
|
@ -319,7 +335,7 @@ pub fn r1cs_program<T: Field>(
|
|||
b.push(b_row);
|
||||
c.push(c_row);
|
||||
}
|
||||
},
|
||||
}
|
||||
FlatStatement::Definition(ref id, ref rhs) => {
|
||||
let mut a_row = Vec::new();
|
||||
let mut b_row = Vec::new();
|
||||
|
@ -335,7 +351,7 @@ pub fn r1cs_program<T: Field>(
|
|||
a.push(a_row);
|
||||
b.push(b_row);
|
||||
c.push(c_row);
|
||||
},
|
||||
}
|
||||
FlatStatement::Condition(ref expr1, ref expr2) => {
|
||||
let mut a_row = Vec::new();
|
||||
let mut b_row = Vec::new();
|
||||
|
@ -351,8 +367,8 @@ pub fn r1cs_program<T: Field>(
|
|||
a.push(a_row);
|
||||
b.push(b_row);
|
||||
c.push(c_row);
|
||||
},
|
||||
FlatStatement::Directive(..) => continue
|
||||
}
|
||||
FlatStatement::Directive(..) => continue,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -394,10 +410,7 @@ mod tests {
|
|||
let y = FlatVariable::new(1);
|
||||
|
||||
let lhs = Identifier(x);
|
||||
let rhs = Add(
|
||||
box Identifier(y),
|
||||
box Number(FieldPrime::from(5)),
|
||||
);
|
||||
let rhs = Add(box Identifier(y), box Number(FieldPrime::from(5)));
|
||||
|
||||
let mut variables: HashMap<FlatVariable, usize> = HashMap::new();
|
||||
variables.insert(one, 0);
|
||||
|
@ -431,46 +444,25 @@ mod tests {
|
|||
let z = FlatVariable::new(2);
|
||||
|
||||
let lhs = Sub(
|
||||
box Add(
|
||||
box Identifier(x),
|
||||
box Identifier(y),
|
||||
),
|
||||
box Add(box Identifier(x), box Identifier(y)),
|
||||
box Sub(
|
||||
box Add(
|
||||
box Identifier(z),
|
||||
box Mult(
|
||||
box Number(FieldPrime::from(3)),
|
||||
box Identifier(x),
|
||||
),
|
||||
box Mult(box Number(FieldPrime::from(3)), box Identifier(x)),
|
||||
),
|
||||
box Identifier(y),
|
||||
),
|
||||
);
|
||||
let rhs = Add(
|
||||
box Sub(
|
||||
box Identifier(x),
|
||||
box Identifier(y),
|
||||
),
|
||||
box Sub(box Identifier(x), box Identifier(y)),
|
||||
box Add(
|
||||
box Sub(
|
||||
box Mult(
|
||||
box Number(FieldPrime::from(2)),
|
||||
box Identifier(x),
|
||||
),
|
||||
box Mult(
|
||||
box Number(FieldPrime::from(4)),
|
||||
box Identifier(y),
|
||||
),
|
||||
box Mult(box Number(FieldPrime::from(2)), box Identifier(x)),
|
||||
box Mult(box Number(FieldPrime::from(4)), box Identifier(y)),
|
||||
),
|
||||
box Sub(
|
||||
box Mult(
|
||||
box Number(FieldPrime::from(4)),
|
||||
box Identifier(y),
|
||||
),
|
||||
box Mult(
|
||||
box Number(FieldPrime::from(2)),
|
||||
box Identifier(z),
|
||||
),
|
||||
box Mult(box Number(FieldPrime::from(4)), box Identifier(y)),
|
||||
box Mult(box Number(FieldPrime::from(2)), box Identifier(z)),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -518,21 +510,12 @@ mod tests {
|
|||
let z = FlatVariable::new(2);
|
||||
|
||||
let lhs = Add(
|
||||
box Mult(
|
||||
box Number(FieldPrime::from(7)),
|
||||
box Identifier(x),
|
||||
),
|
||||
box Mult(box Number(FieldPrime::from(7)), box Identifier(x)),
|
||||
box Identifier(y),
|
||||
);
|
||||
let rhs = Sub(
|
||||
box Mult(
|
||||
box Number(FieldPrime::from(3)),
|
||||
box Identifier(y),
|
||||
),
|
||||
box Mult(
|
||||
box Identifier(z),
|
||||
box Number(FieldPrime::from(6)),
|
||||
),
|
||||
box Mult(box Number(FieldPrime::from(3)), box Identifier(y)),
|
||||
box Mult(box Identifier(z), box Number(FieldPrime::from(6))),
|
||||
);
|
||||
|
||||
let mut variables: HashMap<FlatVariable, usize> = HashMap::new();
|
||||
|
@ -574,24 +557,12 @@ mod tests {
|
|||
|
||||
let lhs = Sub(
|
||||
box Sub(
|
||||
box Mult(
|
||||
box Number(FieldPrime::from(3)),
|
||||
box Identifier(y),
|
||||
),
|
||||
box Mult(
|
||||
box Identifier(z),
|
||||
box Number(FieldPrime::from(2)),
|
||||
),
|
||||
),
|
||||
box Mult(
|
||||
box Identifier(x),
|
||||
box Number(FieldPrime::from(12)),
|
||||
box Mult(box Number(FieldPrime::from(3)), box Identifier(y)),
|
||||
box Mult(box Identifier(z), box Number(FieldPrime::from(2))),
|
||||
),
|
||||
box Mult(box Identifier(x), box Number(FieldPrime::from(12))),
|
||||
);
|
||||
let rhs = Sub(
|
||||
box Identifier(a),
|
||||
box Identifier(x),
|
||||
);
|
||||
let rhs = Sub(box Identifier(a), box Identifier(x));
|
||||
|
||||
let mut variables: HashMap<FlatVariable, usize> = HashMap::new();
|
||||
variables.insert(one, 0);
|
||||
|
@ -634,46 +605,22 @@ mod tests {
|
|||
|
||||
let lhs = Add(
|
||||
box Add(
|
||||
box Mult(
|
||||
box Number(FieldPrime::from(4)),
|
||||
box Identifier(y),
|
||||
),
|
||||
box Mult(
|
||||
box Number(FieldPrime::from(3)),
|
||||
box Identifier(x),
|
||||
),
|
||||
),
|
||||
box Mult(
|
||||
box Number(FieldPrime::from(3)),
|
||||
box Identifier(z),
|
||||
box Mult(box Number(FieldPrime::from(4)), box Identifier(y)),
|
||||
box Mult(box Number(FieldPrime::from(3)), box Identifier(x)),
|
||||
),
|
||||
box Mult(box Number(FieldPrime::from(3)), box Identifier(z)),
|
||||
);
|
||||
let rhs = Mult(
|
||||
box Add(
|
||||
box Add(
|
||||
box Mult(
|
||||
box Number(FieldPrime::from(3)),
|
||||
box Identifier(x),
|
||||
),
|
||||
box Mult(
|
||||
box Number(FieldPrime::from(6)),
|
||||
box Identifier(y),
|
||||
),
|
||||
),
|
||||
box Mult(
|
||||
box Number(FieldPrime::from(4)),
|
||||
box Identifier(z),
|
||||
box Mult(box Number(FieldPrime::from(3)), box Identifier(x)),
|
||||
box Mult(box Number(FieldPrime::from(6)), box Identifier(y)),
|
||||
),
|
||||
box Mult(box Number(FieldPrime::from(4)), box Identifier(z)),
|
||||
),
|
||||
box Add(
|
||||
box Mult(
|
||||
box Number(FieldPrime::from(31)),
|
||||
box Identifier(x),
|
||||
),
|
||||
box Mult(
|
||||
box Number(FieldPrime::from(4)),
|
||||
box Identifier(z),
|
||||
),
|
||||
box Mult(box Number(FieldPrime::from(31)), box Identifier(x)),
|
||||
box Mult(box Number(FieldPrime::from(4)), box Identifier(z)),
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -723,14 +670,8 @@ mod tests {
|
|||
|
||||
let lhs = Identifier(x);
|
||||
let rhs = Div(
|
||||
box Mult(
|
||||
box Number(FieldPrime::from(3)),
|
||||
box Identifier(x),
|
||||
),
|
||||
box Mult(
|
||||
box Identifier(y),
|
||||
box Number(FieldPrime::from(6)),
|
||||
),
|
||||
box Mult(box Number(FieldPrime::from(3)), box Identifier(x)),
|
||||
box Mult(box Identifier(y), box Number(FieldPrime::from(6))),
|
||||
);
|
||||
|
||||
let mut a_row = Vec::new();
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,10 +1,10 @@
|
|||
use types::{Signature, Type};
|
||||
use std::collections::{BTreeMap, HashSet};
|
||||
use flat_absy::{FlatStatement, FlatExpression, FlatFunction, FlatExpressionList};
|
||||
use field::Field;
|
||||
use flat_absy::{FlatExpression, FlatExpressionList, FlatFunction, FlatStatement};
|
||||
use flat_absy::{FlatParameter, FlatVariable};
|
||||
use reduce::Reduce;
|
||||
use helpers::{DirectiveStatement, Helper, LibsnarkGadgetHelper};
|
||||
use reduce::Reduce;
|
||||
use std::collections::{BTreeMap, HashSet};
|
||||
use types::{Signature, Type};
|
||||
|
||||
// for r1cs import, can be moved.
|
||||
// r1cs data structure reflecting JSON standard format:
|
||||
|
@ -20,93 +20,143 @@ use helpers::{DirectiveStatement, Helper, LibsnarkGadgetHelper};
|
|||
// }
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct R1CS {
|
||||
pub input_count: usize,
|
||||
pub outputs: Vec<usize>,
|
||||
pub input_count: usize,
|
||||
pub outputs: Vec<usize>,
|
||||
pub constraints: Vec<Constraint>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct Witness {
|
||||
pub variables: Vec<usize>
|
||||
pub variables: Vec<usize>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub struct Constraint {
|
||||
a: BTreeMap<usize, String>,
|
||||
b: BTreeMap<usize, String>,
|
||||
c: BTreeMap<usize, String>,
|
||||
a: BTreeMap<usize, String>,
|
||||
b: BTreeMap<usize, String>,
|
||||
c: BTreeMap<usize, String>,
|
||||
}
|
||||
|
||||
pub struct DirectiveR1CS {
|
||||
pub r1cs : R1CS,
|
||||
pub directive : LibsnarkGadgetHelper
|
||||
pub r1cs: R1CS,
|
||||
pub directive: LibsnarkGadgetHelper,
|
||||
}
|
||||
|
||||
impl<T: Field> Into<FlatStatement<T>> for Constraint {
|
||||
fn into(self: Constraint) -> FlatStatement<T> {
|
||||
let rhs_a = match self.a.into_iter()
|
||||
.map(|(key, val)| FlatExpression::Mult(box FlatExpression::Number(T::from_dec_string(val.to_string())), box FlatExpression::Identifier(FlatVariable::new(key))))
|
||||
.reduce(|acc, e| FlatExpression::Add(box acc, box e)) {
|
||||
Some(e @ FlatExpression::Mult(..)) => FlatExpression::Add(box FlatExpression::Number(T::zero()), box e), // the R1CS serializer only recognizes Add
|
||||
Some(e) => e,
|
||||
None => FlatExpression::Number(T::zero())
|
||||
};
|
||||
|
||||
let rhs_b = match self.b.into_iter()
|
||||
.map(|(key, val)| FlatExpression::Mult(box FlatExpression::Number(T::from_dec_string(val.to_string())), box FlatExpression::Identifier(FlatVariable::new(key))))
|
||||
.reduce(|acc, e| FlatExpression::Add(box acc, box e)) {
|
||||
Some(e @ FlatExpression::Mult(..)) => FlatExpression::Add(box FlatExpression::Number(T::zero()), box e), // the R1CS serializer only recognizes Add
|
||||
Some(e) => e,
|
||||
None => FlatExpression::Number(T::zero())
|
||||
};
|
||||
|
||||
let lhs = match self.c.into_iter()
|
||||
.map(|(key, val)| FlatExpression::Mult(box FlatExpression::Number(T::from_dec_string(val.to_string())), box FlatExpression::Identifier(FlatVariable::new(key))))
|
||||
.reduce(|acc, e| FlatExpression::Add(box acc, box e)) {
|
||||
Some(e @ FlatExpression::Mult(..)) => FlatExpression::Add(box FlatExpression::Number(T::zero()), box e), // the R1CS serializer only recognizes Add
|
||||
Some(e) => e,
|
||||
None => FlatExpression::Number(T::zero())
|
||||
};
|
||||
fn into(self: Constraint) -> FlatStatement<T> {
|
||||
let rhs_a = match self
|
||||
.a
|
||||
.into_iter()
|
||||
.map(|(key, val)| {
|
||||
FlatExpression::Mult(
|
||||
box FlatExpression::Number(T::from_dec_string(val.to_string())),
|
||||
box FlatExpression::Identifier(FlatVariable::new(key)),
|
||||
)
|
||||
})
|
||||
.reduce(|acc, e| FlatExpression::Add(box acc, box e))
|
||||
{
|
||||
Some(e @ FlatExpression::Mult(..)) => {
|
||||
FlatExpression::Add(box FlatExpression::Number(T::zero()), box e)
|
||||
} // the R1CS serializer only recognizes Add
|
||||
Some(e) => e,
|
||||
None => FlatExpression::Number(T::zero()),
|
||||
};
|
||||
|
||||
FlatStatement::Condition(lhs, FlatExpression::Mult(box rhs_a, box rhs_b))
|
||||
}
|
||||
let rhs_b = match self
|
||||
.b
|
||||
.into_iter()
|
||||
.map(|(key, val)| {
|
||||
FlatExpression::Mult(
|
||||
box FlatExpression::Number(T::from_dec_string(val.to_string())),
|
||||
box FlatExpression::Identifier(FlatVariable::new(key)),
|
||||
)
|
||||
})
|
||||
.reduce(|acc, e| FlatExpression::Add(box acc, box e))
|
||||
{
|
||||
Some(e @ FlatExpression::Mult(..)) => {
|
||||
FlatExpression::Add(box FlatExpression::Number(T::zero()), box e)
|
||||
} // the R1CS serializer only recognizes Add
|
||||
Some(e) => e,
|
||||
None => FlatExpression::Number(T::zero()),
|
||||
};
|
||||
|
||||
let lhs = match self
|
||||
.c
|
||||
.into_iter()
|
||||
.map(|(key, val)| {
|
||||
FlatExpression::Mult(
|
||||
box FlatExpression::Number(T::from_dec_string(val.to_string())),
|
||||
box FlatExpression::Identifier(FlatVariable::new(key)),
|
||||
)
|
||||
})
|
||||
.reduce(|acc, e| FlatExpression::Add(box acc, box e))
|
||||
{
|
||||
Some(e @ FlatExpression::Mult(..)) => {
|
||||
FlatExpression::Add(box FlatExpression::Number(T::zero()), box e)
|
||||
} // the R1CS serializer only recognizes Add
|
||||
Some(e) => e,
|
||||
None => FlatExpression::Number(T::zero()),
|
||||
};
|
||||
|
||||
FlatStatement::Condition(lhs, FlatExpression::Mult(box rhs_a, box rhs_b))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> Into<FlatFunction<T>> for DirectiveR1CS {
|
||||
fn into(self: DirectiveR1CS) -> FlatFunction<T> {
|
||||
|
||||
fn into(self: DirectiveR1CS) -> FlatFunction<T> {
|
||||
let r1cs = self.r1cs;
|
||||
|
||||
// determine the number of variables, assuming there is no i so that column i is only zeroes in a, b and c
|
||||
// determine the number of variables, assuming there is no i so that column i is only zeroes in a, b and c
|
||||
let mut variables_set = HashSet::new();
|
||||
for constraint in r1cs.constraints.iter() {
|
||||
for (key, _) in &constraint.a {
|
||||
variables_set.insert(key.clone());
|
||||
}
|
||||
for (key, _) in &constraint.b {
|
||||
variables_set.insert(key.clone());
|
||||
}
|
||||
for (key, _) in &constraint.c {
|
||||
variables_set.insert(key.clone());
|
||||
}
|
||||
for (key, _) in &constraint.a {
|
||||
variables_set.insert(key.clone());
|
||||
}
|
||||
for (key, _) in &constraint.b {
|
||||
variables_set.insert(key.clone());
|
||||
}
|
||||
for (key, _) in &constraint.c {
|
||||
variables_set.insert(key.clone());
|
||||
}
|
||||
}
|
||||
|
||||
let variables_count = variables_set.len();
|
||||
|
||||
// insert flattened statements to represent constraints
|
||||
let mut statements: Vec<FlatStatement<T>> = r1cs.constraints.into_iter().map(|c| c.into()).collect();
|
||||
// insert flattened statements to represent constraints
|
||||
let mut statements: Vec<FlatStatement<T>> =
|
||||
r1cs.constraints.into_iter().map(|c| c.into()).collect();
|
||||
|
||||
// define the entire witness
|
||||
let variables = vec![0; variables_count].iter().enumerate().map(|(i, _)| FlatVariable::new(i)).collect();
|
||||
let variables = vec![0; variables_count]
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, _)| FlatVariable::new(i))
|
||||
.collect();
|
||||
|
||||
// define the inputs with dummy variables: arguments to the function and to the directive
|
||||
let input_variables: Vec<FlatVariable> = vec![0; r1cs.input_count].iter().enumerate().map(|(i, _)| FlatVariable::new(i + variables_count)).collect();
|
||||
let arguments = input_variables.iter().map(|i| FlatParameter { id: i.clone(), private: true }).collect();
|
||||
let inputs: Vec<FlatExpression<T>> = input_variables.into_iter().map(|i| FlatExpression::Identifier(i)).collect();
|
||||
let input_variables: Vec<FlatVariable> = vec![0; r1cs.input_count]
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, _)| FlatVariable::new(i + variables_count))
|
||||
.collect();
|
||||
let arguments = input_variables
|
||||
.iter()
|
||||
.map(|i| FlatParameter {
|
||||
id: i.clone(),
|
||||
private: true,
|
||||
})
|
||||
.collect();
|
||||
let inputs: Vec<FlatExpression<T>> = input_variables
|
||||
.into_iter()
|
||||
.map(|i| FlatExpression::Identifier(i))
|
||||
.collect();
|
||||
|
||||
// define which subset of the witness is returned
|
||||
let outputs: Vec<FlatExpression<T>> = r1cs.outputs.into_iter()
|
||||
.map(|o| FlatExpression::Identifier(FlatVariable::new(o))).collect();
|
||||
let outputs: Vec<FlatExpression<T>> = r1cs
|
||||
.outputs
|
||||
.into_iter()
|
||||
.map(|o| FlatExpression::Identifier(FlatVariable::new(o)))
|
||||
.collect();
|
||||
|
||||
let signature = Signature {
|
||||
inputs: vec![Type::FieldElement; inputs.len()],
|
||||
|
@ -115,61 +165,59 @@ impl<T: Field> Into<FlatFunction<T>> for DirectiveR1CS {
|
|||
|
||||
// insert a directive to set the witness based on the libsnark gadget and inputs
|
||||
match self.directive {
|
||||
|
||||
LibsnarkGadgetHelper::Sha256Compress => {
|
||||
statements.insert(0, FlatStatement::Directive(
|
||||
DirectiveStatement {
|
||||
statements.insert(
|
||||
0,
|
||||
FlatStatement::Directive(DirectiveStatement {
|
||||
outputs: variables,
|
||||
inputs: inputs ,
|
||||
inputs: inputs,
|
||||
helper: Helper::LibsnarkGadget(LibsnarkGadgetHelper::Sha256Compress),
|
||||
})
|
||||
}),
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
LibsnarkGadgetHelper::Sha256Ethereum => {
|
||||
statements.insert(0, FlatStatement::Directive(
|
||||
DirectiveStatement {
|
||||
statements.insert(
|
||||
0,
|
||||
FlatStatement::Directive(DirectiveStatement {
|
||||
outputs: variables,
|
||||
inputs: inputs ,
|
||||
inputs: inputs,
|
||||
helper: Helper::LibsnarkGadget(LibsnarkGadgetHelper::Sha256Ethereum),
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// insert a statement to return the subset of the witness
|
||||
statements.push(FlatStatement::Return(
|
||||
FlatExpressionList {
|
||||
expressions: outputs
|
||||
})
|
||||
);
|
||||
|
||||
FlatFunction {
|
||||
id: "main".to_owned(),
|
||||
arguments,
|
||||
statements,
|
||||
statements.push(FlatStatement::Return(FlatExpressionList {
|
||||
expressions: outputs,
|
||||
}));
|
||||
|
||||
FlatFunction {
|
||||
id: "main".to_owned(),
|
||||
arguments,
|
||||
statements,
|
||||
signature,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use field::FieldPrime;
|
||||
use serde_json;
|
||||
use super::*;
|
||||
use field::FieldPrime;
|
||||
use serde_json;
|
||||
|
||||
#[test]
|
||||
fn deserialize_constraint() {
|
||||
let constraint = r#"[{"2026": "1"}, {"0": "1", "2026": "1751751751751751751751751751751751751751751"}, {"0": "0"}]"#;
|
||||
let _c: Constraint = serde_json::from_str(constraint).unwrap();
|
||||
}
|
||||
#[test]
|
||||
fn deserialize_constraint() {
|
||||
let constraint = r#"[{"2026": "1"}, {"0": "1", "2026": "1751751751751751751751751751751751751751751"}, {"0": "0"}]"#;
|
||||
let _c: Constraint = serde_json::from_str(constraint).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn constraint_into_flat_statement() {
|
||||
let constraint = r#"[{"2026": "1"}, {"0": "1", "2026": "1751751751751751751751751751751751751751751"}, {"0": "0"}]"#;
|
||||
let c: Constraint = serde_json::from_str(constraint).unwrap();
|
||||
let _statement: FlatStatement<FieldPrime> = c.into();
|
||||
}
|
||||
#[test]
|
||||
fn constraint_into_flat_statement() {
|
||||
let constraint = r#"[{"2026": "1"}, {"0": "1", "2026": "1751751751751751751751751751751751751751751"}, {"0": "0"}]"#;
|
||||
let c: Constraint = serde_json::from_str(constraint).unwrap();
|
||||
let _statement: FlatStatement<FieldPrime> = c.into();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,87 +1,98 @@
|
|||
use std::collections::HashSet;
|
||||
use field::Field;
|
||||
use std::collections::HashSet;
|
||||
use typed_absy::folder::*;
|
||||
use typed_absy::Folder;
|
||||
use typed_absy::*;
|
||||
use typed_absy::folder::*;
|
||||
use types::{Type, Signature};
|
||||
use types::{Signature, Type};
|
||||
|
||||
pub struct DeadCode {
|
||||
called: HashSet<String>,
|
||||
called: HashSet<String>,
|
||||
}
|
||||
|
||||
impl DeadCode {
|
||||
fn new() -> Self {
|
||||
DeadCode {
|
||||
called: HashSet::new()
|
||||
}
|
||||
}
|
||||
fn new() -> Self {
|
||||
DeadCode {
|
||||
called: HashSet::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clean<T: Field>(p: TypedProg<T>) -> TypedProg<T> {
|
||||
DeadCode::new().fold_program(p)
|
||||
DeadCode::new().fold_program(p)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> Folder<T> for DeadCode {
|
||||
fn fold_program(&mut self, p: TypedProg<T>) -> TypedProg<T> {
|
||||
let p = fold_program(self, p);
|
||||
// only keep functions which are being called, or `main`
|
||||
fn fold_program(&mut self, p: TypedProg<T>) -> TypedProg<T> {
|
||||
let p = fold_program(self, p);
|
||||
// only keep functions which are being called, or `main`
|
||||
|
||||
TypedProg {
|
||||
functions: p.functions.into_iter().filter(|f| f.id == "main" || self.called.contains(&f.to_slug())).collect(),
|
||||
..p
|
||||
}
|
||||
}
|
||||
TypedProg {
|
||||
functions: p
|
||||
.functions
|
||||
.into_iter()
|
||||
.filter(|f| f.id == "main" || self.called.contains(&f.to_slug()))
|
||||
.collect(),
|
||||
..p
|
||||
}
|
||||
}
|
||||
|
||||
// add extra statements before the modified statement
|
||||
fn fold_statement(&mut self, s: TypedStatement<T>) -> Vec<TypedStatement<T>> {
|
||||
match s {
|
||||
TypedStatement::MultipleDefinition(variables, elist) => {
|
||||
match elist {
|
||||
TypedExpressionList::FunctionCall(id, exps, types) => {
|
||||
let exps: Vec<_> = exps.into_iter().map(|e| self.fold_expression(e)).collect();
|
||||
// add extra statements before the modified statement
|
||||
fn fold_statement(&mut self, s: TypedStatement<T>) -> Vec<TypedStatement<T>> {
|
||||
match s {
|
||||
TypedStatement::MultipleDefinition(variables, elist) => match elist {
|
||||
TypedExpressionList::FunctionCall(id, exps, types) => {
|
||||
let exps: Vec<_> = exps.into_iter().map(|e| self.fold_expression(e)).collect();
|
||||
|
||||
let signature = Signature::new()
|
||||
.inputs(exps.iter().map(|e| e.get_type()).collect())
|
||||
.outputs(types.clone());
|
||||
|
||||
self.called.insert(format!("{}_{}", id, signature.to_slug()));
|
||||
vec![TypedStatement::MultipleDefinition(variables, TypedExpressionList::FunctionCall(id, exps, types))]
|
||||
}
|
||||
}
|
||||
},
|
||||
s => fold_statement(self, s)
|
||||
}
|
||||
}
|
||||
let signature = Signature::new()
|
||||
.inputs(exps.iter().map(|e| e.get_type()).collect())
|
||||
.outputs(types.clone());
|
||||
|
||||
fn fold_field_expression(&mut self, e: FieldElementExpression<T>) -> FieldElementExpression<T> {
|
||||
self.called
|
||||
.insert(format!("{}_{}", id, signature.to_slug()));
|
||||
vec![TypedStatement::MultipleDefinition(
|
||||
variables,
|
||||
TypedExpressionList::FunctionCall(id, exps, types),
|
||||
)]
|
||||
}
|
||||
},
|
||||
s => fold_statement(self, s),
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_field_expression(&mut self, e: FieldElementExpression<T>) -> FieldElementExpression<T> {
|
||||
match e {
|
||||
FieldElementExpression::FunctionCall(id, exps) => {
|
||||
let exps: Vec<_> = exps.into_iter().map(|e| self.fold_expression(e)).collect();
|
||||
|
||||
let signature = Signature::new()
|
||||
.inputs(exps.iter().map(|e| e.get_type()).collect())
|
||||
.outputs(vec![Type::FieldElement]);
|
||||
|
||||
self.called.insert(format!("{}_{}", id, signature.to_slug()));
|
||||
FieldElementExpression::FunctionCall(id, exps)
|
||||
},
|
||||
e => fold_field_expression(self, e)
|
||||
}
|
||||
}
|
||||
let signature = Signature::new()
|
||||
.inputs(exps.iter().map(|e| e.get_type()).collect())
|
||||
.outputs(vec![Type::FieldElement]);
|
||||
|
||||
fn fold_field_array_expression(&mut self, e: FieldElementArrayExpression<T>) -> FieldElementArrayExpression<T> {
|
||||
self.called
|
||||
.insert(format!("{}_{}", id, signature.to_slug()));
|
||||
FieldElementExpression::FunctionCall(id, exps)
|
||||
}
|
||||
e => fold_field_expression(self, e),
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_field_array_expression(
|
||||
&mut self,
|
||||
e: FieldElementArrayExpression<T>,
|
||||
) -> FieldElementArrayExpression<T> {
|
||||
match e {
|
||||
FieldElementArrayExpression::FunctionCall(size, id, exps) => {
|
||||
let exps: Vec<_> = exps.into_iter().map(|e| self.fold_expression(e)).collect();
|
||||
|
||||
let signature = Signature::new()
|
||||
.inputs(exps.iter().map(|e| e.get_type()).collect())
|
||||
.outputs(vec![Type::FieldElementArray(size)]);
|
||||
|
||||
self.called.insert(format!("{}_{}", id, signature));
|
||||
FieldElementArrayExpression::FunctionCall(size, id, exps)
|
||||
},
|
||||
e => fold_field_array_expression(self, e)
|
||||
let signature = Signature::new()
|
||||
.inputs(exps.iter().map(|e| e.get_type()).collect())
|
||||
.outputs(vec![Type::FieldElementArray(size)]);
|
||||
|
||||
self.called
|
||||
.insert(format!("{}_{}", id, signature.to_slug()));
|
||||
FieldElementArrayExpression::FunctionCall(size, id, exps)
|
||||
}
|
||||
e => fold_field_array_expression(self, e),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,170 +4,188 @@
|
|||
//! @author Thibaut Schaeffer <thibaut@schaeff.fr>
|
||||
//! @date 2018
|
||||
|
||||
use helpers::DirectiveStatement;
|
||||
use flat_absy::*;
|
||||
use std::collections::HashMap;
|
||||
use field::Field;
|
||||
use flat_absy::*;
|
||||
use helpers::DirectiveStatement;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub trait Propagate<T: Field> {
|
||||
fn propagate(self) -> Self;
|
||||
fn propagate(self) -> Self;
|
||||
}
|
||||
|
||||
pub trait PropagateWithContext<T: Field> {
|
||||
fn propagate(self, constants: &mut HashMap<FlatVariable, T>) -> Self;
|
||||
fn propagate(self, constants: &mut HashMap<FlatVariable, T>) -> Self;
|
||||
}
|
||||
|
||||
impl<T: Field> PropagateWithContext<T> for FlatExpression<T> {
|
||||
fn propagate(self, constants: &mut HashMap<FlatVariable, T>) -> FlatExpression<T> {
|
||||
match self {
|
||||
FlatExpression::Number(n) => FlatExpression::Number(n),
|
||||
FlatExpression::Identifier(id) => {
|
||||
match constants.get(&id) {
|
||||
Some(c) => FlatExpression::Number(c.clone()),
|
||||
None => FlatExpression::Identifier(id)
|
||||
}
|
||||
},
|
||||
FlatExpression::Add(box e1, box e2) => {
|
||||
match (e1.propagate(constants), e2.propagate(constants)) {
|
||||
(FlatExpression::Number(n1), FlatExpression::Number(n2)) => FlatExpression::Number(n1 + n2),
|
||||
(e1, e2) => FlatExpression::Add(box e1, box e2),
|
||||
}
|
||||
},
|
||||
FlatExpression::Sub(box e1, box e2) => {
|
||||
match (e1.propagate(constants), e2.propagate(constants)) {
|
||||
(FlatExpression::Number(n1), FlatExpression::Number(n2)) => FlatExpression::Number(n1 - n2),
|
||||
(e1, e2) => FlatExpression::Sub(box e1, box e2),
|
||||
}
|
||||
},
|
||||
FlatExpression::Mult(box e1, box e2) => {
|
||||
match (e1.propagate(constants), e2.propagate(constants)) {
|
||||
(FlatExpression::Number(n1), FlatExpression::Number(n2)) => FlatExpression::Number(n1 * n2),
|
||||
(e1, e2) => FlatExpression::Mult(box e1, box e2),
|
||||
}
|
||||
},
|
||||
FlatExpression::Div(box e1, box e2) => {
|
||||
match (e1.propagate(constants), e2.propagate(constants)) {
|
||||
(FlatExpression::Number(n1), FlatExpression::Number(n2)) => FlatExpression::Number(n1 / n2),
|
||||
(e1, e2) => FlatExpression::Div(box e1, box e2),
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
fn propagate(self, constants: &mut HashMap<FlatVariable, T>) -> FlatExpression<T> {
|
||||
match self {
|
||||
FlatExpression::Number(n) => FlatExpression::Number(n),
|
||||
FlatExpression::Identifier(id) => match constants.get(&id) {
|
||||
Some(c) => FlatExpression::Number(c.clone()),
|
||||
None => FlatExpression::Identifier(id),
|
||||
},
|
||||
FlatExpression::Add(box e1, box e2) => {
|
||||
match (e1.propagate(constants), e2.propagate(constants)) {
|
||||
(FlatExpression::Number(n1), FlatExpression::Number(n2)) => {
|
||||
FlatExpression::Number(n1 + n2)
|
||||
}
|
||||
(e1, e2) => FlatExpression::Add(box e1, box e2),
|
||||
}
|
||||
}
|
||||
FlatExpression::Sub(box e1, box e2) => {
|
||||
match (e1.propagate(constants), e2.propagate(constants)) {
|
||||
(FlatExpression::Number(n1), FlatExpression::Number(n2)) => {
|
||||
FlatExpression::Number(n1 - n2)
|
||||
}
|
||||
(e1, e2) => FlatExpression::Sub(box e1, box e2),
|
||||
}
|
||||
}
|
||||
FlatExpression::Mult(box e1, box e2) => {
|
||||
match (e1.propagate(constants), e2.propagate(constants)) {
|
||||
(FlatExpression::Number(n1), FlatExpression::Number(n2)) => {
|
||||
FlatExpression::Number(n1 * n2)
|
||||
}
|
||||
(e1, e2) => FlatExpression::Mult(box e1, box e2),
|
||||
}
|
||||
}
|
||||
FlatExpression::Div(box e1, box e2) => {
|
||||
match (e1.propagate(constants), e2.propagate(constants)) {
|
||||
(FlatExpression::Number(n1), FlatExpression::Number(n2)) => {
|
||||
FlatExpression::Number(n1 / n2)
|
||||
}
|
||||
(e1, e2) => FlatExpression::Div(box e1, box e2),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> FlatStatement<T> {
|
||||
fn propagate(self, constants: &mut HashMap<FlatVariable, T>) -> Option<FlatStatement<T>> {
|
||||
match self {
|
||||
FlatStatement::Return(list) => Some(FlatStatement::Return(FlatExpressionList {
|
||||
expressions: list.expressions.into_iter().map(|e| e.propagate(constants)).collect()
|
||||
})),
|
||||
FlatStatement::Definition(var, expr) => {
|
||||
match expr.propagate(constants) {
|
||||
FlatExpression::Number(n) => {
|
||||
constants.insert(var, n);
|
||||
None
|
||||
},
|
||||
e => {
|
||||
Some(FlatStatement::Definition(var, e))
|
||||
}
|
||||
}
|
||||
},
|
||||
FlatStatement::Condition(e1, e2) => {
|
||||
Some(FlatStatement::Condition(e1.propagate(constants), e2.propagate(constants)))
|
||||
},
|
||||
FlatStatement::Directive(d) => {
|
||||
Some(FlatStatement::Directive(
|
||||
DirectiveStatement {
|
||||
inputs: d.inputs.into_iter().map(|i| i.propagate(constants)).collect(),
|
||||
..d
|
||||
}
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
fn propagate(self, constants: &mut HashMap<FlatVariable, T>) -> Option<FlatStatement<T>> {
|
||||
match self {
|
||||
FlatStatement::Return(list) => Some(FlatStatement::Return(FlatExpressionList {
|
||||
expressions: list
|
||||
.expressions
|
||||
.into_iter()
|
||||
.map(|e| e.propagate(constants))
|
||||
.collect(),
|
||||
})),
|
||||
FlatStatement::Definition(var, expr) => match expr.propagate(constants) {
|
||||
FlatExpression::Number(n) => {
|
||||
constants.insert(var, n);
|
||||
None
|
||||
}
|
||||
e => Some(FlatStatement::Definition(var, e)),
|
||||
},
|
||||
FlatStatement::Condition(e1, e2) => Some(FlatStatement::Condition(
|
||||
e1.propagate(constants),
|
||||
e2.propagate(constants),
|
||||
)),
|
||||
FlatStatement::Directive(d) => Some(FlatStatement::Directive(DirectiveStatement {
|
||||
inputs: d
|
||||
.inputs
|
||||
.into_iter()
|
||||
.map(|i| i.propagate(constants))
|
||||
.collect(),
|
||||
..d
|
||||
})),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> Propagate<T> for FlatFunction<T> {
|
||||
fn propagate(self) -> FlatFunction<T> {
|
||||
fn propagate(self) -> FlatFunction<T> {
|
||||
let mut constants = HashMap::new();
|
||||
|
||||
let mut constants = HashMap::new();
|
||||
|
||||
FlatFunction {
|
||||
statements: self.statements.into_iter().filter_map(|s| s.propagate(&mut constants)).collect(),
|
||||
..self
|
||||
}
|
||||
}
|
||||
FlatFunction {
|
||||
statements: self
|
||||
.statements
|
||||
.into_iter()
|
||||
.filter_map(|s| s.propagate(&mut constants))
|
||||
.collect(),
|
||||
..self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> FlatProg<T> {
|
||||
pub fn propagate(self) -> FlatProg<T> {
|
||||
pub fn propagate(self) -> FlatProg<T> {
|
||||
let mut functions = vec![];
|
||||
|
||||
let mut functions = vec![];
|
||||
for f in self.functions {
|
||||
let fun = f.propagate();
|
||||
functions.push(fun);
|
||||
}
|
||||
|
||||
for f in self.functions {
|
||||
let fun = f.propagate();
|
||||
functions.push(fun);
|
||||
}
|
||||
|
||||
FlatProg {
|
||||
functions,
|
||||
..self
|
||||
}
|
||||
}
|
||||
FlatProg { functions, ..self }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use field::FieldPrime;
|
||||
|
||||
#[cfg(test)]
|
||||
mod expression {
|
||||
use super::*;
|
||||
use super::*;
|
||||
use field::FieldPrime;
|
||||
|
||||
#[cfg(test)]
|
||||
mod field {
|
||||
use super::*;
|
||||
#[cfg(test)]
|
||||
mod expression {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn add() {
|
||||
let e = FlatExpression::Add(
|
||||
box FlatExpression::Number(FieldPrime::from(2)),
|
||||
box FlatExpression::Number(FieldPrime::from(3))
|
||||
);
|
||||
#[cfg(test)]
|
||||
mod field {
|
||||
use super::*;
|
||||
|
||||
assert_eq!(e.propagate(&mut HashMap::new()), FlatExpression::Number(FieldPrime::from(5)));
|
||||
}
|
||||
#[test]
|
||||
fn add() {
|
||||
let e = FlatExpression::Add(
|
||||
box FlatExpression::Number(FieldPrime::from(2)),
|
||||
box FlatExpression::Number(FieldPrime::from(3)),
|
||||
);
|
||||
|
||||
#[test]
|
||||
fn sub() {
|
||||
let e = FlatExpression::Sub(
|
||||
box FlatExpression::Number(FieldPrime::from(3)),
|
||||
box FlatExpression::Number(FieldPrime::from(2))
|
||||
);
|
||||
assert_eq!(
|
||||
e.propagate(&mut HashMap::new()),
|
||||
FlatExpression::Number(FieldPrime::from(5))
|
||||
);
|
||||
}
|
||||
|
||||
assert_eq!(e.propagate(&mut HashMap::new()), FlatExpression::Number(FieldPrime::from(1)));
|
||||
}
|
||||
#[test]
|
||||
fn sub() {
|
||||
let e = FlatExpression::Sub(
|
||||
box FlatExpression::Number(FieldPrime::from(3)),
|
||||
box FlatExpression::Number(FieldPrime::from(2)),
|
||||
);
|
||||
|
||||
#[test]
|
||||
fn mult() {
|
||||
let e = FlatExpression::Mult(
|
||||
box FlatExpression::Number(FieldPrime::from(3)),
|
||||
box FlatExpression::Number(FieldPrime::from(2))
|
||||
);
|
||||
assert_eq!(
|
||||
e.propagate(&mut HashMap::new()),
|
||||
FlatExpression::Number(FieldPrime::from(1))
|
||||
);
|
||||
}
|
||||
|
||||
assert_eq!(e.propagate(&mut HashMap::new()), FlatExpression::Number(FieldPrime::from(6)));
|
||||
}
|
||||
#[test]
|
||||
fn mult() {
|
||||
let e = FlatExpression::Mult(
|
||||
box FlatExpression::Number(FieldPrime::from(3)),
|
||||
box FlatExpression::Number(FieldPrime::from(2)),
|
||||
);
|
||||
|
||||
#[test]
|
||||
fn div() {
|
||||
let e = FlatExpression::Div(
|
||||
box FlatExpression::Number(FieldPrime::from(6)),
|
||||
box FlatExpression::Number(FieldPrime::from(2))
|
||||
);
|
||||
assert_eq!(
|
||||
e.propagate(&mut HashMap::new()),
|
||||
FlatExpression::Number(FieldPrime::from(6))
|
||||
);
|
||||
}
|
||||
|
||||
assert_eq!(e.propagate(&mut HashMap::new()), FlatExpression::Number(FieldPrime::from(3)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn div() {
|
||||
let e = FlatExpression::Div(
|
||||
box FlatExpression::Number(FieldPrime::from(6)),
|
||||
box FlatExpression::Number(FieldPrime::from(2)),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
e.propagate(&mut HashMap::new()),
|
||||
FlatExpression::Number(FieldPrime::from(3))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,82 +1,105 @@
|
|||
use std::collections::HashMap;
|
||||
use field::Field;
|
||||
use std::collections::HashMap;
|
||||
use typed_absy::folder::*;
|
||||
use typed_absy::Folder;
|
||||
use typed_absy::*;
|
||||
use typed_absy::folder::*;
|
||||
use types::{Type, Signature};
|
||||
use types::{Signature, Type};
|
||||
|
||||
pub struct Inliner<T: Field> {
|
||||
functions: Vec<TypedFunction<T>>,
|
||||
statements_buffer: Vec<TypedStatement<T>>,
|
||||
context: Vec<(String, usize)>,
|
||||
call_count: HashMap<String, usize>
|
||||
functions: Vec<TypedFunction<T>>,
|
||||
statements_buffer: Vec<TypedStatement<T>>,
|
||||
context: Vec<(String, usize)>,
|
||||
call_count: HashMap<String, usize>,
|
||||
}
|
||||
|
||||
impl<T: Field> Inliner<T> {
|
||||
pub fn new() -> Self {
|
||||
Inliner {
|
||||
functions: vec![],
|
||||
statements_buffer: vec![],
|
||||
context: vec![],
|
||||
call_count: HashMap::new()
|
||||
functions: vec![],
|
||||
statements_buffer: vec![],
|
||||
context: vec![],
|
||||
call_count: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn should_inline(&self, function: &Option<TypedFunction<T>>, arguments: &Vec<TypedExpression<T>>) -> bool {
|
||||
// we should define a heuristic here
|
||||
// currently it doesn't seem like there's a tradeoff as everything gets inlined in flattening anyway (apart from compiling performance, as inlining
|
||||
// in flattening should be faster and less memory intensive)
|
||||
// however, using backends such as bellman, we could avoid flattening and "stream" the computation
|
||||
// at proving time, the tradeoff becomes code size (not inlining keeps only one copy of each function) vs optimisation
|
||||
// (inlining enables constant propagation through function calls, which cannot be achieved by our final optimiser in some cases)
|
||||
// for now, we inline functions whose non-array parameters are constant, as this covers our main use case for inlining: propagation of
|
||||
// constant array indices
|
||||
match function {
|
||||
Some(..) => {
|
||||
// check whether non-array arguments are constant
|
||||
arguments.iter().all(|e| match e {
|
||||
TypedExpression::FieldElementArray(..) => true,
|
||||
TypedExpression::FieldElement(FieldElementExpression::Number(..)) => true,
|
||||
TypedExpression::Boolean(BooleanExpression::Value(..)) => true,
|
||||
_ => false
|
||||
})
|
||||
},
|
||||
None => false
|
||||
}
|
||||
fn should_inline(
|
||||
&self,
|
||||
function: &Option<TypedFunction<T>>,
|
||||
arguments: &Vec<TypedExpression<T>>,
|
||||
) -> bool {
|
||||
// we should define a heuristic here
|
||||
// currently it doesn't seem like there's a tradeoff as everything gets inlined in flattening anyway (apart from compiling performance, as inlining
|
||||
// in flattening should be faster and less memory intensive)
|
||||
// however, using backends such as bellman, we could avoid flattening and "stream" the computation
|
||||
// at proving time, the tradeoff becomes code size (not inlining keeps only one copy of each function) vs optimisation
|
||||
// (inlining enables constant propagation through function calls, which cannot be achieved by our final optimiser in some cases)
|
||||
// for now, we inline functions whose non-array parameters are constant, as this covers our main use case for inlining: propagation of
|
||||
// constant array indices
|
||||
match function {
|
||||
Some(..) => {
|
||||
// check whether non-array arguments are constant
|
||||
arguments.iter().all(|e| match e {
|
||||
TypedExpression::FieldElementArray(..) => true,
|
||||
TypedExpression::FieldElement(FieldElementExpression::Number(..)) => true,
|
||||
TypedExpression::Boolean(BooleanExpression::Value(..)) => true,
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
// inline a call to `function` taking `expressions` as inputs
|
||||
// this function mutates `self.call` by incrementing the counter for `function`, and mutates `self.context`
|
||||
fn inline_call(&mut self, function: &TypedFunction<T>, expressions: Vec<TypedExpression<T>>) -> Vec<TypedExpression<T>> {
|
||||
self.call_count.entry(function.to_slug()).and_modify(|i| *i += 1).or_insert(1);
|
||||
self.context.push((function.to_slug(), *self.call_count.get(&function.to_slug()).unwrap()));
|
||||
fn inline_call(
|
||||
&mut self,
|
||||
function: &TypedFunction<T>,
|
||||
expressions: Vec<TypedExpression<T>>,
|
||||
) -> Vec<TypedExpression<T>> {
|
||||
self.call_count
|
||||
.entry(function.to_slug())
|
||||
.and_modify(|i| *i += 1)
|
||||
.or_insert(1);
|
||||
self.context.push((
|
||||
function.to_slug(),
|
||||
*self.call_count.get(&function.to_slug()).unwrap(),
|
||||
));
|
||||
|
||||
// add definitions for the inputs
|
||||
let mut inputs_bindings = function.arguments.iter().zip(expressions)
|
||||
.map(|(a, e)|
|
||||
TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(self.fold_variable(a.id.clone())),
|
||||
e
|
||||
)
|
||||
).collect();
|
||||
self.statements_buffer.append(&mut inputs_bindings);
|
||||
// add definitions for the inputs
|
||||
let mut inputs_bindings = function
|
||||
.arguments
|
||||
.iter()
|
||||
.zip(expressions)
|
||||
.map(|(a, e)| {
|
||||
TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(self.fold_variable(a.id.clone())),
|
||||
e,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
self.statements_buffer.append(&mut inputs_bindings);
|
||||
|
||||
// filter out the return statement and keep it aside
|
||||
let (mut statements, ret) : (Vec<_>, Vec<_>) = function.statements.clone().into_iter().flat_map(|s| self.fold_statement(s)).partition(|s| match s {
|
||||
TypedStatement::Return(..) => false,
|
||||
_ => true
|
||||
});
|
||||
// filter out the return statement and keep it aside
|
||||
let (mut statements, ret): (Vec<_>, Vec<_>) = function
|
||||
.statements
|
||||
.clone()
|
||||
.into_iter()
|
||||
.flat_map(|s| self.fold_statement(s))
|
||||
.partition(|s| match s {
|
||||
TypedStatement::Return(..) => false,
|
||||
_ => true,
|
||||
});
|
||||
|
||||
// add all statements to the buffer
|
||||
self.statements_buffer.append(&mut statements);
|
||||
// add all statements to the buffer
|
||||
self.statements_buffer.append(&mut statements);
|
||||
|
||||
// remove this call from the context
|
||||
self.context.pop();
|
||||
// remove this call from the context
|
||||
self.context.pop();
|
||||
|
||||
match ret[0].clone() {
|
||||
TypedStatement::Return(exprs) => exprs,
|
||||
_ => panic!("")
|
||||
}
|
||||
match ret[0].clone() {
|
||||
TypedStatement::Return(exprs) => exprs,
|
||||
_ => panic!(""),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inline(prog: TypedProg<T>) -> TypedProg<T> {
|
||||
|
@ -85,183 +108,220 @@ impl<T: Field> Inliner<T> {
|
|||
}
|
||||
|
||||
impl<T: Field> Folder<T> for Inliner<T> {
|
||||
// store the list of functions
|
||||
fn fold_program(&mut self, p: TypedProg<T>) -> TypedProg<T> {
|
||||
self.functions = p.functions.clone();
|
||||
fold_program(self, p)
|
||||
}
|
||||
// store the list of functions
|
||||
fn fold_program(&mut self, p: TypedProg<T>) -> TypedProg<T> {
|
||||
self.functions = p.functions.clone();
|
||||
fold_program(self, p)
|
||||
}
|
||||
|
||||
// add extra statements before the modified statement
|
||||
fn fold_statement(&mut self, s: TypedStatement<T>) -> Vec<TypedStatement<T>> {
|
||||
let mut statements = match s {
|
||||
TypedStatement::MultipleDefinition(variables, elist) => {
|
||||
match elist {
|
||||
TypedExpressionList::FunctionCall(id, exps, types) => {
|
||||
let variables: Vec<_> = variables.into_iter().map(|a| self.fold_variable(a)).collect();
|
||||
let exps: Vec<_> = exps.into_iter().map(|e| self.fold_expression(e)).collect();
|
||||
// add extra statements before the modified statement
|
||||
fn fold_statement(&mut self, s: TypedStatement<T>) -> Vec<TypedStatement<T>> {
|
||||
let mut statements = match s {
|
||||
TypedStatement::MultipleDefinition(variables, elist) => {
|
||||
match elist {
|
||||
TypedExpressionList::FunctionCall(id, exps, types) => {
|
||||
let variables: Vec<_> = variables
|
||||
.into_iter()
|
||||
.map(|a| self.fold_variable(a))
|
||||
.collect();
|
||||
let exps: Vec<_> =
|
||||
exps.into_iter().map(|e| self.fold_expression(e)).collect();
|
||||
|
||||
let passed_signature = Signature::new()
|
||||
.inputs(exps.iter().map(|e| e.get_type()).collect())
|
||||
.outputs(types.clone());
|
||||
let passed_signature = Signature::new()
|
||||
.inputs(exps.iter().map(|e| e.get_type()).collect())
|
||||
.outputs(types.clone());
|
||||
|
||||
// find the function
|
||||
let function = self.functions.iter().find(|f| f.id == id && f.signature == passed_signature).cloned();
|
||||
// find the function
|
||||
let function = self
|
||||
.functions
|
||||
.iter()
|
||||
.find(|f| f.id == id && f.signature == passed_signature)
|
||||
.cloned();
|
||||
|
||||
match self.should_inline(&function, &exps) {
|
||||
true => {
|
||||
let ret = self.inline_call(&function.unwrap(), exps);
|
||||
variables.into_iter().zip(ret.into_iter()).map(|(v, e)| TypedStatement::Definition(TypedAssignee::Identifier(v), e)).collect()
|
||||
},
|
||||
false => {
|
||||
vec![TypedStatement::MultipleDefinition(variables, TypedExpressionList::FunctionCall(id, exps, types))]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
s => fold_statement(self, s)
|
||||
};
|
||||
match self.should_inline(&function, &exps) {
|
||||
true => {
|
||||
let ret = self.inline_call(&function.unwrap(), exps);
|
||||
variables
|
||||
.into_iter()
|
||||
.zip(ret.into_iter())
|
||||
.map(|(v, e)| {
|
||||
TypedStatement::Definition(TypedAssignee::Identifier(v), e)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
false => vec![TypedStatement::MultipleDefinition(
|
||||
variables,
|
||||
TypedExpressionList::FunctionCall(id, exps, types),
|
||||
)],
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
s => fold_statement(self, s),
|
||||
};
|
||||
|
||||
// add the result of folding to the buffer
|
||||
self.statements_buffer.append(&mut statements);
|
||||
// return the whole buffer
|
||||
self.statements_buffer.drain(..).collect()
|
||||
}
|
||||
// add the result of folding to the buffer
|
||||
self.statements_buffer.append(&mut statements);
|
||||
// return the whole buffer
|
||||
self.statements_buffer.drain(..).collect()
|
||||
}
|
||||
|
||||
// prefix all names with the context
|
||||
fn fold_name(&mut self, n: String) -> String {
|
||||
match self.context.len() {
|
||||
0 => n,
|
||||
_ => format!("{}_{}", self
|
||||
.context
|
||||
.iter()
|
||||
.map(|(s, i)|
|
||||
format!("{}_{}", s, i)
|
||||
)
|
||||
.collect::<Vec<_>>()
|
||||
.join("_"), n)
|
||||
}
|
||||
}
|
||||
// prefix all names with the context
|
||||
fn fold_name(&mut self, n: String) -> String {
|
||||
match self.context.len() {
|
||||
0 => n,
|
||||
_ => format!(
|
||||
"{}_{}",
|
||||
self.context
|
||||
.iter()
|
||||
.map(|(s, i)| format!("{}_{}", s, i))
|
||||
.collect::<Vec<_>>()
|
||||
.join("_"),
|
||||
n
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
// inline calls which return a field element
|
||||
fn fold_field_expression(&mut self, e: FieldElementExpression<T>) -> FieldElementExpression<T> {
|
||||
// inline calls which return a field element
|
||||
fn fold_field_expression(&mut self, e: FieldElementExpression<T>) -> FieldElementExpression<T> {
|
||||
match e {
|
||||
FieldElementExpression::FunctionCall(id, exps) => {
|
||||
let exps: Vec<_> = exps.into_iter().map(|e| self.fold_expression(e)).collect();
|
||||
|
||||
let passed_signature = Signature::new()
|
||||
.inputs(exps.iter().map(|e| e.get_type()).collect())
|
||||
.outputs(vec![Type::FieldElement]);
|
||||
let passed_signature = Signature::new()
|
||||
.inputs(exps.iter().map(|e| e.get_type()).collect())
|
||||
.outputs(vec![Type::FieldElement]);
|
||||
|
||||
// find the function
|
||||
let function = self.functions.iter().find(|f| f.id == id && f.signature == passed_signature).cloned();
|
||||
// find the function
|
||||
let function = self
|
||||
.functions
|
||||
.iter()
|
||||
.find(|f| f.id == id && f.signature == passed_signature)
|
||||
.cloned();
|
||||
|
||||
match self.should_inline(&function, &exps) {
|
||||
true => {
|
||||
let ret = self.inline_call(&function.unwrap(), exps);
|
||||
// unwrap the result to return a field element
|
||||
match ret[0].clone() {
|
||||
TypedExpression::FieldElement(e) => e,
|
||||
_ => panic!("")
|
||||
}
|
||||
},
|
||||
false => FieldElementExpression::FunctionCall(id, exps)
|
||||
true => {
|
||||
let ret = self.inline_call(&function.unwrap(), exps);
|
||||
// unwrap the result to return a field element
|
||||
match ret[0].clone() {
|
||||
TypedExpression::FieldElement(e) => e,
|
||||
_ => panic!(""),
|
||||
}
|
||||
}
|
||||
false => FieldElementExpression::FunctionCall(id, exps),
|
||||
}
|
||||
},
|
||||
}
|
||||
// default
|
||||
e => fold_field_expression(self, e)
|
||||
e => fold_field_expression(self, e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// inline calls which return a field element array
|
||||
fn fold_field_array_expression(&mut self, e: FieldElementArrayExpression<T>) -> FieldElementArrayExpression<T> {
|
||||
// inline calls which return a field element array
|
||||
fn fold_field_array_expression(
|
||||
&mut self,
|
||||
e: FieldElementArrayExpression<T>,
|
||||
) -> FieldElementArrayExpression<T> {
|
||||
match e {
|
||||
FieldElementArrayExpression::FunctionCall(size, id, exps) => {
|
||||
let exps: Vec<_> = exps.into_iter().map(|e| self.fold_expression(e)).collect();
|
||||
|
||||
let passed_signature = Signature::new()
|
||||
.inputs(exps.iter().map(|e| e.get_type()).collect())
|
||||
.outputs(vec![Type::FieldElementArray(size)]);
|
||||
let passed_signature = Signature::new()
|
||||
.inputs(exps.iter().map(|e| e.get_type()).collect())
|
||||
.outputs(vec![Type::FieldElementArray(size)]);
|
||||
|
||||
// find the function
|
||||
let function = self.functions.iter().find(|f| f.id == id && f.signature == passed_signature).cloned();
|
||||
// find the function
|
||||
let function = self
|
||||
.functions
|
||||
.iter()
|
||||
.find(|f| f.id == id && f.signature == passed_signature)
|
||||
.cloned();
|
||||
|
||||
match self.should_inline(&function, &exps) {
|
||||
true => {
|
||||
let ret = self.inline_call(&function.unwrap(), exps);
|
||||
// unwrap the result to return a field element
|
||||
match ret[0].clone() {
|
||||
TypedExpression::FieldElementArray(e) => e,
|
||||
_ => panic!("")
|
||||
}
|
||||
},
|
||||
false => FieldElementArrayExpression::FunctionCall(size, id, exps)
|
||||
true => {
|
||||
let ret = self.inline_call(&function.unwrap(), exps);
|
||||
// unwrap the result to return a field element
|
||||
match ret[0].clone() {
|
||||
TypedExpression::FieldElementArray(e) => e,
|
||||
_ => panic!(""),
|
||||
}
|
||||
}
|
||||
false => FieldElementArrayExpression::FunctionCall(size, id, exps),
|
||||
}
|
||||
},
|
||||
}
|
||||
// default
|
||||
e => fold_field_array_expression(self, e)
|
||||
e => fold_field_array_expression(self, e),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use field::FieldPrime;
|
||||
|
||||
#[cfg(test)]
|
||||
mod heuristics {
|
||||
use super::*;
|
||||
use absy::{Parameter, Variable};
|
||||
use super::*;
|
||||
use field::FieldPrime;
|
||||
|
||||
#[test]
|
||||
fn inline_constant_field() {
|
||||
let f: TypedFunction<FieldPrime> = TypedFunction {
|
||||
id: String::from("foo"),
|
||||
arguments: vec![Parameter::private(Variable::field_element("a")), Parameter::private(Variable::field_array("b", 3))],
|
||||
statements: vec![
|
||||
TypedStatement::Return(
|
||||
vec![
|
||||
FieldElementExpression::Select(
|
||||
box FieldElementArrayExpression::Identifier(3, String::from("b")),
|
||||
box FieldElementExpression::Identifier(String::from("a"))
|
||||
).into()
|
||||
]
|
||||
)
|
||||
],
|
||||
signature: Signature::new().inputs(vec![Type::FieldElement, Type::FieldElementArray(3)]).outputs(vec![Type::FieldElement])
|
||||
};
|
||||
#[cfg(test)]
|
||||
mod heuristics {
|
||||
use super::*;
|
||||
use absy::{Parameter, Variable};
|
||||
|
||||
let arguments = vec![FieldElementExpression::Number(FieldPrime::from(0)).into(), FieldElementArrayExpression::Identifier(3, String::from("random")).into()];
|
||||
#[test]
|
||||
fn inline_constant_field() {
|
||||
let f: TypedFunction<FieldPrime> = TypedFunction {
|
||||
id: String::from("foo"),
|
||||
arguments: vec![
|
||||
Parameter::private(Variable::field_element("a")),
|
||||
Parameter::private(Variable::field_array("b", 3)),
|
||||
],
|
||||
statements: vec![TypedStatement::Return(vec![
|
||||
FieldElementExpression::Select(
|
||||
box FieldElementArrayExpression::Identifier(3, String::from("b")),
|
||||
box FieldElementExpression::Identifier(String::from("a")),
|
||||
)
|
||||
.into(),
|
||||
])],
|
||||
signature: Signature::new()
|
||||
.inputs(vec![Type::FieldElement, Type::FieldElementArray(3)])
|
||||
.outputs(vec![Type::FieldElement]),
|
||||
};
|
||||
|
||||
let i = Inliner::new();
|
||||
let arguments = vec![
|
||||
FieldElementExpression::Number(FieldPrime::from(0)).into(),
|
||||
FieldElementArrayExpression::Identifier(3, String::from("random")).into(),
|
||||
];
|
||||
|
||||
assert!(i.should_inline(&Some(f), &arguments));
|
||||
}
|
||||
let i = Inliner::new();
|
||||
|
||||
#[test]
|
||||
fn no_inline_non_constant_field() {
|
||||
let f: TypedFunction<FieldPrime> = TypedFunction {
|
||||
id: String::from("foo"),
|
||||
arguments: vec![Parameter::private(Variable::field_element("a")), Parameter::private(Variable::field_array("b", 3))],
|
||||
statements: vec![
|
||||
TypedStatement::Return(
|
||||
vec![
|
||||
FieldElementExpression::Select(
|
||||
box FieldElementArrayExpression::Identifier(3, String::from("b")),
|
||||
box FieldElementExpression::Identifier(String::from("a"))
|
||||
).into()
|
||||
]
|
||||
)
|
||||
],
|
||||
signature: Signature::new().inputs(vec![Type::FieldElement, Type::FieldElementArray(3)]).outputs(vec![Type::FieldElement])
|
||||
};
|
||||
assert!(i.should_inline(&Some(f), &arguments));
|
||||
}
|
||||
|
||||
let arguments = vec![FieldElementExpression::Identifier(String::from("notconstant")).into(), FieldElementArrayExpression::Identifier(3, String::from("random")).into()];
|
||||
#[test]
|
||||
fn no_inline_non_constant_field() {
|
||||
let f: TypedFunction<FieldPrime> = TypedFunction {
|
||||
id: String::from("foo"),
|
||||
arguments: vec![
|
||||
Parameter::private(Variable::field_element("a")),
|
||||
Parameter::private(Variable::field_array("b", 3)),
|
||||
],
|
||||
statements: vec![TypedStatement::Return(vec![
|
||||
FieldElementExpression::Select(
|
||||
box FieldElementArrayExpression::Identifier(3, String::from("b")),
|
||||
box FieldElementExpression::Identifier(String::from("a")),
|
||||
)
|
||||
.into(),
|
||||
])],
|
||||
signature: Signature::new()
|
||||
.inputs(vec![Type::FieldElement, Type::FieldElementArray(3)])
|
||||
.outputs(vec![Type::FieldElement]),
|
||||
};
|
||||
|
||||
let i = Inliner::new();
|
||||
let arguments = vec![
|
||||
FieldElementExpression::Identifier(String::from("notconstant")).into(),
|
||||
FieldElementArrayExpression::Identifier(3, String::from("random")).into(),
|
||||
];
|
||||
|
||||
assert!(!i.should_inline(&Some(f), &arguments));
|
||||
}
|
||||
}
|
||||
}
|
||||
let i = Inliner::new();
|
||||
|
||||
assert!(!i.should_inline(&Some(f), &arguments));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,45 +4,45 @@
|
|||
//! @author Thibaut Schaeffer <thibaut@schaeff.fr>
|
||||
//! @date 2018
|
||||
|
||||
mod propagation;
|
||||
mod unroll;
|
||||
mod dead_code;
|
||||
mod flat_propagation;
|
||||
mod inline;
|
||||
mod dead_code;
|
||||
mod power_check;
|
||||
mod propagation;
|
||||
mod unroll;
|
||||
|
||||
use flat_absy::FlatProg;
|
||||
use field::Field;
|
||||
use typed_absy::TypedProg;
|
||||
use self::unroll::Unroller;
|
||||
use self::inline::Inliner;
|
||||
use self::propagation::Propagator;
|
||||
use self::dead_code::DeadCode;
|
||||
use self::inline::Inliner;
|
||||
use self::power_check::PowerChecker;
|
||||
use self::propagation::Propagator;
|
||||
use self::unroll::Unroller;
|
||||
use field::Field;
|
||||
use flat_absy::FlatProg;
|
||||
use typed_absy::TypedProg;
|
||||
|
||||
pub trait Analyse {
|
||||
fn analyse(self) -> Self;
|
||||
fn analyse(self) -> Self;
|
||||
}
|
||||
|
||||
impl<T: Field> Analyse for TypedProg<T> {
|
||||
fn analyse(self) -> Self {
|
||||
let r = PowerChecker::check(self);
|
||||
// unroll
|
||||
let r = Unroller::unroll(r);
|
||||
//propagate a first time for constants to reach function calls
|
||||
let r = Propagator::propagate(r);
|
||||
// apply inlining strategy
|
||||
let r = Inliner::inline(r);
|
||||
// Propagate again
|
||||
let r = Propagator::propagate(r);
|
||||
// remove unused functions
|
||||
let r = DeadCode::clean(r);
|
||||
r
|
||||
}
|
||||
fn analyse(self) -> Self {
|
||||
let r = PowerChecker::check(self);
|
||||
// unroll
|
||||
let r = Unroller::unroll(r);
|
||||
//propagate a first time for constants to reach function calls
|
||||
let r = Propagator::propagate(r);
|
||||
// apply inlining strategy
|
||||
let r = Inliner::inline(r);
|
||||
// Propagate again
|
||||
let r = Propagator::propagate(r);
|
||||
// remove unused functions
|
||||
let r = DeadCode::clean(r);
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> Analyse for FlatProg<T> {
|
||||
fn analyse(self) -> Self {
|
||||
self.propagate()
|
||||
}
|
||||
}
|
||||
fn analyse(self) -> Self {
|
||||
self.propagate()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
use field::Field;
|
||||
use typed_absy::folder::*;
|
||||
use typed_absy::Folder;
|
||||
use typed_absy::*;
|
||||
use typed_absy::folder::*;
|
||||
|
||||
pub struct PowerChecker {}
|
||||
|
||||
impl PowerChecker {
|
||||
fn new() -> Self {
|
||||
PowerChecker {}
|
||||
}
|
||||
fn new() -> Self {
|
||||
PowerChecker {}
|
||||
}
|
||||
|
||||
pub fn check<T: Field>(p: TypedProg<T>) -> TypedProg<T> {
|
||||
PowerChecker::new().fold_program(p)
|
||||
PowerChecker::new().fold_program(p)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> Folder<T> for PowerChecker {
|
||||
fn fold_field_expression(&mut self, e: FieldElementExpression<T>) -> FieldElementExpression<T> {
|
||||
fn fold_field_expression(&mut self, e: FieldElementExpression<T>) -> FieldElementExpression<T> {
|
||||
match e {
|
||||
FieldElementExpression::Pow(box FieldElementExpression::Identifier(..), _) | FieldElementExpression::Pow(box FieldElementExpression::Number(..), _)=> {
|
||||
fold_field_expression(self, e)
|
||||
|
@ -26,5 +26,5 @@ impl<T: Field> Folder<T> for PowerChecker {
|
|||
},
|
||||
e => fold_field_expression(self, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -5,386 +5,479 @@
|
|||
//! @date 2018
|
||||
|
||||
use absy::variable::Variable;
|
||||
use std::collections::HashMap;
|
||||
use field::Field;
|
||||
use typed_absy::*;
|
||||
use std::collections::HashMap;
|
||||
use typed_absy::folder::*;
|
||||
use typed_absy::*;
|
||||
use types::Type;
|
||||
|
||||
pub struct Unroller {
|
||||
substitution: HashMap<String, usize>
|
||||
substitution: HashMap<String, usize>,
|
||||
}
|
||||
|
||||
impl Unroller {
|
||||
fn new() -> Self {
|
||||
Unroller {
|
||||
substitution: HashMap::new()
|
||||
}
|
||||
}
|
||||
fn new() -> Self {
|
||||
Unroller {
|
||||
substitution: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn issue_next_ssa_variable(&mut self, v: Variable) -> Variable {
|
||||
let res = match self.substitution.get(&v.id) {
|
||||
Some(i) => {
|
||||
Variable { id: format!("{}_{}", v.id, i + 1), ..v}
|
||||
},
|
||||
None => {
|
||||
Variable { id: format!("{}_{}", v.id, 0), ..v}
|
||||
}
|
||||
};
|
||||
self.substitution.entry(v.id)
|
||||
.and_modify(|e| { *e += 1 })
|
||||
.or_insert(0);
|
||||
res
|
||||
}
|
||||
fn issue_next_ssa_variable(&mut self, v: Variable) -> Variable {
|
||||
let res = match self.substitution.get(&v.id) {
|
||||
Some(i) => Variable {
|
||||
id: format!("{}_{}", v.id, i + 1),
|
||||
..v
|
||||
},
|
||||
None => Variable {
|
||||
id: format!("{}_{}", v.id, 0),
|
||||
..v
|
||||
},
|
||||
};
|
||||
self.substitution
|
||||
.entry(v.id)
|
||||
.and_modify(|e| *e += 1)
|
||||
.or_insert(0);
|
||||
res
|
||||
}
|
||||
|
||||
pub fn unroll<T: Field>(p: TypedProg<T>) -> TypedProg<T> {
|
||||
Unroller::new().fold_program(p)
|
||||
}
|
||||
pub fn unroll<T: Field>(p: TypedProg<T>) -> TypedProg<T> {
|
||||
Unroller::new().fold_program(p)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> Folder<T> for Unroller {
|
||||
fn fold_statement(&mut self, s: TypedStatement<T>) -> Vec<TypedStatement<T>> {
|
||||
match s {
|
||||
TypedStatement::Declaration(_) => {
|
||||
vec![]
|
||||
},
|
||||
TypedStatement::Definition(TypedAssignee::Identifier(variable), expr) => {
|
||||
let expr = self.fold_expression(expr);
|
||||
fn fold_statement(&mut self, s: TypedStatement<T>) -> Vec<TypedStatement<T>> {
|
||||
match s {
|
||||
TypedStatement::Declaration(_) => vec![],
|
||||
TypedStatement::Definition(TypedAssignee::Identifier(variable), expr) => {
|
||||
let expr = self.fold_expression(expr);
|
||||
|
||||
vec![TypedStatement::Definition(TypedAssignee::Identifier(self.issue_next_ssa_variable(variable)), expr)]
|
||||
},
|
||||
TypedStatement::Definition(TypedAssignee::ArrayElement(array @ box TypedAssignee::Identifier(..), box index), expr) => {
|
||||
let expr = self.fold_expression(expr);
|
||||
let index = self.fold_field_expression(index);
|
||||
let current_array = self.fold_assignee(*array.clone());
|
||||
vec![TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(self.issue_next_ssa_variable(variable)),
|
||||
expr,
|
||||
)]
|
||||
}
|
||||
TypedStatement::Definition(
|
||||
TypedAssignee::ArrayElement(array @ box TypedAssignee::Identifier(..), box index),
|
||||
expr,
|
||||
) => {
|
||||
let expr = self.fold_expression(expr);
|
||||
let index = self.fold_field_expression(index);
|
||||
let current_array = self.fold_assignee(*array.clone());
|
||||
|
||||
let current_ssa_variable = match current_array {
|
||||
TypedAssignee::Identifier(v) => v,
|
||||
_ => panic!("assignee should be an identifier")
|
||||
};
|
||||
let current_ssa_variable = match current_array {
|
||||
TypedAssignee::Identifier(v) => v,
|
||||
_ => panic!("assignee should be an identifier"),
|
||||
};
|
||||
|
||||
let original_variable = match *array {
|
||||
TypedAssignee::Identifier(v) => v,
|
||||
_ => panic!("assignee should be an identifier")
|
||||
};
|
||||
let original_variable = match *array {
|
||||
TypedAssignee::Identifier(v) => v,
|
||||
_ => panic!("assignee should be an identifier"),
|
||||
};
|
||||
|
||||
let array_size = match original_variable.get_type() {
|
||||
Type::FieldElementArray(size) => size,
|
||||
_ => panic!("array identifier should be a field element array")
|
||||
};
|
||||
let array_size = match original_variable.get_type() {
|
||||
Type::FieldElementArray(size) => size,
|
||||
_ => panic!("array identifier should be a field element array"),
|
||||
};
|
||||
|
||||
let expr = match expr {
|
||||
TypedExpression::FieldElement(e) => e,
|
||||
_ => panic!("right side of array element definition must be a field element")
|
||||
};
|
||||
let expr = match expr {
|
||||
TypedExpression::FieldElement(e) => e,
|
||||
_ => panic!("right side of array element definition must be a field element"),
|
||||
};
|
||||
|
||||
let new_variable = self.issue_next_ssa_variable(original_variable);
|
||||
let new_variable = self.issue_next_ssa_variable(original_variable);
|
||||
|
||||
let new_array = FieldElementArrayExpression::Value(array_size, (0..array_size)
|
||||
.map(|i|
|
||||
FieldElementExpression::IfElse(
|
||||
box BooleanExpression::Eq(
|
||||
box index.clone(),
|
||||
box FieldElementExpression::Number(T::from(i))
|
||||
),
|
||||
box expr.clone(),
|
||||
box FieldElementExpression::Select(
|
||||
box FieldElementArrayExpression::Identifier(array_size, current_ssa_variable.id.clone()),
|
||||
box FieldElementExpression::Number(T::from(i))
|
||||
)
|
||||
)
|
||||
)
|
||||
.collect()
|
||||
);
|
||||
let new_array = FieldElementArrayExpression::Value(
|
||||
array_size,
|
||||
(0..array_size)
|
||||
.map(|i| {
|
||||
FieldElementExpression::IfElse(
|
||||
box BooleanExpression::Eq(
|
||||
box index.clone(),
|
||||
box FieldElementExpression::Number(T::from(i)),
|
||||
),
|
||||
box expr.clone(),
|
||||
box FieldElementExpression::Select(
|
||||
box FieldElementArrayExpression::Identifier(
|
||||
array_size,
|
||||
current_ssa_variable.id.clone(),
|
||||
),
|
||||
box FieldElementExpression::Number(T::from(i)),
|
||||
),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
);
|
||||
|
||||
vec![
|
||||
TypedStatement::Definition(TypedAssignee::Identifier(new_variable), new_array.into()),
|
||||
]
|
||||
},
|
||||
TypedStatement::MultipleDefinition(variables, exprs) => {
|
||||
let exprs = self.fold_expression_list(exprs);
|
||||
let variables = variables.into_iter().map(|v| self.issue_next_ssa_variable(v)).collect();
|
||||
vec![TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(new_variable),
|
||||
new_array.into(),
|
||||
)]
|
||||
}
|
||||
TypedStatement::MultipleDefinition(variables, exprs) => {
|
||||
let exprs = self.fold_expression_list(exprs);
|
||||
let variables = variables
|
||||
.into_iter()
|
||||
.map(|v| self.issue_next_ssa_variable(v))
|
||||
.collect();
|
||||
|
||||
vec![TypedStatement::MultipleDefinition(variables, exprs)]
|
||||
},
|
||||
TypedStatement::For(v, from, to, stats) => {
|
||||
let mut values: Vec<T> = vec![];
|
||||
let mut current = from;
|
||||
vec![TypedStatement::MultipleDefinition(variables, exprs)]
|
||||
}
|
||||
TypedStatement::For(v, from, to, stats) => {
|
||||
let mut values: Vec<T> = vec![];
|
||||
let mut current = from;
|
||||
while current < to {
|
||||
values.push(current.clone());
|
||||
values.push(current.clone());
|
||||
current = T::one() + ¤t;
|
||||
}
|
||||
|
||||
let res = values.into_iter().map(|index| {
|
||||
vec![
|
||||
vec![
|
||||
TypedStatement::Declaration(v.clone()),
|
||||
TypedStatement::Definition(TypedAssignee::Identifier(v.clone()), FieldElementExpression::Number(index).into()),
|
||||
],
|
||||
stats.clone()
|
||||
].into_iter().flat_map(|x| x)
|
||||
}).flat_map(|x| x).flat_map(|x| self.fold_statement(x)).collect();
|
||||
let res = values
|
||||
.into_iter()
|
||||
.map(|index| {
|
||||
vec![
|
||||
vec![
|
||||
TypedStatement::Declaration(v.clone()),
|
||||
TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(v.clone()),
|
||||
FieldElementExpression::Number(index).into(),
|
||||
),
|
||||
],
|
||||
stats.clone(),
|
||||
]
|
||||
.into_iter()
|
||||
.flat_map(|x| x)
|
||||
})
|
||||
.flat_map(|x| x)
|
||||
.flat_map(|x| self.fold_statement(x))
|
||||
.collect();
|
||||
|
||||
res
|
||||
}
|
||||
s => fold_statement(self, s)
|
||||
}
|
||||
}
|
||||
res
|
||||
}
|
||||
s => fold_statement(self, s),
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_function(&mut self, f: TypedFunction<T>) -> TypedFunction<T> {
|
||||
self.substitution = HashMap::new();
|
||||
for arg in &f.arguments {
|
||||
self.substitution.insert(arg.id.id.clone(), 0);
|
||||
}
|
||||
fn fold_function(&mut self, f: TypedFunction<T>) -> TypedFunction<T> {
|
||||
self.substitution = HashMap::new();
|
||||
for arg in &f.arguments {
|
||||
self.substitution.insert(arg.id.id.clone(), 0);
|
||||
}
|
||||
|
||||
fold_function(self, f)
|
||||
}
|
||||
fold_function(self, f)
|
||||
}
|
||||
|
||||
fn fold_name(&mut self, n: String) -> String {
|
||||
format!("{}_{}", n, self.substitution.get(&n).unwrap())
|
||||
}
|
||||
fn fold_name(&mut self, n: String) -> String {
|
||||
format!("{}_{}", n, self.substitution.get(&n).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use field::FieldPrime;
|
||||
use super::*;
|
||||
use field::FieldPrime;
|
||||
|
||||
#[cfg(test)]
|
||||
mod statement {
|
||||
use super::*;
|
||||
#[cfg(test)]
|
||||
mod statement {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn for_loop() {
|
||||
#[test]
|
||||
fn for_loop() {
|
||||
// for field i in 2..5
|
||||
// field foo = i
|
||||
|
||||
// for field i in 2..5
|
||||
// field foo = i
|
||||
|
||||
// should be unrolled to
|
||||
// i_0 = 2
|
||||
// foo_0 = i_0
|
||||
// i_1 = 3
|
||||
// foo_1 = i_1
|
||||
// i_2 = 4
|
||||
// foo_2 = i_2
|
||||
// should be unrolled to
|
||||
// i_0 = 2
|
||||
// foo_0 = i_0
|
||||
// i_1 = 3
|
||||
// foo_1 = i_1
|
||||
// i_2 = 4
|
||||
// foo_2 = i_2
|
||||
|
||||
let s = TypedStatement::For(Variable::field_element("i"), FieldPrime::from(2), FieldPrime::from(5), vec![
|
||||
TypedStatement::Declaration(Variable::field_element("foo")),
|
||||
TypedStatement::Definition(TypedAssignee::Identifier(Variable::field_element("foo")), FieldElementExpression::Identifier(String::from("i")).into())]
|
||||
);
|
||||
let s = TypedStatement::For(
|
||||
Variable::field_element("i"),
|
||||
FieldPrime::from(2),
|
||||
FieldPrime::from(5),
|
||||
vec![
|
||||
TypedStatement::Declaration(Variable::field_element("foo")),
|
||||
TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(Variable::field_element("foo")),
|
||||
FieldElementExpression::Identifier(String::from("i")).into(),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
let expected = vec![
|
||||
TypedStatement::Definition(TypedAssignee::Identifier(Variable::field_element("i_0")), FieldElementExpression::Number(FieldPrime::from(2)).into()),
|
||||
TypedStatement::Definition(TypedAssignee::Identifier(Variable::field_element("foo_0")), FieldElementExpression::Identifier(String::from("i_0")).into()),
|
||||
let expected = vec![
|
||||
TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(Variable::field_element("i_0")),
|
||||
FieldElementExpression::Number(FieldPrime::from(2)).into(),
|
||||
),
|
||||
TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(Variable::field_element("foo_0")),
|
||||
FieldElementExpression::Identifier(String::from("i_0")).into(),
|
||||
),
|
||||
TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(Variable::field_element("i_1")),
|
||||
FieldElementExpression::Number(FieldPrime::from(3)).into(),
|
||||
),
|
||||
TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(Variable::field_element("foo_1")),
|
||||
FieldElementExpression::Identifier(String::from("i_1")).into(),
|
||||
),
|
||||
TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(Variable::field_element("i_2")),
|
||||
FieldElementExpression::Number(FieldPrime::from(4)).into(),
|
||||
),
|
||||
TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(Variable::field_element("foo_2")),
|
||||
FieldElementExpression::Identifier(String::from("i_2")).into(),
|
||||
),
|
||||
];
|
||||
|
||||
TypedStatement::Definition(TypedAssignee::Identifier(Variable::field_element("i_1")), FieldElementExpression::Number(FieldPrime::from(3)).into()),
|
||||
TypedStatement::Definition(TypedAssignee::Identifier(Variable::field_element("foo_1")), FieldElementExpression::Identifier(String::from("i_1")).into()),
|
||||
let mut u = Unroller::new();
|
||||
|
||||
TypedStatement::Definition(TypedAssignee::Identifier(Variable::field_element("i_2")), FieldElementExpression::Number(FieldPrime::from(4)).into()),
|
||||
TypedStatement::Definition(TypedAssignee::Identifier(Variable::field_element("foo_2")), FieldElementExpression::Identifier(String::from("i_2")).into()),
|
||||
];
|
||||
assert_eq!(u.fold_statement(s), expected);
|
||||
}
|
||||
|
||||
let mut u = Unroller::new();
|
||||
#[test]
|
||||
fn definition() {
|
||||
// field a
|
||||
// a = 5
|
||||
// a = 6
|
||||
// a
|
||||
|
||||
assert_eq!(u.fold_statement(s), expected);
|
||||
}
|
||||
// should be turned into
|
||||
// a_0 = 5
|
||||
// a_1 = 6
|
||||
// a_1
|
||||
|
||||
#[test]
|
||||
fn definition() {
|
||||
let mut u = Unroller::new();
|
||||
|
||||
// field a
|
||||
// a = 5
|
||||
// a = 6
|
||||
// a
|
||||
let s: TypedStatement<FieldPrime> =
|
||||
TypedStatement::Declaration(Variable::field_element("a"));
|
||||
assert_eq!(u.fold_statement(s), vec![]);
|
||||
|
||||
// should be turned into
|
||||
// a_0 = 5
|
||||
// a_1 = 6
|
||||
// a_1
|
||||
let s = TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(Variable::field_element("a")),
|
||||
FieldElementExpression::Number(FieldPrime::from(5)).into(),
|
||||
);
|
||||
assert_eq!(
|
||||
u.fold_statement(s),
|
||||
vec![TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(Variable::field_element("a_0")),
|
||||
FieldElementExpression::Number(FieldPrime::from(5)).into()
|
||||
)]
|
||||
);
|
||||
|
||||
let mut u = Unroller::new();
|
||||
let s = TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(Variable::field_element("a")),
|
||||
FieldElementExpression::Number(FieldPrime::from(6)).into(),
|
||||
);
|
||||
assert_eq!(
|
||||
u.fold_statement(s),
|
||||
vec![TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(Variable::field_element("a_1")),
|
||||
FieldElementExpression::Number(FieldPrime::from(6)).into()
|
||||
)]
|
||||
);
|
||||
|
||||
let s: TypedStatement<FieldPrime> = TypedStatement::Declaration(Variable::field_element("a"));
|
||||
assert_eq!(u.fold_statement(s), vec![]);
|
||||
let e: FieldElementExpression<FieldPrime> =
|
||||
FieldElementExpression::Identifier(String::from("a"));
|
||||
assert_eq!(
|
||||
u.fold_field_expression(e),
|
||||
FieldElementExpression::Identifier(String::from("a_1"))
|
||||
);
|
||||
}
|
||||
|
||||
let s = TypedStatement::Definition(TypedAssignee::Identifier(Variable::field_element("a")), FieldElementExpression::Number(FieldPrime::from(5)).into());
|
||||
assert_eq!(u.fold_statement(s), vec![TypedStatement::Definition(TypedAssignee::Identifier(Variable::field_element("a_0")), FieldElementExpression::Number(FieldPrime::from(5)).into())]);
|
||||
|
||||
let s = TypedStatement::Definition(TypedAssignee::Identifier(Variable::field_element("a")), FieldElementExpression::Number(FieldPrime::from(6)).into());
|
||||
assert_eq!(u.fold_statement(s), vec![TypedStatement::Definition(TypedAssignee::Identifier(Variable::field_element("a_1")), FieldElementExpression::Number(FieldPrime::from(6)).into())]);
|
||||
|
||||
let e: FieldElementExpression<FieldPrime> = FieldElementExpression::Identifier(String::from("a"));
|
||||
assert_eq!(u.fold_field_expression(e), FieldElementExpression::Identifier(String::from("a_1")));
|
||||
}
|
||||
#[test]
|
||||
fn incremental_definition() {
|
||||
// field a
|
||||
// a = 5
|
||||
// a = a + 1
|
||||
|
||||
#[test]
|
||||
fn incremental_definition() {
|
||||
// should be turned into
|
||||
// a_0 = 5
|
||||
// a_1 = a_0 + 1
|
||||
|
||||
// field a
|
||||
// a = 5
|
||||
// a = a + 1
|
||||
let mut u = Unroller::new();
|
||||
|
||||
// should be turned into
|
||||
// a_0 = 5
|
||||
// a_1 = a_0 + 1
|
||||
let s: TypedStatement<FieldPrime> =
|
||||
TypedStatement::Declaration(Variable::field_element("a"));
|
||||
assert_eq!(u.fold_statement(s), vec![]);
|
||||
|
||||
let mut u = Unroller::new();
|
||||
let s = TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(Variable::field_element("a")),
|
||||
FieldElementExpression::Number(FieldPrime::from(5)).into(),
|
||||
);
|
||||
assert_eq!(
|
||||
u.fold_statement(s),
|
||||
vec![TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(Variable::field_element("a_0")),
|
||||
FieldElementExpression::Number(FieldPrime::from(5)).into()
|
||||
)]
|
||||
);
|
||||
|
||||
let s: TypedStatement<FieldPrime> = TypedStatement::Declaration(Variable::field_element("a"));
|
||||
assert_eq!(u.fold_statement(s), vec![]);
|
||||
let s = TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(Variable::field_element("a")),
|
||||
FieldElementExpression::Add(
|
||||
box FieldElementExpression::Identifier(String::from("a")),
|
||||
box FieldElementExpression::Number(FieldPrime::from(1)),
|
||||
)
|
||||
.into(),
|
||||
);
|
||||
assert_eq!(
|
||||
u.fold_statement(s),
|
||||
vec![TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(Variable::field_element("a_1")),
|
||||
FieldElementExpression::Add(
|
||||
box FieldElementExpression::Identifier(String::from("a_0")),
|
||||
box FieldElementExpression::Number(FieldPrime::from(1))
|
||||
)
|
||||
.into()
|
||||
)]
|
||||
);
|
||||
}
|
||||
|
||||
let s = TypedStatement::Definition(TypedAssignee::Identifier(Variable::field_element("a")), FieldElementExpression::Number(FieldPrime::from(5)).into());
|
||||
assert_eq!(u.fold_statement(s), vec![TypedStatement::Definition(TypedAssignee::Identifier(Variable::field_element("a_0")), FieldElementExpression::Number(FieldPrime::from(5)).into())]);
|
||||
|
||||
let s = TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(Variable::field_element("a")),
|
||||
FieldElementExpression::Add(
|
||||
box FieldElementExpression::Identifier(String::from("a")),
|
||||
box FieldElementExpression::Number(FieldPrime::from(1))
|
||||
).into()
|
||||
);
|
||||
assert_eq!(
|
||||
u.fold_statement(s),
|
||||
vec![
|
||||
TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(Variable::field_element("a_1")),
|
||||
FieldElementExpression::Add(
|
||||
box FieldElementExpression::Identifier(String::from("a_0")),
|
||||
box FieldElementExpression::Number(FieldPrime::from(1))
|
||||
).into()
|
||||
)
|
||||
]
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn incremental_multiple_definition() {
|
||||
use types::Type;
|
||||
|
||||
#[test]
|
||||
fn incremental_multiple_definition() {
|
||||
// field a
|
||||
// a = 2
|
||||
// a = foo(a)
|
||||
|
||||
use types::Type;
|
||||
// should be turned into
|
||||
// a_0 = 2
|
||||
// a_1 = foo(a_0)
|
||||
|
||||
// field a
|
||||
// a = 2
|
||||
// a = foo(a)
|
||||
let mut u = Unroller::new();
|
||||
|
||||
// should be turned into
|
||||
// a_0 = 2
|
||||
// a_1 = foo(a_0)
|
||||
let s: TypedStatement<FieldPrime> =
|
||||
TypedStatement::Declaration(Variable::field_element("a"));
|
||||
assert_eq!(u.fold_statement(s), vec![]);
|
||||
|
||||
let mut u = Unroller::new();
|
||||
let s = TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(Variable::field_element("a")),
|
||||
FieldElementExpression::Number(FieldPrime::from(2)).into(),
|
||||
);
|
||||
assert_eq!(
|
||||
u.fold_statement(s),
|
||||
vec![TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(Variable::field_element("a_0")),
|
||||
FieldElementExpression::Number(FieldPrime::from(2)).into()
|
||||
)]
|
||||
);
|
||||
|
||||
let s: TypedStatement<FieldPrime> = TypedStatement::Declaration(Variable::field_element("a"));
|
||||
assert_eq!(u.fold_statement(s), vec![]);
|
||||
let s: TypedStatement<FieldPrime> = TypedStatement::MultipleDefinition(
|
||||
vec![Variable::field_element("a")],
|
||||
TypedExpressionList::FunctionCall(
|
||||
String::from("foo"),
|
||||
vec![FieldElementExpression::Identifier(String::from("a")).into()],
|
||||
vec![Type::FieldElement],
|
||||
),
|
||||
);
|
||||
assert_eq!(
|
||||
u.fold_statement(s),
|
||||
vec![TypedStatement::MultipleDefinition(
|
||||
vec![Variable::field_element("a_1")],
|
||||
TypedExpressionList::FunctionCall(
|
||||
String::from("foo"),
|
||||
vec![FieldElementExpression::Identifier(String::from("a_0")).into()],
|
||||
vec![Type::FieldElement],
|
||||
)
|
||||
)]
|
||||
);
|
||||
}
|
||||
|
||||
let s = TypedStatement::Definition(TypedAssignee::Identifier(Variable::field_element("a")), FieldElementExpression::Number(FieldPrime::from(2)).into());
|
||||
assert_eq!(u.fold_statement(s), vec![TypedStatement::Definition(TypedAssignee::Identifier(Variable::field_element("a_0")), FieldElementExpression::Number(FieldPrime::from(2)).into())]);
|
||||
|
||||
let s: TypedStatement<FieldPrime> = TypedStatement::MultipleDefinition(
|
||||
vec![Variable::field_element("a")],
|
||||
TypedExpressionList::FunctionCall(
|
||||
String::from("foo"),
|
||||
vec![FieldElementExpression::Identifier(String::from("a")).into()],
|
||||
vec![Type::FieldElement],
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
u.fold_statement(s),
|
||||
vec![
|
||||
TypedStatement::MultipleDefinition(
|
||||
vec![Variable::field_element("a_1")],
|
||||
TypedExpressionList::FunctionCall(
|
||||
String::from("foo"),
|
||||
vec![FieldElementExpression::Identifier(String::from("a_0")).into()],
|
||||
vec![Type::FieldElement],
|
||||
)
|
||||
)
|
||||
]
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn incremental_array_definition() {
|
||||
// field[2] a = [1, 1]
|
||||
// a[1] = 2
|
||||
|
||||
#[test]
|
||||
fn incremental_array_definition() {
|
||||
// should be turned into
|
||||
// a_0 = [1, 1]
|
||||
// a_1 = [if 0 == 1 then 2 else a_0[0], if 1 == 1 then 2 else a_0[1]]
|
||||
|
||||
// field[2] a = [1, 1]
|
||||
// a[1] = 2
|
||||
let mut u = Unroller::new();
|
||||
|
||||
// should be turned into
|
||||
// a_0 = [1, 1]
|
||||
// a_1 = [if 0 == 1 then 2 else a_0[0], if 1 == 1 then 2 else a_0[1]]
|
||||
let s: TypedStatement<FieldPrime> =
|
||||
TypedStatement::Declaration(Variable::field_array("a", 2));
|
||||
assert_eq!(u.fold_statement(s), vec![]);
|
||||
|
||||
let mut u = Unroller::new();
|
||||
let s = TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(Variable::field_array("a", 2)),
|
||||
FieldElementArrayExpression::Value(
|
||||
2,
|
||||
vec![
|
||||
FieldElementExpression::Number(FieldPrime::from(1)),
|
||||
FieldElementExpression::Number(FieldPrime::from(1)),
|
||||
],
|
||||
)
|
||||
.into(),
|
||||
);
|
||||
|
||||
let s: TypedStatement<FieldPrime> = TypedStatement::Declaration(Variable::field_array("a", 2));
|
||||
assert_eq!(u.fold_statement(s), vec![]);
|
||||
assert_eq!(
|
||||
u.fold_statement(s),
|
||||
vec![TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(Variable::field_array("a_0", 2)),
|
||||
FieldElementArrayExpression::Value(
|
||||
2,
|
||||
vec![
|
||||
FieldElementExpression::Number(FieldPrime::from(1)),
|
||||
FieldElementExpression::Number(FieldPrime::from(1))
|
||||
]
|
||||
)
|
||||
.into()
|
||||
)]
|
||||
);
|
||||
|
||||
let s = TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(
|
||||
Variable::field_array("a", 2)
|
||||
),
|
||||
FieldElementArrayExpression::Value(
|
||||
2,
|
||||
vec![
|
||||
FieldElementExpression::Number(FieldPrime::from(1)),
|
||||
FieldElementExpression::Number(FieldPrime::from(1))
|
||||
]
|
||||
).into()
|
||||
);
|
||||
let s: TypedStatement<FieldPrime> = TypedStatement::Definition(
|
||||
TypedAssignee::ArrayElement(
|
||||
box TypedAssignee::Identifier(Variable::field_array("a", 2)),
|
||||
box FieldElementExpression::Number(FieldPrime::from(1)),
|
||||
),
|
||||
FieldElementExpression::Number(FieldPrime::from(2)).into(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
u.fold_statement(s),
|
||||
vec![
|
||||
TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(
|
||||
Variable::field_array("a_0", 2)
|
||||
),
|
||||
FieldElementArrayExpression::Value(
|
||||
2,
|
||||
vec![
|
||||
FieldElementExpression::Number(FieldPrime::from(1)),
|
||||
FieldElementExpression::Number(FieldPrime::from(1))
|
||||
]
|
||||
).into()
|
||||
)
|
||||
]
|
||||
);
|
||||
|
||||
let s: TypedStatement<FieldPrime> = TypedStatement::Definition(
|
||||
TypedAssignee::ArrayElement(box TypedAssignee::Identifier(Variable::field_array("a", 2)), box FieldElementExpression::Number(FieldPrime::from(1))),
|
||||
FieldElementExpression::Number(FieldPrime::from(2)).into()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
u.fold_statement(s),
|
||||
vec![
|
||||
TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(Variable::field_array("a_1", 2)),
|
||||
FieldElementArrayExpression::Value(
|
||||
2,
|
||||
vec![
|
||||
FieldElementExpression::IfElse(
|
||||
box BooleanExpression::Eq(
|
||||
box FieldElementExpression::Number(FieldPrime::from(1)), box FieldElementExpression::Number(FieldPrime::from(0))
|
||||
),
|
||||
box FieldElementExpression::Number(FieldPrime::from(2)),
|
||||
box FieldElementExpression::Select(
|
||||
box FieldElementArrayExpression::Identifier(2, String::from("a_0")),
|
||||
box FieldElementExpression::Number(FieldPrime::from(0))
|
||||
),
|
||||
),
|
||||
FieldElementExpression::IfElse(
|
||||
box BooleanExpression::Eq(
|
||||
box FieldElementExpression::Number(FieldPrime::from(1)), box FieldElementExpression::Number(FieldPrime::from(1))
|
||||
),
|
||||
box FieldElementExpression::Number(FieldPrime::from(2)),
|
||||
box FieldElementExpression::Select(
|
||||
box FieldElementArrayExpression::Identifier(2, String::from("a_0")),
|
||||
box FieldElementExpression::Number(FieldPrime::from(1))
|
||||
),
|
||||
),
|
||||
]
|
||||
).into()
|
||||
)
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
assert_eq!(
|
||||
u.fold_statement(s),
|
||||
vec![TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(Variable::field_array("a_1", 2)),
|
||||
FieldElementArrayExpression::Value(
|
||||
2,
|
||||
vec![
|
||||
FieldElementExpression::IfElse(
|
||||
box BooleanExpression::Eq(
|
||||
box FieldElementExpression::Number(FieldPrime::from(1)),
|
||||
box FieldElementExpression::Number(FieldPrime::from(0))
|
||||
),
|
||||
box FieldElementExpression::Number(FieldPrime::from(2)),
|
||||
box FieldElementExpression::Select(
|
||||
box FieldElementArrayExpression::Identifier(
|
||||
2,
|
||||
String::from("a_0")
|
||||
),
|
||||
box FieldElementExpression::Number(FieldPrime::from(0))
|
||||
),
|
||||
),
|
||||
FieldElementExpression::IfElse(
|
||||
box BooleanExpression::Eq(
|
||||
box FieldElementExpression::Number(FieldPrime::from(1)),
|
||||
box FieldElementExpression::Number(FieldPrime::from(1))
|
||||
),
|
||||
box FieldElementExpression::Number(FieldPrime::from(2)),
|
||||
box FieldElementExpression::Select(
|
||||
box FieldElementArrayExpression::Identifier(
|
||||
2,
|
||||
String::from("a_0")
|
||||
),
|
||||
box FieldElementExpression::Number(FieldPrime::from(1))
|
||||
),
|
||||
),
|
||||
]
|
||||
)
|
||||
.into()
|
||||
)]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use absy::variable::Variable;
|
|||
use field::Field;
|
||||
use typed_absy::*;
|
||||
|
||||
pub trait Folder<T: Field> : Sized {
|
||||
pub trait Folder<T: Field>: Sized {
|
||||
fn fold_program(&mut self, p: TypedProg<T>) -> TypedProg<T> {
|
||||
fold_program(self, p)
|
||||
}
|
||||
|
@ -20,7 +20,9 @@ pub trait Folder<T: Field> : Sized {
|
|||
}
|
||||
}
|
||||
|
||||
fn fold_name(&mut self, n: String) -> String { n }
|
||||
fn fold_name(&mut self, n: String) -> String {
|
||||
n
|
||||
}
|
||||
|
||||
fn fold_variable(&mut self, v: Variable) -> Variable {
|
||||
Variable {
|
||||
|
@ -32,7 +34,10 @@ pub trait Folder<T: Field> : Sized {
|
|||
fn fold_assignee(&mut self, a: TypedAssignee<T>) -> TypedAssignee<T> {
|
||||
match a {
|
||||
TypedAssignee::Identifier(v) => TypedAssignee::Identifier(self.fold_variable(v)),
|
||||
TypedAssignee::ArrayElement(box a, box index) => TypedAssignee::ArrayElement(box self.fold_assignee(a), box self.fold_field_expression(index))
|
||||
TypedAssignee::ArrayElement(box a, box index) => TypedAssignee::ArrayElement(
|
||||
box self.fold_assignee(a),
|
||||
box self.fold_field_expression(index),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,7 +56,14 @@ pub trait Folder<T: Field> : Sized {
|
|||
fn fold_expression_list(&mut self, es: TypedExpressionList<T>) -> TypedExpressionList<T> {
|
||||
match es {
|
||||
TypedExpressionList::FunctionCall(id, arguments, types) => {
|
||||
TypedExpressionList::FunctionCall(id, arguments.into_iter().map(|a| self.fold_expression(a)).collect(), types)
|
||||
TypedExpressionList::FunctionCall(
|
||||
id,
|
||||
arguments
|
||||
.into_iter()
|
||||
.map(|a| self.fold_expression(a))
|
||||
.collect(),
|
||||
types,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -62,38 +74,75 @@ pub trait Folder<T: Field> : Sized {
|
|||
fn fold_boolean_expression(&mut self, e: BooleanExpression<T>) -> BooleanExpression<T> {
|
||||
fold_boolean_expression(self, e)
|
||||
}
|
||||
fn fold_field_array_expression(&mut self, e: FieldElementArrayExpression<T>) -> FieldElementArrayExpression<T> {
|
||||
fn fold_field_array_expression(
|
||||
&mut self,
|
||||
e: FieldElementArrayExpression<T>,
|
||||
) -> FieldElementArrayExpression<T> {
|
||||
fold_field_array_expression(self, e)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fold_program<T: Field, F: Folder<T>>(f: &mut F, p: TypedProg<T>) -> TypedProg<T> {
|
||||
TypedProg {
|
||||
functions: p.functions.into_iter().map(|fun| f.fold_function(fun)).collect(),
|
||||
functions: p
|
||||
.functions
|
||||
.into_iter()
|
||||
.map(|fun| f.fold_function(fun))
|
||||
.collect(),
|
||||
..p
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fold_statement<T: Field, F: Folder<T>>(f: &mut F, s: TypedStatement<T>) -> Vec<TypedStatement<T>> {
|
||||
pub fn fold_statement<T: Field, F: Folder<T>>(
|
||||
f: &mut F,
|
||||
s: TypedStatement<T>,
|
||||
) -> Vec<TypedStatement<T>> {
|
||||
let res = match s {
|
||||
TypedStatement::Return(expressions) => TypedStatement::Return(expressions.into_iter().map(|e| f.fold_expression(e)).collect()),
|
||||
TypedStatement::Definition(a, e) => TypedStatement::Definition(f.fold_assignee(a), f.fold_expression(e)),
|
||||
TypedStatement::Return(expressions) => TypedStatement::Return(
|
||||
expressions
|
||||
.into_iter()
|
||||
.map(|e| f.fold_expression(e))
|
||||
.collect(),
|
||||
),
|
||||
TypedStatement::Definition(a, e) => {
|
||||
TypedStatement::Definition(f.fold_assignee(a), f.fold_expression(e))
|
||||
}
|
||||
TypedStatement::Declaration(v) => TypedStatement::Declaration(f.fold_variable(v)),
|
||||
TypedStatement::Condition(left, right) => TypedStatement::Condition(f.fold_expression(left), f.fold_expression(right)),
|
||||
TypedStatement::For(v, from, to, statements) => TypedStatement::For(f.fold_variable(v), from, to, statements.into_iter().flat_map(|s| f.fold_statement(s)).collect()),
|
||||
TypedStatement::MultipleDefinition(variables, elist) => TypedStatement::MultipleDefinition(variables.into_iter().map(|v| f.fold_variable(v)).collect(), f.fold_expression_list(elist)),
|
||||
TypedStatement::Condition(left, right) => {
|
||||
TypedStatement::Condition(f.fold_expression(left), f.fold_expression(right))
|
||||
}
|
||||
TypedStatement::For(v, from, to, statements) => TypedStatement::For(
|
||||
f.fold_variable(v),
|
||||
from,
|
||||
to,
|
||||
statements
|
||||
.into_iter()
|
||||
.flat_map(|s| f.fold_statement(s))
|
||||
.collect(),
|
||||
),
|
||||
TypedStatement::MultipleDefinition(variables, elist) => TypedStatement::MultipleDefinition(
|
||||
variables.into_iter().map(|v| f.fold_variable(v)).collect(),
|
||||
f.fold_expression_list(elist),
|
||||
),
|
||||
};
|
||||
vec![res]
|
||||
}
|
||||
|
||||
pub fn fold_field_array_expression<T: Field, F: Folder<T>>(f: &mut F, e: FieldElementArrayExpression<T>) -> FieldElementArrayExpression<T> {
|
||||
pub fn fold_field_array_expression<T: Field, F: Folder<T>>(
|
||||
f: &mut F,
|
||||
e: FieldElementArrayExpression<T>,
|
||||
) -> FieldElementArrayExpression<T> {
|
||||
match e {
|
||||
FieldElementArrayExpression::Identifier(size, id) => {
|
||||
FieldElementArrayExpression::Identifier(size, f.fold_name(id))
|
||||
},
|
||||
FieldElementArrayExpression::Value(size, exprs) => {
|
||||
FieldElementArrayExpression::Value(size, exprs.into_iter().map(|e| f.fold_field_expression(e)).collect())
|
||||
}
|
||||
FieldElementArrayExpression::Value(size, exprs) => FieldElementArrayExpression::Value(
|
||||
size,
|
||||
exprs
|
||||
.into_iter()
|
||||
.map(|e| f.fold_field_expression(e))
|
||||
.collect(),
|
||||
),
|
||||
FieldElementArrayExpression::FunctionCall(size, id, exps) => {
|
||||
let exps = exps.into_iter().map(|e| f.fold_expression(e)).collect();
|
||||
FieldElementArrayExpression::FunctionCall(size, id, exps)
|
||||
|
@ -101,54 +150,62 @@ pub fn fold_field_array_expression<T: Field, F: Folder<T>>(f: &mut F, e: FieldEl
|
|||
}
|
||||
}
|
||||
|
||||
pub fn fold_field_expression<T: Field, F: Folder<T>>(f: &mut F, e: FieldElementExpression<T>) -> FieldElementExpression<T> {
|
||||
pub fn fold_field_expression<T: Field, F: Folder<T>>(
|
||||
f: &mut F,
|
||||
e: FieldElementExpression<T>,
|
||||
) -> FieldElementExpression<T> {
|
||||
match e {
|
||||
FieldElementExpression::Number(n) => FieldElementExpression::Number(n),
|
||||
FieldElementExpression::Identifier(id) => FieldElementExpression::Identifier(f.fold_name(id)),
|
||||
FieldElementExpression::Identifier(id) => {
|
||||
FieldElementExpression::Identifier(f.fold_name(id))
|
||||
}
|
||||
FieldElementExpression::Add(box e1, box e2) => {
|
||||
let e1 = f.fold_field_expression(e1);
|
||||
let e2 = f.fold_field_expression(e2);
|
||||
FieldElementExpression::Add(box e1, box e2)
|
||||
},
|
||||
}
|
||||
FieldElementExpression::Sub(box e1, box e2) => {
|
||||
let e1 = f.fold_field_expression(e1);
|
||||
let e2 = f.fold_field_expression(e2);
|
||||
FieldElementExpression::Sub(box e1, box e2)
|
||||
},
|
||||
}
|
||||
FieldElementExpression::Mult(box e1, box e2) => {
|
||||
let e1 = f.fold_field_expression(e1);
|
||||
let e2 = f.fold_field_expression(e2);
|
||||
FieldElementExpression::Mult(box e1, box e2)
|
||||
},
|
||||
}
|
||||
FieldElementExpression::Div(box e1, box e2) => {
|
||||
let e1 = f.fold_field_expression(e1);
|
||||
let e2 = f.fold_field_expression(e2);
|
||||
FieldElementExpression::Div(box e1, box e2)
|
||||
},
|
||||
}
|
||||
FieldElementExpression::Pow(box e1, box e2) => {
|
||||
let e1 = f.fold_field_expression(e1);
|
||||
let e2 = f.fold_field_expression(e2);
|
||||
FieldElementExpression::Pow(box e1, box e2)
|
||||
},
|
||||
}
|
||||
FieldElementExpression::IfElse(box cond, box cons, box alt) => {
|
||||
let cond = f.fold_boolean_expression(cond);
|
||||
let cons = f.fold_field_expression(cons);
|
||||
let alt = f.fold_field_expression(alt);
|
||||
FieldElementExpression::IfElse(box cond, box cons, box alt)
|
||||
},
|
||||
}
|
||||
FieldElementExpression::FunctionCall(id, exps) => {
|
||||
let exps = exps.into_iter().map(|e| f.fold_expression(e)).collect();
|
||||
FieldElementExpression::FunctionCall(id, exps)
|
||||
},
|
||||
}
|
||||
FieldElementExpression::Select(box array, box index) => {
|
||||
let array = f.fold_field_array_expression(array);
|
||||
let index = f.fold_field_expression(index);
|
||||
FieldElementExpression::Select(box array, box index)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fold_boolean_expression<T: Field, F: Folder<T>>(f: &mut F, e: BooleanExpression<T>) -> BooleanExpression<T> {
|
||||
pub fn fold_boolean_expression<T: Field, F: Folder<T>>(
|
||||
f: &mut F,
|
||||
e: BooleanExpression<T>,
|
||||
) -> BooleanExpression<T> {
|
||||
match e {
|
||||
BooleanExpression::Value(v) => BooleanExpression::Value(v),
|
||||
BooleanExpression::Identifier(id) => BooleanExpression::Identifier(f.fold_name(id)),
|
||||
|
@ -196,8 +253,16 @@ pub fn fold_boolean_expression<T: Field, F: Folder<T>>(f: &mut F, e: BooleanExpr
|
|||
|
||||
pub fn fold_function<T: Field, F: Folder<T>>(f: &mut F, fun: TypedFunction<T>) -> TypedFunction<T> {
|
||||
TypedFunction {
|
||||
arguments: fun.arguments.into_iter().map(|a| f.fold_parameter(a)).collect(),
|
||||
statements: fun.statements.into_iter().flat_map(|s| f.fold_statement(s)).collect(),
|
||||
arguments: fun
|
||||
.arguments
|
||||
.into_iter()
|
||||
.map(|a| f.fold_parameter(a))
|
||||
.collect(),
|
||||
statements: fun
|
||||
.statements
|
||||
.into_iter()
|
||||
.flat_map(|s| f.fold_statement(s))
|
||||
.collect(),
|
||||
..fun
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,14 +7,14 @@
|
|||
|
||||
pub mod folder;
|
||||
|
||||
use types::Signature;
|
||||
use absy::parameter::Parameter;
|
||||
use absy::variable::Variable;
|
||||
use types::Signature;
|
||||
|
||||
use std::fmt;
|
||||
use field::Field;
|
||||
use imports::Import;
|
||||
use flat_absy::*;
|
||||
use imports::Import;
|
||||
use std::fmt;
|
||||
use types::Type;
|
||||
|
||||
pub use self::folder::Folder;
|
||||
|
@ -24,29 +24,31 @@ pub struct TypedProg<T: Field> {
|
|||
/// Functions of the program
|
||||
pub functions: Vec<TypedFunction<T>>,
|
||||
pub imports: Vec<Import>,
|
||||
pub imported_functions: Vec<FlatFunction<T>>
|
||||
pub imported_functions: Vec<FlatFunction<T>>,
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Display for TypedProg<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut res = vec![];
|
||||
res.extend(self.imports
|
||||
res.extend(
|
||||
self.imports
|
||||
.iter()
|
||||
.map(|x| format!("{}", x))
|
||||
.collect::<Vec<_>>());
|
||||
res.extend(self.imported_functions
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
res.extend(
|
||||
self.imported_functions
|
||||
.iter()
|
||||
.map(|x| format!("{}", x))
|
||||
.collect::<Vec<_>>());
|
||||
res.extend(self.functions
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
res.extend(
|
||||
self.functions
|
||||
.iter()
|
||||
.map(|x| format!("{}", x))
|
||||
.collect::<Vec<_>>());
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
res.join("\n")
|
||||
)
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
write!(f, "{}", res.join("\n"))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,7 +99,8 @@ impl<T: Field> fmt::Display for TypedFunction<T> {
|
|||
.map(|x| format!("{}", x))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", "),
|
||||
self.signature.outputs
|
||||
self.signature
|
||||
.outputs
|
||||
.iter()
|
||||
.map(|x| format!("{}", x))
|
||||
.collect::<Vec<_>>()
|
||||
|
@ -130,7 +133,7 @@ impl<T: Field> fmt::Debug for TypedFunction<T> {
|
|||
#[derive(Clone, Serialize, Deserialize, PartialEq, Hash, Eq)]
|
||||
pub enum TypedAssignee<T: Field> {
|
||||
Identifier(Variable),
|
||||
ArrayElement(Box<TypedAssignee<T>>, Box<FieldElementExpression<T>>)
|
||||
ArrayElement(Box<TypedAssignee<T>>, Box<FieldElementExpression<T>>),
|
||||
}
|
||||
|
||||
impl<T: Field> Typed for TypedAssignee<T> {
|
||||
|
@ -141,7 +144,7 @@ impl<T: Field> Typed for TypedAssignee<T> {
|
|||
let a_type = a.get_type();
|
||||
match a_type {
|
||||
Type::FieldElementArray(_) => Type::FieldElement,
|
||||
_ => panic!("array element has to take array")
|
||||
_ => panic!("array element has to take array"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -185,14 +188,14 @@ impl<T: Field> fmt::Debug for TypedStatement<T> {
|
|||
}
|
||||
}
|
||||
write!(f, ")")
|
||||
},
|
||||
TypedStatement::Declaration(ref var) => {
|
||||
write!(f, "Declaration({:?})", var)
|
||||
}
|
||||
TypedStatement::Declaration(ref var) => write!(f, "Declaration({:?})", var),
|
||||
TypedStatement::Definition(ref lhs, ref rhs) => {
|
||||
write!(f, "Definition({:?}, {:?})", lhs, rhs)
|
||||
}
|
||||
TypedStatement::Condition(ref lhs, ref rhs) => write!(f, "Condition({:?}, {:?})", lhs, rhs),
|
||||
TypedStatement::Condition(ref lhs, ref rhs) => {
|
||||
write!(f, "Condition({:?}, {:?})", lhs, rhs)
|
||||
}
|
||||
TypedStatement::For(ref var, ref start, ref stop, ref list) => {
|
||||
try!(write!(f, "for {:?} in {:?}..{:?} do\n", var, start, stop));
|
||||
for l in list {
|
||||
|
@ -202,12 +205,11 @@ impl<T: Field> fmt::Debug for TypedStatement<T> {
|
|||
}
|
||||
TypedStatement::MultipleDefinition(ref lhs, ref rhs) => {
|
||||
write!(f, "MultipleDefinition({:?}, {:?})", lhs, rhs)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<T: Field> fmt::Display for TypedStatement<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
|
@ -220,7 +222,7 @@ impl<T: Field> fmt::Display for TypedStatement<T> {
|
|||
}
|
||||
}
|
||||
write!(f, "")
|
||||
},
|
||||
}
|
||||
TypedStatement::Declaration(ref var) => write!(f, "{}", var),
|
||||
TypedStatement::Definition(ref lhs, ref rhs) => write!(f, "{} = {}", lhs, rhs),
|
||||
TypedStatement::Condition(ref lhs, ref rhs) => write!(f, "{} == {}", lhs, rhs),
|
||||
|
@ -239,13 +241,12 @@ impl<T: Field> fmt::Display for TypedStatement<T> {
|
|||
}
|
||||
}
|
||||
write!(f, " = {}", rhs)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Typed
|
||||
{
|
||||
pub trait Typed {
|
||||
fn get_type(&self) -> Type;
|
||||
}
|
||||
|
||||
|
@ -277,15 +278,9 @@ impl<T: Field> From<FieldElementArrayExpression<T>> for TypedExpression<T> {
|
|||
impl<T: Field> fmt::Display for TypedExpression<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
TypedExpression::Boolean(ref e) => {
|
||||
write!(f, "{}", e)
|
||||
},
|
||||
TypedExpression::FieldElement(ref e) => {
|
||||
write!(f, "{}", e)
|
||||
},
|
||||
TypedExpression::FieldElementArray(ref e) => {
|
||||
write!(f, "{}", e)
|
||||
}
|
||||
TypedExpression::Boolean(ref e) => write!(f, "{}", e),
|
||||
TypedExpression::FieldElement(ref e) => write!(f, "{}", e),
|
||||
TypedExpression::FieldElementArray(ref e) => write!(f, "{}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -293,15 +288,9 @@ impl<T: Field> fmt::Display for TypedExpression<T> {
|
|||
impl<T: Field> fmt::Debug for TypedExpression<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
TypedExpression::Boolean(ref e) => {
|
||||
write!(f, "{:?}", e)
|
||||
},
|
||||
TypedExpression::FieldElement(ref e) => {
|
||||
write!(f, "{:?}", e)
|
||||
}
|
||||
TypedExpression::FieldElementArray(ref e) => {
|
||||
write!(f, "{:?}", e)
|
||||
}
|
||||
TypedExpression::Boolean(ref e) => write!(f, "{:?}", e),
|
||||
TypedExpression::FieldElement(ref e) => write!(f, "{:?}", e),
|
||||
TypedExpression::FieldElementArray(ref e) => write!(f, "{:?}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -311,27 +300,34 @@ impl<T: Field> Typed for TypedExpression<T> {
|
|||
match *self {
|
||||
TypedExpression::Boolean(_) => Type::Boolean,
|
||||
TypedExpression::FieldElement(_) => Type::FieldElement,
|
||||
TypedExpression::FieldElementArray(FieldElementArrayExpression::Identifier(n, _)) => Type::FieldElementArray(n),
|
||||
TypedExpression::FieldElementArray(FieldElementArrayExpression::Value(n, _)) => Type::FieldElementArray(n),
|
||||
TypedExpression::FieldElementArray(FieldElementArrayExpression::FunctionCall(n, ..)) => Type::FieldElementArray(n),
|
||||
TypedExpression::FieldElementArray(FieldElementArrayExpression::Identifier(n, _)) => {
|
||||
Type::FieldElementArray(n)
|
||||
}
|
||||
TypedExpression::FieldElementArray(FieldElementArrayExpression::Value(n, _)) => {
|
||||
Type::FieldElementArray(n)
|
||||
}
|
||||
TypedExpression::FieldElementArray(FieldElementArrayExpression::FunctionCall(
|
||||
n,
|
||||
_,
|
||||
_,
|
||||
)) => Type::FieldElementArray(n),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait MultiTyped
|
||||
{
|
||||
pub trait MultiTyped {
|
||||
fn get_types(&self) -> &Vec<Type>;
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum TypedExpressionList<T: Field> {
|
||||
FunctionCall(String, Vec<TypedExpression<T>>, Vec<Type>)
|
||||
FunctionCall(String, Vec<TypedExpression<T>>, Vec<Type>),
|
||||
}
|
||||
|
||||
impl<T: Field> MultiTyped for TypedExpressionList<T> {
|
||||
fn get_types(&self) -> &Vec<Type> {
|
||||
match *self {
|
||||
TypedExpressionList::FunctionCall(_, _, ref types) => types
|
||||
TypedExpressionList::FunctionCall(_, _, ref types) => types,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -340,25 +336,62 @@ impl<T: Field> MultiTyped for TypedExpressionList<T> {
|
|||
pub enum FieldElementExpression<T: Field> {
|
||||
Number(T),
|
||||
Identifier(String),
|
||||
Add(Box<FieldElementExpression<T>>, Box<FieldElementExpression<T>>),
|
||||
Sub(Box<FieldElementExpression<T>>, Box<FieldElementExpression<T>>),
|
||||
Mult(Box<FieldElementExpression<T>>, Box<FieldElementExpression<T>>),
|
||||
Div(Box<FieldElementExpression<T>>, Box<FieldElementExpression<T>>),
|
||||
Pow(Box<FieldElementExpression<T>>, Box<FieldElementExpression<T>>),
|
||||
IfElse(Box<BooleanExpression<T>>, Box<FieldElementExpression<T>>, Box<FieldElementExpression<T>>),
|
||||
Add(
|
||||
Box<FieldElementExpression<T>>,
|
||||
Box<FieldElementExpression<T>>,
|
||||
),
|
||||
Sub(
|
||||
Box<FieldElementExpression<T>>,
|
||||
Box<FieldElementExpression<T>>,
|
||||
),
|
||||
Mult(
|
||||
Box<FieldElementExpression<T>>,
|
||||
Box<FieldElementExpression<T>>,
|
||||
),
|
||||
Div(
|
||||
Box<FieldElementExpression<T>>,
|
||||
Box<FieldElementExpression<T>>,
|
||||
),
|
||||
Pow(
|
||||
Box<FieldElementExpression<T>>,
|
||||
Box<FieldElementExpression<T>>,
|
||||
),
|
||||
IfElse(
|
||||
Box<BooleanExpression<T>>,
|
||||
Box<FieldElementExpression<T>>,
|
||||
Box<FieldElementExpression<T>>,
|
||||
),
|
||||
FunctionCall(String, Vec<TypedExpression<T>>),
|
||||
Select(Box<FieldElementArrayExpression<T>>, Box<FieldElementExpression<T>>),
|
||||
Select(
|
||||
Box<FieldElementArrayExpression<T>>,
|
||||
Box<FieldElementExpression<T>>,
|
||||
),
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize, Hash, Eq)]
|
||||
pub enum BooleanExpression<T: Field> {
|
||||
Identifier(String),
|
||||
Value(bool),
|
||||
Lt(Box<FieldElementExpression<T>>, Box<FieldElementExpression<T>>),
|
||||
Le(Box<FieldElementExpression<T>>, Box<FieldElementExpression<T>>),
|
||||
Eq(Box<FieldElementExpression<T>>, Box<FieldElementExpression<T>>),
|
||||
Ge(Box<FieldElementExpression<T>>, Box<FieldElementExpression<T>>),
|
||||
Gt(Box<FieldElementExpression<T>>, Box<FieldElementExpression<T>>),
|
||||
Lt(
|
||||
Box<FieldElementExpression<T>>,
|
||||
Box<FieldElementExpression<T>>,
|
||||
),
|
||||
Le(
|
||||
Box<FieldElementExpression<T>>,
|
||||
Box<FieldElementExpression<T>>,
|
||||
),
|
||||
Eq(
|
||||
Box<FieldElementExpression<T>>,
|
||||
Box<FieldElementExpression<T>>,
|
||||
),
|
||||
Ge(
|
||||
Box<FieldElementExpression<T>>,
|
||||
Box<FieldElementExpression<T>>,
|
||||
),
|
||||
Gt(
|
||||
Box<FieldElementExpression<T>>,
|
||||
Box<FieldElementExpression<T>>,
|
||||
),
|
||||
Or(Box<BooleanExpression<T>>, Box<BooleanExpression<T>>),
|
||||
And(Box<BooleanExpression<T>>, Box<BooleanExpression<T>>),
|
||||
Not(Box<BooleanExpression<T>>),
|
||||
|
@ -375,7 +408,9 @@ pub enum FieldElementArrayExpression<T: Field> {
|
|||
impl<T: Field> FieldElementArrayExpression<T> {
|
||||
pub fn size(&self) -> usize {
|
||||
match *self {
|
||||
FieldElementArrayExpression::Identifier(s, _) | FieldElementArrayExpression::Value(s, _) | FieldElementArrayExpression::FunctionCall(s, ..) => s
|
||||
FieldElementArrayExpression::Identifier(s, _)
|
||||
| FieldElementArrayExpression::Value(s, _)
|
||||
| FieldElementArrayExpression::FunctionCall(s, ..) => s,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -390,13 +425,13 @@ impl<T: Field> fmt::Display for FieldElementExpression<T> {
|
|||
FieldElementExpression::Mult(ref lhs, ref rhs) => write!(f, "({} * {})", lhs, rhs),
|
||||
FieldElementExpression::Div(ref lhs, ref rhs) => write!(f, "({} / {})", lhs, rhs),
|
||||
FieldElementExpression::Pow(ref lhs, ref rhs) => write!(f, "{}**{}", lhs, rhs),
|
||||
FieldElementExpression::IfElse(ref condition, ref consequent, ref alternative) => write!(
|
||||
f,
|
||||
"if {} then {} else {} fi",
|
||||
condition,
|
||||
consequent,
|
||||
alternative
|
||||
),
|
||||
FieldElementExpression::IfElse(ref condition, ref consequent, ref alternative) => {
|
||||
write!(
|
||||
f,
|
||||
"if {} then {} else {} fi",
|
||||
condition, consequent, alternative
|
||||
)
|
||||
}
|
||||
FieldElementExpression::FunctionCall(ref i, ref p) => {
|
||||
try!(write!(f, "{}(", i,));
|
||||
for (i, param) in p.iter().enumerate() {
|
||||
|
@ -406,10 +441,8 @@ impl<T: Field> fmt::Display for FieldElementExpression<T> {
|
|||
}
|
||||
}
|
||||
write!(f, ")")
|
||||
},
|
||||
FieldElementExpression::Select(ref id, ref index) => {
|
||||
write!(f, "{}[{}]", id, index)
|
||||
},
|
||||
}
|
||||
FieldElementExpression::Select(ref id, ref index) => write!(f, "{}[{}]", id, index),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -435,7 +468,15 @@ impl<T: Field> fmt::Display for FieldElementArrayExpression<T> {
|
|||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
FieldElementArrayExpression::Identifier(_, ref var) => write!(f, "{}", var),
|
||||
FieldElementArrayExpression::Value(_, ref values) => write!(f, "[{}]", values.iter().map(|o| o.to_string()).collect::<Vec<String>>().join(", ")),
|
||||
FieldElementArrayExpression::Value(_, ref values) => write!(
|
||||
f,
|
||||
"[{}]",
|
||||
values
|
||||
.iter()
|
||||
.map(|o| o.to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join(", ")
|
||||
),
|
||||
FieldElementArrayExpression::FunctionCall(_, ref i, ref p) => {
|
||||
try!(write!(f, "{}(", i,));
|
||||
for (i, param) in p.iter().enumerate() {
|
||||
|
@ -445,7 +486,7 @@ impl<T: Field> fmt::Display for FieldElementArrayExpression<T> {
|
|||
}
|
||||
}
|
||||
write!(f, ")")
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -463,24 +504,26 @@ impl<T: Field> fmt::Debug for FieldElementExpression<T> {
|
|||
FieldElementExpression::Identifier(ref var) => write!(f, "Ide({})", var),
|
||||
FieldElementExpression::Add(ref lhs, ref rhs) => write!(f, "Add({:?}, {:?})", lhs, rhs),
|
||||
FieldElementExpression::Sub(ref lhs, ref rhs) => write!(f, "Sub({:?}, {:?})", lhs, rhs),
|
||||
FieldElementExpression::Mult(ref lhs, ref rhs) => write!(f, "Mult({:?}, {:?})", lhs, rhs),
|
||||
FieldElementExpression::Mult(ref lhs, ref rhs) => {
|
||||
write!(f, "Mult({:?}, {:?})", lhs, rhs)
|
||||
}
|
||||
FieldElementExpression::Div(ref lhs, ref rhs) => write!(f, "Div({:?}, {:?})", lhs, rhs),
|
||||
FieldElementExpression::Pow(ref lhs, ref rhs) => write!(f, "Pow({:?}, {:?})", lhs, rhs),
|
||||
FieldElementExpression::IfElse(ref condition, ref consequent, ref alternative) => write!(
|
||||
f,
|
||||
"IfElse({:?}, {:?}, {:?})",
|
||||
condition,
|
||||
consequent,
|
||||
alternative
|
||||
),
|
||||
FieldElementExpression::IfElse(ref condition, ref consequent, ref alternative) => {
|
||||
write!(
|
||||
f,
|
||||
"IfElse({:?}, {:?}, {:?})",
|
||||
condition, consequent, alternative
|
||||
)
|
||||
}
|
||||
FieldElementExpression::FunctionCall(ref i, ref p) => {
|
||||
try!(write!(f, "FunctionCall({:?}, (", i));
|
||||
try!(f.debug_list().entries(p.iter()).finish());
|
||||
write!(f, ")")
|
||||
},
|
||||
}
|
||||
FieldElementExpression::Select(ref id, ref index) => {
|
||||
write!(f, "Select({:?}, {:?})", id, index)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,33 +2,29 @@ use field::Field;
|
|||
|
||||
#[derive(PartialEq, PartialOrd, Clone, Eq, Ord, Debug)]
|
||||
pub struct Constraints<T: Field> {
|
||||
pub constraints: Vec<Constraint<T>>
|
||||
pub constraints: Vec<Constraint<T>>,
|
||||
}
|
||||
|
||||
impl<T: Field> Constraints<T> {
|
||||
pub fn none() -> Constraints<T> {
|
||||
Constraints {
|
||||
constraints: vec![]
|
||||
}
|
||||
}
|
||||
pub fn boolean() -> Constraints<T> {
|
||||
Constraints {
|
||||
constraints: vec![
|
||||
Constraint {
|
||||
a: box [T::from(1)],
|
||||
b: box [T::from(1)],
|
||||
c: box [T::from(1)],
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
pub fn none() -> Constraints<T> {
|
||||
Constraints {
|
||||
constraints: vec![],
|
||||
}
|
||||
}
|
||||
pub fn boolean() -> Constraints<T> {
|
||||
Constraints {
|
||||
constraints: vec![Constraint {
|
||||
a: box [T::from(1)],
|
||||
b: box [T::from(1)],
|
||||
c: box [T::from(1)],
|
||||
}],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, PartialOrd, Clone, Eq, Ord, Debug)]
|
||||
pub struct Constraint<T: Field> {
|
||||
pub a: Box<[T]>,
|
||||
pub b: Box<[T]>,
|
||||
pub c: Box<[T]>,
|
||||
pub a: Box<[T]>,
|
||||
pub b: Box<[T]>,
|
||||
pub c: Box<[T]>,
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,33 +1,39 @@
|
|||
use types::signature::Signature;
|
||||
use flat_absy::*;
|
||||
use flat_absy::flat_variable::FlatVariable;
|
||||
use bimap::BiMap;
|
||||
use field::Field;
|
||||
use types::Type;
|
||||
use flat_absy::flat_parameter::FlatParameter;
|
||||
use helpers::{Helper, RustHelper, DirectiveStatement};
|
||||
use flat_absy::flat_variable::FlatVariable;
|
||||
use flat_absy::*;
|
||||
use helpers::{DirectiveStatement, Helper, RustHelper};
|
||||
use reduce::Reduce;
|
||||
use types::constraints::Constraint;
|
||||
use bimap::BiMap;
|
||||
use types::signature::Signature;
|
||||
use types::Type;
|
||||
|
||||
fn use_variable(bijection: &mut BiMap<String, FlatVariable>, name: String, index: &mut usize) -> FlatVariable {
|
||||
let var = FlatVariable::new(*index);
|
||||
bijection.insert(name, var);
|
||||
*index = *index + 1;
|
||||
var
|
||||
fn use_variable(
|
||||
bijection: &mut BiMap<String, FlatVariable>,
|
||||
name: String,
|
||||
index: &mut usize,
|
||||
) -> FlatVariable {
|
||||
let var = FlatVariable::new(*index);
|
||||
bijection.insert(name, var);
|
||||
*index = *index + 1;
|
||||
var
|
||||
}
|
||||
|
||||
pub fn pack<T: Field>(nbits: usize) -> FlatProg<T> {
|
||||
assert!(nbits <= T::get_required_bits()); // we cannot pack more bits than the field
|
||||
assert!(nbits <= T::get_required_bits()); // we cannot pack more bits than the field
|
||||
|
||||
let arguments = (0..nbits).map(|i| FlatParameter {
|
||||
id: FlatVariable::new(i),
|
||||
private: true
|
||||
}).collect();
|
||||
let arguments = (0..nbits)
|
||||
.map(|i| FlatParameter {
|
||||
id: FlatVariable::new(i),
|
||||
private: true,
|
||||
})
|
||||
.collect();
|
||||
|
||||
let signature = Signature {
|
||||
inputs: vec![Type::FieldElement; nbits],
|
||||
outputs: vec![Type::FieldElement],
|
||||
};
|
||||
let signature = Signature {
|
||||
inputs: vec![Type::FieldElement; nbits],
|
||||
outputs: vec![Type::FieldElement],
|
||||
};
|
||||
|
||||
// sum check
|
||||
let mut ret = FlatExpression::Number(T::from(0));
|
||||
|
@ -42,62 +48,67 @@ pub fn pack<T: Field>(nbits: usize) -> FlatProg<T> {
|
|||
);
|
||||
}
|
||||
|
||||
let statements = vec![FlatStatement::Return(
|
||||
FlatExpressionList {
|
||||
expressions: vec![ret]
|
||||
}
|
||||
)];
|
||||
|
||||
FlatProg {
|
||||
functions: vec![
|
||||
FlatFunction {
|
||||
id: String::from("main"),
|
||||
arguments,
|
||||
statements,
|
||||
signature
|
||||
}
|
||||
]
|
||||
}
|
||||
let statements = vec![FlatStatement::Return(FlatExpressionList {
|
||||
expressions: vec![ret],
|
||||
})];
|
||||
|
||||
FlatProg {
|
||||
functions: vec![FlatFunction {
|
||||
id: String::from("main"),
|
||||
arguments,
|
||||
statements,
|
||||
signature,
|
||||
}],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unpack<T: Field>(nbits: usize) -> FlatProg<T> {
|
||||
assert!(nbits <= T::get_required_bits()); // we cannot pack more bits than the field
|
||||
assert!(nbits <= T::get_required_bits()); // we cannot pack more bits than the field
|
||||
|
||||
let mut counter = 0;
|
||||
let mut counter = 0;
|
||||
|
||||
let mut bijection = BiMap::new();
|
||||
let mut bijection = BiMap::new();
|
||||
|
||||
let arguments = vec![FlatParameter {
|
||||
id: FlatVariable::new(0),
|
||||
private: true
|
||||
}];
|
||||
let arguments = vec![FlatParameter {
|
||||
id: FlatVariable::new(0),
|
||||
private: true,
|
||||
}];
|
||||
|
||||
// o0, ..., o253 = ToBits(i0)
|
||||
// o0, ..., o253 = ToBits(i0)
|
||||
|
||||
let directive_inputs = vec![FlatExpression::Identifier(use_variable(&mut bijection, format!("i0"), &mut counter))];
|
||||
let directive_outputs: Vec<FlatVariable> = (0..T::get_required_bits()).map(|index| use_variable(&mut bijection, format!("o{}", index), &mut counter)).collect();
|
||||
let directive_inputs = vec![FlatExpression::Identifier(use_variable(
|
||||
&mut bijection,
|
||||
format!("i0"),
|
||||
&mut counter,
|
||||
))];
|
||||
let directive_outputs: Vec<FlatVariable> = (0..T::get_required_bits())
|
||||
.map(|index| use_variable(&mut bijection, format!("o{}", index), &mut counter))
|
||||
.collect();
|
||||
|
||||
let helper = Helper::Rust(RustHelper::Bits);
|
||||
let helper = Helper::Rust(RustHelper::Bits);
|
||||
|
||||
let signature = Signature {
|
||||
inputs: vec![Type::FieldElement],
|
||||
outputs: vec![Type::FieldElement; nbits],
|
||||
};
|
||||
let signature = Signature {
|
||||
inputs: vec![Type::FieldElement],
|
||||
outputs: vec![Type::FieldElement; nbits],
|
||||
};
|
||||
|
||||
let outputs = directive_outputs.iter().enumerate().filter(|(index, _)| *index >= T::get_required_bits() - nbits).map(|(_, o)| FlatExpression::Identifier(o.clone())).collect();
|
||||
let outputs = directive_outputs
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(index, _)| *index >= T::get_required_bits() - nbits)
|
||||
.map(|(_, o)| FlatExpression::Identifier(o.clone()))
|
||||
.collect();
|
||||
|
||||
// o253, o252, ... o{253 - (nbits - 1)} are bits
|
||||
let mut statements: Vec<FlatStatement<T>> = (0..nbits)
|
||||
.map(|index| {
|
||||
let bit = FlatExpression::Identifier(FlatVariable::new(T::get_required_bits() - index));
|
||||
FlatStatement::Condition(
|
||||
bit.clone(),
|
||||
FlatExpression::Mult(
|
||||
box bit.clone(),
|
||||
box bit.clone()
|
||||
)
|
||||
)
|
||||
}).collect();
|
||||
// o253, o252, ... o{253 - (nbits - 1)} are bits
|
||||
let mut statements: Vec<FlatStatement<T>> = (0..nbits)
|
||||
.map(|index| {
|
||||
let bit = FlatExpression::Identifier(FlatVariable::new(T::get_required_bits() - index));
|
||||
FlatStatement::Condition(
|
||||
bit.clone(),
|
||||
FlatExpression::Mult(box bit.clone(), box bit.clone()),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
// sum check: o253 + o252 * 2 + ... + o{253 - (nbits - 1)} * 2**(nbits - 1)
|
||||
let mut lhs_sum = FlatExpression::Number(T::from(0));
|
||||
|
@ -112,241 +123,282 @@ pub fn unpack<T: Field>(nbits: usize) -> FlatProg<T> {
|
|||
);
|
||||
}
|
||||
|
||||
statements.push(
|
||||
FlatStatement::Condition(
|
||||
lhs_sum,
|
||||
FlatExpression::Mult(
|
||||
box FlatExpression::Identifier(FlatVariable::new(0)),
|
||||
box FlatExpression::Number(T::from(1))
|
||||
)
|
||||
)
|
||||
);
|
||||
statements.push(FlatStatement::Condition(
|
||||
lhs_sum,
|
||||
FlatExpression::Mult(
|
||||
box FlatExpression::Identifier(FlatVariable::new(0)),
|
||||
box FlatExpression::Number(T::from(1)),
|
||||
),
|
||||
));
|
||||
|
||||
statements.insert(0, FlatStatement::Directive(
|
||||
DirectiveStatement {
|
||||
inputs: directive_inputs,
|
||||
outputs: directive_outputs,
|
||||
helper: helper
|
||||
}
|
||||
));
|
||||
statements.insert(
|
||||
0,
|
||||
FlatStatement::Directive(DirectiveStatement {
|
||||
inputs: directive_inputs,
|
||||
outputs: directive_outputs,
|
||||
helper: helper,
|
||||
}),
|
||||
);
|
||||
|
||||
statements.push(FlatStatement::Return(
|
||||
FlatExpressionList {
|
||||
expressions: outputs
|
||||
}
|
||||
));
|
||||
|
||||
FlatProg {
|
||||
functions: vec![
|
||||
FlatFunction {
|
||||
id: String::from("main"),
|
||||
arguments,
|
||||
statements,
|
||||
signature
|
||||
}
|
||||
]
|
||||
}
|
||||
statements.push(FlatStatement::Return(FlatExpressionList {
|
||||
expressions: outputs,
|
||||
}));
|
||||
|
||||
FlatProg {
|
||||
functions: vec![FlatFunction {
|
||||
id: String::from("main"),
|
||||
arguments,
|
||||
statements,
|
||||
signature,
|
||||
}],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cast<T: Field>(from: &Type, to: &Type) -> FlatFunction<T> {
|
||||
let mut counter = 0;
|
||||
|
||||
let mut counter = 0;
|
||||
let mut bijection = BiMap::new();
|
||||
|
||||
let mut bijection = BiMap::new();
|
||||
let arguments = (0..from.get_primitive_count())
|
||||
.enumerate()
|
||||
.map(|(index, _)| FlatParameter {
|
||||
id: FlatVariable::new(index),
|
||||
private: true,
|
||||
})
|
||||
.collect();
|
||||
|
||||
let arguments = (0..from.get_primitive_count()).enumerate().map(|(index, _)| FlatParameter {
|
||||
id: FlatVariable::new(index),
|
||||
private: true
|
||||
}).collect();
|
||||
let directive_inputs = (0..from.get_primitive_count())
|
||||
.map(|index| use_variable(&mut bijection, format!("i{}", index), &mut counter))
|
||||
.collect();
|
||||
let directive_outputs: Vec<FlatVariable> = (0..to.get_primitive_count())
|
||||
.map(|index| use_variable(&mut bijection, format!("o{}", index), &mut counter))
|
||||
.collect();
|
||||
|
||||
let directive_inputs = (0..from.get_primitive_count()).map(|index| use_variable(&mut bijection, format!("i{}", index), &mut counter)).collect();
|
||||
let directive_outputs: Vec<FlatVariable> = (0..to.get_primitive_count()).map(|index| use_variable(&mut bijection, format!("o{}", index), &mut counter)).collect();
|
||||
let constraints = to.get_constraints::<T>().constraints;
|
||||
|
||||
let constraints = to.get_constraints::<T>().constraints;
|
||||
let intermediate_variables = match constraints.len() {
|
||||
0 => vec![],
|
||||
_ => constraints[0]
|
||||
.a
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(_, index)| use_variable(&mut bijection, format!("inter{}", index), &mut counter))
|
||||
.collect(),
|
||||
};
|
||||
|
||||
let intermediate_variables = match constraints.len() {
|
||||
0 => vec![],
|
||||
_ => constraints[0].a.iter().enumerate().map(|(_, index)| use_variable(&mut bijection, format!("inter{}", index), &mut counter)).collect()
|
||||
};
|
||||
let conditions: Vec<FlatStatement<T>> = to
|
||||
.get_constraints()
|
||||
.constraints
|
||||
.iter()
|
||||
.map(|constraint: &Constraint<T>| {
|
||||
let rhs_a = match constraint
|
||||
.a
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(key, val)| {
|
||||
FlatExpression::Mult(
|
||||
box FlatExpression::Number(val.clone()),
|
||||
box FlatExpression::Identifier(intermediate_variables[key]),
|
||||
)
|
||||
})
|
||||
.reduce(|acc, e| FlatExpression::Add(box acc, box e))
|
||||
{
|
||||
Some(e @ FlatExpression::Mult(..)) => {
|
||||
FlatExpression::Add(box FlatExpression::Number(T::zero()), box e)
|
||||
} // the R1CS serializer only recognizes Add
|
||||
Some(e) => e,
|
||||
None => FlatExpression::Number(T::zero()),
|
||||
};
|
||||
|
||||
let conditions: Vec<FlatStatement<T>> = to.get_constraints().constraints.iter().map(|constraint: &Constraint<T>| {
|
||||
let rhs_a = match constraint.a.iter()
|
||||
.enumerate()
|
||||
.map(|(key, val)| FlatExpression::Mult(box FlatExpression::Number(val.clone()), box FlatExpression::Identifier(intermediate_variables[key])))
|
||||
.reduce(|acc, e| FlatExpression::Add(box acc, box e)) {
|
||||
Some(e @ FlatExpression::Mult(..)) => FlatExpression::Add(box FlatExpression::Number(T::zero()), box e), // the R1CS serializer only recognizes Add
|
||||
Some(e) => e,
|
||||
None => FlatExpression::Number(T::zero())
|
||||
};
|
||||
|
||||
let rhs_b = match constraint.b.iter()
|
||||
.enumerate()
|
||||
.map(|(key, val)| FlatExpression::Mult(box FlatExpression::Number(val.clone()), box FlatExpression::Identifier(intermediate_variables[key])))
|
||||
.reduce(|acc, e| FlatExpression::Add(box acc, box e)) {
|
||||
Some(e @ FlatExpression::Mult(..)) => FlatExpression::Add(box FlatExpression::Number(T::zero()), box e), // the R1CS serializer only recognizes Add
|
||||
Some(e) => e,
|
||||
None => FlatExpression::Number(T::zero())
|
||||
};
|
||||
|
||||
let lhs = match constraint.c.iter()
|
||||
.enumerate()
|
||||
.map(|(key, val)| FlatExpression::Mult(box FlatExpression::Number(val.clone()), box FlatExpression::Identifier(intermediate_variables[key])))
|
||||
.reduce(|acc, e| FlatExpression::Add(box acc, box e)) {
|
||||
Some(e @ FlatExpression::Mult(..)) => FlatExpression::Add(box FlatExpression::Number(T::zero()), box e), // the R1CS serializer only recognizes Add
|
||||
Some(e) => e,
|
||||
None => FlatExpression::Number(T::zero())
|
||||
};
|
||||
let rhs_b = match constraint
|
||||
.b
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(key, val)| {
|
||||
FlatExpression::Mult(
|
||||
box FlatExpression::Number(val.clone()),
|
||||
box FlatExpression::Identifier(intermediate_variables[key]),
|
||||
)
|
||||
})
|
||||
.reduce(|acc, e| FlatExpression::Add(box acc, box e))
|
||||
{
|
||||
Some(e @ FlatExpression::Mult(..)) => {
|
||||
FlatExpression::Add(box FlatExpression::Number(T::zero()), box e)
|
||||
} // the R1CS serializer only recognizes Add
|
||||
Some(e) => e,
|
||||
None => FlatExpression::Number(T::zero()),
|
||||
};
|
||||
|
||||
FlatStatement::Condition(lhs, FlatExpression::Mult(box rhs_a, box rhs_b))
|
||||
}).collect();
|
||||
let lhs = match constraint
|
||||
.c
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(key, val)| {
|
||||
FlatExpression::Mult(
|
||||
box FlatExpression::Number(val.clone()),
|
||||
box FlatExpression::Identifier(intermediate_variables[key]),
|
||||
)
|
||||
})
|
||||
.reduce(|acc, e| FlatExpression::Add(box acc, box e))
|
||||
{
|
||||
Some(e @ FlatExpression::Mult(..)) => {
|
||||
FlatExpression::Add(box FlatExpression::Number(T::zero()), box e)
|
||||
} // the R1CS serializer only recognizes Add
|
||||
Some(e) => e,
|
||||
None => FlatExpression::Number(T::zero()),
|
||||
};
|
||||
|
||||
let helper = match (from, to) {
|
||||
(Type::Boolean, Type::FieldElement) => {
|
||||
Helper::Rust(RustHelper::Identity)
|
||||
},
|
||||
(Type::FieldElement, Type::Boolean) => {
|
||||
Helper::Rust(RustHelper::Identity)
|
||||
}
|
||||
_ => panic!(format!("can't cast {} to {}", from, to))
|
||||
};
|
||||
FlatStatement::Condition(lhs, FlatExpression::Mult(box rhs_a, box rhs_b))
|
||||
})
|
||||
.collect();
|
||||
|
||||
let signature = Signature {
|
||||
inputs: vec![from.clone()],
|
||||
outputs: vec![to.clone()],
|
||||
};
|
||||
let helper = match (from, to) {
|
||||
(Type::Boolean, Type::FieldElement) => Helper::Rust(RustHelper::Identity),
|
||||
(Type::FieldElement, Type::Boolean) => Helper::Rust(RustHelper::Identity),
|
||||
_ => panic!(format!("can't cast {} to {}", from, to)),
|
||||
};
|
||||
|
||||
let outputs = directive_outputs.iter().map(|o| FlatExpression::Identifier(o.clone())).collect();
|
||||
let signature = Signature {
|
||||
inputs: vec![from.clone()],
|
||||
outputs: vec![to.clone()],
|
||||
};
|
||||
|
||||
let mut statements = conditions;
|
||||
let outputs = directive_outputs
|
||||
.iter()
|
||||
.map(|o| FlatExpression::Identifier(o.clone()))
|
||||
.collect();
|
||||
|
||||
statements.insert(0, FlatStatement::Directive(
|
||||
DirectiveStatement::new(
|
||||
directive_outputs,
|
||||
helper,
|
||||
directive_inputs,
|
||||
)
|
||||
));
|
||||
let mut statements = conditions;
|
||||
|
||||
statements.push(FlatStatement::Return(
|
||||
FlatExpressionList {
|
||||
expressions: outputs
|
||||
}
|
||||
));
|
||||
|
||||
FlatFunction {
|
||||
id: format!("_{}_to_{}", from, to),
|
||||
arguments,
|
||||
statements,
|
||||
signature
|
||||
}
|
||||
statements.insert(
|
||||
0,
|
||||
FlatStatement::Directive(DirectiveStatement::new(
|
||||
directive_outputs,
|
||||
helper,
|
||||
directive_inputs,
|
||||
)),
|
||||
);
|
||||
|
||||
statements.push(FlatStatement::Return(FlatExpressionList {
|
||||
expressions: outputs,
|
||||
}));
|
||||
|
||||
FlatFunction {
|
||||
id: format!("_{}_to_{}", from, to),
|
||||
arguments,
|
||||
statements,
|
||||
signature,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use field::FieldPrime;
|
||||
use super::*;
|
||||
use super::*;
|
||||
use field::FieldPrime;
|
||||
|
||||
#[cfg(test)]
|
||||
mod cast {
|
||||
use super::*;
|
||||
#[cfg(test)]
|
||||
mod cast {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn field_to_bool() {
|
||||
let f2b: FlatFunction<FieldPrime> = cast(&Type::FieldElement, &Type::Boolean);
|
||||
assert_eq!(f2b.id, String::from("_field_to_bool"));
|
||||
assert_eq!(f2b.arguments, vec![FlatParameter::private(FlatVariable::new(0))]);
|
||||
assert_eq!(f2b.statements.len(), 3); // 1 directive, 1 constraint, 1 return
|
||||
assert_eq!(
|
||||
f2b.statements[0],
|
||||
FlatStatement::Directive(
|
||||
DirectiveStatement::new(
|
||||
vec![FlatVariable::new(1)],
|
||||
Helper::Rust(RustHelper::Identity),
|
||||
vec![FlatVariable::new(0)]
|
||||
)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
f2b.statements[2],
|
||||
FlatStatement::Return(
|
||||
FlatExpressionList {
|
||||
expressions: vec![FlatExpression::Identifier(FlatVariable::new(1))]
|
||||
}
|
||||
)
|
||||
);
|
||||
assert_eq!(f2b.signature.outputs.len(), 1);
|
||||
}
|
||||
#[test]
|
||||
fn field_to_bool() {
|
||||
let f2b: FlatFunction<FieldPrime> = cast(&Type::FieldElement, &Type::Boolean);
|
||||
assert_eq!(f2b.id, String::from("_field_to_bool"));
|
||||
assert_eq!(
|
||||
f2b.arguments,
|
||||
vec![FlatParameter::private(FlatVariable::new(0))]
|
||||
);
|
||||
assert_eq!(f2b.statements.len(), 3); // 1 directive, 1 constraint, 1 return
|
||||
assert_eq!(
|
||||
f2b.statements[0],
|
||||
FlatStatement::Directive(DirectiveStatement::new(
|
||||
vec![FlatVariable::new(1)],
|
||||
Helper::Rust(RustHelper::Identity),
|
||||
vec![FlatVariable::new(0)]
|
||||
))
|
||||
);
|
||||
assert_eq!(
|
||||
f2b.statements[2],
|
||||
FlatStatement::Return(FlatExpressionList {
|
||||
expressions: vec![FlatExpression::Identifier(FlatVariable::new(1))]
|
||||
})
|
||||
);
|
||||
assert_eq!(f2b.signature.outputs.len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bool_to_field() {
|
||||
let b2f: FlatFunction<FieldPrime> = cast(&Type::Boolean, &Type::FieldElement);
|
||||
assert_eq!(b2f.id, String::from("_bool_to_field"));
|
||||
assert_eq!(b2f.arguments, vec![FlatParameter::private(FlatVariable::new(0))]);
|
||||
assert_eq!(b2f.statements.len(), 2); // 1 directive, 1 return
|
||||
assert_eq!(
|
||||
b2f.statements[0],
|
||||
FlatStatement::Directive(
|
||||
DirectiveStatement::new(
|
||||
vec![FlatVariable::new(1)],
|
||||
Helper::Rust(RustHelper::Identity),
|
||||
vec![FlatVariable::new(0)]
|
||||
)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
b2f.statements[1],
|
||||
FlatStatement::Return(
|
||||
FlatExpressionList {
|
||||
expressions: vec![FlatExpression::Identifier(FlatVariable::new(1))]
|
||||
}
|
||||
)
|
||||
);
|
||||
assert_eq!(b2f.signature.outputs.len(), 1);
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn bool_to_field() {
|
||||
let b2f: FlatFunction<FieldPrime> = cast(&Type::Boolean, &Type::FieldElement);
|
||||
assert_eq!(b2f.id, String::from("_bool_to_field"));
|
||||
assert_eq!(
|
||||
b2f.arguments,
|
||||
vec![FlatParameter::private(FlatVariable::new(0))]
|
||||
);
|
||||
assert_eq!(b2f.statements.len(), 2); // 1 directive, 1 return
|
||||
assert_eq!(
|
||||
b2f.statements[0],
|
||||
FlatStatement::Directive(DirectiveStatement::new(
|
||||
vec![FlatVariable::new(1)],
|
||||
Helper::Rust(RustHelper::Identity),
|
||||
vec![FlatVariable::new(0)]
|
||||
))
|
||||
);
|
||||
assert_eq!(
|
||||
b2f.statements[1],
|
||||
FlatStatement::Return(FlatExpressionList {
|
||||
expressions: vec![FlatExpression::Identifier(FlatVariable::new(1))]
|
||||
})
|
||||
);
|
||||
assert_eq!(b2f.signature.outputs.len(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod unpack {
|
||||
use super::*;
|
||||
#[cfg(test)]
|
||||
mod unpack {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn unpack128() {
|
||||
let nbits = 128;
|
||||
#[test]
|
||||
fn unpack128() {
|
||||
let nbits = 128;
|
||||
|
||||
let unpack: FlatProg<FieldPrime> = unpack(nbits);
|
||||
let unpack = &unpack.functions[0];
|
||||
let unpack: FlatProg<FieldPrime> = unpack(nbits);
|
||||
let unpack = &unpack.functions[0];
|
||||
|
||||
assert_eq!(unpack.id, String::from("main"));
|
||||
assert_eq!(unpack.arguments, vec![FlatParameter::private(FlatVariable::new(0))]);
|
||||
assert_eq!(unpack.statements.len(), nbits + 1 + 1 + 1); // 128 bit checks, 1 directive, 1 sum check, 1 return
|
||||
assert_eq!(
|
||||
unpack.statements[0],
|
||||
FlatStatement::Directive(
|
||||
DirectiveStatement::new(
|
||||
(0..FieldPrime::get_required_bits()).map(|i| FlatVariable::new(i + 1)).collect(),
|
||||
Helper::Rust(RustHelper::Bits),
|
||||
vec![FlatVariable::new(0)]
|
||||
)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
*unpack.statements.last().unwrap(),
|
||||
FlatStatement::Return(
|
||||
FlatExpressionList {
|
||||
expressions: (FieldPrime::get_required_bits() - nbits..FieldPrime::get_required_bits()).map(|i| FlatExpression::Identifier(FlatVariable::new(i + 1))).collect()
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
assert_eq!(unpack.id, String::from("main"));
|
||||
assert_eq!(
|
||||
unpack.arguments,
|
||||
vec![FlatParameter::private(FlatVariable::new(0))]
|
||||
);
|
||||
assert_eq!(unpack.statements.len(), nbits + 1 + 1 + 1); // 128 bit checks, 1 directive, 1 sum check, 1 return
|
||||
assert_eq!(
|
||||
unpack.statements[0],
|
||||
FlatStatement::Directive(DirectiveStatement::new(
|
||||
(0..FieldPrime::get_required_bits())
|
||||
.map(|i| FlatVariable::new(i + 1))
|
||||
.collect(),
|
||||
Helper::Rust(RustHelper::Bits),
|
||||
vec![FlatVariable::new(0)]
|
||||
))
|
||||
);
|
||||
assert_eq!(
|
||||
*unpack.statements.last().unwrap(),
|
||||
FlatStatement::Return(FlatExpressionList {
|
||||
expressions: (FieldPrime::get_required_bits() - nbits
|
||||
..FieldPrime::get_required_bits())
|
||||
.map(|i| FlatExpression::Identifier(FlatVariable::new(i + 1)))
|
||||
.collect()
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pack128() {
|
||||
let pack: FlatProg<FieldPrime> = pack(128);
|
||||
let pack = &pack.functions[0];
|
||||
#[test]
|
||||
fn pack128() {
|
||||
let pack: FlatProg<FieldPrime> = pack(128);
|
||||
let pack = &pack.functions[0];
|
||||
|
||||
assert_eq!(pack.id, String::from("main"));
|
||||
assert_eq!(pack.arguments.len(), 128);
|
||||
assert_eq!(pack.statements.len(), 1); // just sum bits * 2**i
|
||||
}
|
||||
}
|
||||
}
|
||||
assert_eq!(pack.id, String::from("main"));
|
||||
assert_eq!(pack.arguments.len(), 128);
|
||||
assert_eq!(pack.statements.len(), 1); // just sum bits * 2**i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,84 +1,84 @@
|
|||
use field::Field;
|
||||
use types::constraints::Constraints;
|
||||
use std::fmt;
|
||||
use types::constraints::Constraints;
|
||||
pub use types::signature::Signature;
|
||||
|
||||
mod signature;
|
||||
pub mod conversions;
|
||||
mod constraints;
|
||||
pub mod conversions;
|
||||
mod signature;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum Type {
|
||||
FieldElement,
|
||||
Boolean,
|
||||
FieldElementArray(usize),
|
||||
FieldElement,
|
||||
Boolean,
|
||||
FieldElementArray(usize),
|
||||
}
|
||||
|
||||
impl fmt::Display for Type {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Type::FieldElement => write!(f, "field"),
|
||||
Type::Boolean => write!(f, "bool"),
|
||||
Type::FieldElementArray(size) => write!(f, "{}[{}]", Type::FieldElement, size)
|
||||
}
|
||||
match *self {
|
||||
Type::FieldElement => write!(f, "field"),
|
||||
Type::Boolean => write!(f, "bool"),
|
||||
Type::FieldElementArray(size) => write!(f, "{}[{}]", Type::FieldElement, size),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Type {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Type::FieldElement => write!(f, "field"),
|
||||
Type::Boolean => write!(f, "bool"),
|
||||
Type::FieldElementArray(size) => write!(f, "{}[{}]", Type::FieldElement, size),
|
||||
}
|
||||
match *self {
|
||||
Type::FieldElement => write!(f, "field"),
|
||||
Type::Boolean => write!(f, "bool"),
|
||||
Type::FieldElementArray(size) => write!(f, "{}[{}]", Type::FieldElement, size),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Type {
|
||||
fn get_constraints<T: Field>(&self) -> Constraints<T> {
|
||||
match self {
|
||||
Type::FieldElement => Constraints::none(),
|
||||
Type::Boolean => Constraints::boolean(),
|
||||
Type::FieldElementArray(_) => Type::FieldElement.get_constraints(),
|
||||
}
|
||||
}
|
||||
fn get_constraints<T: Field>(&self) -> Constraints<T> {
|
||||
match self {
|
||||
Type::FieldElement => Constraints::none(),
|
||||
Type::Boolean => Constraints::boolean(),
|
||||
Type::FieldElementArray(_) => Type::FieldElement.get_constraints(),
|
||||
}
|
||||
}
|
||||
|
||||
// the number of field elements the type maps to
|
||||
pub fn get_primitive_count(&self) -> usize {
|
||||
match self {
|
||||
Type::FieldElement => 1,
|
||||
Type::Boolean => 1,
|
||||
Type::FieldElementArray(size) => size * Type::FieldElement.get_primitive_count(),
|
||||
}
|
||||
}
|
||||
// the number of field elements the type maps to
|
||||
pub fn get_primitive_count(&self) -> usize {
|
||||
match self {
|
||||
Type::FieldElement => 1,
|
||||
Type::Boolean => 1,
|
||||
Type::FieldElementArray(size) => size * Type::FieldElement.get_primitive_count(),
|
||||
}
|
||||
}
|
||||
|
||||
fn to_slug(&self) -> String {
|
||||
match *self {
|
||||
Type::FieldElement => String::from("f"),
|
||||
Type::Boolean => String::from("b"),
|
||||
Type::FieldElementArray(size) => format!("{}[{}]", Type::FieldElement.to_slug(), size), // TODO differentiate types?
|
||||
}
|
||||
}
|
||||
fn to_slug(&self) -> String {
|
||||
match *self {
|
||||
Type::FieldElement => String::from("f"),
|
||||
Type::Boolean => String::from("b"),
|
||||
Type::FieldElementArray(size) => format!("{}[{}]", Type::FieldElement.to_slug(), size), // TODO differentiate types?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use field::FieldPrime;
|
||||
use super::*;
|
||||
use super::*;
|
||||
use field::FieldPrime;
|
||||
|
||||
#[test]
|
||||
fn array() {
|
||||
let t = Type::FieldElementArray(42);
|
||||
assert_eq!(t.get_primitive_count(), 42);
|
||||
assert_eq!(t.get_constraints::<FieldPrime>(), Constraints::none());
|
||||
assert_eq!(t.to_slug(), "f[42]");
|
||||
}
|
||||
#[test]
|
||||
fn array() {
|
||||
let t = Type::FieldElementArray(42);
|
||||
assert_eq!(t.get_primitive_count(), 42);
|
||||
assert_eq!(t.get_constraints::<FieldPrime>(), Constraints::none());
|
||||
assert_eq!(t.to_slug(), "f[42]");
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn array_of_arrays() {
|
||||
// let t = Type::FieldElementArray(42, box Type::FieldElementArray(33, box Type::Boolean));
|
||||
// assert_eq!(t.get_primitive_count(), 1);
|
||||
// assert_eq!(t.get_constraints::<FieldPrime>(), Constraints::boolean());
|
||||
// assert_eq!(t.to_slug(), "[]");
|
||||
// }
|
||||
}
|
||||
// #[test]
|
||||
// fn array_of_arrays() {
|
||||
// let t = Type::FieldElementArray(42, box Type::FieldElementArray(33, box Type::Boolean));
|
||||
// assert_eq!(t.get_primitive_count(), 1);
|
||||
// assert_eq!(t.get_constraints::<FieldPrime>(), Constraints::boolean());
|
||||
// assert_eq!(t.to_slug(), "[]");
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -1,22 +1,26 @@
|
|||
use types::Type;
|
||||
use std::fmt;
|
||||
use types::Type;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub struct Signature {
|
||||
pub inputs: Vec<Type>,
|
||||
pub outputs: Vec<Type>
|
||||
pub inputs: Vec<Type>,
|
||||
pub outputs: Vec<Type>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for Signature {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Signature(inputs: {:?}, outputs: {:?})", self.inputs, self.outputs)
|
||||
write!(
|
||||
f,
|
||||
"Signature(inputs: {:?}, outputs: {:?})",
|
||||
self.inputs, self.outputs
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Signature {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
try!(write!(f, "("));
|
||||
for (i, t) in self.inputs.iter().enumerate() {
|
||||
try!(write!(f, "("));
|
||||
for (i, t) in self.inputs.iter().enumerate() {
|
||||
try!(write!(f, "{}", t));
|
||||
if i < self.inputs.len() - 1 {
|
||||
try!(write!(f, ", "));
|
||||
|
@ -44,7 +48,6 @@ impl Signature {
|
|||
/// [field, field, bool, field] -> 2fbf
|
||||
///
|
||||
pub fn to_slug(&self) -> String {
|
||||
|
||||
let to_slug = |types| {
|
||||
let mut res = vec![];
|
||||
for t in types {
|
||||
|
@ -59,18 +62,20 @@ impl Signature {
|
|||
}
|
||||
}
|
||||
}
|
||||
res.into_iter().map(|(n, t) : (usize, &Type)| {
|
||||
let mut r = String::new();
|
||||
res.into_iter()
|
||||
.map(|(n, t): (usize, &Type)| {
|
||||
let mut r = String::new();
|
||||
|
||||
if n > 1 {
|
||||
r.push_str(&format!("{}", n));
|
||||
}
|
||||
r.push_str(&t.to_slug());
|
||||
r
|
||||
}).fold(String::new(), |mut acc, e| {
|
||||
acc.push_str(&e);
|
||||
acc
|
||||
})
|
||||
if n > 1 {
|
||||
r.push_str(&format!("{}", n));
|
||||
}
|
||||
r.push_str(&t.to_slug());
|
||||
r
|
||||
})
|
||||
.fold(String::new(), |mut acc, e| {
|
||||
acc.push_str(&e);
|
||||
acc
|
||||
})
|
||||
};
|
||||
|
||||
format!("i{}o{}", to_slug(&self.inputs), to_slug(&self.outputs))
|
||||
|
@ -79,7 +84,7 @@ impl Signature {
|
|||
pub fn new() -> Signature {
|
||||
Signature {
|
||||
inputs: vec![],
|
||||
outputs: vec![]
|
||||
outputs: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,9 +114,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn slug_0() {
|
||||
let s = Signature::new()
|
||||
.inputs(vec![])
|
||||
.outputs(vec![]);
|
||||
let s = Signature::new().inputs(vec![]).outputs(vec![]);
|
||||
|
||||
assert_eq!(s.to_slug(), String::from("io"));
|
||||
}
|
||||
|
@ -120,7 +123,12 @@ mod tests {
|
|||
fn slug_1() {
|
||||
let s = Signature::new()
|
||||
.inputs(vec![Type::FieldElement, Type::Boolean])
|
||||
.outputs(vec![Type::FieldElement, Type::FieldElement, Type::Boolean, Type::FieldElement]);
|
||||
.outputs(vec![
|
||||
Type::FieldElement,
|
||||
Type::FieldElement,
|
||||
Type::Boolean,
|
||||
Type::FieldElement,
|
||||
]);
|
||||
|
||||
assert_eq!(s.to_slug(), String::from("ifbo2fbf"));
|
||||
}
|
||||
|
@ -128,7 +136,11 @@ mod tests {
|
|||
#[test]
|
||||
fn slug_2() {
|
||||
let s = Signature::new()
|
||||
.inputs(vec![Type::FieldElement, Type::FieldElement, Type::FieldElement])
|
||||
.inputs(vec![
|
||||
Type::FieldElement,
|
||||
Type::FieldElement,
|
||||
Type::FieldElement,
|
||||
])
|
||||
.outputs(vec![Type::FieldElement, Type::Boolean, Type::FieldElement]);
|
||||
|
||||
assert_eq!(s.to_slug(), String::from("i3fofbf"));
|
||||
|
@ -137,9 +149,12 @@ mod tests {
|
|||
#[test]
|
||||
fn array_slug() {
|
||||
let s = Signature::new()
|
||||
.inputs(vec![Type::FieldElementArray(42), Type::FieldElementArray(21)])
|
||||
.inputs(vec![
|
||||
Type::FieldElementArray(42),
|
||||
Type::FieldElementArray(21),
|
||||
])
|
||||
.outputs(vec![]);
|
||||
|
||||
assert_eq!(s.to_slug(), String::from("if[42]f[21]o"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "zokrates_fs_resolver"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
authors = ["Thibaut Schaeffer <thibaut@schaeff.fr>"]
|
||||
repository = "https://github.com/JacobEberhardt/ZoKrates.git"
|
||||
|
||||
|
|
|
@ -1,85 +1,90 @@
|
|||
use std::io::{BufReader};
|
||||
use std::path::PathBuf;
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::BufReader;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub fn resolve(location: &Option<String>, source: &String) -> Result<(BufReader<File>, String, String), io::Error> {
|
||||
// the fs resolver has to be provided a location, as it supports relative paths
|
||||
match location {
|
||||
Some(location) => resolve_with_location(location, source),
|
||||
None => Err(io::Error::new(io::ErrorKind::Other, "No location provided"))
|
||||
}
|
||||
pub fn resolve(
|
||||
location: &Option<String>,
|
||||
source: &String,
|
||||
) -> Result<(BufReader<File>, String, String), io::Error> {
|
||||
// the fs resolver has to be provided a location, as it supports relative paths
|
||||
match location {
|
||||
Some(location) => resolve_with_location(location, source),
|
||||
None => Err(io::Error::new(io::ErrorKind::Other, "No location provided")),
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_with_location(location: &String, source: &String) -> Result<(BufReader<File>, String, String), io::Error> {
|
||||
let path = PathBuf::from(location).join(PathBuf::from(source));
|
||||
let (next_location, alias) = generate_next_parameters(&path)?;
|
||||
fn resolve_with_location(
|
||||
location: &String,
|
||||
source: &String,
|
||||
) -> Result<(BufReader<File>, String, String), io::Error> {
|
||||
let path = PathBuf::from(location).join(PathBuf::from(source));
|
||||
let (next_location, alias) = generate_next_parameters(&path)?;
|
||||
|
||||
File::open(path).and_then(|f| Ok((BufReader::new(f), next_location, alias)))
|
||||
File::open(path).and_then(|f| Ok((BufReader::new(f), next_location, alias)))
|
||||
}
|
||||
|
||||
fn generate_next_parameters(path: &PathBuf) -> Result<(String, String), io::Error> {
|
||||
match (path.parent(), path.file_stem()) {
|
||||
(Some(parent), Some(stem)) => Ok(
|
||||
(
|
||||
parent.to_path_buf().into_os_string().into_string().unwrap(),
|
||||
stem.to_os_string().to_string_lossy().to_string()
|
||||
)
|
||||
),
|
||||
_ => Err(io::Error::new(io::ErrorKind::Other, "Invalid path"))
|
||||
}
|
||||
match (path.parent(), path.file_stem()) {
|
||||
(Some(parent), Some(stem)) => Ok((
|
||||
parent.to_path_buf().into_os_string().into_string().unwrap(),
|
||||
stem.to_os_string().to_string_lossy().to_string(),
|
||||
)),
|
||||
_ => Err(io::Error::new(io::ErrorKind::Other, "Invalid path")),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn valid_path_with_location() {
|
||||
let (_, next_location, alias) = resolve(&Some(String::from("./src")), &String::from("lib.rs")).unwrap();
|
||||
assert_eq!(next_location, String::from("./src"));
|
||||
assert_eq!(alias, String::from("lib"));
|
||||
}
|
||||
#[test]
|
||||
fn valid_path_with_location() {
|
||||
let (_, next_location, alias) =
|
||||
resolve(&Some(String::from("./src")), &String::from("lib.rs")).unwrap();
|
||||
assert_eq!(next_location, String::from("./src"));
|
||||
assert_eq!(alias, String::from("lib"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn valid_path_without_location() {
|
||||
let res = resolve(&None, &String::from("./src/lib.rs"));
|
||||
assert!(res.is_err());
|
||||
}
|
||||
#[test]
|
||||
fn valid_path_without_location() {
|
||||
let res = resolve(&None, &String::from("./src/lib.rs"));
|
||||
assert!(res.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn non_existing_file() {
|
||||
let res = resolve(&Some(String::from("./src")), &String::from("rubbish.rs"));
|
||||
assert!(res.is_err());
|
||||
}
|
||||
#[test]
|
||||
fn non_existing_file() {
|
||||
let res = resolve(&Some(String::from("./src")), &String::from("rubbish.rs"));
|
||||
assert!(res.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_location() {
|
||||
let res = resolve(&Some(String::from(",8!-$2abc")), &String::from("foo.code"));
|
||||
assert!(res.is_err());
|
||||
}
|
||||
#[test]
|
||||
fn invalid_location() {
|
||||
let res = resolve(&Some(String::from(",8!-$2abc")), &String::from("foo.code"));
|
||||
assert!(res.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_file() {
|
||||
let res = resolve(&Some(String::from("./src")), &String::from(",8!-$2abc"));
|
||||
assert!(res.is_err());
|
||||
}
|
||||
#[test]
|
||||
fn invalid_file() {
|
||||
let res = resolve(&Some(String::from("./src")), &String::from(",8!-$2abc"));
|
||||
assert!(res.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_a_file() {
|
||||
let res = resolve(&Some(String::from(".")), &String::from("/src/"));
|
||||
assert!(res.is_err());
|
||||
}
|
||||
#[test]
|
||||
fn not_a_file() {
|
||||
let res = resolve(&Some(String::from(".")), &String::from("/src/"));
|
||||
assert!(res.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_parent() {
|
||||
let res = resolve(&Some(String::from(".")), &String::from("."));
|
||||
assert!(res.is_err());
|
||||
}
|
||||
#[test]
|
||||
fn no_parent() {
|
||||
let res = resolve(&Some(String::from(".")), &String::from("."));
|
||||
assert!(res.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_file_name() {
|
||||
let res = resolve(&Some(String::from(".")), &String::from(""));
|
||||
assert!(res.is_err());
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn no_file_name() {
|
||||
let res = resolve(&Some(String::from(".")), &String::from(""));
|
||||
assert!(res.is_err());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue