1
0
Fork 0
mirror of synced 2025-09-24 04:40:05 +00:00

merge develop, format

This commit is contained in:
schaeff 2018-11-10 12:10:12 +01:00
commit 5bf7f9cb49
62 changed files with 6534 additions and 5327 deletions

36
.circleci/config.yml Normal file
View 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
View file

@ -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
View file

@ -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)

View file

@ -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
View 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 \

View file

@ -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

View file

@ -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());
}

View file

@ -0,0 +1 @@
[1, 1, 1, 2, 2, 3, 4, 4, 4, 4]

View 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

View 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

View file

@ -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();
}
}
}
}

View file

@ -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"

View file

@ -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");
}

View file

@ -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)

View file

@ -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![],
}
}
}

View file

@ -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 {

View file

@ -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,)
}
}
}

View file

@ -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());
}
}

View file

@ -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
);
}

View file

@ -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,
}
}
}
}

View file

@ -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);
}
}
}

View file

@ -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

View file

@ -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),
}
}
}

View file

@ -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[..]);
}
}
}

View file

@ -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));
}
}

View file

@ -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()),
}
);
}
}

View file

@ -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;

View file

@ -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]);

View file

@ -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);
}
}
}
}

View file

@ -26,4 +26,4 @@ impl<T: Field> fmt::Debug for Error<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
}

View file

@ -1,6 +1,6 @@
mod tokenize;
mod error;
mod parse;
mod tokenize;
pub use parser::error::Error;
pub use parser::parse::parse_program;

View file

@ -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))),

View file

@ -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)
)
}
}
}

View file

@ -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,
},
))
}
}

View file

@ -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)
)
}
}
}

View file

@ -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;

View file

@ -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![],
})
}

View file

@ -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,

View file

@ -4,4 +4,4 @@ mod tokenizer;
pub use self::position::Position;
pub use self::token::Token;
pub use self::tokenizer::*;
pub use self::tokenizer::*;

View file

@ -46,4 +46,4 @@ fn position_col() {
col: 235,
}
);
}
}

View file

@ -1,5 +1,5 @@
use field::Field;
use std::fmt;
use field::{Field};
use types::Type;
#[derive(PartialEq)]

View file

@ -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!(

View file

@ -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

View file

@ -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();
}
}

View file

@ -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),
}
}
}
}
}

View file

@ -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))
);
}
}
}
}

View file

@ -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));
}
}
}

View file

@ -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()
}
}

View file

@ -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

View file

@ -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() + &current;
}
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()
)]
);
}
}
}

View file

@ -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
}
}

View file

@ -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)
},
}
}
}
}

View file

@ -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]>,
}

View file

@ -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
}
}
}

View file

@ -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(), "[]");
// }
}

View file

@ -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"));
}
}
}

View file

@ -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"

View file

@ -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());
}
}