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

Merge pull request #32 from JacobEberhardt/develop

Develop
This commit is contained in:
JacobEberhardt 2018-03-08 08:19:07 +01:00 committed by GitHub
commit 4bb56c6f04
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 2066 additions and 698 deletions

12
.gitignore vendored
View file

@ -2,6 +2,18 @@
# will have compiled files and executables
/target/
# ZoKrates default files
out
out.code
out.wit
proving.key
variables.inf
verification.key
verifier.sol
witness
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock
# Cargo.lock
.DS_Store

501
Cargo.lock generated
View file

@ -1,41 +1,58 @@
[root]
name = "zokrates"
version = "0.1.0"
dependencies = [
"bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.26.2 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.42 (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.20 (registry+https://github.com/rust-lang/crates.io-index)",
"num 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "aho-corasick"
version = "0.6.3"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ansi_term"
version = "0.9.0"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "atty"
version = "0.2.3"
name = "assert_cli"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
"colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"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.9 (registry+https://github.com/rust-lang/crates.io-index)",
"skeptic 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "atty"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "backtrace"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "backtrace-sys"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -43,9 +60,9 @@ name = "bincode"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.1 (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.27 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -53,29 +70,105 @@ name = "bitflags"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bitflags"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bytecount"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "byteorder"
version = "1.1.0"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cargo_metadata"
version = "0.3.3"
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.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cc"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cfg-if"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "clap"
version = "2.26.2"
version = "2.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"atty 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"textwrap 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
"atty 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "colored"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "difference"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "dtoa"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "environment"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "error-chain"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fuchsia-zircon"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fuchsia-zircon-sys"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "gcc"
version = "0.3.42"
version = "0.3.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -83,6 +176,11 @@ name = "glob"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "itoa"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "kernel32-sys"
version = "0.2.2"
@ -99,87 +197,108 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lazy_static"
version = "0.2.9"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lazy_static"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.20"
version = "0.2.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "memchr"
version = "1.0.2"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num"
version = "0.1.36"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-bigint 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"num-complex 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"num-iter 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"num-rational 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
"num-bigint 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
"num-complex 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
"num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
"num-iter 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"num-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-bigint"
version = "0.1.35"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
"num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-complex"
version = "0.1.35"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-integer"
version = "0.1.32"
version = "0.1.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-iter"
version = "0.1.32"
version = "0.1.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
"num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-rational"
version = "0.1.35"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-bigint 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
"num-bigint 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
"num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-traits"
version = "0.1.36"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-traits"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "pulldown-cmark"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quote"
@ -188,15 +307,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rand"
version = "0.3.15"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "redox_syscall"
version = "0.1.31"
version = "0.1.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -204,58 +325,121 @@ name = "redox_termios"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex"
version = "0.2.2"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex-syntax"
version = "0.4.1"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "remove_dir_all"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-demangle"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rustc-serialize"
version = "0.3.22"
version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "same-file"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "semver"
version = "0.8.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.27 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde"
version = "1.0.15"
version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde_derive"
version = "1.0.15"
version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive_internals 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive_internals 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_derive_internals"
version = "0.16.0"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
"synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_json"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"itoa 0.3.4 (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.27 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "skeptic"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytecount 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cargo_metadata 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"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.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
"tempdir 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "strsim"
version = "0.6.0"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -277,13 +461,12 @@ dependencies = [
]
[[package]]
name = "term_size"
version = "0.3.0"
name = "tempdir"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"remove_dir_all 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -291,26 +474,25 @@ name = "termion"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "textwrap"
version = "0.8.0"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thread_local"
version = "0.3.4"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -347,60 +529,137 @@ name = "void"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "walkdir"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.3.4"
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)",
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi-build"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "zokrates"
version = "0.1.0"
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.30.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.54 (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.36 (registry+https://github.com/rust-lang/crates.io-index)",
"num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[metadata]
"checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699"
"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"
"checksum atty 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21e50800ec991574876040fff8ee46b136a53e985286fbe6a3bdfe6421b78860"
"checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4"
"checksum ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b3568b48b7cefa6b8ce125f9bb4989e52fbcc29ebea88df04cc7c5f12f70455"
"checksum assert_cli 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "72342c21057a3cb5f7c2d849bf7999a83795434dd36d74fa8c24680581bd1930"
"checksum atty 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8352656fd42c30a0c3c89d26dea01e3b77c0ab2af18230835c15e2e13cd51859"
"checksum backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbbf59b1c43eefa8c3ede390fcc36820b4999f7914104015be25025e0d62af2"
"checksum backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "44585761d6161b0f57afc49482ab6bd067e4edef48c12a152c237eb0203f7661"
"checksum bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e103c8b299b28a9c6990458b7013dc4a8356a9b854c51b9883241f5866fac36e"
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
"checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d"
"checksum clap 2.26.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3451e409013178663435d6f15fdb212f14ee4424a3d74f979d081d0a66b6f1f2"
"checksum gcc 0.3.42 (registry+https://github.com/rust-lang/crates.io-index)" = "291055c78f59ca3d84c99026c9501c469413d386bb46be1e1cf1d285cd1db3b0"
"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
"checksum bytecount 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "af27422163679dea46a1a7239dffff64d3dcdc3ba5fe9c49c789fbfe0eb949de"
"checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23"
"checksum cargo_metadata 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1f56ec3e469bca7c276f2eea015aa05c5e381356febdbb0683c2580189604537"
"checksum cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "deaf9ec656256bb25b404c51ef50097207b9cbb29c933d31f92cae5a8a0ffee0"
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
"checksum clap 2.30.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1c07b9257a00f3fc93b7f3c417fc15607ec7a56823bc2c37ec744e266387de5b"
"checksum colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b0aa3473e85a3161b59845d6096b289bb577874cafeaf75ea1b1beaa6572c7fc"
"checksum difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3304d19798a8e067e48d8e69b2c37f0b5e9b4e462504ad9e27e9f3fce02bba8"
"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
"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.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8324a32baf01e2ae060e9de58ed0bc2320c9a2833491ee36cd3b4c414de4db8c"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "cf186d1a8aa5f5bee5fd662bc9c1b949e0259e1bcc379d1f006847b0080c7417"
"checksum lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c9e5e58fa1a4c3b915a561a78a22ee0cac6ab97dca2504428bc1cb074375f8d5"
"checksum libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)" = "684f330624d8c3784fb9558ca46c4ce488073a8d22450415c5eb4f4cfb0d11b5"
"checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a"
"checksum num 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "bde7c03b09e7c6a301ee81f6ddf66d7a28ec305699e3d3b056d2fc56470e3120"
"checksum num-bigint 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "88b14378471f7c2adc5262f05b4701ef53e8da376453a8d8fee48e51db745e49"
"checksum num-complex 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "f0c78e054dd19c3fd03419ade63fa661e9c49bb890ce3beb4eee5b7baf93f92f"
"checksum num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "fb24d9bfb3f222010df27995441ded1e954f8f69cd35021f6bef02ca9552fb92"
"checksum num-iter 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "287a1c9969a847055e1122ec0ea7a5c5d6f72aad97934e131c83d5c08ab4e45c"
"checksum num-rational 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "54ff603b8334a72fbb27fe66948aac0abaaa40231b3cecd189e76162f6f38aaf"
"checksum num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "a16a42856a256b39c6d3484f097f6713e14feacd9bfb02290917904fae46c81c"
"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d"
"checksum libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "1e5d97d6708edaa407429faa671b942dc0f2727222fb6b6539bf1db936e4b121"
"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
"checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e"
"checksum num-bigint 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "81b483ea42927c463e191802e7334556b48e7875297564c0e9951bd3a0ae53e3"
"checksum num-complex 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "26ff8edeab9f1d8cf6b595e35138c2a389ea29f4f57a0e6bc44abf406e4b0077"
"checksum num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f8d26da319fb45674985c78f1d1caf99aa4941f785d384a2ae36d0740bc3e2fe"
"checksum num-iter 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "4b226df12c5a59b63569dd57fafb926d91b385dfce33d8074a412411b689d593"
"checksum num-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "ee314c74bd753fc86b4780aa9475da469155f3848473a261d2d18e35245a784e"
"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
"checksum num-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e7de20f146db9d920c45ee8ed8f71681fd9ade71909b48c3acbd766aa504cf10"
"checksum pulldown-cmark 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a656fdb8b6848f896df5e478a0eb9083681663e37dcb77dd16981ff65329fe8b"
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d"
"checksum redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "8dde11f18c108289bef24469638a04dce49da56084f2d50618b226e47eb04509"
"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5"
"checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
"checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b"
"checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db"
"checksum rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "237546c689f20bb44980270c73c3b9edd0891c1be49cc1274406134a66d3957b"
"checksum serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "6a7046c9d4c6c522d10b2d098f9bebe2bef227e0e74044d8c1bfcf6b476af799"
"checksum serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "1afcaae083fd1c46952a315062326bc9957f182358eb7da03b57ef1c688f7aa9"
"checksum serde_derive_internals 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd381f6d01a6616cdba8530492d453b7761b456ba974e98768a18cad2cd76f58"
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
"checksum regex 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "5be5347bde0c48cfd8c3fdc0766cdfe9d8a755ef84d620d6794c778c91de8b2b"
"checksum regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8e931c58b93d86f080c734bfd2bce7dd0079ae2331235818133c8be7f422e20e"
"checksum remove_dir_all 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b5d2f806b0fcdabd98acd380dc8daef485e22bcb7cddc811d1337967f2528cf5"
"checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e"
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7"
"checksum semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bee2bc909ab2d8d60dab26e8cad85b25d795b14603a0dcb627b78b9d30b6454b"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "db99f3919e20faa51bb2996057f5031d8685019b5a06139b1ce761da671b8526"
"checksum serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "f4ba7591cfe93755e89eeecdbcc668885624829b020050e6aec99c2a03bd3fd0"
"checksum serde_derive_internals 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6e03f1c9530c3fb0a0a5c9b826bdd9246a5921ae995d75f512ac917fc4dd55b5"
"checksum serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c9db7266c7d63a4c4b7fe8719656ccdd51acf1bed6124b174f933b009fb10bcb"
"checksum skeptic 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c8431f8fca168e2db4be547bd8329eac70d095dff1444fee4b0fa0fabc7df75a"
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
"checksum term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b6b55df3198cc93372e85dd2ed817f0e38ce8cc0f22eb32391bfad9c4bf209"
"checksum tempdir 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f73eebdb68c14bcb24aef74ea96079830e7fa7b31a6106e42ea7ee887c1e134e"
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
"checksum textwrap 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df8e08afc40ae3459e4838f303e465aa50d823df8d7f83ca88108f6d3afe7edd"
"checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14"
"checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693"
"checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963"
"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f"
"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
"checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c"
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
"checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View file

@ -18,11 +18,13 @@ clap = "2.26.2"
# serialization and deserialization
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
bincode = "0.8.0"
regex = "0.2"
[dev-dependencies]
glob = "0.2.11"
assert_cli = "0.5"
[build-dependencies]
gcc = "0.3.41"

View file

@ -18,7 +18,7 @@ RUN wget https://github.com/scipr-lab/libsnark/archive/$libsnarkcommit.zip \
&& ./prepare-depends.sh
RUN curl https://sh.rustup.rs -sSf | \
sh -s -- --default-toolchain nightly-2017-03-20 -y
sh -s -- --default-toolchain nightly-2018-02-10 -y
ENV PATH=/root/.cargo/bin:$PATH

View file

@ -1,4 +1,4 @@
# ZoKrates
# Zokrates
[![Join the chat at https://gitter.im/ZoKrates/Lobby](https://badges.gitter.im/ZoKrates/Lobby.svg)](https://gitter.im/ZoKrates/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
@ -6,16 +6,25 @@ Zokrates is a toolbox for zkSNARKs on Ethereum.
_This is a proof-of-concept implementation. It has not been tested for production._
## Using ZoKrates
# Motivation
ZoKrates provides a command line interface.
To see an overview of the available subcommands, run
Ethereum runs computations on all nodes of the network, resulting in high costs, limits in complexity, and low privacy.
SNARKs have been enabling to only verify computations on-chain for a fraction of the cost of running them, but are hard to grasp and work with.
Zokrates bridges this gap. It helps you create offchain programs and link them to the Ethereum blockchain, expanding the possibilities for your Dapp.
# Installation
Using Docker is currently the recommended way to get started with Zokrates.
```
./zokrates
git clone https://github.com/JacobEberhardt/ZoKrates
cd ZoKrates
docker build -t zokrates .
docker run -ti zokrates /bin/bash
cd ZoKrates/target/release
```
### Example
# Example
To execute the program, perform the setup for the program, generate a proof
```
@ -31,33 +40,74 @@ with `add(1, 2, 3)`, call
./zokrates export-verifier
```
## Building
# API reference
Currently needs to be build with nightly Rust.
Zokrates provides a command line interface.
You can see an overview of the available subcommands by running
### Docker (Recommended)
Example usage:
```
docker build -t zokrates .
docker run -ti zokrates /bin/bash
cd ZoKrates
./target/release/zokrates compile -i examples/add.code
./zokrates
```
### Without libsnark
Build with the feature `nolibsnark`
#### `compile`
```
cargo build --features nolibsnark
./zokrates compile -i /path/to/add.code
```
### Environment Variables
Set the libsnark library path in `LD_LIBRARY_PATH`
Compile a `.code` file.
Creates a compiled `.code` file at `./out.code`.
#### `compute-witness`
```
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
./zokrates compute-witness -a 1 2
```
## Testing
Computes a witness for the compiled program found at `./out.code` and arguments to the program.
A witness is a valid assignment of the variables, which include the results of the computation.
Creates a witness file at `./witness`
#### `setup`
```
./zokrates setup
```
Generates a trusted setup for the compiled program found at `./out.code`.
Creates a proving key and a verifying key at `./proving.key` and `./verifying.key`.
#### `export-verifier`
```
./zokrates export-verifier
```
Using the verifying key at `./verifying.key`, generates a Solidity contract enabling to verify proofs for computations of the compiled program at `./out.code`.
Creates a verifier contract at `./verifier.sol`
#### `generate-proof`
```
./zokrates generate-proof
```
Using the proving key at `./proving.key`, generates a proof for a computation of the compiled program `./out.code` resulting in `./witness`.
Returns the proof, for example:
```
A = 0x45582d7906c967b1fd1cac0aad3efefa526e4cd888b8ecb5907b46c2eb1f781, 0x8158089a63a6aafa4afc3bbfd5ebf392e5ef61d0c5faf2e2445c9112450f29c
A_p = 0x5e4fe0bfa79a571b8918138ee5d7b3d0ad394c9bb8f7d2e1549f7e3c3bab7e9, 0x1708b5ba3d138e433406c792f679ae6902fc9f7c6131305a9a5f826dbe2d71fb
B = [0x34f5c5b7518597452e55a69bf9171a63837a98a1c1c1870b610b2cfe79c4573, 0x18e56afd179d67960db838a8fdb128eb78d5dd2c1ffcd564f9d0dada928ed71f], [0xf160ea8d2dc33b564a45c0998309b4bf5a050cc8f6288793b7401b37d1eb1a2, 0x23ade8ba2c64300b5ff90e18641516407054a21179829252fd87f1bd61a3be34]
B_p = 0xc88b87d45f90da42b9c455da16dad76996ef5b1e859a4f0db7dcef4f7e3b2fd, 0x20ed7c62dd8c6c47506e6db1d4837daa42ae80b931227153054539dcbf6f3778
C = 0x2c230cbffbcb6211d2cf8f434df291a413721e3bef5ada4030d532d14b6ea504, 0x21421565f75429d0922c8cf00b68e4da23c61670e787ce6a5de14a5a86ebdcb0
C_p = 0xce11fe724ce1ce183c15c4f5405d9607d6c769422aa9f62f4868478324a2f5, 0x1e585b35ed22ef32fd70ef960818f1514d1dd94b3517c127e782de24173c69f9
H = 0x2306e74a1a7e318d2d3c40cbea708b0e0b91cd1548c9db6261fc2bd815740978, 0xde538e4e99b0e20e84cdbbd3bc08c37bca0af21edd67faf52bc4027a9b00f7c
K = 0x1868436121f271e9fbf78a8f75bb4077e2d4f208891793fd5b468afc3b05c0e4, 0x1021c3ecb15c3fd7340d4eb5bf446e1ad457020e4f8b7cc82f8af64507a35fbe
```
Passed to the verifier contract, this proof can be checked.
# Testing
Run normal tests with
```

View file

@ -4,14 +4,20 @@ extern crate gcc;
fn main() {
#[cfg(not(feature = "nolibsnark"))]
{
println!("cargo:rustc-link-search=/usr/local/lib");
gcc::Config::new()
.cpp(true)
.debug(true)
.include("/usr/local/include")
.include("/usr/local/include/libsnark")
.flag("-std=c++11")
.define("CURVE_ALT_BN128", None)
.file("lib/wraplibsnark.cpp")
.compile("libwraplibsnark.a");
println!("cargo:rustc-link-lib=gmp");
println!("cargo:rustc-link-lib=gmpxx");
println!("cargo:rustc-link-lib=supercop");
println!("cargo:rustc-link-lib=snark");
println!("cargo:rustc-link-search=/usr/local/lib");
}
}

View file

@ -1,7 +1,4 @@
// a and b are factorization of c
def main(c):
a1 = if a == 1 then 0 else 1 fi // "a != 1"
b1 = if b == 1 then 0 else 1 fi // "b != 1"
a1 * b1 == 1 // "a1 and b1"
def main(c, private a, private b):
c == a * b
return 1

View file

@ -0,0 +1,23 @@
def lt(a,b):
return if a < b then 1 else 0 fi
def cutoff():
return 31337
def getThing(index):
result = 3
result = if index == 0 then 13 else result fi
result = if index == 1 then 23 else result fi
result = if index == 2 then 43 else result fi
result = if index == 3 then 53 else result fi
result = if index == 4 then 73 else result fi
result = if index == 5 then 83 else result fi
return result
def cubeThing(thing):
return thing**3
def main(index):
thing = getThing(index)
thing = cubeThing(thing)
return lt(cutoff(), thing)

View file

@ -0,0 +1,7 @@
def foo(a):
b = 12*a
return a, 2*a, 5*b, a*b
def main(i):
x, y, z, t = foo(i)
return 1

View file

@ -0,0 +1,5 @@
def foo():
return 1, 2
def main():
a, b = foo()
return a + b, b - a

View file

@ -1,3 +0,0 @@
def main():
c = 3 + a
return 3

View file

@ -22,7 +22,7 @@ def validateInput(x):
return (x-1)*(x-2)*(x-3)*(x-4)
// variables naming: box'row''column'
def main(a21,b11,b22,c11,c22,d21):
def main(a21, b11, b22, c11, c22, d21, private a11, private a12, private a22, private b12, private b21, private c12, private c21, private d11, private d12, private d22):
// validate inputs
0 == validateInput(a11)

View file

@ -44,7 +44,7 @@ std::string HexStringFromLibsnarkBigint(libsnark::bigint<libsnark::alt_bn128_r_l
ss << std::hex << std::setw(2) << (int)x[i];
}
std:string str = ss.str();
std::string str = ss.str();
return str.erase(0, min(str.find_first_not_of('0'), str.size()-1));
}

View file

@ -6,11 +6,10 @@
//! @date 2017
use std::fmt;
use std::collections::HashMap;
use std::io::{stdin, BufRead};
use std::collections::{HashMap, BTreeMap};
use field::Field;
#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, Clone)]
pub struct Prog<T: Field> {
/// Functions of the program
pub functions: Vec<Function<T>>,
@ -20,7 +19,7 @@ pub struct Prog<T: Field> {
impl<T: Field> Prog<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
pub fn get_witness(&self, inputs: Vec<T>) -> HashMap<String, T> {
pub fn get_witness(&self, inputs: Vec<T>) -> BTreeMap<String, T> {
let main = self.functions.iter().find(|x| x.id == "main").unwrap();
assert!(main.arguments.len() == inputs.len());
main.get_witness(inputs)
@ -56,7 +55,7 @@ impl<T: Field> fmt::Debug for Prog<T> {
}
}
#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, Clone)]
pub struct Function<T: Field> {
/// Name of the program
pub id: String,
@ -64,22 +63,26 @@ pub struct Function<T: Field> {
pub arguments: Vec<Parameter>,
/// Vector of statements that are executed when running the function
pub statements: Vec<Statement<T>>,
/// number of returns
pub return_count: usize,
}
impl<T: Field> Function<T> {
// for flattened functions
pub fn get_witness(&self, inputs: Vec<T>) -> HashMap<String, T> {
pub fn get_witness(&self, inputs: Vec<T>) -> BTreeMap<String, T> {
assert!(self.arguments.len() == inputs.len());
let mut witness = HashMap::new();
let mut witness = BTreeMap::new();
witness.insert("~one".to_string(), T::one());
for (i, arg) in self.arguments.iter().enumerate() {
witness.insert(arg.id.to_string(), inputs[i].clone());
}
for statement in &self.statements {
match *statement {
Statement::Return(ref expr) => {
let s = expr.solve(&mut witness);
witness.insert("~out".to_string(), s);
Statement::Return(ref list) => {
for (i, val) in list.expressions.iter().enumerate() {
let s = val.solve(&mut witness);
witness.insert(format!("~out_{}", i).to_string(), s);
}
}
Statement::Compiler(ref id, ref expr) | Statement::Definition(ref id, ref expr) => {
let s = expr.solve(&mut witness);
@ -88,7 +91,8 @@ impl<T: Field> Function<T> {
Statement::For(..) => unimplemented!(),
Statement::Condition(ref lhs, ref rhs) => {
assert_eq!(lhs.solve(&mut witness), rhs.solve(&mut witness))
}
},
Statement::MultipleDefinition(..) => panic!("No MultipleDefinition allowed in flattened code"),
}
}
witness
@ -131,19 +135,21 @@ impl<T: Field> fmt::Debug for Function<T> {
}
}
#[derive(Clone, Serialize, Deserialize)]
#[derive(Clone, Serialize, Deserialize, PartialEq)]
pub enum Statement<T: Field> {
Return(Expression<T>),
Return(ExpressionList<T>),
Definition(String, Expression<T>),
Condition(Expression<T>, Expression<T>),
For(String, T, T, Vec<Statement<T>>),
Compiler(String, Expression<T>),
MultipleDefinition(Vec<String>, Expression<T>),
}
impl<T: Field> Statement<T> {
pub fn is_flattened(&self) -> bool {
match *self {
Statement::Return(ref x) | Statement::Definition(_, ref x) => x.is_flattened(),
Statement::Definition(_, ref x) | Statement::MultipleDefinition(_, ref x) => x.is_flattened(),
Statement::Return(ref x) => x.is_flattened(),
Statement::Compiler(..) => true,
Statement::Condition(ref x, ref y) => {
(x.is_linear() && y.is_flattened()) || (x.is_flattened() && y.is_linear())
@ -168,6 +174,15 @@ impl<T: Field> fmt::Display for Statement<T> {
write!(f, "\tendfor")
}
Statement::Compiler(ref lhs, ref rhs) => write!(f, "# {} = {}", lhs, rhs),
Statement::MultipleDefinition(ref ids, ref rhs) => {
for (i, id) in ids.iter().enumerate() {
try!(write!(f, "{}", id));
if i < ids.len() - 1 {
try!(write!(f, ", "));
}
}
write!(f, " = {}", rhs)
},
}
}
}
@ -188,6 +203,9 @@ impl<T: Field> fmt::Debug for Statement<T> {
write!(f, "\tendfor")
}
Statement::Compiler(ref lhs, ref rhs) => write!(f, "Compiler({:?}, {:?})", lhs, rhs),
Statement::MultipleDefinition(ref lhs, ref rhs) => {
write!(f, "MultipleDefinition({:?}, {:?})", lhs, rhs)
},
}
}
}
@ -195,11 +213,13 @@ impl<T: Field> fmt::Debug for Statement<T> {
#[derive(Clone, PartialEq, Serialize, Deserialize)]
pub struct Parameter {
pub id: String,
pub private: bool,
}
impl fmt::Display for Parameter {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.id)
let visibility = if self.private { "private " } else { "" };
write!(f, "{}{}", visibility, self.id)
}
}
@ -269,7 +289,7 @@ impl<T: Field> Expression<T> {
}
}
fn solve(&self, inputs: &mut HashMap<String, T>) -> T {
fn solve(&self, inputs: &mut BTreeMap<String, T>) -> T {
match *self {
Expression::Number(ref x) => x.clone(),
Expression::Identifier(ref var) => {
@ -288,19 +308,11 @@ impl<T: Field> Expression<T> {
}
assert_eq!(num, T::zero());
} else {
println!(
"Could not calculate variable {:?}, inputs: {:?}",
panic!(
"Variable {:?} is undeclared in inputs: {:?}",
var,
inputs
);
println!("Please enter a value for {:?}:", var);
let mut input = String::new();
let stdin = stdin();
stdin
.lock()
.read_line(&mut input)
.expect("Did not enter a correct String");
inputs.insert(var.to_string(), T::from(input.trim()));
}
}
inputs[var].clone()
@ -350,7 +362,7 @@ impl<T: Field> Expression<T> {
(box Expression::Sub(..), _) | (_, box Expression::Sub(..)) => false,
(box x, box y) => x.is_linear() && y.is_linear(),
}
}
},
_ => false,
}
}
@ -378,7 +390,7 @@ impl<T: Field> fmt::Display for Expression<T> {
for (i, param) in p.iter().enumerate() {
try!(write!(f, "{}", param));
if i < p.len() - 1 {
try!(write!(f, ","));
try!(write!(f, ", "));
}
}
write!(f, ")")
@ -413,6 +425,48 @@ impl<T: Field> fmt::Debug for Expression<T> {
}
}
#[derive(Clone, PartialEq, Serialize, Deserialize)]
pub struct ExpressionList<T: Field> {
pub expressions: Vec<Expression<T>>
}
impl<T: Field> ExpressionList<T> {
pub fn new() -> ExpressionList<T> {
ExpressionList {
expressions: vec![]
}
}
pub fn apply_substitution(&self, substitution: &HashMap<String, String>) -> ExpressionList<T> {
let expressions: Vec<Expression<T>> = self.expressions.iter().map(|e| e.apply_substitution(substitution)).collect();
ExpressionList {
expressions: expressions
}
}
pub fn is_flattened(&self) -> bool {
self.expressions.iter().all(|e| e.is_flattened())
}
}
impl<T: Field> fmt::Display for ExpressionList<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for (i, param) in self.expressions.iter().enumerate() {
try!(write!(f, "{}", param));
if i < self.expressions.len() - 1 {
try!(write!(f, ", "));
}
}
write!(f, "")
}
}
impl<T: Field> fmt::Debug for ExpressionList<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "ExpressionList({:?})", self.expressions)
}
}
#[derive(Clone, PartialEq, Serialize, Deserialize)]
pub enum Condition<T: Field> {
Lt(Expression<T>, Expression<T>),
@ -448,7 +502,7 @@ impl<T: Field> Condition<T> {
}
}
fn solve(&self, inputs: &mut HashMap<String, T>) -> bool {
fn solve(&self, inputs: &mut BTreeMap<String, T>) -> bool {
match *self {
Condition::Lt(ref lhs, ref rhs) => lhs.solve(inputs) < rhs.solve(inputs),
Condition::Le(ref lhs, ref rhs) => lhs.solve(inputs) <= rhs.solve(inputs),

View file

@ -18,6 +18,8 @@ pub struct Flattener {
variables: HashSet<String>,
/// Map of renamings for reassigned variables while processing the program.
substitution: HashMap<String, String>,
/// Map of function id to invocation counter
function_calls: HashMap<String, usize>,
/// Index of the next introduced variable while processing the program.
next_var_idx: usize,
}
@ -32,6 +34,7 @@ impl Flattener {
bits: bits,
variables: HashSet::new(),
substitution: HashMap::new(),
function_calls: HashMap::new(),
next_var_idx: 0,
}
}
@ -195,6 +198,105 @@ impl Flattener {
}
}
fn flatten_function_call<T: Field>(
&mut self,
functions_flattened: &Vec<Function<T>>,
arguments_flattened: &Vec<Parameter>,
statements_flattened: &mut Vec<Statement<T>>,
id: &String,
param_expressions: &Vec<Expression<T>>
) -> ExpressionList<T> {
for funct in functions_flattened {
if funct.id == *id && funct.arguments.len() == (*param_expressions).len() {
// funct is now the called function
// Idea: variables are given a prefix.
// It consists of the function name followed by a call counter value
// e.g.: add_1_a_2
// Stores prefixed variables
let mut replacement_map: HashMap<String, String> = HashMap::new();
// build prefix
match self.function_calls.clone().get(&funct.id) {
Some(val) => {
self.function_calls.insert(funct.id.clone(),val+1);
}
None => {
self.function_calls.insert(funct.id.clone(),1);
}
}
let prefix = format!("{}_{}_", funct.id.clone(), self.function_calls.get(&funct.id).unwrap());
// Handle complex parameters and assign values:
// Rename Parameters, assign them to values in call. Resolve complex expressions with definitions
for (i, param_expr) in param_expressions.iter().enumerate() {
let new_var;
match param_expr.apply_substitution(&self.substitution) {
Expression::Identifier(ref x) => {
new_var = format!("{}param_{}", &prefix, i);
statements_flattened
.push(Statement::Definition(new_var.clone(), Expression::Identifier(x.clone().to_string())));
},
_ => {
let expr_subbed = param_expr.apply_substitution(&self.substitution);
let rhs = self.flatten_expression(
functions_flattened,
arguments_flattened,
statements_flattened,
expr_subbed,
);
new_var = format!("{}param_{}", &prefix, i);
statements_flattened
.push(Statement::Definition(new_var.clone(), rhs));
}
}
replacement_map.insert(funct.arguments.get(i).unwrap().id.clone(), new_var);
}
// Ensure Renaming and correct returns:
// add all flattened statements, adapt return statement
for stat in funct.statements.clone() {
assert!(stat.is_flattened(), format!("Not flattened: {}", &stat));
match stat {
// set return statements right side as expression result
Statement::Return(list) => {
return ExpressionList {
expressions: list.expressions.into_iter().map(|x| x.apply_substitution(&replacement_map)).collect()
}
},
Statement::Definition(var, rhs) => {
let new_rhs = rhs.apply_substitution(&replacement_map);
let new_var: String = format!("{}{}", prefix, var.clone());
replacement_map.insert(var, new_var.clone());
statements_flattened.push(
Statement::Definition(new_var, new_rhs)
);
},
Statement::Compiler(var, rhs) => {
let new_rhs = rhs.apply_substitution(&replacement_map);
let new_var: String = format!("{}{}", prefix, var.clone());
replacement_map.insert(var, new_var.clone());
statements_flattened.push(Statement::Compiler(new_var, new_rhs));
},
Statement::Condition(lhs, rhs) => {
let new_lhs = lhs.apply_substitution(&replacement_map);
let new_rhs = rhs.apply_substitution(&replacement_map);
statements_flattened
.push(Statement::Condition(new_lhs, new_rhs));
},
_ => panic!("Statement inside function not flattened when flattening function call")
}
}
}
}
panic!(
"Function definition for function {} with {:?} argument(s) not found.",
id,
param_expressions
);
}
/// Returns a flattened `Expression` based on the given `expr`.
///
/// # Arguments
@ -418,110 +520,38 @@ impl Flattener {
)
}
FunctionCall(ref id, ref param_expressions) => {
// Replace complex expressions with definitions in parameters
let mut params_flattened: Vec<Parameter> = Vec::new();
for (i, param_expr) in param_expressions.iter().enumerate() {
match param_expr.apply_substitution(&self.substitution) {
Expression::Identifier(ref x) => params_flattened.push(Parameter {
id: x.clone().to_string(),
}),
_ => {
let expr_subbed = param_expr.apply_substitution(&self.substitution);
let rhs = self.flatten_expression(
functions_flattened,
arguments_flattened,
statements_flattened,
expr_subbed,
);
let intermediate_var =
self.use_variable(&format!("{}_param_{}", &id, i));
statements_flattened
.push(Statement::Definition(intermediate_var.clone(), rhs));
params_flattened.push(Parameter {
id: intermediate_var.clone().to_string(),
});
}
}
}
for funct in functions_flattened {
if funct.id == *id && funct.arguments.len() == (*param_expressions).len() {
// funct is now the called function
// add all variables of caller to ensure no conflicting variable can be used in funct
// update with new variables created during processing
let mut used_vars: HashSet<String> = self.variables.clone();
// if conflicting variable is found, a replacement variable needs to be created
// and the substitution needs to be added to replacement map.
let mut replacement_map: HashMap<String, String> = HashMap::new();
for (i, _) in params_flattened.iter().enumerate() {
let identifier_call: String =
params_flattened.get(i).unwrap().id.clone();
let identifier_called: String =
funct.arguments.get(i).unwrap().id.clone();
if identifier_called != identifier_call{
replacement_map.insert(identifier_called, identifier_call);
}
}
// add all flattened statements, adapt return statement
for stat in funct.statements.clone() {
assert!(stat.is_flattened(), format!("Not flattened: {}", &stat));
match stat {
// set return statements right side as expression result
Statement::Return(x) => {
let result = x.apply_substitution(&replacement_map);
// add back variables and substitutions to calling function
for v in used_vars{
self.variables.insert(v);
}
return result;
}
Statement::Definition(var, rhs) => {
let new_rhs = rhs.apply_substitution(&replacement_map);
let mut new_var: String = var.clone();
if used_vars.contains(&var){
new_var = self.get_new_var(&var, &mut used_vars);
replacement_map.insert(var, new_var.clone());
} else{
used_vars.insert(new_var.clone()); // variables must not be used again
}
statements_flattened.push(
Statement::Definition(new_var, new_rhs)
);
}
Statement::Compiler(var, rhs) => {
let new_rhs = rhs.apply_substitution(&replacement_map);
let mut new_var: String = var.clone();
if used_vars.contains(&var){
new_var = self.get_new_var(&var, &mut used_vars);
replacement_map.insert(var, new_var.clone());
} else{
used_vars.insert(new_var.clone()); // variables must not be used again
}
statements_flattened.push(Statement::Compiler(new_var, new_rhs));
}
Statement::Condition(lhs, rhs) => {
let new_lhs = lhs.apply_substitution(&replacement_map);
let new_rhs = rhs.apply_substitution(&replacement_map);
statements_flattened
.push(Statement::Condition(new_lhs, new_rhs));
}
Statement::For(..) => panic!("Not flattened!"),
}
}
}
}
panic!(
"Function definition for function {} with {:?} argument(s) not found.",
let exprs_flattened = self.flatten_function_call(
functions_flattened,
arguments_flattened,
statements_flattened,
id,
param_expressions
);
assert!(exprs_flattened.expressions.len() == 1); // outside of MultipleDefinition, FunctionCalls must return a single value
exprs_flattened.expressions[0].clone()
}
}
}
pub fn flatten_expression_list<T: Field>(
&mut self,
functions_flattened: &mut Vec<Function<T>>,
arguments_flattened: &Vec<Parameter>,
statements_flattened: &mut Vec<Statement<T>>,
list: ExpressionList<T>,
) -> ExpressionList<T> {
let flattened_exprs = list.expressions.into_iter().map(|x|
self.flatten_expression(
functions_flattened,
arguments_flattened,
statements_flattened,
x.clone())
).collect();
ExpressionList {
expressions: flattened_exprs
}
}
pub fn flatten_statement<T: Field>(
&mut self,
functions_flattened: &mut Vec<Function<T>>,
@ -530,14 +560,15 @@ impl Flattener {
stat: &Statement<T>,
) {
match *stat {
Statement::Return(ref expr) => {
let expr_subbed = expr.apply_substitution(&self.substitution);
let rhs = self.flatten_expression(
Statement::Return(ref exprs) => {
let exprs_subbed = exprs.apply_substitution(&self.substitution);
let rhs = self.flatten_expression_list(
functions_flattened,
arguments_flattened,
statements_flattened,
expr_subbed,
exprs_subbed,
);
statements_flattened.push(Statement::Return(rhs));
}
Statement::Definition(ref id, ref expr) => {
@ -554,6 +585,7 @@ impl Flattener {
if !(var == var_to_replace) && self.variables.contains(&var_to_replace) && !self.substitution.contains_key(&var_to_replace){
self.substitution.insert(var_to_replace.clone().to_string(),var.clone());
}
statements_flattened.push(Statement::Definition(var, rhs));
}
Statement::Condition(ref expr1, ref expr2) => {
@ -603,6 +635,31 @@ impl Flattener {
}
}
ref s @ Statement::Compiler(..) => statements_flattened.push(s.clone()),
Statement::MultipleDefinition(ref ids, ref rhs) => {
let rhs_subbed = rhs.apply_substitution(&self.substitution);
match rhs_subbed {
FunctionCall(ref fun_id, ref exprs) => {
let rhs_flattened = self.flatten_function_call(
functions_flattened,
arguments_flattened,
statements_flattened,
fun_id,
exprs,
);
for (i, id) in ids.into_iter().enumerate() {
let var = self.use_variable(&id);
// handle return of function call
let var_to_replace = self.get_latest_var_substitution(&id);
if !(var == var_to_replace) && self.variables.contains(&var_to_replace) && !self.substitution.contains_key(&var_to_replace){
self.substitution.insert(var_to_replace.clone().to_string(),var.clone());
}
statements_flattened.push(Statement::Definition(var, rhs_flattened.expressions[i].clone()));
}
},
_ => panic!("Right hand side of a MultipleDefinition should be a FunctionCall")
}
},
}
}
@ -626,6 +683,7 @@ impl Flattener {
for arg in funct.arguments {
arguments_flattened.push(Parameter {
id: arg.id.to_string(),
private: arg.private
});
}
// flatten statements in functions and apply substitution
@ -641,6 +699,7 @@ impl Flattener {
id: funct.id,
arguments: arguments_flattened,
statements: statements_flattened,
return_count: funct.return_count
}
}
@ -695,20 +754,153 @@ impl Flattener {
}
}
}
}
// used for function call flattening
fn get_new_var(&mut self, name: &String, used_vars: &mut HashSet<String>) -> String{
let mut i = 0;
let mut new_name = name.to_string();
loop {
if used_vars.contains(&new_name) {
new_name = format!("{}_{}", &name, i);
i += 1;
} else {
used_vars.insert(new_name.to_string());
return new_name;
#[cfg(test)]
mod multiple_definition {
use super::*;
use field::FieldPrime;
#[test]
fn multiple_definition() {
// def foo()
// return 1, 2
// def main()
// a, b = foo()
let mut flattener = Flattener::new(FieldPrime::get_required_bits());
let mut functions_flattened = vec![
Function {
id: "foo".to_string(),
arguments: vec![],
statements: vec![Statement::Return(
ExpressionList {
expressions: vec![
Expression::Number(FieldPrime::from(1)),
Expression::Number(FieldPrime::from(2))
]
}
)],
return_count: 2,
}
}
];
let arguments_flattened = vec![];
let mut statements_flattened = vec![];
let statement = Statement::MultipleDefinition(
vec![
"a".to_string(),
"b".to_string()
],
Expression::FunctionCall("foo".to_string(), vec![])
);
flattener.flatten_statement(
&mut functions_flattened,
&arguments_flattened,
&mut statements_flattened,
&statement,
);
assert_eq!(
statements_flattened[0]
,
Statement::Definition("a".to_string(), Expression::Number(FieldPrime::from(1)))
);
}
#[test]
fn multiple_definition2() {
// def dup(x)
// return x, x
// def main()
// a, b = dup(2)
let mut flattener = Flattener::new(FieldPrime::get_required_bits());
let mut functions_flattened = vec![
Function {
id: "dup".to_string(),
arguments: vec![Parameter { id: "x".to_string(), private: true }],
statements: vec![Statement::Return(
ExpressionList {
expressions: vec![
Expression::Identifier("x".to_string()),
Expression::Identifier("x".to_string()),
]
}
)],
return_count: 2,
}
];
let arguments_flattened = vec![];
let mut statements_flattened = vec![];
let statement = Statement::MultipleDefinition(
vec![
"a".to_string(),
"b".to_string()
],
Expression::FunctionCall("dup".to_string(), vec![Expression::Number(FieldPrime::from(2))])
);
flattener.flatten_statement(
&mut functions_flattened,
&arguments_flattened,
&mut statements_flattened,
&statement,
);
println!("{:?}", statements_flattened);
assert_eq!(
statements_flattened[0]
,
Statement::Definition("dup_1_param_0".to_string(), Expression::Number(FieldPrime::from(2)))
);
}
#[test]
fn simple_definition() {
// def foo()
// return 1
// def main()
// a = foo()
let mut flattener = Flattener::new(FieldPrime::get_required_bits());
let mut functions_flattened = vec![
Function {
id: "foo".to_string(),
arguments: vec![],
statements: vec![Statement::Return(
ExpressionList {
expressions: vec![
Expression::Number(FieldPrime::from(1))
]
}
)],
return_count: 1,
}
];
let arguments_flattened = vec![];
let mut statements_flattened = vec![];
let statement = Statement::Definition(
"a".to_string(),
Expression::FunctionCall("foo".to_string(), vec![])
);
flattener.flatten_statement(
&mut functions_flattened,
&arguments_flattened,
&mut statements_flattened,
&statement,
);
assert_eq!(
statements_flattened[0]
,
Statement::Definition("a".to_string(), Expression::Number(FieldPrime::from(1)))
);
}
}

View file

@ -14,10 +14,6 @@ use std::cmp::max;
use field::Field;
#[link(name = "snark")]
#[link(name = "supercop")]
#[link(name = "gmp")]
#[link(name = "gmpxx")]
extern "C" {
fn _setup(

View file

@ -18,21 +18,23 @@ extern crate regex;
mod absy;
mod parser;
mod semantics;
mod flatten;
mod r1cs;
mod field;
mod verification;
#[cfg(not(feature = "nolibsnark"))]
mod libsnark;
use std::fs::File;
use std::path::Path;
use std::io::{BufWriter, Write, BufReader, BufRead};
use std::io::{BufWriter, Write, BufReader, BufRead, stdin};
use std::collections::HashMap;
use std::string::String;
use std::io::prelude::*;
use field::{Field, FieldPrime};
use absy::Prog;
use parser::parse_program;
use semantics::Checker;
use flatten::Flattener;
use r1cs::r1cs_program;
use clap::{App, AppSettings, Arg, SubCommand};
@ -40,6 +42,7 @@ use clap::{App, AppSettings, Arg, SubCommand};
use libsnark::{setup, generate_proof};
use bincode::{serialize_into, deserialize_from , Infinite};
use regex::Regex;
use verification::CONTRACT_TEMPLATE;
fn main() {
const FLATTENED_CODE_DEFAULT_PATH: &str = "out";
@ -139,7 +142,7 @@ fn main() {
.arg(Arg::with_name("input")
.short("i")
.long("input")
.help("path of comiled code.")
.help("path of compiled code.")
.value_name("FILE")
.takes_value(true)
.required(false)
@ -159,6 +162,10 @@ fn main() {
.takes_value(true)
.multiple(true) // allows multiple values
.required(false)
).arg(Arg::with_name("interactive")
.long("interactive")
.help("enter private inputs interactively.")
.required(false)
)
)
.subcommand(SubCommand::with_name("generate-proof")
@ -209,6 +216,12 @@ fn main() {
}
};
// check semantics
match Checker::new().check_program(program_ast.clone()) {
Ok(()) => (),
Err(why) => panic!("Semantic analysis failed with: {}", why)
};
// flatten input program
let program_flattened =
Flattener::new(FieldPrime::get_required_bits()).flatten_program(program_ast);
@ -241,7 +254,7 @@ fn main() {
hrofb.flush().expect("Unable to flush buffer.");
// debugging output
//println!("Compiled program:\n{}", program_flattened);
println!("Compiled program:\n{}", program_flattened);
println!(
@ -286,28 +299,56 @@ fn main() {
println!("{}", main_flattened);
// validate #arguments
let mut args: Vec<FieldPrime> = Vec::new();
let mut cli_arguments: Vec<FieldPrime> = Vec::new();
match sub_matches.values_of("arguments"){
Some(p) => {
let arg_strings: Vec<&str> = p.collect();
args = arg_strings.into_iter().map(|x| FieldPrime::from(x)).collect();
cli_arguments = arg_strings.into_iter().map(|x| FieldPrime::from(x)).collect();
},
None => {
}
}
if main_flattened.arguments.len() != args.len() {
println!("Wrong number of arguments. Given: {}, Required: {}.", args.len(), main_flattened.arguments.len());
// 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();
if 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 witness_map = main_flattened.get_witness(args);
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() {
Some(x) => x,
None => {
std::process::exit(1);
}
}
}
}
}).collect();
let witness_map = main_flattened.get_witness(arguments);
// let witness_map: HashMap<String, FieldPrime> = main_flattened.get_witness(args);
println!("Witness: {:?}", witness_map);
match witness_map.get("~out") {
Some(out) => println!("Returned (~out): {}", out),
None => println!("~out not found, no value returned")
}
// write witness to file
let output_path = Path::new(sub_matches.value_of("output").unwrap());
@ -381,7 +422,7 @@ fn main() {
// run setup phase
#[cfg(not(feature="nolibsnark"))]{
// number of inputs in the zkSNARK sense, i.e., input variables + output variables
let num_inputs = main_flattened.arguments.len() + 1; //currently exactly one output variable
let num_inputs = main_flattened.arguments.iter().filter(|x| !x.private).count() + main_flattened.return_count;
println!("setup successful: {:?}", setup(variables, a, b, c, num_inputs, pk_path, vk_path));
}
}
@ -396,14 +437,7 @@ fn main() {
let reader = BufReader::new(input_file);
let mut lines = reader.lines();
//read template
let template_path = Path::new("templates/sol_verification.template");
let mut template_file = match File::open(&template_path) {
Ok(template_file) => template_file,
Err(why) => panic!("couldn't open {}: {}", template_path.display(), why)
};
let mut template_text = String::new();
template_file.read_to_string(&mut template_text).unwrap();
let mut template_text = String::from(CONTRACT_TEMPLATE);
let ic_template = String::from("vk.IC[index] = Pairing.G1Point(points);"); //copy this for each entry
//replace things in template

View file

@ -69,7 +69,7 @@ use std::fmt;
use std::io::{BufReader, Lines};
use std::io::prelude::*;
use std::fs::File;
use field::Field;
use field::{Field, FieldPrime};
use absy::*;
#[derive(Clone, PartialEq)]
@ -150,6 +150,7 @@ enum Token<T: Field> {
Mult,
Div,
Pow,
Private,
Ide(String),
Num(T),
Unknown(String),
@ -188,6 +189,7 @@ impl<T: Field> fmt::Display for Token<T> {
Token::Mult => write!(f, "*"),
Token::Div => write!(f, "/"),
Token::Pow => write!(f, "**"),
Token::Private => write!(f, "private"),
Token::Ide(ref x) => write!(f, "{}", x),
Token::Num(ref x) => write!(f, "{}", x),
Token::Unknown(ref x) => write!(f, "{}", x),
@ -502,6 +504,14 @@ fn next_token<T: Field>(input: &String, pos: &Position) -> (Token<T>, String, Po
},
)
}
Some(_) if input[offset..].starts_with("private ") => (
Token::Private,
input[offset + 8..].to_string(),
Position {
line: pos.line,
col: pos.col + offset + 8,
},
),
Some(x) => match x {
'0'...'9' => parse_num(
&input[offset..].to_string(),
@ -781,6 +791,25 @@ fn parse_function_call<T: Field>(
}
}
// parse an expression list starting with an identifier
fn parse_identifier_list1<T: Field>(
head: String,
input: String,
pos: Position,
) -> Result<(Vec<String>, String, Position), Error<T>> {
let mut res = Vec::new();
res.push(head);
parse_comma_separated_identifier_list_rec(input, pos, &mut res)
}
// parse an expression list
fn parse_expression_list<T: Field>(
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)
}
fn parse_expr<T: Field>(
input: &String,
@ -821,6 +850,7 @@ fn parse_expr<T: Field>(
}
}
// parse statement that starts with an identifier
fn parse_statement1<T: Field>(
ide: String,
input: String,
@ -855,6 +885,24 @@ fn parse_statement1<T: Field>(
},
Err(err) => Err(err),
},
(Token::Comma, s1, p1) => match parse_identifier_list1(ide, s1, p1) { // if we find a comma, parse the rest of the destructure
Ok((e2, s2, p2)) => match next_token(&s2, &p2) { // then we should have an equal sign
(Token::Eq, s3, p3) => match parse_expr(&s3, &p3) {
Ok((e4, s4, p4)) => {
Ok((Statement::MultipleDefinition(e2, e4), s4, p4)) // output a multipledefinition with the destructure and the expression
},
Err(err) => Err(err)
},
(t3, _, p3) => Err(Error {
expected: vec![
Token::Eq
],
got: t3,
pos: p3,
}),
},
Err(err) => Err(err)
},
_ => match parse_term1(Expression::Identifier(ide), input, pos) {
Ok((e2, s2, p2)) => match parse_expr1(e2, s2, p2) {
Ok((e3, s3, p3)) => match next_token(&s3, &p3) {
@ -1067,27 +1115,20 @@ fn parse_statement<T: Field>(
pos: p2,
}),
},
(Token::Return, s1, p1) => match parse_expr(&s1, &p1) {
Ok((expr, s2, p2)) => match next_token(&s2, &p2) {
(Token::Return, s1, p1) => match parse_expression_list(s1, p1) {
Ok((e2, s2, p2)) => match next_token(&s2, &p2) {
(Token::InlineComment(_), ref s3, _) => {
assert_eq!(s3, "");
Ok((Statement::Return(expr), s2, p2))
Ok((Statement::Return(e2), s2, p2))
}
(Token::Unknown(ref t3), ref s3, _) if t3 == "" => {
assert_eq!(s3, "");
Ok((Statement::Return(expr), s2, p2))
Ok((Statement::Return(e2), s2, p2))
}
(t4, _, p4) => Err(Error {
expected: vec![
Token::Add,
Token::Sub,
Token::Pow,
Token::Mult,
Token::Div,
Token::Unknown("".to_string()),
],
got: t4,
pos: p4,
(t3, _, p3) => Err(Error {
expected: vec![Token::Unknown("".to_string())],
got: t3,
pos: p3,
}),
},
Err(err) => Err(err),
@ -1132,8 +1173,55 @@ fn parse_function<T: Field>(
let mut p = p3;
loop {
match next_token(&s, &p) {
(Token::Private, s4, p4) => {
match next_token(&s4, &p4) {
(Token::Ide(x), s5, p5) => {
args.push(Parameter { id: x, private: true });
match next_token(&s5, &p5) {
(Token::Comma, s6, p6) => {
s = s6;
p = p6;
}
(Token::Close, s5, p5) => match next_token(&s5, &p5) {
(Token::Colon, s6, p6) => match next_token(&s6, &p6) {
(Token::InlineComment(_), _, _) => break,
(Token::Unknown(ref x6), ..) if x6 == "" => break,
(t6, _, p6) => {
return Err(Error {
expected: vec![Token::Unknown("".to_string())],
got: t6,
pos: p6,
})
}
},
(t6, _, p6) => {
return Err(Error {
expected: vec![Token::Colon],
got: t6,
pos: p6,
})
}
},
(t5, _, p5) => {
return Err(Error {
expected: vec![Token::Comma, Token::Close],
got: t5,
pos: p5,
})
}
}
}
(t5, _, p5) => {
return Err(Error {
expected: vec![Token::Comma, Token::Close],
got: t5,
pos: p5,
})
}
}
}
(Token::Ide(x), s4, p4) => {
args.push(Parameter { id: x });
args.push(Parameter { id: x, private: false });
match next_token(&s4, &p4) {
(Token::Comma, s5, p5) => {
s = s5;
@ -1222,6 +1310,7 @@ fn parse_function<T: Field>(
// parse function body
let mut stats = Vec::new();
let return_count;
loop {
match lines.next() {
Some(Ok(ref x)) if x.trim().starts_with("//") || x.trim() == "" => {} // skip
@ -1233,8 +1322,9 @@ fn parse_function<T: Field>(
col: 1,
},
) {
Ok((statement @ Statement::Return(_), ..)) => {
stats.push(statement);
Ok((Statement::Return(list), ..)) => {
return_count = list.expressions.len();
stats.push(Statement::Return(list));
break;
}
Ok((statement, _, pos)) => {
@ -1259,6 +1349,7 @@ fn parse_function<T: Field>(
id: id,
arguments: args,
statements: stats,
return_count: return_count
},
Position {
line: current_line,
@ -1285,23 +1376,6 @@ pub fn parse_program<T: Field>(file: File) -> Result<Prog<T>, Error<T>> {
) {
(Token::Def, ref s1, ref p1) => match parse_function(&mut lines, s1, p1) {
Ok((function, p2)) => {
// panic if signature is not unique
match functions.iter().find(|x: &&Function<T>| {
x.id == function.id && x.arguments.len() == function.arguments.len()
}) {
Some(_) => panic!(
"Error while reading function: {}({}). Duplicate function signatures.",
function.id,
function
.arguments
.iter()
.map(|x| format!("{}", x))
.collect::<Vec<_>>()
.join(",")
),
_ => {}
}
functions.push(function);
current_line = p2.line; // this is the line of the return statement
current_line += 1;
@ -1321,25 +1395,47 @@ pub fn parse_program<T: Field>(file: File) -> Result<Prog<T>, Error<T>> {
}
}
//check if exactly one main function exists
let mut has_main = false;
for func in &functions {
if func.id == "main".to_string() {
if !has_main {
has_main = true;
} else {
panic!("Error while parsing program: Multiple main functions!");
}
}
}
if !has_main {
panic!("Error while parsing program: No main function found.")
};
Ok(Prog { functions })
}
fn parse_comma_separated_expression_list_rec<T: Field>(
input: String,
pos: Position,
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::<FieldPrime>(&s1, &p1) {
(Token::Comma, s2, p2) => parse_comma_separated_expression_list_rec(s2, p2, &mut acc),
(..) => Ok((acc.clone(), s1, p1)),
}
},
Err(err) => Err(err)
}
}
fn parse_comma_separated_identifier_list_rec<T: Field>(
input: String,
pos: Position,
mut acc: &mut Vec<String>
) -> Result<(Vec<String>, String, Position), Error<T>> {
match next_token(&input, &pos) {
(Token::Ide(id), s1, p1) => {
acc.push(id);
match next_token::<FieldPrime>(&s1, &p1) {
(Token::Comma, s2, p2) => parse_comma_separated_identifier_list_rec(s2, p2, &mut acc),
(..) => Ok((acc.to_vec(), s1, p1)),
}
},
(t1, _, p1) => Err(Error {
expected: vec![Token::Ide(String::from("ide"))],
got: t1,
pos: p1,
})
}
}
#[cfg(test)]
mod tests {
@ -1520,6 +1616,87 @@ mod tests {
}
}
#[cfg(test)]
mod parse_comma_separated_list {
use super::*;
fn parse_comma_separated_list<T: Field>(
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)
}
#[test]
fn comma_separated_list() {
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"))]
};
assert_eq!(
Ok((expr, String::from(""), pos.col(string.len() as isize))),
parse_expression_list(string, pos)
)
}
#[test]
fn comma_separated_list_single() {
let pos = Position { line: 45, col: 121 };
let string = String::from("a");
let exprs = ExpressionList {
expressions: vec![Expression::Identifier(String::from("a"))]
};
assert_eq!(
Ok((exprs, String::from(""), pos.col(string.len() as isize))),
parse_comma_separated_list::<FieldPrime>(string, pos)
)
}
#[test]
fn comma_separated_list_three() {
let pos = Position { line: 45, col: 121 };
let string = String::from("a, b, c");
let exprs = ExpressionList {
expressions: vec![
Expression::Identifier(String::from("a")),
Expression::Identifier(String::from("b")),
Expression::Identifier(String::from("c"))
]
};
assert_eq!(
Ok((exprs, String::from(""), pos.col(string.len() as isize))),
parse_comma_separated_list::<FieldPrime>(string, pos)
)
}
// test impossible to run forever?
}
// #[cfg(test)]
// mod parse_program {
// use super::*;
// #[test]
// fn single_output() {
// let pos = Position { line: 45, col: 121 };
// let string = "
// def foo():
// return 1
// ";
// let fun = Function {
// id: "foo".to_string(),
// arguments: vec![],
// statements: vec![Expression::Return(Expression::Number(FieldPrime::from(1)))],
// return_count: 1
// };
// assert_eq!(
// Ok((fun, String::from(""), pos.col(string.len() as isize))),
// parse_function(string, pos)
// )
// }
// }
// parse function
// parse_term1
// parse_term

View file

@ -290,49 +290,58 @@ pub fn r1cs_program<T: Field>(
.iter()
.find(|x: &&Function<T>| x.id == "main".to_string())
.unwrap();
variables.extend(main.arguments.iter().map(|x| format!("{}", x)));
variables.extend(main.arguments.iter().filter(|x| !x.private).map(|x| format!("{}", x)));
// ~out is added after main's arguments as we want variables (columns)
// in the r1cs to be aligned like "public inputs | private inputs"
variables.push("~out".to_string());
for i in 0..main.return_count {
variables.push(format!("~out_{}", i).to_string());
}
// position where private part of witness starts
let private_inputs_offset = variables.len();
for def in &main.statements {
let mut a_row: Vec<(usize, T)> = Vec::new();
let mut b_row: Vec<(usize, T)> = Vec::new();
let mut c_row: Vec<(usize, T)> = Vec::new();
match *def {
Statement::Return(ref expr) => r1cs_expression(
Identifier("~out".to_string()),
expr.clone(),
&mut variables,
&mut a_row,
&mut b_row,
&mut c_row,
),
Statement::Definition(ref id, ref expr) => r1cs_expression(
Identifier(id.to_string()),
expr.clone(),
&mut variables,
&mut a_row,
&mut b_row,
&mut c_row,
),
Statement::Condition(ref expr1, ref expr2) => r1cs_expression(
expr1.clone(),
expr2.clone(),
&mut variables,
&mut a_row,
&mut b_row,
&mut c_row,
),
Statement::Return(ref list) => {
for (i, val) in list.expressions.iter().enumerate() {
let mut a_row: Vec<(usize, T)> = Vec::new();
let mut b_row: Vec<(usize, T)> = Vec::new();
let mut c_row: Vec<(usize, T)> = Vec::new();
r1cs_expression(
Identifier(format!("~out_{}", i).to_string()),
val.clone(),
&mut variables,
&mut a_row,
&mut b_row,
&mut c_row,
);
a.push(a_row);
b.push(b_row);
c.push(c_row);
}
},
Statement::Definition(_, _) => continue,
Statement::Condition(ref expr1, ref expr2) => {
let mut a_row: Vec<(usize, T)> = Vec::new();
let mut b_row: Vec<(usize, T)> = Vec::new();
let mut c_row: Vec<(usize, T)> = Vec::new();
r1cs_expression(
expr1.clone(),
expr2.clone(),
&mut variables,
&mut a_row,
&mut b_row,
&mut c_row,
);
a.push(a_row);
b.push(b_row);
c.push(c_row);
},
Statement::For(..) => panic!("For-loop not flattened"),
Statement::Compiler(..) => continue,
Statement::MultipleDefinition(..) => unimplemented!(),
}
a.push(a_row);
b.push(b_row);
c.push(c_row);
}
(variables, private_inputs_offset, a, b, c)
}

705
src/semantics.rs Normal file
View file

@ -0,0 +1,705 @@
//! Module containing semantic analysis tools to run at compile time
//! The goal is to detect semantic errors such as undefined variables
//! A variable is undefined if it isn't present in the static scope
//!
//! @file semantics.rs
//! @author Thibaut Schaeffer <thibaut@schaeff.fr>
//! @date 2017
use std::collections::HashSet;
use absy::*;
use field::Field;
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct Symbol {
id: String,
level: usize
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct FunctionDeclaration {
id: String,
return_count: usize,
arg_count: usize,
}
// Checker, checks the semantics of a program.
pub struct Checker {
scope: HashSet<Symbol>,
functions: HashSet<FunctionDeclaration>,
level: usize
}
impl Checker {
pub fn new() -> Checker {
Checker {
scope: HashSet::new(),
functions: HashSet::new(),
level: 0
}
}
#[test]
pub fn new_with_args(scope: HashSet<Symbol>, level: usize, functions: HashSet<FunctionDeclaration>) -> Checker {
Checker {
scope: scope,
functions: functions,
level: level,
}
}
pub fn check_program<T: Field>(&mut self, prog: Prog<T>) -> Result<(), String> {
for func in prog.functions {
self.check_function(&func)?;
self.functions.insert(FunctionDeclaration {
id: func.id,
return_count: func.return_count,
arg_count: func.arguments.len()
});
}
self.check_single_main()?;
Ok(())
}
fn check_single_main(&mut self) -> Result<(), String> {
match self.functions.clone().into_iter().filter(|fun| fun.id == "main").count() {
1 => Ok(()),
0 => Err((format!("No main function found"))),
n => Err((format!("Only one main function allowed, found {}", n)))
}
}
fn check_function<T: Field>(&mut self, funct: &Function<T>) -> Result<(), String> {
match self.find_function(&funct.id, funct.arguments.len()) {
Some(_) => {
return Err(format!("Duplicate definition for function {} with {} arguments", funct.id, funct.arguments.len()))
},
None => {
}
}
self.level += 1;
for arg in funct.arguments.clone() {
self.scope.insert(Symbol {
id: arg.id.to_string(),
level: self.level
});
}
for stat in funct.statements.clone() {
self.check_statement(stat)?;
}
let current_level = self.level.clone();
let current_scope = self.scope.clone();
let to_remove = current_scope.iter().filter(|symbol| symbol.level == current_level);
for symbol in to_remove {
self.scope.remove(symbol);
}
self.level -= 1;
Ok(())
}
fn check_statement<T: Field>(&mut self, stat: Statement<T>) -> Result<(), String> {
match stat {
Statement::Return(list) => {
self.check_expression_list(list)?;
Ok(())
}
Statement::Definition(id, expr) | Statement::Compiler(id, expr) => {
self.check_expression(expr)?;
self.scope.insert(Symbol {
id: id.to_string(),
level: self.level
});
Ok(())
}
Statement::Condition(lhs, rhs) => {
self.check_expression(lhs)?;
self.check_expression(rhs)?;
Ok(())
}
Statement::For(id, _, _, statements) => {
self.level += 1;
let index = Symbol {
id: id.to_string(),
level: self.level
};
self.scope.insert(index.clone());
for stat in statements {
self.check_statement(stat)?;
}
self.scope.remove(&index);
self.level -= 1;
Ok(())
},
Statement::MultipleDefinition(ids, rhs) => {
// All elements of the left side have to be identifiers
match rhs {
// Right side has to be a function call
Expression::FunctionCall(ref fun_id, ref arguments) => {
match self.find_function(fun_id, arguments.len()) {
// the function has to be defined
Some(f) => {
if f.return_count == ids.len() {
// the return count has to match the left side
for id in ids {
self.scope.insert(Symbol {
id: id.to_string(),
level: self.level
});
}
return Ok(())
}
Err(format!("{} returns {} values but left side is of size {}", f.id, f.return_count, ids.len()))
},
None => Err(format!("Function definition for function {} with {} argument(s) not found.", fun_id, arguments.len()))
}
},
_ => Err(format!("{} should be a FunctionCall", rhs))
}
},
}
}
fn check_expression<T: Field>(&mut self, expr: Expression<T>) -> Result<(), String> {
match expr {
Expression::Identifier(id) => {
// check that `id` is defined in the scope
match self.scope.iter().find(|symbol| symbol.id == id.to_string()) {
Some(_) => Ok(()),
None => Err(format!("{} is undefined", id.to_string())),
}
}
Expression::Add(box e1, box e2) | Expression::Sub(box e1, box e2) | Expression::Mult(box e1, box e2) |
Expression::Div(box e1, box e2) | Expression::Pow(box e1, box e2) => {
self.check_expression(e1)?;
self.check_expression(e2)?;
Ok(())
}
Expression::IfElse(box condition, box consequence, box alternative) => {
self.check_condition(condition)?;
self.check_expression(consequence)?;
self.check_expression(alternative)?;
Ok(())
}
Expression::FunctionCall(ref fun_id, ref arguments) => {
match self.find_function(fun_id, arguments.len()) {
// the function has to be defined
Some(f) => {
if f.return_count == 1 { // Functions must return a single value when not in a MultipleDefinition
for expr in arguments {
self.check_expression(expr.clone())?;
}
return Ok(())
}
Err(format!("{} returns {} values but is called outside of a definition", fun_id, f.return_count))
},
None => Err(format!("Function definition for function {} with {} argument(s) not found.", fun_id, arguments.len()))
}
}
Expression::Number(_) => Ok(())
}
}
fn check_expression_list<T: Field>(&mut self, list: ExpressionList<T>) -> Result<(), String> {
for expr in list.expressions { // implement Iterator trait?
self.check_expression(expr)?
}
Ok(())
}
fn check_condition<T: Field>(&mut self, cond: Condition<T>) -> Result<(), String> {
match cond {
Condition::Lt(e1, e2) |
Condition::Le(e1, e2) |
Condition::Eq(e1, e2) |
Condition::Ge(e1, e2) |
Condition::Gt(e1, e2) => {
self.check_expression(e1)?;
self.check_expression(e2)?;
Ok(())
}
}
}
fn find_function(&mut self, id: &str, arg_count: usize) -> Option<FunctionDeclaration> {
self.functions.clone().into_iter().find(|fun| fun.id == id && fun.arg_count == arg_count)
}
}
#[cfg(test)]
mod tests {
use super::*;
use field::FieldPrime;
#[test]
fn undefined_variable_in_statement() {
// a = b
// b undefined
let statement: Statement<FieldPrime> = Statement::Definition(
String::from("a"),
Expression::Identifier(String::from("b"))
);
let mut checker = Checker::new();
assert_eq!(checker.check_statement(statement), Err("b is undefined".to_string()));
}
#[test]
fn defined_variable_in_statement() {
// a = b
// b defined
let statement: Statement<FieldPrime> = Statement::Definition(
String::from("a"),
Expression::Identifier(String::from("b"))
);
let mut scope = HashSet::new();
scope.insert(Symbol {
id: String::from("b"),
level: 0
});
let mut checker = Checker::new_with_args(scope, 1, HashSet::new());
assert_eq!(checker.check_statement(statement), Ok(()));
}
#[test]
fn declared_in_other_function() {
// def foo():
// a = 1
// def bar():
// return a
// should fail
let foo_args = Vec::<Parameter>::new();
let mut foo_statements = Vec::<Statement<FieldPrime>>::new();
foo_statements.push(Statement::Definition(
String::from("a"),
Expression::Number(FieldPrime::from(1)))
);
let foo = Function {
id: "foo".to_string(),
arguments: foo_args,
statements: foo_statements,
return_count: 1,
};
let bar_args = Vec::<Parameter>::new();
let mut bar_statements = Vec::<Statement<FieldPrime>>::new();
bar_statements.push(Statement::Return(
ExpressionList {
expressions: vec![Expression::Identifier(String::from("a"))]
}
));
let bar = Function {
id: "bar".to_string(),
arguments: bar_args,
statements: bar_statements,
return_count: 1,
};
let mut funcs = Vec::<Function<FieldPrime>>::new();
funcs.push(foo);
funcs.push(bar);
let prog = Prog {
functions: funcs
};
let mut checker = Checker::new();
assert_eq!(checker.check_program(prog), Err("a is undefined".to_string()));
}
#[test]
fn declared_in_two_scopes() {
// def foo():
// a = 1
// def bar():
// a = 2
// return a
// def main():
// return 1
// should pass
let foo_args = Vec::<Parameter>::new();
let mut foo_statements = Vec::<Statement<FieldPrime>>::new();
foo_statements.push(Statement::Definition(
String::from("a"),
Expression::Number(FieldPrime::from(1)))
);
let foo = Function {
id: "foo".to_string(),
arguments: foo_args,
statements: foo_statements,
return_count: 1,
};
let bar_args = Vec::<Parameter>::new();
let mut bar_statements = Vec::<Statement<FieldPrime>>::new();
bar_statements.push(Statement::Definition(
String::from("a"),
Expression::Number(FieldPrime::from(2))
));
bar_statements.push(Statement::Return(
ExpressionList {
expressions: vec![Expression::Identifier(String::from("a"))]
}
));
let bar = Function {
id: "bar".to_string(),
arguments: bar_args,
statements: bar_statements,
return_count: 1,
};
let main_args = Vec::<Parameter>::new();
let mut main_statements = Vec::<Statement<FieldPrime>>::new();
main_statements.push(Statement::Return(
ExpressionList {
expressions: vec![Expression::Number(FieldPrime::from(1))]
})
);
let main = Function {
id: "main".to_string(),
arguments: main_args,
statements: main_statements,
return_count: 1,
};
let mut funcs = Vec::<Function<FieldPrime>>::new();
funcs.push(foo);
funcs.push(bar);
funcs.push(main);
let prog = Prog {
functions: funcs
};
let mut checker = Checker::new();
assert_eq!(checker.check_program(prog), Ok(()));
}
#[test]
fn for_index_after_end() {
// def foo():
// for i in 0..10 do
// endfor
// return i
// should fail
let mut foo_statements = Vec::<Statement<FieldPrime>>::new();
foo_statements.push(Statement::For(
String::from("i"),
FieldPrime::from(0),
FieldPrime::from(10),
Vec::<Statement<FieldPrime>>::new())
);
foo_statements.push(Statement::Return(
ExpressionList {
expressions: vec![Expression::Identifier(String::from("i"))]
}
));
let foo = Function {
id: "foo".to_string(),
arguments: Vec::<Parameter>::new(),
statements: foo_statements,
return_count: 1,
};
let mut checker = Checker::new();
assert_eq!(checker.check_function(&foo), Err("i is undefined".to_string()));
}
#[test]
fn for_index_in_for() {
// def foo():
// for i in 0..10 do
// a = i
// endfor
// should pass
let mut foo_statements = Vec::<Statement<FieldPrime>>::new();
let mut for_statements = Vec::<Statement<FieldPrime>>::new();
for_statements.push(Statement::Definition(
String::from("a"),
Expression::Identifier(String::from("i"))
));
foo_statements.push(Statement::For(
String::from("i"),
FieldPrime::from(0),
FieldPrime::from(10),
for_statements
));
let foo = Function {
id: "foo".to_string(),
arguments: Vec::<Parameter>::new(),
statements: foo_statements,
return_count: 1,
};
let mut checker = Checker::new();
assert_eq!(checker.check_function(&foo), Ok(()));
}
#[test]
fn arity_mismatch() {
// def foo():
// return 1, 2
// def bar():
// c = foo()
// should fail
let bar_statements: Vec<Statement<FieldPrime>> = vec![Statement::MultipleDefinition(
vec!["c".to_string()],
Expression::FunctionCall("foo".to_string(), vec![])
)];
let foo = FunctionDeclaration {
id: "foo".to_string(),
arg_count: 0,
return_count: 2,
};
let mut functions = HashSet::new();
functions.insert(foo);
let bar = Function {
id: "bar".to_string(),
arguments: vec![],
statements: bar_statements,
return_count: 1
};
let mut checker = Checker::new_with_args(HashSet::new(), 0, functions);
assert_eq!(checker.check_function(bar), Err("foo returns 2 values but left side is of size 1".to_string()));
}
#[test]
fn multi_return_outside_multidef() {
// def foo():
// return 1, 2
// def bar():
// 4 == foo()
// should fail
let bar_statements: Vec<Statement<FieldPrime>> = vec![Statement::Condition(
Expression::Number(FieldPrime::from(2)),
Expression::FunctionCall("foo".to_string(), vec![])
)];
let foo = FunctionDeclaration {
id: "foo".to_string(),
arg_count: 0,
return_count: 2,
};
let mut functions = HashSet::new();
functions.insert(foo);
let bar = Function {
id: "bar".to_string(),
arguments: vec![],
statements: bar_statements,
return_count: 1
};
let mut checker = Checker::new_with_args(HashSet::new(), 0, functions);
assert_eq!(checker.check_function(bar), Err("foo returns 2 values but is called outside of a definition".to_string()));
}
#[test]
fn function_undefined_in_multidef() {
// def bar():
// c = foo()
// should fail
let bar_statements: Vec<Statement<FieldPrime>> = vec![Statement::MultipleDefinition(
vec!["c".to_string()],
Expression::FunctionCall("foo".to_string(), vec![])
)];
let bar = Function {
id: "bar".to_string(),
arguments: vec![],
statements: bar_statements,
return_count: 1
};
let mut checker = Checker::new_with_args(HashSet::new(), 0, HashSet::new());
assert_eq!(checker.check_function(bar), Err("Function definition for function foo with 0 argument(s) not found.".to_string()));
}
#[test]
fn function_undefined() {
// def bar():
// 1 = foo()
// should fail
let bar_statements: Vec<Statement<FieldPrime>> = vec![Statement::Condition(
Expression::Number(FieldPrime::from(1)),
Expression::FunctionCall("foo".to_string(), vec![])
)];
let bar = Function {
id: "bar".to_string(),
arguments: vec![],
statements: bar_statements,
return_count: 1
};
let mut checker = Checker::new_with_args(HashSet::new(), 0, HashSet::new());
assert_eq!(checker.check_function(bar), Err("Function definition for function foo with 0 argument(s) not found.".to_string()));
}
#[test]
fn return_undefined() {
// def bar():
// return a, b
// should fail
let bar_statements: Vec<Statement<FieldPrime>> = vec![Statement::Return(
ExpressionList { expressions: vec![
Expression::Identifier("a".to_string()),
Expression::Identifier("b".to_string())
]}
)];
let bar = Function {
id: "bar".to_string(),
arguments: vec![],
statements: bar_statements,
return_count: 2
};
let mut checker = Checker::new_with_args(HashSet::new(), 0, HashSet::new());
assert_eq!(checker.check_function(bar), Err("a is undefined".to_string()));
}
#[test]
fn multi_def() {
// def foo():
// return 1, 2
// def bar():
// a, b = foo()
// return a + b
//
// should pass
let bar_statements: Vec<Statement<FieldPrime>> = vec![
Statement::MultipleDefinition(
vec!["a".to_string(), "b".to_string()],
Expression::FunctionCall("foo".to_string(), vec![])
),
Statement::Return(
ExpressionList { expressions: vec![
Expression::Add(
box Expression::Identifier("a".to_string()),
box Expression::Identifier("b".to_string())
)]
}
)
];
let foo = FunctionDeclaration {
id: "foo".to_string(),
arg_count: 0,
return_count: 2,
};
let mut functions = HashSet::new();
functions.insert(foo);
let bar = Function {
id: "bar".to_string(),
arguments: vec![],
statements: bar_statements,
return_count: 1
};
let mut checker = Checker::new_with_args(HashSet::new(), 0, functions);
assert_eq!(checker.check_function(&bar), Ok(()));
}
#[test]
fn duplicate_function_declaration() {
// def foo(a, b):
// return 1
// def foo(c, d):
// return 2
//
// should fail
let foo2_statements: Vec<Statement<FieldPrime>> = vec![
Statement::Return(
ExpressionList {
expressions: vec![
Expression::Number(FieldPrime::from(1))
]
}
)
];
let foo2_arguments = vec![
Parameter { id: 'c'.to_string(), private: true },
Parameter { id: 'd'.to_string(), private: true }
];
let foo1 = FunctionDeclaration {
id: "foo".to_string(),
arg_count: 2,
return_count: 1,
};
let mut functions = HashSet::new();
functions.insert(foo1);
let foo2 = Function {
id: "foo".to_string(),
arguments: foo2_arguments,
statements: foo2_statements,
return_count: 1
};
let mut checker = Checker::new_with_args(HashSet::new(), 0, functions);
assert_eq!(checker.check_function(&foo2), Err(("Duplicate definition for function foo with 2 arguments".to_string())));
}
#[test]
fn duplicate_main_function() {
// def main(a):
// return 1
// def main():
// return 1
//
// should fail
let main1_statements: Vec<Statement<FieldPrime>> = vec![
Statement::Return(
ExpressionList {
expressions: vec![
Expression::Number(FieldPrime::from(1))
]
}
)
];
let main1_arguments = vec![Parameter { id: 'a'.to_string(), private: false }];
let main2_statements: Vec<Statement<FieldPrime>> = vec![
Statement::Return(
ExpressionList {
expressions: vec![
Expression::Number(FieldPrime::from(1))
]
}
)
];
let main2_arguments = vec![];
let main1 = Function {
id: "main".to_string(),
arguments: main1_arguments,
statements: main1_statements,
return_count: 1,
};
let main2 = Function {
id: "main".to_string(),
arguments: main2_arguments,
statements: main2_statements,
return_count: 1,
};
let prog = Prog {
functions: vec![main1, main2]
};
let mut checker = Checker::new();
assert_eq!(checker.check_program(prog), Err(("Only one main function allowed, found 2".to_string())));
}
}

View file

@ -1,3 +1,10 @@
pub const CONTRACT_TEMPLATE: &str = r#"// This file is MIT Licensed.
//
// Copyright 2017 Christian Reitwiessner
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
pragma solidity ^0.4.14;
library Pairing {
struct G1Point {
@ -223,3 +230,4 @@ contract Verifier {
}
}
}
"#;

View file

@ -1,291 +0,0 @@
// This file is MIT Licensed.
//
// Copyright 2017 Christian Reitwiessner
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
pragma solidity ^0.4.14;
library Pairing {
struct G1Point {
uint X;
uint Y;
}
// Encoding of field elements is: X[0] * z + X[1]
struct G2Point {
uint[2] X;
uint[2] Y;
}
/// @return the generator of G1
function P1() internal returns (G1Point) {
return G1Point(1, 2);
}
/// @return the generator of G2
function P2() internal returns (G2Point) {
return G2Point(
[11559732032986387107991004021392285783925812861821192530917403151452391805634,
10857046999023057135944570762232829481370756359578518086990519993285655852781],
[4082367875863433681332203403145435568316851327593401208105741076214120093531,
8495653923123431417604973247489272438418190587263600148770280649306958101930]
);
}
/// @return the negation of p, i.e. p.add(p.negate()) should be zero.
function negate(G1Point p) internal returns (G1Point) {
// The prime q in the base field F_q for G1
uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
if (p.X == 0 && p.Y == 0)
return G1Point(0, 0);
return G1Point(p.X, q - (p.Y % q));
}
/// @return the sum of two points of G1
function add(G1Point p1, G1Point p2) internal returns (G1Point r) {
uint[4] memory input;
input[0] = p1.X;
input[1] = p1.Y;
input[2] = p2.X;
input[3] = p2.Y;
bool success;
assembly {
success := call(sub(gas, 2000), 6, 0, input, 0xc0, r, 0x60)
// Use "invalid" to make gas estimation work
switch success case 0 { invalid }
}
require(success);
}
/// @return the product of a point on G1 and a scalar, i.e.
/// p == p.mul(1) and p.add(p) == p.mul(2) for all points p.
function mul(G1Point p, uint s) internal returns (G1Point r) {
uint[3] memory input;
input[0] = p.X;
input[1] = p.Y;
input[2] = s;
bool success;
assembly {
success := call(sub(gas, 2000), 7, 0, input, 0x80, r, 0x60)
// Use "invalid" to make gas estimation work
switch success case 0 { invalid }
}
require (success);
}
/// @return the result of computing the pairing check
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should
/// return true.
function pairing(G1Point[] p1, G2Point[] p2) internal returns (bool) {
require(p1.length == p2.length);
uint elements = p1.length;
uint inputSize = elements * 6;
uint[] memory input = new uint[](inputSize);
for (uint i = 0; i < elements; i++)
{
input[i * 6 + 0] = p1[i].X;
input[i * 6 + 1] = p1[i].Y;
input[i * 6 + 2] = p2[i].X[0];
input[i * 6 + 3] = p2[i].X[1];
input[i * 6 + 4] = p2[i].Y[0];
input[i * 6 + 5] = p2[i].Y[1];
}
uint[1] memory out;
bool success;
assembly {
success := call(sub(gas, 2000), 8, 0, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
// Use "invalid" to make gas estimation work
switch success case 0 { invalid }
}
require(success);
return out[0] != 0;
}
/// Convenience method for a pairing check for two pairs.
function pairingProd2(G1Point a1, G2Point a2, G1Point b1, G2Point b2) internal returns (bool) {
G1Point[] memory p1 = new G1Point[](2);
G2Point[] memory p2 = new G2Point[](2);
p1[0] = a1;
p1[1] = b1;
p2[0] = a2;
p2[1] = b2;
return pairing(p1, p2);
}
/// Convenience method for a pairing check for three pairs.
function pairingProd3(
G1Point a1, G2Point a2,
G1Point b1, G2Point b2,
G1Point c1, G2Point c2
) internal returns (bool) {
G1Point[] memory p1 = new G1Point[](3);
G2Point[] memory p2 = new G2Point[](3);
p1[0] = a1;
p1[1] = b1;
p1[2] = c1;
p2[0] = a2;
p2[1] = b2;
p2[2] = c2;
return pairing(p1, p2);
}
/// Convenience method for a pairing check for four pairs.
function pairingProd4(
G1Point a1, G2Point a2,
G1Point b1, G2Point b2,
G1Point c1, G2Point c2,
G1Point d1, G2Point d2
) internal returns (bool) {
G1Point[] memory p1 = new G1Point[](4);
G2Point[] memory p2 = new G2Point[](4);
p1[0] = a1;
p1[1] = b1;
p1[2] = c1;
p1[3] = d1;
p2[0] = a2;
p2[1] = b2;
p2[2] = c2;
p2[3] = d2;
return pairing(p1, p2);
}
}
contract Test {
using Pairing for *;
struct VerifyingKey {
Pairing.G2Point A;
Pairing.G1Point B;
Pairing.G2Point C;
Pairing.G2Point gamma;
Pairing.G1Point gammaBeta1;
Pairing.G2Point gammaBeta2;
Pairing.G2Point Z;
Pairing.G1Point[] IC;
}
struct Proof {
Pairing.G1Point A;
Pairing.G1Point A_p;
Pairing.G2Point B;
Pairing.G1Point B_p;
Pairing.G1Point C;
Pairing.G1Point C_p;
Pairing.G1Point K;
Pairing.G1Point H;
}
function f() returns (bool) {
Pairing.G1Point memory p1;
Pairing.G1Point memory p2;
p1.X = 1; p1.Y = 2;
p2.X = 1; p2.Y = 2;
var explict_sum = Pairing.add(p1, p2);
var scalar_prod = Pairing.mul(p1, 2);
return (explict_sum.X == scalar_prod.X &&
explict_sum.Y == scalar_prod.Y);
}
function g() returns (bool) {
Pairing.G1Point memory x = Pairing.add(Pairing.P1(), Pairing.negate(Pairing.P1()));
// should be zero
return (x.X == 0 && x.Y == 0);
}
function testMul() returns (bool) {
Pairing.G1Point memory p;
// @TODO The points here are reported to be not well-formed
p.X = 14125296762497065001182820090155008161146766663259912659363835465243039841726;
p.Y = 16229134936871442251132173501211935676986397196799085184804749187146857848057;
p = Pairing.mul(p, 13986731495506593864492662381614386532349950841221768152838255933892789078521);
return
p.X == 18256332256630856740336504687838346961237861778318632856900758565550522381207 &&
p.Y == 6976682127058094634733239494758371323697222088503263230319702770853579280803;
}
function pair() returns (bool) {
Pairing.G2Point memory fiveTimesP2 = Pairing.G2Point(
[4540444681147253467785307942530223364530218361853237193970751657229138047649, 20954117799226682825035885491234530437475518021362091509513177301640194298072],
[11631839690097995216017572651900167465857396346217730511548857041925508482915, 21508930868448350162258892668132814424284302804699005394342512102884055673846]
);
// The prime p in the base field F_p for G1
uint p = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
Pairing.G1Point[] memory g1points = new Pairing.G1Point[](2);
Pairing.G2Point[] memory g2points = new Pairing.G2Point[](2);
// // check e(5 P1, P2)e(-P1, 5 P2) == 1
g1points[0] = Pairing.P1().mul(5);
g1points[1] = Pairing.P1();
g1points[1].Y = p - g1points[1].Y;
g2points[0] = Pairing.P2();
g2points[1] = fiveTimesP2;
if (!Pairing.pairing(g1points, g2points))
return false;
// check e(P1, P2)e(-P1, P2) == 0
g1points[0] = Pairing.P1();
g1points[1] = Pairing.P1().negate();
g2points[0] = Pairing.P2();
g2points[1] = Pairing.P2();
if (!Pairing.pairing(g1points, g2points))
return false;
return true;
}
function verifyingKey() internal returns (VerifyingKey vk) {
vk.A = Pairing.G2Point([0x209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf7, 0x04bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a41678], [0x2bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d, 0x120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550]);
vk.B = Pairing.G1Point(0x2eca0c7238bf16e83e7a1e6c5d49540685ff51380f309842a98561558019fc02, 0x03d3260361bb8451de5ff5ecd17f010ff22f5c31cdf184e9020b06fa5997db84);
vk.C = Pairing.G2Point([0x2e89718ad33c8bed92e210e81d1853435399a271913a6520736a4729cf0d51eb, 0x01a9e2ffa2e92599b68e44de5bcf354fa2642bd4f26b259daa6f7ce3ed57aeb3], [0x14a9a87b789a58af499b314e13c3d65bede56c07ea2d418d6874857b70763713, 0x178fb49a2d6cd347dc58973ff49613a20757d0fcc22079f9abd10c3baee24590]);
vk.gamma = Pairing.G2Point([0x25f83c8b6ab9de74e7da488ef02645c5a16a6652c3c71a15dc37fe3a5dcb7cb1, 0x22acdedd6308e3bb230d226d16a105295f523a8a02bfc5e8bd2da135ac4c245d], [0x065bbad92e7c4e31bf3757f1fe7362a63fbfee50e7dc68da116e67d600d9bf68, 0x06d302580dc0661002994e7cd3a7f224e7ddc27802777486bf80f40e4ca3cfdb]);
vk.gammaBeta1 = Pairing.G1Point(0x15794ab061441e51d01e94640b7e3084a07e02c78cf3103c542bc5b298669f21, 0x14db745c6780e9df549864cec19c2daf4531f6ec0c89cc1c7436cc4d8d300c6d);
vk.gammaBeta2 = Pairing.G2Point([0x1f39e4e4afc4bc74790a4a028aff2c3d2538731fb755edefd8cb48d6ea589b5e, 0x283f150794b6736f670d6a1033f9b46c6f5204f50813eb85c8dc4b59db1c5d39], [0x140d97ee4d2b36d99bc49974d18ecca3e7ad51011956051b464d9e27d46cc25e, 0x0764bb98575bd466d32db7b15f582b2d5c452b36aa394b789366e5e3ca5aabd4]);
vk.Z = Pairing.G2Point([0x217cee0a9ad79a4493b5253e2e4e3a39fc2df38419f230d341f60cb064a0ac29, 0x0a3d76f140db8418ba512272381446eb73958670f00cf46f1d9e64cba057b53c], [0x26f64a8ec70387a13e41430ed3ee4a7db2059cc5fc13c067194bcc0cb49a9855, 0x2fd72bd9edb657346127da132e5b82ab908f5816c826acb499e22f2412d1a2d7]);
vk.IC = new Pairing.G1Point[](10);
vk.IC[0] = Pairing.G1Point(0x0aee46a7ea6e80a3675026dfa84019deee2a2dedb1bbe11d7fe124cb3efb4b5a, 0x044747b6e9176e13ede3a4dfd0d33ccca6321b9acd23bf3683a60adc0366ebaf);
vk.IC[1] = Pairing.G1Point(0x1e39e9f0f91fa7ff8047ffd90de08785777fe61c0e3434e728fce4cf35047ddc, 0x2e0b64d75ebfa86d7f8f8e08abbe2e7ae6e0a1c0b34d028f19fa56e9450527cb);
vk.IC[2] = Pairing.G1Point(0x1c36e713d4d54e3a9644dffca1fc524be4868f66572516025a61ca542539d43f, 0x042dcc4525b82dfb242b09cb21909d5c22643dcdbe98c4d082cc2877e96b24db);
vk.IC[3] = Pairing.G1Point(0x17d5d09b4146424bff7e6fb01487c477bbfcd0cdbbc92d5d6457aae0b6717cc5, 0x02b5636903efbf46db9235bbe74045d21c138897fda32e079040db1a16c1a7a1);
vk.IC[4] = Pairing.G1Point(0x0f103f14a584d4203c27c26155b2c955f8dfa816980b24ba824e1972d6486a5d, 0x0c4165133b9f5be17c804203af781bcf168da7386620479f9b885ecbcd27b17b);
vk.IC[5] = Pairing.G1Point(0x232063b584fb76c8d07995bee3a38fa7565405f3549c6a918ddaa90ab971e7f8, 0x2ac9b135a81d96425c92d02296322ad56ffb16299633233e4880f95aafa7fda7);
vk.IC[6] = Pairing.G1Point(0x09b54f111d3b2d1b2fe1ae9669b3db3d7bf93b70f00647e65c849275de6dc7fe, 0x18b2e77c63a3e400d6d1f1fbc6e1a1167bbca603d34d03edea231eb0ab7b14b4);
vk.IC[7] = Pairing.G1Point(0x0c54b42137b67cc268cbb53ac62b00ecead23984092b494a88befe58445a244a, 0x18e3723d37fae9262d58b548a0575f59d9c3266db7afb4d5739555837f6b8b3e);
vk.IC[8] = Pairing.G1Point(0x0a6de0e2240aa253f46ce0da883b61976e3588146e01c9d8976548c145fe6e4a, 0x04fbaa3a4aed4bb77f30ebb07a3ec1c7d77a7f2edd75636babfeff97b1ea686e);
vk.IC[9] = Pairing.G1Point(0x111e2e2a5f8828f80ddad08f9f74db56dac1cc16c1cb278036f79a84cf7a116f, 0x1d7d62e192b219b9808faa906c5ced871788f6339e8d91b83ac1343e20a16b30);
}
function verify(uint[] input, Proof proof) internal returns (uint) {
VerifyingKey memory vk = verifyingKey();
require(input.length + 1 == vk.IC.length);
// Compute the linear combination vk_x
Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0);
for (uint i = 0; i < input.length; i++)
vk_x = Pairing.add(vk_x, Pairing.mul(vk.IC[i + 1], input[i]));
vk_x = Pairing.add(vk_x, vk.IC[0]);
if (!Pairing.pairingProd2(proof.A, vk.A, Pairing.negate(proof.A_p), Pairing.P2())) return 1;
if (!Pairing.pairingProd2(vk.B, proof.B, Pairing.negate(proof.B_p), Pairing.P2())) return 2;
if (!Pairing.pairingProd2(proof.C, vk.C, Pairing.negate(proof.C_p), Pairing.P2())) return 3;
if (!Pairing.pairingProd3(
proof.K, vk.gamma,
Pairing.negate(Pairing.add(vk_x, Pairing.add(proof.A, proof.C))), vk.gammaBeta2,
Pairing.negate(vk.gammaBeta1), proof.B
)) return 4;
if (!Pairing.pairingProd3(
Pairing.add(vk_x, proof.A), proof.B,
Pairing.negate(proof.H), vk.Z,
Pairing.negate(proof.C), Pairing.P2()
)) return 5;
return 0;
}
event Verified(string);
function verifyTx() returns (bool r) {
uint[] memory input = new uint[](9);
Proof memory proof;
proof.A = Pairing.G1Point(12873740738727497448187997291915224677121726020054032516825496230827252793177, 21804419174137094775122804775419507726154084057848719988004616848382402162497);
proof.A_p = Pairing.G1Point(7742452358972543465462254569134860944739929848367563713587808717088650354556, 7324522103398787664095385319014038380128814213034709026832529060148225837366);
proof.B = Pairing.G2Point(
[8176651290984905087450403379100573157708110416512446269839297438960217797614, 15588556568726919713003060429893850972163943674590384915350025440408631945055],
[15347511022514187557142999444367533883366476794364262773195059233657571533367, 4265071979090628150845437155927259896060451682253086069461962693761322642015]);
proof.B_p = Pairing.G1Point(2979746655438963305714517285593753729335852012083057917022078236006592638393, 6470627481646078059765266161088786576504622012540639992486470834383274712950);
proof.C = Pairing.G1Point(6851077925310461602867742977619883934042581405263014789956638244065803308498, 10336382210592135525880811046708757754106524561907815205241508542912494488506);
proof.C_p = Pairing.G1Point(12491625890066296859584468664467427202390981822868257437245835716136010795448, 13818492518017455361318553880921248537817650587494176379915981090396574171686);
proof.H = Pairing.G1Point(12091046215835229523641173286701717671667447745509192321596954139357866668225, 14446807589950902476683545679847436767890904443411534435294953056557941441758);
proof.K = Pairing.G1Point(21341087976609916409401737322664290631992568431163400450267978471171152600502, 2942165230690572858696920423896381470344658299915828986338281196715687693170);
input[0] = 13986731495506593864492662381614386532349950841221768152838255933892789078521;
input[1] = 622860516154313070522697309645122400675542217310916019527100517240519630053;
input[2] = 11094488463398718754251685950409355128550342438297986977413505294941943071569;
input[3] = 6627643779954497813586310325594578844876646808666478625705401786271515864467;
input[4] = 2957286918163151606545409668133310005545945782087581890025685458369200827463;
input[5] = 1384290496819542862903939282897996566903332587607290986044945365745128311081;
input[6] = 5613571677741714971687805233468747950848449704454346829971683826953541367271;
input[7] = 9643208548031422463313148630985736896287522941726746581856185889848792022807;
input[8] = 18066496933330839731877828156604;
if (verify(input, proof) == 0) {
Verified("Transaction successfully verified.");
return true;
} else {
return false;
}
}
}

View file

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

View file

@ -0,0 +1,3 @@
// only using add, no need to flatten
def main(a, b):
return a + b

View file

@ -0,0 +1,2 @@
def main(a,b):
return (a + b)

View file

@ -0,0 +1 @@
~out_0 3

View file

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

View file

@ -0,0 +1,2 @@
def main(a, b, c):
return a * b * c

View file

@ -0,0 +1,3 @@
def main(a,b,c):
sym_0 = (b * c)
return (a * sym_0)

View file

@ -0,0 +1 @@
~out_0 24

112
tests/integration.rs Normal file
View file

@ -0,0 +1,112 @@
extern crate assert_cli;
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;
fn setup() {
fs::create_dir("./tests/tmp").unwrap();
}
fn teardown() {
fs::remove_dir_all("./tests/tmp").unwrap();
}
#[test]
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()
});
teardown();
assert!(result.is_ok())
}
fn test_compile_and_witness_dir() {
let dir = Path::new("./tests/code");
if dir.is_dir() {
for entry in fs::read_dir(dir).unwrap() {
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 prog = dir.join(program_name).with_extension("code");
let flat = dir.join(program_name).with_extension("expected.out.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, &flat, &args, &witness);
}
}
}
}
fn test_compile_and_witness(program_name: &str, program_path: &Path, expected_flattened_code_path: &Path, arguments_path: &Path, expected_witness_path: &Path) {
let tmp_base = Path::new("./tests/tmp/");
let test_case_path = tmp_base.join(program_name);
let flattened_path = tmp_base.join(program_name).join("out");
let flattened_code_path = tmp_base.join(program_name).join("out").with_extension("code");
let witness_path = tmp_base.join(program_name).join("witness");
// create a tmp folder to store artifacts
fs::create_dir(test_case_path).unwrap();
// compile
assert_cli::Assert::command(&["cargo", "run", "--", "compile", "-i", program_path.to_str().unwrap(), "-o", flattened_path.to_str().unwrap()])
.succeeds()
.unwrap();
// compute
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 mut compute = vec!["cargo", "run", "--", "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();
// load the expected result
let mut expected_flattened_code_file = File::open(&expected_flattened_code_path).unwrap();
let mut expected_flattened_code = String::new();
expected_flattened_code_file.read_to_string(&mut expected_flattened_code).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();
// load the actual result
let mut flattened_code_file = File::open(&flattened_code_path).unwrap();
let mut flattened_code = String::new();
flattened_code_file.read_to_string(&mut flattened_code).unwrap();
// load the actual witness
let mut witness_file = File::open(&witness_path).unwrap();
let mut witness = String::new();
witness_file.read_to_string(&mut witness).unwrap();
// check equality
assert_eq!(flattened_code, expected_flattened_code, "Flattening failed for {}\n\nExpected\n\n{}\n\nGot\n\n{}", program_path.to_str().unwrap(), expected_flattened_code.as_str(), flattened_code.as_str());
assert!(witness.contains(expected_witness.as_str()), "Witness generation failed for {}\n\nExpected\n\n{}\n\nGot\n\n{}", program_path.to_str().unwrap(), expected_witness.as_str(), witness.as_str());
}
}