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

merge dev

This commit is contained in:
schaeff 2021-01-28 23:32:57 +01:00
commit f612ba7a29
65 changed files with 3447 additions and 2351 deletions

View file

@ -75,12 +75,11 @@ jobs:
- v4-cargo-cache-{{ arch }}-{{ checksum "Cargo.lock" }}
- run:
name: Test on firefox
command: GECKODRIVER=geckodriver cd zokrates_core && wasm-pack test --firefox --headless -- --no-default-features --features "wasm bellman"
command: cd zokrates_core && wasm-pack test --firefox --headless -- --no-default-features --features "wasm bellman"
integration_test:
docker:
- image: zokrates/env:latest
- image: trufflesuite/ganache-cli:next
port: 8545:8545
steps:
- checkout
- run:

317
Cargo.lock generated
View file

@ -36,7 +36,7 @@ dependencies = [
[[package]]
name = "ark-bls12-377"
version = "0.1.0"
source = "git+https://github.com/arkworks-rs/curves#23e87bf224c23be5c5bccc6084aae31fff8bb83f"
source = "git+https://github.com/arkworks-rs/curves#7f1fcd66967328a1c5a3d12f8b148d69f7d86888"
dependencies = [
"ark-ec",
"ark-ff",
@ -46,7 +46,7 @@ dependencies = [
[[package]]
name = "ark-bn254"
version = "0.1.0"
source = "git+https://github.com/arkworks-rs/curves#23e87bf224c23be5c5bccc6084aae31fff8bb83f"
source = "git+https://github.com/arkworks-rs/curves#7f1fcd66967328a1c5a3d12f8b148d69f7d86888"
dependencies = [
"ark-ec",
"ark-ff",
@ -56,7 +56,7 @@ dependencies = [
[[package]]
name = "ark-bw6-761"
version = "0.1.0"
source = "git+https://github.com/arkworks-rs/curves#23e87bf224c23be5c5bccc6084aae31fff8bb83f"
source = "git+https://github.com/arkworks-rs/curves#7f1fcd66967328a1c5a3d12f8b148d69f7d86888"
dependencies = [
"ark-bls12-377",
"ark-ec",
@ -84,7 +84,7 @@ dependencies = [
[[package]]
name = "ark-ec"
version = "0.1.0"
source = "git+https://github.com/arkworks-rs/algebra#902c8c2882a8aa6f87395df888b50090e2705cac"
source = "git+https://github.com/arkworks-rs/algebra#eac2dd72fd048ea7eac00dabe2ba8bda84287a64"
dependencies = [
"ark-ff",
"ark-serialize",
@ -92,35 +92,49 @@ dependencies = [
"derivative",
"num-traits 0.2.14",
"rand 0.7.3",
"zeroize",
]
[[package]]
name = "ark-ff"
version = "0.1.0"
source = "git+https://github.com/arkworks-rs/algebra#902c8c2882a8aa6f87395df888b50090e2705cac"
source = "git+https://github.com/arkworks-rs/algebra#eac2dd72fd048ea7eac00dabe2ba8bda84287a64"
dependencies = [
"ark-ff-asm",
"ark-ff-macros",
"ark-serialize",
"ark-std",
"derivative",
"num-traits 0.2.14",
"rand 0.7.3",
"rustc_version",
"zeroize",
]
[[package]]
name = "ark-ff-asm"
version = "0.1.0"
source = "git+https://github.com/arkworks-rs/algebra#902c8c2882a8aa6f87395df888b50090e2705cac"
source = "git+https://github.com/arkworks-rs/algebra#eac2dd72fd048ea7eac00dabe2ba8bda84287a64"
dependencies = [
"quote 1.0.7",
"syn 1.0.50",
"syn 1.0.54",
]
[[package]]
name = "ark-ff-macros"
version = "0.1.0"
source = "git+https://github.com/arkworks-rs/algebra#eac2dd72fd048ea7eac00dabe2ba8bda84287a64"
dependencies = [
"num-bigint 0.3.1",
"num-traits 0.2.14",
"quote 1.0.7",
"syn 1.0.54",
]
[[package]]
name = "ark-gm17"
version = "0.1.0"
source = "git+https://github.com/arkworks-rs/gm17#4382f9103a18c50cc84dc673740286a7604a2ae5"
source = "git+https://github.com/arkworks-rs/gm17#f74debdb0557af2a873c8261970617e6aad7211d"
dependencies = [
"ark-crypto-primitives",
"ark-ec",
@ -136,7 +150,7 @@ dependencies = [
[[package]]
name = "ark-poly"
version = "0.1.0"
source = "git+https://github.com/arkworks-rs/algebra#902c8c2882a8aa6f87395df888b50090e2705cac"
source = "git+https://github.com/arkworks-rs/algebra#eac2dd72fd048ea7eac00dabe2ba8bda84287a64"
dependencies = [
"ark-ff",
"ark-serialize",
@ -148,7 +162,7 @@ dependencies = [
[[package]]
name = "ark-relations"
version = "0.1.0"
source = "git+https://github.com/arkworks-rs/snark#f074e77ab35489da12f2f6cb97d24b7d992b8a35"
source = "git+https://github.com/arkworks-rs/snark#0648c547e4f9fda46a40ad0a4896652b87c2316b"
dependencies = [
"ark-ff",
"ark-std",
@ -158,7 +172,7 @@ dependencies = [
[[package]]
name = "ark-serialize"
version = "0.1.0"
source = "git+https://github.com/arkworks-rs/algebra#902c8c2882a8aa6f87395df888b50090e2705cac"
source = "git+https://github.com/arkworks-rs/algebra#eac2dd72fd048ea7eac00dabe2ba8bda84287a64"
dependencies = [
"ark-serialize-derive",
"ark-std",
@ -167,17 +181,17 @@ dependencies = [
[[package]]
name = "ark-serialize-derive"
version = "0.1.1-alpha.0"
source = "git+https://github.com/arkworks-rs/algebra#902c8c2882a8aa6f87395df888b50090e2705cac"
source = "git+https://github.com/arkworks-rs/algebra#eac2dd72fd048ea7eac00dabe2ba8bda84287a64"
dependencies = [
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn 1.0.50",
"syn 1.0.54",
]
[[package]]
name = "ark-snark"
version = "0.1.0"
source = "git+https://github.com/arkworks-rs/snark#f074e77ab35489da12f2f6cb97d24b7d992b8a35"
source = "git+https://github.com/arkworks-rs/snark#0648c547e4f9fda46a40ad0a4896652b87c2316b"
dependencies = [
"ark-ff",
"ark-relations",
@ -188,7 +202,7 @@ dependencies = [
[[package]]
name = "ark-std"
version = "0.1.0"
source = "git+https://github.com/arkworks-rs/utils#0825eeafe7a3fb54be5ca9b90b02b6057adca964"
source = "git+https://github.com/arkworks-rs/utils#f6974ac72f59339b7ab798a728a84c5a7b8bac45"
[[package]]
name = "arrayref"
@ -196,6 +210,15 @@ version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
[[package]]
name = "arrayvec"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9"
dependencies = [
"nodrop",
]
[[package]]
name = "arrayvec"
version = "0.5.2"
@ -249,9 +272,9 @@ dependencies = [
[[package]]
name = "base64"
version = "0.12.3"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
[[package]]
name = "bellman_ce"
@ -272,8 +295,8 @@ dependencies = [
[[package]]
name = "bench-utils"
version = "0.1.1-alpha.0"
source = "git+https://github.com/arkworks-rs/utils#0825eeafe7a3fb54be5ca9b90b02b6057adca964"
version = "0.1.0"
source = "git+https://github.com/arkworks-rs/utils#f6974ac72f59339b7ab798a728a84c5a7b8bac45"
[[package]]
name = "bincode"
@ -288,9 +311,9 @@ dependencies = [
[[package]]
name = "bit-vec"
version = "0.6.2"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f0dc55f2d8a1a85650ac47858bb001b4c0dd73d79e3c455a842925e68d29cd3"
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
[[package]]
name = "bitflags"
@ -310,6 +333,17 @@ dependencies = [
"opaque-debug",
]
[[package]]
name = "blake2-rfc_bellman_edition"
version = "0.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdc60350286c7c3db13b98e91dbe5c8b6830a6821bc20af5b0c310ce94d74915"
dependencies = [
"arrayvec 0.4.12",
"byteorder",
"constant_time_eq",
]
[[package]]
name = "blake2b_simd"
version = "0.5.11"
@ -317,7 +351,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587"
dependencies = [
"arrayref",
"arrayvec",
"arrayvec 0.5.2",
"constant_time_eq",
]
@ -368,9 +402,9 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
[[package]]
name = "bytecount"
version = "0.6.1"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c39a773ba75db12126d8d383f1bdbf7eb92ea47ec27dd0557aff1fedf172764c"
checksum = "72feb31ffc86498dacdbd0fcebb56138e7177a8cc5cea4516031d15ae85a742e"
[[package]]
name = "byteorder"
@ -392,9 +426,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.0.65"
version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95752358c8f7552394baf48cd82695b345628ad3f170d607de3ca03b8dacca15"
checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
dependencies = [
"jobserver",
]
@ -473,7 +507,7 @@ dependencies = [
"crossbeam-deque",
"crossbeam-epoch",
"crossbeam-queue",
"crossbeam-utils",
"crossbeam-utils 0.7.2",
]
[[package]]
@ -482,7 +516,7 @@ version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87"
dependencies = [
"crossbeam-utils",
"crossbeam-utils 0.7.2",
"maybe-uninit",
]
@ -493,7 +527,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285"
dependencies = [
"crossbeam-epoch",
"crossbeam-utils",
"crossbeam-utils 0.7.2",
"maybe-uninit",
]
@ -505,7 +539,7 @@ checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace"
dependencies = [
"autocfg",
"cfg-if 0.1.10",
"crossbeam-utils",
"crossbeam-utils 0.7.2",
"lazy_static",
"maybe-uninit",
"memoffset",
@ -519,7 +553,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570"
dependencies = [
"cfg-if 0.1.10",
"crossbeam-utils",
"crossbeam-utils 0.7.2",
"maybe-uninit",
]
@ -534,6 +568,23 @@ dependencies = [
"lazy_static",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d"
dependencies = [
"autocfg",
"cfg-if 1.0.0",
"lazy_static",
]
[[package]]
name = "crunchy"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]]
name = "crypto-mac"
version = "0.7.0"
@ -546,9 +597,9 @@ dependencies = [
[[package]]
name = "csv"
version = "1.1.4"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc4666154fd004af3fd6f1da2e81a96fd5a81927fe8ddb6ecc79e2aa6e138b54"
checksum = "f9d58633299b24b515ac72a3f869f8b91306a3cec616a602843a383acd6f9e97"
dependencies = [
"bstr",
"csv-core",
@ -573,7 +624,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fbaabec2c953050352311293be5c6aba8e141ba19d6811862b232d6fd020484"
dependencies = [
"quote 1.0.7",
"syn 1.0.50",
"syn 1.0.54",
]
[[package]]
@ -584,7 +635,7 @@ checksum = "cb582b60359da160a9477ee80f15c8d784c477e69c217ef2cdd4169c24ea380f"
dependencies = [
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn 1.0.50",
"syn 1.0.54",
]
[[package]]
@ -676,7 +727,7 @@ checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4"
dependencies = [
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn 1.0.50",
"syn 1.0.54",
"synstructure",
]
@ -715,12 +766,12 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50c052fa6d4c2f12305ec364bfb8ef884836f3f61ea015b202372ff996d1ac4b"
dependencies = [
"num-bigint",
"num-bigint 0.2.6",
"num-integer",
"num-traits 0.2.14",
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn 1.0.50",
"syn 1.0.54",
]
[[package]]
@ -941,9 +992,9 @@ dependencies = [
[[package]]
name = "js-sys"
version = "0.3.45"
version = "0.3.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca059e81d9486668f12d455a4ea6daa600bd408134cd17e3d3fb5a32d1f016f8"
checksum = "cf3d7383929f7c9c7c2d0fa596f325832df98c3704f2c60553080f7127a58175"
dependencies = [
"wasm-bindgen",
]
@ -956,9 +1007,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.80"
version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614"
checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb"
[[package]]
name = "libgit2-sys"
@ -1052,6 +1103,12 @@ dependencies = [
"autocfg",
]
[[package]]
name = "nodrop"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
[[package]]
name = "num"
version = "0.1.42"
@ -1075,6 +1132,17 @@ dependencies = [
"serde",
]
[[package]]
name = "num-bigint"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e9a41747ae4633fce5adffb4d2e81ffc5e89593cb19917f8fb2cc5ff76507bf"
dependencies = [
"autocfg",
"num-integer",
"num-traits 0.2.14",
]
[[package]]
name = "num-integer"
version = "0.1.44"
@ -1150,9 +1218,9 @@ checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
[[package]]
name = "openssl-sys"
version = "0.9.58"
version = "0.9.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a842db4709b604f0fe5d1170ae3565899be2ad3d9cbc72dedc789ac0511f78de"
checksum = "de52d8eabd217311538a39bba130d7dea1f1e118010fee7a033d966845e7d5fe"
dependencies = [
"autocfg",
"cc",
@ -1229,7 +1297,7 @@ dependencies = [
"pest_meta",
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn 1.0.50",
"syn 1.0.54",
]
[[package]]
@ -1260,14 +1328,14 @@ checksum = "f8e8d2bf0b23038a4424865103a4df472855692821aab4e4f5c3312d461d9e5f"
dependencies = [
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn 1.0.50",
"syn 1.0.54",
]
[[package]]
name = "pin-project-lite"
version = "0.1.11"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c917123afa01924fc84bb20c4c03f004d9c38e5127e3c039bbf7f4b9c76a2f6b"
checksum = "6b063f57ec186e6140e2b8b6921e5f1bd89c7356dda5b33acc5401203ca6131c"
[[package]]
name = "pin-utils"
@ -1487,14 +1555,14 @@ dependencies = [
[[package]]
name = "rust-argon2"
version = "0.8.2"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9dab61250775933275e84053ac235621dfb739556d5c54a2f2e9313b7cf43a19"
checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb"
dependencies = [
"base64",
"blake2b_simd",
"constant_time_eq",
"crossbeam-utils",
"crossbeam-utils 0.8.1",
]
[[package]]
@ -1527,6 +1595,23 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "sapling-crypto_ce"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c4ff5309ec3e4bd800ad4ab3f71e9b76e9ea81c9f0eda6efa16008afbe440b3"
dependencies = [
"bellman_ce",
"blake2-rfc_bellman_edition",
"byteorder",
"digest",
"rand 0.4.6",
"serde",
"serde_derive",
"sha2",
"tiny-keccak",
]
[[package]]
name = "scoped-tls"
version = "1.0.0"
@ -1575,29 +1660,29 @@ dependencies = [
[[package]]
name = "serde"
version = "1.0.117"
version = "1.0.118"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a"
checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.117"
version = "1.0.118"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbd1ae72adb44aab48f325a02444a5fc079349a8d804c1fc922aed3f7454c74e"
checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df"
dependencies = [
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn 1.0.50",
"syn 1.0.54",
]
[[package]]
name = "serde_json"
version = "1.0.59"
version = "1.0.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcac07dbffa1c65e7f816ab9eba78eb142c6d44410f4eeba1e26e4f5dfa56b95"
checksum = "1500e84d27fe482ed1dc791a56eddc2f230046a040fa908c08bda1d9fb615779"
dependencies = [
"itoa",
"ryu",
@ -1683,9 +1768,9 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.50"
version = "1.0.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "443b4178719c5a851e1bde36ce12da21d74a0e60b4d982ec3385a933c812f0f6"
checksum = "9a2af957a63d6bd42255c359c93d9bfdb97076bd3b820897ce55ffbfbf107f44"
dependencies = [
"proc-macro2 1.0.24",
"quote 1.0.7",
@ -1700,7 +1785,7 @@ checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701"
dependencies = [
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn 1.0.50",
"syn 1.0.54",
"unicode-xid 0.2.1",
]
@ -1746,6 +1831,15 @@ dependencies = [
"lazy_static",
]
[[package]]
name = "tiny-keccak"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
dependencies = [
"crunchy",
]
[[package]]
name = "tinyvec"
version = "1.1.0"
@ -1763,11 +1857,11 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "tracing"
version = "0.1.21"
version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0987850db3733619253fe60e17cb59b82d37c7e6c0236bb81e4d6b87c879f27"
checksum = "9f47026cdc4080c07e49b37087de021820269d996f581aac150ef9e5583eefe3"
dependencies = [
"cfg-if 0.1.10",
"cfg-if 1.0.0",
"pin-project-lite",
"tracing-core",
]
@ -1858,9 +1952,9 @@ checksum = "b4ae116fef2b7fea257ed6440d3cfcff7f190865f170cdad00bb6465bf18ecba"
[[package]]
name = "vcpkg"
version = "0.2.10"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c"
checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb"
[[package]]
name = "vec_map"
@ -1899,36 +1993,36 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "wasm-bindgen"
version = "0.2.68"
version = "0.2.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ac64ead5ea5f05873d7c12b545865ca2b8d28adfc50a49b84770a3a97265d42"
checksum = "3cd364751395ca0f68cafb17666eee36b63077fb5ecd972bbcd74c90c4bf736e"
dependencies = [
"cfg-if 0.1.10",
"cfg-if 1.0.0",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.68"
version = "0.2.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f22b422e2a757c35a73774860af8e112bff612ce6cb604224e8e47641a9e4f68"
checksum = "1114f89ab1f4106e5b55e688b828c0ab0ea593a1ea7c094b141b14cbaaec2d62"
dependencies = [
"bumpalo",
"lazy_static",
"log",
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn 1.0.50",
"syn 1.0.54",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.18"
version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7866cab0aa01de1edf8b5d7936938a7e397ee50ce24119aef3e1eaa3b6171da"
checksum = "1fe9756085a84584ee9457a002b7cdfe0bfff169f45d2591d8be1345a6780e35"
dependencies = [
"cfg-if 0.1.10",
"cfg-if 1.0.0",
"js-sys",
"wasm-bindgen",
"web-sys",
@ -1936,9 +2030,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.68"
version = "0.2.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b13312a745c08c469f0b292dd2fcd6411dba5f7160f593da6ef69b64e407038"
checksum = "7a6ac8995ead1f084a8dea1e65f194d0973800c7f571f6edd70adf06ecf77084"
dependencies = [
"quote 1.0.7",
"wasm-bindgen-macro-support",
@ -1946,28 +2040,28 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.68"
version = "0.2.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f249f06ef7ee334cc3b8ff031bfc11ec99d00f34d86da7498396dc1e3b1498fe"
checksum = "b5a48c72f299d80557c7c62e37e7225369ecc0c963964059509fbafe917c7549"
dependencies = [
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn 1.0.50",
"syn 1.0.54",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.68"
version = "0.2.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d649a3145108d7d3fbcde896a468d1bd636791823c9921135218ad89be08307"
checksum = "7e7811dd7f9398f14cc76efd356f98f03aa30419dea46aa810d71e819fc97158"
[[package]]
name = "wasm-bindgen-test"
version = "0.3.18"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34d1cdc8b98a557f24733d50a1199c4b0635e465eecba9c45b214544da197f64"
checksum = "0355fa0c1f9b792a09b6dcb6a8be24d51e71e6d74972f9eb4a44c4c004d24a25"
dependencies = [
"console_error_panic_hook",
"js-sys",
@ -1979,9 +2073,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-test-macro"
version = "0.3.18"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8fb9c67be7439ee8ab1b7db502a49c05e51e2835b66796c705134d9b8e1a585"
checksum = "27e07b46b98024c2ba2f9e83a10c2ef0515f057f2da299c1762a2017de80438b"
dependencies = [
"proc-macro2 1.0.24",
"quote 1.0.7",
@ -1989,9 +2083,9 @@ dependencies = [
[[package]]
name = "web-sys"
version = "0.3.45"
version = "0.3.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bf6ef87ad7ae8008e15a355ce696bed26012b7caa21605188cfd8214ab51e2d"
checksum = "222b1ef9334f92a21d3fb53dc3fd80f30836959a90f9274a626d7e06315ba3c3"
dependencies = [
"js-sys",
"wasm-bindgen",
@ -2028,9 +2122,30 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "zeroize"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81a974bcdd357f0dca4d41677db03436324d45a4c9ed2d0b873a5a360ce41c36"
dependencies = [
"zeroize_derive",
]
[[package]]
name = "zeroize_derive"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3f369ddb18862aba61aa49bf31e74d29f0f162dec753063200e1dc084345d16"
dependencies = [
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn 1.0.54",
"synstructure",
]
[[package]]
name = "zokrates_abi"
version = "0.1.2"
version = "0.1.3"
dependencies = [
"serde",
"serde_derive",
@ -2041,7 +2156,7 @@ dependencies = [
[[package]]
name = "zokrates_cli"
version = "0.6.2"
version = "0.6.3"
dependencies = [
"assert_cli",
"bincode",
@ -2050,6 +2165,7 @@ dependencies = [
"dirs",
"fs_extra",
"glob 0.2.11",
"lazy_static",
"regex",
"serde_json",
"tempdir",
@ -2065,7 +2181,7 @@ version = "0.1.0"
[[package]]
name = "zokrates_core"
version = "0.5.2"
version = "0.5.3"
dependencies = [
"ark-bls12-377",
"ark-bn254",
@ -2086,7 +2202,7 @@ dependencies = [
"hex",
"lazy_static",
"num",
"num-bigint",
"num-bigint 0.2.6",
"pairing_ce",
"pretty_assertions",
"rand 0.4.6",
@ -2098,18 +2214,27 @@ dependencies = [
"typed-arena",
"wasm-bindgen-test",
"zokrates_common",
"zokrates_embed",
"zokrates_field",
"zokrates_pest_ast",
]
[[package]]
name = "zokrates_core_test"
version = "0.1.3"
version = "0.1.4"
dependencies = [
"zokrates_test",
"zokrates_test_derive",
]
[[package]]
name = "zokrates_embed"
version = "0.1.1"
dependencies = [
"bellman_ce",
"sapling-crypto_ce",
]
[[package]]
name = "zokrates_field"
version = "0.3.7"
@ -2122,7 +2247,7 @@ dependencies = [
"bellman_ce",
"bincode",
"lazy_static",
"num-bigint",
"num-bigint 0.2.6",
"num-integer",
"num-traits 0.2.14",
"rand 0.4.6",
@ -2142,7 +2267,7 @@ dependencies = [
[[package]]
name = "zokrates_parser"
version = "0.1.5"
version = "0.1.6"
dependencies = [
"glob 0.2.11",
"pest",
@ -2151,7 +2276,7 @@ dependencies = [
[[package]]
name = "zokrates_pest_ast"
version = "0.1.4"
version = "0.1.5"
dependencies = [
"from-pest",
"glob 0.2.11",

View file

@ -6,6 +6,7 @@ members = [
"zokrates_cli",
"zokrates_fs_resolver",
"zokrates_stdlib",
"zokrates_embed",
"zokrates_abi",
"zokrates_test",
"zokrates_core_test",

View file

@ -9,10 +9,9 @@ RUN cd src; ./build_release.sh
FROM ubuntu:18.04
ENV ZOKRATES_HOME=/home/zokrates/.zokrates
COPY --from=build /build/src/scripts/install_libsnark_prerequisites.sh /tmp/
RUN /tmp/install_libsnark_prerequisites.sh \
&& useradd -u 1000 -m zokrates
RUN apt-get update \
&& apt-get install -y --no-install-recommends libgmp3-dev \
&& useradd -u 1000 -m zokrates
USER zokrates
WORKDIR /home/zokrates

View file

@ -22,20 +22,24 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
clang-format \
python3 \
python-markdown \
&& add-apt-repository ppa:jonathonf/firefox-esr; apt-get install -y firefox-esr \
&& add-apt-repository ppa:mozillateam/ppa \
&& apt-get update \
&& apt-get install -y --no-install-recommends firefox-esr \
&& ln -s /usr/bin/firefox-esr /usr/bin/firefox \
&& rm -rf /var/lib/apt/lists/*
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain none -y \
&& rustup toolchain install nightly --allow-downgrade --profile minimal --component rustfmt \
&& rustup toolchain install nightly --allow-downgrade --profile minimal --component rustfmt clippy \
&& cargo install --git https://github.com/rustwasm/wasm-pack \
&& rm -rf /usr/local/cargo/registry \
&& curl -sL https://deb.nodesource.com/setup_lts.x | bash - && apt-get install -y nodejs && npm i -g solc \
&& curl -sL https://raw.githubusercontent.com/Sarcasm/run-clang-format/master/run-clang-format.py > /opt/run-clang-format.py \
&& chmod +x /opt/run-clang-format.py \
&& ln -s /opt/run-clang-format.py /usr/bin \
&& rustup --version; cargo --version; rustc --version; wasm-pack --version; echo nodejs $(node -v);
RUN cd /opt && curl -LO https://github.com/mozilla/geckodriver/releases/download/v0.26.0/geckodriver-v0.26.0-linux64.tar.gz \
&& tar -xzf geckodriver-v0.26.0-linux64.tar.gz geckodriver \
RUN cd /opt && curl -LO https://github.com/mozilla/geckodriver/releases/download/v0.28.0/geckodriver-v0.28.0-linux64.tar.gz \
&& tar -xzf geckodriver-v0.28.0-linux64.tar.gz geckodriver \
&& ln -s /opt/geckodriver /usr/bin \
&& geckodriver --version \
&& rm -rf geckodriver-v0.26.0-linux64.tar.gz
&& rm -rf geckodriver-v0.28.0-linux64.tar.gz

View file

@ -1,6 +1,6 @@
[package]
name = "zokrates_abi"
version = "0.1.2"
version = "0.1.3"
authors = ["Thibaut Schaeffer <thibaut@schaeff.fr>"]
edition = "2018"

View file

@ -1,6 +1,6 @@
[package]
name = "zokrates_cli"
version = "0.6.2"
version = "0.6.3"
authors = ["Jacob Eberhardt <jacob.eberhardt@tu-berlin.de>", "Dennis Kuhnert <mail@kyroy.com>", "Thibaut Schaeffer <thibaut@schaeff.fr>"]
repository = "https://github.com/JacobEberhardt/ZoKrates.git"
edition = "2018"
@ -22,6 +22,7 @@ zokrates_core = { version = "0.5", path = "../zokrates_core", default-features =
zokrates_fs_resolver = { version = "0.5", path = "../zokrates_fs_resolver"}
serde_json = "1.0"
dirs = "3.0.1"
lazy_static = "1.4.0"
[dev-dependencies]
glob = "0.2.11"

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,24 @@
pub const FLATTENED_CODE_DEFAULT_PATH: &str = "out";
pub const ABI_SPEC_DEFAULT_PATH: &str = "abi.json";
pub const VERIFICATION_KEY_DEFAULT_PATH: &str = "verification.key";
pub const PROVING_KEY_DEFAULT_PATH: &str = "proving.key";
pub const VERIFICATION_CONTRACT_DEFAULT_PATH: &str = "verifier.sol";
pub const WITNESS_DEFAULT_PATH: &str = "witness";
pub const JSON_PROOF_PATH: &str = "proof.json";
pub const BELLMAN: &str = "bellman";
pub const LIBSNARK: &str = "libsnark";
pub const ARK: &str = "ark";
lazy_static! {
pub static ref DEFAULT_STDLIB_PATH: String = dirs::home_dir()
.map(|p| p.join(".zokrates/stdlib"))
.unwrap()
.into_os_string()
.into_string()
.unwrap();
}
pub const BACKENDS: &[&str] = if cfg!(feature = "libsnark") {
if cfg!(feature = "ark") {
if cfg!(feature = "bellman") {

View file

@ -1,6 +1,5 @@
use core::convert::TryFrom;
use crate::constants::*;
use std::convert::TryFrom;
#[derive(Debug)]
pub enum CurveParameter {

View file

@ -0,0 +1,101 @@
use crate::constants;
use crate::helpers::CurveParameter;
use clap::{App, Arg, ArgMatches, SubCommand};
use std::convert::TryFrom;
use std::fs::File;
use std::io::{BufReader, Read};
use std::path::{Path, PathBuf};
use zokrates_core::compile::{check, CompileError};
use zokrates_field::{Bls12_377Field, Bls12_381Field, Bn128Field, Bw6_761Field, Field};
use zokrates_fs_resolver::FileSystemResolver;
pub fn subcommand() -> App<'static, 'static> {
SubCommand::with_name("check")
.about("Checks a program for errors")
.arg(
Arg::with_name("input")
.short("i")
.long("input")
.help("Path of the source code")
.value_name("FILE")
.takes_value(true)
.required(true),
)
.arg(
Arg::with_name("stdlib-path")
.long("stdlib-path")
.help("Path to the standard library")
.value_name("PATH")
.takes_value(true)
.required(false)
.env("ZOKRATES_STDLIB")
.default_value(constants::DEFAULT_STDLIB_PATH.as_str()),
)
.arg(
Arg::with_name("curve")
.short("c")
.long("curve")
.help("Curve to be used in the compilation")
.takes_value(true)
.required(false)
.possible_values(constants::CURVES)
.default_value(constants::BN128),
)
}
pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> {
let curve = CurveParameter::try_from(sub_matches.value_of("curve").unwrap())?;
match curve {
CurveParameter::Bn128 => cli_check::<Bn128Field>(sub_matches),
CurveParameter::Bls12_377 => cli_check::<Bls12_377Field>(sub_matches),
CurveParameter::Bls12_381 => cli_check::<Bls12_381Field>(sub_matches),
CurveParameter::Bw6_761 => cli_check::<Bw6_761Field>(sub_matches),
}
}
fn cli_check<T: Field>(sub_matches: &ArgMatches) -> Result<(), String> {
println!("Checking {}\n", sub_matches.value_of("input").unwrap());
let path = PathBuf::from(sub_matches.value_of("input").unwrap());
let file = File::open(path.clone())
.map_err(|why| format!("Couldn't open input file {}: {}", path.display(), why))?;
let mut reader = BufReader::new(file);
let mut source = String::new();
reader.read_to_string(&mut source).unwrap();
let fmt_error = |e: &CompileError| {
let file = e.file().canonicalize().unwrap();
format!(
"{}:{}",
file.strip_prefix(std::env::current_dir().unwrap())
.unwrap_or(file.as_path())
.display(),
e.value()
)
};
let stdlib_path = sub_matches.value_of("stdlib-path").unwrap();
match Path::new(stdlib_path).exists() {
true => Ok(()),
_ => Err(format!(
"Invalid standard library source path: {}",
stdlib_path
)),
}?;
let resolver = FileSystemResolver::with_stdlib_root(stdlib_path);
let _ = check::<T, _>(source, path, Some(&resolver)).map_err(|e| {
format!(
"Check failed:\n\n{}",
e.0.iter()
.map(|e| fmt_error(e))
.collect::<Vec<_>>()
.join("\n\n")
)
})?;
println!("Program checked, no errors found.");
Ok(())
}

View file

@ -0,0 +1,173 @@
use crate::constants;
use crate::helpers::CurveParameter;
use clap::{App, Arg, ArgMatches, SubCommand};
use serde_json::to_writer_pretty;
use std::convert::TryFrom;
use std::fs::File;
use std::io::{BufReader, BufWriter, Read, Write};
use std::path::{Path, PathBuf};
use zokrates_core::compile::{compile, CompilationArtifacts, CompileConfig, CompileError};
use zokrates_field::{Bls12_377Field, Bls12_381Field, Bn128Field, Bw6_761Field, Field};
use zokrates_fs_resolver::FileSystemResolver;
pub fn subcommand() -> App<'static, 'static> {
SubCommand::with_name("compile")
.about("Compiles into flattened conditions. Produces two files: human-readable '.ztf' file for debugging and binary file")
.arg(Arg::with_name("input")
.short("i")
.long("input")
.help("Path of the source code")
.value_name("FILE")
.takes_value(true)
.required(true)
).arg(Arg::with_name("stdlib-path")
.long("stdlib-path")
.help("Path to the standard library")
.value_name("PATH")
.takes_value(true)
.required(false)
.env("ZOKRATES_STDLIB")
.default_value(constants::DEFAULT_STDLIB_PATH.as_str())
).arg(Arg::with_name("abi_spec")
.short("s")
.long("abi_spec")
.help("Path of the ABI specification")
.value_name("FILE")
.takes_value(true)
.required(false)
.default_value(constants::ABI_SPEC_DEFAULT_PATH)
).arg(Arg::with_name("output")
.short("o")
.long("output")
.help("Path of the output binary")
.value_name("FILE")
.takes_value(true)
.required(false)
.default_value(constants::FLATTENED_CODE_DEFAULT_PATH)
).arg(Arg::with_name("curve")
.short("c")
.long("curve")
.help("Curve to be used in the compilation")
.takes_value(true)
.required(false)
.possible_values(constants::CURVES)
.default_value(constants::BN128)
).arg(Arg::with_name("light")
.long("light")
.help("Skip logs and human readable output")
.required(false)
)
}
pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> {
let curve = CurveParameter::try_from(sub_matches.value_of("curve").unwrap())?;
match curve {
CurveParameter::Bn128 => cli_compile::<Bn128Field>(sub_matches),
CurveParameter::Bls12_377 => cli_compile::<Bls12_377Field>(sub_matches),
CurveParameter::Bls12_381 => cli_compile::<Bls12_381Field>(sub_matches),
CurveParameter::Bw6_761 => cli_compile::<Bw6_761Field>(sub_matches),
}
}
fn cli_compile<T: Field>(sub_matches: &ArgMatches) -> Result<(), String> {
println!("Compiling {}\n", sub_matches.value_of("input").unwrap());
let path = PathBuf::from(sub_matches.value_of("input").unwrap());
let light = sub_matches.occurrences_of("light") > 0;
let bin_output_path = Path::new(sub_matches.value_of("output").unwrap());
let abi_spec_path = Path::new(sub_matches.value_of("abi_spec").unwrap());
let hr_output_path = bin_output_path.to_path_buf().with_extension("ztf");
let file = File::open(path.clone())
.map_err(|why| format!("Couldn't open input file {}: {}", path.display(), why))?;
let mut reader = BufReader::new(file);
let mut source = String::new();
reader.read_to_string(&mut source).unwrap();
let fmt_error = |e: &CompileError| {
let file = e.file().canonicalize().unwrap();
format!(
"{}:{}",
file.strip_prefix(std::env::current_dir().unwrap())
.unwrap_or(file.as_path())
.display(),
e.value()
)
};
let stdlib_path = sub_matches.value_of("stdlib-path").unwrap();
match Path::new(stdlib_path).exists() {
true => Ok(()),
_ => Err(format!(
"Invalid standard library source path: {}",
stdlib_path
)),
}?;
let config = CompileConfig {
allow_unconstrained_variables: sub_matches.is_present("allow-unconstrained-variables"),
};
let resolver = FileSystemResolver::with_stdlib_root(stdlib_path);
let artifacts: CompilationArtifacts<T> = compile(source, path, Some(&resolver), &config)
.map_err(|e| {
format!(
"Compilation failed:\n\n{}",
e.0.iter()
.map(|e| fmt_error(e))
.collect::<Vec<_>>()
.join("\n\n")
)
})?;
let program_flattened = artifacts.prog();
// number of constraints the flattened program will translate to.
let num_constraints = program_flattened.constraint_count();
// serialize flattened program and write to binary file
let bin_output_file = File::create(&bin_output_path)
.map_err(|why| format!("Couldn't create {}: {}", bin_output_path.display(), why))?;
let mut writer = BufWriter::new(bin_output_file);
program_flattened.serialize(&mut writer);
// serialize ABI spec and write to JSON file
let abi_spec_file = File::create(&abi_spec_path)
.map_err(|why| format!("Couldn't create {}: {}", abi_spec_path.display(), why))?;
let abi = artifacts.abi();
let mut writer = BufWriter::new(abi_spec_file);
to_writer_pretty(&mut writer, &abi).map_err(|_| "Unable to write data to file.".to_string())?;
if !light {
// write human-readable output file
let hr_output_file = File::create(&hr_output_path)
.map_err(|why| format!("Couldn't create {}: {}", hr_output_path.display(), why))?;
let mut hrofb = BufWriter::new(hr_output_file);
write!(&mut hrofb, "{}\n", program_flattened)
.map_err(|_| "Unable to write data to file".to_string())?;
hrofb
.flush()
.map_err(|_| "Unable to flush buffer".to_string())?;
}
if !light {
// debugging output
println!("Compiled program:\n{}", program_flattened);
}
println!("Compiled code written to '{}'", bin_output_path.display());
if !light {
println!("Human readable code to '{}'", hr_output_path.display());
}
println!("Number of constraints: {}", num_constraints);
Ok(())
}

View file

@ -0,0 +1,189 @@
use crate::constants::{ABI_SPEC_DEFAULT_PATH, FLATTENED_CODE_DEFAULT_PATH, WITNESS_DEFAULT_PATH};
use clap::{App, Arg, ArgMatches, SubCommand};
use serde_json::from_reader;
use std::fs::File;
use std::io::{stdin, BufReader, BufWriter, Read};
use std::path::Path;
use zokrates_abi::Encode;
use zokrates_core::ir;
use zokrates_core::ir::ProgEnum;
use zokrates_core::typed_absy::abi::Abi;
use zokrates_core::typed_absy::{Signature, Type};
use zokrates_field::Field;
pub fn subcommand() -> App<'static, 'static> {
SubCommand::with_name("compute-witness")
.about("Calculates a witness for a given constraint system")
.arg(Arg::with_name("input")
.short("i")
.long("input")
.help("Path of the binary")
.value_name("FILE")
.takes_value(true)
.required(false)
.default_value(FLATTENED_CODE_DEFAULT_PATH)
).arg(Arg::with_name("abi_spec")
.short("s")
.long("abi_spec")
.help("Path of the ABI specification")
.value_name("FILE")
.takes_value(true)
.required(false)
.default_value(ABI_SPEC_DEFAULT_PATH)
).arg(Arg::with_name("output")
.short("o")
.long("output")
.help("Path of the output file")
.value_name("FILE")
.takes_value(true)
.required(false)
.default_value(WITNESS_DEFAULT_PATH)
).arg(Arg::with_name("arguments")
.short("a")
.long("arguments")
.help("Arguments for the program's main function, when not using ABI encoding. Expects a space-separated list of field elements like `-a 1 2 3`")
.takes_value(true)
.multiple(true) // allows multiple values
.required(false)
.conflicts_with("abi")
.conflicts_with("stdin")
).arg(Arg::with_name("abi")
.long("abi")
.help("Use ABI encoding. Arguments are expected as a JSON object as specified at zokrates.github.io/toolbox/abi.html#abi-input-format")
.conflicts_with("arguments")
.required(false)
).arg(Arg::with_name("stdin")
.long("stdin")
.help("Read arguments from stdin")
.conflicts_with("arguments")
.required(false)
).arg(Arg::with_name("light")
.long("light")
.help("Skip logging the human-readable program")
.required(false)
)
}
pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> {
// read compiled program
let path = Path::new(sub_matches.value_of("input").unwrap());
let file =
File::open(&path).map_err(|why| format!("Couldn't open {}: {}", path.display(), why))?;
let mut reader = BufReader::new(file);
match ProgEnum::deserialize(&mut reader)? {
ProgEnum::Bn128Program(p) => cli_compute(p, sub_matches),
ProgEnum::Bls12_377Program(p) => cli_compute(p, sub_matches),
ProgEnum::Bls12_381Program(p) => cli_compute(p, sub_matches),
ProgEnum::Bw6_761Program(p) => cli_compute(p, sub_matches),
}
}
fn cli_compute<T: Field>(ir_prog: ir::Prog<T>, sub_matches: &ArgMatches) -> Result<(), String> {
println!("Computing witness...");
// print deserialized flattened program
if !sub_matches.is_present("light") {
println!("{}", ir_prog);
}
let is_stdin = sub_matches.is_present("stdin");
let is_abi = sub_matches.is_present("abi");
if !is_stdin && is_abi {
return Err("ABI input as inline argument is not supported. Please use `--stdin`.".into());
}
let signature = match is_abi {
true => {
let path = Path::new(sub_matches.value_of("abi_spec").unwrap());
let file = File::open(&path)
.map_err(|why| format!("couldn't open {}: {}", path.display(), why))?;
let mut reader = BufReader::new(file);
let abi: Abi = from_reader(&mut reader).map_err(|why| why.to_string())?;
abi.signature()
}
false => Signature::new()
.inputs(vec![Type::FieldElement; ir_prog.main.arguments.len()])
.outputs(vec![Type::FieldElement; ir_prog.main.returns.len()]),
};
use zokrates_abi::Inputs;
// get arguments
let arguments = match is_stdin {
// take inline arguments
false => {
let arguments = sub_matches.values_of("arguments");
arguments
.map(|a| {
a.map(|x| T::try_from_dec_str(x).map_err(|_| x.to_string()))
.collect::<Result<Vec<_>, _>>()
})
.unwrap_or(Ok(vec![]))
.map(|v| Inputs::Raw(v))
}
// take stdin arguments
true => {
let mut stdin = stdin();
let mut input = String::new();
match is_abi {
true => match stdin.read_to_string(&mut input) {
Ok(_) => {
use zokrates_abi::parse_strict;
parse_strict(&input, signature.inputs)
.map(|parsed| Inputs::Abi(parsed))
.map_err(|why| why.to_string())
}
Err(_) => Err(String::from("???")),
},
false => match ir_prog.arguments_count() {
0 => Ok(Inputs::Raw(vec![])),
_ => match stdin.read_to_string(&mut input) {
Ok(_) => {
input.retain(|x| x != '\n');
input
.split(" ")
.map(|x| T::try_from_dec_str(x).map_err(|_| x.to_string()))
.collect::<Result<Vec<_>, _>>()
.map(|v| Inputs::Raw(v))
}
Err(_) => Err(String::from("???")),
},
},
}
}
}
.map_err(|e| format!("Could not parse argument: {}", e))?;
let interpreter = ir::Interpreter::default();
let witness = interpreter
.execute(&ir_prog, &arguments.encode())
.map_err(|e| format!("Execution failed: {}", e))?;
use zokrates_abi::Decode;
let results_json_value: serde_json::Value =
zokrates_abi::CheckedValues::decode(witness.return_values(), signature.outputs).into();
println!("\nWitness: \n\n{}", results_json_value);
// write witness to file
let output_path = Path::new(sub_matches.value_of("output").unwrap());
let output_file = File::create(&output_path)
.map_err(|why| format!("couldn't create {}: {}", output_path.display(), why))?;
let writer = BufWriter::new(output_file);
witness
.write(writer)
.map_err(|why| format!("could not save witness: {:?}", why))?;
Ok(())
}

View file

@ -0,0 +1,119 @@
use crate::constants;
use crate::helpers::{CurveParameter, SchemeParameter};
use clap::{App, Arg, ArgMatches, SubCommand};
use std::convert::TryFrom;
use std::fs::File;
use std::io::{BufReader, BufWriter, Write};
use std::path::Path;
use zokrates_core::proof_system::*;
use zokrates_field::Bn128Field;
pub fn subcommand() -> App<'static, 'static> {
SubCommand::with_name("export-verifier")
.about("Exports a verifier as Solidity smart contract")
.arg(
Arg::with_name("input")
.short("i")
.long("input")
.help("Path of the verifier")
.value_name("FILE")
.takes_value(true)
.required(false)
.default_value(constants::VERIFICATION_KEY_DEFAULT_PATH),
)
.arg(
Arg::with_name("output")
.short("o")
.long("output")
.help("Path of the output file")
.value_name("FILE")
.takes_value(true)
.required(false)
.default_value(constants::VERIFICATION_CONTRACT_DEFAULT_PATH),
)
.arg(
Arg::with_name("curve")
.short("c")
.long("curve")
.help("Curve to be used to export the verifier")
.takes_value(true)
.required(false)
.possible_values(constants::CURVES)
.default_value(constants::BN128),
)
.arg(
Arg::with_name("proving-scheme")
.short("s")
.long("proving-scheme")
.help("Proving scheme to use to export the verifier")
.value_name("FILE")
.takes_value(true)
.required(false)
.possible_values(constants::SCHEMES)
.default_value(constants::G16),
)
.arg(
Arg::with_name("solidity-abi")
.short("a")
.long("solidity-abi")
.help("Flag for setting the version of the ABI Encoder used in the contract")
.takes_value(true)
.possible_values(&["v1", "v2"])
.default_value("v1")
.required(false),
)
}
pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> {
let curve = sub_matches.value_of("curve").unwrap();
let scheme = sub_matches.value_of("proving-scheme").unwrap();
let curve_parameter = CurveParameter::try_from(curve)?;
let scheme_parameter = SchemeParameter::try_from(scheme)?;
match (curve_parameter, scheme_parameter) {
(CurveParameter::Bn128, SchemeParameter::G16) => {
cli_export_verifier::<Bn128Field, G16>(sub_matches)
}
(CurveParameter::Bn128, SchemeParameter::GM17) => {
cli_export_verifier::<Bn128Field, GM17>(sub_matches)
}
(CurveParameter::Bn128, SchemeParameter::PGHR13) => {
cli_export_verifier::<Bn128Field, PGHR13>(sub_matches)
}
_ => Err(format!("Could not export verifier with given parameters (curve: {}, scheme: {}): not supported", curve, scheme))
}
}
fn cli_export_verifier<T: SolidityCompatibleField, S: SolidityCompatibleScheme<T>>(
sub_matches: &ArgMatches,
) -> Result<(), String> {
println!("Exporting verifier...");
// read vk file
let input_path = Path::new(sub_matches.value_of("input").unwrap());
let input_file = File::open(&input_path)
.map_err(|why| format!("Couldn't open {}: {}", input_path.display(), why))?;
let reader = BufReader::new(input_file);
let vk = serde_json::from_reader(reader)
.map_err(|why| format!("Couldn't deserialize verifying key: {}", why))?;
let abi = SolidityAbi::from(sub_matches.value_of("solidity-abi").unwrap())?;
let verifier = S::export_solidity_verifier(vk, abi);
//write output file
let output_path = Path::new(sub_matches.value_of("output").unwrap());
let output_file = File::create(&output_path)
.map_err(|why| format!("Couldn't create {}: {}", output_path.display(), why))?;
let mut writer = BufWriter::new(output_file);
writer
.write_all(&verifier.as_bytes())
.map_err(|_| "Failed writing output to file".to_string())?;
println!("Finished exporting verifier");
Ok(())
}

View file

@ -0,0 +1,180 @@
use crate::constants;
use crate::helpers::*;
use clap::{App, Arg, ArgMatches, SubCommand};
use std::convert::TryFrom;
use std::fs::File;
use std::io::{BufReader, Read, Write};
use std::path::Path;
use zokrates_core::ir;
use zokrates_core::ir::ProgEnum;
#[cfg(feature = "ark")]
use zokrates_core::proof_system::ark::Ark;
#[cfg(feature = "bellman")]
use zokrates_core::proof_system::bellman::Bellman;
#[cfg(feature = "libsnark")]
use zokrates_core::proof_system::libsnark::Libsnark;
#[cfg(any(feature = "bellman", feature = "ark", feature = "libsnark"))]
use zokrates_core::proof_system::*;
use zokrates_field::Field;
pub fn subcommand() -> App<'static, 'static> {
SubCommand::with_name("generate-proof")
.about("Calculates a proof for a given constraint system and witness")
.arg(
Arg::with_name("witness")
.short("w")
.long("witness")
.help("Path of the witness file")
.value_name("FILE")
.takes_value(true)
.required(false)
.default_value(constants::WITNESS_DEFAULT_PATH),
)
.arg(
Arg::with_name("proving-key-path")
.short("p")
.long("proving-key-path")
.help("Path of the proving key file")
.value_name("FILE")
.takes_value(true)
.required(false)
.default_value(constants::PROVING_KEY_DEFAULT_PATH),
)
.arg(
Arg::with_name("proof-path")
.short("j")
.long("proof-path")
.help("Path of the JSON proof file")
.value_name("FILE")
.takes_value(true)
.required(false)
.default_value(constants::JSON_PROOF_PATH),
)
.arg(
Arg::with_name("input")
.short("i")
.long("input")
.help("Path of the binary")
.value_name("FILE")
.takes_value(true)
.required(false)
.default_value(constants::FLATTENED_CODE_DEFAULT_PATH),
)
.arg(
Arg::with_name("backend")
.short("b")
.long("backend")
.help("Backend to use")
.takes_value(true)
.required(false)
.possible_values(constants::BACKENDS)
.default_value(constants::BELLMAN),
)
.arg(
Arg::with_name("proving-scheme")
.short("s")
.long("proving-scheme")
.help("Proving scheme to use to generate the proof")
.value_name("FILE")
.takes_value(true)
.required(false)
.possible_values(constants::SCHEMES)
.default_value(constants::G16),
)
}
pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> {
let program_path = Path::new(sub_matches.value_of("input").unwrap());
let program_file = File::open(&program_path)
.map_err(|why| format!("Couldn't open {}: {}", program_path.display(), why))?;
let mut reader = BufReader::new(program_file);
let prog = ProgEnum::deserialize(&mut reader)?;
let parameters = Parameters::try_from((
sub_matches.value_of("backend").unwrap(),
match prog {
ProgEnum::Bn128Program(_) => constants::BN128,
ProgEnum::Bls12_381Program(_) => constants::BLS12_381,
ProgEnum::Bls12_377Program(_) => constants::BLS12_377,
ProgEnum::Bw6_761Program(_) => constants::BW6_761,
},
sub_matches.value_of("proving-scheme").unwrap(),
))?;
match parameters {
#[cfg(feature = "bellman")]
Parameters(BackendParameter::Bellman, _, SchemeParameter::G16) => match prog {
ProgEnum::Bn128Program(p) => cli_generate_proof::<_, G16, Bellman>(p, sub_matches),
ProgEnum::Bls12_381Program(p) => cli_generate_proof::<_, G16, Bellman>(p, sub_matches),
_ => unreachable!(),
},
#[cfg(feature = "ark")]
Parameters(BackendParameter::Ark, _, SchemeParameter::GM17) => match prog {
ProgEnum::Bls12_377Program(p) => cli_generate_proof::<_, GM17, Ark>(p, sub_matches),
ProgEnum::Bw6_761Program(p) => cli_generate_proof::<_, GM17, Ark>(p, sub_matches),
ProgEnum::Bn128Program(p) => cli_generate_proof::<_, GM17, Ark>(p, sub_matches),
_ => unreachable!(),
},
#[cfg(feature = "libsnark")]
Parameters(BackendParameter::Libsnark, CurveParameter::Bn128, SchemeParameter::GM17) => {
match prog {
ProgEnum::Bn128Program(p) => {
cli_generate_proof::<_, GM17, Libsnark>(p, sub_matches)
}
_ => unreachable!(),
}
}
#[cfg(feature = "libsnark")]
Parameters(BackendParameter::Libsnark, CurveParameter::Bn128, SchemeParameter::PGHR13) => {
match prog {
ProgEnum::Bn128Program(p) => {
cli_generate_proof::<_, PGHR13, Libsnark>(p, sub_matches)
}
_ => unreachable!(),
}
}
_ => unreachable!(),
}
}
fn cli_generate_proof<T: Field, S: Scheme<T>, B: Backend<T, S>>(
program: ir::Prog<T>,
sub_matches: &ArgMatches,
) -> Result<(), String> {
println!("Generating proof...");
// deserialize witness
let witness_path = Path::new(sub_matches.value_of("witness").unwrap());
let witness_file = match File::open(&witness_path) {
Ok(file) => file,
Err(why) => panic!("Couldn't open {}: {}", witness_path.display(), why),
};
let witness = ir::Witness::read(witness_file)
.map_err(|why| format!("Could not load witness: {:?}", why))?;
let pk_path = Path::new(sub_matches.value_of("proving-key-path").unwrap());
let proof_path = Path::new(sub_matches.value_of("proof-path").unwrap());
let pk_file = File::open(&pk_path)
.map_err(|why| format!("Couldn't open {}: {}", pk_path.display(), why))?;
let mut pk: Vec<u8> = Vec::new();
let mut pk_reader = BufReader::new(pk_file);
pk_reader
.read_to_end(&mut pk)
.map_err(|why| format!("Couldn't read {}: {}", pk_path.display(), why))?;
let proof = B::generate_proof(program, witness, pk);
let mut proof_file = File::create(proof_path).unwrap();
let proof = serde_json::to_string_pretty(&proof).unwrap();
proof_file
.write(proof.as_bytes())
.map_err(|why| format!("Couldn't write to {}: {}", proof_path.display(), why))?;
println!("Proof:\n{}", format!("{}", proof));
Ok(())
}

View file

@ -0,0 +1,12 @@
pub mod check;
pub mod compile;
pub mod compute_witness;
#[cfg(any(feature = "bellman", feature = "ark", feature = "libsnark"))]
pub mod export_verifier;
#[cfg(any(feature = "bellman", feature = "ark", feature = "libsnark"))]
pub mod generate_proof;
pub mod print_proof;
#[cfg(any(feature = "bellman", feature = "ark", feature = "libsnark"))]
pub mod setup;
#[cfg(any(feature = "bellman", feature = "ark", feature = "libsnark"))]
pub mod verify;

View file

@ -0,0 +1,68 @@
use crate::constants::JSON_PROOF_PATH;
use clap::{App, Arg, ArgMatches, SubCommand};
use serde_json::Value;
use std::fs::File;
use std::path::Path;
pub fn subcommand() -> App<'static, 'static> {
SubCommand::with_name("print-proof")
.about("Prints proof in the chosen format")
.arg(
Arg::with_name("proof-path")
.short("j")
.long("proof-path")
.help("Path of the JSON proof file")
.value_name("FILE")
.takes_value(true)
.required(false)
.default_value(JSON_PROOF_PATH),
)
.arg(
Arg::with_name("format")
.short("f")
.long("format")
.value_name("FORMAT")
.help("Format in which the proof should be printed")
.takes_value(true)
.possible_values(&["remix", "json"])
.required(true),
)
}
pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> {
let format = sub_matches.value_of("format").unwrap();
let path = Path::new(sub_matches.value_of("proof-path").unwrap());
let file =
File::open(&path).map_err(|why| format!("Couldn't open {}: {}", path.display(), why))?;
let proof_object: Value = serde_json::from_reader(file).map_err(|why| format!("{:?}", why))?;
match format {
"json" => {
println!("~~~~~~~~ Copy the output below for valid ABIv2 format ~~~~~~~~");
println!();
print!("{}", proof_object["proof"]);
print!(",");
println!("{}", proof_object["inputs"]);
println!();
println!("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
}
"remix" => {
println!("~~~~~~~~ Copy the output below for valid ABIv1 format ~~~~~~~~");
println!();
for (_, value) in proof_object["proof"].as_object().unwrap().iter() {
print!("{}", value);
print!(",");
}
println!("{}", proof_object["inputs"]);
println!();
println!("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
}
_ => unreachable!(),
}
Ok(())
}

View file

@ -0,0 +1,172 @@
use crate::constants;
use crate::helpers::*;
use clap::{App, Arg, ArgMatches, SubCommand};
use std::convert::TryFrom;
use std::fs::File;
use std::io::{BufReader, Write};
use std::path::Path;
use zokrates_core::ir;
use zokrates_core::ir::ProgEnum;
#[cfg(feature = "ark")]
use zokrates_core::proof_system::ark::Ark;
#[cfg(feature = "bellman")]
use zokrates_core::proof_system::bellman::Bellman;
#[cfg(feature = "libsnark")]
use zokrates_core::proof_system::libsnark::Libsnark;
#[cfg(any(feature = "bellman", feature = "ark", feature = "libsnark"))]
use zokrates_core::proof_system::*;
use zokrates_field::Field;
pub fn subcommand() -> App<'static, 'static> {
SubCommand::with_name("setup")
.about("Performs a trusted setup for a given constraint system")
.arg(
Arg::with_name("input")
.short("i")
.long("input")
.help("Path of the binary")
.value_name("FILE")
.takes_value(true)
.required(false)
.default_value(constants::FLATTENED_CODE_DEFAULT_PATH),
)
.arg(
Arg::with_name("proving-key-path")
.short("p")
.long("proving-key-path")
.help("Path of the generated proving key file")
.value_name("FILE")
.takes_value(true)
.required(false)
.default_value(constants::PROVING_KEY_DEFAULT_PATH),
)
.arg(
Arg::with_name("verification-key-path")
.short("v")
.long("verification-key-path")
.help("Path of the generated verification key file")
.value_name("FILE")
.takes_value(true)
.required(false)
.default_value(constants::VERIFICATION_KEY_DEFAULT_PATH),
)
.arg(
Arg::with_name("backend")
.short("b")
.long("backend")
.help("Backend to use")
.takes_value(true)
.required(false)
.possible_values(constants::BACKENDS)
.default_value(constants::BELLMAN),
)
.arg(
Arg::with_name("proving-scheme")
.short("s")
.long("proving-scheme")
.help("Proving scheme to use in the setup")
.takes_value(true)
.required(false)
.possible_values(constants::SCHEMES)
.default_value(constants::G16),
)
.arg(
Arg::with_name("light")
.long("light")
.help("Skip logging the human-readable program and writing it to a file")
.required(false),
)
}
pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> {
// read compiled program
let path = Path::new(sub_matches.value_of("input").unwrap());
let file =
File::open(&path).map_err(|why| format!("Couldn't open {}: {}", path.display(), why))?;
let mut reader = BufReader::new(file);
let prog = ProgEnum::deserialize(&mut reader)?;
let parameters = Parameters::try_from((
sub_matches.value_of("backend").unwrap(),
match prog {
ProgEnum::Bn128Program(_) => constants::BN128,
ProgEnum::Bls12_377Program(_) => constants::BLS12_377,
ProgEnum::Bls12_381Program(_) => constants::BLS12_381,
ProgEnum::Bw6_761Program(_) => constants::BW6_761,
},
sub_matches.value_of("proving-scheme").unwrap(),
))?;
match parameters {
#[cfg(feature = "bellman")]
Parameters(BackendParameter::Bellman, _, SchemeParameter::G16) => match prog {
ProgEnum::Bn128Program(p) => cli_setup::<_, G16, Bellman>(p, sub_matches),
ProgEnum::Bls12_381Program(p) => cli_setup::<_, G16, Bellman>(p, sub_matches),
_ => unreachable!(),
},
#[cfg(feature = "ark")]
Parameters(BackendParameter::Ark, _, SchemeParameter::GM17) => match prog {
ProgEnum::Bls12_377Program(p) => cli_setup::<_, GM17, Ark>(p, sub_matches),
ProgEnum::Bw6_761Program(p) => cli_setup::<_, GM17, Ark>(p, sub_matches),
ProgEnum::Bn128Program(p) => cli_setup::<_, GM17, Ark>(p, sub_matches),
_ => unreachable!(),
},
#[cfg(feature = "libsnark")]
Parameters(BackendParameter::Libsnark, CurveParameter::Bn128, SchemeParameter::GM17) => {
match prog {
ProgEnum::Bn128Program(p) => cli_setup::<_, GM17, Libsnark>(p, sub_matches),
_ => unreachable!(),
}
}
#[cfg(feature = "libsnark")]
Parameters(BackendParameter::Libsnark, CurveParameter::Bn128, SchemeParameter::PGHR13) => {
match prog {
ProgEnum::Bn128Program(p) => cli_setup::<_, PGHR13, Libsnark>(p, sub_matches),
_ => unreachable!(),
}
}
_ => unreachable!(),
}
}
fn cli_setup<T: Field, S: Scheme<T>, B: Backend<T, S>>(
program: ir::Prog<T>,
sub_matches: &ArgMatches,
) -> Result<(), String> {
println!("Performing setup...");
// print deserialized flattened program
if !sub_matches.is_present("light") {
println!("{}", program);
}
// get paths for proving and verification keys
let pk_path = Path::new(sub_matches.value_of("proving-key-path").unwrap());
let vk_path = Path::new(sub_matches.value_of("verification-key-path").unwrap());
// run setup phase
let keypair = B::setup(program);
// write verification key
let mut vk_file = File::create(vk_path)
.map_err(|why| format!("couldn't create {}: {}", vk_path.display(), why))?;
vk_file
.write(
serde_json::to_string_pretty(&keypair.vk)
.unwrap()
.as_bytes(),
)
.map_err(|why| format!("couldn't write to {}: {}", vk_path.display(), why))?;
// write proving key
let mut pk_file = File::create(pk_path)
.map_err(|why| format!("couldn't create {}: {}", pk_path.display(), why))?;
pk_file
.write(keypair.pk.as_ref())
.map_err(|why| format!("couldn't write to {}: {}", pk_path.display(), why))?;
println!("Setup completed.");
Ok(())
}

View file

@ -0,0 +1,133 @@
use crate::constants;
use crate::helpers::*;
use clap::{App, Arg, ArgMatches, SubCommand};
use std::convert::TryFrom;
use std::fs::File;
use std::io::BufReader;
use std::path::Path;
#[cfg(feature = "ark")]
use zokrates_core::proof_system::ark::Ark;
#[cfg(feature = "bellman")]
use zokrates_core::proof_system::bellman::Bellman;
#[cfg(feature = "libsnark")]
use zokrates_core::proof_system::libsnark::Libsnark;
#[cfg(any(feature = "bellman", feature = "ark", feature = "libsnark"))]
use zokrates_core::proof_system::*;
use zokrates_field::{Bls12_377Field, Bls12_381Field, Bn128Field, Bw6_761Field, Field};
pub fn subcommand() -> App<'static, 'static> {
SubCommand::with_name("verify")
.about("Verifies a given proof with the given verification key")
.arg(Arg::with_name("proof-path")
.short("j")
.long("proof-path")
.help("Path of the JSON proof file")
.value_name("FILE")
.takes_value(true)
.required(false)
.default_value(constants::JSON_PROOF_PATH)
).arg(Arg::with_name("verification-key-path")
.short("v")
.long("verification-key-path")
.help("Path of the generated verification key file")
.value_name("FILE")
.takes_value(true)
.required(false)
.default_value(constants::VERIFICATION_KEY_DEFAULT_PATH)
).arg(Arg::with_name("backend")
.short("b")
.long("backend")
.help("Backend to use")
.takes_value(true)
.required(false)
.possible_values(constants::BACKENDS)
.default_value(constants::BELLMAN)
).arg(Arg::with_name("proving-scheme")
.short("s")
.long("proving-scheme")
.help("Proving scheme to use in the setup. Available options are G16 (default), PGHR13 and GM17")
.value_name("FILE")
.takes_value(true)
.required(false)
.default_value(constants::G16)
).arg(Arg::with_name("curve")
.short("c")
.long("curve")
.help("Curve to be used in the verification")
.takes_value(true)
.required(false)
.possible_values(constants::CURVES)
.default_value(constants::BN128)
)
}
pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> {
let parameters = Parameters::try_from((
sub_matches.value_of("backend").unwrap(),
sub_matches.value_of("curve").unwrap(),
sub_matches.value_of("proving-scheme").unwrap(),
))?;
match parameters {
#[cfg(feature = "bellman")]
Parameters(BackendParameter::Bellman, CurveParameter::Bn128, SchemeParameter::G16) => {
cli_verify::<Bn128Field, G16, Bellman>(sub_matches)
}
#[cfg(feature = "bellman")]
Parameters(BackendParameter::Bellman, CurveParameter::Bls12_381, SchemeParameter::G16) => {
cli_verify::<Bls12_381Field, G16, Bellman>(sub_matches)
}
#[cfg(feature = "ark")]
Parameters(BackendParameter::Ark, CurveParameter::Bls12_377, SchemeParameter::GM17) => {
cli_verify::<Bls12_377Field, GM17, Ark>(sub_matches)
}
#[cfg(feature = "ark")]
Parameters(BackendParameter::Ark, CurveParameter::Bw6_761, SchemeParameter::GM17) => {
cli_verify::<Bw6_761Field, GM17, Ark>(sub_matches)
}
#[cfg(feature = "ark")]
Parameters(BackendParameter::Ark, CurveParameter::Bn128, SchemeParameter::GM17) => {
cli_verify::<Bn128Field, GM17, Ark>(sub_matches)
}
#[cfg(feature = "libsnark")]
Parameters(BackendParameter::Libsnark, CurveParameter::Bn128, SchemeParameter::GM17) => {
cli_verify::<Bn128Field, GM17, Libsnark>(sub_matches)
}
#[cfg(feature = "libsnark")]
Parameters(BackendParameter::Libsnark, CurveParameter::Bn128, SchemeParameter::PGHR13) => {
cli_verify::<Bn128Field, PGHR13, Libsnark>(sub_matches)
}
_ => unreachable!(),
}
}
fn cli_verify<T: Field, S: Scheme<T>, B: Backend<T, S>>(
sub_matches: &ArgMatches,
) -> Result<(), String> {
let vk_path = Path::new(sub_matches.value_of("verification-key-path").unwrap());
let vk_file = File::open(&vk_path)
.map_err(|why| format!("Couldn't open {}: {}", vk_path.display(), why))?;
let vk_reader = BufReader::new(vk_file);
let vk = serde_json::from_reader(vk_reader)
.map_err(|why| format!("Couldn't deserialize verification key: {}", why))?;
let proof_path = Path::new(sub_matches.value_of("proof-path").unwrap());
let proof_file = File::open(&proof_path)
.map_err(|why| format!("Couldn't open {}: {}", proof_path.display(), why))?;
let proof_reader = BufReader::new(proof_file);
let proof = serde_json::from_reader(proof_reader)
.map_err(|why| format!("Couldn't deserialize proof: {}", why))?;
println!("Performing verification...");
println!(
"The verification result is: {}",
match B::verify(vk, proof) {
true => "PASS",
false => "FAIL",
}
);
Ok(())
}

View file

@ -1,6 +1,6 @@
[package]
name = "zokrates_core"
version = "0.5.2"
version = "0.5.3"
edition = "2018"
authors = ["Jacob Eberhardt <jacob.eberhardt@tu-berlin.de>", "Dennis Kuhnert <mail@kyroy.com>"]
repository = "https://github.com/JacobEberhardt/ZoKrates"
@ -31,6 +31,7 @@ regex = "0.2"
zokrates_field = { version = "0.3.0", path = "../zokrates_field", default-features = false }
zokrates_pest_ast = { version = "0.1.0", path = "../zokrates_pest_ast" }
zokrates_common = { path = "../zokrates_common" }
zokrates_embed = { path = "../zokrates_embed" }
rand_0_4 = { version = "0.4", package = "rand" }
rand_0_7 = { version = "0.7", package = "rand" }
csv = "1"

View file

@ -5,12 +5,23 @@ use crate::flat_absy::{
use crate::solvers::Solver;
use crate::typed_absy::types::{FunctionKey, Signature, Type};
use std::collections::HashMap;
use zokrates_field::Field;
use zokrates_field::{Bn128Field, Field};
cfg_if::cfg_if! {
if #[cfg(feature = "bellman")] {
use pairing_ce::bn256::Bn256;
use pairing_ce::ff::{PrimeField, PrimeFieldRepr};
use pairing_ce::Engine;
use zokrates_embed::{generate_sha256_round_constraints, BellmanConstraint};
}
}
/// A low level function that contains non-deterministic introduction of variables. It is carried out as is until
/// the flattening step when it can be inlined.
#[derive(Debug, Clone, PartialEq, Hash)]
pub enum FlatEmbed {
#[cfg(feature = "bellman")]
Sha256Round,
Unpack(usize),
U8ToBits,
U16ToBits,
@ -23,6 +34,13 @@ pub enum FlatEmbed {
impl FlatEmbed {
pub fn signature(&self) -> Signature {
match self {
#[cfg(feature = "bellman")]
FlatEmbed::Sha256Round => Signature::new()
.inputs(vec![
Type::array(Type::Boolean, 512),
Type::array(Type::Boolean, 256),
])
.outputs(vec![Type::array(Type::Boolean, 256)]),
FlatEmbed::Unpack(bitwidth) => Signature::new()
.inputs(vec![Type::FieldElement])
.outputs(vec![Type::array(Type::Boolean, *bitwidth)]),
@ -53,6 +71,8 @@ impl FlatEmbed {
pub fn id(&self) -> &'static str {
match self {
#[cfg(feature = "bellman")]
FlatEmbed::Sha256Round => "_SHA256_ROUND",
FlatEmbed::Unpack(_) => "_UNPACK",
FlatEmbed::U8ToBits => "_U8_TO_BITS",
FlatEmbed::U16ToBits => "_U16_TO_BITS",
@ -66,12 +86,137 @@ impl FlatEmbed {
/// Actually get the `FlatFunction` that this `FlatEmbed` represents
pub fn synthetize<T: Field>(&self) -> FlatFunction<T> {
match self {
#[cfg(feature = "bellman")]
FlatEmbed::Sha256Round => sha256_round(),
FlatEmbed::Unpack(bitwidth) => unpack_to_bitwidth(*bitwidth),
_ => unreachable!(),
}
}
}
// util to convert a vector of `(variable_id, coefficient)` to a flat_expression
// we build a binary tree of additions by splitting the vector recursively
#[cfg(feature = "bellman")]
fn flat_expression_from_vec<T: Field, E: Engine>(v: &[(usize, E::Fr)]) -> FlatExpression<T> {
match v.len() {
0 => FlatExpression::Number(T::zero()),
1 => {
let (key, val) = v[0].clone();
let mut res: Vec<u8> = vec![];
val.into_repr().write_le(&mut res).unwrap();
FlatExpression::Mult(
box FlatExpression::Number(T::from_byte_vector(res)),
box FlatExpression::Identifier(FlatVariable::new(key)),
)
}
n => {
let (u, v) = v.split_at(n / 2);
FlatExpression::Add(
box flat_expression_from_vec::<T, E>(u),
box flat_expression_from_vec::<T, E>(v),
)
}
}
}
#[cfg(feature = "bellman")]
impl<T: Field, E: Engine> From<BellmanConstraint<E>> for FlatStatement<T> {
fn from(c: BellmanConstraint<E>) -> FlatStatement<T> {
let rhs_a = flat_expression_from_vec::<T, E>(&c.a);
let rhs_b = flat_expression_from_vec::<T, E>(&c.b);
let lhs = flat_expression_from_vec::<T, E>(&c.c);
FlatStatement::Condition(lhs, FlatExpression::Mult(box rhs_a, box rhs_b))
}
}
/// Returns a flat function which computes a sha256 round
///
/// # Remarks
///
/// The variables inside the function are set in this order:
/// - constraint system variables
/// - arguments
#[cfg(feature = "bellman")]
pub fn sha256_round<T: Field>() -> FlatFunction<T> {
assert_eq!(T::id(), Bn128Field::id());
// Define iterators for all indices at hand
let (r1cs, input_indices, current_hash_indices, output_indices) =
generate_sha256_round_constraints::<Bn256>();
// indices of the input
let input_indices = input_indices.into_iter();
// indices of the current hash
let current_hash_indices = current_hash_indices.into_iter();
// indices of the output
let output_indices = output_indices.into_iter();
let variable_count = r1cs.aux_count + 1; // auxiliary and ONE
// indices of the sha256round constraint system variables
let cs_indices = (0..variable_count).into_iter();
// indices of the arguments to the function
// apply an offset of `variable_count` to get the indice of our dummy `input` argument
let input_argument_indices = input_indices
.clone()
.into_iter()
.map(|i| i + variable_count);
// apply an offset of `variable_count` to get the indice of our dummy `current_hash` argument
let current_hash_argument_indices = current_hash_indices
.clone()
.into_iter()
.map(|i| i + variable_count);
// define parameters to the function based on the variables
let arguments = input_argument_indices
.clone()
.chain(current_hash_argument_indices.clone())
.map(|i| FlatParameter {
id: FlatVariable::new(i),
private: true,
})
.collect();
// define a binding of the first variable in the constraint system to one
let one_binding_statement = FlatStatement::Condition(
FlatVariable::new(0).into(),
FlatExpression::Number(T::from(1)),
);
let input_binding_statements =
// bind input and current_hash to inputs
input_indices.clone().chain(current_hash_indices).zip(input_argument_indices.clone().chain(current_hash_argument_indices.clone())).map(|(cs_index, argument_index)| {
FlatStatement::Condition(
FlatVariable::new(cs_index).into(),
FlatVariable::new(argument_index).into(),
)
});
// insert flattened statements to represent constraints
let constraint_statements = r1cs.constraints.into_iter().map(|c| c.into());
// define which subset of the witness is returned
let outputs: Vec<FlatExpression<T>> = output_indices
.map(|o| FlatExpression::Identifier(FlatVariable::new(o)))
.collect();
// insert a directive to set the witness based on the bellman gadget and inputs
let directive_statement = FlatStatement::Directive(FlatDirective {
outputs: cs_indices.map(|i| FlatVariable::new(i)).collect(),
inputs: input_argument_indices
.chain(current_hash_argument_indices)
.map(|i| FlatVariable::new(i).into())
.collect(),
solver: Solver::Sha256Round,
});
// insert a statement to return the subset of the witness
let return_statement = FlatStatement::Return(FlatExpressionList {
expressions: outputs,
});
let statements = std::iter::once(directive_statement)
.chain(std::iter::once(one_binding_statement))
.chain(input_binding_statements)
.chain(constraint_statements)
.chain(std::iter::once(return_statement))
.collect();
FlatFunction {
arguments,
statements,
}
}
fn use_variable(
layout: &mut HashMap<String, FlatVariable>,
name: String,
@ -219,4 +364,86 @@ mod tests {
);
}
}
#[cfg(feature = "bellman")]
#[cfg(test)]
mod sha256 {
use super::*;
use crate::ir::Interpreter;
#[test]
fn generate_sha256_constraints() {
let compiled = sha256_round::<Bn128Field>();
// function should have 768 inputs
assert_eq!(compiled.arguments.len(), 768);
// function should return 256 values
assert_eq!(
compiled
.statements
.iter()
.filter_map(|s| match s {
FlatStatement::Return(v) => Some(v),
_ => None,
})
.next()
.unwrap()
.expressions
.len(),
256,
);
// directive should take 768 inputs and return n_var outputs
let directive = compiled
.statements
.iter()
.filter_map(|s| match s {
FlatStatement::Directive(d) => Some(d.clone()),
_ => None,
})
.next()
.unwrap();
assert_eq!(directive.inputs.len(), 768);
assert_eq!(directive.outputs.len(), 26935);
// function input should be offset by variable_count
assert_eq!(
compiled.arguments[0].id,
FlatVariable::new(directive.outputs.len() + 1)
);
// bellman variable #0: index 0 should equal 1
assert_eq!(
compiled.statements[1],
FlatStatement::Condition(
FlatVariable::new(0).into(),
FlatExpression::Number(Bn128Field::from(1))
)
);
// bellman input #0: index 1 should equal zokrates input #0: index v_count
assert_eq!(
compiled.statements[2],
FlatStatement::Condition(
FlatVariable::new(1).into(),
FlatVariable::new(26936).into()
)
);
let f = crate::ir::Function::from(compiled);
let prog = crate::ir::Prog {
main: f,
private: vec![true; 768],
};
let input = (0..512)
.map(|_| 0)
.chain((0..256).map(|_| 1))
.map(|i| Bn128Field::from(i))
.collect();
let interpreter = Interpreter::default();
interpreter.execute(&prog, &input).unwrap();
}
}
}

View file

@ -11,8 +11,7 @@ use self::utils::flat_expression_from_bits;
use crate::compile::CompileConfig;
use crate::flat_absy::*;
use crate::ir;
use crate::solvers::Solver;
use crate::solvers::{Executable, Solver};
use crate::zir::types::{FunctionIdentifier, FunctionKey, Signature, Type, UBitwidth};
use crate::zir::*;
use std::collections::hash_map::Entry;
@ -1655,8 +1654,9 @@ impl<'ast, T: Field> Flattener<'ast, T> {
// constants do not require directives
match e.field {
Some(FlatExpression::Number(ref x)) => {
let bits: Vec<_> = ir::Interpreter::default()
.execute_solver(&Solver::bits(to), &vec![x.clone()])
let solver = Solver::bits(to);
let bits: Vec<_> = solver
.execute(&vec![x.clone()])
.unwrap()
.into_iter()
.map(|x| FlatExpression::Number(x))
@ -2147,17 +2147,14 @@ impl<'ast, T: Field> Flattener<'ast, T> {
}
}
/// Checks if the given name is a not used variable and returns a fresh variable.
/// Returns a fresh FlatVariable for a given Variable
/// # Arguments
///
/// * `variable` - a variable in the program being flattened
fn use_variable(&mut self, variable: &Variable<'ast>) -> FlatVariable {
let var = self.issue_new_variable();
assert!(self
.layout
.insert(variable.id.clone(), var.clone())
.is_none());
self.layout.insert(variable.id.clone(), var.clone());
var
}
@ -2651,17 +2648,4 @@ mod tests {
]
);
}
#[test]
#[should_panic]
fn next_variable() {
let config = CompileConfig::default();
let mut flattener: Flattener<Bn128Field> = Flattener::new(&config);
assert_eq!(
FlatVariable::new(0),
flattener.use_variable(&Variable::field_element("a"))
);
// using the same variable a second time should panic
flattener.use_variable(&Variable::field_element("a"));
}
}

View file

@ -16,7 +16,7 @@ use std::path::{Path, PathBuf};
use typed_arena::Arena;
use zokrates_common::Resolver;
use zokrates_field::Field;
use zokrates_field::{Bn128Field, Field};
#[derive(PartialEq, Debug)]
pub struct Error {
@ -149,6 +149,30 @@ impl Importer {
// handle the case of special bellman and packing imports
if import.source.starts_with("EMBED") {
match import.source.to_str().unwrap() {
#[cfg(feature = "bellman")]
"EMBED/sha256round" => {
if T::id() != Bn128Field::id() {
return Err(CompileErrorInner::ImportError(
Error::new(format!(
"Embed sha256round cannot be used with curve {}",
T::name()
))
.with_pos(Some(pos)),
)
.in_file(&location)
.into());
} else {
let alias = alias.unwrap_or("sha256round");
symbols.push(
SymbolDeclaration {
id: &alias,
symbol: Symbol::Flat(FlatEmbed::Sha256Round),
}
.start_end(pos.0, pos.1),
);
}
}
"EMBED/unpack" => {
let alias = alias.unwrap_or("unpack");

View file

@ -1,7 +1,7 @@
use crate::flat_absy::flat_variable::FlatVariable;
use crate::ir::Directive;
use crate::ir::{LinComb, Prog, QuadComb, Statement, Witness};
use crate::solvers::Solver;
use crate::solvers::{Executable, Solver};
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::fmt;
@ -76,7 +76,7 @@ impl Interpreter {
.iter()
.map(|i| i.evaluate(&witness).unwrap())
.collect();
match self.execute_solver(&d.solver, &inputs) {
match d.solver.execute(&inputs) {
Ok(res) => {
for (i, o) in d.outputs.iter().enumerate() {
witness.insert(o.clone(), res[i].clone());
@ -134,79 +134,6 @@ impl Interpreter {
})
}
}
pub fn execute_solver<T: Field>(&self, s: &Solver, inputs: &Vec<T>) -> Result<Vec<T>, String> {
let (expected_input_count, expected_output_count) = s.get_signature();
assert!(inputs.len() == expected_input_count);
let res = match s {
Solver::ConditionEq => match inputs[0].is_zero() {
true => vec![T::zero(), T::one()],
false => vec![
T::one(),
T::one().checked_div(&inputs[0]).unwrap_or(T::one()),
],
},
Solver::Bits(bit_width) => {
let mut num = inputs[0].clone();
let mut res = vec![];
for i in (0..*bit_width).rev() {
if T::from(2).pow(i) <= num {
num = num - T::from(2).pow(i);
res.push(T::one());
} else {
res.push(T::zero());
}
}
res
}
Solver::Xor => {
let x = inputs[0].clone();
let y = inputs[1].clone();
vec![x.clone() + y.clone() - T::from(2) * x * y]
}
Solver::Or => {
let x = inputs[0].clone();
let y = inputs[1].clone();
vec![x.clone() + y.clone() - x * y]
}
// res = b * c - (2b * c - b - c) * (a)
Solver::ShaAndXorAndXorAnd => {
let a = inputs[0].clone();
let b = inputs[1].clone();
let c = inputs[2].clone();
vec![b.clone() * c.clone() - (T::from(2) * b.clone() * c.clone() - b - c) * a]
}
// res = a(b - c) + c
Solver::ShaCh => {
let a = inputs[0].clone();
let b = inputs[1].clone();
let c = inputs[2].clone();
vec![a * (b - c.clone()) + c]
}
Solver::Div => vec![inputs[0]
.clone()
.checked_div(&inputs[1])
.unwrap_or(T::one())],
Solver::EuclideanDiv => {
use num::CheckedDiv;
let n = inputs[0].clone().to_biguint();
let d = inputs[1].clone().to_biguint();
let q = n.checked_div(&d).unwrap_or(0u32.into());
let r = n - d * &q;
vec![T::try_from(q).unwrap(), T::try_from(r).unwrap()]
}
};
assert_eq!(res.len(), expected_output_count);
Ok(res)
}
}
impl<T: Field> LinComb<T> {
@ -265,77 +192,3 @@ impl fmt::Debug for Error {
write!(f, "{}", self)
}
}
#[cfg(test)]
mod tests {
use super::*;
use zokrates_field::Bn128Field;
mod eq_condition {
// Wanted: (Y = (X != 0) ? 1 : 0)
// # Y = if X == 0 then 0 else 1 fi
// # M = if X == 0 then 1 else 1/X fi
use super::*;
#[test]
fn execute() {
let cond_eq = Solver::ConditionEq;
let inputs = vec![0];
let interpreter = Interpreter::default();
let r = interpreter
.execute_solver(
&cond_eq,
&inputs.iter().map(|&i| Bn128Field::from(i)).collect(),
)
.unwrap();
let res: Vec<Bn128Field> = vec![0, 1].iter().map(|&i| Bn128Field::from(i)).collect();
assert_eq!(r, &res[..]);
}
#[test]
fn execute_non_eq() {
let cond_eq = Solver::ConditionEq;
let inputs = vec![1];
let interpreter = Interpreter::default();
let r = interpreter
.execute_solver(
&cond_eq,
&inputs.iter().map(|&i| Bn128Field::from(i)).collect(),
)
.unwrap();
let res: Vec<Bn128Field> = vec![1, 1].iter().map(|&i| Bn128Field::from(i)).collect();
assert_eq!(r, &res[..]);
}
}
#[test]
fn bits_of_one() {
let inputs = vec![Bn128Field::from(1)];
let interpreter = Interpreter::default();
let res = interpreter
.execute_solver(&Solver::Bits(Bn128Field::get_required_bits()), &inputs)
.unwrap();
assert_eq!(res[253], Bn128Field::from(1));
for i in 0..253 {
assert_eq!(res[i], Bn128Field::from(0));
}
}
#[test]
fn bits_of_42() {
let inputs = vec![Bn128Field::from(42)];
let interpreter = Interpreter::default();
let res = interpreter
.execute_solver(&Solver::Bits(Bn128Field::get_required_bits()), &inputs)
.unwrap();
assert_eq!(res[253], Bn128Field::from(0));
assert_eq!(res[252], Bn128Field::from(1));
assert_eq!(res[251], Bn128Field::from(0));
assert_eq!(res[250], Bn128Field::from(1));
assert_eq!(res[249], Bn128Field::from(0));
assert_eq!(res[248], Bn128Field::from(1));
assert_eq!(res[247], Bn128Field::from(0));
}
}

View file

@ -40,6 +40,7 @@ use crate::flat_absy::flat_variable::FlatVariable;
use crate::ir::folder::{fold_function, Folder};
use crate::ir::LinComb;
use crate::ir::*;
use crate::solvers::Executable;
use std::collections::{HashMap, HashSet};
use zokrates_field::Field;
@ -146,10 +147,8 @@ impl<T: Field> Folder<T> for RedefinitionOptimizer<T> {
true => {
// unwrap inputs to their constant value
let inputs = inputs.into_iter().map(|i| i.unwrap()).collect();
// run the interpereter
let outputs = Interpreter::default()
.execute_solver(&d.solver, &inputs)
.unwrap();
// run the solver
let outputs = d.solver.execute(&inputs).unwrap();
assert_eq!(outputs.len(), d.outputs.len());

View file

@ -6,6 +6,10 @@ pub mod gm17;
pub mod groth16;
pub mod pghr13;
pub use self::gm17::GM17;
pub use self::groth16::G16;
pub use self::pghr13::PGHR13;
pub trait Scheme<T: Field> {
type VerificationKey: Serialize + DeserializeOwned;
type ProofPoints: Serialize + DeserializeOwned;

View file

@ -973,22 +973,9 @@ impl<'ast> Checker<'ast> {
return Err(errors.into_iter().map(|e| e.unwrap_err()).collect());
}
// constrain assignees to being identifiers
let (variables, errors): (Vec<_>, Vec<_>) = assignees.into_iter().map(|a| match a.unwrap() {
TypedAssignee::Identifier(v) => Ok(v),
a => Err(ErrorInner {
pos: Some(pos),
message: format!("Only assignment to identifiers is supported, found {}", a)
})
}).partition(|r| r.is_ok());
let assignees: Vec<_> = assignees.into_iter().map(|a| a.unwrap()).collect();
if errors.len() > 0 {
return Err(errors.into_iter().map(|e| e.unwrap_err()).collect());
}
let variables: Vec<_> = variables.into_iter().map(|v| v.unwrap()).collect();
let vars_types = variables.iter().map(|a| Some(a.get_type().clone())).collect();
let assignee_types = assignees.iter().map(|a| Some(a.get_type().clone())).collect();
// find argument types
let mut arguments_checked = vec![];
@ -1000,7 +987,7 @@ impl<'ast> Checker<'ast> {
let arguments_types =
arguments_checked.iter().map(|a| a.get_type()).collect();
let query = FunctionQuery::new(&fun_id, &arguments_types, &vars_types);
let query = FunctionQuery::new(&fun_id, &arguments_types, &assignee_types);
let f = self.find_function(&query);
@ -1010,7 +997,7 @@ impl<'ast> Checker<'ast> {
let call = TypedExpressionList::FunctionCall(f.clone(), arguments_checked, f.signature.outputs.clone());
Ok(TypedStatement::MultipleDefinition(variables, call))
Ok(TypedStatement::MultipleDefinition(assignees, call))
},
None => Err(ErrorInner { pos: Some(pos),
message: format!("Function definition for function {} with signature {} not found.", fun_id, query) }),
@ -3617,14 +3604,14 @@ mod tests {
}
#[test]
fn assign_to_non_variable() {
fn assign_to_select() {
// def foo() -> field:
// return 1
// def main():
// field[1] a = [0]
// a[0] = foo()
// return
// should fail
// should succeed
let foo_statements: Vec<StatementNode> = vec![Statement::Return(
ExpressionList {
@ -3711,16 +3698,7 @@ mod tests {
State::<Bn128Field>::new(vec![("main".into(), module)].into_iter().collect());
let mut checker = new_with_args(HashSet::new(), 0, HashSet::new());
assert_eq!(
checker.check_module(&"main".into(), &mut state),
Err(vec![Error {
inner: ErrorInner {
pos: Some((Position::mock(), Position::mock())),
message: "Only assignment to identifiers is supported, found a[0]".into()
},
module_id: "main".into()
}])
);
assert!(checker.check_module(&"main".into(), &mut state).is_ok());
}
#[test]
@ -3848,8 +3826,8 @@ mod tests {
TypedStatement::Declaration(typed_absy::Variable::field_element("b")),
TypedStatement::MultipleDefinition(
vec![
typed_absy::Variable::field_element("a"),
typed_absy::Variable::field_element("b"),
typed_absy::Variable::field_element("a").into(),
typed_absy::Variable::field_element("b").into(),
],
TypedExpressionList::FunctionCall(
FunctionKey::with_id("foo").signature(

View file

@ -1,6 +1,10 @@
#[cfg(feature = "bellman")]
use pairing_ce::bn256::Bn256;
use serde::{Deserialize, Serialize};
use std::fmt;
use zokrates_field::Field;
#[cfg(feature = "bellman")]
use zokrates_embed::generate_sha256_round_witness;
use zokrates_field::{Bn128Field, Field};
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize, Hash, Eq)]
pub enum Solver {
@ -12,6 +16,8 @@ pub enum Solver {
ShaAndXorAndXorAnd,
ShaCh,
EuclideanDiv,
#[cfg(feature = "bellman")]
Sha256Round,
}
impl fmt::Display for Solver {
@ -31,6 +37,8 @@ impl Solver {
Solver::ShaAndXorAndXorAnd => (3, 1),
Solver::ShaCh => (3, 1),
Solver::EuclideanDiv => (2, 2),
#[cfg(feature = "bellman")]
Solver::Sha256Round => (768, 26935),
}
}
}
@ -41,10 +49,167 @@ impl Solver {
}
}
pub trait Executable<T: Field>: Signed {
pub trait Executable<T> {
fn execute(&self, inputs: &Vec<T>) -> Result<Vec<T>, String>;
}
pub trait Signed {
fn get_signature(&self) -> (usize, usize);
impl<T: Field> Executable<T> for Solver {
fn execute(&self, inputs: &Vec<T>) -> Result<Vec<T>, String> {
let (expected_input_count, expected_output_count) = self.get_signature();
assert_eq!(inputs.len(), expected_input_count);
let res = match self {
Solver::ConditionEq => match inputs[0].is_zero() {
true => vec![T::zero(), T::one()],
false => vec![
T::one(),
T::one().checked_div(&inputs[0]).unwrap_or(T::one()),
],
},
Solver::Bits(bit_width) => {
let mut num = inputs[0].clone();
let mut res = vec![];
for i in (0..*bit_width).rev() {
if T::from(2).pow(i) <= num {
num = num - T::from(2).pow(i);
res.push(T::one());
} else {
res.push(T::zero());
}
}
res
}
Solver::Xor => {
let x = inputs[0].clone();
let y = inputs[1].clone();
vec![x.clone() + y.clone() - T::from(2) * x * y]
}
Solver::Or => {
let x = inputs[0].clone();
let y = inputs[1].clone();
vec![x.clone() + y.clone() - x * y]
}
// res = b * c - (2b * c - b - c) * (a)
Solver::ShaAndXorAndXorAnd => {
let a = inputs[0].clone();
let b = inputs[1].clone();
let c = inputs[2].clone();
vec![b.clone() * c.clone() - (T::from(2) * b.clone() * c.clone() - b - c) * a]
}
// res = a(b - c) + c
Solver::ShaCh => {
let a = inputs[0].clone();
let b = inputs[1].clone();
let c = inputs[2].clone();
vec![a * (b - c.clone()) + c]
}
Solver::Div => vec![inputs[0]
.clone()
.checked_div(&inputs[1])
.unwrap_or(T::one())],
Solver::EuclideanDiv => {
use num::CheckedDiv;
let n = inputs[0].clone().to_biguint();
let d = inputs[1].clone().to_biguint();
let q = n.checked_div(&d).unwrap_or(0u32.into());
let r = n - d * &q;
vec![T::try_from(q).unwrap(), T::try_from(r).unwrap()]
}
#[cfg(feature = "bellman")]
Solver::Sha256Round => {
assert_eq!(T::id(), Bn128Field::id());
let i = &inputs[0..512];
let h = &inputs[512..];
let to_fr = |x: &T| {
use pairing_ce::ff::{PrimeField, ScalarEngine};
let s = x.to_dec_string();
<Bn256 as ScalarEngine>::Fr::from_str(&s).unwrap()
};
let i: Vec<_> = i.iter().map(|x| to_fr(x)).collect();
let h: Vec<_> = h.iter().map(|x| to_fr(x)).collect();
assert_eq!(h.len(), 256);
generate_sha256_round_witness::<Bn256>(&i, &h)
.into_iter()
.map(|x| {
use bellman_ce::pairing::ff::{PrimeField, PrimeFieldRepr};
let mut res: Vec<u8> = vec![];
x.into_repr().write_le(&mut res).unwrap();
T::from_byte_vector(res)
})
.collect()
}
};
assert_eq!(res.len(), expected_output_count);
Ok(res)
}
}
#[cfg(test)]
mod tests {
use super::*;
use zokrates_field::Bn128Field;
mod eq_condition {
// Wanted: (Y = (X != 0) ? 1 : 0)
// # Y = if X == 0 then 0 else 1 fi
// # M = if X == 0 then 1 else 1/X fi
use super::*;
#[test]
fn execute() {
let cond_eq = Solver::ConditionEq;
let inputs = vec![0];
let r = cond_eq
.execute(&inputs.iter().map(|&i| Bn128Field::from(i)).collect())
.unwrap();
let res: Vec<Bn128Field> = vec![0, 1].iter().map(|&i| Bn128Field::from(i)).collect();
assert_eq!(r, &res[..]);
}
#[test]
fn execute_non_eq() {
let cond_eq = Solver::ConditionEq;
let inputs = vec![1];
let r = cond_eq
.execute(&inputs.iter().map(|&i| Bn128Field::from(i)).collect())
.unwrap();
let res: Vec<Bn128Field> = vec![1, 1].iter().map(|&i| Bn128Field::from(i)).collect();
assert_eq!(r, &res[..]);
}
}
#[test]
fn bits_of_one() {
let bits = Solver::Bits(Bn128Field::get_required_bits());
let inputs = vec![Bn128Field::from(1)];
let res = bits.execute(&inputs).unwrap();
assert_eq!(res[253], Bn128Field::from(1));
for i in 0..253 {
assert_eq!(res[i], Bn128Field::from(0));
}
}
#[test]
fn bits_of_42() {
let bits = Solver::Bits(Bn128Field::get_required_bits());
let inputs = vec![Bn128Field::from(42)];
let res = bits.execute(&inputs).unwrap();
assert_eq!(res[253], Bn128Field::from(0));
assert_eq!(res[252], Bn128Field::from(1));
assert_eq!(res[251], Bn128Field::from(0));
assert_eq!(res[250], Bn128Field::from(1));
assert_eq!(res[249], Bn128Field::from(0));
assert_eq!(res[248], Bn128Field::from(1));
assert_eq!(res[247], Bn128Field::from(0));
}
}

View file

@ -100,7 +100,47 @@ impl<'ast, T: Field> Flattener<T> {
) -> Vec<zir::ZirAssignee<'ast>> {
match a {
typed_absy::TypedAssignee::Identifier(v) => self.fold_variable(v),
_ => unreachable!(),
typed_absy::TypedAssignee::Select(box a, box i) => {
use typed_absy::Typed;
let count = match a.get_type() {
typed_absy::Type::Array(array_ty) => array_ty.ty.get_primitive_count(),
_ => unreachable!(),
};
let a = self.fold_assignee(a);
match i {
typed_absy::FieldElementExpression::Number(n) => {
let index = n.to_dec_string().parse::<usize>().unwrap();
a[index * count..(index + 1) * count].to_vec()
}
i => unreachable!("index {} not allowed, should be a constant", i),
}
}
typed_absy::TypedAssignee::Member(box a, m) => {
use typed_absy::Typed;
let (offset, size) = match a.get_type() {
typed_absy::Type::Struct(struct_type) => {
struct_type
.members
.iter()
.fold((0, None), |(offset, size), member| match size {
Some(_) => (offset, size),
None => match m == member.id {
true => (offset, Some(member.ty.get_primitive_count())),
false => (offset + member.ty.get_primitive_count(), None),
},
})
}
_ => unreachable!(),
};
let size = size.unwrap();
let a = self.fold_assignee(a);
a[offset..offset + size].to_vec()
}
}
}
@ -257,7 +297,7 @@ pub fn fold_statement<'ast, T: Field>(
vec![zir::ZirStatement::MultipleDefinition(
variables
.into_iter()
.flat_map(|v| f.fold_variable(v))
.flat_map(|v| f.fold_assignee(v))
.collect(),
f.fold_expression_list(elist),
)]

View file

@ -100,6 +100,14 @@ impl<'ast, T: Field> Inliner<'ast, T> {
// inline all calls in the main function, recursively
let main = inliner.fold_function_symbol(main);
cfg_if::cfg_if! {
if #[cfg(feature = "bellman")] {
// define a function in the main module for the `sha256` embed
let sha256_round = crate::embed::FlatEmbed::Sha256Round;
let sha256_round_key = sha256_round.key::<T>();
}
}
// define a function in the main module for the `unpack` embed
let unpack = crate::embed::FlatEmbed::Unpack(T::get_required_bits());
let unpack_key = unpack.key::<T>();
@ -135,6 +143,8 @@ impl<'ast, T: Field> Inliner<'ast, T> {
"main".into(),
TypedModule {
functions: vec![
#[cfg(feature = "bellman")]
(sha256_round_key, TypedFunctionSymbol::Flat(sha256_round)),
(unpack_key, TypedFunctionSymbol::Flat(unpack)),
(u32_from_bits_key, TypedFunctionSymbol::Flat(u32_from_bits)),
(u16_from_bits_key, TypedFunctionSymbol::Flat(u16_from_bits)),
@ -290,24 +300,22 @@ impl<'ast, T: Field> Folder<'ast, T> for Inliner<'ast, T> {
// add extra statements before the modified statement
fn fold_statement(&mut self, s: TypedStatement<'ast, T>) -> Vec<TypedStatement<'ast, T>> {
let folded = match s {
TypedStatement::MultipleDefinition(variables, elist) => match elist {
TypedStatement::MultipleDefinition(assignees, elist) => match elist {
TypedExpressionList::FunctionCall(key, exps, types) => {
let variables: Vec<_> = variables
let assignees: Vec<_> = assignees
.into_iter()
.map(|a| self.fold_variable(a))
.map(|a| self.fold_assignee(a))
.collect();
let exps: Vec<_> = exps.into_iter().map(|e| self.fold_expression(e)).collect();
match self.try_inline_call(&key, exps) {
Ok(ret) => variables
Ok(ret) => assignees
.into_iter()
.zip(ret.into_iter())
.map(|(v, e)| {
TypedStatement::Definition(TypedAssignee::Identifier(v), e)
})
.map(|(a, e)| TypedStatement::Definition(a, e))
.collect(),
Err((key, expressions)) => vec![TypedStatement::MultipleDefinition(
variables,
assignees,
TypedExpressionList::FunctionCall(key, expressions, types),
)],
}
@ -356,7 +364,7 @@ impl<'ast, T: Field> Folder<'ast, T> for Inliner<'ast, T> {
};
self.statement_buffer
.push(TypedStatement::MultipleDefinition(
vec![Variable::with_id_and_type(id.clone(), tys[0].clone())],
vec![Variable::with_id_and_type(id.clone(), tys[0].clone()).into()],
TypedExpressionList::FunctionCall(
key.clone(),
expressions.clone(),
@ -410,7 +418,7 @@ impl<'ast, T: Field> Folder<'ast, T> for Inliner<'ast, T> {
};
self.statement_buffer
.push(TypedStatement::MultipleDefinition(
vec![Variable::with_id_and_type(id.clone(), tys[0].clone())],
vec![Variable::with_id_and_type(id.clone(), tys[0].clone()).into()],
TypedExpressionList::FunctionCall(
key.clone(),
expressions.clone(),
@ -466,7 +474,7 @@ impl<'ast, T: Field> Folder<'ast, T> for Inliner<'ast, T> {
};
self.statement_buffer
.push(TypedStatement::MultipleDefinition(
vec![Variable::with_id_and_type(id.clone(), tys[0].clone())],
vec![Variable::with_id_and_type(id.clone(), tys[0].clone()).into()],
TypedExpressionList::FunctionCall(
embed_key.clone(),
expressions.clone(),
@ -523,7 +531,7 @@ impl<'ast, T: Field> Folder<'ast, T> for Inliner<'ast, T> {
};
self.statement_buffer
.push(TypedStatement::MultipleDefinition(
vec![Variable::with_id_and_type(id.clone(), tys[0].clone())],
vec![Variable::with_id_and_type(id.clone(), tys[0].clone()).into()],
TypedExpressionList::FunctionCall(
key.clone(),
expressions.clone(),
@ -577,7 +585,7 @@ impl<'ast, T: Field> Folder<'ast, T> for Inliner<'ast, T> {
};
self.statement_buffer
.push(TypedStatement::MultipleDefinition(
vec![Variable::with_id_and_type(id.clone(), tys[0].clone())],
vec![Variable::with_id_and_type(id.clone(), tys[0].clone()).into()],
TypedExpressionList::FunctionCall(
embed_key.clone(),
expressions.clone(),
@ -1259,7 +1267,7 @@ mod tests {
arguments: vec![],
statements: vec![
TypedStatement::MultipleDefinition(
vec![Variable::field_element("a")],
vec![Variable::field_element("a").into()],
TypedExpressionList::FunctionCall(
FunctionKey::with_id("foo").signature(
Signature::new().outputs(vec![Type::FieldElement]),
@ -1368,7 +1376,7 @@ mod tests {
arguments: vec![],
statements: vec![
TypedStatement::MultipleDefinition(
vec![Variable::field_element("a")],
vec![Variable::field_element("a").into()],
TypedExpressionList::FunctionCall(
FunctionKey::with_id("foo").signature(
Signature::new().outputs(vec![Type::FieldElement]),

View file

@ -14,7 +14,8 @@ mod return_binder;
mod uint_optimizer;
mod unconstrained_vars;
mod unroll;
mod variable_access_remover;
mod variable_read_remover;
mod variable_write_remover;
use self::flatten_complex_types::Flattener;
use self::inline::Inliner;
@ -24,7 +25,8 @@ use self::redefinition::RedefinitionOptimizer;
use self::return_binder::ReturnBinder;
use self::uint_optimizer::UintOptimizer;
use self::unconstrained_vars::UnconstrainedVariableDetector;
use self::variable_access_remover::VariableAccessRemover;
use self::variable_read_remover::VariableReadRemover;
use self::variable_write_remover::VariableWriteRemover;
use crate::flat_absy::FlatProg;
use crate::ir::Prog;
use crate::typed_absy::TypedProgram;
@ -52,8 +54,11 @@ impl<'ast, T: Field> TypedProgram<'ast, T> {
// optimize redefinitions
let r = RedefinitionOptimizer::optimize(r);
// remove assignment to variable index
let r = VariableWriteRemover::apply(r);
// remove variable access to complex types
let r = VariableAccessRemover::apply(r);
let r = VariableReadRemover::apply(r);
// convert to zir, removing complex types
let zir = Flattener::flatten(r);

View file

@ -20,7 +20,7 @@ use zokrates_field::Field;
pub struct Propagator<'ast, T: Field> {
// constants keeps track of constant expressions
// we currently do not support partially constant expressions: `field [x, 1][1]` is not considered constant, `field [0, 1][1]` is
constants: HashMap<TypedAssignee<'ast, T>, TypedExpression<'ast, T>>,
constants: HashMap<Identifier<'ast>, TypedExpression<'ast, T>>,
// the verbose mode doesn't remove statements which assign constants to variables
// it's required when using propagation in combination with unrolling
verbose: bool,
@ -48,6 +48,63 @@ impl<'ast, T: Field> Propagator<'ast, T> {
pub fn propagate_verbose(p: TypedProgram<'ast, T>) -> TypedProgram<'ast, T> {
Propagator::verbose().fold_program(p)
}
// get a mutable reference to the constant corresponding to a given assignee if any, otherwise
// return the identifier at the root of this assignee
fn try_get_constant_mut<'a>(
&mut self,
assignee: &'a TypedAssignee<'ast, T>,
) -> Result<(&'a Variable<'ast>, &mut TypedExpression<'ast, T>), &'a Variable<'ast>> {
match assignee {
TypedAssignee::Identifier(var) => self
.constants
.get_mut(&var.id)
.map(|c| Ok((var, c)))
.unwrap_or(Err(var)),
TypedAssignee::Select(box assignee, box index) => {
match self.try_get_constant_mut(&assignee) {
Ok((v, c)) => match index {
FieldElementExpression::Number(n) => {
let n = n.to_dec_string().parse::<usize>().unwrap();
match c {
TypedExpression::Array(a) => match a.as_inner_mut() {
ArrayExpressionInner::Value(value) => Ok((v, &mut value[n])),
_ => unreachable!(),
},
_ => unreachable!(),
}
}
_ => Err(v),
},
e => e,
}
}
TypedAssignee::Member(box assignee, m) => match self.try_get_constant_mut(&assignee) {
Ok((v, c)) => {
let ty = assignee.get_type();
let index = match ty {
Type::Struct(struct_ty) => struct_ty
.members
.iter()
.position(|member| *m == member.id)
.unwrap(),
_ => unreachable!(),
};
match c {
TypedExpression::Struct(a) => match a.as_inner_mut() {
StructExpressionInner::Value(value) => Ok((v, &mut value[index])),
_ => unreachable!(),
},
_ => unreachable!(),
}
}
e => e,
},
}
}
}
fn is_constant<'ast, T: Field>(e: &TypedExpression<'ast, T>) -> bool {
@ -78,44 +135,81 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
fn fold_statement(&mut self, s: TypedStatement<'ast, T>) -> Vec<TypedStatement<'ast, T>> {
let res = match s {
TypedStatement::Declaration(v) => Some(TypedStatement::Declaration(v)),
TypedStatement::Return(expressions) => Some(TypedStatement::Return(
TypedStatement::Declaration(v) => vec![TypedStatement::Declaration(v)],
TypedStatement::Return(expressions) => vec![TypedStatement::Return(
expressions
.into_iter()
.map(|e| self.fold_expression(e))
.collect(),
)),
)],
// propagation to the defined variable if rhs is a constant
TypedStatement::Definition(TypedAssignee::Identifier(var), expr) => {
TypedStatement::Definition(assignee, expr) => {
let expr = self.fold_expression(expr);
let assignee = self.fold_assignee(assignee);
if is_constant(&expr) {
self.constants
.insert(TypedAssignee::Identifier(var.clone()), expr.clone());
match self.verbose {
true => Some(TypedStatement::Definition(
TypedAssignee::Identifier(var),
expr,
)),
false => None,
let verbose = self.verbose;
match assignee {
TypedAssignee::Identifier(var) => match verbose {
true => {
assert!(self
.constants
.insert(var.id.clone(), expr.clone())
.is_none());
vec![TypedStatement::Definition(
TypedAssignee::Identifier(var),
expr,
)]
}
false => {
assert!(self.constants.insert(var.id, expr).is_none());
vec![]
}
},
assignee => match self.try_get_constant_mut(&assignee) {
Ok((_, c)) => match verbose {
true => {
*c = expr.clone();
vec![TypedStatement::Definition(assignee, expr)]
}
false => {
*c = expr;
vec![]
}
},
Err(v) => match self.constants.remove(&v.id) {
// invalidate the cache for this identifier, and define the latest
// version of the constant in the program, if any
Some(c) => vec![
TypedStatement::Definition(v.clone().into(), c),
TypedStatement::Definition(assignee, expr),
],
None => vec![TypedStatement::Definition(assignee, expr)],
},
},
}
} else {
Some(TypedStatement::Definition(
TypedAssignee::Identifier(var),
expr,
))
// the expression being assigned is not constant, invalidate the cache
let v = self
.try_get_constant_mut(&assignee)
.map(|(v, _)| v)
.unwrap_or_else(|v| v);
match self.constants.remove(&v.id) {
Some(c) => vec![
TypedStatement::Definition(v.clone().into(), c),
TypedStatement::Definition(assignee, expr),
],
None => vec![TypedStatement::Definition(assignee, expr)],
}
}
}
TypedStatement::Definition(TypedAssignee::Select(..), _) => {
unreachable!("array updates should have been replaced with full array redef")
}
TypedStatement::Definition(TypedAssignee::Member(..), _) => {
unreachable!("struct update should have been replaced with full struct redef")
}
// propagate the boolean
TypedStatement::Assertion(e) => {
// could stop execution here if condition is known to fail
Some(TypedStatement::Assertion(self.fold_boolean_expression(e)))
vec![TypedStatement::Assertion(self.fold_boolean_expression(e))]
}
// only loops with variable bounds are expected here
// we stop propagation here as constants maybe be modified inside the loop body
@ -127,10 +221,15 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
// invalidate the constants map as any constant could be modified inside the loop body, which we don't visit
self.constants.clear();
Some(TypedStatement::For(v, from, to, statements))
vec![TypedStatement::For(v, from, to, statements)]
}
TypedStatement::MultipleDefinition(variables, expression_list) => {
TypedStatement::MultipleDefinition(assignees, expression_list) => {
let assignees: Vec<TypedAssignee<'ast, T>> = assignees
.into_iter()
.map(|a| self.fold_assignee(a))
.collect();
let expression_list = self.fold_expression_list(expression_list);
match expression_list {
TypedExpressionList::FunctionCall(key, arguments, types) => {
let arguments: Vec<_> = arguments
@ -139,7 +238,7 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
.collect();
fn process_u_from_bits<'ast, T: Field>(
variables: Vec<Variable<'ast>>,
variables: Vec<TypedAssignee<'ast, T>>,
arguments: Vec<TypedExpression<'ast, T>>,
bitwidth: UBitwidth,
) -> TypedExpression<'ast, T> {
@ -183,7 +282,7 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
}
fn process_u_to_bits<'ast, T: Field>(
variables: Vec<Variable<'ast>>,
variables: Vec<TypedAssignee<'ast, T>>,
arguments: Vec<TypedExpression<'ast, T>>,
bitwidth: UBitwidth,
) -> TypedExpression<'ast, T> {
@ -224,37 +323,37 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
true => {
let r: Option<TypedExpression<'ast, T>> = match key.id {
"_U32_FROM_BITS" => Some(process_u_from_bits(
variables.clone(),
assignees.clone(),
arguments.clone(),
UBitwidth::B32,
)),
"_U16_FROM_BITS" => Some(process_u_from_bits(
variables.clone(),
assignees.clone(),
arguments.clone(),
UBitwidth::B16,
)),
"_U8_FROM_BITS" => Some(process_u_from_bits(
variables.clone(),
assignees.clone(),
arguments.clone(),
UBitwidth::B8,
)),
"_U32_TO_BITS" => Some(process_u_to_bits(
variables.clone(),
assignees.clone(),
arguments.clone(),
UBitwidth::B32,
)),
"_U16_TO_BITS" => Some(process_u_to_bits(
variables.clone(),
assignees.clone(),
arguments.clone(),
UBitwidth::B16,
)),
"_U8_TO_BITS" => Some(process_u_to_bits(
variables.clone(),
assignees.clone(),
arguments.clone(),
UBitwidth::B8,
)),
"_UNPACK" => {
assert_eq!(variables.len(), 1);
assert_eq!(assignees.len(), 1);
assert_eq!(arguments.len(), 1);
match FieldElementExpression::try_from(arguments[0].clone())
@ -294,32 +393,120 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
};
match r {
// if the function call returns a constant
Some(expr) => {
self.constants.insert(
TypedAssignee::Identifier(variables[0].clone()),
expr.clone(),
);
match self.verbose {
true => Some(TypedStatement::MultipleDefinition(
variables,
TypedExpressionList::FunctionCall(
key, arguments, types,
),
)),
false => None,
let verbose = self.verbose;
let mut assignees = assignees;
match assignees.pop().unwrap() {
TypedAssignee::Identifier(var) => match verbose {
true => {
self.constants
.insert(var.id.clone(), expr.clone());
vec![TypedStatement::Definition(
TypedAssignee::Identifier(var),
expr,
)]
}
false => {
self.constants.insert(var.id, expr);
vec![]
}
},
assignee => {
match self.try_get_constant_mut(&assignee) {
Ok((_, c)) => match verbose {
true => {
*c = expr.clone();
vec![TypedStatement::Definition(
assignee, expr,
)]
}
false => {
*c = expr;
vec![]
}
},
Err(v) => match self.constants.remove(&v.id) {
Some(c) => vec![
TypedStatement::Definition(
v.clone().into(),
c,
),
TypedStatement::Definition(
assignee, expr,
),
],
None => vec![TypedStatement::Definition(
assignee, expr,
)],
},
}
}
}
}
None => {
let l = TypedExpressionList::FunctionCall(
key, arguments, types,
);
Some(TypedStatement::MultipleDefinition(variables, l))
// if the function call does not return a constant, invalidate the cache
// this happpens because we only propagate certain calls here
let mut assignees = assignees;
let assignee = assignees.pop().unwrap();
let v = self
.try_get_constant_mut(&assignee)
.map(|(v, _)| v)
.unwrap_or_else(|v| v);
match self.constants.remove(&v.id) {
Some(c) => vec![
TypedStatement::Definition(v.clone().into(), c),
TypedStatement::MultipleDefinition(
vec![assignee],
TypedExpressionList::FunctionCall(
key, arguments, types,
),
),
],
None => vec![TypedStatement::MultipleDefinition(
vec![assignee],
TypedExpressionList::FunctionCall(
key, arguments, types,
),
)],
}
}
}
}
false => {
// if the function arguments are not constant, invalidate the cache
// for the return assignees
let invalidations = assignees
.iter()
.flat_map(|assignee| {
let v = self
.try_get_constant_mut(&assignee)
.map(|(v, _)| v)
.unwrap_or_else(|v| v);
match self.constants.remove(&v.id) {
Some(c) => vec![TypedStatement::Definition(
v.clone().into(),
c,
)],
None => vec![],
}
})
.collect::<Vec<_>>();
let l = TypedExpressionList::FunctionCall(key, arguments, types);
Some(TypedStatement::MultipleDefinition(variables, l))
invalidations
.into_iter()
.chain(std::iter::once(TypedStatement::MultipleDefinition(
assignees, l,
)))
.collect()
}
}
}
@ -327,13 +514,10 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
}
};
// In verbose mode, we always return a statement
assert!(res.is_some() || !self.verbose);
// In verbose mode, we always return at least a statement
assert!(res.len() > 0 || !self.verbose);
match res {
Some(v) => vec![v],
None => vec![],
}
res
}
fn fold_uint_expression_inner(
@ -342,20 +526,13 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
e: UExpressionInner<'ast, T>,
) -> UExpressionInner<'ast, T> {
match e {
UExpressionInner::Identifier(id) => {
match self
.constants
.get(&TypedAssignee::Identifier(Variable::uint(
id.clone(),
bitwidth,
))) {
Some(e) => match e {
TypedExpression::Uint(e) => e.as_inner().clone(),
_ => unreachable!("constant stored for a uint should be a uint"),
},
None => UExpressionInner::Identifier(id),
}
}
UExpressionInner::Identifier(id) => match self.constants.get(&id) {
Some(e) => match e {
TypedExpression::Uint(e) => e.as_inner().clone(),
_ => unreachable!("constant stored for a uint should be a uint"),
},
None => UExpressionInner::Identifier(id),
},
UExpressionInner::Add(box e1, box e2) => match (
self.fold_uint_expression(e1).into_inner(),
self.fold_uint_expression(e2).into_inner(),
@ -567,16 +744,16 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
}
}
(ArrayExpressionInner::Identifier(id), FieldElementExpression::Number(n)) => {
match self.constants.get(&TypedAssignee::Select(
box TypedAssignee::Identifier(Variable::array(
id.clone(),
inner_type.clone(),
size,
)),
box FieldElementExpression::Number(n.clone()).into(),
)) {
Some(e) => match e {
TypedExpression::Uint(e) => e.clone().into_inner(),
match self.constants.get(&id) {
Some(a) => match a {
TypedExpression::Array(a) => match a.as_inner() {
ArrayExpressionInner::Value(v) => UExpression::try_from(
v[n.to_dec_string().parse::<usize>().unwrap()].clone(),
)
.unwrap()
.into_inner(),
_ => unreachable!(),
},
_ => unreachable!(""),
},
None => UExpressionInner::Select(
@ -608,21 +785,15 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
e: FieldElementExpression<'ast, T>,
) -> FieldElementExpression<'ast, T> {
match e {
FieldElementExpression::Identifier(id) => {
match self
.constants
.get(&TypedAssignee::Identifier(Variable::field_element(
id.clone(),
))) {
Some(e) => match e {
TypedExpression::FieldElement(e) => e.clone(),
_ => unreachable!(
"constant stored for a field element should be a field element"
),
},
None => FieldElementExpression::Identifier(id),
}
}
FieldElementExpression::Identifier(id) => match self.constants.get(&id) {
Some(e) => match e {
TypedExpression::FieldElement(e) => e.clone(),
_ => unreachable!(
"constant stored for a field element should be a field element"
),
},
None => FieldElementExpression::Identifier(id),
},
FieldElementExpression::Add(box e1, box e2) => match (
self.fold_field_expression(e1),
self.fold_field_expression(e2),
@ -707,17 +878,18 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
}
}
(ArrayExpressionInner::Identifier(id), FieldElementExpression::Number(n)) => {
match self.constants.get(&TypedAssignee::Select(
box TypedAssignee::Identifier(Variable::array(
id.clone(),
inner_type.clone(),
size,
)),
box FieldElementExpression::Number(n.clone()).into(),
)) {
Some(e) => match e {
TypedExpression::FieldElement(e) => e.clone(),
_ => unreachable!("??"),
match self.constants.get(&id) {
Some(a) => match a {
TypedExpression::Array(a) => match a.as_inner() {
ArrayExpressionInner::Value(v) => {
FieldElementExpression::try_from(
v[n.to_dec_string().parse::<usize>().unwrap()].clone(),
)
.unwrap()
}
_ => unreachable!(),
},
_ => unreachable!(""),
},
None => FieldElementExpression::Select(
box ArrayExpressionInner::Identifier(id).annotate(inner_type, size),
@ -772,21 +944,13 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
e: ArrayExpressionInner<'ast, T>,
) -> ArrayExpressionInner<'ast, T> {
match e {
ArrayExpressionInner::Identifier(id) => {
match self
.constants
.get(&TypedAssignee::Identifier(Variable::array(
id.clone(),
ty.clone(),
size,
))) {
Some(e) => match e {
TypedExpression::Array(e) => e.as_inner().clone(),
_ => panic!("constant stored for an array should be an array"),
},
None => ArrayExpressionInner::Identifier(id),
}
}
ArrayExpressionInner::Identifier(id) => match self.constants.get(&id) {
Some(e) => match e {
TypedExpression::Array(e) => e.as_inner().clone(),
_ => panic!("constant stored for an array should be an array"),
},
None => ArrayExpressionInner::Identifier(id),
},
ArrayExpressionInner::Select(box array, box index) => {
let array = self.fold_array_expression(array);
let index = self.fold_field_expression(index);
@ -809,17 +973,17 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
}
}
(ArrayExpressionInner::Identifier(id), FieldElementExpression::Number(n)) => {
match self.constants.get(&TypedAssignee::Select(
box TypedAssignee::Identifier(Variable::array(
id.clone(),
inner_type.clone(),
size,
)),
box FieldElementExpression::Number(n.clone()).into(),
)) {
Some(e) => match e {
TypedExpression::Array(e) => e.clone().into_inner(),
_ => unreachable!("should be an array"),
match self.constants.get(&id) {
Some(a) => match a {
TypedExpression::Array(a) => match a.as_inner() {
ArrayExpressionInner::Value(v) => ArrayExpression::try_from(
v[n.to_dec_string().parse::<usize>().unwrap()].clone(),
)
.unwrap()
.into_inner(),
_ => unreachable!(),
},
_ => unreachable!(""),
},
None => ArrayExpressionInner::Select(
box ArrayExpressionInner::Identifier(id).annotate(inner_type, size),
@ -885,20 +1049,13 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
e: StructExpressionInner<'ast, T>,
) -> StructExpressionInner<'ast, T> {
match e {
StructExpressionInner::Identifier(id) => {
match self
.constants
.get(&TypedAssignee::Identifier(Variable::struc(
id.clone(),
ty.clone(),
))) {
Some(e) => match e {
TypedExpression::Struct(e) => e.as_inner().clone(),
_ => panic!("constant stored for an array should be an array"),
},
None => StructExpressionInner::Identifier(id),
}
}
StructExpressionInner::Identifier(id) => match self.constants.get(&id) {
Some(e) => match e {
TypedExpression::Struct(e) => e.as_inner().clone(),
_ => panic!("constant stored for an array should be an array"),
},
None => StructExpressionInner::Identifier(id),
},
StructExpressionInner::Select(box array, box index) => {
let array = self.fold_array_expression(array);
let index = self.fold_field_expression(index);
@ -921,17 +1078,17 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
}
}
(ArrayExpressionInner::Identifier(id), FieldElementExpression::Number(n)) => {
match self.constants.get(&TypedAssignee::Select(
box TypedAssignee::Identifier(Variable::array(
id.clone(),
inner_type.clone(),
size,
)),
box FieldElementExpression::Number(n.clone()).into(),
)) {
Some(e) => match e {
TypedExpression::Struct(e) => e.clone().into_inner(),
_ => unreachable!("should be a struct"),
match self.constants.get(&id) {
Some(a) => match a {
TypedExpression::Array(a) => match a.as_inner() {
ArrayExpressionInner::Value(v) => StructExpression::try_from(
v[n.to_dec_string().parse::<usize>().unwrap()].clone(),
)
.unwrap()
.into_inner(),
_ => unreachable!(),
},
_ => unreachable!(""),
},
None => StructExpressionInner::Select(
box ArrayExpressionInner::Identifier(id).annotate(inner_type, size),
@ -1002,10 +1159,7 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
// These kind of reduction rules are easier to apply later in the process, when we have canonical representations
// of expressions, ie `a + a` would always be written `2 * a`
match e {
BooleanExpression::Identifier(id) => match self
.constants
.get(&TypedAssignee::Identifier(Variable::boolean(id.clone())))
{
BooleanExpression::Identifier(id) => match self.constants.get(&id) {
Some(e) => match e {
TypedExpression::Boolean(e) => e.clone(),
_ => panic!("constant stored for a boolean should be a boolean"),
@ -1152,17 +1306,16 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
}
}
(ArrayExpressionInner::Identifier(id), FieldElementExpression::Number(n)) => {
match self.constants.get(&TypedAssignee::Select(
box TypedAssignee::Identifier(Variable::array(
id.clone(),
inner_type.clone(),
size,
)),
box FieldElementExpression::Number(n.clone()).into(),
)) {
Some(e) => match e {
TypedExpression::Boolean(e) => e.clone(),
_ => unreachable!("Should be a boolean"),
match self.constants.get(&id) {
Some(a) => match a {
TypedExpression::Array(a) => match a.as_inner() {
ArrayExpressionInner::Value(v) => BooleanExpression::try_from(
v[n.to_dec_string().parse::<usize>().unwrap()].clone(),
)
.unwrap(),
_ => unreachable!(),
},
_ => unreachable!(""),
},
None => BooleanExpression::Select(
box ArrayExpressionInner::Identifier(id).annotate(inner_type, size),

View file

@ -6,10 +6,8 @@
use crate::typed_absy::folder::*;
use crate::typed_absy::identifier::CoreIdentifier;
use crate::typed_absy::types::{MemberId, Type};
use crate::typed_absy::*;
use std::collections::HashMap;
use std::collections::HashSet;
use zokrates_field::Field;
pub enum Output<'ast, T: Field> {
@ -63,320 +61,6 @@ impl<'ast> Unroller<'ast> {
false => Output::Incomplete(p, unroller.statement_count),
}
}
fn choose_many<T: Field>(
base: TypedExpression<'ast, T>,
indices: Vec<Access<'ast, T>>,
new_expression: TypedExpression<'ast, T>,
statements: &mut HashSet<TypedStatement<'ast, T>>,
) -> TypedExpression<'ast, T> {
let mut indices = indices;
match indices.len() {
0 => new_expression,
_ => match base {
TypedExpression::Array(base) => {
let inner_ty = base.inner_type();
let size = base.size();
let head = indices.remove(0);
let tail = indices;
match head {
Access::Select(head) => {
statements.insert(TypedStatement::Assertion(
BooleanExpression::Lt(
box head.clone(),
box FieldElementExpression::Number(T::from(size)),
)
.into(),
));
ArrayExpressionInner::Value(
(0..size)
.map(|i| match inner_ty {
Type::Array(..) => ArrayExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(T::from(i)),
box head.clone(),
),
match Self::choose_many(
ArrayExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
)
.into(),
tail.clone(),
new_expression.clone(),
statements,
) {
TypedExpression::Array(e) => e,
e => unreachable!(
"the interior was expected to be an array, was {}",
e.get_type()
),
},
ArrayExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
),
)
.into(),
Type::Struct(..) => StructExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(T::from(i)),
box head.clone(),
),
match Self::choose_many(
StructExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
)
.into(),
tail.clone(),
new_expression.clone(),
statements,
) {
TypedExpression::Struct(e) => e,
e => unreachable!(
"the interior was expected to be a struct, was {}",
e.get_type()
),
},
StructExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
),
)
.into(),
Type::FieldElement => FieldElementExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(T::from(i)),
box head.clone(),
),
match Self::choose_many(
FieldElementExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
)
.into(),
tail.clone(),
new_expression.clone(),
statements,
) {
TypedExpression::FieldElement(e) => e,
e => unreachable!(
"the interior was expected to be a field, was {}",
e.get_type()
),
},
FieldElementExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
),
)
.into(),
Type::Boolean => BooleanExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(T::from(i)),
box head.clone(),
),
match Self::choose_many(
BooleanExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
)
.into(),
tail.clone(),
new_expression.clone(),
statements,
) {
TypedExpression::Boolean(e) => e,
e => unreachable!(
"the interior was expected to be a boolean, was {}",
e.get_type()
),
},
BooleanExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
),
)
.into(),
Type::Uint(..) => UExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(T::from(i)),
box head.clone(),
),
match Self::choose_many(
UExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
)
.into(),
tail.clone(),
new_expression.clone(),
statements,
) {
TypedExpression::Uint(e) => e,
e => unreachable!(
"the interior was expected to be a uint, was {}",
e.get_type()
),
},
UExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
),
)
.into(),
})
.collect(),
)
.annotate(inner_ty.clone(), size)
.into()
}
Access::Member(..) => unreachable!("can't get a member from an array"),
}
}
TypedExpression::Struct(base) => {
let members = match base.get_type() {
Type::Struct(members) => members.clone(),
_ => unreachable!(),
};
let head = indices.remove(0);
let tail = indices;
match head {
Access::Member(head) => StructExpressionInner::Value(
members
.clone()
.into_iter()
.map(|member| match *member.ty {
Type::FieldElement => {
if member.id == head {
Self::choose_many(
FieldElementExpression::member(
base.clone(),
head.clone(),
)
.into(),
tail.clone(),
new_expression.clone(),
statements,
)
} else {
FieldElementExpression::member(
base.clone(),
member.id.clone(),
)
.into()
}
}
Type::Uint(..) => {
if member.id == head {
Self::choose_many(
UExpression::member(base.clone(), head.clone())
.into(),
tail.clone(),
new_expression.clone(),
statements,
)
} else {
UExpression::member(base.clone(), member.id.clone())
.into()
}
}
Type::Boolean => {
if member.id == head {
Self::choose_many(
BooleanExpression::member(
base.clone(),
head.clone(),
)
.into(),
tail.clone(),
new_expression.clone(),
statements,
)
} else {
BooleanExpression::member(
base.clone(),
member.id.clone(),
)
.into()
}
}
Type::Array(..) => {
if member.id == head {
Self::choose_many(
ArrayExpression::member(base.clone(), head.clone())
.into(),
tail.clone(),
new_expression.clone(),
statements,
)
} else {
ArrayExpression::member(base.clone(), member.id.clone())
.into()
}
}
Type::Struct(..) => {
if member.id == head {
Self::choose_many(
StructExpression::member(
base.clone(),
head.clone(),
)
.into(),
tail.clone(),
new_expression.clone(),
statements,
)
} else {
StructExpression::member(
base.clone(),
member.id.clone(),
)
.into()
}
}
})
.collect(),
)
.annotate(members)
.into(),
Access::Select(..) => unreachable!("can't get a element from a struct"),
}
}
e => unreachable!("can't make an access on a {}", e.get_type()),
},
}
}
}
#[derive(Clone, Debug)]
enum Access<'ast, T: Field> {
Select(FieldElementExpression<'ast, T>),
Member(MemberId),
}
/// Turn an assignee into its representation as a base variable and a list accesses
/// a[2][3][4] -> (a, [2, 3, 4])
fn linear<'ast, T: Field>(a: TypedAssignee<'ast, T>) -> (Variable, Vec<Access<'ast, T>>) {
match a {
TypedAssignee::Identifier(v) => (v, vec![]),
TypedAssignee::Select(box array, box index) => {
let (v, mut indices) = linear(array);
indices.push(Access::Select(index));
(v, indices)
}
TypedAssignee::Member(box s, m) => {
let (v, mut indices) = linear(s);
indices.push(Access::Member(m));
(v, indices)
}
}
}
impl<'ast, T: Field> Folder<'ast, T> for Unroller<'ast> {
@ -384,64 +68,31 @@ impl<'ast, T: Field> Folder<'ast, T> for Unroller<'ast> {
self.statement_count += 1;
match s {
TypedStatement::Declaration(_) => vec![],
TypedStatement::Definition(assignee, expr) => {
let expr = self.fold_expression(expr);
TypedStatement::Definition(a, e) => {
let e = self.fold_expression(e);
let (variable, indices) = linear(assignee);
let base = match variable.get_type() {
Type::FieldElement => {
FieldElementExpression::Identifier(variable.id.clone().into()).into()
}
Type::Boolean => {
BooleanExpression::Identifier(variable.id.clone().into()).into()
}
Type::Uint(bitwidth) => {
UExpressionInner::Identifier(variable.id.clone().into())
.annotate(bitwidth)
.into()
}
Type::Array(array_type) => {
ArrayExpressionInner::Identifier(variable.id.clone().into())
.annotate(*array_type.ty, array_type.size)
.into()
}
Type::Struct(members) => {
StructExpressionInner::Identifier(variable.id.clone().into())
.annotate(members)
.into()
let a = match a {
TypedAssignee::Identifier(v) => {
TypedAssignee::Identifier(self.issue_next_ssa_variable(v))
}
a => fold_assignee(self, a),
};
let base = self.fold_expression(base);
let indices = indices
vec![TypedStatement::Definition(a, e)]
}
TypedStatement::MultipleDefinition(assignees, exprs) => {
let exprs = self.fold_expression_list(exprs);
let assignees = assignees
.into_iter()
.map(|a| match a {
Access::Select(i) => Access::Select(self.fold_field_expression(i)),
a => a,
TypedAssignee::Identifier(v) => {
TypedAssignee::Identifier(self.issue_next_ssa_variable(v))
}
a => fold_assignee(self, a),
})
.collect();
let mut range_checks = HashSet::new();
let e = Self::choose_many(base, indices, expr, &mut range_checks);
range_checks
.into_iter()
.chain(std::iter::once(TypedStatement::Definition(
TypedAssignee::Identifier(self.issue_next_ssa_variable(variable)),
e,
)))
.collect()
}
TypedStatement::MultipleDefinition(variables, exprs) => {
let exprs = self.fold_expression_list(exprs);
let variables = variables
.into_iter()
.map(|v| self.issue_next_ssa_variable(v))
.collect();
vec![TypedStatement::MultipleDefinition(variables, exprs)]
vec![TypedStatement::MultipleDefinition(assignees, exprs)]
}
TypedStatement::For(v, from, to, stats) => {
let from = self.fold_field_expression(from);
@ -510,246 +161,6 @@ mod tests {
use super::*;
use zokrates_field::Bn128Field;
#[test]
fn ssa_array() {
let a0 = ArrayExpressionInner::Identifier("a".into()).annotate(Type::FieldElement, 3);
let e = FieldElementExpression::Number(Bn128Field::from(42)).into();
let index = FieldElementExpression::Number(Bn128Field::from(1));
let a1 = Unroller::choose_many(
a0.clone().into(),
vec![Access::Select(index)],
e,
&mut HashSet::new(),
);
// a[1] = 42
// -> a = [0 == 1 ? 42 : a[0], 1 == 1 ? 42 : a[1], 2 == 1 ? 42 : a[2]]
assert_eq!(
a1,
ArrayExpressionInner::Value(vec![
FieldElementExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(Bn128Field::from(0)),
box FieldElementExpression::Number(Bn128Field::from(1))
),
FieldElementExpression::Number(Bn128Field::from(42)),
FieldElementExpression::select(
a0.clone(),
FieldElementExpression::Number(Bn128Field::from(0))
)
)
.into(),
FieldElementExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(Bn128Field::from(1)),
box FieldElementExpression::Number(Bn128Field::from(1))
),
FieldElementExpression::Number(Bn128Field::from(42)),
FieldElementExpression::select(
a0.clone(),
FieldElementExpression::Number(Bn128Field::from(1))
)
)
.into(),
FieldElementExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(Bn128Field::from(2)),
box FieldElementExpression::Number(Bn128Field::from(1))
),
FieldElementExpression::Number(Bn128Field::from(42)),
FieldElementExpression::select(
a0.clone(),
FieldElementExpression::Number(Bn128Field::from(2))
)
)
.into()
])
.annotate(Type::FieldElement, 3)
.into()
);
let a0 = ArrayExpressionInner::Identifier("a".into())
.annotate(Type::array(Type::FieldElement, 3), 3);
let e = ArrayExpressionInner::Identifier("b".into()).annotate(Type::FieldElement, 3);
let index = FieldElementExpression::Number(Bn128Field::from(1));
let a1 = Unroller::choose_many(
a0.clone().into(),
vec![Access::Select(index)],
e.clone().into(),
&mut HashSet::new(),
);
// a[0] = b
// -> a = [0 == 1 ? b : a[0], 1 == 1 ? b : a[1], 2 == 1 ? b : a[2]]
assert_eq!(
a1,
ArrayExpressionInner::Value(vec![
ArrayExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(Bn128Field::from(0)),
box FieldElementExpression::Number(Bn128Field::from(1))
),
e.clone(),
ArrayExpression::select(
a0.clone(),
FieldElementExpression::Number(Bn128Field::from(0))
)
)
.into(),
ArrayExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(Bn128Field::from(1)),
box FieldElementExpression::Number(Bn128Field::from(1))
),
e.clone(),
ArrayExpression::select(
a0.clone(),
FieldElementExpression::Number(Bn128Field::from(1))
)
)
.into(),
ArrayExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(Bn128Field::from(2)),
box FieldElementExpression::Number(Bn128Field::from(1))
),
e.clone(),
ArrayExpression::select(
a0.clone(),
FieldElementExpression::Number(Bn128Field::from(2))
)
)
.into()
])
.annotate(Type::array(Type::FieldElement, 3), 3)
.into()
);
let a0 = ArrayExpressionInner::Identifier("a".into())
.annotate(Type::array(Type::FieldElement, 2), 2);
let e = FieldElementExpression::Number(Bn128Field::from(42));
let indices = vec![
Access::Select(FieldElementExpression::Number(Bn128Field::from(0))),
Access::Select(FieldElementExpression::Number(Bn128Field::from(0))),
];
let a1 = Unroller::choose_many(
a0.clone().into(),
indices,
e.clone().into(),
&mut HashSet::new(),
);
// a[0][0] = 42
// -> a = [0 == 0 ? [0 == 0 ? 42 : a[0][0], 1 == 0 ? 42 : a[0][1]] : a[0], 1 == 0 ? [0 == 0 ? 42 : a[1][0], 1 == 0 ? 42 : a[1][1]] : a[1]]
assert_eq!(
a1,
ArrayExpressionInner::Value(vec![
ArrayExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(Bn128Field::from(0)),
box FieldElementExpression::Number(Bn128Field::from(0))
),
ArrayExpressionInner::Value(vec![
FieldElementExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(Bn128Field::from(0)),
box FieldElementExpression::Number(Bn128Field::from(0))
),
e.clone(),
FieldElementExpression::select(
ArrayExpression::select(
a0.clone(),
FieldElementExpression::Number(Bn128Field::from(0))
),
FieldElementExpression::Number(Bn128Field::from(0))
)
)
.into(),
FieldElementExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(Bn128Field::from(1)),
box FieldElementExpression::Number(Bn128Field::from(0))
),
e.clone(),
FieldElementExpression::select(
ArrayExpression::select(
a0.clone(),
FieldElementExpression::Number(Bn128Field::from(0))
),
FieldElementExpression::Number(Bn128Field::from(1))
)
)
.into()
])
.annotate(Type::FieldElement, 2),
ArrayExpression::select(
a0.clone(),
FieldElementExpression::Number(Bn128Field::from(0))
)
)
.into(),
ArrayExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(Bn128Field::from(1)),
box FieldElementExpression::Number(Bn128Field::from(0))
),
ArrayExpressionInner::Value(vec![
FieldElementExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(Bn128Field::from(0)),
box FieldElementExpression::Number(Bn128Field::from(0))
),
e.clone(),
FieldElementExpression::select(
ArrayExpression::select(
a0.clone(),
FieldElementExpression::Number(Bn128Field::from(1))
),
FieldElementExpression::Number(Bn128Field::from(0))
)
)
.into(),
FieldElementExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(Bn128Field::from(1)),
box FieldElementExpression::Number(Bn128Field::from(0))
),
e.clone(),
FieldElementExpression::select(
ArrayExpression::select(
a0.clone(),
FieldElementExpression::Number(Bn128Field::from(1))
),
FieldElementExpression::Number(Bn128Field::from(1))
)
)
.into()
])
.annotate(Type::FieldElement, 2),
ArrayExpression::select(
a0.clone(),
FieldElementExpression::Number(Bn128Field::from(1))
)
)
.into(),
])
.annotate(Type::array(Type::FieldElement, 2), 2)
.into()
);
}
#[cfg(test)]
mod statement {
use super::*;
@ -829,17 +240,45 @@ mod tests {
fn idempotence() {
// an already unrolled program should not be modified by unrolling again
// b = [5]
// b[0] = 1
// a = 5
// a_1 = 6
// a_2 = 7
// should be turned into
// b = [5]
// b[0] = 1
// a = 5
// a_1 = 6
// a_2 = 7
let mut u = Unroller::new();
let s = TypedStatement::Definition(
TypedAssignee::Identifier(Variable::array(
Identifier::from("b").version(0),
Type::FieldElement,
1,
)),
ArrayExpressionInner::Value(vec![FieldElementExpression::from(Bn128Field::from(
5,
))
.into()])
.annotate(Type::FieldElement, 1)
.into(),
);
assert_eq!(u.fold_statement(s.clone()), vec![s]);
let s = TypedStatement::Definition(
TypedAssignee::Select(
box Variable::field_element(Identifier::from("b").version(0)).into(),
box FieldElementExpression::Number(Bn128Field::from(0)),
),
FieldElementExpression::Number(Bn128Field::from(1)).into(),
);
assert_eq!(u.fold_statement(s.clone()), vec![s]);
let s = TypedStatement::Definition(
TypedAssignee::Identifier(Variable::field_element(
Identifier::from("a").version(0),
@ -1005,7 +444,7 @@ mod tests {
);
let s: TypedStatement<Bn128Field> = TypedStatement::MultipleDefinition(
vec![Variable::field_element("a")],
vec![Variable::field_element("a").into()],
TypedExpressionList::FunctionCall(
FunctionKey::with_id("foo").signature(
Signature::new()
@ -1019,7 +458,7 @@ mod tests {
assert_eq!(
u.fold_statement(s),
vec![TypedStatement::MultipleDefinition(
vec![Variable::field_element(Identifier::from("a").version(1))],
vec![Variable::field_element(Identifier::from("a").version(1)).into()],
TypedExpressionList::FunctionCall(
FunctionKey::with_id("foo").signature(
Signature::new()
@ -1043,7 +482,7 @@ mod tests {
// should be turned into
// a_0 = [1, 1]
// a_1 = [if 0 == 1 then 2 else a_0[0], if 1 == 1 then 2 else a_0[1]]
// a_0[1] = 2
let mut u = Unroller::new();
@ -1085,58 +524,7 @@ mod tests {
FieldElementExpression::Number(Bn128Field::from(2)).into(),
);
assert_eq!(
u.fold_statement(s),
vec![
TypedStatement::Assertion(
BooleanExpression::Lt(
box FieldElementExpression::Number(Bn128Field::from(1)),
box FieldElementExpression::Number(Bn128Field::from(2))
)
.into(),
),
TypedStatement::Definition(
TypedAssignee::Identifier(Variable::field_array(
Identifier::from("a").version(1),
2
)),
ArrayExpressionInner::Value(vec![
FieldElementExpression::IfElse(
box BooleanExpression::FieldEq(
box FieldElementExpression::Number(Bn128Field::from(0)),
box FieldElementExpression::Number(Bn128Field::from(1))
),
box FieldElementExpression::Number(Bn128Field::from(2)),
box FieldElementExpression::Select(
box ArrayExpressionInner::Identifier(
Identifier::from("a").version(0)
)
.annotate(Type::FieldElement, 2),
box FieldElementExpression::Number(Bn128Field::from(0))
),
)
.into(),
FieldElementExpression::IfElse(
box BooleanExpression::FieldEq(
box FieldElementExpression::Number(Bn128Field::from(1)),
box FieldElementExpression::Number(Bn128Field::from(1))
),
box FieldElementExpression::Number(Bn128Field::from(2)),
box FieldElementExpression::Select(
box ArrayExpressionInner::Identifier(
Identifier::from("a").version(0)
)
.annotate(Type::FieldElement, 2),
box FieldElementExpression::Number(Bn128Field::from(1))
),
)
.into(),
])
.annotate(Type::FieldElement, 2)
.into()
)
]
);
assert_eq!(u.fold_statement(s.clone()), vec![s]);
}
#[test]
@ -1146,7 +534,7 @@ mod tests {
// should be turned into
// a_0 = [[0, 1], [2, 3]]
// a_1 = [if 0 == 1 then [4, 5] else a_0[0], if 1 == 1 then [4, 5] else a_0[1]]
// a_0 = [4, 5]
let mut u = Unroller::new();
@ -1222,72 +610,7 @@ mod tests {
.into(),
);
assert_eq!(
u.fold_statement(s),
vec![
TypedStatement::Assertion(
BooleanExpression::Lt(
box FieldElementExpression::Number(Bn128Field::from(1)),
box FieldElementExpression::Number(Bn128Field::from(2))
)
.into(),
),
TypedStatement::Definition(
TypedAssignee::Identifier(Variable::with_id_and_type(
Identifier::from("a").version(1),
array_of_array_ty.clone()
)),
ArrayExpressionInner::Value(vec![
ArrayExpressionInner::IfElse(
box BooleanExpression::FieldEq(
box FieldElementExpression::Number(Bn128Field::from(0)),
box FieldElementExpression::Number(Bn128Field::from(1))
),
box ArrayExpressionInner::Value(vec![
FieldElementExpression::Number(Bn128Field::from(4)).into(),
FieldElementExpression::Number(Bn128Field::from(5)).into(),
])
.annotate(Type::FieldElement, 2)
.into(),
box ArrayExpressionInner::Select(
box ArrayExpressionInner::Identifier(
Identifier::from("a").version(0)
)
.annotate(Type::array(Type::FieldElement, 2), 2),
box FieldElementExpression::Number(Bn128Field::from(0))
)
.annotate(Type::FieldElement, 2),
)
.annotate(Type::FieldElement, 2)
.into(),
ArrayExpressionInner::IfElse(
box BooleanExpression::FieldEq(
box FieldElementExpression::Number(Bn128Field::from(1)),
box FieldElementExpression::Number(Bn128Field::from(1))
),
box ArrayExpressionInner::Value(vec![
FieldElementExpression::Number(Bn128Field::from(4)).into(),
FieldElementExpression::Number(Bn128Field::from(5)).into(),
])
.annotate(Type::FieldElement, 2)
.into(),
box ArrayExpressionInner::Select(
box ArrayExpressionInner::Identifier(
Identifier::from("a").version(0)
)
.annotate(Type::array(Type::FieldElement, 2), 2),
box FieldElementExpression::Number(Bn128Field::from(1))
)
.annotate(Type::FieldElement, 2),
)
.annotate(Type::FieldElement, 2)
.into(),
])
.annotate(Type::array(Type::FieldElement, 2), 2)
.into()
)
]
);
assert_eq!(u.fold_statement(s.clone()), vec![s]);
}
}
}

View file

@ -13,11 +13,11 @@
use crate::typed_absy::{folder::*, *};
use zokrates_field::Field;
pub struct VariableAccessRemover<'ast, T: Field> {
pub struct VariableReadRemover<'ast, T: Field> {
statements: Vec<TypedStatement<'ast, T>>,
}
impl<'ast, T: Field> VariableAccessRemover<'ast, T> {
impl<'ast, T: Field> VariableReadRemover<'ast, T> {
fn new() -> Self {
Self { statements: vec![] }
}
@ -76,7 +76,7 @@ impl<'ast, T: Field> VariableAccessRemover<'ast, T> {
}
}
impl<'ast, T: Field> Folder<'ast, T> for VariableAccessRemover<'ast, T> {
impl<'ast, T: Field> Folder<'ast, T> for VariableReadRemover<'ast, T> {
fn fold_field_expression(
&mut self,
e: FieldElementExpression<'ast, T>,
@ -167,7 +167,7 @@ mod tests {
);
assert_eq!(
VariableAccessRemover::new().fold_statement(access),
VariableReadRemover::new().fold_statement(access),
vec![
TypedStatement::Assertion(
BooleanExpression::Or(

View file

@ -0,0 +1,413 @@
//! Module containing SSA reduction, including for-loop unrolling
//!
//! @file unroll.rs
//! @author Thibaut Schaeffer <thibaut@schaeff.fr>
//! @date 2018
use crate::typed_absy::folder::*;
use crate::typed_absy::types::{MemberId, Type};
use crate::typed_absy::*;
use std::collections::HashSet;
use zokrates_field::Field;
pub struct VariableWriteRemover;
impl<'ast> VariableWriteRemover {
fn new() -> Self {
VariableWriteRemover
}
pub fn apply<T: Field>(p: TypedProgram<T>) -> TypedProgram<T> {
let mut remover = VariableWriteRemover::new();
remover.fold_program(p)
}
fn choose_many<T: Field>(
base: TypedExpression<'ast, T>,
indices: Vec<Access<'ast, T>>,
new_expression: TypedExpression<'ast, T>,
statements: &mut HashSet<TypedStatement<'ast, T>>,
) -> TypedExpression<'ast, T> {
let mut indices = indices;
match indices.len() {
0 => new_expression,
_ => match base {
TypedExpression::Array(base) => {
let inner_ty = base.inner_type();
let size = base.size();
let head = indices.remove(0);
let tail = indices;
match head {
Access::Select(head) => {
statements.insert(TypedStatement::Assertion(
BooleanExpression::Lt(
box head.clone(),
box FieldElementExpression::Number(T::from(size)),
)
.into(),
));
ArrayExpressionInner::Value(
(0..size)
.map(|i| match inner_ty {
Type::Array(..) => ArrayExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(T::from(i)),
box head.clone(),
),
match Self::choose_many(
ArrayExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
)
.into(),
tail.clone(),
new_expression.clone(),
statements,
) {
TypedExpression::Array(e) => e,
e => unreachable!(
"the interior was expected to be an array, was {}",
e.get_type()
),
},
ArrayExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
),
)
.into(),
Type::Struct(..) => StructExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(T::from(i)),
box head.clone(),
),
match Self::choose_many(
StructExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
)
.into(),
tail.clone(),
new_expression.clone(),
statements,
) {
TypedExpression::Struct(e) => e,
e => unreachable!(
"the interior was expected to be a struct, was {}",
e.get_type()
),
},
StructExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
),
)
.into(),
Type::FieldElement => FieldElementExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(T::from(i)),
box head.clone(),
),
match Self::choose_many(
FieldElementExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
)
.into(),
tail.clone(),
new_expression.clone(),
statements,
) {
TypedExpression::FieldElement(e) => e,
e => unreachable!(
"the interior was expected to be a field, was {}",
e.get_type()
),
},
FieldElementExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
),
)
.into(),
Type::Boolean => BooleanExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(T::from(i)),
box head.clone(),
),
match Self::choose_many(
BooleanExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
)
.into(),
tail.clone(),
new_expression.clone(),
statements,
) {
TypedExpression::Boolean(e) => e,
e => unreachable!(
"the interior was expected to be a boolean, was {}",
e.get_type()
),
},
BooleanExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
),
)
.into(),
Type::Uint(..) => UExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(T::from(i)),
box head.clone(),
),
match Self::choose_many(
UExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
)
.into(),
tail.clone(),
new_expression.clone(),
statements,
) {
TypedExpression::Uint(e) => e,
e => unreachable!(
"the interior was expected to be a uint, was {}",
e.get_type()
),
},
UExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
),
)
.into(),
})
.collect(),
)
.annotate(inner_ty.clone(), size)
.into()
}
Access::Member(..) => unreachable!("can't get a member from an array"),
}
}
TypedExpression::Struct(base) => {
let members = match base.get_type() {
Type::Struct(members) => members.clone(),
_ => unreachable!(),
};
let head = indices.remove(0);
let tail = indices;
match head {
Access::Member(head) => StructExpressionInner::Value(
members
.clone()
.into_iter()
.map(|member| match *member.ty {
Type::FieldElement => {
if member.id == head {
Self::choose_many(
FieldElementExpression::member(
base.clone(),
head.clone(),
)
.into(),
tail.clone(),
new_expression.clone(),
statements,
)
} else {
FieldElementExpression::member(
base.clone(),
member.id.clone(),
)
.into()
}
}
Type::Uint(..) => {
if member.id == head {
Self::choose_many(
UExpression::member(base.clone(), head.clone())
.into(),
tail.clone(),
new_expression.clone(),
statements,
)
} else {
UExpression::member(base.clone(), member.id.clone())
.into()
}
}
Type::Boolean => {
if member.id == head {
Self::choose_many(
BooleanExpression::member(
base.clone(),
head.clone(),
)
.into(),
tail.clone(),
new_expression.clone(),
statements,
)
} else {
BooleanExpression::member(
base.clone(),
member.id.clone(),
)
.into()
}
}
Type::Array(..) => {
if member.id == head {
Self::choose_many(
ArrayExpression::member(base.clone(), head.clone())
.into(),
tail.clone(),
new_expression.clone(),
statements,
)
} else {
ArrayExpression::member(base.clone(), member.id.clone())
.into()
}
}
Type::Struct(..) => {
if member.id == head {
Self::choose_many(
StructExpression::member(
base.clone(),
head.clone(),
)
.into(),
tail.clone(),
new_expression.clone(),
statements,
)
} else {
StructExpression::member(
base.clone(),
member.id.clone(),
)
.into()
}
}
})
.collect(),
)
.annotate(members)
.into(),
Access::Select(..) => unreachable!("can't get a element from a struct"),
}
}
e => unreachable!("can't make an access on a {}", e.get_type()),
},
}
}
}
#[derive(Clone, Debug)]
enum Access<'ast, T: Field> {
Select(FieldElementExpression<'ast, T>),
Member(MemberId),
}
/// Turn an assignee into its representation as a base variable and a list accesses
/// a[2][3][4] -> (a, [2, 3, 4])
fn linear<'ast, T: Field>(a: TypedAssignee<'ast, T>) -> (Variable, Vec<Access<'ast, T>>) {
match a {
TypedAssignee::Identifier(v) => (v, vec![]),
TypedAssignee::Select(box array, box index) => {
let (v, mut indices) = linear(array);
indices.push(Access::Select(index));
(v, indices)
}
TypedAssignee::Member(box s, m) => {
let (v, mut indices) = linear(s);
indices.push(Access::Member(m));
(v, indices)
}
}
}
fn is_constant<'ast, T>(assignee: &TypedAssignee<'ast, T>) -> bool {
match assignee {
TypedAssignee::Identifier(_) => true,
TypedAssignee::Select(box assignee, box index) => match index {
FieldElementExpression::Number(_) => is_constant(assignee),
_ => false,
},
TypedAssignee::Member(box assignee, _) => is_constant(assignee),
}
}
impl<'ast, T: Field> Folder<'ast, T> for VariableWriteRemover {
fn fold_statement(&mut self, s: TypedStatement<'ast, T>) -> Vec<TypedStatement<'ast, T>> {
match s {
TypedStatement::Definition(assignee, expr) => {
if is_constant(&assignee) {
vec![TypedStatement::Definition(assignee, expr)]
} else {
// Note: here we redefine the whole object, ideally we would only redefine some of it
// Example: `a[0][i] = 42` we redefine `a` but we could redefine just `a[0]`
let expr = self.fold_expression(expr);
let (variable, indices) = linear(assignee);
let base = match variable.get_type() {
Type::FieldElement => {
FieldElementExpression::Identifier(variable.id.clone().into()).into()
}
Type::Boolean => {
BooleanExpression::Identifier(variable.id.clone().into()).into()
}
Type::Uint(bitwidth) => {
UExpressionInner::Identifier(variable.id.clone().into())
.annotate(bitwidth)
.into()
}
Type::Array(array_type) => {
ArrayExpressionInner::Identifier(variable.id.clone().into())
.annotate(*array_type.ty, array_type.size)
.into()
}
Type::Struct(members) => {
StructExpressionInner::Identifier(variable.id.clone().into())
.annotate(members)
.into()
}
};
let base = self.fold_expression(base);
let indices = indices
.into_iter()
.map(|a| match a {
Access::Select(i) => Access::Select(self.fold_field_expression(i)),
a => a,
})
.collect();
let mut range_checks = HashSet::new();
let e = Self::choose_many(base, indices, expr, &mut range_checks);
range_checks
.into_iter()
.chain(std::iter::once(TypedStatement::Definition(
TypedAssignee::Identifier(variable),
e,
)))
.collect()
}
}
s => fold_statement(self, s),
}
}
}

View file

@ -42,14 +42,7 @@ pub trait Folder<'ast, T: Field>: Sized {
}
fn fold_assignee(&mut self, a: TypedAssignee<'ast, T>) -> TypedAssignee<'ast, T> {
match a {
TypedAssignee::Identifier(v) => TypedAssignee::Identifier(self.fold_variable(v)),
TypedAssignee::Select(box a, box index) => TypedAssignee::Select(
box self.fold_assignee(a),
box self.fold_field_expression(index),
),
TypedAssignee::Member(box s, m) => TypedAssignee::Member(box self.fold_assignee(s), m),
}
fold_assignee(self, a)
}
fn fold_statement(&mut self, s: TypedStatement<'ast, T>) -> Vec<TypedStatement<'ast, T>> {
@ -175,8 +168,8 @@ pub fn fold_statement<'ast, T: Field, F: Folder<'ast, T>>(
.flat_map(|s| f.fold_statement(s))
.collect(),
),
TypedStatement::MultipleDefinition(variables, elist) => TypedStatement::MultipleDefinition(
variables.into_iter().map(|v| f.fold_variable(v)).collect(),
TypedStatement::MultipleDefinition(assignees, elist) => TypedStatement::MultipleDefinition(
assignees.into_iter().map(|a| f.fold_assignee(a)).collect(),
f.fold_expression_list(elist),
),
};
@ -548,6 +541,19 @@ pub fn fold_function_symbol<'ast, T: Field, F: Folder<'ast, T>>(
}
}
pub fn fold_assignee<'ast, T: Field, F: Folder<'ast, T>>(
f: &mut F,
a: TypedAssignee<'ast, T>,
) -> TypedAssignee<'ast, T> {
match a {
TypedAssignee::Identifier(v) => TypedAssignee::Identifier(f.fold_variable(v)),
TypedAssignee::Select(box a, box index) => {
TypedAssignee::Select(box f.fold_assignee(a), box f.fold_field_expression(index))
}
TypedAssignee::Member(box s, m) => TypedAssignee::Member(box f.fold_assignee(s), m),
}
}
pub fn fold_program<'ast, T: Field, F: Folder<'ast, T>>(
f: &mut F,
p: TypedProgram<'ast, T>,

View file

@ -259,6 +259,12 @@ pub enum TypedAssignee<'ast, T> {
Member(Box<TypedAssignee<'ast, T>>, MemberId),
}
impl<'ast, T> From<Variable<'ast>> for TypedAssignee<'ast, T> {
fn from(v: Variable<'ast>) -> Self {
TypedAssignee::Identifier(v)
}
}
impl<'ast, T> Typed for TypedAssignee<'ast, T> {
fn get_type(&self) -> Type {
match *self {
@ -319,7 +325,7 @@ pub enum TypedStatement<'ast, T> {
FieldElementExpression<'ast, T>,
Vec<TypedStatement<'ast, T>>,
),
MultipleDefinition(Vec<Variable<'ast>>, TypedExpressionList<'ast, T>),
MultipleDefinition(Vec<TypedAssignee<'ast, T>>, TypedExpressionList<'ast, T>),
}
impl<'ast, T: fmt::Debug> fmt::Debug for TypedStatement<'ast, T> {
@ -628,6 +634,12 @@ pub enum FieldElementExpression<'ast, T> {
),
}
impl<'ast, T> From<T> for FieldElementExpression<'ast, T> {
fn from(n: T) -> Self {
FieldElementExpression::Number(n)
}
}
/// An expression of type `bool`
#[derive(Clone, PartialEq, Hash, Eq)]
pub enum BooleanExpression<'ast, T> {
@ -737,6 +749,10 @@ impl<'ast, T> ArrayExpression<'ast, T> {
&self.inner
}
pub fn as_inner_mut(&mut self) -> &mut ArrayExpressionInner<'ast, T> {
&mut self.inner
}
pub fn into_inner(self) -> ArrayExpressionInner<'ast, T> {
self.inner
}
@ -757,6 +773,10 @@ impl<'ast, T> StructExpression<'ast, T> {
&self.inner
}
pub fn as_inner_mut(&mut self) -> &mut StructExpressionInner<'ast, T> {
&mut self.inner
}
pub fn into_inner(self) -> StructExpressionInner<'ast, T> {
self.inner
}

View file

@ -192,7 +192,7 @@ pub enum ZirStatement<'ast, T> {
Definition(ZirAssignee<'ast>, ZirExpression<'ast, T>),
Declaration(Variable<'ast>),
Assertion(BooleanExpression<'ast, T>),
MultipleDefinition(Vec<Variable<'ast>>, ZirExpressionList<'ast, T>),
MultipleDefinition(Vec<ZirAssignee<'ast>>, ZirExpressionList<'ast, T>),
}
impl<'ast, T: fmt::Debug> fmt::Debug for ZirStatement<'ast, T> {

View file

@ -1,6 +1,6 @@
[package]
name = "zokrates_core_test"
version = "0.1.3"
version = "0.1.4"
authors = ["schaeff <thibaut@schaeff.fr>"]
edition = "2018"

14
zokrates_embed/Cargo.toml Normal file
View file

@ -0,0 +1,14 @@
[package]
name = "zokrates_embed"
version = "0.1.1"
authors = ["schaeff <thibaut@schaeff.fr>"]
edition = "2018"
[features]
default = []
wasm = ["bellman_ce/wasm", "sapling-crypto_ce/wasm"]
multicore = ["bellman_ce/multicore", "sapling-crypto_ce/multicore"]
[dependencies]
bellman_ce = { version = "^0.3", default-features = false }
sapling-crypto_ce = { version = "^0.1", default-features = false }

319
zokrates_embed/src/lib.rs Normal file
View file

@ -0,0 +1,319 @@
extern crate sapling_crypto_ce as sapling_crypto;
use sapling_crypto::bellman;
use bellman::{
pairing::{ff::Field, Engine},
ConstraintSystem, Index, LinearCombination, SynthesisError, Variable,
};
use sapling_crypto::circuit::{
boolean::{AllocatedBit, Boolean},
sha256::sha256_compression_function,
uint32::UInt32,
};
#[derive(Debug)]
pub struct BellmanR1CS<E: Engine> {
pub aux_count: usize,
pub constraints: Vec<BellmanConstraint<E>>,
}
impl<E: Engine> BellmanR1CS<E> {
pub fn new() -> Self {
BellmanR1CS {
aux_count: 0,
constraints: vec![],
}
}
}
#[derive(Debug)]
pub struct BellmanWitness<E: Engine> {
pub values: Vec<E::Fr>,
}
#[derive(Debug, PartialEq)]
pub struct BellmanConstraint<E: Engine> {
pub a: Vec<(usize, E::Fr)>,
pub b: Vec<(usize, E::Fr)>,
pub c: Vec<(usize, E::Fr)>,
}
fn sha256_round<E: Engine, CS: ConstraintSystem<E>>(
mut cs: CS,
input: &Vec<Option<E::Fr>>,
current_hash: &Vec<Option<E::Fr>>,
) -> Result<(Vec<usize>, Vec<usize>, Vec<usize>), SynthesisError> {
// Allocate bits for `input`
let input_bits = input
.iter()
.enumerate()
.map(|(index, i)| {
AllocatedBit::alloc::<E, _>(
&mut cs.namespace(|| format!("input_{}", index)),
Some(*i == Some(<E::Fr as Field>::one())),
)
.unwrap()
})
.collect::<Vec<_>>();
// Define Booleans whose values are the defined bits
let input = input_bits
.iter()
.map(|i| Boolean::Is(i.clone()))
.collect::<Vec<_>>();
// Allocate bits for `current_hash`
let current_hash_bits = current_hash
.iter()
.enumerate()
.map(|(index, i)| {
AllocatedBit::alloc::<E, _>(
&mut cs.namespace(|| format!("current_hash_{}", index)),
Some(*i == Some(<E::Fr as Field>::one())),
)
.unwrap()
})
.collect::<Vec<_>>();
// Define Booleans whose values are the defined bits
let current_hash = current_hash_bits
.chunks(32)
.map(|chunk| {
UInt32::from_bits_be(
&chunk
.into_iter()
.map(|i| Boolean::Is(i.clone()))
.collect::<Vec<_>>(),
)
})
.collect::<Vec<_>>();
// Apply the compression function, returning the 8 bytes of outputs
let res = sha256_compression_function::<E, _>(&mut cs, &input, &current_hash).unwrap();
// Extract the 256 bits of output out of the 8 bytes
let output_bits = res
.into_iter()
.flat_map(|u| u.into_bits_be())
.map(|b| b.get_variable().unwrap().clone())
.collect::<Vec<_>>();
// Return indices of `input`, `current_hash` and `output` in the CS
Ok((
input_bits
.into_iter()
.map(|b| var_to_index(b.get_variable()))
.collect(),
current_hash_bits
.into_iter()
.map(|b| var_to_index(b.get_variable()))
.collect(),
output_bits
.into_iter()
.map(|b| var_to_index(b.get_variable()))
.collect(),
))
}
impl<E: Engine> ConstraintSystem<E> for BellmanWitness<E> {
type Root = Self;
fn alloc<F, A, AR>(&mut self, _: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
{
let index = self.values.len();
let var = Variable::new_unchecked(Index::Aux(index));
self.values.push(f().unwrap());
Ok(var)
}
fn alloc_input<F, A, AR>(&mut self, _: A, _: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
{
unreachable!("Bellman helpers are not allowed to allocate public variables")
}
fn enforce<A, AR, LA, LB, LC>(&mut self, _: A, _: LA, _: LB, _: LC)
where
A: FnOnce() -> AR,
AR: Into<String>,
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
{
// do nothing
}
fn push_namespace<NR, N>(&mut self, _: N)
where
NR: Into<String>,
N: FnOnce() -> NR,
{
// do nothing
}
fn pop_namespace(&mut self) {
// do nothing
}
fn get_root(&mut self) -> &mut Self::Root {
self
}
}
impl<E: Engine> ConstraintSystem<E> for BellmanR1CS<E> {
type Root = Self;
fn alloc<F, A, AR>(&mut self, _: A, _: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
{
// we don't care about the value as we're only generating the CS
let index = self.aux_count;
let var = Variable::new_unchecked(Index::Aux(index));
self.aux_count += 1;
Ok(var)
}
fn alloc_input<F, A, AR>(&mut self, _: A, _: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
{
unreachable!("Bellman helpers are not allowed to allocate public variables")
}
fn enforce<A, AR, LA, LB, LC>(&mut self, _: A, a: LA, b: LB, c: LC)
where
A: FnOnce() -> AR,
AR: Into<String>,
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
{
let a = a(LinearCombination::zero());
let b = b(LinearCombination::zero());
let c = c(LinearCombination::zero());
let a = a
.as_ref()
.into_iter()
.map(|(variable, coefficient)| (var_to_index(*variable), *coefficient))
.collect();
let b = b
.as_ref()
.into_iter()
.map(|(variable, coefficient)| (var_to_index(*variable), *coefficient))
.collect();
let c = c
.as_ref()
.into_iter()
.map(|(variable, coefficient)| (var_to_index(*variable), *coefficient))
.collect();
self.constraints.push(BellmanConstraint { a, b, c });
}
fn push_namespace<NR, N>(&mut self, _: N)
where
NR: Into<String>,
N: FnOnce() -> NR,
{
// do nothing
}
fn pop_namespace(&mut self) {
// do nothing
}
fn get_root(&mut self) -> &mut Self::Root {
self
}
}
pub fn generate_sha256_round_constraints<E: Engine>(
) -> (BellmanR1CS<E>, Vec<usize>, Vec<usize>, Vec<usize>) {
let mut cs = BellmanR1CS::new();
let (input_bits, current_hash_bits, output_bits) =
sha256_round(&mut cs, &vec![None; 512], &vec![None; 256]).unwrap();
// res is now the allocated bits for `input`, `current_hash` and `sha256_output`
(cs, input_bits, current_hash_bits, output_bits)
}
pub fn generate_sha256_round_witness<E: Engine>(
input: &[E::Fr],
current_hash: &[E::Fr],
) -> Vec<E::Fr> {
assert_eq!(input.len(), 512);
assert_eq!(current_hash.len(), 256);
let mut cs: BellmanWitness<E> = BellmanWitness {
values: vec![<E::Fr as Field>::one()],
};
sha256_round(
&mut cs,
&input.iter().map(|x| Some(x.clone())).collect(),
&current_hash.iter().map(|x| Some(x.clone())).collect(),
)
.unwrap();
cs.values
}
fn var_to_index(v: Variable) -> usize {
match v.get_unchecked() {
Index::Aux(i) => i + 1,
Index::Input(0) => 0,
_ => unreachable!("No public variables should have been allocated"),
}
}
#[cfg(test)]
mod tests {
use super::*;
use bellman::pairing::bn256::{Bn256, Fr};
#[test]
fn generate_constraints() {
let (_c, input, current_hash, output) = generate_sha256_round_constraints::<Bn256>();
assert_eq!(input.len(), 512);
assert_eq!(current_hash.len(), 256);
assert_eq!(output.len(), 256);
}
#[test]
fn generate_witness() {
let witness =
generate_sha256_round_witness::<Bn256>(&vec![Fr::one(); 512], &vec![Fr::zero(); 256]);
assert_eq!(witness.len(), 26935);
}
#[test]
fn test_cs() {
use sapling_crypto::circuit::test::TestConstraintSystem;
let mut cs: TestConstraintSystem<Bn256> = TestConstraintSystem::new();
let _ = sha256_round(
&mut cs,
&vec![Some(Fr::zero()); 512],
&vec![Some(Fr::one()); 256],
)
.unwrap();
assert!(cs.is_satisfied());
}
}

View file

@ -1,6 +1,6 @@
[package]
name = "zokrates_js"
version = "1.0.26"
version = "1.0.27"
authors = ["Darko Macesic"]
edition = "2018"

View file

@ -2,7 +2,7 @@
"name": "zokrates-js",
"main": "index.js",
"author": "Darko Macesic <darem966@gmail.com>",
"version": "1.0.26",
"version": "1.0.27",
"keywords": [
"zokrates",
"wasm-bindgen",

View file

@ -1,6 +1,6 @@
[package]
name = "zokrates_parser"
version = "0.1.5"
version = "0.1.6"
authors = ["JacobEberhardt <jacob.eberhardt@tu-berlin.de>"]
edition = "2018"

View file

@ -1,6 +1,6 @@
[package]
name = "zokrates_pest_ast"
version = "0.1.4"
version = "0.1.5"
authors = ["schaeff <thibaut@schaeff.fr>"]
edition = "2018"

View file

@ -0,0 +1,13 @@
import "./IVconstants" as IVconstants
import "./shaRoundNoBoolCheck" as sha256
// A function that takes 4 bool[256] arrays as inputs
// and applies 2 rounds of sha256 compression.
// It returns an array of 256 bool.
def main(bool[256] a, bool[256] b, bool[256] c, bool[256] d) -> (bool[256]):
bool[256] IV = IVconstants()
bool[256] digest1 = sha256(a, b, IV)
bool[256] digest2 = sha256(c, d, digest1)
return digest2

View file

@ -0,0 +1,16 @@
import "./1536bit" as sha256
// Take two bool[256] arrays as input
// and returns their sha256 full round output as an array of 256 bool.
def main(bool[256] a, bool[256] b, bool[256] c, bool[256] d) -> (bool[256]):
// Hash is computed on the full 1024bit block size
// padding does not fit in the first two blocks
// add dummy block (single "1" followed by "0" + total length)
bool[256] dummyblock1 = [true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]
// total length of message is 1024 bits: 0b10000000000
bool[256] dummyblock2 = [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false]
bool[256] digest = sha256(a, b, c, d, dummyblock1, dummyblock2)
return digest

View file

@ -0,0 +1,14 @@
import "./IVconstants" as IVconstants
import "./shaRoundNoBoolCheck" as sha256
// A function that takes 6 bool[256] arrays as inputs
// and applies 3 rounds of sha256 compression.
// It returns an array of 256 bool.
def main(bool[256] a, bool[256] b, bool[256] c, bool[256] d, bool[256] e, bool[256] f) -> (bool[256]):
bool[256] IV = IVconstants()
bool[256] digest1 = sha256(a, b, IV)
bool[256] digest2 = sha256(c, d, digest1)
bool[256] digest3 = sha256(e, f, digest2)
return digest3

View file

@ -0,0 +1,30 @@
import "./512bit" as sha256
// A function that takes 1 bool[256] array as input
// and returns the sha256 full round output as an array of 256 bool.
def main(bool[256] a) -> (bool[256]):
// Hash is computed on 256 bits of input
// padding fits in the remaining 256 bits of the first block
// add dummy block (single "1" followed by "0" + total length)
bool[256] dummyblock1 = [ \
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]
bool[256] digest = sha256(a, dummyblock1)
return digest

View file

@ -0,0 +1,15 @@
import "./IVconstants" as IVconstants
import "./shaRoundNoBoolCheck" as sha256
// A function that takes 2 bool[256] arrays as inputs
// and returns their sha256 compression function as an array of 256 bool.
// In contrast to full_round.zok no padding is being applied
def main(bool[256] a, bool[256] b) -> (bool[256]):
// a and b is NOT checked to be of type bool
bool[256] IV = IVconstants()
bool[256] digest = sha256(a, b, IV)
//digest is constraint to be of type bool
return digest

View file

@ -0,0 +1,23 @@
import "../../../utils/pack/bool/pack128" as pack128
import "../../../utils/pack/bool/unpack128" as unpack128
import "./512bitPadded" as sha256
// A function that takes an array of 4 field elements as inputs, unpacks each of them to 128
// bits (big endian), concatenates them and applies sha256.
// It then returns an array of two field elements, each representing 128 bits of the result.
def main(field[4] preimage) -> (field[2]):
bool[128] a = unpack128(preimage[0])
bool[128] b = unpack128(preimage[1])
bool[128] c = unpack128(preimage[2])
bool[128] d = unpack128(preimage[3])
bool[256] lhs = [...a, ...b]
bool[256] rhs = [...c, ...d]
bool[256] r = sha256(lhs, rhs)
field res0 = pack128(r[..128])
field res1 = pack128(r[128..])
return [res0, res1]

View file

@ -0,0 +1,17 @@
import "./1024bit" as sha256
// A function that takes 2 bool[256] arrays as inputs
// and returns their sha256 full round output as an array of 256 bool.
def main(bool[256] a, bool[256] b) -> (bool[256]):
// Hash is computed on the full 512bit block size
// padding does not fit in the primary block
// add dummy block (single "1" followed by "0" + total length)
bool[256] dummyblock1 = [true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]
// total length of message is 512 bits: 0b1000000000
bool[256] dummyblock2 = [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false]
bool[256] digest = sha256(a, b, dummyblock1, dummyblock2)
return digest

View file

@ -0,0 +1,15 @@
// SHA-256 is specified in FIPS 180-3 and initial values are listed in section 5.3.3
// https://csrc.nist.gov/csrc/media/publications/fips/180/3/archive/2008-10-31/documents/fips180-3_final.pdf
def main() -> (bool[256]):
bool[32] h0 = [false, true, true, false, true, false, true, false, false, false, false, false, true, false, false, true, true, true, true, false, false, true, true, false, false, true, true, false, false, true, true, true]
bool[32] h1 = [true, false, true, true, true, false, true, true, false, true, true, false, false, true, true, true, true, false, true, false, true, true, true, false, true, false, false, false, false, true, false, true]
bool[32] h2 = [false, false, true, true, true, true, false, false, false, true, true, false, true, true, true, false, true, true, true, true, false, false, true, true, false, true, true, true, false, false, true, false]
bool[32] h3 = [true, false, true, false, false, true, false, true, false, true, false, false, true, true, true, true, true, true, true, true, false, true, false, true, false, false, true, true, true, false, true, false]
bool[32] h4 = [false, true, false, true, false, false, false, true, false, false, false, false, true, true, true, false, false, true, false, true, false, false, true, false, false, true, true, true, true, true, true, true]
bool[32] h5 = [true, false, false, true, true, false, true, true, false, false, false, false, false, true, false, true, false, true, true, false, true, false, false, false, true, false, false, false, true, true, false, false]
bool[32] h6 = [false, false, false, true, true, true, true, true, true, false, false, false, false, false, true, true, true, true, false, true, true, false, false, true, true, false, true, false, true, false, true, true]
bool[32] h7 = [false, true, false, true, true, false, true, true, true, true, true, false, false, false, false, false, true, true, false, false, true, true, false, true, false, false, false, true, true, false, false, true]
bool[256] IV = [...h0, ...h1, ...h2, ...h3, ...h4, ...h5, ...h6, ...h7]
return IV

View file

@ -0,0 +1,8 @@
#pragma curve bn128
import "EMBED/sha256round" as sha256round
// a and b is NOT checked to be 0 or 1
// the return value is checked to be 0 or 1
// IV vector is checked to be of type bool
def main(bool[256] a, bool[256] b, bool[256] IV) -> (bool[256]):
return sha256round([...a, ...b], IV)

View file

@ -85,8 +85,7 @@ def main(u32[16] input, u32[8] current) -> u32[8]:
u32[64] w = [...input, ...[0x00000000; 48]]
for field i in 16..64 do
u32 r = extend(w, i)
w[i] = r
w[i] = extend(w, i)
endfor
u32 a = h0

View file

@ -0,0 +1,15 @@
{
"entry_point": "./tests/tests/hashes/sha256/embed/1024bitPadded.zok",
"tests": [
{
"input": {
"values": []
},
"output": {
"Ok": {
"values": ["1"]
}
}
}
]
}

View file

@ -0,0 +1,13 @@
import "hashes/sha256/embed/1024bitPadded" as sha256
def main() -> (field):
bool[256] a = [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]
bool[256] b = [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]
bool[256] c = [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]
bool[256] d = [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, true]
bool[256] digest = sha256(a, b, c, d)
assert(digest == [true, true, true, false, true, true, true, true, true, false, true, false, false, true, false, false, false, false, false, true, true, true, false, false, true, false, true, false, false, true, false, false, true, false, true, false, false, true, false, true, true, true, false, false, false, true, true, true, false, true, true, false, true, false, true, true, false, true, false, false, true, false, false, true, false, true, false, true, true, true, false, true, false, true, false, true, false, true, false, true, true, true, false, true, true, true, true, true, true, true, false, true, true, false, true, true, true, true, true, true, true, false, false, true, false, false, false, true, false, true, true, true, false, true, false, true, false, false, true, true, false, false, true, false, false, false, false, false, false, true, false, false, false, false, false, false, false, true, false, false, true, false, true, true, false, false, true, true, true, true, false, false, true, false, false, false, false, false, false, false, false, true, false, false, true, false, false, false, true, false, true, true, false, false, true, true, true, false, false, false, true, true, true, false, true, false, true, true, false, false, false, true, true, false, false, false, false, true, true, true, false, false, true, true, true, false, true, false, true, false, true, false, false, true, true, false, false, true, true, false, false, false, true, true, false, false, true, true, true, false, true, false, false, false, true, true, false, true, true, false, false, false, true, true, true, false, false, false, true, false, false, false, false, false, true, true])
return 1

View file

@ -0,0 +1,16 @@
{
"entry_point": "./tests/tests/hashes/sha256/embed/512bit.zok",
"curves": ["Bn128"],
"tests": [
{
"input": {
"values": []
},
"output": {
"Ok": {
"values": ["1"]
}
}
}
]
}

View file

@ -0,0 +1,11 @@
import "hashes/sha256/embed/512bit" as sha256
def main() -> (field):
bool[256] a = [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]
bool[256] b = [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, true]
bool[256] digest = sha256(a, b)
assert(digest == [false, false, false, true, true, true, true, true, false, false, true, true, true, false, true, true, true, false, false, false, true, false, true, true, true, false, false, true, true, false, false, false, true, true, false, false, false, false, true, false, false, false, false, true, true, true, true, false, true, false, true, true, true, false, false, false, true, false, false, true, false, true, false, false, false, false, true, true, true, true, false, false, true, false, false, false, true, true, true, false, true, true, true, false, false, false, true, true, false, false, true, true, false, false, true, false, false, false, true, false, true, true, false, false, false, false, false, true, false, true, false, false, false, false, false, true, false, true, false, false, true, false, true, true, false, true, true, false, false, false, false, true, false, false, false, false, false, true, false, true, false, true, false, true, false, true, true, false, false, false, true, false, false, true, true, false, false, false, false, true, false, true, false, false, true, true, true, false, false, true, true, true, false, false, true, true, true, false, false, false, true, true, true, true, false, false, true, true, false, true, false, true, true, true, true, false, true, true, true, true, false, false, false, true, false, false, true, true, true, false, true, false, false, false, false, false, false, true, true, true, true, false, true, true, true, true, true, false, true, false, true, false, true, true, false, false, true, true, false, false, false, false, true, true, true, true, false, true, false, false, true, false, true, true, false, true])
return 1

View file

@ -0,0 +1,16 @@
{
"entry_point": "./tests/tests/hashes/sha256/embed/512bitPacked.zok",
"curves": ["Bn128"],
"tests": [
{
"input": {
"values": []
},
"output": {
"Ok": {
"values": ["1"]
}
}
}
]
}

View file

@ -0,0 +1,14 @@
import "hashes/sha256/embed/512bitPacked" as sha256packed
def main() -> (field):
field a = 0
field b = 0
field c = 0
field d = 5
field[2] h = sha256packed([a, b, c, d])
assert(h[0] == 263561599766550617289250058199814760685)
assert(h[1] == 65303172752238645975888084098459749904)
return 1

View file

@ -0,0 +1,16 @@
{
"entry_point": "./tests/tests/hashes/sha256/embed/512bitPadded.zok",
"curves": ["Bn128"],
"tests": [
{
"input": {
"values": []
},
"output": {
"Ok": {
"values": ["1"]
}
}
}
]
}

View file

@ -0,0 +1,11 @@
import "hashes/sha256/embed/512bitPadded" as sha256
def main() -> (field):
bool[256] a = [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]
bool[256] b = [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, true]
bool[256] digest = sha256(a, b)
assert(digest == [true, true, false, false, false, true, true, false, false, true, false, false, true, false, false, false, false, false, false, true, true, true, true, false, false, false, true, false, false, false, true, false, true, true, false, false, false, true, false, true, true, true, true, true, true, true, true, true, false, true, false, false, false, false, false, true, false, true, true, false, false, true, false, false, true, false, true, false, true, true, true, true, false, true, true, false, true, false, false, false, false, false, false, false, true, false, true, true, true, false, false, false, true, true, false, false, true, true, true, true, true, false, true, false, true, false, true, false, false, true, false, true, true, true, true, false, true, false, false, false, true, true, true, false, true, true, false, true, false, false, true, true, false, false, false, true, false, false, true, false, false, false, false, false, true, true, true, false, true, true, true, false, true, true, true, true, true, true, true, true, true, false, false, false, true, false, false, true, true, true, false, false, false, true, false, false, true, true, true, true, false, false, true, true, false, false, false, false, false, true, true, true, true, true, false, false, false, true, false, false, true, false, true, false, false, true, true, false, true, true, true, true, true, false, true, false, true, false, true, false, true, false, true, false, true, true, true, false, false, false, false, false, false, true, false, true, true, false, false, true, true, true, false, false, true, true, true, false, false, false, false, true, false, false, false, false])
return 1

View file

@ -8,12 +8,9 @@ def main(u32[4] a, u16[4] b, u8[4] c) -> (bool[4][32], bool[4][16], bool[4][8]):
bool[4][8] f = [[false; 8]; 4]
for field i in 0..4 do
bool[32] g = u32_to_bits(a[i])
d[i] = g
bool[16] h = u16_to_bits(b[i])
e[i] = h
bool[8] j = u8_to_bits(c[i])
f[i] = j
d[i] = u32_to_bits(a[i])
e[i] = u16_to_bits(b[i])
f[i] = u8_to_bits(c[i])
endfor
return d, e, f

View file

@ -95,14 +95,24 @@ pub fn test_inner(test_path: &str) {
let curves = t.curves.clone().unwrap_or(vec![Curve::Bn128]);
for c in &curves {
match c {
Curve::Bn128 => compile_and_run::<Bn128Field>(t.clone()),
Curve::Bls12_381 => compile_and_run::<Bls12_381Field>(t.clone()),
Curve::Bls12_377 => compile_and_run::<Bls12_377Field>(t.clone()),
Curve::Bw6_761 => compile_and_run::<Bw6_761Field>(t.clone()),
}
}
// this function typically runs in a spawn thread whose stack size is small, leading to stack overflows
// to avoid that, run the stack-heavy bit in a thread with a larger stack (8M)
let builder = std::thread::Builder::new().stack_size(8388608);
builder
.spawn(move || {
for c in &curves {
match c {
Curve::Bn128 => compile_and_run::<Bn128Field>(t.clone()),
Curve::Bls12_381 => compile_and_run::<Bls12_381Field>(t.clone()),
Curve::Bls12_377 => compile_and_run::<Bls12_377Field>(t.clone()),
Curve::Bw6_761 => compile_and_run::<Bw6_761Field>(t.clone()),
}
}
})
.unwrap()
.join()
.unwrap();
}
fn compile_and_run<T: Field>(t: Tests) {