merge dev
This commit is contained in:
commit
f612ba7a29
65 changed files with 3447 additions and 2351 deletions
|
@ -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
317
Cargo.lock
generated
|
@ -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",
|
||||
|
|
|
@ -6,6 +6,7 @@ members = [
|
|||
"zokrates_cli",
|
||||
"zokrates_fs_resolver",
|
||||
"zokrates_stdlib",
|
||||
"zokrates_embed",
|
||||
"zokrates_abi",
|
||||
"zokrates_test",
|
||||
"zokrates_core_test",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "zokrates_abi"
|
||||
version = "0.1.2"
|
||||
version = "0.1.3"
|
||||
authors = ["Thibaut Schaeffer <thibaut@schaeff.fr>"]
|
||||
edition = "2018"
|
||||
|
||||
|
|
|
@ -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
|
@ -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") {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use core::convert::TryFrom;
|
||||
|
||||
use crate::constants::*;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CurveParameter {
|
||||
|
|
101
zokrates_cli/src/ops/check.rs
Normal file
101
zokrates_cli/src/ops/check.rs
Normal 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(())
|
||||
}
|
173
zokrates_cli/src/ops/compile.rs
Normal file
173
zokrates_cli/src/ops/compile.rs
Normal 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(())
|
||||
}
|
189
zokrates_cli/src/ops/compute_witness.rs
Normal file
189
zokrates_cli/src/ops/compute_witness.rs
Normal 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(())
|
||||
}
|
119
zokrates_cli/src/ops/export_verifier.rs
Normal file
119
zokrates_cli/src/ops/export_verifier.rs
Normal 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(())
|
||||
}
|
180
zokrates_cli/src/ops/generate_proof.rs
Normal file
180
zokrates_cli/src/ops/generate_proof.rs
Normal 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(())
|
||||
}
|
12
zokrates_cli/src/ops/mod.rs
Normal file
12
zokrates_cli/src/ops/mod.rs
Normal 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;
|
68
zokrates_cli/src/ops/print_proof.rs
Normal file
68
zokrates_cli/src/ops/print_proof.rs
Normal 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(())
|
||||
}
|
172
zokrates_cli/src/ops/setup.rs
Normal file
172
zokrates_cli/src/ops/setup.rs
Normal 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(())
|
||||
}
|
133
zokrates_cli/src/ops/verify.rs
Normal file
133
zokrates_cli/src/ops/verify.rs
Normal 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(())
|
||||
}
|
|
@ -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"
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
)]
|
||||
|
|
|
@ -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]),
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(
|
413
zokrates_core/src/static_analysis/variable_write_remover.rs
Normal file
413
zokrates_core/src/static_analysis/variable_write_remover.rs
Normal 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),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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
14
zokrates_embed/Cargo.toml
Normal 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
319
zokrates_embed/src/lib.rs
Normal 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, ¤t_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(),
|
||||
¤t_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());
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "zokrates_js"
|
||||
version = "1.0.26"
|
||||
version = "1.0.27"
|
||||
authors = ["Darko Macesic"]
|
||||
edition = "2018"
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "zokrates_pest_ast"
|
||||
version = "0.1.4"
|
||||
version = "0.1.5"
|
||||
authors = ["schaeff <thibaut@schaeff.fr>"]
|
||||
edition = "2018"
|
||||
|
||||
|
|
13
zokrates_stdlib/stdlib/hashes/sha256/embed/1024bit.zok
Normal file
13
zokrates_stdlib/stdlib/hashes/sha256/embed/1024bit.zok
Normal 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
|
16
zokrates_stdlib/stdlib/hashes/sha256/embed/1024bitPadded.zok
Normal file
16
zokrates_stdlib/stdlib/hashes/sha256/embed/1024bitPadded.zok
Normal 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
|
14
zokrates_stdlib/stdlib/hashes/sha256/embed/1536bit.zok
Normal file
14
zokrates_stdlib/stdlib/hashes/sha256/embed/1536bit.zok
Normal 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
|
30
zokrates_stdlib/stdlib/hashes/sha256/embed/256bitPadded.zok
Normal file
30
zokrates_stdlib/stdlib/hashes/sha256/embed/256bitPadded.zok
Normal 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
|
15
zokrates_stdlib/stdlib/hashes/sha256/embed/512bit.zok
Normal file
15
zokrates_stdlib/stdlib/hashes/sha256/embed/512bit.zok
Normal 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
|
23
zokrates_stdlib/stdlib/hashes/sha256/embed/512bitPacked.zok
Normal file
23
zokrates_stdlib/stdlib/hashes/sha256/embed/512bitPacked.zok
Normal 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]
|
17
zokrates_stdlib/stdlib/hashes/sha256/embed/512bitPadded.zok
Normal file
17
zokrates_stdlib/stdlib/hashes/sha256/embed/512bitPadded.zok
Normal 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
|
15
zokrates_stdlib/stdlib/hashes/sha256/embed/IVconstants.zok
Normal file
15
zokrates_stdlib/stdlib/hashes/sha256/embed/IVconstants.zok
Normal 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
|
|
@ -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)
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/hashes/sha256/embed/1024bitPadded.zok",
|
||||
"tests": [
|
||||
{
|
||||
"input": {
|
||||
"values": []
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": ["1"]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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
|
16
zokrates_stdlib/tests/tests/hashes/sha256/embed/512bit.json
Normal file
16
zokrates_stdlib/tests/tests/hashes/sha256/embed/512bit.json
Normal file
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/hashes/sha256/embed/512bit.zok",
|
||||
"curves": ["Bn128"],
|
||||
"tests": [
|
||||
{
|
||||
"input": {
|
||||
"values": []
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": ["1"]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
11
zokrates_stdlib/tests/tests/hashes/sha256/embed/512bit.zok
Normal file
11
zokrates_stdlib/tests/tests/hashes/sha256/embed/512bit.zok
Normal 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
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/hashes/sha256/embed/512bitPacked.zok",
|
||||
"curves": ["Bn128"],
|
||||
"tests": [
|
||||
{
|
||||
"input": {
|
||||
"values": []
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": ["1"]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/hashes/sha256/embed/512bitPadded.zok",
|
||||
"curves": ["Bn128"],
|
||||
"tests": [
|
||||
{
|
||||
"input": {
|
||||
"values": []
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": ["1"]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue