commit
4bb56c6f04
31 changed files with 2066 additions and 698 deletions
12
.gitignore
vendored
12
.gitignore
vendored
|
@ -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
501
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
96
README.md
96
README.md
|
@ -1,4 +1,4 @@
|
|||
# ZoKrates
|
||||
# Zokrates
|
||||
|
||||
[](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
|
||||
```
|
||||
|
|
8
build.rs
8
build.rs
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
23
examples/functions/lt_comparison
Normal file
23
examples/functions/lt_comparison
Normal 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)
|
7
examples/multi_return.code
Normal file
7
examples/multi_return.code
Normal 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
|
5
examples/multi_return_sum.code
Normal file
5
examples/multi_return_sum.code
Normal file
|
@ -0,0 +1,5 @@
|
|||
def foo():
|
||||
return 1, 2
|
||||
def main():
|
||||
a, b = foo()
|
||||
return a + b, b - a
|
|
@ -1,3 +0,0 @@
|
|||
def main():
|
||||
c = 3 + a
|
||||
return 3
|
|
@ -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)
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
112
src/absy.rs
112
src/absy.rs
|
@ -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),
|
||||
|
|
418
src/flatten.rs
418
src/flatten.rs
|
@ -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)))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
78
src/main.rs
78
src/main.rs
|
@ -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
|
||||
|
|
281
src/parser.rs
281
src/parser.rs
|
@ -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
|
||||
|
|
73
src/r1cs.rs
73
src/r1cs.rs
|
@ -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
705
src/semantics.rs
Normal 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())));
|
||||
}
|
||||
}
|
|
@ -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 {
|
|||
}
|
||||
}
|
||||
}
|
||||
"#;
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
1
tests/code/simple_add.arguments.json
Normal file
1
tests/code/simple_add.arguments.json
Normal file
|
@ -0,0 +1 @@
|
|||
[1, 2]
|
3
tests/code/simple_add.code
Normal file
3
tests/code/simple_add.code
Normal file
|
@ -0,0 +1,3 @@
|
|||
// only using add, no need to flatten
|
||||
def main(a, b):
|
||||
return a + b
|
2
tests/code/simple_add.expected.out.code
Normal file
2
tests/code/simple_add.expected.out.code
Normal file
|
@ -0,0 +1,2 @@
|
|||
def main(a,b):
|
||||
return (a + b)
|
1
tests/code/simple_add.expected.witness
Normal file
1
tests/code/simple_add.expected.witness
Normal file
|
@ -0,0 +1 @@
|
|||
~out_0 3
|
1
tests/code/simple_mul.arguments.json
Normal file
1
tests/code/simple_mul.arguments.json
Normal file
|
@ -0,0 +1 @@
|
|||
[2, 3, 4]
|
2
tests/code/simple_mul.code
Normal file
2
tests/code/simple_mul.code
Normal file
|
@ -0,0 +1,2 @@
|
|||
def main(a, b, c):
|
||||
return a * b * c
|
3
tests/code/simple_mul.expected.out.code
Normal file
3
tests/code/simple_mul.expected.out.code
Normal file
|
@ -0,0 +1,3 @@
|
|||
def main(a,b,c):
|
||||
sym_0 = (b * c)
|
||||
return (a * sym_0)
|
1
tests/code/simple_mul.expected.witness
Normal file
1
tests/code/simple_mul.expected.witness
Normal file
|
@ -0,0 +1 @@
|
|||
~out_0 24
|
112
tests/integration.rs
Normal file
112
tests/integration.rs
Normal 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());
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue