diff --git a/.circleci/config.yml b/.circleci/config.yml index 98c18e57e..08cdc0a63 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -12,7 +12,7 @@ jobs: build: docker: - image: zokrates/env:latest - resource_class: large + resource_class: xlarge steps: - checkout - run: @@ -22,6 +22,7 @@ jobs: - restore-sccache-cache - run: name: Build + no_output_timeout: "30m" command: RUSTFLAGS="-D warnings" ./build.sh - save-sccache-cache test: @@ -68,7 +69,7 @@ jobs: docker: - image: zokrates/env:latest - image: trufflesuite/ganache-cli:next - resource_class: large + resource_class: xlarge steps: - checkout - run: @@ -76,6 +77,9 @@ jobs: command: rustc --version; cargo --version; rustup --version - setup-sccache - restore-sccache-cache + - run: + name: Install foundry + command: ./scripts/install_foundry.sh - run: name: Run integration tests no_output_timeout: "30m" @@ -119,11 +123,13 @@ jobs: - setup-sccache - restore-sccache-cache - run: - name: Check format - command: cargo fmt --all -- --check - - run: - name: Run clippy - command: cargo clippy -- -D warnings + name: Install headless chrome dependencies + command: | + apt-get update && apt-get install -yq \ + ca-certificates fonts-liberation libasound2 libatk-bridge2.0-0 libatk1.0-0 libc6 libcairo2 libcups2 \ + libdbus-1-3 libexpat1 libfontconfig1 libgbm1 libgcc1 libglib2.0-0 libgtk-3-0 libnspr4 libnss3 \ + libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 \ + libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 lsb-release wget xdg-utils - run: name: Run tests no_output_timeout: "30m" @@ -187,7 +193,7 @@ commands: steps: - restore_cache: name: Restore sccache cache - key: sccache-cache-stable-{{ arch }}-{{ .Environment.CIRCLE_JOB }} + key: sccache-cache-stable-{{ .Environment.CACHE_VERSION }}-{{ arch }}-{{ .Environment.CIRCLE_JOB }} save-sccache-cache: steps: - save_cache: @@ -244,7 +250,7 @@ workflows: jobs: - build - test - - wasm_test + # - wasm_test - integration_test - zokrates_js_build - zokrates_js_test @@ -302,7 +308,7 @@ workflows: requires: - build - test - - wasm_test + # - wasm_test - integration_test - zokrates_js_build - zokrates_js_test diff --git a/.github/workflows/js-format-check.yml b/.github/workflows/js-format-check.yml index f09fe5974..9c88c5cc9 100644 --- a/.github/workflows/js-format-check.yml +++ b/.github/workflows/js-format-check.yml @@ -6,6 +6,6 @@ jobs: steps: - uses: actions/checkout@v2 - name: Check format with prettier - uses: creyD/prettier_action@v4.2 + uses: creyD/prettier_action@v4.3 with: prettier_options: --check ./**/*.{js,ts,json} diff --git a/.gitignore b/.gitignore index a11fa3038..81e430487 100644 --- a/.gitignore +++ b/.gitignore @@ -7,12 +7,17 @@ out out.ztf abi.json proof.json +init.json +steps.json proving.key verification.key verifier.sol proof.json universal_setup.dat witness +witness.json +nova.params +running_instance.json # ZoKrates source files at the root of the repository /*.zok diff --git a/CHANGELOG.md b/CHANGELOG.md index e589ac990..0fffeb93f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,54 @@ All notable changes to this project will be documented in this file. ## [Unreleased] https://github.com/Zokrates/ZoKrates/compare/latest...develop +## [0.8.7] - 2023-04-22 + +### Release +- https://github.com/Zokrates/ZoKrates/releases/tag/0.8.7 + +### Changes +- Reduce memory usage of compilation (#1296, @schaeff) +- Add initial support for the Nova proving scheme (#1235, @schaeff) + +## [0.8.6] - 2023-04-13 + +### Release +- https://github.com/Zokrates/ZoKrates/releases/tag/0.8.6 + +### Changes +- Make ZoKrates build on stable rust (#1288, @schaeff) +- Introduce sourcemaps, introduce `inspect` command to identify costly parts of the source (#1285, @schaeff) +- Change witness format to binary, optimize backend integration code to improve proving time (#1289, @dark64) +- Fixed precedence issue on Sudoku example. (#1287, @Turupawn) +- Reduce compiled program size by deduplicating assembly solvers (#1268, @dark64) + +## [0.8.5] - 2023-03-28 + +### Release +- https://github.com/Zokrates/ZoKrates/releases/tag/0.8.5 + +### Changes +- Reduce memory usage and runtime by refactoring the reducer (ssa, propagation, unrolling and inlining) (#1283, @schaeff) +- Fix `radix-path` help message on `mpc init` subcommand (#1280, @dark64) +- Fix a potential crash in `zokrates-js` due to inefficient serialization of a setup keypair (#1277, @dark64) +- Show help when running `zokrates mpc` (#1275, @dark64) + +## [0.8.4] - 2023-01-31 + +### Release +- https://github.com/Zokrates/ZoKrates/releases/tag/0.8.4 + +### Changes +- Fix array propagation for spreads and repeaters (#1269, @schaeff) +- Remove solc dependency for tests, use foundry instead (#1266, @schaeff) +- Optimize `zokrates-js` library size (#1264, @dark64) +- Use multicore feature in ark and bellman to improve performance (#1261, @dark64) +- Allow user-provided randomness in setup and proof generation (#1254, @dark64) +- Fix typos (#1260, @rex4539) +- Introduce constraint generation through assembly blocks (#1246, @dark64) +- Loosen up whitespace restrictions to allow more formatting styles (#1232, @dark64) +- Reduce cost of boolean array equality checks (#1228, @schaeff) + ## [0.8.3] - 2022-10-11 ### Release diff --git a/Cargo.lock b/Cargo.lock index 33389a5d4..4f4c991bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,11 +2,22 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addchain" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2e69442aa5628ea6951fa33e24efe8313f4321a91bd729fc2f75bdfc858570" +dependencies = [ + "num-bigint 0.3.3", + "num-integer", + "num-traits 0.2.15", +] + [[package]] name = "addr2line" -version = "0.17.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" dependencies = [ "gimli", ] @@ -39,9 +50,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.7.18" +version = "0.7.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" dependencies = [ "memchr", ] @@ -127,6 +138,7 @@ dependencies = [ "blake2 0.9.2", "derivative", "digest 0.9.0", + "rayon", "tracing", ] @@ -141,6 +153,7 @@ dependencies = [ "ark-std", "derivative", "num-traits 0.2.15", + "rayon", "zeroize", ] @@ -158,6 +171,7 @@ dependencies = [ "num-bigint 0.4.3", "num-traits 0.2.15", "paste", + "rayon", "rustc_version", "zeroize", ] @@ -168,8 +182,8 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" dependencies = [ - "quote 1.0.20", - "syn 1.0.98", + "quote 1.0.26", + "syn 1.0.109", ] [[package]] @@ -180,8 +194,8 @@ checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" dependencies = [ "num-bigint 0.4.3", "num-traits 0.2.15", - "quote 1.0.20", - "syn 1.0.98", + "quote 1.0.26", + "syn 1.0.109", ] [[package]] @@ -199,6 +213,7 @@ dependencies = [ "ark-serialize", "ark-std", "derivative", + "rayon", "tracing", ] @@ -215,6 +230,7 @@ dependencies = [ "ark-relations", "ark-serialize", "ark-std", + "rayon", ] [[package]] @@ -230,6 +246,7 @@ dependencies = [ "ark-std", "derivative", "digest 0.9.0", + "rayon", ] [[package]] @@ -250,6 +267,17 @@ dependencies = [ "tracing", ] +[[package]] +name = "ark-pallas" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e945e1c8d86aa869853944ce6ecf072c2dac623b88c94e68792901b06190e53" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-std", +] + [[package]] name = "ark-poly" version = "0.3.0" @@ -261,6 +289,7 @@ dependencies = [ "ark-std", "derivative", "hashbrown 0.11.2", + "rayon", ] [[package]] @@ -271,11 +300,14 @@ checksum = "a71ddfa72bad1446cab7bbecb6018dbbdc9abcbc3a0065483ae5186ad2a64dcd" dependencies = [ "ark-ec", "ark-ff", + "ark-nonnative-field", "ark-poly", + "ark-relations", "ark-serialize", "ark-std", "derivative", "digest 0.9.0", + "rayon", "tracing", ] @@ -304,6 +336,7 @@ dependencies = [ "ark-ff", "ark-std", "tracing", + "tracing-subscriber", ] [[package]] @@ -323,9 +356,9 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8dd4e5f0bf8285d5ed538d27fab7411f3e297908fd93c62195de8bee3f199e82" dependencies = [ - "proc-macro2 1.0.40", - "quote 1.0.20", - "syn 1.0.98", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", ] [[package]] @@ -347,13 +380,26 @@ checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" dependencies = [ "num-traits 0.2.15", "rand 0.8.5", + "rayon", +] + +[[package]] +name = "ark-vesta" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2666857534c298a6ed92d7258f3289f66651a98948abe80aad0b599c160291c" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-pallas", + "ark-std", ] [[package]] name = "arrayref" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" [[package]] name = "arrayvec" @@ -364,6 +410,12 @@ dependencies = [ "nodrop", ] +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + [[package]] name = "arrayvec" version = "0.7.2" @@ -390,23 +442,11 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", "winapi", ] -[[package]] -name = "auto_impl" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a8c1df849285fbacd587de7818cc7d13be6cd2cbcd47a04fb1801b0e2706e33" -dependencies = [ - "proc-macro-error 1.0.4", - "proc-macro2 1.0.40", - "quote 1.0.20", - "syn 1.0.98", -] - [[package]] name = "autocfg" version = "1.1.0" @@ -415,9 +455,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.65" +version = "0.3.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61" +checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" dependencies = [ "addr2line", "cc", @@ -445,6 +485,34 @@ dependencies = [ "web-sys", ] +[[package]] +name = "bellperson" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93eaee4b4753554139ae52ecf0e8b8c128cbc561b32e1bfaa32f70cba8518c1f" +dependencies = [ + "bincode 1.3.3", + "blake2s_simd 1.0.1", + "blstrs", + "byteorder", + "crossbeam-channel 0.5.8", + "digest 0.10.6", + "ec-gpu", + "ec-gpu-gen", + "ff 0.13.0", + "group 0.13.0", + "log", + "memmap2", + "pairing 0.23.0", + "rand 0.8.5", + "rand_core 0.6.4", + "rayon", + "rustversion", + "serde", + "sha2 0.10.6", + "thiserror", +] + [[package]] name = "bincode" version = "0.8.0" @@ -456,6 +524,15 @@ dependencies = [ "serde", ] +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + [[package]] name = "bit-vec" version = "0.6.3" @@ -470,9 +547,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitvec" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1489fcb93a5bb47da0462ca93ad252ad6af2145cce58d10d46a83931ba9f016b" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" dependencies = [ "funty", "radium", @@ -510,7 +587,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" dependencies = [ "arrayvec 0.4.12", - "constant_time_eq", + "constant_time_eq 0.1.5", ] [[package]] @@ -521,7 +598,40 @@ checksum = "fdc60350286c7c3db13b98e91dbe5c8b6830a6821bc20af5b0c310ce94d74915" dependencies = [ "arrayvec 0.4.12", "byteorder", - "constant_time_eq", + "constant_time_eq 0.1.5", +] + +[[package]] +name = "blake2b_simd" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c2f0dc9a68c6317d884f97cc36cf5a3d20ba14ce404227df55e1af708ab04bc" +dependencies = [ + "arrayref", + "arrayvec 0.7.2", + "constant_time_eq 0.2.5", +] + +[[package]] +name = "blake2s_simd" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e461a7034e85b211a4acb57ee2e6730b32912b06c08cc242243c39fc21ae6a2" +dependencies = [ + "arrayref", + "arrayvec 0.5.2", + "constant_time_eq 0.1.5", +] + +[[package]] +name = "blake2s_simd" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6637f448b9e61dfadbdcbae9a885fadee1f3eaffb1f8d3c1965d3ade8bdfd44f" +dependencies = [ + "arrayref", + "arrayvec 0.7.2", + "constant_time_eq 0.2.5", ] [[package]] @@ -543,16 +653,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ "block-padding 0.2.1", - "generic-array 0.14.5", + "generic-array 0.14.7", ] [[package]] name = "block-buffer" -version = "0.10.2" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array 0.14.5", + "generic-array 0.14.7", ] [[package]] @@ -571,28 +681,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" [[package]] -name = "bstr" -version = "0.2.17" +name = "blst" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" +checksum = "6a30d0edd9dd1c60ddb42b80341c7852f6f985279a5c1a83659dcb65899dec99" dependencies = [ - "lazy_static", - "memchr", - "regex-automata", + "cc", + "glob 0.3.1", + "threadpool", + "which", + "zeroize", +] + +[[package]] +name = "blstrs" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33149fccb7f93271f0192614b884430cf274e880506bbd171cbc8918dcc95b14" +dependencies = [ + "blst", + "byte-slice-cast", + "ff 0.13.0", + "group 0.13.0", + "pairing 0.23.0", + "rand_core 0.6.4", "serde", + "subtle 2.5.0", ] [[package]] name = "bumpalo" -version = "3.10.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "byte-slice-cast" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87c5fdd0166095e1d463fc6cc01aa8ce547ad77a4e84d42eb6762b084e28067e" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" [[package]] name = "byte-tools" @@ -614,15 +741,15 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.1.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" [[package]] name = "camino" -version = "1.0.9" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "869119e97797867fd90f5e22af7d0bd274bd4635ebb9eb68c04f3f513ae6c412" +checksum = "c530edf18f37068ac2d977409ed5cd50d53d73bc653c7647b48eb78976ac9ae2" dependencies = [ "serde", ] @@ -644,16 +771,16 @@ checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" dependencies = [ "camino", "cargo-platform", - "semver 1.0.12", + "semver 1.0.17", "serde", "serde_json", ] [[package]] name = "cc" -version = "1.0.73" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" [[package]] name = "cfg-if" @@ -707,19 +834,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6dd675567eb3e35787bd2583d129e85fabc7503b0a093d08c51198a307e2091" dependencies = [ "heck", - "proc-macro-error 0.4.12", - "proc-macro2 1.0.40", - "quote 1.0.20", - "syn 1.0.98", -] - -[[package]] -name = "cmake" -version = "0.1.48" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8ad8cef104ac57b68b89df3208164d228503abbdce70f6880ffa3d970e7443a" -dependencies = [ - "cc", + "proc-macro-error", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", ] [[package]] @@ -749,15 +867,30 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" +[[package]] +name = "constant_time_eq" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13418e745008f7349ec7e449155f419a61b92b58a99cc3616942b926825ec76b" + [[package]] name = "cpufeatures" -version = "0.2.2" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +checksum = "280a9f2d8b3a38871a3c8a46fb80db65e5e5ed97da80c4d08bf27fb63e35e181" dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if 1.0.0", +] + [[package]] name = "crossbeam" version = "0.7.3" @@ -765,11 +898,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69323bff1fb41c635347b8ead484a5ca6c3f11914d784170b158d8449ab07f8e" dependencies = [ "cfg-if 0.1.10", - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-epoch", + "crossbeam-channel 0.4.4", + "crossbeam-deque 0.7.4", + "crossbeam-epoch 0.8.2", "crossbeam-queue", - "crossbeam-utils", + "crossbeam-utils 0.7.2", ] [[package]] @@ -778,21 +911,42 @@ 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", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils 0.8.15", +] + [[package]] name = "crossbeam-deque" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c20ff29ded3204c5106278a81a38f4b482636ed4fa1e6cfbeef193291beb29ed" dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", + "crossbeam-epoch 0.8.2", + "crossbeam-utils 0.7.2", "maybe-uninit", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-epoch 0.9.14", + "crossbeam-utils 0.8.15", +] + [[package]] name = "crossbeam-epoch" version = "0.8.2" @@ -801,10 +955,23 @@ checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" dependencies = [ "autocfg", "cfg-if 0.1.10", - "crossbeam-utils", + "crossbeam-utils 0.7.2", "lazy_static", "maybe-uninit", - "memoffset", + "memoffset 0.5.6", + "scopeguard", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" +dependencies = [ + "autocfg", + "cfg-if 1.0.0", + "crossbeam-utils 0.8.15", + "memoffset 0.8.0", "scopeguard", ] @@ -815,7 +982,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", ] @@ -830,6 +997,15 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "crossbeam-utils" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +dependencies = [ + "cfg-if 1.0.0", +] + [[package]] name = "crunchy" version = "0.2.2" @@ -838,11 +1014,11 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-common" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5999502d32b9c48d492abe66392408144895020ec4709e549e840799f3bb74c0" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array 0.14.5", + "generic-array 0.14.7", "typenum", ] @@ -862,40 +1038,18 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" dependencies = [ - "generic-array 0.14.5", - "subtle 2.4.1", -] - -[[package]] -name = "csv" -version = "1.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" -dependencies = [ - "bstr", - "csv-core", - "itoa 0.4.8", - "ryu", - "serde", -] - -[[package]] -name = "csv-core" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" -dependencies = [ - "memchr", + "generic-array 0.14.7", + "subtle 2.5.0", ] [[package]] name = "ctor" -version = "0.1.22" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c" +checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" dependencies = [ - "quote 1.0.20", - "syn 1.0.98", + "quote 1.0.26", + "syn 1.0.109", ] [[package]] @@ -904,9 +1058,9 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "proc-macro2 1.0.40", - "quote 1.0.20", - "syn 1.0.98", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", ] [[package]] @@ -942,16 +1096,16 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "generic-array 0.14.5", + "generic-array 0.14.7", ] [[package]] name = "digest" -version = "0.10.3" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" dependencies = [ - "block-buffer 0.10.2", + "block-buffer 0.10.4", "crypto-common", ] @@ -975,22 +1129,50 @@ dependencies = [ "winapi", ] +[[package]] +name = "ec-gpu" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd63582de2b59ea1aa48d7c1941b5d87618d95484397521b3acdfa0e1e9f5e45" + +[[package]] +name = "ec-gpu-gen" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "892df2aa20abec5b816e15d5d6383892ca142077708efa3067dd3ac44b75c664" +dependencies = [ + "bitvec", + "crossbeam-channel 0.5.8", + "ec-gpu", + "execute", + "ff 0.13.0", + "group 0.13.0", + "hex 0.4.3", + "log", + "num_cpus", + "once_cell", + "rayon", + "sha2 0.10.6", + "thiserror", + "yastl", +] + [[package]] name = "either" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "env_logger" -version = "0.9.0" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" dependencies = [ "atty", "humantime", "log", - "regex 1.6.0", + "regex 1.7.3", "termcolor", ] @@ -1000,6 +1182,27 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f4b14e20978669064c33b4c1e0fb4083412e40fe56cbea2eae80fd7591503ee" +[[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "error-chain" version = "0.11.0" @@ -1020,17 +1223,17 @@ dependencies = [ [[package]] name = "ethabi" -version = "17.1.0" +version = "17.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f186de076b3e77b8e6d73c99d1b52edc2a229e604f4b5eb6992c06c11d79d537" +checksum = "e4966fba78396ff92db3b817ee71143eccd98acf0f876b8d600e585a670c5d1b" dependencies = [ "ethereum-types", "hex 0.4.3", "once_cell", - "regex 1.6.0", + "regex 1.7.3", "serde", "serde_json", - "sha3 0.10.1", + "sha3 0.10.7", "thiserror", "uint", ] @@ -1062,6 +1265,43 @@ dependencies = [ "uint", ] +[[package]] +name = "execute" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d9a9ea4c04632c16bc5c71a2fcc63d308481f7fc67eb1a1ce6315c44a426ae" +dependencies = [ + "execute-command-macro", + "execute-command-tokens", + "generic-array 0.14.7", +] + +[[package]] +name = "execute-command-macro" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5fbc65a0cf735106743f4c38c9a3671c1e734b5c2c20d21a3c93c696daa3157" +dependencies = [ + "execute-command-macro-impl", +] + +[[package]] +name = "execute-command-macro-impl" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5109f6bc9cd57feda665da326f3f6c57e0498c8fe9f7d12d7b8abc96719ca91b" +dependencies = [ + "execute-command-tokens", + "quote 1.0.26", + "syn 1.0.109", +] + +[[package]] +name = "execute-command-tokens" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ba569491c70ec8471e34aa7e9c0b9e82bb5d2464c0398442d17d3c4af814e5a" + [[package]] name = "exitcode" version = "1.1.2" @@ -1084,9 +1324,9 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" dependencies = [ - "proc-macro2 1.0.40", - "quote 1.0.20", - "syn 1.0.98", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", "synstructure", ] @@ -1098,13 +1338,36 @@ checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" [[package]] name = "fastrand" -version = "1.7.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" dependencies = [ "instant", ] +[[package]] +name = "ff" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" +dependencies = [ + "rand_core 0.6.4", + "subtle 2.5.0", +] + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "bitvec", + "byteorder", + "ff_derive", + "rand_core 0.6.4", + "subtle 2.5.0", +] + [[package]] name = "ff_ce" version = "0.10.3" @@ -1117,6 +1380,22 @@ dependencies = [ "rand 0.4.6", ] +[[package]] +name = "ff_derive" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9f54704be45ed286151c5e11531316eaef5b8f5af7d597b806fdb8af108d84a" +dependencies = [ + "addchain", + "cfg-if 1.0.0", + "num-bigint 0.3.3", + "num-integer", + "num-traits 0.2.15", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", +] + [[package]] name = "ff_derive_ce" version = "0.8.0" @@ -1126,9 +1405,9 @@ dependencies = [ "num-bigint 0.2.6", "num-integer", "num-traits 0.2.15", - "proc-macro2 1.0.40", - "quote 1.0.20", - "syn 1.0.98", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", ] [[package]] @@ -1143,6 +1422,25 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "flate2" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "flume" +version = "0.10.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577" +dependencies = [ + "spin 0.9.8", +] + [[package]] name = "from-pest" version = "0.3.1" @@ -1155,9 +1453,9 @@ dependencies = [ [[package]] name = "fs_extra" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" [[package]] name = "fuchsia-cprng" @@ -1173,9 +1471,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.21" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" dependencies = [ "futures-channel", "futures-core", @@ -1188,9 +1486,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.21" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ "futures-core", "futures-sink", @@ -1198,15 +1496,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.21" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" [[package]] name = "futures-executor" -version = "0.3.21" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" dependencies = [ "futures-core", "futures-task", @@ -1216,27 +1514,27 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.21" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" [[package]] name = "futures-sink" -version = "0.3.21" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" [[package]] name = "futures-task" -version = "0.3.21" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" [[package]] name = "futures-util" -version = "0.3.21" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ "futures-channel", "futures-core", @@ -1260,9 +1558,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.5" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -1270,9 +1568,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.7" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -1283,9 +1581,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.26.1" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" +checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" [[package]] name = "glob" @@ -1295,9 +1593,33 @@ checksum = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" [[package]] name = "glob" -version = "0.3.0" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "group" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" +dependencies = [ + "ff 0.12.1", + "rand_core 0.6.4", + "subtle 2.5.0", +] + +[[package]] +name = "group" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff 0.13.0", + "rand 0.8.5", + "rand_core 0.6.4", + "rand_xorshift", + "subtle 2.5.0", +] [[package]] name = "half" @@ -1320,15 +1642,6 @@ dependencies = [ "ahash", ] -[[package]] -name = "hashbrown" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3" -dependencies = [ - "ahash", -] - [[package]] name = "heck" version = "0.3.3" @@ -1347,6 +1660,21 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + [[package]] name = "hex" version = "0.3.2" @@ -1358,6 +1686,9 @@ name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] [[package]] name = "hex-literal" @@ -1417,9 +1748,9 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" dependencies = [ - "proc-macro2 1.0.40", - "quote 1.0.20", - "syn 1.0.98", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", ] [[package]] @@ -1441,6 +1772,17 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "io-lifetimes" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" +dependencies = [ + "hermit-abi 0.3.1", + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "itertools" version = "0.7.11" @@ -1460,16 +1802,19 @@ dependencies = [ ] [[package]] -name = "itoa" -version = "0.4.8" +name = "itertools" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" +checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" +dependencies = [ + "either", +] [[package]] name = "itoa" -version = "1.0.2" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" [[package]] name = "js-sys" @@ -1488,9 +1833,12 @@ checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd" [[package]] name = "keccak" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9b7d56ba4a8344d6be9729995e6b06f928af29998cdf79fe390cbf6b1fee838" +checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768" +dependencies = [ + "cpufeatures", +] [[package]] name = "lazy_static" @@ -1498,14 +1846,30 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" dependencies = [ - "spin", + "spin 0.5.2", ] [[package]] name = "libc" -version = "0.2.126" +version = "0.2.141" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" + +[[package]] +name = "linux-raw-sys" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" + +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] [[package]] name = "log" @@ -1516,12 +1880,6 @@ dependencies = [ "cfg-if 1.0.0", ] -[[package]] -name = "maplit" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" - [[package]] name = "maybe-uninit" version = "2.0.0" @@ -1534,6 +1892,15 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "memmap2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +dependencies = [ + "libc", +] + [[package]] name = "memoffset" version = "0.5.6" @@ -1543,15 +1910,43 @@ dependencies = [ "autocfg", ] +[[package]] +name = "memoffset" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +dependencies = [ + "autocfg", +] + [[package]] name = "miniz_oxide" -version = "0.5.3" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" dependencies = [ "adler", ] +[[package]] +name = "neptune" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4227e5557caad6d2a910b7770f2479f0c9aeb8ddc1dc537623cb6ffec7f01d31" +dependencies = [ + "bellperson", + "blake2s_simd 0.5.11", + "blstrs", + "byteorder", + "ff 0.13.0", + "generic-array 0.14.7", + "itertools 0.8.2", + "log", + "pasta_curves", + "serde", + "trait-set", +] + [[package]] name = "nodrop" version = "0.1.14" @@ -1559,27 +1954,43 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" [[package]] -name = "num" -version = "0.1.42" +name = "nova-snark" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" +checksum = "d6247c61ab29e5da01c8f80403c25c40956045f0343d79793a2675bf7775dd80" dependencies = [ + "bellperson", + "bincode 1.3.3", + "bitvec", + "byteorder", + "digest 0.8.1", + "ff 0.13.0", + "flate2", + "generic-array 0.14.7", + "itertools 0.9.0", + "neptune", + "num-bigint 0.4.3", "num-integer", - "num-iter", "num-traits 0.2.15", + "pasta-msm", + "pasta_curves", + "rand_chacha", + "rand_core 0.6.4", + "rayon", + "serde", + "sha3 0.8.2", + "subtle 2.5.0", + "thiserror", ] [[package]] name = "num" -version = "0.4.0" +version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" +checksum = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" dependencies = [ - "num-bigint 0.4.3", - "num-complex", "num-integer", "num-iter", - "num-rational", "num-traits 0.2.15", ] @@ -1597,9 +2008,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.3" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +checksum = "5f6f7833f2cbf2360a6cfd58cd41a53aa7a90bd4c202f5b1c7dd2ed73c57b2c3" dependencies = [ "autocfg", "num-integer", @@ -1607,12 +2018,16 @@ dependencies = [ ] [[package]] -name = "num-complex" -version = "0.4.2" +name = "num-bigint" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" dependencies = [ + "autocfg", + "num-integer", "num-traits 0.2.15", + "rand 0.8.5", + "serde", ] [[package]] @@ -1636,18 +2051,6 @@ dependencies = [ "num-traits 0.2.15", ] -[[package]] -name = "num-rational" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" -dependencies = [ - "autocfg", - "num-bigint 0.4.3", - "num-integer", - "num-traits 0.2.15", -] - [[package]] name = "num-traits" version = "0.1.43" @@ -1668,49 +2071,28 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.13.1" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ - "hermit-abi", + "hermit-abi 0.2.6", "libc", ] -[[package]] -name = "num_enum" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9" -dependencies = [ - "num_enum_derive", -] - -[[package]] -name = "num_enum_derive" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" -dependencies = [ - "proc-macro-crate", - "proc-macro2 1.0.40", - "quote 1.0.20", - "syn 1.0.98", -] - [[package]] name = "object" -version = "0.28.4" +version = "0.30.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" +checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.13.0" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "opaque-debug" @@ -1733,6 +2115,24 @@ dependencies = [ "winapi", ] +[[package]] +name = "pairing" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135590d8bdba2b31346f9cd1fb2a912329f5135e832a4f422942eb6ead8b6b3b" +dependencies = [ + "group 0.12.1", +] + +[[package]] +name = "pairing" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fec4625e73cf41ef4bb6846cafa6d44736525f442ba45e407c4a000a13996f" +dependencies = [ + "group 0.13.0", +] + [[package]] name = "pairing_ce" version = "0.21.1" @@ -1746,9 +2146,9 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.1.5" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9182e4a71cae089267ab03e67c99368db7cd877baf50f931e5d6d4b71e195ac0" +checksum = "637935964ff85a605d114591d4d2c13c5d1ba2806dae97cea6bf180238a749ac" dependencies = [ "arrayvec 0.7.2", "bitvec", @@ -1760,28 +2160,59 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.1.3" +version = "3.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9299338969a3d2f491d65f140b00ddec470858402f888af98e8642fb5e8965cd" +checksum = "86b26a931f824dd4eca30b3e43bb4f31cd5f0d3a403c5f5ff27106b805bfde7b" dependencies = [ "proc-macro-crate", - "proc-macro2 1.0.40", - "quote 1.0.20", - "syn 1.0.98", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", +] + +[[package]] +name = "pasta-msm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e85d75eba3e7e9ee3bd11342b669185e194dadda3557934bc1000d9b87159d3" +dependencies = [ + "cc", + "pasta_curves", + "semolina", + "sppark", + "which", +] + +[[package]] +name = "pasta_curves" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e57598f73cc7e1b2ac63c79c517b31a0877cd7c402cdcaa311b5208de7a095" +dependencies = [ + "blake2b_simd", + "ff 0.13.0", + "group 0.13.0", + "hex 0.4.3", + "lazy_static", + "rand 0.8.5", + "serde", + "static_assertions", + "subtle 2.5.0", ] [[package]] name = "paste" -version = "1.0.7" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc" +checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" [[package]] name = "pest" -version = "2.1.3" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +checksum = "cb779fcf4bb850fbbb0edc96ff6cf34fd90c4b1a112ce042653280d9a7364048" dependencies = [ + "thiserror", "ucd-trie", ] @@ -1800,9 +2231,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.1.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" +checksum = "502b62a6d0245378b04ffe0a7fb4f4419a4815fce813bd8a0ec89a56e07d67b1" dependencies = [ "pest", "pest_generator", @@ -1810,26 +2241,26 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.1.3" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" +checksum = "451e629bf49b750254da26132f1a5a9d11fd8a95a3df51d15c4abd1ba154cb6c" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.40", - "quote 1.0.20", - "syn 1.0.98", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", ] [[package]] name = "pest_meta" -version = "2.1.3" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d" +checksum = "bcec162c71c45e269dfc3fc2916eaeb97feab22993a21bcce4721d08cd7801a6" dependencies = [ - "maplit", + "once_cell", "pest", - "sha-1", + "sha1", ] [[package]] @@ -1862,9 +2293,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "ppv-lite86" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "pretty_assertions" @@ -1880,14 +2311,14 @@ dependencies = [ [[package]] name = "pretty_assertions" -version = "1.2.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89f989ac94207d048d92db058e4f6ec7342b0971fc58d1271ca148b799b3563" +checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755" dependencies = [ - "ansi_term 0.12.1", "ctor", "diff", "output_vt100", + "yansi", ] [[package]] @@ -1905,10 +2336,11 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "1.1.3" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" +checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" dependencies = [ + "once_cell", "thiserror", "toml", ] @@ -1919,23 +2351,10 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18f33027081eba0a6d8aba6d1b1c3a3be58cbb12106341c2d5759fcd9b5277e7" dependencies = [ - "proc-macro-error-attr 0.4.12", - "proc-macro2 1.0.40", - "quote 1.0.20", - "syn 1.0.98", - "version_check", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr 1.0.4", - "proc-macro2 1.0.40", - "quote 1.0.20", - "syn 1.0.98", + "proc-macro-error-attr", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", "version_check", ] @@ -1945,29 +2364,18 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a5b4b77fdb63c1eca72173d68d24501c54ab1269409f6b672c85deb18af69de" dependencies = [ - "proc-macro2 1.0.40", - "quote 1.0.20", - "syn 1.0.98", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", "syn-mid", "version_check", ] -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2 1.0.40", - "quote 1.0.20", - "version_check", -] - [[package]] name = "proc-macro-hack" -version = "0.5.19" +version = "0.5.20+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" @@ -1980,18 +2388,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.40" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" dependencies = [ "unicode-ident", ] [[package]] name = "pulldown-cmark" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34f197a544b0c9ab3ae46c359a7ec9cbbb5c7bf97054266fecb7ead794a181d6" +checksum = "2d9cc634bc78768157b5cbfe988ffcd1dcba95cd2b2f03a88316c08c6d00ed63" dependencies = [ "bitflags", "memchr", @@ -2009,11 +2417,11 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.20" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" dependencies = [ - "proc-macro2 1.0.40", + "proc-macro2 1.0.56", ] [[package]] @@ -2043,7 +2451,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", - "rand_core 0.6.3", + "rand_core 0.6.4", ] [[package]] @@ -2053,7 +2461,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.3", + "rand_core 0.6.4", ] [[package]] @@ -2073,13 +2481,44 @@ checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" [[package]] name = "rand_core" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", ] +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "rayon" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +dependencies = [ + "crossbeam-channel 0.5.8", + "crossbeam-deque 0.8.3", + "crossbeam-utils 0.8.15", + "num_cpus", +] + [[package]] name = "rdrand" version = "0.4.0" @@ -2091,9 +2530,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.13" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_syscall" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ "bitflags", ] @@ -2105,16 +2553,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ "getrandom", - "redox_syscall", + "redox_syscall 0.2.16", "thiserror", ] -[[package]] -name = "reduce" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16d2dc47b68ac15ea328cd7ebe01d7d512ed29787f7d534ad2a3c341328b35d7" - [[package]] name = "regex" version = "0.2.11" @@ -2130,21 +2572,15 @@ dependencies = [ [[package]] name = "regex" -version = "1.6.0" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" +checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" dependencies = [ - "aho-corasick 0.7.18", + "aho-corasick 0.7.20", "memchr", - "regex-syntax 0.6.27", + "regex-syntax 0.6.29", ] -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" - [[package]] name = "regex-syntax" version = "0.5.6" @@ -2156,9 +2592,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.27" +version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "remove_dir_all" @@ -2169,53 +2605,11 @@ dependencies = [ "winapi", ] -[[package]] -name = "revm" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b60030444003ac25474f5281e7e91f15e8475c173b729aac1c10aced56b3adac" -dependencies = [ - "arrayref", - "auto_impl", - "bytes", - "hashbrown 0.12.1", - "num_enum", - "primitive-types", - "revm_precompiles", - "rlp", - "sha3 0.10.1", -] - -[[package]] -name = "revm_precompiles" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd6aae8f44783ef6ff39fc22c9c999dfa0e17b79d663b752730c02a025935185" -dependencies = [ - "bytes", - "num 0.4.0", - "primitive-types", - "ripemd", - "secp256k1", - "sha2 0.10.2", - "sha3 0.10.1", - "substrate-bn", -] - -[[package]] -name = "ripemd" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1facec54cb5e0dc08553501fa740091086d0259ad0067e0d4103448e4cb22ed3" -dependencies = [ - "digest 0.10.3", -] - [[package]] name = "rlp" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "999508abb0ae792aabed2460c45b89106d97fe4adac593bdaef433c2605847b5" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" dependencies = [ "bytes", "rustc-hex", @@ -2223,9 +2617,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" +checksum = "d4a36c42d1873f9a77c53bde094f9664d9891bc604a45b4798fd2c389ed12e5b" [[package]] name = "rustc-hex" @@ -2242,11 +2636,31 @@ dependencies = [ "semver 0.11.0", ] +[[package]] +name = "rustix" +version = "0.37.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85597d61f83914ddeba6a47b3b8ffe7365107221c2e557ed94426489fefb5f77" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustversion" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" + [[package]] name = "ryu" -version = "1.0.10" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" [[package]] name = "same-file" @@ -2276,9 +2690,9 @@ dependencies = [ [[package]] name = "scoped-tls" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" [[package]] name = "scopeguard" @@ -2287,21 +2701,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] -name = "secp256k1" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26947345339603ae8395f68e2f3d85a6b0a8ddfe6315818e80b8504415099db0" -dependencies = [ - "secp256k1-sys", -] - -[[package]] -name = "secp256k1-sys" -version = "0.5.2" +name = "semolina" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "152e20a0fd0519390fc43ab404663af8a0b794273d2a91d60ad4a39f13ffe110" +checksum = "2b0111fd4fa831becb0606b9a2285ef3bee3c6a70d690209b8ae9514e9befe23" dependencies = [ "cc", + "glob 0.3.1", ] [[package]] @@ -2315,9 +2721,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.12" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" dependencies = [ "serde", ] @@ -2333,9 +2739,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.138" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1578c6245786b9d168c5447eeacfb96856573ca56c9d68fdcf394be134882a47" +checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" dependencies = [ "serde_derive", ] @@ -2352,37 +2758,36 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.138" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "023e9b1467aef8a10fb88f25611870ada9800ef7e22afce356bb0d2387b6f27c" +checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" dependencies = [ - "proc-macro2 1.0.40", - "quote 1.0.20", - "syn 1.0.98", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 2.0.15", ] [[package]] name = "serde_json" -version = "1.0.82" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" dependencies = [ "indexmap", - "itoa 1.0.2", + "itoa", "ryu", "serde", ] [[package]] -name = "sha-1" -version = "0.8.2" +name = "sha1" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" dependencies = [ - "block-buffer 0.7.3", - "digest 0.8.1", - "fake-simd", - "opaque-debug 0.2.3", + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.6", ] [[package]] @@ -2399,13 +2804,26 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.2" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "digest 0.10.3", + "digest 0.10.6", +] + +[[package]] +name = "sha3" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf" +dependencies = [ + "block-buffer 0.7.3", + "byte-tools", + "digest 0.8.1", + "keccak", + "opaque-debug 0.2.3", ] [[package]] @@ -2422,19 +2840,19 @@ dependencies = [ [[package]] name = "sha3" -version = "0.10.1" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "881bf8156c87b6301fc5ca6b27f11eeb2761224c7081e69b409d5a1951a70c86" +checksum = "54c2bb1a323307527314a36bfb73f24febb08ce2b8a554bf4ffd6f51ad15198c" dependencies = [ - "digest 0.10.3", + "digest 0.10.6", "keccak", ] [[package]] name = "single" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd5add732a1ab689845591a1b50339cf5310b563e08dc5813c65991f30369ea2" +checksum = "9db45bb685b486eec37e0271dcc0dac76eae5e893125f8a4f0511d0a1d29543b" dependencies = [ "failure", ] @@ -2448,7 +2866,7 @@ dependencies = [ "bytecount", "cargo_metadata", "error-chain 0.12.4", - "glob 0.3.0", + "glob 0.3.1", "pulldown-cmark", "tempfile", "walkdir", @@ -2456,17 +2874,11 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" - -[[package]] -name = "solc" -version = "0.1.0" -source = "git+https://github.com/g-r-a-n-t/solc-rust?rev=52d4146#52d414631bc6c3f0c29749503923a8d7e48b9f4d" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" dependencies = [ - "cmake", - "lazy_static", + "autocfg", ] [[package]] @@ -2475,6 +2887,25 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "sppark" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfb9486baeb35ca1197c4df27451d4df5bd321e15da94c1ddb89670f9e94896a" +dependencies = [ + "cc", + "which", +] + [[package]] name = "static_assertions" version = "1.1.0" @@ -2493,19 +2924,6 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" -[[package]] -name = "substrate-bn" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b5bbfa79abbae15dd642ea8176a21a635ff3c00059961d1ea27ad04e5b441c" -dependencies = [ - "byteorder", - "crunchy", - "lazy_static", - "rand 0.8.5", - "rustc-hex", -] - [[package]] name = "subtle" version = "1.0.0" @@ -2514,9 +2932,9 @@ checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" [[package]] name = "subtle" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "syn" @@ -2531,12 +2949,23 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.98" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" dependencies = [ - "proc-macro2 1.0.40", - "quote 1.0.20", + "proc-macro2 1.0.56", + "quote 1.0.26", "unicode-ident", ] @@ -2546,9 +2975,9 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baa8e7560a164edb1621a55d18a0c59abf49d360f47aa7b821061dd7eea7fac9" dependencies = [ - "proc-macro2 1.0.40", - "quote 1.0.20", - "syn 1.0.98", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", ] [[package]] @@ -2557,10 +2986,10 @@ version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ - "proc-macro2 1.0.40", - "quote 1.0.20", - "syn 1.0.98", - "unicode-xid 0.2.3", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", + "unicode-xid 0.2.4", ] [[package]] @@ -2581,23 +3010,22 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.3.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" dependencies = [ "cfg-if 1.0.0", "fastrand", - "libc", - "redox_syscall", - "remove_dir_all", - "winapi", + "redox_syscall 0.3.5", + "rustix", + "windows-sys 0.45.0", ] [[package]] name = "termcolor" -version = "1.1.3" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" dependencies = [ "winapi-util", ] @@ -2613,22 +3041,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.31" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.31" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ - "proc-macro2 1.0.40", - "quote 1.0.20", - "syn 1.0.98", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 2.0.15", ] [[package]] @@ -2640,6 +3068,15 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + [[package]] name = "tiny-keccak" version = "2.0.2" @@ -2651,18 +3088,18 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ "serde", ] [[package]] name = "tracing" -version = "0.1.35" +version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if 1.0.0", "pin-project-lite", @@ -2672,20 +3109,44 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" +checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" dependencies = [ - "proc-macro2 1.0.40", - "quote 1.0.20", - "syn 1.0.98", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", ] [[package]] name = "tracing-core" -version = "0.1.28" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-subscriber" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" +dependencies = [ + "tracing-core", +] + +[[package]] +name = "trait-set" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7" +checksum = "b79e2e9c9ab44c6d7c20d5976961b47e8f49ac199154daa514b77cd1ab536625" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", +] [[package]] name = "typed-arena" @@ -2695,27 +3156,27 @@ checksum = "a9b2228007eba4120145f785df0f6c92ea538f5a3635a612ecf4e334c8c1446d" [[package]] name = "typenum" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] name = "ucd-trie" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89570599c4fe5585de2b388aab47e99f7fa4e9238a1399f707a02e356058141c" +checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" [[package]] name = "ucd-util" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bfcbf611b122f2c10eb1bb6172fbc4c2e25df9970330e4d75ce2b5201c9bfc" +checksum = "abd2fc5d32b590614af8b0a20d837f32eca055edd0bbead59a9cfe80858be003" [[package]] name = "uint" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f03af7ccf01dd611cc450a0d10dbc9b745770d096473e2faf0ca6e2d66d1e0" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" dependencies = [ "byteorder", "crunchy", @@ -2734,21 +3195,21 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.1" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" [[package]] name = "unicode-segmentation" -version = "1.9.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" [[package]] name = "unicode-width" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" [[package]] name = "unicode-xid" @@ -2758,9 +3219,9 @@ checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" [[package]] name = "unicode-xid" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "utf8-ranges" @@ -2768,6 +3229,12 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcfc827f90e53a02eaef5e535ee14266c1d569214c6aa70133a624d8a3164ba" +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "vec_map" version = "0.8.2" @@ -2788,12 +3255,11 @@ checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" [[package]] name = "walkdir" -version = "2.3.2" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" dependencies = [ "same-file", - "winapi", "winapi-util", ] @@ -2824,9 +3290,9 @@ dependencies = [ "bumpalo", "lazy_static", "log", - "proc-macro2 1.0.40", - "quote 1.0.20", - "syn 1.0.98", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", "wasm-bindgen-shared", ] @@ -2848,7 +3314,7 @@ version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa" dependencies = [ - "quote 1.0.20", + "quote 1.0.26", "wasm-bindgen-macro-support", ] @@ -2858,9 +3324,9 @@ version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048" dependencies = [ - "proc-macro2 1.0.40", - "quote 1.0.20", - "syn 1.0.98", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2891,8 +3357,8 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88ad594bf33e73cafcac2ae9062fc119d4f75f9c77e25022f91c9a64bd5b6463" dependencies = [ - "proc-macro2 1.0.40", - "quote 1.0.20", + "proc-macro2 1.0.56", + "quote 1.0.26", ] [[package]] @@ -2905,6 +3371,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "which" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" +dependencies = [ + "either", + "libc", + "once_cell", +] + [[package]] name = "winapi" version = "0.3.9" @@ -2936,34 +3413,181 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + [[package]] name = "wyz" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b31594f29d27036c383b53b59ed3476874d518f0efb151b27a4c275141390e" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" dependencies = [ "tap", ] +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + +[[package]] +name = "yastl" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca6c5a4d66c1a9ea261811cf4773c27343de7e5033e1b75ea3f297dc7db3c1a" +dependencies = [ + "flume", + "scopeguard", +] + [[package]] name = "zeroize" -version = "1.5.6" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20b578acffd8516a6c3f2a1bdefc1ec37e547bb4e0fb8b6b01a4cafc886b4442" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" dependencies = [ "zeroize_derive", ] [[package]] name = "zeroize_derive" -version = "1.3.2" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ - "proc-macro2 1.0.40", - "quote 1.0.20", - "syn 1.0.98", - "synstructure", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 2.0.15", ] [[package]] @@ -2988,7 +3612,7 @@ dependencies = [ [[package]] name = "zokrates_abi" -version = "0.1.7" +version = "0.1.9" dependencies = [ "serde", "serde_derive", @@ -2999,30 +3623,26 @@ dependencies = [ [[package]] name = "zokrates_analysis" -version = "0.1.0" +version = "0.1.3" dependencies = [ "cfg-if 0.1.10", - "csv", "lazy_static", "log", - "num 0.1.42", + "num", "num-bigint 0.2.6", "pretty_assertions 0.6.1", - "reduce", "serde", "serde_json", - "typed-arena", "zokrates_ast", "zokrates_common", "zokrates_embed", "zokrates_field", - "zokrates_fs_resolver", "zokrates_pest_ast", ] [[package]] name = "zokrates_ark" -version = "0.1.1" +version = "0.1.4" dependencies = [ "ark-bls12-377", "ark-bn254", @@ -3049,11 +3669,11 @@ dependencies = [ [[package]] name = "zokrates_ast" -version = "0.1.3" +version = "0.1.7" dependencies = [ "ark-bls12-377", + "byteorder", "cfg-if 0.1.10", - "csv", "derivative", "num-bigint 0.2.6", "pairing_ce", @@ -3067,7 +3687,7 @@ dependencies = [ [[package]] name = "zokrates_bellman" -version = "0.1.0" +version = "0.1.3" dependencies = [ "bellman_ce", "getrandom", @@ -3075,28 +3695,48 @@ dependencies = [ "pairing_ce", "phase2", "rand 0.4.6", + "rand 0.8.5", "zokrates_ast", "zokrates_field", "zokrates_interpreter", "zokrates_proof_systems", ] +[[package]] +name = "zokrates_bellperson" +version = "0.1.0" +dependencies = [ + "bellperson", + "ff 0.13.0", + "getrandom", + "hex 0.4.3", + "nova-snark", + "pairing 0.22.0", + "pasta_curves", + "rand 0.4.6", + "serde", + "typed-arena", + "zokrates_ast", + "zokrates_core", + "zokrates_field", + "zokrates_interpreter", +] + [[package]] name = "zokrates_circom" -version = "0.1.1" +version = "0.1.4" dependencies = [ "bellman_ce", "byteorder", - "pretty_assertions 1.2.1", + "pretty_assertions 1.3.0", "zkutil", "zokrates_ast", - "zokrates_core", "zokrates_field", ] [[package]] name = "zokrates_cli" -version = "0.8.3" +version = "0.8.7" dependencies = [ "assert_cli", "blake2 0.8.1", @@ -3111,7 +3751,7 @@ dependencies = [ "hex 0.3.2", "lazy_static", "log", - "pretty_assertions 1.2.1", + "pretty_assertions 1.3.0", "primitive-types", "rand 0.4.6", "rand 0.8.5", @@ -3119,26 +3759,28 @@ dependencies = [ "serde", "serde_cbor", "serde_json", - "sha2 0.10.2", + "sha2 0.10.6", "tempdir", "typed-arena", "zokrates_abi", "zokrates_ark", "zokrates_ast", "zokrates_bellman", + "zokrates_bellperson", "zokrates_circom", "zokrates_common", "zokrates_core", + "zokrates_embed", "zokrates_field", "zokrates_fs_resolver", "zokrates_interpreter", + "zokrates_profiler", "zokrates_proof_systems", - "zokrates_solidity_test", ] [[package]] name = "zokrates_codegen" -version = "0.1.0" +version = "0.1.3" dependencies = [ "zokrates_ast", "zokrates_common", @@ -3149,22 +3791,20 @@ dependencies = [ [[package]] name = "zokrates_common" -version = "0.1.1" +version = "0.1.3" dependencies = [ "serde", ] [[package]] name = "zokrates_core" -version = "0.7.2" +version = "0.7.6" dependencies = [ "cfg-if 0.1.10", - "csv", "lazy_static", "log", - "num 0.1.42", + "num", "num-bigint 0.2.6", - "pretty_assertions 0.6.1", "serde", "serde_json", "typed-arena", @@ -3174,14 +3814,13 @@ dependencies = [ "zokrates_common", "zokrates_embed", "zokrates_field", - "zokrates_fs_resolver", "zokrates_interpreter", "zokrates_pest_ast", ] [[package]] name = "zokrates_core_test" -version = "0.2.9" +version = "0.2.11" dependencies = [ "zokrates_test", "zokrates_test_derive", @@ -3189,7 +3828,7 @@ dependencies = [ [[package]] name = "zokrates_embed" -version = "0.1.8" +version = "0.1.10" dependencies = [ "ark-bls12-377", "ark-bw6-761", @@ -3207,7 +3846,7 @@ dependencies = [ [[package]] name = "zokrates_field" -version = "0.5.2" +version = "0.5.5" dependencies = [ "ark-bls12-377", "ark-bls12-381", @@ -3215,13 +3854,20 @@ dependencies = [ "ark-bw6-761", "ark-ec", "ark-ff", + "ark-pallas", "ark-serialize", + "ark-vesta", "bellman_ce", - "bincode", + "bellperson", + "bincode 0.8.0", + "ff 0.13.0", "lazy_static", + "nova-snark", "num-bigint 0.2.6", "num-integer", "num-traits 0.2.15", + "pairing 0.22.0", + "pasta_curves", "rand 0.4.6", "serde", "serde_derive", @@ -3239,10 +3885,10 @@ dependencies = [ [[package]] name = "zokrates_interpreter" -version = "0.1.1" +version = "0.1.5" dependencies = [ "ark-bls12-377", - "num 0.1.42", + "num", "num-bigint 0.2.6", "pairing_ce", "serde", @@ -3255,13 +3901,15 @@ dependencies = [ [[package]] name = "zokrates_js" -version = "1.1.4" +version = "1.1.8" dependencies = [ "console_error_panic_hook", + "getrandom", "indexmap", "js-sys", "json", "lazy_static", + "rand 0.8.5", "serde", "serde_json", "toml", @@ -3275,6 +3923,7 @@ dependencies = [ "zokrates_circom", "zokrates_common", "zokrates_core", + "zokrates_embed", "zokrates_field", "zokrates_interpreter", "zokrates_proof_systems", @@ -3282,7 +3931,7 @@ dependencies = [ [[package]] name = "zokrates_parser" -version = "0.3.2" +version = "0.3.5" dependencies = [ "glob 0.2.11", "pest", @@ -3291,7 +3940,7 @@ dependencies = [ [[package]] name = "zokrates_pest_ast" -version = "0.3.0" +version = "0.3.3" dependencies = [ "from-pest", "glob 0.2.11", @@ -3302,33 +3951,27 @@ dependencies = [ ] [[package]] -name = "zokrates_proof_systems" +name = "zokrates_profiler" version = "0.1.0" dependencies = [ - "cfg-if 0.1.10", - "ethabi", - "getrandom", - "hex 0.4.3", - "primitive-types", - "rand 0.4.6", - "regex 0.2.11", - "serde", "zokrates_ast", - "zokrates_field", ] [[package]] -name = "zokrates_solidity_test" -version = "0.1.1" +name = "zokrates_proof_systems" +version = "0.1.3" dependencies = [ - "bytes", + "blake2 0.8.1", + "byteorder", + "cfg-if 0.1.10", "ethabi", "hex 0.4.3", "primitive-types", "rand 0.8.5", - "revm", - "serde_json", - "solc", + "regex 0.2.11", + "serde", + "zokrates_ast", + "zokrates_field", ] [[package]] @@ -3342,8 +3985,10 @@ dependencies = [ [[package]] name = "zokrates_test" -version = "0.2.0" +version = "0.2.3" dependencies = [ + "getrandom", + "rand 0.8.5", "serde", "serde_derive", "serde_json", @@ -3362,7 +4007,7 @@ dependencies = [ [[package]] name = "zokrates_test_derive" -version = "0.0.1" +version = "0.0.2" dependencies = [ - "glob 0.3.0", + "glob 0.3.1", ] diff --git a/Cargo.toml b/Cargo.toml index 8c5b23352..81d2c241e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] - +resolver = "2" members = [ "zokrates_common", "zokrates_core", @@ -12,15 +12,17 @@ members = [ "zokrates_abi", "zokrates_test", "zokrates_core_test", - "zokrates_solidity_test", "zokrates_ark", "zokrates_ast", "zokrates_interpreter", "zokrates_embed", "zokrates_bellman", + "zokrates_bellperson", "zokrates_proof_systems", "zokrates_js", - "zokrates_circom" + "zokrates_circom", + "zokrates_profiler", ] -exclude = [] \ No newline at end of file +[profile.dev] +opt-level = 1 \ No newline at end of file diff --git a/changelogs/unreleased/1228-schaeff b/changelogs/unreleased/1228-schaeff deleted file mode 100644 index 0727702e4..000000000 --- a/changelogs/unreleased/1228-schaeff +++ /dev/null @@ -1 +0,0 @@ -Reduce cost of boolean array equality checks \ No newline at end of file diff --git a/changelogs/unreleased/1232-dark64 b/changelogs/unreleased/1232-dark64 deleted file mode 100644 index 86c554b4d..000000000 --- a/changelogs/unreleased/1232-dark64 +++ /dev/null @@ -1 +0,0 @@ -Loosen up whitespace restrictions to allow more formatting styles \ No newline at end of file diff --git a/changelogs/unreleased/1246-dark64 b/changelogs/unreleased/1246-dark64 deleted file mode 100644 index 6c45d9a10..000000000 --- a/changelogs/unreleased/1246-dark64 +++ /dev/null @@ -1 +0,0 @@ -Introduce constraint generation through assembly blocks \ No newline at end of file diff --git a/changelogs/unreleased/1313-schaeff b/changelogs/unreleased/1313-schaeff new file mode 100644 index 000000000..81fc1ab2a --- /dev/null +++ b/changelogs/unreleased/1313-schaeff @@ -0,0 +1 @@ +Propagate embed call \ No newline at end of file diff --git a/changelogs/unreleased/1315-schaeff b/changelogs/unreleased/1315-schaeff new file mode 100644 index 000000000..004bc45d1 --- /dev/null +++ b/changelogs/unreleased/1315-schaeff @@ -0,0 +1 @@ +Short-circuit on compile-time constant branch conditions \ No newline at end of file diff --git a/changelogs/unreleased/1317-dark64 b/changelogs/unreleased/1317-dark64 new file mode 100644 index 000000000..c55916170 --- /dev/null +++ b/changelogs/unreleased/1317-dark64 @@ -0,0 +1 @@ +Fix invalid constant in mimc7 diff --git a/changelogs/unreleased/1318-dark64 b/changelogs/unreleased/1318-dark64 new file mode 100644 index 000000000..9efd21301 --- /dev/null +++ b/changelogs/unreleased/1318-dark64 @@ -0,0 +1 @@ +Allow composite type in assembly assignment statement \ No newline at end of file diff --git a/changelogs/unreleased/1326-dark64 b/changelogs/unreleased/1326-dark64 new file mode 100644 index 000000000..46fb945fd --- /dev/null +++ b/changelogs/unreleased/1326-dark64 @@ -0,0 +1 @@ +Detect division by zero on compile-time \ No newline at end of file diff --git a/clippy.toml b/clippy.toml deleted file mode 100644 index 3f707a567..000000000 --- a/clippy.toml +++ /dev/null @@ -1 +0,0 @@ -blacklisted-names = [] \ No newline at end of file diff --git a/dev.Dockerfile b/dev.Dockerfile index 267cf436a..bcb73b0d8 100644 --- a/dev.Dockerfile +++ b/dev.Dockerfile @@ -1,11 +1,9 @@ -FROM rustlang/rust:nightly - -MAINTAINER JacobEberhardt , Thibaut Schaeffer +FROM rust:latest RUN useradd -u 1000 -m zokrates -COPY ./scripts/install_solcjs_deb.sh /tmp/ -RUN /tmp/install_solcjs_deb.sh +COPY ./scripts/install_foundry.sh /tmp/ +RUN /tmp/install_foundry.sh USER zokrates diff --git a/integration_test.sh b/integration_test.sh index 8bee95467..229c98944 100755 --- a/integration_test.sh +++ b/integration_test.sh @@ -2,5 +2,4 @@ # Exit if any subcommand fails set -e - cargo test -j 4 --release --package zokrates_cli -- --ignored \ No newline at end of file diff --git a/rust-toolchain.toml b/rust-toolchain.toml index cbfe2704f..292fe499e 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "nightly-2022-07-01" +channel = "stable" diff --git a/scripts/install_foundry.sh b/scripts/install_foundry.sh new file mode 100755 index 000000000..426caddaf --- /dev/null +++ b/scripts/install_foundry.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +apt-get update -y +apt-get install -y curl gnupg sudo build-essential git +curl -L https://foundry.paradigm.xyz | bash +$HOME/.foundry/bin/foundryup \ No newline at end of file diff --git a/scripts/install_solcjs_deb.sh b/scripts/install_solcjs_deb.sh deleted file mode 100755 index edca332a0..000000000 --- a/scripts/install_solcjs_deb.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -apt-get update -y -apt-get install -y curl gnupg sudo build-essential git -curl -sL https://deb.nodesource.com/setup_16.x | bash - -apt-get install -y nodejs -npm i -g solc \ No newline at end of file diff --git a/zokrates_abi/Cargo.toml b/zokrates_abi/Cargo.toml index 953aa53f9..967ff018b 100644 --- a/zokrates_abi/Cargo.toml +++ b/zokrates_abi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zokrates_abi" -version = "0.1.7" +version = "0.1.9" authors = ["Thibaut Schaeffer "] edition = "2018" diff --git a/zokrates_abi/src/lib.rs b/zokrates_abi/src/lib.rs index a85adb219..2f92063cb 100644 --- a/zokrates_abi/src/lib.rs +++ b/zokrates_abi/src/lib.rs @@ -1,5 +1,3 @@ -#![feature(box_patterns, box_syntax)] - pub enum Inputs { Raw(Vec), Abi(Values), @@ -240,7 +238,7 @@ impl Values { } } -fn parse_value( +pub fn parse_value( value: serde_json::Value, expected_type: ConcreteType, ) -> Result, Error> { diff --git a/zokrates_analysis/Cargo.toml b/zokrates_analysis/Cargo.toml index e347abcdf..1a55312a8 100644 --- a/zokrates_analysis/Cargo.toml +++ b/zokrates_analysis/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zokrates_analysis" -version = "0.1.0" +version = "0.1.3" edition = "2021" [features] @@ -14,8 +14,6 @@ cfg-if = "0.1" num = { version = "0.1.36", default-features = false } num-bigint = { version = "0.2", default-features = false } lazy_static = "1.4" -typed-arena = "1.4.1" -reduce = "0.1.1" # serialization and deserialization serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0", features = ["preserve_order"] } @@ -24,8 +22,6 @@ zokrates_pest_ast = { version = "0.3.0", path = "../zokrates_pest_ast" } zokrates_common = { version = "0.1", path = "../zokrates_common", default-features = false } zokrates_embed = { version = "0.1.0", path = "../zokrates_embed", default-features = false } zokrates_ast = { version = "0.1", path = "../zokrates_ast", default-features = false } -csv = "1" [dev-dependencies] -pretty_assertions = "0.6.1" -zokrates_fs_resolver = { version = "0.5", path = "../zokrates_fs_resolver"} \ No newline at end of file +pretty_assertions = "0.6.1" \ No newline at end of file diff --git a/zokrates_analysis/src/assembly_transformer.rs b/zokrates_analysis/src/assembly_transformer.rs index 7c8e856e0..446f4c8f6 100644 --- a/zokrates_analysis/src/assembly_transformer.rs +++ b/zokrates_analysis/src/assembly_transformer.rs @@ -3,9 +3,13 @@ use crate::ZirPropagator; use std::fmt; +use std::ops::*; use zokrates_ast::zir::lqc::LinQuadComb; use zokrates_ast::zir::result_folder::ResultFolder; -use zokrates_ast::zir::{FieldElementExpression, Id, Identifier, ZirAssemblyStatement, ZirProgram}; +use zokrates_ast::zir::AssemblyConstraint; +use zokrates_ast::zir::{ + Expr, FieldElementExpression, Id, Identifier, ZirAssemblyStatement, ZirProgram, +}; use zokrates_field::Field; #[derive(Debug)] @@ -28,143 +32,132 @@ impl AssemblyTransformer { impl<'ast, T: Field> ResultFolder<'ast, T> for AssemblyTransformer { type Error = Error; - fn fold_assembly_statement( + fn fold_assembly_constraint( &mut self, - s: ZirAssemblyStatement<'ast, T>, + s: AssemblyConstraint<'ast, T>, ) -> Result>, Self::Error> { - match s { - ZirAssemblyStatement::Assignment(_, _) => Ok(vec![s]), - ZirAssemblyStatement::Constraint(lhs, rhs, metadata) => { - let lhs = self.fold_field_expression(lhs)?; - let rhs = self.fold_field_expression(rhs)?; - - let (is_quadratic, lhs, rhs) = match (lhs, rhs) { - ( - lhs @ FieldElementExpression::Identifier(..), - rhs @ FieldElementExpression::Identifier(..), - ) => (true, lhs, rhs), - (FieldElementExpression::Mult(x, y), other) - | (other, FieldElementExpression::Mult(x, y)) - if other.is_linear() => - { - ( - x.is_linear() && y.is_linear(), - other, - FieldElementExpression::Mult(x, y), + let lhs = self.fold_field_expression(s.left)?; + let rhs = self.fold_field_expression(s.right)?; + + let (is_quadratic, lhs, rhs) = match (lhs, rhs) { + ( + lhs @ FieldElementExpression::Identifier(..), + rhs @ FieldElementExpression::Identifier(..), + ) => (true, lhs, rhs), + (FieldElementExpression::Mult(e), other) | (other, FieldElementExpression::Mult(e)) + if other.is_linear() => + { + ( + e.left.is_linear() && e.right.is_linear(), + other, + FieldElementExpression::Mult(e), + ) + } + (lhs, rhs) => (false, lhs, rhs), + }; + + match is_quadratic { + true => Ok(vec![ZirAssemblyStatement::constraint(lhs, rhs, s.metadata)]), + false => { + let sub = FieldElementExpression::sub(lhs, rhs); + let mut lqc = LinQuadComb::try_from(sub.clone()) + .map_err(|_| Error("Non-quadratic constraints are not allowed".to_string()))?; + + let linear = lqc + .linear + .into_iter() + .map(|(c, i)| { + FieldElementExpression::mul( + FieldElementExpression::value(c), + FieldElementExpression::identifier(i), ) - } - (lhs, rhs) => (false, lhs, rhs), - }; - - match is_quadratic { - true => Ok(vec![ZirAssemblyStatement::Constraint(lhs, rhs, metadata)]), - false => { - let sub = FieldElementExpression::Sub(box lhs, box rhs); - let mut lqc = LinQuadComb::try_from(sub.clone()).map_err(|_| { - Error("Non-quadratic constraints are not allowed".to_string()) - })?; - - let linear = lqc - .linear - .into_iter() - .map(|(c, i)| { - FieldElementExpression::Mult( - box FieldElementExpression::Number(c), - box FieldElementExpression::identifier(i), - ) - }) - .fold(FieldElementExpression::Number(T::from(0)), |acc, e| { - FieldElementExpression::Add(box acc, box e) - }); - - let lhs = FieldElementExpression::Add( - box FieldElementExpression::Number(lqc.constant), - box linear, - ); - - let rhs: FieldElementExpression<'ast, T> = if lqc.quadratic.len() > 1 { - let common_factor = lqc - .quadratic - .iter() - .scan(None, |state: &mut Option>, (_, a, b)| { - // short circuit if we do not have any common factors anymore - if *state == Some(vec![]) { - None - } else { - match state { - // only keep factors found in this term - Some(factors) => { - factors.retain(|&x| x == a || x == b); - } - // initialisation step, start with the two factors in the first term - None => { - *state = Some(vec![a, b]); - } - }; - state.clone() + }) + .fold(FieldElementExpression::value(T::from(0)), |acc, e| { + FieldElementExpression::add(acc, e) + }); + + let lhs = FieldElementExpression::add( + FieldElementExpression::value(lqc.constant), + linear, + ); + + let rhs: FieldElementExpression<'ast, T> = if lqc.quadratic.len() > 1 { + let common_factor = lqc + .quadratic + .iter() + .scan(None, |state: &mut Option>, (_, a, b)| { + // short circuit if we do not have any common factors anymore + if *state == Some(vec![]) { + None + } else { + match state { + // only keep factors found in this term + Some(factors) => { + factors.retain(|&x| x == a || x == b); } - }) - .last() - .and_then(|mut v| v.pop().cloned()); - - match common_factor { - Some(factor) => Ok(FieldElementExpression::Mult( - box lqc - .quadratic - .into_iter() - .map(|(c, i0, i1)| { - let c = T::zero() - c; - let e = match (i0, i1) { - (i0, i1) if factor.eq(&i0) => { - FieldElementExpression::identifier(i1) - } - (i0, i1) if factor.eq(&i1) => { - FieldElementExpression::identifier(i0) - } - _ => unreachable!(), - }; - FieldElementExpression::Mult( - box FieldElementExpression::Number(c), - box e, - ) - }) - .fold( - FieldElementExpression::Number(T::from(0)), - |acc, e| FieldElementExpression::Add(box acc, box e), - ), - box FieldElementExpression::identifier(factor), - )), - None => Err(Error( - "Non-quadratic constraints are not allowed".to_string(), - )), - }? - } else { + // initialisation step, start with the two factors in the first term + None => { + *state = Some(vec![a, b]); + } + }; + state.clone() + } + }) + .last() + .and_then(|mut v| v.pop().cloned()); + + match common_factor { + Some(factor) => Ok(FieldElementExpression::mul( lqc.quadratic - .pop() + .into_iter() .map(|(c, i0, i1)| { - FieldElementExpression::Mult( - box FieldElementExpression::Mult( - box FieldElementExpression::Number(T::zero() - c), - box FieldElementExpression::identifier(i0), - ), - box FieldElementExpression::identifier(i1), - ) + let c = T::zero() - c; + let e = match (i0, i1) { + (i0, i1) if factor.eq(&i0) => { + FieldElementExpression::identifier(i1) + } + (i0, i1) if factor.eq(&i1) => { + FieldElementExpression::identifier(i0) + } + _ => unreachable!(), + }; + FieldElementExpression::mul(FieldElementExpression::value(c), e) }) - .unwrap_or_else(|| FieldElementExpression::Number(T::from(0))) - }; + .fold( + FieldElementExpression::value(T::from(0)), + FieldElementExpression::add, + ), + FieldElementExpression::identifier(factor), + )), + None => Err(Error( + "Non-quadratic constraints are not allowed".to_string(), + )), + }? + } else { + lqc.quadratic + .pop() + .map(|(c, i0, i1)| { + FieldElementExpression::mul( + FieldElementExpression::mul( + FieldElementExpression::value(T::zero() - c), + FieldElementExpression::identifier(i0), + ), + FieldElementExpression::identifier(i1), + ) + }) + .unwrap_or_else(|| FieldElementExpression::value(T::from(0))) + }; - let mut propagator = ZirPropagator::default(); - let lhs = propagator - .fold_field_expression(lhs) - .map_err(|e| Error(e.to_string()))?; + let mut propagator = ZirPropagator::default(); + let lhs = propagator + .fold_field_expression(lhs) + .map_err(|e| Error(e.to_string()))?; - let rhs = propagator - .fold_field_expression(rhs) - .map_err(|e| Error(e.to_string()))?; + let rhs = propagator + .fold_field_expression(rhs) + .map_err(|e| Error(e.to_string()))?; - Ok(vec![ZirAssemblyStatement::Constraint(lhs, rhs, metadata)]) - } - } + Ok(vec![ZirAssemblyStatement::constraint(lhs, rhs, s.metadata)]) } } } @@ -180,21 +173,21 @@ mod tests { fn quadratic() { // x === a * b; let lhs = FieldElementExpression::::identifier("x".into()); - let rhs = FieldElementExpression::Mult( - box FieldElementExpression::identifier("a".into()), - box FieldElementExpression::identifier("b".into()), + let rhs = FieldElementExpression::mul( + FieldElementExpression::identifier("a".into()), + FieldElementExpression::identifier("b".into()), ); - let expected = vec![ZirAssemblyStatement::Constraint( + let expected = vec![ZirAssemblyStatement::constraint( FieldElementExpression::identifier("x".into()), - FieldElementExpression::Mult( - box FieldElementExpression::identifier("a".into()), - box FieldElementExpression::identifier("b".into()), + FieldElementExpression::mul( + FieldElementExpression::identifier("a".into()), + FieldElementExpression::identifier("b".into()), ), SourceMetadata::default(), )]; let result = AssemblyTransformer - .fold_assembly_statement(ZirAssemblyStatement::Constraint( + .fold_assembly_statement(ZirAssemblyStatement::constraint( lhs, rhs, SourceMetadata::default(), @@ -208,15 +201,15 @@ mod tests { fn non_quadratic() { // x === ((a * b) * c); let lhs = FieldElementExpression::::identifier("x".into()); - let rhs = FieldElementExpression::Mult( - box FieldElementExpression::Mult( - box FieldElementExpression::identifier("a".into()), - box FieldElementExpression::identifier("b".into()), + let rhs = FieldElementExpression::mul( + FieldElementExpression::mul( + FieldElementExpression::identifier("a".into()), + FieldElementExpression::identifier("b".into()), ), - box FieldElementExpression::identifier("c".into()), + FieldElementExpression::identifier("c".into()), ); - let result = AssemblyTransformer.fold_assembly_statement(ZirAssemblyStatement::Constraint( + let result = AssemblyTransformer.fold_assembly_statement(ZirAssemblyStatement::constraint( lhs, rhs, SourceMetadata::default(), @@ -229,31 +222,31 @@ mod tests { fn transform() { // x === 1 - a * b; --> (-1) + x === (((-1) * a) * b); let lhs = FieldElementExpression::identifier("x".into()); - let rhs = FieldElementExpression::Sub( - box FieldElementExpression::Number(Bn128Field::from(1)), - box FieldElementExpression::Mult( - box FieldElementExpression::identifier("a".into()), - box FieldElementExpression::identifier("b".into()), + let rhs = FieldElementExpression::sub( + FieldElementExpression::value(Bn128Field::from(1)), + FieldElementExpression::mul( + FieldElementExpression::identifier("a".into()), + FieldElementExpression::identifier("b".into()), ), ); - let expected = vec![ZirAssemblyStatement::Constraint( - FieldElementExpression::Add( - box FieldElementExpression::Number(Bn128Field::from(-1)), - box FieldElementExpression::identifier("x".into()), + let expected = vec![ZirAssemblyStatement::constraint( + FieldElementExpression::add( + FieldElementExpression::value(Bn128Field::from(-1)), + FieldElementExpression::identifier("x".into()), ), - FieldElementExpression::Mult( - box FieldElementExpression::Mult( - box FieldElementExpression::Number(Bn128Field::from(-1)), - box FieldElementExpression::identifier("a".into()), + FieldElementExpression::mul( + FieldElementExpression::mul( + FieldElementExpression::value(Bn128Field::from(-1)), + FieldElementExpression::identifier("a".into()), ), - box FieldElementExpression::identifier("b".into()), + FieldElementExpression::identifier("b".into()), ), SourceMetadata::default(), )]; let result = AssemblyTransformer - .fold_assembly_statement(ZirAssemblyStatement::Constraint( + .fold_assembly_statement(ZirAssemblyStatement::constraint( lhs, rhs, SourceMetadata::default(), @@ -267,30 +260,30 @@ mod tests { fn factorize() { // x === (a * b) + (b * c); --> x === ((a + c) * b); let lhs = FieldElementExpression::::identifier("x".into()); - let rhs = FieldElementExpression::Add( - box FieldElementExpression::Mult( - box FieldElementExpression::identifier("a".into()), - box FieldElementExpression::identifier("b".into()), + let rhs = FieldElementExpression::add( + FieldElementExpression::mul( + FieldElementExpression::identifier("a".into()), + FieldElementExpression::identifier("b".into()), ), - box FieldElementExpression::Mult( - box FieldElementExpression::identifier("b".into()), - box FieldElementExpression::identifier("c".into()), + FieldElementExpression::mul( + FieldElementExpression::identifier("b".into()), + FieldElementExpression::identifier("c".into()), ), ); - let expected = vec![ZirAssemblyStatement::Constraint( + let expected = vec![ZirAssemblyStatement::constraint( FieldElementExpression::identifier("x".into()), - FieldElementExpression::Mult( - box FieldElementExpression::Add( - box FieldElementExpression::identifier("a".into()), - box FieldElementExpression::identifier("c".into()), + FieldElementExpression::mul( + FieldElementExpression::add( + FieldElementExpression::identifier("a".into()), + FieldElementExpression::identifier("c".into()), ), - box FieldElementExpression::identifier("b".into()), + FieldElementExpression::identifier("b".into()), ), SourceMetadata::default(), )]; let result = AssemblyTransformer - .fold_assembly_statement(ZirAssemblyStatement::Constraint( + .fold_assembly_statement(ZirAssemblyStatement::constraint( lhs, rhs, SourceMetadata::default(), @@ -307,100 +300,100 @@ mod tests { // --> // ((((x + ((-1)*a)) + ((-1)*b)) + ((-1)*c)) + (2*mid)) === (((((-2)*b) + ((-2)*c)) + (4*mid)) * a); let lhs = FieldElementExpression::::identifier("x".into()); - let rhs = FieldElementExpression::Add( - box FieldElementExpression::Sub( - box FieldElementExpression::Sub( - box FieldElementExpression::Sub( - box FieldElementExpression::Add( - box FieldElementExpression::Add( - box FieldElementExpression::identifier("a".into()), - box FieldElementExpression::identifier("b".into()), + let rhs = FieldElementExpression::add( + FieldElementExpression::sub( + FieldElementExpression::sub( + FieldElementExpression::sub( + FieldElementExpression::add( + FieldElementExpression::add( + FieldElementExpression::identifier("a".into()), + FieldElementExpression::identifier("b".into()), ), - box FieldElementExpression::identifier("c".into()), + FieldElementExpression::identifier("c".into()), ), - box FieldElementExpression::Mult( - box FieldElementExpression::Mult( - box FieldElementExpression::Number(Bn128Field::from(2)), - box FieldElementExpression::identifier("a".into()), + FieldElementExpression::mul( + FieldElementExpression::mul( + FieldElementExpression::value(Bn128Field::from(2)), + FieldElementExpression::identifier("a".into()), ), - box FieldElementExpression::identifier("b".into()), + FieldElementExpression::identifier("b".into()), ), ), - box FieldElementExpression::Mult( - box FieldElementExpression::Mult( - box FieldElementExpression::Number(Bn128Field::from(2)), - box FieldElementExpression::identifier("a".into()), + FieldElementExpression::mul( + FieldElementExpression::mul( + FieldElementExpression::value(Bn128Field::from(2)), + FieldElementExpression::identifier("a".into()), ), - box FieldElementExpression::identifier("c".into()), + FieldElementExpression::identifier("c".into()), ), ), - box FieldElementExpression::Mult( - box FieldElementExpression::Number(Bn128Field::from(2)), - box FieldElementExpression::identifier("mid".into()), + FieldElementExpression::mul( + FieldElementExpression::value(Bn128Field::from(2)), + FieldElementExpression::identifier("mid".into()), ), ), - box FieldElementExpression::Mult( - box FieldElementExpression::Mult( - box FieldElementExpression::Number(Bn128Field::from(4)), - box FieldElementExpression::identifier("a".into()), + FieldElementExpression::mul( + FieldElementExpression::mul( + FieldElementExpression::value(Bn128Field::from(4)), + FieldElementExpression::identifier("a".into()), ), - box FieldElementExpression::identifier("mid".into()), + FieldElementExpression::identifier("mid".into()), ), ); - let lhs_expected = FieldElementExpression::Add( - box FieldElementExpression::Add( - box FieldElementExpression::Add( - box FieldElementExpression::Add( - box FieldElementExpression::identifier("x".into()), - box FieldElementExpression::Mult( - box FieldElementExpression::Number(Bn128Field::from(-1)), - box FieldElementExpression::identifier("a".into()), + let lhs_expected = FieldElementExpression::add( + FieldElementExpression::add( + FieldElementExpression::add( + FieldElementExpression::add( + FieldElementExpression::identifier("x".into()), + FieldElementExpression::mul( + FieldElementExpression::value(Bn128Field::from(-1)), + FieldElementExpression::identifier("a".into()), ), ), - box FieldElementExpression::Mult( - box FieldElementExpression::Number(Bn128Field::from(-1)), - box FieldElementExpression::identifier("b".into()), + FieldElementExpression::mul( + FieldElementExpression::value(Bn128Field::from(-1)), + FieldElementExpression::identifier("b".into()), ), ), - box FieldElementExpression::Mult( - box FieldElementExpression::Number(Bn128Field::from(-1)), - box FieldElementExpression::identifier("c".into()), + FieldElementExpression::mul( + FieldElementExpression::value(Bn128Field::from(-1)), + FieldElementExpression::identifier("c".into()), ), ), - box FieldElementExpression::Mult( - box FieldElementExpression::Number(Bn128Field::from(2)), - box FieldElementExpression::identifier("mid".into()), + FieldElementExpression::mul( + FieldElementExpression::value(Bn128Field::from(2)), + FieldElementExpression::identifier("mid".into()), ), ); - let rhs_expected = FieldElementExpression::Mult( - box FieldElementExpression::Add( - box FieldElementExpression::Add( - box FieldElementExpression::Mult( - box FieldElementExpression::Number(Bn128Field::from(-2)), - box FieldElementExpression::identifier("b".into()), + let rhs_expected = FieldElementExpression::mul( + FieldElementExpression::add( + FieldElementExpression::add( + FieldElementExpression::mul( + FieldElementExpression::value(Bn128Field::from(-2)), + FieldElementExpression::identifier("b".into()), ), - box FieldElementExpression::Mult( - box FieldElementExpression::Number(Bn128Field::from(-2)), - box FieldElementExpression::identifier("c".into()), + FieldElementExpression::mul( + FieldElementExpression::value(Bn128Field::from(-2)), + FieldElementExpression::identifier("c".into()), ), ), - box FieldElementExpression::Mult( - box FieldElementExpression::Number(Bn128Field::from(4)), - box FieldElementExpression::identifier("mid".into()), + FieldElementExpression::mul( + FieldElementExpression::value(Bn128Field::from(4)), + FieldElementExpression::identifier("mid".into()), ), ), - box FieldElementExpression::identifier("a".into()), + FieldElementExpression::identifier("a".into()), ); - let expected = vec![ZirAssemblyStatement::Constraint( + let expected = vec![ZirAssemblyStatement::constraint( lhs_expected, rhs_expected, SourceMetadata::default(), )]; let result = AssemblyTransformer - .fold_assembly_statement(ZirAssemblyStatement::Constraint( + .fold_assembly_statement(ZirAssemblyStatement::constraint( lhs, rhs, SourceMetadata::default(), diff --git a/zokrates_analysis/src/boolean_array_comparator.rs b/zokrates_analysis/src/boolean_array_comparator.rs index cb016c034..72c158193 100644 --- a/zokrates_analysis/src/boolean_array_comparator.rs +++ b/zokrates_analysis/src/boolean_array_comparator.rs @@ -1,10 +1,22 @@ -use zokrates_ast::typed::{ - folder::*, ArrayExpressionInner, ArrayValue, BooleanExpression, ConditionalExpression, - ConditionalKind, EqExpression, FieldElementExpression, SelectExpression, Type, TypedExpression, - TypedProgram, UExpressionInner, +use zokrates_ast::{ + common::WithSpan, + typed::{ + folder::*, ArrayExpression, ArrayType, BooleanExpression, Conditional, ConditionalKind, + Expr, FieldElementExpression, Select, Type, TypedExpression, TypedProgram, UExpression, + UExpressionInner, + }, }; + use zokrates_field::Field; +fn sum_rec + Clone>(a: &[T], default: &T) -> T { + match a.len() { + 0 => default.clone(), + 1 => a[0].clone(), + n => sum_rec(&a[..n / 2], default) + sum_rec(&a[n / 2..], default), + } +} + #[derive(Default)] pub struct BooleanArrayComparator; @@ -15,73 +27,57 @@ impl BooleanArrayComparator { } impl<'ast, T: Field> Folder<'ast, T> for BooleanArrayComparator { - fn fold_boolean_expression( + fn fold_boolean_expression_cases( &mut self, e: BooleanExpression<'ast, T>, ) -> BooleanExpression<'ast, T> { match e { - BooleanExpression::ArrayEq(e) => match e.left.inner_type() { + BooleanExpression::ArrayEq(e) => match *e.left.inner_type() { Type::Boolean => { + let span = e.get_span(); + let len = e.left.size(); let len = match len.as_inner() { - UExpressionInner::Value(v) => *v as usize, + UExpressionInner::Value(v) => v.value as usize, _ => unreachable!("array size should be known"), }; - let chunk_size = T::get_required_bits() as usize - 1; + let chunk_size = T::get_required_bits() - 1; let left_elements: Vec<_> = (0..len) - .map(|i| { - BooleanExpression::Select(SelectExpression::new( - *e.left.clone(), - (i as u32).into(), - )) - }) + .map(|i| BooleanExpression::select(*e.left.clone(), i as u32).span(span)) .collect(); let right_elements: Vec<_> = (0..len) - .map(|i| { - BooleanExpression::Select(SelectExpression::new( - *e.right.clone(), - (i as u32).into(), - )) - }) + .map(|i| BooleanExpression::select(*e.right.clone(), i as u32).span(span)) .collect(); let process = |elements: &[BooleanExpression<'ast, T>]| { elements .chunks(chunk_size) .map(|chunk| { - TypedExpression::from( - chunk + TypedExpression::from(sum_rec( + &chunk .iter() .rev() .enumerate() .rev() .map(|(index, c)| { - FieldElementExpression::Conditional( - ConditionalExpression::new( - c.clone(), - FieldElementExpression::Pow( - box FieldElementExpression::Number( - T::from(2), - ), - box (index as u32).into(), - ), - T::zero().into(), - ConditionalKind::Ternary, + FieldElementExpression::conditional( + c.clone().span(span), + FieldElementExpression::pow( + FieldElementExpression::value(T::from(2)) + .span(span), + UExpression::from(index as u32).span(span), ), + FieldElementExpression::from(T::zero()).span(span), + ConditionalKind::Ternary, ) + .span(span) }) - .fold(None, |acc, e| match acc { - Some(acc) => { - Some(FieldElementExpression::Add(box acc, box e)) - } - None => Some(e), - }) - .unwrap_or_else(|| { - FieldElementExpression::Number(T::zero()) - }), - ) + .collect::>(), + &FieldElementExpression::value(T::from(0)).span(span), + )) + .span(span) .into() }) .collect() @@ -93,23 +89,28 @@ impl<'ast, T: Field> Folder<'ast, T> for BooleanArrayComparator { let chunk_count = left.len(); - BooleanExpression::ArrayEq(EqExpression::new( - ArrayExpressionInner::Value(ArrayValue(left)) - .annotate(Type::FieldElement, chunk_count as u32), - ArrayExpressionInner::Value(ArrayValue(right)) - .annotate(Type::FieldElement, chunk_count as u32), - )) + BooleanExpression::array_eq( + ArrayExpression::value(left) + .annotate(ArrayType::new(Type::FieldElement, chunk_count as u32)) + .span(span), + ArrayExpression::value(right) + .annotate(ArrayType::new(Type::FieldElement, chunk_count as u32)) + .span(span), + ) } - _ => fold_boolean_expression(self, BooleanExpression::ArrayEq(e)), + _ => fold_boolean_expression_cases(self, BooleanExpression::ArrayEq(e)), }, - e => fold_boolean_expression(self, e), + e => fold_boolean_expression_cases(self, e), } } } #[cfg(test)] mod tests { - use zokrates_ast::typed::{BooleanExpression, EqExpression, Type}; + use zokrates_ast::{ + common::expressions::BinaryExpression, + typed::{BooleanExpression, Type}, + }; use zokrates_field::DummyCurveField; use zokrates_ast::typed::utils::{a, a_id, conditional, f, select, u_32}; @@ -123,13 +124,13 @@ mod tests { // [x[0] ? 2**1 : 0 + x[1] ? 2**0 : 0] == [y[0] ? 2**1 : 0 + y[1] ? 2**0 : 0] // a single field is sufficient, as the prime we're working with is 3 bits long, so we can pack up to 2 bits - let x = a_id("x").annotate(Type::Boolean, 2u32); - let y = a_id("y").annotate(Type::Boolean, 2u32); + let x = a_id("x").annotate(ArrayType::new(Type::Boolean, 2u32)); + let y = a_id("y").annotate(ArrayType::new(Type::Boolean, 2u32)); let e: BooleanExpression = - BooleanExpression::ArrayEq(EqExpression::new(x.clone(), y.clone())); + BooleanExpression::ArrayEq(BinaryExpression::new(x.clone(), y.clone())); - let expected = BooleanExpression::ArrayEq(EqExpression::new( + let expected = BooleanExpression::ArrayEq(BinaryExpression::new( a([ conditional(select(x.clone(), 0u32), f(2).pow(u_32(1)), f(0)) + conditional(select(x.clone(), 1u32), f(2).pow(u_32(0)), f(0)), @@ -151,13 +152,13 @@ mod tests { // should become // [x[0] ? 2**2 : 0 + x[1] ? 2**1 : 0, x[2] ? 2**0 : 0] == [y[0] ? 2**2 : 0 + y[1] ? 2**1 : 0 y[2] ? 2**0 : 0] - let x = a_id("x").annotate(Type::Boolean, 3u32); - let y = a_id("y").annotate(Type::Boolean, 3u32); + let x = a_id("x").annotate(ArrayType::new(Type::Boolean, 3u32)); + let y = a_id("y").annotate(ArrayType::new(Type::Boolean, 3u32)); let e: BooleanExpression = - BooleanExpression::ArrayEq(EqExpression::new(x.clone(), y.clone())); + BooleanExpression::ArrayEq(BinaryExpression::new(x.clone(), y.clone())); - let expected = BooleanExpression::ArrayEq(EqExpression::new( + let expected = BooleanExpression::ArrayEq(BinaryExpression::new( a([ conditional(select(x.clone(), 0u32), f(2).pow(u_32(1)), f(0)) + conditional(select(x.clone(), 1u32), f(2).pow(u_32(0)), f(0)), diff --git a/zokrates_analysis/src/branch_isolator.rs b/zokrates_analysis/src/branch_isolator.rs index ee41233a4..6b6789ec6 100644 --- a/zokrates_analysis/src/branch_isolator.rs +++ b/zokrates_analysis/src/branch_isolator.rs @@ -3,6 +3,7 @@ // `if c then a else b fi` becomes `if c then { a } else { b } fi`, and down the line any statements resulting from trating `a` and `b` can be safely kept inside the respective blocks. +use zokrates_ast::common::{Fold, WithSpan}; use zokrates_ast::typed::folder::*; use zokrates_ast::typed::*; use zokrates_field::Field; @@ -18,17 +19,25 @@ impl Isolator { impl<'ast, T: Field> Folder<'ast, T> for Isolator { fn fold_conditional_expression< - E: Expr<'ast, T> + Block<'ast, T> + Fold<'ast, T> + Conditional<'ast, T>, + E: Expr<'ast, T> + Block<'ast, T> + Fold + Conditional<'ast, T>, >( &mut self, _: &E::Ty, e: ConditionalExpression<'ast, T, E>, ) -> ConditionalOrExpression<'ast, T, E> { - ConditionalOrExpression::Conditional(ConditionalExpression::new( - self.fold_boolean_expression(*e.condition), - E::block(vec![], e.consequence.fold(self)), - E::block(vec![], e.alternative.fold(self)), - e.kind, - )) + let span = e.get_span(); + + let consequence_span = e.consequence.get_span(); + let alternative_span = e.alternative.get_span(); + + ConditionalOrExpression::Conditional( + ConditionalExpression::new( + self.fold_boolean_expression(*e.condition), + E::block(vec![], e.consequence.fold(self)).span(consequence_span), + E::block(vec![], e.alternative.fold(self)).span(alternative_span), + e.kind, + ) + .span(span), + ) } } diff --git a/zokrates_analysis/src/condition_redefiner.rs b/zokrates_analysis/src/condition_redefiner.rs index 775271b1d..535a51375 100644 --- a/zokrates_analysis/src/condition_redefiner.rs +++ b/zokrates_analysis/src/condition_redefiner.rs @@ -1,7 +1,10 @@ -use zokrates_ast::typed::{ - folder::*, BlockExpression, BooleanExpression, Conditional, ConditionalExpression, - ConditionalOrExpression, CoreIdentifier, Expr, Id, Identifier, Type, TypedExpression, - TypedProgram, TypedStatement, Variable, +use zokrates_ast::{ + common::{Fold, WithSpan}, + typed::{ + folder::*, BlockExpression, BooleanExpression, Conditional, ConditionalExpression, + ConditionalOrExpression, CoreIdentifier, Expr, Id, Identifier, Type, TypedExpression, + TypedProgram, TypedStatement, Variable, + }, }; use zokrates_field::Field; @@ -18,14 +21,14 @@ impl<'ast, T: Field> ConditionRedefiner<'ast, T> { } impl<'ast, T: Field> Folder<'ast, T> for ConditionRedefiner<'ast, T> { - fn fold_statement(&mut self, s: TypedStatement<'ast, T>) -> Vec> { + fn fold_statement_cases(&mut self, s: TypedStatement<'ast, T>) -> Vec> { assert!(self.buffer.is_empty()); - let s = fold_statement(self, s); + let s = fold_statement_cases(self, s); let buffer = std::mem::take(&mut self.buffer); buffer.into_iter().chain(s).collect() } - fn fold_block_expression>( + fn fold_block_expression>( &mut self, b: BlockExpression<'ast, T, E>, ) -> BlockExpression<'ast, T, E> { @@ -54,25 +57,32 @@ impl<'ast, T: Field> Folder<'ast, T> for ConditionRedefiner<'ast, T> { b } - fn fold_conditional_expression + Conditional<'ast, T> + Fold<'ast, T>>( + fn fold_conditional_expression + Conditional<'ast, T> + Fold>( &mut self, _: &E::Ty, e: ConditionalExpression<'ast, T, E>, ) -> ConditionalOrExpression<'ast, T, E> { let condition = self.fold_boolean_expression(*e.condition); + let condition_span = condition.get_span(); let condition = match condition { condition @ BooleanExpression::Value(_) | condition @ BooleanExpression::Identifier(_) => condition, condition => { let condition_id = Identifier::from(CoreIdentifier::Condition(self.index)); - self.buffer.push(TypedStatement::definition( - Variable::immutable(condition_id.clone(), Type::Boolean).into(), - TypedExpression::from(condition), - )); + self.buffer.push( + TypedStatement::definition( + Variable::new(condition_id.clone(), Type::Boolean) + .span(condition_span) + .into(), + TypedExpression::from(condition).span(condition_span), + ) + .span(condition_span), + ); self.index += 1; - BooleanExpression::identifier(condition_id) + BooleanExpression::identifier(condition_id).span(condition_span) } - }; + } + .span(condition_span); let consequence = e.consequence.fold(self); let alternative = e.alternative.fold(self); @@ -89,6 +99,7 @@ impl<'ast, T: Field> Folder<'ast, T> for ConditionRedefiner<'ast, T> { #[cfg(test)] mod tests { use super::*; + use std::ops::*; use zokrates_ast::typed::{ Block, BooleanExpression, Conditional, ConditionalKind, FieldElementExpression, Type, }; @@ -102,9 +113,9 @@ mod tests { let s = TypedStatement::definition( Variable::field_element("foo").into(), FieldElementExpression::conditional( - BooleanExpression::Value(true), - FieldElementExpression::Number(Bn128Field::from(1)), - FieldElementExpression::Number(Bn128Field::from(2)), + BooleanExpression::value(true), + FieldElementExpression::value(Bn128Field::from(1)), + FieldElementExpression::value(Bn128Field::from(2)), ConditionalKind::IfElse, ) .into(), @@ -124,8 +135,8 @@ mod tests { Variable::field_element("foo").into(), FieldElementExpression::conditional( BooleanExpression::identifier("c".into()), - FieldElementExpression::Number(Bn128Field::from(1)), - FieldElementExpression::Number(Bn128Field::from(2)), + FieldElementExpression::value(Bn128Field::from(1)), + FieldElementExpression::value(Bn128Field::from(2)), ConditionalKind::IfElse, ) .into(), @@ -143,17 +154,17 @@ mod tests { // bool #CONDITION_0 = c && d; // field foo = if #CONDITION_0 { 1 } else { 2 }; - let condition = BooleanExpression::And( - box BooleanExpression::identifier("c".into()), - box BooleanExpression::identifier("d".into()), + let condition = BooleanExpression::bitand( + BooleanExpression::identifier("c".into()), + BooleanExpression::identifier("d".into()), ); let s = TypedStatement::definition( Variable::field_element("foo").into(), FieldElementExpression::conditional( condition.clone(), - FieldElementExpression::Number(Bn128Field::from(1)), - FieldElementExpression::Number(Bn128Field::from(2)), + FieldElementExpression::value(Bn128Field::from(1)), + FieldElementExpression::value(Bn128Field::from(2)), ConditionalKind::IfElse, ) .into(), @@ -164,7 +175,7 @@ mod tests { let expected = vec![ // define condition TypedStatement::definition( - Variable::immutable(CoreIdentifier::Condition(0), Type::Boolean).into(), + Variable::new(CoreIdentifier::Condition(0), Type::Boolean).into(), condition.into(), ), // rewrite statement @@ -172,8 +183,8 @@ mod tests { Variable::field_element("foo").into(), FieldElementExpression::conditional( BooleanExpression::identifier(CoreIdentifier::Condition(0).into()), - FieldElementExpression::Number(Bn128Field::from(1)), - FieldElementExpression::Number(Bn128Field::from(2)), + FieldElementExpression::value(Bn128Field::from(1)), + FieldElementExpression::value(Bn128Field::from(2)), ConditionalKind::IfElse, ) .into(), @@ -202,14 +213,14 @@ mod tests { // 3 // }; - let condition_0 = BooleanExpression::And( - box BooleanExpression::identifier("c".into()), - box BooleanExpression::identifier("d".into()), + let condition_0 = BooleanExpression::bitand( + BooleanExpression::identifier("c".into()), + BooleanExpression::identifier("d".into()), ); - let condition_1 = BooleanExpression::And( - box BooleanExpression::identifier("e".into()), - box BooleanExpression::identifier("f".into()), + let condition_1 = BooleanExpression::bitand( + BooleanExpression::identifier("e".into()), + BooleanExpression::identifier("f".into()), ); let s = TypedStatement::definition( @@ -218,11 +229,11 @@ mod tests { condition_0.clone(), FieldElementExpression::conditional( condition_1.clone(), - FieldElementExpression::Number(Bn128Field::from(1)), - FieldElementExpression::Number(Bn128Field::from(2)), + FieldElementExpression::value(Bn128Field::from(1)), + FieldElementExpression::value(Bn128Field::from(2)), ConditionalKind::IfElse, ), - FieldElementExpression::Number(Bn128Field::from(3)), + FieldElementExpression::value(Bn128Field::from(3)), ConditionalKind::IfElse, ) .into(), @@ -233,11 +244,11 @@ mod tests { let expected = vec![ // define conditions TypedStatement::definition( - Variable::immutable(CoreIdentifier::Condition(0), Type::Boolean).into(), + Variable::new(CoreIdentifier::Condition(0), Type::Boolean).into(), condition_0.into(), ), TypedStatement::definition( - Variable::immutable(CoreIdentifier::Condition(1), Type::Boolean).into(), + Variable::new(CoreIdentifier::Condition(1), Type::Boolean).into(), condition_1.into(), ), // rewrite statement @@ -247,11 +258,11 @@ mod tests { BooleanExpression::identifier(CoreIdentifier::Condition(0).into()), FieldElementExpression::conditional( BooleanExpression::identifier(CoreIdentifier::Condition(1).into()), - FieldElementExpression::Number(Bn128Field::from(1)), - FieldElementExpression::Number(Bn128Field::from(2)), + FieldElementExpression::value(Bn128Field::from(1)), + FieldElementExpression::value(Bn128Field::from(2)), ConditionalKind::IfElse, ), - FieldElementExpression::Number(Bn128Field::from(3)), + FieldElementExpression::value(Bn128Field::from(3)), ConditionalKind::IfElse, ) .into(), @@ -284,19 +295,19 @@ mod tests { // if #CONDITION_2 { 2 } : { 3 } // }; - let condition_0 = BooleanExpression::And( - box BooleanExpression::identifier("c".into()), - box BooleanExpression::identifier("d".into()), + let condition_0 = BooleanExpression::bitand( + BooleanExpression::identifier("c".into()), + BooleanExpression::identifier("d".into()), ); - let condition_1 = BooleanExpression::And( - box BooleanExpression::identifier("e".into()), - box BooleanExpression::identifier("f".into()), + let condition_1 = BooleanExpression::bitand( + BooleanExpression::identifier("e".into()), + BooleanExpression::identifier("f".into()), ); - let condition_2 = BooleanExpression::And( - box BooleanExpression::identifier("e".into()), - box BooleanExpression::identifier("f".into()), + let condition_2 = BooleanExpression::bitand( + BooleanExpression::identifier("e".into()), + BooleanExpression::identifier("f".into()), ); let condition_id_0 = BooleanExpression::identifier(CoreIdentifier::Condition(0).into()); @@ -310,24 +321,24 @@ mod tests { FieldElementExpression::block( vec![TypedStatement::definition( Variable::field_element("a").into(), - FieldElementExpression::Number(Bn128Field::from(1)).into(), + FieldElementExpression::value(Bn128Field::from(1)).into(), )], FieldElementExpression::conditional( condition_1.clone(), - FieldElementExpression::Number(Bn128Field::from(2)), - FieldElementExpression::Number(Bn128Field::from(3)), + FieldElementExpression::value(Bn128Field::from(2)), + FieldElementExpression::value(Bn128Field::from(3)), ConditionalKind::IfElse, ), ), FieldElementExpression::block( vec![TypedStatement::definition( Variable::field_element("b").into(), - FieldElementExpression::Number(Bn128Field::from(2)).into(), + FieldElementExpression::value(Bn128Field::from(2)).into(), )], FieldElementExpression::conditional( condition_2.clone(), - FieldElementExpression::Number(Bn128Field::from(2)), - FieldElementExpression::Number(Bn128Field::from(3)), + FieldElementExpression::value(Bn128Field::from(2)), + FieldElementExpression::value(Bn128Field::from(3)), ConditionalKind::IfElse, ), ), @@ -341,7 +352,7 @@ mod tests { let expected = vec![ // define conditions TypedStatement::definition( - Variable::immutable(CoreIdentifier::Condition(0), Type::Boolean).into(), + Variable::new(CoreIdentifier::Condition(0), Type::Boolean).into(), condition_0.into(), ), // rewrite statement @@ -353,18 +364,17 @@ mod tests { vec![ TypedStatement::definition( Variable::field_element("a").into(), - FieldElementExpression::Number(Bn128Field::from(1)).into(), + FieldElementExpression::value(Bn128Field::from(1)).into(), ), TypedStatement::definition( - Variable::immutable(CoreIdentifier::Condition(1), Type::Boolean) - .into(), + Variable::new(CoreIdentifier::Condition(1), Type::Boolean).into(), condition_1.into(), ), ], FieldElementExpression::conditional( condition_id_1, - FieldElementExpression::Number(Bn128Field::from(2)), - FieldElementExpression::Number(Bn128Field::from(3)), + FieldElementExpression::value(Bn128Field::from(2)), + FieldElementExpression::value(Bn128Field::from(3)), ConditionalKind::IfElse, ), ), @@ -372,18 +382,17 @@ mod tests { vec![ TypedStatement::definition( Variable::field_element("b").into(), - FieldElementExpression::Number(Bn128Field::from(2)).into(), + FieldElementExpression::value(Bn128Field::from(2)).into(), ), TypedStatement::definition( - Variable::immutable(CoreIdentifier::Condition(2), Type::Boolean) - .into(), + Variable::new(CoreIdentifier::Condition(2), Type::Boolean).into(), condition_2.into(), ), ], FieldElementExpression::conditional( condition_id_2, - FieldElementExpression::Number(Bn128Field::from(2)), - FieldElementExpression::Number(Bn128Field::from(3)), + FieldElementExpression::value(Bn128Field::from(2)), + FieldElementExpression::value(Bn128Field::from(3)), ConditionalKind::IfElse, ), ), diff --git a/zokrates_analysis/src/constant_argument_checker.rs b/zokrates_analysis/src/constant_argument_checker.rs index 485cf9181..a8b772f51 100644 --- a/zokrates_analysis/src/constant_argument_checker.rs +++ b/zokrates_analysis/src/constant_argument_checker.rs @@ -1,9 +1,10 @@ use std::fmt; use zokrates_ast::common::FlatEmbed; +use zokrates_ast::typed::result_folder::*; +use zokrates_ast::typed::{result_folder::ResultFolder, Constant, EmbedCall, TypedStatement}; use zokrates_ast::typed::{ - result_folder::fold_statement, result_folder::ResultFolder, Constant, EmbedCall, TypedStatement, + DefinitionRhs, DefinitionStatement, TypedProgram, UBitwidth, UExpression, UExpressionInner, }; -use zokrates_ast::typed::{DefinitionRhs, TypedProgram}; use zokrates_field::Field; pub struct ConstantArgumentChecker; @@ -26,47 +27,83 @@ impl fmt::Display for Error { impl<'ast, T: Field> ResultFolder<'ast, T> for ConstantArgumentChecker { type Error = Error; - fn fold_statement( + fn fold_definition_statement( &mut self, - s: TypedStatement<'ast, T>, + s: DefinitionStatement<'ast, T>, ) -> Result>, Self::Error> { - match s { - TypedStatement::Definition(assignee, DefinitionRhs::EmbedCall(embed_call)) => { - match embed_call { - EmbedCall { - embed: FlatEmbed::BitArrayLe, - .. - } => { - let arguments = embed_call - .arguments - .into_iter() - .map(|a| self.fold_expression(a)) - .collect::, _>>()?; + match s.rhs { + DefinitionRhs::EmbedCall(embed_call) => match embed_call { + EmbedCall { + embed: FlatEmbed::BitArrayLe, + .. + } => { + let arguments = embed_call + .arguments + .into_iter() + .map(|a| self.fold_expression(a)) + .collect::, _>>()?; - if arguments[1].is_constant() { - Ok(vec![TypedStatement::Definition( - assignee, - EmbedCall { - embed: FlatEmbed::BitArrayLe, - generics: embed_call.generics, - arguments, - } - .into(), - )]) - } else { - Err(Error(format!( - "Cannot compare to a variable value, found `{}`", - arguments[1] - ))) - } + if arguments[1].is_constant() { + Ok(vec![TypedStatement::embed_call_definition( + s.assignee, + EmbedCall { + embed: FlatEmbed::BitArrayLe, + generics: embed_call.generics, + arguments, + }, + )]) + } else { + Err(Error(format!( + "Cannot compare to a variable value, found `{}`", + arguments[1] + ))) } - embed_call => Ok(vec![TypedStatement::Definition( - assignee, - embed_call.into(), - )]), + } + embed_call => Ok(vec![TypedStatement::embed_call_definition( + s.assignee, embed_call, + )]), + }, + _ => fold_definition_statement(self, s), + } + } + + fn fold_uint_expression_cases( + &mut self, + bitwidth: UBitwidth, + e: UExpressionInner<'ast, T>, + ) -> Result, Error> { + match e { + UExpressionInner::LeftShift(e) => { + let left = self.fold_uint_expression(*e.left)?; + let right = self.fold_uint_expression(*e.right)?; + + match right.as_inner() { + UExpressionInner::Value(_) => { + Ok(UExpression::left_shift(left, right).into_inner()) + } + by => Err(Error(format!( + "Cannot shift by a variable value, found `{} << {}`", + left, + by.clone().annotate(UBitwidth::B32) + ))), + } + } + UExpressionInner::RightShift(e) => { + let left = self.fold_uint_expression(*e.left)?; + let right = self.fold_uint_expression(*e.right)?; + + match right.as_inner() { + UExpressionInner::Value(_) => { + Ok(UExpression::right_shift(left, right).into_inner()) + } + by => Err(Error(format!( + "Cannot shift by a variable value, found `{} >> {}`", + left, + by.clone().annotate(UBitwidth::B32) + ))), } } - s => fold_statement(self, s), + e => fold_uint_expression_cases(self, bitwidth, e), } } } diff --git a/zokrates_analysis/src/constant_resolver.rs b/zokrates_analysis/src/constant_resolver.rs index bf816248f..5ff42f4c2 100644 --- a/zokrates_analysis/src/constant_resolver.rs +++ b/zokrates_analysis/src/constant_resolver.rs @@ -9,18 +9,18 @@ use zokrates_field::Field; // a map of the canonical constants in this program. with all imported constants reduced to their canonical value type ProgramConstants<'ast, T> = - HashMap, TypedConstant<'ast, T>>>; + HashMap, TypedConstant<'ast, T>>>; pub struct ConstantResolver<'ast, T> { modules: TypedModules<'ast, T>, - location: OwnedTypedModuleId, + location: OwnedModuleId, constants: ProgramConstants<'ast, T>, } impl<'ast, T: Field> ConstantResolver<'ast, T> { pub fn new( modules: TypedModules<'ast, T>, - location: OwnedTypedModuleId, + location: OwnedModuleId, constants: ProgramConstants<'ast, T>, ) -> Self { ConstantResolver { @@ -35,14 +35,14 @@ impl<'ast, T: Field> ConstantResolver<'ast, T> { inliner.fold_program(p) } - fn change_location(&mut self, location: OwnedTypedModuleId) -> OwnedTypedModuleId { + fn change_location(&mut self, location: OwnedModuleId) -> OwnedModuleId { let prev = self.location.clone(); self.location = location; self.constants.entry(self.location.clone()).or_default(); prev } - fn treated(&self, id: &TypedModuleId) -> bool { + fn treated(&self, id: &ModuleId) -> bool { self.constants.contains_key(id) } @@ -67,7 +67,7 @@ impl<'ast, T: Field> Folder<'ast, T> for ConstantResolver<'ast, T> { } } - fn fold_module_id(&mut self, id: OwnedTypedModuleId) -> OwnedTypedModuleId { + fn fold_module_id(&mut self, id: OwnedModuleId) -> OwnedModuleId { // anytime we encounter a module id, visit the corresponding module if it hasn't been done yet if !self.treated(&id) { let current_m_id = self.change_location(id.clone()); @@ -109,10 +109,11 @@ impl<'ast, T: Field> Folder<'ast, T> for ConstantResolver<'ast, T> { #[cfg(test)] mod tests { use super::*; + use std::ops::*; use zokrates_ast::typed::types::{DeclarationSignature, GTupleType}; use zokrates_ast::typed::{ DeclarationArrayType, DeclarationFunctionKey, DeclarationType, FieldElementExpression, - GType, Identifier, TypedConstant, TypedExpression, TypedFunction, TypedFunctionSymbol, + Identifier, TypedConstant, TypedExpression, TypedFunction, TypedFunctionSymbol, TypedStatement, }; use zokrates_field::Bn128Field; @@ -130,7 +131,7 @@ mod tests { let const_id = "a"; let main: TypedFunction = TypedFunction { arguments: vec![], - statements: vec![TypedStatement::Return( + statements: vec![TypedStatement::ret( FieldElementExpression::identifier(Identifier::from(const_id)).into(), )], signature: DeclarationSignature::new() @@ -139,6 +140,7 @@ mod tests { }; let program = TypedProgram { + module_map: Default::default(), main: "main".into(), modules: vec![( "main".into(), @@ -147,7 +149,7 @@ mod tests { TypedConstantSymbolDeclaration::new( CanonicalConstantIdentifier::new(const_id, "main".into()), TypedConstantSymbol::Here(TypedConstant::new( - TypedExpression::FieldElement(FieldElementExpression::Number( + TypedExpression::FieldElement(FieldElementExpression::value( Bn128Field::from(1), )), DeclarationType::FieldElement, @@ -190,7 +192,7 @@ mod tests { let const_id = CanonicalConstantIdentifier::new("a", "main".into()); let main: TypedFunction = TypedFunction { arguments: vec![], - statements: vec![TypedStatement::Return( + statements: vec![TypedStatement::ret( BooleanExpression::identifier(Identifier::from(const_id.clone())).into(), )], signature: DeclarationSignature::new() @@ -199,6 +201,7 @@ mod tests { }; let program = TypedProgram { + module_map: Default::default(), main: "main".into(), modules: vec![( "main".into(), @@ -207,7 +210,7 @@ mod tests { TypedConstantSymbolDeclaration::new( const_id, TypedConstantSymbol::Here(TypedConstant::new( - TypedExpression::Boolean(BooleanExpression::Value(true)), + TypedExpression::Boolean(BooleanExpression::value(true)), DeclarationType::Boolean, )), ) @@ -248,7 +251,7 @@ mod tests { let const_id = CanonicalConstantIdentifier::new("a", "main".into()); let main: TypedFunction = TypedFunction { arguments: vec![], - statements: vec![TypedStatement::Return( + statements: vec![TypedStatement::ret( UExpression::identifier(Identifier::from(const_id.clone())) .annotate(UBitwidth::B32) .into(), @@ -259,6 +262,7 @@ mod tests { }; let program = TypedProgram { + module_map: Default::default(), main: "main".into(), modules: vec![( "main".into(), @@ -267,9 +271,7 @@ mod tests { TypedConstantSymbolDeclaration::new( const_id, TypedConstantSymbol::Here(TypedConstant::new( - UExpressionInner::Value(1u128) - .annotate(UBitwidth::B32) - .into(), + UExpression::value(1u128).annotate(UBitwidth::B32).into(), DeclarationType::Uint(UBitwidth::B32), )), ) @@ -310,20 +312,18 @@ mod tests { let const_id = CanonicalConstantIdentifier::new("a", "main".into()); let main: TypedFunction = TypedFunction { arguments: vec![], - statements: vec![TypedStatement::Return( - FieldElementExpression::Add( + statements: vec![TypedStatement::ret( + FieldElementExpression::add( FieldElementExpression::select( ArrayExpression::identifier(Identifier::from(const_id.clone())) - .annotate(GType::FieldElement, 2u32), - UExpressionInner::Value(0u128).annotate(UBitwidth::B32), - ) - .into(), + .annotate(GArrayType::new(Type::FieldElement, 2u32)), + UExpression::value(0u128).annotate(UBitwidth::B32), + ), FieldElementExpression::select( ArrayExpression::identifier(Identifier::from(const_id.clone())) - .annotate(GType::FieldElement, 2u32), - UExpressionInner::Value(1u128).annotate(UBitwidth::B32), - ) - .into(), + .annotate(GArrayType::new(Type::FieldElement, 2u32)), + UExpression::value(1u128).annotate(UBitwidth::B32), + ), ) .into(), )], @@ -333,6 +333,7 @@ mod tests { }; let program = TypedProgram { + module_map: Default::default(), main: "main".into(), modules: vec![( "main".into(), @@ -342,16 +343,11 @@ mod tests { const_id.clone(), TypedConstantSymbol::Here(TypedConstant::new( TypedExpression::Array( - ArrayExpressionInner::Value( - vec![ - FieldElementExpression::Number(Bn128Field::from(2)) - .into(), - FieldElementExpression::Number(Bn128Field::from(2)) - .into(), - ] - .into(), - ) - .annotate(GType::FieldElement, 2u32), + ArrayExpression::value(vec![ + FieldElementExpression::value(Bn128Field::from(2)).into(), + FieldElementExpression::value(Bn128Field::from(2)).into(), + ]) + .annotate(GArrayType::new(Type::FieldElement, 2u32)), ), DeclarationType::Array(DeclarationArrayType::new( DeclarationType::FieldElement, @@ -397,7 +393,7 @@ mod tests { let main: TypedFunction = TypedFunction { arguments: vec![], - statements: vec![TypedStatement::Return( + statements: vec![TypedStatement::ret( FieldElementExpression::identifier(Identifier::from(const_b_id.clone())).into(), )], signature: DeclarationSignature::new() @@ -406,6 +402,7 @@ mod tests { }; let program = TypedProgram { + module_map: Default::default(), main: "main".into(), modules: vec![( "main".into(), @@ -414,7 +411,7 @@ mod tests { TypedConstantSymbolDeclaration::new( const_a_id.clone(), TypedConstantSymbol::Here(TypedConstant::new( - TypedExpression::FieldElement(FieldElementExpression::Number( + TypedExpression::FieldElement(FieldElementExpression::value( Bn128Field::from(1), )), DeclarationType::FieldElement, @@ -424,11 +421,11 @@ mod tests { TypedConstantSymbolDeclaration::new( const_b_id.clone(), TypedConstantSymbol::Here(TypedConstant::new( - TypedExpression::FieldElement(FieldElementExpression::Add( - box FieldElementExpression::identifier(Identifier::from( + TypedExpression::FieldElement(FieldElementExpression::add( + FieldElementExpression::identifier(Identifier::from( const_a_id.clone(), )), - box FieldElementExpression::Number(Bn128Field::from(1)), + FieldElementExpression::value(Bn128Field::from(1)), )), DeclarationType::FieldElement, )), @@ -505,7 +502,7 @@ mod tests { TypedConstantSymbolDeclaration::new( foo_const_id.clone(), TypedConstantSymbol::Here(TypedConstant::new( - TypedExpression::FieldElement(FieldElementExpression::Number( + TypedExpression::FieldElement(FieldElementExpression::value( Bn128Field::from(42), )), DeclarationType::FieldElement, @@ -556,7 +553,7 @@ mod tests { ), TypedFunctionSymbol::Here(TypedFunction { arguments: vec![], - statements: vec![TypedStatement::Return( + statements: vec![TypedStatement::ret( FieldElementExpression::identifier(Identifier::from( main_const_id.clone(), )) @@ -572,6 +569,7 @@ mod tests { }; let program = TypedProgram { + module_map: Default::default(), main: "main".into(), modules: vec![ ("main".into(), main_module), @@ -602,7 +600,7 @@ mod tests { ), TypedFunctionSymbol::Here(TypedFunction { arguments: vec![], - statements: vec![TypedStatement::Return( + statements: vec![TypedStatement::ret( FieldElementExpression::identifier(Identifier::from( main_const_id.clone(), )) @@ -618,6 +616,7 @@ mod tests { }; let expected_program: TypedProgram = TypedProgram { + module_map: Default::default(), main: "main".into(), modules: vec![ ("main".into(), expected_main_module), @@ -683,7 +682,7 @@ mod tests { TypedConstantSymbolDeclaration::new( foo_const_id.clone(), TypedConstantSymbol::Here(TypedConstant::new( - TypedExpression::FieldElement(FieldElementExpression::Number( + TypedExpression::FieldElement(FieldElementExpression::value( Bn128Field::from(2), )), DeclarationType::FieldElement, @@ -693,13 +692,10 @@ mod tests { TypedConstantSymbolDeclaration::new( bar_const_id.clone(), TypedConstantSymbol::Here(TypedConstant::new( - TypedExpression::Array( - ArrayExpressionInner::Repeat( - box FieldElementExpression::Number(Bn128Field::from(1)).into(), - box UExpression::from(foo_const_id.clone()), - ) - .annotate(Type::FieldElement, foo_const_id.clone()), - ), + TypedExpression::Array(ArrayExpression::repeat( + FieldElementExpression::value(Bn128Field::from(1)).into(), + UExpression::from(foo_const_id.clone()), + )), DeclarationType::Array(DeclarationArrayType::new( DeclarationType::FieldElement, DeclarationConstant::Constant(foo_const_id.clone()), @@ -745,8 +741,9 @@ mod tests { main_baz_const_id.clone(), TypedConstantSymbol::Here(TypedConstant::new( TypedExpression::Array( - ArrayExpression::identifier(main_bar_const_id.clone().into()) - .annotate(Type::FieldElement, main_foo_const_id.clone()), + ArrayExpression::identifier(main_bar_const_id.clone().into()).annotate( + ArrayType::new(Type::FieldElement, main_foo_const_id.clone()), + ), ), DeclarationType::Array(DeclarationArrayType::new( DeclarationType::FieldElement, @@ -763,7 +760,7 @@ mod tests { ), TypedFunctionSymbol::Here(TypedFunction { arguments: vec![], - statements: vec![TypedStatement::Return( + statements: vec![TypedStatement::ret( FieldElementExpression::identifier(Identifier::from( main_foo_const_id.clone(), )) @@ -779,6 +776,7 @@ mod tests { }; let program = TypedProgram { + module_map: Default::default(), main: "main".into(), modules: vec![ ("main".into(), main_module), @@ -794,7 +792,7 @@ mod tests { TypedConstantSymbolDeclaration::new( main_foo_const_id.clone(), TypedConstantSymbol::Here(TypedConstant::new( - FieldElementExpression::Number(Bn128Field::from(2)).into(), + FieldElementExpression::value(Bn128Field::from(2)).into(), DeclarationType::FieldElement, )), ) @@ -802,13 +800,10 @@ mod tests { TypedConstantSymbolDeclaration::new( main_bar_const_id.clone(), TypedConstantSymbol::Here(TypedConstant::new( - TypedExpression::Array( - ArrayExpressionInner::Repeat( - box FieldElementExpression::Number(Bn128Field::from(1)).into(), - box UExpression::from(foo_const_id.clone()), - ) - .annotate(Type::FieldElement, foo_const_id.clone()), - ), + TypedExpression::Array(ArrayExpression::repeat( + FieldElementExpression::value(Bn128Field::from(1)).into(), + UExpression::from(foo_const_id.clone()), + )), DeclarationType::Array(DeclarationArrayType::new( DeclarationType::FieldElement, DeclarationConstant::Constant(foo_const_id.clone()), @@ -820,8 +815,9 @@ mod tests { main_baz_const_id.clone(), TypedConstantSymbol::Here(TypedConstant::new( TypedExpression::Array( - ArrayExpression::identifier(main_bar_const_id.into()) - .annotate(Type::FieldElement, main_foo_const_id.clone()), + ArrayExpression::identifier(main_bar_const_id.into()).annotate( + ArrayType::new(Type::FieldElement, main_foo_const_id.clone()), + ), ), DeclarationType::Array(DeclarationArrayType::new( DeclarationType::FieldElement, @@ -838,7 +834,7 @@ mod tests { ), TypedFunctionSymbol::Here(TypedFunction { arguments: vec![], - statements: vec![TypedStatement::Return( + statements: vec![TypedStatement::ret( FieldElementExpression::identifier(Identifier::from( main_foo_const_id.clone(), )) @@ -854,6 +850,7 @@ mod tests { }; let expected_program: TypedProgram = TypedProgram { + module_map: Default::default(), main: "main".into(), modules: vec![ ("main".into(), expected_main_module), diff --git a/zokrates_analysis/src/dead_code.rs b/zokrates_analysis/src/dead_code.rs index 4b67b08b2..d1baba976 100644 --- a/zokrates_analysis/src/dead_code.rs +++ b/zokrates_analysis/src/dead_code.rs @@ -26,38 +26,56 @@ impl<'ast, T: Field> Folder<'ast, T> for DeadCodeEliminator<'ast> { ZirFunction { statements, ..f } } - fn fold_statement(&mut self, s: ZirStatement<'ast, T>) -> Vec> { - match s { - ZirStatement::Definition(v, e) => { - // if the lhs is used later in the program - if self.used.remove(&v.id) { - // include this statement - fold_statement(self, ZirStatement::Definition(v, e)) - } else { - // otherwise remove it - vec![] - } - } - ZirStatement::IfElse(condition, consequence, alternative) => { - let condition = self.fold_boolean_expression(condition); + fn fold_if_else_statement( + &mut self, + s: zokrates_ast::zir::IfElseStatement<'ast, T>, + ) -> Vec> { + let condition = self.fold_boolean_expression(s.condition); - let mut consequence: Vec<_> = consequence - .into_iter() - .rev() - .flat_map(|e| self.fold_statement(e)) - .collect(); - consequence.reverse(); + let mut consequence: Vec<_> = s + .consequence + .into_iter() + .rev() + .flat_map(|e| self.fold_statement(e)) + .collect(); + consequence.reverse(); - let mut alternative: Vec<_> = alternative - .into_iter() - .rev() - .flat_map(|e| self.fold_statement(e)) - .collect(); - alternative.reverse(); + let mut alternative: Vec<_> = s + .alternative + .into_iter() + .rev() + .flat_map(|e| self.fold_statement(e)) + .collect(); + alternative.reverse(); + + vec![ZirStatement::if_else(condition, consequence, alternative)] + } + + fn fold_multiple_definition_statement( + &mut self, + s: zokrates_ast::zir::MultipleDefinitionStatement<'ast, T>, + ) -> Vec> { + // if the lhs is used later in the program + if s.assignees.iter().any(|a| self.used.remove(&a.id)) { + // include this statement + fold_multiple_definition_statement(self, s) + } else { + // otherwise remove it + vec![] + } + } - vec![ZirStatement::IfElse(condition, consequence, alternative)] - } - s => fold_statement(self, s), + fn fold_definition_statement( + &mut self, + s: zokrates_ast::zir::DefinitionStatement<'ast, T>, + ) -> Vec> { + // if the lhs is used later in the program + if self.used.remove(&s.assignee.id) { + // include this statement + fold_definition_statement(self, s) + } else { + // otherwise remove it + vec![] } } diff --git a/zokrates_analysis/src/expression_validator.rs b/zokrates_analysis/src/expression_validator.rs index d3a0a96ef..9dcd63413 100644 --- a/zokrates_analysis/src/expression_validator.rs +++ b/zokrates_analysis/src/expression_validator.rs @@ -1,7 +1,5 @@ use std::fmt; -use zokrates_ast::typed::result_folder::{ - fold_assembly_statement, fold_field_expression, fold_uint_expression_inner, ResultFolder, -}; +use zokrates_ast::typed::{result_folder::*, AssemblyAssignment, UExpression}; use zokrates_ast::typed::{ FieldElementExpression, TypedAssemblyStatement, TypedProgram, UBitwidth, UExpressionInner, }; @@ -27,81 +25,80 @@ impl ExpressionValidator { impl<'ast, T: Field> ResultFolder<'ast, T> for ExpressionValidator { type Error = Error; - fn fold_assembly_statement( + // we allow more dynamic expressions in witness generation + fn fold_assembly_assignment( &mut self, - s: TypedAssemblyStatement<'ast, T>, + s: AssemblyAssignment<'ast, T>, ) -> Result>, Self::Error> { - match s { - // we allow more dynamic expressions in witness generation - TypedAssemblyStatement::Assignment(_, _) => Ok(vec![s]), - s => fold_assembly_statement(self, s), - } + Ok(vec![TypedAssemblyStatement::Assignment(s)]) } - fn fold_field_expression( + fn fold_field_expression_cases( &mut self, e: FieldElementExpression<'ast, T>, ) -> Result, Self::Error> { match e { // these should have been propagated away - FieldElementExpression::And(_, _) - | FieldElementExpression::Or(_, _) - | FieldElementExpression::Xor(_, _) - | FieldElementExpression::LeftShift(_, _) - | FieldElementExpression::RightShift(_, _) => Err(Error(format!( + FieldElementExpression::And(_) + | FieldElementExpression::Or(_) + | FieldElementExpression::Xor(_) + | FieldElementExpression::LeftShift(_) + | FieldElementExpression::RightShift(_) => Err(Error(format!( "Found non-constant bitwise operation in field element expression `{}`", e ))), - FieldElementExpression::Pow(box e, box exp) => { - let e = self.fold_field_expression(e)?; - let exp = self.fold_uint_expression(exp)?; + FieldElementExpression::Pow(e) => { + let base = self.fold_field_expression(*e.left)?; + let exp = self.fold_uint_expression(*e.right)?; match exp.as_inner() { - UExpressionInner::Value(_) => Ok(FieldElementExpression::Pow(box e, box exp)), + UExpressionInner::Value(_) => Ok(FieldElementExpression::pow(base, exp)), exp => Err(Error(format!( "Found non-constant exponent in power expression `{}**{}`", - e, + base, exp.clone().annotate(UBitwidth::B32) ))), } } - e => fold_field_expression(self, e), + e => fold_field_expression_cases(self, e), } } - fn fold_uint_expression_inner( + fn fold_uint_expression_cases( &mut self, bitwidth: UBitwidth, e: UExpressionInner<'ast, T>, ) -> Result, Error> { match e { - UExpressionInner::LeftShift(box e, box by) => { - let e = self.fold_uint_expression(e)?; - let by = self.fold_uint_expression(by)?; + UExpressionInner::LeftShift(e) => { + let expr = self.fold_uint_expression(*e.left)?; + let by = self.fold_uint_expression(*e.right)?; match by.as_inner() { - UExpressionInner::Value(_) => Ok(UExpressionInner::LeftShift(box e, box by)), - by => Err(Error(format!( - "Cannot shift by a variable value, found `{} << {}`", - e, - by.clone().annotate(UBitwidth::B32) + UExpressionInner::Value(_) => { + Ok(UExpression::left_shift(expr, by).into_inner()) + } + _ => Err(Error(format!( + "Cannot shift by a variable value, found `{}`", + UExpression::left_shift(expr, by) ))), } } - UExpressionInner::RightShift(box e, box by) => { - let e = self.fold_uint_expression(e)?; - let by = self.fold_uint_expression(by)?; + UExpressionInner::RightShift(e) => { + let expr = self.fold_uint_expression(*e.left)?; + let by = self.fold_uint_expression(*e.right)?; match by.as_inner() { - UExpressionInner::Value(_) => Ok(UExpressionInner::RightShift(box e, box by)), - by => Err(Error(format!( - "Cannot shift by a variable value, found `{} >> {}`", - e, - by.clone().annotate(UBitwidth::B32) + UExpressionInner::Value(_) => { + Ok(UExpression::right_shift(expr, by).into_inner()) + } + _ => Err(Error(format!( + "Cannot shift by a variable value, found `{}`", + UExpression::right_shift(expr, by) ))), } } - e => fold_uint_expression_inner(self, bitwidth, e), + e => fold_uint_expression_cases(self, bitwidth, e), } } } diff --git a/zokrates_analysis/src/flat_propagation.rs b/zokrates_analysis/src/flat_propagation.rs index 155d803c8..547712ff3 100644 --- a/zokrates_analysis/src/flat_propagation.rs +++ b/zokrates_analysis/src/flat_propagation.rs @@ -5,6 +5,9 @@ //! @date 2018 use std::collections::HashMap; +use std::ops::*; +use zokrates_ast::common::expressions::IdentifierOrExpression; +use zokrates_ast::common::WithSpan; use zokrates_ast::flat::folder::*; use zokrates_ast::flat::*; use zokrates_field::Field; @@ -17,49 +20,62 @@ struct Propagator { impl<'ast, T: Field> Folder<'ast, T> for Propagator { fn fold_statement(&mut self, s: FlatStatement<'ast, T>) -> Vec> { match s { - FlatStatement::Definition(var, expr) => match self.fold_expression(expr) { - FlatExpression::Number(n) => { - self.constants.insert(var, n); + FlatStatement::Definition(s) => match self.fold_expression(s.rhs) { + FlatExpression::Value(n) => { + self.constants.insert(s.assignee, n.value); vec![] } - e => vec![FlatStatement::Definition(var, e)], + e => vec![FlatStatement::definition(s.assignee, e)], }, s => fold_statement(self, s), } } + fn fold_identifier_expression( + &mut self, + e: zokrates_ast::common::expressions::IdentifierExpression>, + ) -> IdentifierOrExpression, FlatExpression> { + match self.constants.get(&e.id) { + Some(c) => IdentifierOrExpression::Expression(FlatExpression::value(*c)), + None => IdentifierOrExpression::Identifier(e), + } + } + fn fold_expression(&mut self, e: FlatExpression) -> FlatExpression { + let span = e.get_span(); + match e { - FlatExpression::Number(n) => FlatExpression::Number(n), - FlatExpression::Identifier(id) => match self.constants.get(&id) { - Some(c) => FlatExpression::Number(c.clone()), - None => FlatExpression::Identifier(id), - }, - FlatExpression::Add(box e1, box e2) => { - match (self.fold_expression(e1), self.fold_expression(e2)) { - (FlatExpression::Number(n1), FlatExpression::Number(n2)) => { - FlatExpression::Number(n1 + n2) - } - (e1, e2) => FlatExpression::Add(box e1, box e2), + FlatExpression::Value(n) => FlatExpression::Value(n), + FlatExpression::Add(e) => match ( + self.fold_expression(*e.left), + self.fold_expression(*e.right), + ) { + (FlatExpression::Value(n1), FlatExpression::Value(n2)) => { + FlatExpression::value(n1.value + n2.value) } - } - FlatExpression::Sub(box e1, box e2) => { - match (self.fold_expression(e1), self.fold_expression(e2)) { - (FlatExpression::Number(n1), FlatExpression::Number(n2)) => { - FlatExpression::Number(n1 - n2) - } - (e1, e2) => FlatExpression::Sub(box e1, box e2), + (e1, e2) => FlatExpression::add(e1, e2), + }, + FlatExpression::Sub(e) => match ( + self.fold_expression(*e.left), + self.fold_expression(*e.right), + ) { + (FlatExpression::Value(n1), FlatExpression::Value(n2)) => { + FlatExpression::value(n1.value - n2.value) } - } - FlatExpression::Mult(box e1, box e2) => { - match (self.fold_expression(e1), self.fold_expression(e2)) { - (FlatExpression::Number(n1), FlatExpression::Number(n2)) => { - FlatExpression::Number(n1 * n2) - } - (e1, e2) => FlatExpression::Mult(box e1, box e2), + (e1, e2) => FlatExpression::sub(e1, e2), + }, + FlatExpression::Mult(e) => match ( + self.fold_expression(*e.left), + self.fold_expression(*e.right), + ) { + (FlatExpression::Value(n1), FlatExpression::Value(n2)) => { + FlatExpression::value(n1.value * n2.value) } - } + (e1, e2) => FlatExpression::mul(e1, e2), + }, + e => fold_expression(self, e), } + .span(span) } } @@ -80,14 +96,14 @@ mod tests { fn add() { let mut propagator = Propagator::default(); - let e = FlatExpression::Add( - box FlatExpression::Number(Bn128Field::from(2)), - box FlatExpression::Number(Bn128Field::from(3)), + let e = FlatExpression::add( + FlatExpression::value(Bn128Field::from(2)), + FlatExpression::value(Bn128Field::from(3)), ); assert_eq!( propagator.fold_expression(e), - FlatExpression::Number(Bn128Field::from(5)) + FlatExpression::value(Bn128Field::from(5)) ); } @@ -95,14 +111,14 @@ mod tests { fn sub() { let mut propagator = Propagator::default(); - let e = FlatExpression::Sub( - box FlatExpression::Number(Bn128Field::from(3)), - box FlatExpression::Number(Bn128Field::from(2)), + let e = FlatExpression::sub( + FlatExpression::value(Bn128Field::from(3)), + FlatExpression::value(Bn128Field::from(2)), ); assert_eq!( propagator.fold_expression(e), - FlatExpression::Number(Bn128Field::from(1)) + FlatExpression::value(Bn128Field::from(1)) ); } @@ -110,14 +126,14 @@ mod tests { fn mult() { let mut propagator = Propagator::default(); - let e = FlatExpression::Mult( - box FlatExpression::Number(Bn128Field::from(3)), - box FlatExpression::Number(Bn128Field::from(2)), + let e = FlatExpression::mul( + FlatExpression::value(Bn128Field::from(3)), + FlatExpression::value(Bn128Field::from(2)), ); assert_eq!( propagator.fold_expression(e), - FlatExpression::Number(Bn128Field::from(6)) + FlatExpression::value(Bn128Field::from(6)) ); } } diff --git a/zokrates_analysis/src/flatten_complex_types.rs b/zokrates_analysis/src/flatten_complex_types.rs index f4b81d8e1..64705d1ad 100644 --- a/zokrates_analysis/src/flatten_complex_types.rs +++ b/zokrates_analysis/src/flatten_complex_types.rs @@ -1,10 +1,15 @@ -use std::collections::HashMap; +use std::collections::BTreeMap; use std::convert::{TryFrom, TryInto}; use std::marker::PhantomData; +use std::ops::*; +use zokrates_ast::common::expressions::{BinaryExpression, ValueExpression}; +use zokrates_ast::common::operators::OpEq; +use zokrates_ast::common::statements::LogStatement; +use zokrates_ast::common::{Span, WithSpan}; use zokrates_ast::typed::types::{ConcreteArrayType, IntoType, UBitwidth}; -use zokrates_ast::typed::{self, Expr, Typed}; -use zokrates_ast::zir::IntoType as ZirIntoType; -use zokrates_ast::zir::{self, Folder, Id, Select}; +use zokrates_ast::typed::{self, Basic, Expr, Typed}; +use zokrates_ast::zir::{self, Expr as ZirExpr, Folder, Id, MultipleDefinitionStatement, Select}; +use zokrates_ast::zir::{IntoType as ZirIntoType, SourceIdentifier}; use zokrates_field::Field; #[derive(Default)] @@ -18,31 +23,30 @@ fn flatten_identifier_rec<'ast>( ) -> Vec> { match ty { typed::ConcreteType::Int => unreachable!(), - typed::ConcreteType::FieldElement => vec![zir::Variable { - id: zir::Identifier::Source(id), - _type: zir::Type::FieldElement, - }], - typed::types::ConcreteType::Boolean => vec![zir::Variable { - id: zir::Identifier::Source(id), - _type: zir::Type::Boolean, - }], - typed::types::ConcreteType::Uint(bitwidth) => vec![zir::Variable { - id: zir::Identifier::Source(id), - _type: zir::Type::uint(bitwidth.to_usize()), - }], + typed::ConcreteType::FieldElement => vec![zir::Variable::new( + zir::Identifier::Source(id), + zir::Type::FieldElement, + )], + typed::types::ConcreteType::Boolean => vec![zir::Variable::new( + zir::Identifier::Source(id), + zir::Type::Boolean, + )], + typed::types::ConcreteType::Uint(bitwidth) => { + vec![zir::Variable::new( + zir::Identifier::Source(id), + zir::Type::uint(bitwidth.to_usize()), + )] + } typed::types::ConcreteType::Array(array_type) => (0..*array_type.size) .flat_map(|i| { - flatten_identifier_rec( - zir::SourceIdentifier::Select(box id.clone(), i), - &array_type.ty, - ) + flatten_identifier_rec(SourceIdentifier::select(id.clone(), i), &array_type.ty) }) .collect(), typed::types::ConcreteType::Struct(members) => members .iter() .flat_map(|struct_member| { flatten_identifier_rec( - zir::SourceIdentifier::Member(box id.clone(), struct_member.id.clone()), + SourceIdentifier::member(id.clone(), struct_member.id.clone()), &struct_member.ty, ) }) @@ -52,7 +56,7 @@ fn flatten_identifier_rec<'ast>( .iter() .enumerate() .flat_map(|(i, ty)| { - flatten_identifier_rec(zir::SourceIdentifier::Element(box id.clone(), i as u32), ty) + flatten_identifier_rec(SourceIdentifier::element(id.clone(), i as u32), ty) }) .collect(), } @@ -78,7 +82,7 @@ fn flatten_identifier_to_expression_rec<'ast, T: Field>( typed::ConcreteType::Array(array_type) => (0..*array_type.size) .flat_map(|i| { flatten_identifier_to_expression_rec( - zir::SourceIdentifier::Select(box id.clone(), i), + SourceIdentifier::select(id.clone(), i), &array_type.ty, ) }) @@ -87,7 +91,7 @@ fn flatten_identifier_to_expression_rec<'ast, T: Field>( .iter() .flat_map(|struct_member| { flatten_identifier_to_expression_rec( - zir::SourceIdentifier::Member(box id.clone(), struct_member.id.clone()), + SourceIdentifier::member(id.clone(), struct_member.id.clone()), &struct_member.ty, ) }) @@ -98,7 +102,7 @@ fn flatten_identifier_to_expression_rec<'ast, T: Field>( .enumerate() .flat_map(|(i, ty)| { flatten_identifier_to_expression_rec( - zir::SourceIdentifier::Element(box id.clone(), i as u32), + SourceIdentifier::element(id.clone(), i as u32), ty, ) }) @@ -192,44 +196,50 @@ impl<'ast, T: Field> Flattener { &mut self, p: typed::DeclarationParameter<'ast, T>, ) -> Vec> { + let span = p.get_span(); + let private = p.private; self.fold_variable(zokrates_ast::typed::variable::try_from_g_variable(p.id).unwrap()) .into_iter() - .map(|v| zir::Parameter { id: v, private }) + .map(|v| zir::Parameter::new(v, private).span(span)) .collect() } fn fold_name(&mut self, n: typed::Identifier<'ast>) -> zir::SourceIdentifier<'ast> { - zir::SourceIdentifier::Basic(n) + SourceIdentifier::Basic(n) } fn fold_variable(&mut self, v: typed::Variable<'ast, T>) -> Vec> { + let span = v.get_span(); let ty = v.get_type(); let id = self.fold_name(v.id); let ty = typed::types::ConcreteType::try_from(ty).unwrap(); flatten_identifier_rec(id, &ty) + .into_iter() + .map(|v| v.span(span)) + .collect() } fn fold_assignee(&mut self, a: typed::TypedAssignee<'ast, T>) -> Vec> { match a { typed::TypedAssignee::Identifier(v) => self.fold_variable(v), - typed::TypedAssignee::Select(box a, box i) => { + typed::TypedAssignee::Select(a, i) => { let count = match typed::ConcreteType::try_from(a.get_type()).unwrap() { typed::ConcreteType::Array(array_ty) => array_ty.ty.get_primitive_count(), _ => unreachable!(), }; - let a = self.fold_assignee(a); + let a = self.fold_assignee(*a); match i.as_inner() { typed::UExpressionInner::Value(index) => { - a[*index as usize * count..(*index as usize + 1) * count].to_vec() + a[index.value as usize * count..(index.value as usize + 1) * count].to_vec() } i => unreachable!("index {:?} not allowed, should be a constant", i), } } - typed::TypedAssignee::Member(box a, m) => { + typed::TypedAssignee::Member(a, m) => { let (offset, size) = match typed::ConcreteType::try_from(a.get_type()).unwrap() { typed::ConcreteType::Struct(struct_type) => struct_type @@ -247,11 +257,11 @@ impl<'ast, T: Field> Flattener { let size = size.unwrap(); - let a = self.fold_assignee(a); + let a = self.fold_assignee(*a); a[offset..offset + size].to_vec() } - typed::TypedAssignee::Element(box a, index) => { + typed::TypedAssignee::Element(a, index) => { let tuple_ty = typed::ConcreteTupleType::try_from( typed::ConcreteType::try_from(a.get_type()).unwrap(), ) @@ -266,7 +276,7 @@ impl<'ast, T: Field> Flattener { let size = &tuple_ty.elements[index as usize].get_primitive_count(); - let a = self.fold_assignee(a); + let a = self.fold_assignee(*a); a[offset..offset + size].to_vec() } @@ -366,6 +376,20 @@ impl<'ast, T: Field> Flattener { fold_conditional_expression(self, statements_buffer, c) } + fn fold_binary_expression< + L: Flatten<'ast, T> + typed::Expr<'ast, T> + Basic<'ast, T>, + R: Flatten<'ast, T> + typed::Expr<'ast, T> + Basic<'ast, T>, + E: Flatten<'ast, T> + typed::Expr<'ast, T> + Basic<'ast, T>, + Op, + >( + &mut self, + statements_buffer: &mut Vec>, + e: BinaryExpression, + ) -> BinaryExpression + { + fold_binary_expression(self, statements_buffer, e) + } + fn fold_member_expression( &mut self, statements_buffer: &mut Vec>, @@ -393,7 +417,7 @@ impl<'ast, T: Field> Flattener { fn fold_eq_expression>( &mut self, statements_buffer: &mut Vec>, - eq: typed::EqExpression, + eq: BinaryExpression>, ) -> zir::BooleanExpression<'ast, T> { fold_eq_expression(self, statements_buffer, eq) } @@ -481,29 +505,30 @@ impl<'ast, T: Field> Flattener { // } #[derive(Default)] pub struct ArgumentFinder<'ast, T> { - pub identifiers: HashMap, zir::Type>, + pub identifiers: BTreeMap, zir::Type>, _phantom: PhantomData, } impl<'ast, T: Field> Folder<'ast, T> for ArgumentFinder<'ast, T> { fn fold_statement(&mut self, s: zir::ZirStatement<'ast, T>) -> Vec> { match s { - zir::ZirStatement::Definition(assignee, expr) => { - let assignee = self.fold_assignee(assignee); - let expr = self.fold_expression(expr); + zir::ZirStatement::Definition(s) => { + let assignee = self.fold_assignee(s.assignee); + let expr = self.fold_expression(s.rhs); self.identifiers.remove(&assignee.id); - vec![zir::ZirStatement::Definition(assignee, expr)] + vec![zir::ZirStatement::definition(assignee, expr)] } - zir::ZirStatement::MultipleDefinition(assignees, list) => { - let assignees: Vec> = assignees + zir::ZirStatement::MultipleDefinition(s) => { + let assignees: Vec> = s + .assignees .into_iter() .map(|v| self.fold_assignee(v)) .collect(); - let list = self.fold_expression_list(list); + let list = self.fold_expression_list(s.rhs); for a in &assignees { self.identifiers.remove(&a.id); } - vec![zir::ZirStatement::MultipleDefinition(assignees, list)] + vec![zir::ZirStatement::multiple_definition(assignees, list)] } s => zir::folder::fold_statement(self, s), } @@ -525,12 +550,14 @@ fn fold_assembly_statement<'ast, T: Field>( statements_buffer: &mut Vec>, s: typed::TypedAssemblyStatement<'ast, T>, ) -> zir::ZirAssemblyStatement<'ast, T> { + let span = s.get_span(); + match s { - typed::TypedAssemblyStatement::Assignment(a, e) => { + typed::TypedAssemblyStatement::Assignment(s) => { let mut statements_buffer: Vec> = vec![]; - let a = f.fold_assignee(a); - let e = f.fold_expression(&mut statements_buffer, e); - statements_buffer.push(zir::ZirStatement::Return(e)); + let a = f.fold_assignee(s.assignee); + let e = f.fold_expression(&mut statements_buffer, s.expression); + statements_buffer.push(zir::ZirStatement::ret(e)); let mut finder = ArgumentFinder::default(); let mut statements_buffer: Vec> = statements_buffer @@ -547,22 +574,22 @@ fn fold_assembly_statement<'ast, T: Field>( arguments: finder .identifiers .into_iter() - .map(|(id, ty)| zir::Parameter { - id: zir::Variable::with_id_and_type(id, ty), - private: true, + .map(|(id, ty)| { + zir::Parameter::private(zir::Variable::with_id_and_type(id, ty)) }) .collect(), statements: statements_buffer, }; - zir::ZirAssemblyStatement::Assignment(a, function) + zir::ZirAssemblyStatement::assignment(a, function) } - typed::TypedAssemblyStatement::Constraint(lhs, rhs, metadata) => { - let lhs = f.fold_field_expression(statements_buffer, lhs); - let rhs = f.fold_field_expression(statements_buffer, rhs); - zir::ZirAssemblyStatement::Constraint(lhs, rhs, metadata) + typed::TypedAssemblyStatement::Constraint(s) => { + let lhs = f.fold_field_expression(statements_buffer, s.left); + let rhs = f.fold_field_expression(statements_buffer, s.right); + zir::ZirAssemblyStatement::constraint(lhs, rhs, s.metadata) } } + .span(span) } fn fold_statement<'ast, T: Field>( @@ -570,57 +597,68 @@ fn fold_statement<'ast, T: Field>( statements_buffer: &mut Vec>, s: typed::TypedStatement<'ast, T>, ) { + let span = s.get_span(); + let res = match s { - typed::TypedStatement::Assembly(statements) => { - let statements = statements + typed::TypedStatement::Return(s) => vec![zir::ZirStatement::ret( + f.fold_expression(statements_buffer, s.inner), + )], + typed::TypedStatement::Assembly(s) => { + let statements = s + .inner .into_iter() .map(|s| f.fold_assembly_statement(statements_buffer, s)) .collect(); - vec![zir::ZirStatement::Assembly(statements)] + vec![zir::ZirStatement::assembly(statements)] } - typed::TypedStatement::Return(expression) => vec![zir::ZirStatement::Return( - f.fold_expression(statements_buffer, expression), - )], - typed::TypedStatement::Definition(a, typed::DefinitionRhs::Expression(e)) => { + typed::TypedStatement::Definition(typed::DefinitionStatement { + assignee: a, + rhs: typed::DefinitionRhs::Expression(e), + .. + }) => { let a = f.fold_assignee(a); let e = f.fold_expression(statements_buffer, e); assert_eq!(a.len(), e.len()); a.into_iter() .zip(e.into_iter()) - .map(|(a, e)| zir::ZirStatement::Definition(a, e)) + .map(|(a, e)| zir::ZirStatement::definition(a, e)) .collect() } - typed::TypedStatement::Assertion(e, error) => { - let e = f.fold_boolean_expression(statements_buffer, e); - let error = match error { + typed::TypedStatement::Assertion(s) => { + let e = f.fold_boolean_expression(statements_buffer, s.expression); + let error = match s.error { typed::RuntimeError::SourceAssertion(metadata) => { zir::RuntimeError::SourceAssertion(metadata) } typed::RuntimeError::SelectRangeCheck => zir::RuntimeError::SelectRangeCheck, typed::RuntimeError::DivisionByZero => zir::RuntimeError::DivisionByZero, }; - vec![zir::ZirStatement::Assertion(e, error)] + vec![zir::ZirStatement::assertion(e, error)] } - typed::TypedStatement::Definition( - assignee, - typed::DefinitionRhs::EmbedCall(embed_call), - ) => { + typed::TypedStatement::Definition(typed::DefinitionStatement { + assignee: a, + rhs: typed::DefinitionRhs::EmbedCall(embed_call), + .. + }) => { vec![zir::ZirStatement::MultipleDefinition( - f.fold_assignee(assignee), - zir::ZirExpressionList::EmbedCall( - embed_call.embed, - embed_call.generics, - embed_call - .arguments - .into_iter() - .flat_map(|a| f.fold_expression(statements_buffer, a)) - .collect(), + MultipleDefinitionStatement::new( + f.fold_assignee(a), + zir::ZirExpressionList::EmbedCall( + embed_call.embed, + embed_call.generics, + embed_call + .arguments + .into_iter() + .flat_map(|a| f.fold_expression(statements_buffer, a)) + .collect(), + ), ), )] } - typed::TypedStatement::Log(l, e) => vec![zir::ZirStatement::Log( - l, - e.into_iter() + typed::TypedStatement::Log(e) => vec![zir::ZirStatement::Log(LogStatement::new( + e.format_string, + e.expressions + .into_iter() .map(|e| { ( e.get_type().try_into().unwrap(), @@ -628,13 +666,11 @@ fn fold_statement<'ast, T: Field>( ) }) .collect(), - )], - typed::TypedStatement::PushCallLog(..) => vec![], - typed::TypedStatement::PopCallLog => vec![], + ))], typed::TypedStatement::For(..) => unreachable!(), }; - statements_buffer.extend(res); + statements_buffer.extend(res.into_iter().map(|s| s.span(span))); } fn fold_array_expression_inner<'ast, T: Field>( @@ -673,31 +709,32 @@ fn fold_array_expression_inner<'ast, T: Field>( typed::ArrayExpressionInner::Select(select) => { f.fold_select_expression(statements_buffer, select) } - typed::ArrayExpressionInner::Slice(box array, box from, box to) => { - let array = f.fold_array_expression(statements_buffer, array); - let from = f.fold_uint_expression(statements_buffer, from); - let to = f.fold_uint_expression(statements_buffer, to); + typed::ArrayExpressionInner::Slice(e) => { + let array = f.fold_array_expression(statements_buffer, *e.array); + let from = f.fold_uint_expression(statements_buffer, *e.from); + let to = f.fold_uint_expression(statements_buffer, *e.to); match (from.into_inner(), to.into_inner()) { (zir::UExpressionInner::Value(from), zir::UExpressionInner::Value(to)) => { - assert_eq!(size, to.saturating_sub(from) as u32); + assert_eq!(size, to.value.saturating_sub(from.value) as u32); let element_size = ty.get_primitive_count(); - let start = from as usize * element_size; - let end = to as usize * element_size; + let start = from.value as usize * element_size; + let end = to.value as usize * element_size; array[start..end].to_vec() } _ => unreachable!(), } } - typed::ArrayExpressionInner::Repeat(box e, box count) => { - let e = f.fold_expression(statements_buffer, e); - let count = f.fold_uint_expression(statements_buffer, count); + typed::ArrayExpressionInner::Repeat(r) => { + let e = f.fold_expression(statements_buffer, *r.e); + let count = f.fold_uint_expression(statements_buffer, *r.count); match count.into_inner() { - zir::UExpressionInner::Value(count) => { - vec![e; count as usize].into_iter().flatten().collect() - } + zir::UExpressionInner::Value(count) => vec![e; count.value as usize] + .into_iter() + .flatten() + .collect(), _ => unreachable!(), } } @@ -862,7 +899,7 @@ fn fold_select_expression<'ast, T: Field, E>( match index.as_inner() { zir::UExpressionInner::Value(v) => { - let v = *v as usize; + let v = v.value as usize; array[v * size..(v + 1) * size].to_vec() } @@ -927,6 +964,9 @@ fn fold_conditional_expression<'ast, T: Field, E: Flatten<'ast, T>>( statements_buffer: &mut Vec>, c: typed::ConditionalExpression<'ast, T, E>, ) -> Vec> { + let span = c.get_span(); + let condition_span = c.condition.get_span(); + let mut consequence_statements = vec![]; let mut alternative_statements = vec![]; @@ -937,11 +977,14 @@ fn fold_conditional_expression<'ast, T: Field, E: Flatten<'ast, T>>( assert_eq!(consequence.len(), alternative.len()); if !consequence_statements.is_empty() || !alternative_statements.is_empty() { - statements_buffer.push(zir::ZirStatement::IfElse( - condition.clone(), - consequence_statements, - alternative_statements, - )); + statements_buffer.push( + zir::ZirStatement::if_else( + condition.clone().span(condition_span), + consequence_statements, + alternative_statements, + ) + .span(span), + ); } use zokrates_ast::zir::Conditional; @@ -951,19 +994,46 @@ fn fold_conditional_expression<'ast, T: Field, E: Flatten<'ast, T>>( .zip(alternative.into_iter()) .map(|(c, a)| match (c, a) { (zir::ZirExpression::FieldElement(c), zir::ZirExpression::FieldElement(a)) => { - zir::FieldElementExpression::conditional(condition.clone(), c, a).into() + zir::FieldElementExpression::conditional(condition.clone(), c, a) + .span(span) + .into() } (zir::ZirExpression::Boolean(c), zir::ZirExpression::Boolean(a)) => { - zir::BooleanExpression::conditional(condition.clone(), c, a).into() + zir::BooleanExpression::conditional(condition.clone(), c, a) + .span(span) + .into() } (zir::ZirExpression::Uint(c), zir::ZirExpression::Uint(a)) => { - zir::UExpression::conditional(condition.clone(), c, a).into() + zir::UExpression::conditional(condition.clone(), c, a) + .span(span) + .into() } _ => unreachable!(), }) .collect() } +fn fold_binary_expression< + 'ast, + T: Field, + L: Flatten<'ast, T> + typed::Expr<'ast, T> + Basic<'ast, T>, + R: Flatten<'ast, T> + typed::Expr<'ast, T> + Basic<'ast, T>, + E: Flatten<'ast, T> + typed::Expr<'ast, T> + Basic<'ast, T>, + Op, +>( + f: &mut Flattener, + statements_buffer: &mut Vec>, + e: BinaryExpression, +) -> BinaryExpression { + let left_span = e.left.get_span(); + let right_span = e.left.get_span(); + + let left: L::ZirExpressionType = e.left.flatten(f, statements_buffer).pop().unwrap().into(); + let right: R::ZirExpressionType = e.right.flatten(f, statements_buffer).pop().unwrap().into(); + + BinaryExpression::new(left.span(left_span), right.span(right_span)).span(e.span) +} + fn fold_identifier_expression<'ast, T: Field, E: Expr<'ast, T>>( f: &mut Flattener, ty: E::ConcreteTy, @@ -977,77 +1047,56 @@ fn fold_field_expression<'ast, T: Field>( statements_buffer: &mut Vec>, e: typed::FieldElementExpression<'ast, T>, ) -> zir::FieldElementExpression<'ast, T> { + let span = e.get_span(); + match e { - typed::FieldElementExpression::Number(n) => zir::FieldElementExpression::Number(n), + typed::FieldElementExpression::Value(n) => zir::FieldElementExpression::Value(n), typed::FieldElementExpression::Identifier(id) => f .fold_identifier_expression(typed::ConcreteType::FieldElement, id) .pop() .unwrap() .try_into() .unwrap(), - typed::FieldElementExpression::Add(box e1, box e2) => { - let e1 = f.fold_field_expression(statements_buffer, e1); - let e2 = f.fold_field_expression(statements_buffer, e2); - zir::FieldElementExpression::Add(box e1, box e2) - } - typed::FieldElementExpression::Sub(box e1, box e2) => { - let e1 = f.fold_field_expression(statements_buffer, e1); - let e2 = f.fold_field_expression(statements_buffer, e2); - zir::FieldElementExpression::Sub(box e1, box e2) - } - typed::FieldElementExpression::Mult(box e1, box e2) => { - let e1 = f.fold_field_expression(statements_buffer, e1); - let e2 = f.fold_field_expression(statements_buffer, e2); - zir::FieldElementExpression::Mult(box e1, box e2) - } - typed::FieldElementExpression::Div(box e1, box e2) => { - let e1 = f.fold_field_expression(statements_buffer, e1); - let e2 = f.fold_field_expression(statements_buffer, e2); - zir::FieldElementExpression::Div(box e1, box e2) - } - typed::FieldElementExpression::Pow(box e1, box e2) => { - let e1 = f.fold_field_expression(statements_buffer, e1); - let e2 = f.fold_uint_expression(statements_buffer, e2); - zir::FieldElementExpression::Pow(box e1, box e2) - } - typed::FieldElementExpression::Neg(box e) => { - let e = f.fold_field_expression(statements_buffer, e); - - zir::FieldElementExpression::Sub( - box zir::FieldElementExpression::Number(T::zero()), - box e, - ) + typed::FieldElementExpression::Add(e) => { + zir::FieldElementExpression::Add(f.fold_binary_expression(statements_buffer, e)) } - typed::FieldElementExpression::Pos(box e) => f.fold_field_expression(statements_buffer, e), - typed::FieldElementExpression::Xor(box left, box right) => { - let left = f.fold_field_expression(statements_buffer, left); - let right = f.fold_field_expression(statements_buffer, right); - - zir::FieldElementExpression::Xor(box left, box right) + typed::FieldElementExpression::Sub(e) => { + zir::FieldElementExpression::Sub(f.fold_binary_expression(statements_buffer, e)) } - typed::FieldElementExpression::And(box left, box right) => { - let left = f.fold_field_expression(statements_buffer, left); - let right = f.fold_field_expression(statements_buffer, right); - - zir::FieldElementExpression::And(box left, box right) + typed::FieldElementExpression::Mult(e) => { + zir::FieldElementExpression::Mult(f.fold_binary_expression(statements_buffer, e)) } - typed::FieldElementExpression::Or(box left, box right) => { - let left = f.fold_field_expression(statements_buffer, left); - let right = f.fold_field_expression(statements_buffer, right); - - zir::FieldElementExpression::Or(box left, box right) + typed::FieldElementExpression::Div(e) => { + zir::FieldElementExpression::Div(f.fold_binary_expression(statements_buffer, e)) } - typed::FieldElementExpression::LeftShift(box e, box by) => { - let e = f.fold_field_expression(statements_buffer, e); - let by = f.fold_uint_expression(statements_buffer, by); - - zir::FieldElementExpression::LeftShift(box e, box by) + typed::FieldElementExpression::Pow(e) => { + zir::FieldElementExpression::Pow(f.fold_binary_expression(statements_buffer, e)) } - typed::FieldElementExpression::RightShift(box e, box by) => { - let e = f.fold_field_expression(statements_buffer, e); - let by = f.fold_uint_expression(statements_buffer, by); + typed::FieldElementExpression::And(e) => { + zir::FieldElementExpression::And(f.fold_binary_expression(statements_buffer, e)) + } + typed::FieldElementExpression::Or(e) => { + zir::FieldElementExpression::Or(f.fold_binary_expression(statements_buffer, e)) + } + typed::FieldElementExpression::Xor(e) => { + zir::FieldElementExpression::Xor(f.fold_binary_expression(statements_buffer, e)) + } + typed::FieldElementExpression::LeftShift(e) => { + zir::FieldElementExpression::LeftShift(f.fold_binary_expression(statements_buffer, e)) + } + typed::FieldElementExpression::RightShift(e) => { + zir::FieldElementExpression::RightShift(f.fold_binary_expression(statements_buffer, e)) + } + typed::FieldElementExpression::Neg(e) => { + let e = f.fold_field_expression(statements_buffer, *e.inner); - zir::FieldElementExpression::RightShift(box e, box by) + zir::FieldElementExpression::sub( + zir::FieldElementExpression::Value(ValueExpression::new(T::zero())), + e, + ) + } + typed::FieldElementExpression::Pos(e) => { + f.fold_field_expression(statements_buffer, *e.inner) } typed::FieldElementExpression::Conditional(c) => f .fold_conditional_expression(statements_buffer, c) @@ -1082,6 +1131,7 @@ fn fold_field_expression<'ast, T: Field>( f.fold_field_expression(statements_buffer, *block.value) } } + .span(span) } // util function to output a boolean expression representing the equality of two lists of ZirExpression. @@ -1090,27 +1140,32 @@ fn fold_field_expression<'ast, T: Field>( fn conjunction_tree<'ast, T: Field>( v: &[zir::ZirExpression<'ast, T>], w: &[zir::ZirExpression<'ast, T>], + span: Option, ) -> zir::BooleanExpression<'ast, T> { assert_eq!(v.len(), w.len()); match v.len() { - 0 => zir::BooleanExpression::Value(true), + 0 => zir::BooleanExpression::value(true), 1 => match (v[0].clone(), w[0].clone()) { (zir::ZirExpression::Boolean(v), zir::ZirExpression::Boolean(w)) => { - zir::BooleanExpression::BoolEq(box v, box w) + zir::BooleanExpression::bool_eq(v, w).span(span) } (zir::ZirExpression::FieldElement(v), zir::ZirExpression::FieldElement(w)) => { - zir::BooleanExpression::FieldEq(box v, box w) + zir::BooleanExpression::field_eq(v, w).span(span) } (zir::ZirExpression::Uint(v), zir::ZirExpression::Uint(w)) => { - zir::BooleanExpression::UintEq(box v, box w) + zir::BooleanExpression::uint_eq(v, w).span(span) } _ => unreachable!(), }, n => { let (x0, y0) = v.split_at(n / 2); let (x1, y1) = w.split_at(n / 2); - zir::BooleanExpression::And(box conjunction_tree(x0, x1), box conjunction_tree(y0, y1)) + zir::BooleanExpression::bitand( + conjunction_tree(x0, x1, span), + conjunction_tree(y0, y1, span), + ) + .span(span) } } } @@ -1118,11 +1173,18 @@ fn conjunction_tree<'ast, T: Field>( fn fold_eq_expression<'ast, T: Field, E: Flatten<'ast, T>>( f: &mut Flattener, statements_buffer: &mut Vec>, - e: typed::EqExpression, + e: zokrates_ast::common::expressions::BinaryExpression< + OpEq, + E, + E, + typed::BooleanExpression<'ast, T>, + >, ) -> zir::BooleanExpression<'ast, T> { + let span = e.get_span(); + let left = e.left.flatten(f, statements_buffer); let right = e.right.flatten(f, statements_buffer); - conjunction_tree(&left, &right) + conjunction_tree(&left, &right, span) } fn fold_boolean_expression<'ast, T: Field>( @@ -1130,6 +1192,8 @@ fn fold_boolean_expression<'ast, T: Field>( statements_buffer: &mut Vec>, e: typed::BooleanExpression<'ast, T>, ) -> zir::BooleanExpression<'ast, T> { + let span = e.get_span(); + match e { typed::BooleanExpression::Block(block) => { block @@ -1151,59 +1215,26 @@ fn fold_boolean_expression<'ast, T: Field>( typed::BooleanExpression::StructEq(e) => f.fold_eq_expression(statements_buffer, e), typed::BooleanExpression::TupleEq(e) => f.fold_eq_expression(statements_buffer, e), typed::BooleanExpression::UintEq(e) => f.fold_eq_expression(statements_buffer, e), - typed::BooleanExpression::FieldLt(box e1, box e2) => { - let e1 = f.fold_field_expression(statements_buffer, e1); - let e2 = f.fold_field_expression(statements_buffer, e2); - zir::BooleanExpression::FieldLt(box e1, box e2) - } - typed::BooleanExpression::FieldLe(box e1, box e2) => { - let e1 = f.fold_field_expression(statements_buffer, e1); - let e2 = f.fold_field_expression(statements_buffer, e2); - zir::BooleanExpression::FieldLe(box e1, box e2) - } - typed::BooleanExpression::FieldGt(box e1, box e2) => { - let e1 = f.fold_field_expression(statements_buffer, e1); - let e2 = f.fold_field_expression(statements_buffer, e2); - zir::BooleanExpression::FieldLt(box e2, box e1) - } - typed::BooleanExpression::FieldGe(box e1, box e2) => { - let e1 = f.fold_field_expression(statements_buffer, e1); - let e2 = f.fold_field_expression(statements_buffer, e2); - zir::BooleanExpression::FieldLe(box e2, box e1) - } - typed::BooleanExpression::UintLt(box e1, box e2) => { - let e1 = f.fold_uint_expression(statements_buffer, e1); - let e2 = f.fold_uint_expression(statements_buffer, e2); - zir::BooleanExpression::UintLt(box e1, box e2) - } - typed::BooleanExpression::UintLe(box e1, box e2) => { - let e1 = f.fold_uint_expression(statements_buffer, e1); - let e2 = f.fold_uint_expression(statements_buffer, e2); - zir::BooleanExpression::UintLe(box e1, box e2) - } - typed::BooleanExpression::UintGt(box e1, box e2) => { - let e1 = f.fold_uint_expression(statements_buffer, e1); - let e2 = f.fold_uint_expression(statements_buffer, e2); - zir::BooleanExpression::UintLt(box e2, box e1) - } - typed::BooleanExpression::UintGe(box e1, box e2) => { - let e1 = f.fold_uint_expression(statements_buffer, e1); - let e2 = f.fold_uint_expression(statements_buffer, e2); - zir::BooleanExpression::UintLe(box e2, box e1) - } - typed::BooleanExpression::Or(box e1, box e2) => { - let e1 = f.fold_boolean_expression(statements_buffer, e1); - let e2 = f.fold_boolean_expression(statements_buffer, e2); - zir::BooleanExpression::Or(box e1, box e2) - } - typed::BooleanExpression::And(box e1, box e2) => { - let e1 = f.fold_boolean_expression(statements_buffer, e1); - let e2 = f.fold_boolean_expression(statements_buffer, e2); - zir::BooleanExpression::And(box e1, box e2) - } - typed::BooleanExpression::Not(box e) => { - let e = f.fold_boolean_expression(statements_buffer, e); - zir::BooleanExpression::Not(box e) + typed::BooleanExpression::FieldLt(e) => { + zir::BooleanExpression::FieldLt(f.fold_binary_expression(statements_buffer, e)) + } + typed::BooleanExpression::FieldLe(e) => { + zir::BooleanExpression::FieldLe(f.fold_binary_expression(statements_buffer, e)) + } + typed::BooleanExpression::UintLt(e) => { + zir::BooleanExpression::UintLt(f.fold_binary_expression(statements_buffer, e)) + } + typed::BooleanExpression::UintLe(e) => { + zir::BooleanExpression::UintLe(f.fold_binary_expression(statements_buffer, e)) + } + typed::BooleanExpression::Or(e) => { + zir::BooleanExpression::Or(f.fold_binary_expression(statements_buffer, e)) + } + typed::BooleanExpression::And(e) => { + zir::BooleanExpression::And(f.fold_binary_expression(statements_buffer, e)) + } + typed::BooleanExpression::Not(e) => { + zir::BooleanExpression::not(f.fold_boolean_expression(statements_buffer, *e.inner)) } typed::BooleanExpression::Conditional(c) => f .fold_conditional_expression(statements_buffer, c) @@ -1231,6 +1262,7 @@ fn fold_boolean_expression<'ast, T: Field>( .try_into() .unwrap(), } + .span(span) } fn fold_uint_expression<'ast, T: Field>( @@ -1238,8 +1270,10 @@ fn fold_uint_expression<'ast, T: Field>( statements_buffer: &mut Vec>, e: typed::UExpression<'ast, T>, ) -> zir::UExpression<'ast, T> { + let span = e.get_span(); f.fold_uint_expression_inner(statements_buffer, e.bitwidth, e.inner) .annotate(e.bitwidth.to_usize()) + .span(span) } fn fold_uint_expression_inner<'ast, T: Field>( @@ -1248,6 +1282,8 @@ fn fold_uint_expression_inner<'ast, T: Field>( bitwidth: UBitwidth, e: typed::UExpressionInner<'ast, T>, ) -> zir::UExpressionInner<'ast, T> { + let span = e.get_span(); + match e { typed::UExpressionInner::Block(block) => { block @@ -1263,95 +1299,83 @@ fn fold_uint_expression_inner<'ast, T: Field>( .unwrap() .into_inner() } - typed::UExpressionInner::Add(box left, box right) => { - let left = f.fold_uint_expression(statements_buffer, left); - let right = f.fold_uint_expression(statements_buffer, right); + typed::UExpressionInner::Add(e) => { + let left = f.fold_uint_expression(statements_buffer, *e.left); + let right = f.fold_uint_expression(statements_buffer, *e.right); - zir::UExpressionInner::Add(box left, box right) + zir::UExpression::add(left, right).into_inner() } - typed::UExpressionInner::Sub(box left, box right) => { - let left = f.fold_uint_expression(statements_buffer, left); - let right = f.fold_uint_expression(statements_buffer, right); + typed::UExpressionInner::Sub(e) => { + let left = f.fold_uint_expression(statements_buffer, *e.left); + let right = f.fold_uint_expression(statements_buffer, *e.right); - zir::UExpressionInner::Sub(box left, box right) + zir::UExpression::sub(left, right).into_inner() } typed::UExpressionInner::FloorSub(..) => unreachable!(), - typed::UExpressionInner::Mult(box left, box right) => { - let left = f.fold_uint_expression(statements_buffer, left); - let right = f.fold_uint_expression(statements_buffer, right); + typed::UExpressionInner::Mult(e) => { + let left = f.fold_uint_expression(statements_buffer, *e.left); + let right = f.fold_uint_expression(statements_buffer, *e.right); - zir::UExpressionInner::Mult(box left, box right) + zir::UExpression::mult(left, right).into_inner() } - typed::UExpressionInner::Div(box left, box right) => { - let left = f.fold_uint_expression(statements_buffer, left); - let right = f.fold_uint_expression(statements_buffer, right); + typed::UExpressionInner::Div(e) => { + let left = f.fold_uint_expression(statements_buffer, *e.left); + let right = f.fold_uint_expression(statements_buffer, *e.right); - zir::UExpressionInner::Div(box left, box right) + zir::UExpression::div(left, right).into_inner() } - typed::UExpressionInner::Rem(box left, box right) => { - let left = f.fold_uint_expression(statements_buffer, left); - let right = f.fold_uint_expression(statements_buffer, right); + typed::UExpressionInner::Rem(e) => { + let left = f.fold_uint_expression(statements_buffer, *e.left); + let right = f.fold_uint_expression(statements_buffer, *e.right); - zir::UExpressionInner::Rem(box left, box right) + zir::UExpression::rem(left, right).into_inner() } - typed::UExpressionInner::Xor(box left, box right) => { - let left = f.fold_uint_expression(statements_buffer, left); - let right = f.fold_uint_expression(statements_buffer, right); + typed::UExpressionInner::Xor(e) => { + let left = f.fold_uint_expression(statements_buffer, *e.left); + let right = f.fold_uint_expression(statements_buffer, *e.right); - zir::UExpressionInner::Xor(box left, box right) + zir::UExpression::xor(left, right).into_inner() } - typed::UExpressionInner::And(box left, box right) => { - let left = f.fold_uint_expression(statements_buffer, left); - let right = f.fold_uint_expression(statements_buffer, right); + typed::UExpressionInner::And(e) => { + let left = f.fold_uint_expression(statements_buffer, *e.left); + let right = f.fold_uint_expression(statements_buffer, *e.right); - zir::UExpressionInner::And(box left, box right) + zir::UExpression::and(left, right).into_inner() } - typed::UExpressionInner::Or(box left, box right) => { - let left = f.fold_uint_expression(statements_buffer, left); - let right = f.fold_uint_expression(statements_buffer, right); + typed::UExpressionInner::Or(e) => { + let left = f.fold_uint_expression(statements_buffer, *e.left); + let right = f.fold_uint_expression(statements_buffer, *e.right); - zir::UExpressionInner::Or(box left, box right) + zir::UExpression::or(left, right).into_inner() } - typed::UExpressionInner::LeftShift(box e, box by) => { - let e = f.fold_uint_expression(statements_buffer, e); - - let by = match by.as_inner() { - typed::UExpressionInner::Value(by) => by, - _ => unreachable!("static analysis should have made sure that this is constant"), - }; + typed::UExpressionInner::LeftShift(e) => { + let left = f.fold_uint_expression(statements_buffer, *e.left); + let right = f.fold_uint_expression(statements_buffer, *e.right); - zir::UExpressionInner::LeftShift(box e, *by as u32) + zir::UExpression::left_shift(left, right).into_inner() } - typed::UExpressionInner::RightShift(box e, box by) => { - let e = f.fold_uint_expression(statements_buffer, e); - - let by = match by.as_inner() { - typed::UExpressionInner::Value(by) => by, - _ => unreachable!("static analysis should have made sure that this is constant"), - }; + typed::UExpressionInner::RightShift(e) => { + let left = f.fold_uint_expression(statements_buffer, *e.left); + let right = f.fold_uint_expression(statements_buffer, *e.right); - zir::UExpressionInner::RightShift(box e, *by as u32) + zir::UExpression::right_shift(left, right).into_inner() } - typed::UExpressionInner::Not(box e) => { - let e = f.fold_uint_expression(statements_buffer, e); - - zir::UExpressionInner::Not(box e) + typed::UExpressionInner::Not(e) => { + zir::UExpression::not(f.fold_uint_expression(statements_buffer, *e.inner)).into_inner() } - typed::UExpressionInner::Neg(box e) => { - let bitwidth = e.bitwidth(); + typed::UExpressionInner::Neg(e) => { + let bitwidth = e.inner.bitwidth(); f.fold_uint_expression( statements_buffer, - typed::UExpressionInner::Value(0).annotate(bitwidth) - e, + typed::UExpression::value(0).annotate(bitwidth) - *e.inner, ) .into_inner() } - typed::UExpressionInner::Pos(box e) => { - let e = f.fold_uint_expression(statements_buffer, e); - - e.into_inner() - } + typed::UExpressionInner::Pos(e) => f + .fold_uint_expression(statements_buffer, *e.inner) + .into_inner(), typed::UExpressionInner::FunctionCall(..) => { unreachable!("function calls should have been removed") } @@ -1384,6 +1408,7 @@ fn fold_uint_expression_inner<'ast, T: Field>( .unwrap() .into_inner(), } + .span(span) } fn fold_function<'ast, T: Field>( @@ -1420,6 +1445,7 @@ fn fold_array_expression<'ast, T: Field>( statements_buffer: &mut Vec>, e: typed::ArrayExpression<'ast, T>, ) -> Vec> { + let span = e.get_span(); let size: u32 = e.size().try_into().unwrap(); f.fold_array_expression_inner( statements_buffer, @@ -1427,6 +1453,9 @@ fn fold_array_expression<'ast, T: Field>( size, e.into_inner(), ) + .into_iter() + .map(|e| e.span(span)) + .collect() } fn fold_struct_expression<'ast, T: Field>( @@ -1434,11 +1463,15 @@ fn fold_struct_expression<'ast, T: Field>( statements_buffer: &mut Vec>, e: typed::StructExpression<'ast, T>, ) -> Vec> { + let span = e.get_span(); f.fold_struct_expression_inner( statements_buffer, typed::types::ConcreteStructType::try_from(e.ty().clone()).unwrap(), e.into_inner(), ) + .into_iter() + .map(|e| e.span(span)) + .collect() } fn fold_tuple_expression<'ast, T: Field>( @@ -1446,11 +1479,15 @@ fn fold_tuple_expression<'ast, T: Field>( statements_buffer: &mut Vec>, e: typed::TupleExpression<'ast, T>, ) -> Vec> { + let span = e.get_span(); f.fold_tuple_expression_inner( statements_buffer, typed::types::ConcreteTupleType::try_from(e.ty().clone()).unwrap(), e.into_inner(), ) + .into_iter() + .map(|e| e.span(span)) + .collect() } fn fold_program<'ast, T: Field>( @@ -1471,5 +1508,6 @@ fn fold_program<'ast, T: Field>( zir::ZirProgram { main: f.fold_function(main_function), + module_map: p.module_map, } } diff --git a/zokrates_analysis/src/lib.rs b/zokrates_analysis/src/lib.rs index c628e7283..2cf0c24fc 100644 --- a/zokrates_analysis/src/lib.rs +++ b/zokrates_analysis/src/lib.rs @@ -1,5 +1,3 @@ -#![feature(box_patterns, box_syntax)] - //! Module containing static analysis //! //! @file mod.rs @@ -161,10 +159,6 @@ pub fn analyse<'ast, T: Field>( let r = reduce_program(r).map_err(Error::from)?; log::trace!("\n{}", r); - log::debug!("Static analyser: Propagate"); - let r = Propagator::propagate(r)?; - log::trace!("\n{}", r); - log::debug!("Static analyser: Concretize structs"); let r = StructConcretizer::concretize(r); log::trace!("\n{}", r); diff --git a/zokrates_analysis/src/log_ignorer.rs b/zokrates_analysis/src/log_ignorer.rs index a5a8cd54e..2c8aa5a8c 100644 --- a/zokrates_analysis/src/log_ignorer.rs +++ b/zokrates_analysis/src/log_ignorer.rs @@ -1,4 +1,4 @@ -use zokrates_ast::typed::{folder::*, TypedProgram, TypedStatement}; +use zokrates_ast::typed::{folder::*, LogStatement, TypedProgram, TypedStatement}; use zokrates_field::Field; #[derive(Default)] @@ -11,10 +11,7 @@ impl LogIgnorer { } impl<'ast, T: Field> Folder<'ast, T> for LogIgnorer { - fn fold_statement(&mut self, s: TypedStatement<'ast, T>) -> Vec> { - match s { - TypedStatement::Log(..) => vec![], - s => fold_statement(self, s), - } + fn fold_log_statement(&mut self, _: LogStatement<'ast, T>) -> Vec> { + vec![] } } diff --git a/zokrates_analysis/src/out_of_bounds.rs b/zokrates_analysis/src/out_of_bounds.rs index 7cdc88b6c..7ed8613a7 100644 --- a/zokrates_analysis/src/out_of_bounds.rs +++ b/zokrates_analysis/src/out_of_bounds.rs @@ -46,29 +46,29 @@ impl<'ast, T: Field> ResultFolder<'ast, T> for OutOfBoundsChecker { a: TypedAssignee<'ast, T>, ) -> Result, Error> { match a { - TypedAssignee::Select(box array, box index) => { + TypedAssignee::Select(array, index) => { use zokrates_ast::typed::Typed; - let array = self.fold_assignee(array)?; + let array = self.fold_assignee(*array)?; let size = match array.get_type() { Type::Array(array_ty) => match array_ty.size.as_inner() { - UExpressionInner::Value(size) => *size, + UExpressionInner::Value(size) => size.value, _ => unreachable!(), }, _ => unreachable!(), }; match index.as_inner() { - UExpressionInner::Value(i) if i >= &size => Err(Error(format!( + UExpressionInner::Value(i) if i.value >= size => Err(Error(format!( "Out of bounds write to `{}` because `{}` has size {}", - TypedAssignee::Select(box array.clone(), box index), + TypedAssignee::select(array.clone(), *index), array, size ))), - _ => Ok(TypedAssignee::Select( - box self.fold_assignee(array)?, - box self.fold_uint_expression(index)?, + _ => Ok(TypedAssignee::select( + array, + self.fold_uint_expression(*index)?, )), } } diff --git a/zokrates_analysis/src/panic_extractor.rs b/zokrates_analysis/src/panic_extractor.rs index d17675a83..dd2628cd5 100644 --- a/zokrates_analysis/src/panic_extractor.rs +++ b/zokrates_analysis/src/panic_extractor.rs @@ -1,6 +1,11 @@ -use zokrates_ast::zir::{ - folder::*, BooleanExpression, Conditional, ConditionalExpression, ConditionalOrExpression, - FieldElementExpression, RuntimeError, UBitwidth, UExpressionInner, ZirProgram, ZirStatement, +use std::ops::*; +use zokrates_ast::{ + common::{Fold, WithSpan}, + zir::{ + folder::*, BooleanExpression, Conditional, ConditionalExpression, ConditionalOrExpression, + Expr, FieldElementExpression, IfElseStatement, RuntimeError, UBitwidth, UExpression, + UExpressionInner, ZirProgram, ZirStatement, + }, }; use zokrates_field::Field; @@ -18,67 +23,85 @@ impl<'ast, T: Field> PanicExtractor<'ast, T> { } impl<'ast, T: Field> Folder<'ast, T> for PanicExtractor<'ast, T> { - fn fold_statement(&mut self, s: ZirStatement<'ast, T>) -> Vec> { + fn fold_if_else_statement( + &mut self, + s: IfElseStatement<'ast, T>, + ) -> Vec> { + let condition = self.fold_boolean_expression(s.condition); + let mut consequence_extractor = Self::default(); + let consequence = s + .consequence + .into_iter() + .flat_map(|s| consequence_extractor.fold_statement(s)) + .collect(); + assert!(consequence_extractor.panic_buffer.is_empty()); + let mut alternative_extractor = Self::default(); + let alternative = s + .alternative + .into_iter() + .flat_map(|s| alternative_extractor.fold_statement(s)) + .collect(); + assert!(alternative_extractor.panic_buffer.is_empty()); + + self.panic_buffer + .drain(..) + .chain(std::iter::once(ZirStatement::if_else( + condition, + consequence, + alternative, + ))) + .collect() + } + + fn fold_statement_cases(&mut self, s: ZirStatement<'ast, T>) -> Vec> { match s { - ZirStatement::IfElse(condition, consequence, alternative) => { - let condition = self.fold_boolean_expression(condition); - let mut consequence_extractor = Self::default(); - let consequence = consequence - .into_iter() - .flat_map(|s| consequence_extractor.fold_statement(s)) - .collect(); - assert!(consequence_extractor.panic_buffer.is_empty()); - let mut alternative_extractor = Self::default(); - let alternative = alternative - .into_iter() - .flat_map(|s| alternative_extractor.fold_statement(s)) - .collect(); - assert!(alternative_extractor.panic_buffer.is_empty()); - - self.panic_buffer - .drain(..) - .chain(std::iter::once(ZirStatement::IfElse( - condition, - consequence, - alternative, - ))) - .collect() - } + ZirStatement::IfElse(s) => self.fold_if_else_statement(s), s => { - let s = fold_statement(self, s); + let s = fold_statement_cases(self, s); self.panic_buffer.drain(..).chain(s).collect() } } } - fn fold_field_expression( + fn fold_field_expression_cases( &mut self, e: FieldElementExpression<'ast, T>, ) -> FieldElementExpression<'ast, T> { + let span = e.get_span(); + match e { - FieldElementExpression::Div(box n, box d) => { - let n = self.fold_field_expression(n); - let d = self.fold_field_expression(d); - self.panic_buffer.push(ZirStatement::Assertion( - BooleanExpression::Not(box BooleanExpression::FieldEq( - box d.clone(), - box FieldElementExpression::Number(T::zero()), - )), - RuntimeError::DivisionByZero, - )); - FieldElementExpression::Div(box n, box d) + FieldElementExpression::Div(e) => { + let n = self.fold_field_expression(*e.left); + let d = self.fold_field_expression(*e.right); + self.panic_buffer.push( + ZirStatement::assertion( + BooleanExpression::not( + BooleanExpression::field_eq( + d.clone().span(span), + FieldElementExpression::value(T::zero()).span(span), + ) + .span(span), + ) + .span(span), + RuntimeError::DivisionByZero, + ) + .span(span), + ); + FieldElementExpression::div(n, d) } - e => fold_field_expression(self, e), + e => fold_field_expression_cases(self, e), } } fn fold_conditional_expression< - E: zokrates_ast::zir::Expr<'ast, T> + Fold<'ast, T> + Conditional<'ast, T>, + E: zokrates_ast::zir::Expr<'ast, T> + Fold + Conditional<'ast, T>, >( &mut self, _: &E::Ty, e: ConditionalExpression<'ast, T, E>, ) -> ConditionalOrExpression<'ast, T, E> { + let span = e.get_span(); + let condition = self.fold_boolean_expression(*e.condition); let mut consequence_extractor = Self::default(); let consequence = e.consequence.fold(&mut consequence_extractor); @@ -89,62 +112,72 @@ impl<'ast, T: Field> Folder<'ast, T> for PanicExtractor<'ast, T> { let alternative_panics: Vec<_> = alternative_extractor.panic_buffer.drain(..).collect(); if !(consequence_panics.is_empty() && alternative_panics.is_empty()) { - self.panic_buffer.push(ZirStatement::IfElse( - condition.clone(), - consequence_panics, - alternative_panics, - )); + self.panic_buffer.push( + ZirStatement::if_else(condition.clone(), consequence_panics, alternative_panics) + .span(span), + ); } - ConditionalOrExpression::Conditional(ConditionalExpression::new( - condition, - consequence, - alternative, - )) + ConditionalOrExpression::Conditional( + ConditionalExpression::new(condition, consequence, alternative).span(span), + ) } - fn fold_uint_expression_inner( + fn fold_uint_expression_cases( &mut self, b: UBitwidth, e: UExpressionInner<'ast, T>, ) -> UExpressionInner<'ast, T> { + let span = e.get_span(); + match e { - UExpressionInner::Div(box n, box d) => { - let n = self.fold_uint_expression(n); - let d = self.fold_uint_expression(d); - self.panic_buffer.push(ZirStatement::Assertion( - BooleanExpression::Not(box BooleanExpression::UintEq( - box d.clone(), - box UExpressionInner::Value(0).annotate(b), - )), - RuntimeError::DivisionByZero, - )); - UExpressionInner::Div(box n, box d) + UExpressionInner::Div(e) => { + let n = self.fold_uint_expression(*e.left); + let d = self.fold_uint_expression(*e.right); + self.panic_buffer.push( + ZirStatement::assertion( + BooleanExpression::not( + BooleanExpression::uint_eq( + d.clone().span(span), + UExpression::value(0).annotate(b).span(span), + ) + .span(span), + ) + .span(span), + RuntimeError::DivisionByZero, + ) + .span(span), + ); + UExpression::div(n, d).into_inner() } - e => fold_uint_expression_inner(self, b, e), + e => fold_uint_expression_cases(self, b, e), } } - fn fold_boolean_expression( + fn fold_boolean_expression_cases( &mut self, e: BooleanExpression<'ast, T>, ) -> BooleanExpression<'ast, T> { match e { // constant range checks are complete, so no panic needs to be extracted - e @ BooleanExpression::FieldLt(box FieldElementExpression::Number(_), _) - | e @ BooleanExpression::FieldLt(_, box FieldElementExpression::Number(_)) => { - fold_boolean_expression(self, e) + BooleanExpression::FieldLt(b) + if matches!(b.left.as_ref(), FieldElementExpression::Value(_)) + || matches!(b.right.as_ref(), FieldElementExpression::Value(_)) => + { + fold_boolean_expression_cases(self, BooleanExpression::FieldLt(b)) } - BooleanExpression::FieldLt(box left, box right) => { - let left = self.fold_field_expression(left); - let right = self.fold_field_expression(right); + BooleanExpression::FieldLt(e) => { + let span = e.get_span(); + + let left = self.fold_field_expression(*e.left); + let right = self.fold_field_expression(*e.right); let bit_width = T::get_required_bits(); let safe_width = bit_width - 2; // dynamic comparison is not complete, it only applies to field elements whose difference is strictly smaller than 2**(bitwidth - 2) - let offset = FieldElementExpression::Number(T::from(2).pow(safe_width)); - let max = FieldElementExpression::Number(T::from(2).pow(safe_width + 1)); + let offset = FieldElementExpression::number(T::from(2).pow(safe_width)); + let max = FieldElementExpression::number(T::from(2).pow(safe_width + 1)); // `|left - right|` must be of bitwidth at most `safe_bitwidth` // this means we need to guarantee the following: `-2**(safe_width) < left - right < 2**(safe_width)` @@ -153,26 +186,40 @@ impl<'ast, T: Field> Folder<'ast, T> for PanicExtractor<'ast, T> { // we split this check in two: // `2**(safe_width) + left - right < 2**(safe_width + 1)` - self.panic_buffer.push(ZirStatement::Assertion( - BooleanExpression::FieldLt( - box FieldElementExpression::Add( - box offset.clone(), - box FieldElementExpression::Sub(box left.clone(), box right.clone()), - ), - box max, - ), - RuntimeError::IncompleteDynamicRange, - )); + self.panic_buffer.push( + ZirStatement::assertion( + BooleanExpression::field_lt( + offset.clone().span(span) + + FieldElementExpression::sub(left.clone(), right.clone()) + .span(span), + max, + ) + .span(span), + RuntimeError::IncompleteDynamicRange, + ) + .span(span), + ); // and // `2**(safe_width) + left - right != 0` - self.panic_buffer.push(ZirStatement::Assertion( - BooleanExpression::Not(box BooleanExpression::FieldEq( - box FieldElementExpression::Sub(box right.clone(), box left.clone()), - box offset, - )), - RuntimeError::IncompleteDynamicRange, - )); + self.panic_buffer.push( + ZirStatement::assertion( + BooleanExpression::not( + BooleanExpression::field_eq( + FieldElementExpression::sub( + right.clone().span(span), + left.clone().span(span), + ) + .span(span), + offset.span(span), + ) + .span(span), + ) + .span(span), + RuntimeError::IncompleteDynamicRange, + ) + .span(span), + ); // NOTE: // instead of splitting the check in two, we could have used a single `Lt` here, by simply subtracting 1 from all sides: @@ -182,9 +229,9 @@ impl<'ast, T: Field> Folder<'ast, T> for PanicExtractor<'ast, T> { // if we use `x - 1` here, we end up having to calculate the bits of both `x` and `x - 1`, which is expensive // by splitting, we can reuse the bits of `x` needed for this completeness check when computing the result - BooleanExpression::FieldLt(box left, box right) + BooleanExpression::field_lt(left, right) } - e => fold_boolean_expression(self, e), + e => fold_boolean_expression_cases(self, e), } } } diff --git a/zokrates_analysis/src/propagation.rs b/zokrates_analysis/src/propagation.rs index b7e5c0a17..03c98c38b 100644 --- a/zokrates_analysis/src/propagation.rs +++ b/zokrates_analysis/src/propagation.rs @@ -12,8 +12,13 @@ use num_bigint::BigUint; use std::collections::HashMap; use std::convert::{TryFrom, TryInto}; use std::fmt; +use std::ops::*; use std::ops::{BitAnd, BitOr, BitXor, Shl, Shr, Sub}; -use zokrates_ast::common::FlatEmbed; +use zokrates_ast::common::expressions::{ + BinaryExpression, BinaryOrExpression, EqExpression, ValueExpression, +}; +use zokrates_ast::common::operators::OpEq; +use zokrates_ast::common::{FlatEmbed, ResultFold, WithSpan}; use zokrates_ast::typed::result_folder::*; use zokrates_ast::typed::types::Type; use zokrates_ast::typed::*; @@ -27,6 +32,8 @@ pub enum Error { AssertionFailed(RuntimeError), InvalidValue(String), OutOfBounds(u128, u128), + VariableLength(String), + DivisionByZero, } impl fmt::Display for Error { @@ -40,29 +47,28 @@ impl fmt::Display for Error { "Out of bounds index ({} >= {}) found during static analysis", index, size ), + Error::VariableLength(message) => write!(f, "{}", message), + Error::DivisionByZero => { + write!(f, "Division by zero detected during static analysis",) + } } } } -#[derive(Debug)] -pub struct Propagator<'ast, 'a, T: Field> { +#[derive(Debug, Default)] +pub struct Propagator<'ast, T> { // 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: &'a mut Constants<'ast, T>, + pub constants: Constants<'ast, T>, } -impl<'ast, 'a, T: Field> Propagator<'ast, 'a, T> { - pub fn with_constants(constants: &'a mut Constants<'ast, T>) -> Self { - Propagator { constants } - } - +impl<'ast, T: Field> Propagator<'ast, T> { pub fn propagate(p: TypedProgram<'ast, T>) -> Result, Error> { - let mut constants = Constants::new(); + Propagator::default().fold_program(p) + } - Propagator { - constants: &mut constants, - } - .fold_program(p) + pub fn clear_call_frame(&mut self, frame: usize) { + self.constants.retain(|id, _| id.id.frame != frame); } // get a mutable reference to the constant corresponding to a given assignee if any, otherwise @@ -77,30 +83,28 @@ impl<'ast, 'a, T: Field> Propagator<'ast, 'a, T> { .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((variable, constant)) => match index.as_inner() { - UExpressionInner::Value(n) => match constant { - TypedExpression::Array(a) => match a.as_inner_mut() { - ArrayExpressionInner::Value(value) => { - match value.0.get_mut(*n as usize) { - Some(TypedExpressionOrSpread::Expression(ref mut e)) => { - Ok((variable, e)) - } - None => Err(variable), - _ => unreachable!(), + TypedAssignee::Select(assignee, index) => match self.try_get_constant_mut(assignee) { + Ok((variable, constant)) => match index.as_inner() { + UExpressionInner::Value(n) => match constant { + TypedExpression::Array(a) => match a.as_inner_mut() { + ArrayExpressionInner::Value(value) => { + match value.value.get_mut(n.value as usize) { + Some(TypedExpressionOrSpread::Expression(ref mut e)) => { + Ok((variable, e)) } + None => Err(variable), + _ => unreachable!(), } - _ => unreachable!("should be an array value"), - }, - _ => unreachable!("should be an array expression"), + } + _ => unreachable!("should be an array value"), }, - _ => Err(variable), + _ => unreachable!("should be an array expression"), }, - e => e, - } - } - TypedAssignee::Member(box assignee, m) => match self.try_get_constant_mut(assignee) { + _ => Err(variable), + }, + e => e, + }, + TypedAssignee::Member(assignee, m) => match self.try_get_constant_mut(assignee) { Ok((v, c)) => { let ty = assignee.get_type(); @@ -115,7 +119,7 @@ impl<'ast, 'a, T: Field> Propagator<'ast, 'a, T> { match c { TypedExpression::Struct(a) => match a.as_inner_mut() { - StructExpressionInner::Value(value) => Ok((v, &mut value[index])), + StructExpressionInner::Value(value) => Ok((v, &mut value.value[index])), _ => unreachable!("should be a struct value"), }, _ => unreachable!("should be a struct expression"), @@ -123,25 +127,23 @@ impl<'ast, 'a, T: Field> Propagator<'ast, 'a, T> { } e => e, }, - TypedAssignee::Element(box assignee, index) => { - match self.try_get_constant_mut(assignee) { - Ok((v, c)) => match c { - TypedExpression::Tuple(a) => match a.as_inner_mut() { - TupleExpressionInner::Value(value) => { - Ok((v, &mut value[*index as usize])) - } - _ => unreachable!("should be a tuple value"), - }, - _ => unreachable!("should be a tuple expression"), + TypedAssignee::Element(assignee, index) => match self.try_get_constant_mut(assignee) { + Ok((v, c)) => match c { + TypedExpression::Tuple(a) => match a.as_inner_mut() { + TupleExpressionInner::Value(value) => { + Ok((v, &mut value.value[*index as usize])) + } + _ => unreachable!("should be a tuple value"), }, - e => e, - } - } + _ => unreachable!("should be a tuple expression"), + }, + e => e, + }, } } } -impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> { +impl<'ast, T: Field> ResultFolder<'ast, T> for Propagator<'ast, T> { type Error = Error; fn fold_program(&mut self, p: TypedProgram<'ast, T>) -> Result, Error> { @@ -159,7 +161,7 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> { } }) .collect::>()?, - main: p.main, + ..p }) } @@ -177,133 +179,117 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> { } fn fold_conditional_expression< - E: Expr<'ast, T> + Conditional<'ast, T> + PartialEq + ResultFold<'ast, T>, + E: Expr<'ast, T> + Conditional<'ast, T> + PartialEq + ResultFold, >( &mut self, _: &E::Ty, e: ConditionalExpression<'ast, T, E>, ) -> Result, Self::Error> { - Ok( - match ( - self.fold_boolean_expression(*e.condition)?, - e.consequence.fold(self)?, - e.alternative.fold(self)?, - ) { - (BooleanExpression::Value(true), consequence, _) => { - ConditionalOrExpression::Expression(consequence.into_inner()) - } - (BooleanExpression::Value(false), _, alternative) => { - ConditionalOrExpression::Expression(alternative.into_inner()) - } - (_, consequence, alternative) if consequence == alternative => { + Ok(match self.fold_boolean_expression(*e.condition)? { + BooleanExpression::Value(v) if v.value => { + ConditionalOrExpression::Expression(e.consequence.fold(self)?.into_inner()) + } + BooleanExpression::Value(v) if !v.value => { + ConditionalOrExpression::Expression(e.alternative.fold(self)?.into_inner()) + } + condition => match (e.consequence.fold(self)?, e.alternative.fold(self)?) { + (consequence, alternative) if consequence == alternative => { ConditionalOrExpression::Expression(consequence.into_inner()) } - (condition, consequence, alternative) => ConditionalOrExpression::Conditional( + (consequence, alternative) => ConditionalOrExpression::Conditional( ConditionalExpression::new(condition, consequence, alternative, e.kind), ), }, - ) + }) } - fn fold_assembly_statement( + fn fold_assembly_assignment( &mut self, - s: TypedAssemblyStatement<'ast, T>, + s: AssemblyAssignment<'ast, T>, ) -> Result>, Self::Error> { - match s { - TypedAssemblyStatement::Assignment(assignee, expr) => { - let assignee = self.fold_assignee(assignee)?; - let expr = self.fold_expression(expr)?; + let assignee = self.fold_assignee(s.assignee)?; + let expr = self.fold_expression(s.expression)?; - if expr.is_constant() { - match assignee { - TypedAssignee::Identifier(var) => { - let expr = expr.into_canonical_constant(); + if expr.is_constant() { + match assignee { + TypedAssignee::Identifier(var) => { + let expr = expr.into_canonical_constant(); - assert!(self.constants.insert(var.id, expr).is_none()); + assert!(self.constants.insert(var.id, expr).is_none()); - Ok(vec![]) - } - assignee => match self.try_get_constant_mut(&assignee) { - Ok((_, c)) => { - *c = expr.into_canonical_constant(); - Ok(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) => Ok(vec![ - TypedAssemblyStatement::Assignment(v.clone().into(), c), - TypedAssemblyStatement::Assignment(assignee, expr), - ]), - None => { - Ok(vec![TypedAssemblyStatement::Assignment(assignee, expr)]) - } - }, - }, + Ok(vec![]) + } + assignee => match self.try_get_constant_mut(&assignee) { + Ok((_, c)) => { + *c = expr.into_canonical_constant(); + Ok(vec![]) } - } else { - // 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) { + 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) => Ok(vec![ - TypedAssemblyStatement::Assignment(v.clone().into(), c), - TypedAssemblyStatement::Assignment(assignee, expr), + TypedAssemblyStatement::assignment(v.clone().into(), c), + TypedAssemblyStatement::assignment(assignee, expr), ]), - None => Ok(vec![TypedAssemblyStatement::Assignment(assignee, expr)]), - } - } + None => Ok(vec![TypedAssemblyStatement::assignment(assignee, expr)]), + }, + }, } - TypedAssemblyStatement::Constraint(left, right, metadata) => { - let left = self.fold_field_expression(left)?; - let right = self.fold_field_expression(right)?; - - // a bit hacky, but we use a fake boolean expression to check this - let is_equal = - BooleanExpression::FieldEq(EqExpression::new(left.clone(), right.clone())); - let is_equal = self.fold_boolean_expression(is_equal)?; - - match is_equal { - BooleanExpression::Value(true) => Ok(vec![]), - BooleanExpression::Value(false) => { - Err(Error::AssertionFailed(RuntimeError::SourceAssertion( - metadata - .message(Some(format!("In asm block: `{} !== {}`", left, right))), - ))) - } - _ => Ok(vec![TypedAssemblyStatement::Constraint( - left, right, metadata, - )]), - } + } else { + // 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) => Ok(vec![ + TypedAssemblyStatement::assignment(v.clone().into(), c), + TypedAssemblyStatement::assignment(assignee, expr), + ]), + None => Ok(vec![TypedAssemblyStatement::assignment(assignee, expr)]), } } } - fn fold_statement( + fn fold_assembly_constraint( &mut self, - s: TypedStatement<'ast, T>, - ) -> Result>, Error> { - match s { - TypedStatement::Assembly(statements) => { - let statements: Vec<_> = statements - .into_iter() - .map(|s| self.fold_assembly_statement(s)) - .collect::, _>>()? - .into_iter() - .flatten() - .collect(); - match statements.len() { - 0 => Ok(vec![]), - _ => Ok(vec![TypedStatement::Assembly(statements)]), - } + s: AssemblyConstraint<'ast, T>, + ) -> Result>, Self::Error> { + let span = s.get_span(); + + let left = self.fold_field_expression(s.left)?; + let right = self.fold_field_expression(s.right)?; + + // a bit hacky, but we use a fake boolean expression to check this + let is_equal = BooleanExpression::field_eq(left.clone(), right.clone()).span(span); + let is_equal = self.fold_boolean_expression(is_equal)?; + + match is_equal { + BooleanExpression::Value(v) if v.value => Ok(vec![]), + BooleanExpression::Value(v) if !v.value => { + Err(Error::AssertionFailed(RuntimeError::SourceAssertion( + s.metadata + .message(Some(format!("In asm block: `{} !== {}`", left, right))), + ))) } + _ => Ok(vec![TypedAssemblyStatement::constraint( + left, right, s.metadata, + )]), + } + } + + fn fold_definition_statement( + &mut self, + s: DefinitionStatement<'ast, T>, + ) -> Result>, Self::Error> { + let span = s.get_span(); + + match s.rhs { // propagation to the defined variable if rhs is a constant - TypedStatement::Definition(assignee, DefinitionRhs::Expression(expr)) => { - let assignee = self.fold_assignee(assignee)?; - let expr = self.fold_expression(expr)?; + DefinitionRhs::Expression(e) => { + let assignee = self.fold_assignee(s.assignee)?; + let expr = self.fold_expression(e)?; if let (Ok(a), Ok(e)) = ( ConcreteType::try_from(assignee.get_type()), @@ -335,10 +321,10 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> { // invalidate the cache for this identifier, and define the latest // version of the constant in the program, if any Some(c) => Ok(vec![ - TypedStatement::Definition(v.clone().into(), c.into()), - TypedStatement::Definition(assignee, expr.into()), + TypedStatement::definition(v.clone().into(), c), + TypedStatement::definition(assignee, expr), ]), - None => Ok(vec![TypedStatement::Definition(assignee, expr.into())]), + None => Ok(vec![TypedStatement::definition(assignee, expr)]), }, }, } @@ -351,23 +337,16 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> { match self.constants.remove(&v.id) { Some(c) => Ok(vec![ - TypedStatement::Definition(v.clone().into(), c.into()), - TypedStatement::Definition(assignee, expr.into()), + TypedStatement::definition(v.clone().into(), c), + TypedStatement::definition(assignee, expr), ]), - None => Ok(vec![TypedStatement::Definition(assignee, expr.into())]), + None => Ok(vec![TypedStatement::definition(assignee, expr)]), } } } - // we do not visit the for-loop statements - TypedStatement::For(v, from, to, statements) => { - let from = self.fold_uint_expression(from)?; - let to = self.fold_uint_expression(to)?; - - Ok(vec![TypedStatement::For(v, from, to, statements)]) - } - TypedStatement::Definition(assignee, DefinitionRhs::EmbedCall(embed_call)) => { - let assignee = self.fold_assignee(assignee)?; - let embed_call = self.fold_embed_call(embed_call)?; + DefinitionRhs::EmbedCall(e) => { + let assignee = self.fold_assignee(s.assignee)?; + let embed_call = self.fold_embed_call(e)?; fn process_u_from_bits<'ast, T: Field>( arguments: &[TypedExpression<'ast, T>], @@ -383,7 +362,7 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> { .into_inner() { ArrayExpressionInner::Value(v) => - UExpressionInner::Value( + UExpression::value( v.into_iter() .map(|v| match v { TypedExpressionOrSpread::Expression( @@ -395,7 +374,7 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> { }) .enumerate() .fold(0, |acc, (i, v)| { - if v { + if v.value { acc + 2u128.pow( (bitwidth.to_usize() - i - 1) .try_into() @@ -423,7 +402,7 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> { .into_inner() { UExpressionInner::Value(v) => { - let mut num = v; + let mut num = v.value; let mut res = vec![]; for i in (0..bitwidth as u32).rev() { @@ -436,13 +415,12 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> { } assert_eq!(num, 0); - ArrayExpressionInner::Value( + ArrayExpression::value( res.into_iter() - .map(|v| BooleanExpression::Value(v).into()) - .collect::>() - .into(), + .map(|v| BooleanExpression::value(v).into()) + .collect::>(), ) - .annotate(Type::Boolean, bitwidth.to_usize() as u32) + .annotate(ArrayType::new(Type::Boolean, bitwidth.to_usize() as u32)) .into() } _ => unreachable!("should be a uint value"), @@ -457,13 +435,17 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> { match FieldElementExpression::try_from_typed( embed_call.arguments[0].clone(), ) { - Ok(FieldElementExpression::Number(n)) if n == T::from(0) => { - Ok(Some(BooleanExpression::Value(false).into())) + Ok(FieldElementExpression::Value(n)) + if n.value == T::from(0) => + { + Ok(Some(BooleanExpression::value(false).span(span).into())) } - Ok(FieldElementExpression::Number(n)) if n == T::from(1) => { - Ok(Some(BooleanExpression::Value(true).into())) + Ok(FieldElementExpression::Value(n)) + if n.value == T::from(1) => + { + Ok(Some(BooleanExpression::value(true).span(span).into())) } - Ok(FieldElementExpression::Number(n)) => { + Ok(FieldElementExpression::Value(n)) => { Err(Error::InvalidValue(format!( "Cannot call `{}` with value `{}`: should be 0 or 1", embed_call.embed.id(), @@ -516,8 +498,8 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> { ) .unwrap() { - FieldElementExpression::Number(num) => { - let mut acc = num.clone(); + FieldElementExpression::Value(num) => { + let mut acc = num.value; let mut res = vec![]; for i in (0..bit_width as usize).rev() { @@ -537,13 +519,17 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> { ))) } else { Ok(Some( - ArrayExpressionInner::Value( + ArrayExpression::value( res.into_iter() - .map(|v| BooleanExpression::Value(v).into()) - .collect::>() - .into(), + .map(|v| { + BooleanExpression::value(v) + .span(span) + .into() + }) + .collect::>(), ) - .annotate(Type::Boolean, bit_width) + .annotate(ArrayType::new(Type::Boolean, bit_width)) + .span(span) .into(), )) } @@ -571,11 +557,11 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> { } Err(v) => match self.constants.remove(&v.id) { Some(c) => vec![ - TypedStatement::Definition(v.clone().into(), c.into()), - TypedStatement::Definition(assignee, expr.into()), + TypedStatement::definition(v.clone().into(), c), + TypedStatement::definition(assignee, expr), ], None => { - vec![TypedStatement::Definition(assignee, expr.into())] + vec![TypedStatement::definition(assignee, expr)] } }, }, @@ -591,12 +577,11 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> { match self.constants.remove(&v.id) { Some(c) => vec![ - TypedStatement::Definition(v.clone().into(), c.into()), - TypedStatement::Definition(assignee, embed_call.into()), + TypedStatement::definition(v.clone().into(), c), + TypedStatement::embed_call_definition(assignee, embed_call), ], - None => vec![TypedStatement::Definition( - assignee, - embed_call.into(), + None => vec![TypedStatement::embed_call_definition( + assignee, embed_call, )], } } @@ -605,7 +590,8 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> { false => { // if the function arguments are not constant, invalidate the cache // for the return assignees - let def = TypedStatement::Definition(assignee.clone(), embed_call.into()); + let def = + TypedStatement::embed_call_definition(assignee.clone(), embed_call); let v = self .try_get_constant_mut(&assignee) @@ -614,403 +600,451 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> { Ok(match self.constants.remove(&v.id) { Some(c) => { - vec![TypedStatement::Definition(v.clone().into(), c.into()), def] + vec![TypedStatement::definition(v.clone().into(), c), def] } None => vec![def], }) } } } - TypedStatement::Assertion(e, err) => { - let expr = self.fold_boolean_expression(e)?; - match expr { - BooleanExpression::Value(false) => Err(Error::AssertionFailed(err)), - BooleanExpression::Value(true) => Ok(vec![]), - _ => Ok(vec![TypedStatement::Assertion(expr, err)]), - } - } - s @ TypedStatement::PushCallLog(..) => Ok(vec![s]), - s @ TypedStatement::PopCallLog => Ok(vec![s]), - s => fold_statement(self, s), } } - fn fold_uint_expression_inner( + fn fold_assembly_block( + &mut self, + s: AssemblyBlockStatement<'ast, T>, + ) -> Result>, Self::Error> { + Ok(fold_assembly_block(self, s)? + .into_iter() + .filter(|s| match s { + TypedStatement::Assembly(s) => !s.inner.is_empty(), + _ => true, + }) + .collect()) + } + + fn fold_for_statement( + &mut self, + s: ForStatement<'ast, T>, + ) -> Result>, Self::Error> { + // we do not visit the for-loop statements + let from = self.fold_uint_expression(s.from)?; + let to = self.fold_uint_expression(s.to)?; + + Ok(vec![TypedStatement::for_(s.var, from, to, s.statements)]) + } + + fn fold_assertion_statement( + &mut self, + s: AssertionStatement<'ast, T>, + ) -> Result>, Self::Error> { + let _e_str = s.expression.to_string(); + let expr = self.fold_boolean_expression(s.expression)?; + + match expr { + BooleanExpression::Value(v) if !v.value => Err(Error::AssertionFailed(s.error)), + BooleanExpression::Value(v) if v.value => Ok(vec![]), + _ => Ok(vec![TypedStatement::assertion(expr, s.error)]), + } + } + + fn fold_uint_expression_cases( &mut self, bitwidth: UBitwidth, e: UExpressionInner<'ast, T>, ) -> Result, Error> { match e { - UExpressionInner::Add(box e1, box e2) => match ( - self.fold_uint_expression(e1)?.into_inner(), - self.fold_uint_expression(e2)?.into_inner(), + UExpressionInner::Add(e) => match ( + self.fold_uint_expression(*e.left)?.into_inner(), + self.fold_uint_expression(*e.right)?.into_inner(), ) { (UExpressionInner::Value(v1), UExpressionInner::Value(v2)) => { - Ok(UExpressionInner::Value( - (v1 + v2) % 2_u128.pow(bitwidth.to_usize().try_into().unwrap()), + Ok(UExpression::value( + (v1.value + v2.value) % 2_u128.pow(bitwidth.to_usize().try_into().unwrap()), )) } - (e, UExpressionInner::Value(v)) | (UExpressionInner::Value(v), e) => match v { - 0 => Ok(e), - _ => Ok(UExpressionInner::Add( - box e.annotate(bitwidth), - box UExpressionInner::Value(v).annotate(bitwidth), - )), - }, - (e1, e2) => Ok(UExpressionInner::Add( - box e1.annotate(bitwidth), - box e2.annotate(bitwidth), - )), + (e, UExpressionInner::Value(v)) | (UExpressionInner::Value(v), e) => { + match v.value { + 0 => Ok(e), + _ => Ok(UExpression::add( + e.annotate(bitwidth), + UExpression::value(v.value).annotate(bitwidth), + ) + .into_inner()), + } + } + (e1, e2) => { + Ok(UExpression::add(e1.annotate(bitwidth), e2.annotate(bitwidth)).into_inner()) + } }, - UExpressionInner::Sub(box e1, box e2) => match ( - self.fold_uint_expression(e1)?.into_inner(), - self.fold_uint_expression(e2)?.into_inner(), + UExpressionInner::Sub(e) => match ( + self.fold_uint_expression(*e.left)?.into_inner(), + self.fold_uint_expression(*e.right)?.into_inner(), ) { (UExpressionInner::Value(v1), UExpressionInner::Value(v2)) => { - Ok(UExpressionInner::Value( - (v1.wrapping_sub(v2)) % 2_u128.pow(bitwidth.to_usize().try_into().unwrap()), + Ok(UExpression::value( + (v1.value.wrapping_sub(v2.value)) + % 2_u128.pow(bitwidth.to_usize().try_into().unwrap()), )) } - (e, UExpressionInner::Value(v)) => match v { + (e, UExpressionInner::Value(v)) => match v.value { 0 => Ok(e), - _ => Ok(UExpressionInner::Sub( - box e.annotate(bitwidth), - box UExpressionInner::Value(v).annotate(bitwidth), - )), + _ => Ok(UExpression::sub( + e.annotate(bitwidth), + UExpressionInner::Value(v).annotate(bitwidth), + ) + .into_inner()), }, - (e1, e2) => Ok(UExpressionInner::Sub( - box e1.annotate(bitwidth), - box e2.annotate(bitwidth), - )), + (e1, e2) => { + Ok(UExpression::sub(e1.annotate(bitwidth), e2.annotate(bitwidth)).into_inner()) + } }, - UExpressionInner::FloorSub(box e1, box e2) => match ( - self.fold_uint_expression(e1)?.into_inner(), - self.fold_uint_expression(e2)?.into_inner(), + UExpressionInner::FloorSub(e) => match ( + self.fold_uint_expression(*e.left)?.into_inner(), + self.fold_uint_expression(*e.right)?.into_inner(), ) { (UExpressionInner::Value(v1), UExpressionInner::Value(v2)) => { - Ok(UExpressionInner::Value( - v1.saturating_sub(v2) % 2_u128.pow(bitwidth.to_usize().try_into().unwrap()), + Ok(UExpression::value( + v1.value.saturating_sub(v2.value) + % 2_u128.pow(bitwidth.to_usize().try_into().unwrap()), )) } - (e, UExpressionInner::Value(v)) => match v { + (e, UExpressionInner::Value(v)) => match v.value { 0 => Ok(e), - _ => Ok(UExpressionInner::FloorSub( - box e.annotate(bitwidth), - box UExpressionInner::Value(v).annotate(bitwidth), - )), + _ => Ok(UExpression::floor_sub( + e.annotate(bitwidth), + UExpressionInner::Value(v).annotate(bitwidth), + ) + .into_inner()), }, - (e1, e2) => Ok(UExpressionInner::Sub( - box e1.annotate(bitwidth), - box e2.annotate(bitwidth), - )), + (e1, e2) => { + Ok(UExpression::sub(e1.annotate(bitwidth), e2.annotate(bitwidth)).into_inner()) + } }, - UExpressionInner::Mult(box e1, box e2) => match ( - self.fold_uint_expression(e1)?.into_inner(), - self.fold_uint_expression(e2)?.into_inner(), + UExpressionInner::Mult(e) => match ( + self.fold_uint_expression(*e.left)?.into_inner(), + self.fold_uint_expression(*e.right)?.into_inner(), ) { (UExpressionInner::Value(v1), UExpressionInner::Value(v2)) => { - Ok(UExpressionInner::Value( - (v1 * v2) % 2_u128.pow(bitwidth.to_usize().try_into().unwrap()), + Ok(UExpression::value( + (v1.value * v2.value) % 2_u128.pow(bitwidth.to_usize().try_into().unwrap()), )) } - (e, UExpressionInner::Value(v)) | (UExpressionInner::Value(v), e) => match v { - 0 => Ok(UExpressionInner::Value(0)), - 1 => Ok(e), - _ => Ok(UExpressionInner::Mult( - box e.annotate(bitwidth), - box UExpressionInner::Value(v).annotate(bitwidth), - )), - }, - (e1, e2) => Ok(UExpressionInner::Mult( - box e1.annotate(bitwidth), - box e2.annotate(bitwidth), - )), + (e, UExpressionInner::Value(v)) | (UExpressionInner::Value(v), e) => { + match v.value { + 0 => Ok(UExpression::value(0)), + 1 => Ok(e), + _ => Ok(UExpression::mul( + e.annotate(bitwidth), + UExpressionInner::Value(v).annotate(bitwidth), + ) + .into_inner()), + } + } + (e1, e2) => { + Ok(UExpression::mul(e1.annotate(bitwidth), e2.annotate(bitwidth)).into_inner()) + } }, - UExpressionInner::Div(box e1, box e2) => match ( - self.fold_uint_expression(e1)?.into_inner(), - self.fold_uint_expression(e2)?.into_inner(), + UExpressionInner::Div(e) => match ( + self.fold_uint_expression(*e.left)?.into_inner(), + self.fold_uint_expression(*e.right)?.into_inner(), ) { (UExpressionInner::Value(v1), UExpressionInner::Value(v2)) => { - Ok(UExpressionInner::Value( - (v1 / v2) % 2_u128.pow(bitwidth.to_usize().try_into().unwrap()), + Ok(UExpression::value( + (v1.value / v2.value) % 2_u128.pow(bitwidth.to_usize().try_into().unwrap()), )) } - (e, UExpressionInner::Value(v)) => match v { + (e, UExpressionInner::Value(v)) => match v.value { 1 => Ok(e), - _ => Ok(UExpressionInner::Div( - box e.annotate(bitwidth), - box UExpressionInner::Value(v).annotate(bitwidth), - )), + _ => Ok(UExpression::div( + e.annotate(bitwidth), + UExpressionInner::Value(v).annotate(bitwidth), + ) + .into_inner()), }, - (e1, e2) => Ok(UExpressionInner::Div( - box e1.annotate(bitwidth), - box e2.annotate(bitwidth), - )), + (e1, e2) => { + Ok(UExpression::div(e1.annotate(bitwidth), e2.annotate(bitwidth)).into_inner()) + } }, - UExpressionInner::Rem(box e1, box e2) => match ( - self.fold_uint_expression(e1)?.into_inner(), - self.fold_uint_expression(e2)?.into_inner(), + UExpressionInner::Rem(e) => match ( + self.fold_uint_expression(*e.left)?.into_inner(), + self.fold_uint_expression(*e.right)?.into_inner(), ) { (UExpressionInner::Value(v1), UExpressionInner::Value(v2)) => { - Ok(UExpressionInner::Value( - (v1 % v2) % 2_u128.pow(bitwidth.to_usize().try_into().unwrap()), + Ok(UExpression::value( + (v1.value % v2.value) % 2_u128.pow(bitwidth.to_usize().try_into().unwrap()), )) } - (e, UExpressionInner::Value(v)) => match v { - 1 => Ok(UExpressionInner::Value(0)), - _ => Ok(UExpressionInner::Rem( - box e.annotate(bitwidth), - box UExpressionInner::Value(v).annotate(bitwidth), - )), + (e, UExpressionInner::Value(v)) => match v.value { + 1 => Ok(UExpression::value(0)), + _ => Ok(UExpression::rem( + e.annotate(bitwidth), + UExpressionInner::Value(v).annotate(bitwidth), + ) + .into_inner()), }, - (e1, e2) => Ok(UExpressionInner::Rem( - box e1.annotate(bitwidth), - box e2.annotate(bitwidth), - )), + (e1, e2) => { + Ok(UExpression::rem(e1.annotate(bitwidth), e2.annotate(bitwidth)).into_inner()) + } }, - UExpressionInner::RightShift(box e, box by) => { - let e = self.fold_uint_expression(e)?; - let by = self.fold_uint_expression(by)?; - match (e.into_inner(), by.into_inner()) { + UExpressionInner::RightShift(e) => { + let left = self.fold_uint_expression(*e.left)?; + let right = self.fold_uint_expression(*e.right)?; + match (left.into_inner(), right.into_inner()) { (UExpressionInner::Value(v), UExpressionInner::Value(by)) => { - Ok(UExpressionInner::Value(v >> by)) + Ok(UExpression::value(v.value >> by.value)) } - (e, by) => Ok(UExpressionInner::RightShift( - box e.annotate(bitwidth), - box by.annotate(UBitwidth::B32), - )), + (e, by) => Ok(UExpression::right_shift( + e.annotate(bitwidth), + by.annotate(UBitwidth::B32), + ) + .into_inner()), } } - UExpressionInner::LeftShift(box e, box by) => { - let e = self.fold_uint_expression(e)?; - let by = self.fold_uint_expression(by)?; - match (e.into_inner(), by.into_inner()) { - (UExpressionInner::Value(v), UExpressionInner::Value(by)) => Ok( - UExpressionInner::Value((v << by) & (2_u128.pow(bitwidth as u32) - 1)), - ), - (e, by) => Ok(UExpressionInner::LeftShift( - box e.annotate(bitwidth), - box by.annotate(UBitwidth::B32), - )), + UExpressionInner::LeftShift(e) => { + let left = self.fold_uint_expression(*e.left)?; + let right = self.fold_uint_expression(*e.right)?; + match (left.into_inner(), right.into_inner()) { + (UExpressionInner::Value(v), UExpressionInner::Value(by)) => { + Ok(UExpression::value( + (v.value << by.value) & (2_u128.pow(bitwidth as u32) - 1), + )) + } + (e, by) => Ok(UExpression::left_shift( + e.annotate(bitwidth), + by.annotate(UBitwidth::B32), + ) + .into_inner()), } } - UExpressionInner::Xor(box e1, box e2) => match ( - self.fold_uint_expression(e1)?.into_inner(), - self.fold_uint_expression(e2)?.into_inner(), + UExpressionInner::Xor(e) => match ( + self.fold_uint_expression(*e.left)?.into_inner(), + self.fold_uint_expression(*e.right)?.into_inner(), ) { (UExpressionInner::Value(v1), UExpressionInner::Value(v2)) => { - Ok(UExpressionInner::Value(v1 ^ v2)) + Ok(UExpression::value(v1.value ^ v2.value)) + } + (UExpressionInner::Value(v), e2) | (e2, UExpressionInner::Value(v)) + if v.value == 0 => + { + Ok(e2) } - (UExpressionInner::Value(0), e2) => Ok(e2), - (e1, UExpressionInner::Value(0)) => Ok(e1), (e1, e2) => { if e1 == e2 { - Ok(UExpressionInner::Value(0)) + Ok(UExpression::value(0)) } else { - Ok(UExpressionInner::Xor( - box e1.annotate(bitwidth), - box e2.annotate(bitwidth), - )) + Ok( + UExpression::xor(e1.annotate(bitwidth), e2.annotate(bitwidth)) + .into_inner(), + ) } } }, - UExpressionInner::And(box e1, box e2) => match ( - self.fold_uint_expression(e1)?.into_inner(), - self.fold_uint_expression(e2)?.into_inner(), + UExpressionInner::And(e) => match ( + self.fold_uint_expression(*e.left)?.into_inner(), + self.fold_uint_expression(*e.right)?.into_inner(), ) { (UExpressionInner::Value(v1), UExpressionInner::Value(v2)) => { - Ok(UExpressionInner::Value(v1 & v2)) + Ok(UExpression::value(v1.value & v2.value)) + } + (UExpressionInner::Value(v), _) | (_, UExpressionInner::Value(v)) + if v.value == 0 => + { + Ok(UExpression::value(0)) } - (UExpressionInner::Value(0), _) | (_, UExpressionInner::Value(0)) => { - Ok(UExpressionInner::Value(0)) + (e1, e2) => { + Ok(UExpression::and(e1.annotate(bitwidth), e2.annotate(bitwidth)).into_inner()) } - (e1, e2) => Ok(UExpressionInner::And( - box e1.annotate(bitwidth), - box e2.annotate(bitwidth), - )), }, - UExpressionInner::Not(box e) => { - let e = self.fold_uint_expression(e)?.into_inner(); + UExpressionInner::Not(e) => { + let e = self.fold_uint_expression(*e.inner)?.into_inner(); match e { - UExpressionInner::Value(v) => Ok(UExpressionInner::Value( - (!v) & (2_u128.pow(bitwidth as u32) - 1), + UExpressionInner::Value(v) => Ok(UExpression::value( + (!v.value) & (2_u128.pow(bitwidth as u32) - 1), )), - e => Ok(UExpressionInner::Not(box e.annotate(bitwidth))), + e => Ok(UExpression::not(e.annotate(bitwidth)).into_inner()), } } - UExpressionInner::Neg(box e) => { - let e = self.fold_uint_expression(e)?.into_inner(); + UExpressionInner::Neg(e) => { + let e = self.fold_uint_expression(*e.inner)?.into_inner(); match e { - UExpressionInner::Value(v) => Ok(UExpressionInner::Value( - (0u128.wrapping_sub(v)) + UExpressionInner::Value(v) => Ok(UExpression::value( + (0u128.wrapping_sub(v.value)) % 2_u128.pow(bitwidth.to_usize().try_into().unwrap()), )), - e => Ok(UExpressionInner::Neg(box e.annotate(bitwidth))), + e => Ok(UExpression::neg(e.annotate(bitwidth)).into_inner()), } } - UExpressionInner::Pos(box e) => { - let e = self.fold_uint_expression(e)?.into_inner(); + UExpressionInner::Pos(e) => { + let e = self.fold_uint_expression(*e.inner)?.into_inner(); match e { - UExpressionInner::Value(v) => Ok(UExpressionInner::Value(v)), - e => Ok(UExpressionInner::Pos(box e.annotate(bitwidth))), + UExpressionInner::Value(v) => Ok(UExpression::value(v.value)), + e => Ok(UExpression::pos(e.annotate(bitwidth)).into_inner()), } } - e => fold_uint_expression_inner(self, bitwidth, e), + e => fold_uint_expression_cases(self, bitwidth, e), } } - fn fold_field_expression( + fn fold_field_expression_cases( &mut self, e: FieldElementExpression<'ast, T>, ) -> Result, Error> { match e { - FieldElementExpression::Add(box e1, box e2) => match ( - self.fold_field_expression(e1)?, - self.fold_field_expression(e2)?, - ) { - (FieldElementExpression::Number(n1), FieldElementExpression::Number(n2)) => { - Ok(FieldElementExpression::Number(n1 + n2)) - } - (e1, e2) => Ok(FieldElementExpression::Add(box e1, box e2)), - }, - FieldElementExpression::Sub(box e1, box e2) => match ( - self.fold_field_expression(e1)?, - self.fold_field_expression(e2)?, - ) { - (FieldElementExpression::Number(n1), FieldElementExpression::Number(n2)) => { - Ok(FieldElementExpression::Number(n1 - n2)) - } - (e1, e2) => Ok(FieldElementExpression::Sub(box e1, box e2)), - }, - FieldElementExpression::Mult(box e1, box e2) => match ( - self.fold_field_expression(e1)?, - self.fold_field_expression(e2)?, - ) { - (FieldElementExpression::Number(n1), FieldElementExpression::Number(n2)) => { - Ok(FieldElementExpression::Number(n1 * n2)) - } - (e1, e2) => Ok(FieldElementExpression::Mult(box e1, box e2)), - }, - FieldElementExpression::Div(box e1, box e2) => match ( - self.fold_field_expression(e1)?, - self.fold_field_expression(e2)?, - ) { - (FieldElementExpression::Number(n1), FieldElementExpression::Number(n2)) => { - Ok(FieldElementExpression::Number(n1 / n2)) + FieldElementExpression::Add(e) => { + let left = self.fold_field_expression(*e.left)?; + let right = self.fold_field_expression(*e.right)?; + + Ok(match (left, right) { + (FieldElementExpression::Value(n1), FieldElementExpression::Value(n2)) => { + FieldElementExpression::Value(ValueExpression::new(n1.value + n2.value)) + } + (e1, e2) => e1 + e2, + }) + } + FieldElementExpression::Sub(e) => { + let left = self.fold_field_expression(*e.left)?; + let right = self.fold_field_expression(*e.right)?; + + Ok(match (left, right) { + (FieldElementExpression::Value(n1), FieldElementExpression::Value(n2)) => { + FieldElementExpression::Value(ValueExpression::new(n1.value - n2.value)) + } + (e1, e2) => e1 - e2, + }) + } + FieldElementExpression::Mult(e) => { + let left = self.fold_field_expression(*e.left)?; + let right = self.fold_field_expression(*e.right)?; + + Ok(match (left, right) { + (FieldElementExpression::Value(n1), FieldElementExpression::Value(n2)) => { + FieldElementExpression::Value(ValueExpression::new(n1.value * n2.value)) + } + (e1, e2) => e1 * e2, + }) + } + FieldElementExpression::Div(e) => { + let left = self.fold_field_expression(*e.left)?; + let right = self.fold_field_expression(*e.right)?; + + match (left, right) { + (_, FieldElementExpression::Value(n)) if n.value == T::from(0) => { + Err(Error::DivisionByZero) + } + (e, FieldElementExpression::Value(n)) if n.value == T::from(1) => Ok(e), + (FieldElementExpression::Value(n1), FieldElementExpression::Value(n2)) => Ok( + FieldElementExpression::Value(ValueExpression::new(n1.value / n2.value)), + ), + (e1, e2) => Ok(e1 / e2), } - (e1, e2) => Ok(FieldElementExpression::Div(box e1, box e2)), - }, - FieldElementExpression::Neg(box e) => match self.fold_field_expression(e)? { - FieldElementExpression::Number(n) => { - Ok(FieldElementExpression::Number(T::zero() - n)) + } + FieldElementExpression::Neg(e) => match self.fold_field_expression(*e.inner)? { + FieldElementExpression::Value(n) => { + Ok(FieldElementExpression::value(T::zero() - n.value)) } - e => Ok(FieldElementExpression::Neg(box e)), + e => Ok(FieldElementExpression::neg(e)), }, - FieldElementExpression::Pos(box e) => match self.fold_field_expression(e)? { - FieldElementExpression::Number(n) => Ok(FieldElementExpression::Number(n)), - e => Ok(FieldElementExpression::Pos(box e)), + FieldElementExpression::Pos(e) => match self.fold_field_expression(*e.inner)? { + FieldElementExpression::Value(n) => Ok(FieldElementExpression::Value(n)), + e => Ok(FieldElementExpression::pos(e)), }, - FieldElementExpression::Pow(box e1, box e2) => { - let e1 = self.fold_field_expression(e1)?; - let e2 = self.fold_uint_expression(e2)?; + FieldElementExpression::Pow(e) => { + let e1 = self.fold_field_expression(*e.left)?; + let e2 = self.fold_uint_expression(*e.right)?; match (e1, e2.into_inner()) { - (_, UExpressionInner::Value(ref n2)) if *n2 == 0 => { - Ok(FieldElementExpression::Number(T::from(1))) + (_, UExpressionInner::Value(ref n2)) if n2.value == 0 => { + Ok(FieldElementExpression::value(T::from(1))) } - (FieldElementExpression::Number(n1), UExpressionInner::Value(n2)) => { - Ok(FieldElementExpression::Number(n1.pow(n2 as usize))) - } - (e1, UExpressionInner::Value(n2)) => Ok(FieldElementExpression::Pow( - box e1, - box UExpressionInner::Value(n2).annotate(UBitwidth::B32), - )), - (e1, e2) => Ok(FieldElementExpression::Pow( - box e1, - box e2.annotate(UBitwidth::B32), - )), + (FieldElementExpression::Value(n1), UExpressionInner::Value(n2)) => Ok( + FieldElementExpression::value(n1.value.pow(n2.value as usize)), + ), + (e1, e2) => Ok(FieldElementExpression::pow(e1, e2.annotate(UBitwidth::B32))), } } - FieldElementExpression::Xor(box e1, box e2) => { - let e1 = self.fold_field_expression(e1)?; - let e2 = self.fold_field_expression(e2)?; + FieldElementExpression::Xor(e) => { + let e1 = self.fold_field_expression(*e.left)?; + let e2 = self.fold_field_expression(*e.right)?; match (e1, e2) { - (FieldElementExpression::Number(n1), FieldElementExpression::Number(n2)) => { - Ok(FieldElementExpression::Number( - T::try_from(n1.to_biguint().bitxor(n2.to_biguint())).unwrap(), + (FieldElementExpression::Value(n1), FieldElementExpression::Value(n2)) => { + Ok(FieldElementExpression::value( + T::try_from(n1.value.to_biguint().bitxor(n2.value.to_biguint())) + .unwrap(), )) } - (FieldElementExpression::Number(n), e) - | (e, FieldElementExpression::Number(n)) - if n == T::from(0) => + (FieldElementExpression::Value(n), e) + | (e, FieldElementExpression::Value(n)) + if n.value == T::from(0) => { Ok(e) } - (e1, e2) if e1.eq(&e2) => Ok(FieldElementExpression::Number(T::from(0))), - (e1, e2) => Ok(FieldElementExpression::Xor(box e1, box e2)), + (e1, e2) if e1.eq(&e2) => Ok(FieldElementExpression::value(T::from(0))), + (e1, e2) => Ok(FieldElementExpression::bitxor(e1, e2)), } } - - FieldElementExpression::And(box e1, box e2) => { - let e1 = self.fold_field_expression(e1)?; - let e2 = self.fold_field_expression(e2)?; + FieldElementExpression::And(e) => { + let e1 = self.fold_field_expression(*e.left)?; + let e2 = self.fold_field_expression(*e.right)?; match (e1, e2) { - (_, FieldElementExpression::Number(n)) - | (FieldElementExpression::Number(n), _) - if n == T::from(0) => + (_, FieldElementExpression::Value(n)) + | (FieldElementExpression::Value(n), _) + if n.value == T::from(0) => { - Ok(FieldElementExpression::Number(n)) + Ok(FieldElementExpression::Value(n)) } - (FieldElementExpression::Number(n1), FieldElementExpression::Number(n2)) => { - Ok(FieldElementExpression::Number( - T::try_from(n1.to_biguint().bitand(n2.to_biguint())).unwrap(), + (FieldElementExpression::Value(n1), FieldElementExpression::Value(n2)) => { + Ok(FieldElementExpression::value( + T::try_from(n1.value.to_biguint().bitand(n2.value.to_biguint())) + .unwrap(), )) } - (e1, e2) => Ok(FieldElementExpression::And(box e1, box e2)), + (e1, e2) => Ok(FieldElementExpression::bitand(e1, e2)), } } - FieldElementExpression::Or(box e1, box e2) => { - let e1 = self.fold_field_expression(e1)?; - let e2 = self.fold_field_expression(e2)?; + FieldElementExpression::Or(e) => { + let e1 = self.fold_field_expression(*e.left)?; + let e2 = self.fold_field_expression(*e.right)?; match (e1, e2) { - (e, FieldElementExpression::Number(n)) - | (FieldElementExpression::Number(n), e) - if n == T::from(0) => + (e, FieldElementExpression::Value(n)) + | (FieldElementExpression::Value(n), e) + if n.value == T::from(0) => { Ok(e) } - (FieldElementExpression::Number(n1), FieldElementExpression::Number(n2)) => { - Ok(FieldElementExpression::Number( - T::try_from(n1.to_biguint().bitor(n2.to_biguint())).unwrap(), + (FieldElementExpression::Value(n1), FieldElementExpression::Value(n2)) => { + Ok(FieldElementExpression::value( + T::try_from(n1.value.to_biguint().bitor(n2.value.to_biguint())) + .unwrap(), )) } - (e1, e2) => Ok(FieldElementExpression::Or(box e1, box e2)), + (e1, e2) => Ok(FieldElementExpression::bitor(e1, e2)), } } - FieldElementExpression::LeftShift(box e, box by) => { - let e = self.fold_field_expression(e)?; - let by = self.fold_uint_expression(by)?; - match (e, by) { + FieldElementExpression::LeftShift(e) => { + let expr = self.fold_field_expression(*e.left)?; + let by = self.fold_uint_expression(*e.right)?; + match (expr, by) { ( e, UExpression { inner: UExpressionInner::Value(by), .. }, - ) if by == 0 => Ok(e), + ) if by.value == 0 => Ok(e), ( _, UExpression { inner: UExpressionInner::Value(by), .. }, - ) if by as usize >= T::get_required_bits() => { - Ok(FieldElementExpression::Number(T::from(0))) + ) if by.value as usize >= T::get_required_bits() => { + Ok(FieldElementExpression::value(T::from(0))) } ( - FieldElementExpression::Number(n), + FieldElementExpression::Value(n), UExpression { inner: UExpressionInner::Value(by), .. @@ -1019,46 +1053,47 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> { let two = BigUint::from(2usize); let mask: BigUint = two.pow(T::get_required_bits()).sub(1usize); - Ok(FieldElementExpression::Number( - T::try_from(n.to_biguint().shl(by as usize).bitand(mask)).unwrap(), + Ok(FieldElementExpression::value( + T::try_from(n.value.to_biguint().shl(by.value as usize).bitand(mask)) + .unwrap(), )) } - (e, by) => Ok(FieldElementExpression::LeftShift(box e, box by)), + (e, by) => Ok(FieldElementExpression::left_shift(e, by)), } } - FieldElementExpression::RightShift(box e, box by) => { - let e = self.fold_field_expression(e)?; - let by = self.fold_uint_expression(by)?; - match (e, by) { + FieldElementExpression::RightShift(e) => { + let expr = self.fold_field_expression(*e.left)?; + let by = self.fold_uint_expression(*e.right)?; + match (expr, by) { ( e, UExpression { inner: UExpressionInner::Value(by), .. }, - ) if by == 0 => Ok(e), + ) if by.value == 0 => Ok(e), ( _, UExpression { inner: UExpressionInner::Value(by), .. }, - ) if by as usize >= T::get_required_bits() => { - Ok(FieldElementExpression::Number(T::from(0))) + ) if by.value as usize >= T::get_required_bits() => { + Ok(FieldElementExpression::value(T::from(0))) } ( - FieldElementExpression::Number(n), + FieldElementExpression::Value(n), UExpression { inner: UExpressionInner::Value(by), .. }, - ) => Ok(FieldElementExpression::Number( - T::try_from(n.to_biguint().shr(by as usize)).unwrap(), + ) => Ok(FieldElementExpression::value( + T::try_from(n.value.to_biguint().shr(by.value as usize)).unwrap(), )), - (e, by) => Ok(FieldElementExpression::RightShift(box e, box by)), + (e, by) => Ok(FieldElementExpression::right_shift(e, by)), } } - e => fold_field_expression(self, e), + e => fold_field_expression_cases(self, e), } } @@ -1128,58 +1163,94 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> { _: &E::Ty, e: SelectExpression<'ast, T, E>, ) -> Result, Self::Error> { - let array = self.fold_array_expression(*e.array)?; let index = self.fold_uint_expression(*e.index)?; + let array = *e.array; + + let ty = self.fold_array_type(*array.ty)?; + let size = match ty.size.as_inner() { + UExpressionInner::Value(v) => Ok(v), + _ => unreachable!("array size was checked when folding array type"), + }?; + + match (array.inner, index.into_inner()) { + // special case if the array is an identifier: check the cache and only clone the element, not the whole array + (ArrayExpressionInner::Identifier(id), UExpressionInner::Value(n)) => { + match self.constants.get(&id.id) { + Some(v) => { + // get the constant array. it was guaranteed to be a value when it was inserted + let v = match v { + TypedExpression::Array(a) => match a.as_inner() { + ArrayExpressionInner::Value(v) => v, + _ => unreachable!(), + }, + _ => unreachable!(), + }; - let inner_type = array.inner_type().clone(); - let size = array.size(); - - match size.into_inner() { - UExpressionInner::Value(size) => match (array.into_inner(), index.into_inner()) { - (ArrayExpressionInner::Value(v), UExpressionInner::Value(n)) => { - if n < size { - Ok(SelectOrExpression::Expression( - v.expression_at::(n as usize).unwrap().into_inner(), - )) - } else { - Err(Error::OutOfBounds(n, size)) + // sanity check that the value does not contain spreads + assert!(v + .value + .iter() + .all(|e| matches!(e, TypedExpressionOrSpread::Expression(_)))); + + if n.value < size.value { + Ok(SelectOrExpression::Expression( + // clone only the element + match v.value[n.value as usize].clone() { + TypedExpressionOrSpread::Expression(e) => { + E::try_from(e).unwrap().into_inner() + } + _ => unreachable!(), + }, + )) + } else { + Err(Error::OutOfBounds(n.value, size.value)) + } } + _ => Ok(SelectOrExpression::Select(SelectExpression::new( + ArrayExpressionInner::Identifier(id).annotate(ty), + UExpressionInner::Value(n).annotate(UBitwidth::B32), + ))), } - (ArrayExpressionInner::Identifier(id), UExpressionInner::Value(n)) => { - match self.constants.get(&id.id) { - Some(a) => match a { - TypedExpression::Array(a) => match a.as_inner() { - ArrayExpressionInner::Value(v) => { - Ok(SelectOrExpression::Expression( - v.expression_at::(n as usize).unwrap().into_inner(), - )) - } - _ => unreachable!("should be an array value"), - }, - _ => unreachable!("should be an array expression"), - }, - None => Ok(SelectOrExpression::Expression( - E::select( - ArrayExpressionInner::Identifier(id) - .annotate(inner_type, size as u32), - UExpressionInner::Value(n).annotate(UBitwidth::B32), - ) - .into_inner(), - )), + } + (array, index) => { + let array = self.fold_array_expression_inner(&ty, array)?; + + match (array, index) { + (ArrayExpressionInner::Value(v), UExpressionInner::Value(n)) => { + if n.value < size.value { + Ok(SelectOrExpression::Expression( + v.expression_at::(n.value as usize).into_inner(), + )) + } else { + Err(Error::OutOfBounds(n.value, size.value)) + } } + (a, i) => Ok(SelectOrExpression::Select(SelectExpression::new( + a.annotate(ty), + i.annotate(UBitwidth::B32), + ))), } - (a, i) => Ok(SelectOrExpression::Select(SelectExpression::new( - a.annotate(inner_type, size as u32), - i.annotate(UBitwidth::B32), - ))), - }, - _ => Ok(SelectOrExpression::Select(SelectExpression::new( - array, index, - ))), + } + } + } + + fn fold_array_type( + &mut self, + t: ArrayType<'ast, T>, + ) -> Result, Self::Error> { + let size = self.fold_uint_expression(*t.size)?; + + if !size.is_constant() { + return Err(Error::VariableLength(format!( + "Array length should be fixed, found {}", + size + ))); } + + Ok(ArrayType::new(self.fold_type(*t.ty)?, size)) } - fn fold_array_expression_inner( + fn fold_array_expression_cases( &mut self, ty: &ArrayType<'ast, T>, e: ArrayExpressionInner<'ast, T>, @@ -1201,7 +1272,7 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> { inner: ArrayExpressionInner::Value(v), .. }, - }) => v.0, + }) => v.value, e => vec![e], } }) @@ -1225,11 +1296,11 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> { .collect(), )) } - e => fold_array_expression_inner(self, ty, e), + e => fold_array_expression_cases(self, ty, e), } } - fn fold_struct_expression_inner( + fn fold_struct_expression_cases( &mut self, ty: &StructType<'ast, T>, e: StructExpressionInner<'ast, T>, @@ -1251,11 +1322,13 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> { Ok(StructExpressionInner::Value(v)) } - e => fold_struct_expression_inner(self, ty, e), + e => fold_struct_expression_cases(self, ty, e), } } - fn fold_identifier_expression + Id<'ast, T> + ResultFold<'ast, T>>( + fn fold_identifier_expression< + E: Expr<'ast, T> + Id<'ast, T> + ResultFold, + >( &mut self, _: &E::Ty, id: IdentifierExpression<'ast, E>, @@ -1266,7 +1339,7 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> { } } - fn fold_tuple_expression_inner( + fn fold_tuple_expression_cases( &mut self, ty: &TupleType<'ast, T>, e: TupleExpressionInner<'ast, T>, @@ -1288,16 +1361,19 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> { Ok(TupleExpressionInner::Value(v)) } - e => fold_tuple_expression_inner(self, ty, e), + e => fold_tuple_expression_cases(self, ty, e), } } fn fold_eq_expression< - E: Expr<'ast, T> + PartialEq + Constant + Typed<'ast, T> + ResultFold<'ast, T>, + E: Expr<'ast, T> + PartialEq + Constant + Typed<'ast, T> + ResultFold, >( &mut self, - e: EqExpression, - ) -> Result, Self::Error> { + e: EqExpression>, + ) -> Result< + BinaryOrExpression, BooleanExpression<'ast, T>>, + Self::Error, + > { let left = e.left.fold(self)?; let right = e.right.fold(self)?; @@ -1316,22 +1392,26 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> { // if the two expressions are the same, we can reduce to `true`. // Note that if they are different we cannot reduce to `false`: `a == 1` may still be `true` even though `a` and `1` are different expressions if left == right { - return Ok(EqOrBoolean::Boolean(BooleanExpression::Value(true))); + return Ok(BinaryOrExpression::Expression(BooleanExpression::value( + true, + ))); } // if both expressions are constant, we can reduce the equality check after we put them in canonical form if left.is_constant() && right.is_constant() { let left = left.into_canonical_constant(); let right = right.into_canonical_constant(); - Ok(EqOrBoolean::Boolean(BooleanExpression::Value( + Ok(BinaryOrExpression::Expression(BooleanExpression::value( left == right, ))) } else { - Ok(EqOrBoolean::Eq(EqExpression::new(left, right))) + Ok(BinaryOrExpression::Binary(BinaryExpression::new( + left, right, + ))) } } - fn fold_boolean_expression( + fn fold_boolean_expression_cases( &mut self, e: BooleanExpression<'ast, T>, ) -> Result, Error> { @@ -1341,142 +1421,106 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, 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::FieldLt(box e1, box e2) => { - let e1 = self.fold_field_expression(e1)?; - let e2 = self.fold_field_expression(e2)?; - - match (e1, e2) { - (FieldElementExpression::Number(n1), FieldElementExpression::Number(n2)) => { - Ok(BooleanExpression::Value(n1 < n2)) - } - (e1, e2) => Ok(BooleanExpression::FieldLt(box e1, box e2)), - } - } - BooleanExpression::FieldLe(box e1, box e2) => { - let e1 = self.fold_field_expression(e1)?; - let e2 = self.fold_field_expression(e2)?; - - match (e1, e2) { - (FieldElementExpression::Number(n1), FieldElementExpression::Number(n2)) => { - Ok(BooleanExpression::Value(n1 <= n2)) - } - (e1, e2) => Ok(BooleanExpression::FieldLe(box e1, box e2)), - } - } - BooleanExpression::FieldGt(box e1, box e2) => { - let e1 = self.fold_field_expression(e1)?; - let e2 = self.fold_field_expression(e2)?; + BooleanExpression::FieldLt(e) => { + let e1 = self.fold_field_expression(*e.left)?; + let e2 = self.fold_field_expression(*e.right)?; match (e1, e2) { - (FieldElementExpression::Number(n1), FieldElementExpression::Number(n2)) => { - Ok(BooleanExpression::Value(n1 > n2)) + (FieldElementExpression::Value(n1), FieldElementExpression::Value(n2)) => { + Ok(BooleanExpression::value(n1.value < n2.value)) } - (e1, e2) => Ok(BooleanExpression::FieldGt(box e1, box e2)), + (e1, e2) => Ok(BooleanExpression::field_lt(e1, e2)), } } - BooleanExpression::FieldGe(box e1, box e2) => { - let e1 = self.fold_field_expression(e1)?; - let e2 = self.fold_field_expression(e2)?; + BooleanExpression::FieldLe(e) => { + let e1 = self.fold_field_expression(*e.left)?; + let e2 = self.fold_field_expression(*e.right)?; match (e1, e2) { - (FieldElementExpression::Number(n1), FieldElementExpression::Number(n2)) => { - Ok(BooleanExpression::Value(n1 >= n2)) - } - (e1, e2) => Ok(BooleanExpression::FieldGe(box e1, box e2)), - } - } - BooleanExpression::UintLt(box e1, box e2) => { - let e1 = self.fold_uint_expression(e1)?; - let e2 = self.fold_uint_expression(e2)?; - - match (e1.as_inner(), e2.as_inner()) { - (UExpressionInner::Value(n1), UExpressionInner::Value(n2)) => { - Ok(BooleanExpression::Value(n1 < n2)) + (FieldElementExpression::Value(n1), FieldElementExpression::Value(n2)) => { + Ok(BooleanExpression::value(n1.value <= n2.value)) } - _ => Ok(BooleanExpression::UintLt(box e1, box e2)), + (e1, e2) => Ok(BooleanExpression::field_le(e1, e2)), } } - BooleanExpression::UintLe(box e1, box e2) => { - let e1 = self.fold_uint_expression(e1)?; - let e2 = self.fold_uint_expression(e2)?; + BooleanExpression::UintLt(e) => { + let e1 = self.fold_uint_expression(*e.left)?; + let e2 = self.fold_uint_expression(*e.right)?; match (e1.as_inner(), e2.as_inner()) { (UExpressionInner::Value(n1), UExpressionInner::Value(n2)) => { - Ok(BooleanExpression::Value(n1 <= n2)) + Ok(BooleanExpression::value(n1.value < n2.value)) } - _ => Ok(BooleanExpression::UintLe(box e1, box e2)), + _ => Ok(BooleanExpression::uint_lt(e1, e2)), } } - BooleanExpression::UintGt(box e1, box e2) => { - let e1 = self.fold_uint_expression(e1)?; - let e2 = self.fold_uint_expression(e2)?; + BooleanExpression::UintLe(e) => { + let e1 = self.fold_uint_expression(*e.left)?; + let e2 = self.fold_uint_expression(*e.right)?; match (e1.as_inner(), e2.as_inner()) { (UExpressionInner::Value(n1), UExpressionInner::Value(n2)) => { - Ok(BooleanExpression::Value(n1 > n2)) + Ok(BooleanExpression::value(n1.value <= n2.value)) } - _ => Ok(BooleanExpression::UintGt(box e1, box e2)), + _ => Ok(BooleanExpression::uint_le(e1, e2)), } } - BooleanExpression::UintGe(box e1, box e2) => { - let e1 = self.fold_uint_expression(e1)?; - let e2 = self.fold_uint_expression(e2)?; - - match (e1.as_inner(), e2.as_inner()) { - (UExpressionInner::Value(n1), UExpressionInner::Value(n2)) => { - Ok(BooleanExpression::Value(n1 >= n2)) - } - _ => Ok(BooleanExpression::UintGe(box e1, box e2)), - } - } - BooleanExpression::Or(box e1, box e2) => { - let e1 = self.fold_boolean_expression(e1)?; - let e2 = self.fold_boolean_expression(e2)?; + BooleanExpression::Or(e) => { + let e1 = self.fold_boolean_expression(*e.left)?; + let e2 = self.fold_boolean_expression(*e.right)?; match (e1, e2) { // reduction of constants (BooleanExpression::Value(v1), BooleanExpression::Value(v2)) => { - Ok(BooleanExpression::Value(v1 || v2)) + Ok(BooleanExpression::value(v1.value || v2.value)) } // x || true == true - (_, BooleanExpression::Value(true)) | (BooleanExpression::Value(true), _) => { - Ok(BooleanExpression::Value(true)) + (_, BooleanExpression::Value(v)) | (BooleanExpression::Value(v), _) + if v.value => + { + Ok(BooleanExpression::value(true)) } // x || false == x - (e, BooleanExpression::Value(false)) | (BooleanExpression::Value(false), e) => { + (e, BooleanExpression::Value(v)) | (BooleanExpression::Value(v), e) + if !v.value => + { Ok(e) } - (e1, e2) => Ok(BooleanExpression::Or(box e1, box e2)), + (e1, e2) => Ok(BooleanExpression::bitor(e1, e2)), } } - BooleanExpression::And(box e1, box e2) => { - let e1 = self.fold_boolean_expression(e1)?; - let e2 = self.fold_boolean_expression(e2)?; + BooleanExpression::And(e) => { + let e1 = self.fold_boolean_expression(*e.left)?; + let e2 = self.fold_boolean_expression(*e.right)?; match (e1, e2) { // reduction of constants (BooleanExpression::Value(v1), BooleanExpression::Value(v2)) => { - Ok(BooleanExpression::Value(v1 && v2)) + Ok(BooleanExpression::value(v1.value && v2.value)) } // x && true == x - (e, BooleanExpression::Value(true)) | (BooleanExpression::Value(true), e) => { + (e, BooleanExpression::Value(v)) | (BooleanExpression::Value(v), e) + if v.value => + { Ok(e) } // x && false == false - (_, BooleanExpression::Value(false)) | (BooleanExpression::Value(false), _) => { - Ok(BooleanExpression::Value(false)) + (_, BooleanExpression::Value(v)) | (BooleanExpression::Value(v), _) + if !v.value => + { + Ok(BooleanExpression::value(false)) } - (e1, e2) => Ok(BooleanExpression::And(box e1, box e2)), + (e1, e2) => Ok(BooleanExpression::bitand(e1, e2)), } } - BooleanExpression::Not(box e) => { - let e = self.fold_boolean_expression(e)?; + BooleanExpression::Not(e) => { + let e = self.fold_boolean_expression(*e.inner)?; match e { - BooleanExpression::Value(v) => Ok(BooleanExpression::Value(!v)), - e => Ok(BooleanExpression::Not(box e)), + BooleanExpression::Value(v) => Ok(BooleanExpression::value(!v.value)), + e => Ok(BooleanExpression::not(e)), } } - e => fold_boolean_expression(self, e), + e => fold_boolean_expression_cases(self, e), } } } @@ -1496,225 +1540,235 @@ mod tests { #[test] fn add() { - let e = FieldElementExpression::Add( - box FieldElementExpression::Number(Bn128Field::from(2)), - box FieldElementExpression::Number(Bn128Field::from(3)), + let e = FieldElementExpression::add( + FieldElementExpression::value(Bn128Field::from(2)), + FieldElementExpression::value(Bn128Field::from(3)), ); assert_eq!( - Propagator::with_constants(&mut Constants::new()).fold_field_expression(e), - Ok(FieldElementExpression::Number(Bn128Field::from(5))) + Propagator::default().fold_field_expression(e), + Ok(FieldElementExpression::value(Bn128Field::from(5))) ); } #[test] fn sub() { - let e = FieldElementExpression::Sub( - box FieldElementExpression::Number(Bn128Field::from(3)), - box FieldElementExpression::Number(Bn128Field::from(2)), + let e = FieldElementExpression::sub( + FieldElementExpression::value(Bn128Field::from(3)), + FieldElementExpression::value(Bn128Field::from(2)), ); assert_eq!( - Propagator::with_constants(&mut Constants::new()).fold_field_expression(e), - Ok(FieldElementExpression::Number(Bn128Field::from(1))) + Propagator::default().fold_field_expression(e), + Ok(FieldElementExpression::value(Bn128Field::from(1))) ); } #[test] fn mult() { - let e = FieldElementExpression::Mult( - box FieldElementExpression::Number(Bn128Field::from(3)), - box FieldElementExpression::Number(Bn128Field::from(2)), + let e = FieldElementExpression::mul( + FieldElementExpression::value(Bn128Field::from(3)), + FieldElementExpression::value(Bn128Field::from(2)), ); assert_eq!( - Propagator::with_constants(&mut Constants::new()).fold_field_expression(e), - Ok(FieldElementExpression::Number(Bn128Field::from(6))) + Propagator::default().fold_field_expression(e), + Ok(FieldElementExpression::value(Bn128Field::from(6))) ); } #[test] fn div() { - let e = FieldElementExpression::Div( - box FieldElementExpression::Number(Bn128Field::from(6)), - box FieldElementExpression::Number(Bn128Field::from(2)), + let mut propagator = Propagator::default(); + + assert_eq!( + propagator.fold_field_expression(FieldElementExpression::div( + FieldElementExpression::value(Bn128Field::from(6)), + FieldElementExpression::value(Bn128Field::from(2)), + )), + Ok(FieldElementExpression::value(Bn128Field::from(3))) + ); + + assert_eq!( + propagator.fold_field_expression(FieldElementExpression::div( + FieldElementExpression::identifier("a".into()), + FieldElementExpression::value(Bn128Field::from(1)), + )), + Ok(FieldElementExpression::identifier("a".into())) ); assert_eq!( - Propagator::with_constants(&mut Constants::new()).fold_field_expression(e), - Ok(FieldElementExpression::Number(Bn128Field::from(3))) + propagator.fold_field_expression(FieldElementExpression::div( + FieldElementExpression::value(Bn128Field::from(6)), + FieldElementExpression::value(Bn128Field::from(0)), + )), + Err(Error::DivisionByZero) ); } #[test] fn pow() { - let e = FieldElementExpression::Pow( - box FieldElementExpression::Number(Bn128Field::from(2)), - box 3u32.into(), + let e = FieldElementExpression::pow( + FieldElementExpression::value(Bn128Field::from(2)), + 3u32.into(), ); assert_eq!( - Propagator::with_constants(&mut Constants::new()).fold_field_expression(e), - Ok(FieldElementExpression::Number(Bn128Field::from(8))) + Propagator::default().fold_field_expression(e), + Ok(FieldElementExpression::value(Bn128Field::from(8))) ); } #[test] fn left_shift() { - let mut constants = Constants::new(); - let mut propagator = Propagator::with_constants(&mut constants); + let mut propagator = Propagator::default(); assert_eq!( - propagator.fold_field_expression(FieldElementExpression::LeftShift( - box FieldElementExpression::identifier("a".into()), - box 0u32.into(), + propagator.fold_field_expression(FieldElementExpression::left_shift( + FieldElementExpression::identifier("a".into()), + 0u32.into(), )), Ok(FieldElementExpression::identifier("a".into())) ); assert_eq!( - propagator.fold_field_expression(FieldElementExpression::LeftShift( - box FieldElementExpression::Number(Bn128Field::from(2)), - box 2u32.into(), + propagator.fold_field_expression(FieldElementExpression::left_shift( + FieldElementExpression::value(Bn128Field::from(2)), + 2u32.into(), )), - Ok(FieldElementExpression::Number(Bn128Field::from(8))) + Ok(FieldElementExpression::value(Bn128Field::from(8))) ); assert_eq!( - propagator.fold_field_expression(FieldElementExpression::LeftShift( - box FieldElementExpression::Number(Bn128Field::from(1)), - box ((Bn128Field::get_required_bits() - 1) as u32).into(), + propagator.fold_field_expression(FieldElementExpression::left_shift( + FieldElementExpression::value(Bn128Field::from(1)), + ((Bn128Field::get_required_bits() - 1) as u32).into(), )), - Ok(FieldElementExpression::Number(Bn128Field::try_from_dec_str("14474011154664524427946373126085988481658748083205070504932198000989141204992").unwrap())) + Ok(FieldElementExpression::value(Bn128Field::try_from_dec_str("14474011154664524427946373126085988481658748083205070504932198000989141204992").unwrap())) ); assert_eq!( - propagator.fold_field_expression(FieldElementExpression::LeftShift( - box FieldElementExpression::Number(Bn128Field::from(3)), - box ((Bn128Field::get_required_bits() - 3) as u32).into(), + propagator.fold_field_expression(FieldElementExpression::left_shift( + FieldElementExpression::value(Bn128Field::from(3)), + ((Bn128Field::get_required_bits() - 3) as u32).into(), )), - Ok(FieldElementExpression::Number(Bn128Field::try_from_dec_str("10855508365998393320959779844564491361244061062403802878699148500741855903744").unwrap())) + Ok(FieldElementExpression::value(Bn128Field::try_from_dec_str("10855508365998393320959779844564491361244061062403802878699148500741855903744").unwrap())) ); assert_eq!( - propagator.fold_field_expression(FieldElementExpression::LeftShift( - box FieldElementExpression::Number(Bn128Field::from(1)), - box (Bn128Field::get_required_bits() as u32).into(), + propagator.fold_field_expression(FieldElementExpression::left_shift( + FieldElementExpression::value(Bn128Field::from(1)), + (Bn128Field::get_required_bits() as u32).into(), )), - Ok(FieldElementExpression::Number(Bn128Field::from(0))) + Ok(FieldElementExpression::value(Bn128Field::from(0))) ); } #[test] fn right_shift() { - let mut constants = Constants::new(); - let mut propagator = Propagator::with_constants(&mut constants); + let mut propagator = Propagator::default(); assert_eq!( - propagator.fold_field_expression(FieldElementExpression::RightShift( - box FieldElementExpression::identifier("a".into()), - box 0u32.into(), + propagator.fold_field_expression(FieldElementExpression::right_shift( + FieldElementExpression::identifier("a".into()), + 0u32.into(), )), Ok(FieldElementExpression::identifier("a".into())) ); assert_eq!( - propagator.fold_field_expression(FieldElementExpression::RightShift( - box FieldElementExpression::identifier("a".into()), - box (Bn128Field::get_required_bits() as u32).into(), + propagator.fold_field_expression(FieldElementExpression::right_shift( + FieldElementExpression::identifier("a".into()), + (Bn128Field::get_required_bits() as u32).into(), )), - Ok(FieldElementExpression::Number(Bn128Field::from(0))) + Ok(FieldElementExpression::value(Bn128Field::from(0))) ); assert_eq!( - propagator.fold_field_expression(FieldElementExpression::RightShift( - box FieldElementExpression::Number(Bn128Field::from(3)), - box 1u32.into(), + propagator.fold_field_expression(FieldElementExpression::right_shift( + FieldElementExpression::value(Bn128Field::from(3)), + 1u32.into(), )), - Ok(FieldElementExpression::Number(Bn128Field::from(1))) + Ok(FieldElementExpression::value(Bn128Field::from(1))) ); assert_eq!( - propagator.fold_field_expression(FieldElementExpression::RightShift( - box FieldElementExpression::Number(Bn128Field::from(2)), - box 2u32.into(), + propagator.fold_field_expression(FieldElementExpression::right_shift( + FieldElementExpression::value(Bn128Field::from(2)), + 2u32.into(), )), - Ok(FieldElementExpression::Number(Bn128Field::from(0))) + Ok(FieldElementExpression::value(Bn128Field::from(0))) ); assert_eq!( - propagator.fold_field_expression(FieldElementExpression::RightShift( - box FieldElementExpression::Number(Bn128Field::from(2)), - box 4u32.into(), + propagator.fold_field_expression(FieldElementExpression::right_shift( + FieldElementExpression::value(Bn128Field::from(2)), + 4u32.into(), )), - Ok(FieldElementExpression::Number(Bn128Field::from(0))) + Ok(FieldElementExpression::value(Bn128Field::from(0))) ); assert_eq!( - propagator.fold_field_expression(FieldElementExpression::RightShift( - box FieldElementExpression::Number(Bn128Field::max_value()), - box ((Bn128Field::get_required_bits() - 1) as u32).into(), + propagator.fold_field_expression(FieldElementExpression::right_shift( + FieldElementExpression::value(Bn128Field::max_value()), + ((Bn128Field::get_required_bits() - 1) as u32).into(), )), - Ok(FieldElementExpression::Number(Bn128Field::from(1))) + Ok(FieldElementExpression::value(Bn128Field::from(1))) ); assert_eq!( - propagator.fold_field_expression(FieldElementExpression::RightShift( - box FieldElementExpression::Number(Bn128Field::max_value()), - box (Bn128Field::get_required_bits() as u32).into(), + propagator.fold_field_expression(FieldElementExpression::right_shift( + FieldElementExpression::value(Bn128Field::max_value()), + (Bn128Field::get_required_bits() as u32).into(), )), - Ok(FieldElementExpression::Number(Bn128Field::from(0))) + Ok(FieldElementExpression::value(Bn128Field::from(0))) ); } #[test] fn if_else_true() { let e = FieldElementExpression::conditional( - BooleanExpression::Value(true), - FieldElementExpression::Number(Bn128Field::from(2)), - FieldElementExpression::Number(Bn128Field::from(3)), + BooleanExpression::value(true), + FieldElementExpression::value(Bn128Field::from(2)), + FieldElementExpression::value(Bn128Field::from(3)), ConditionalKind::IfElse, ); assert_eq!( - Propagator::with_constants(&mut Constants::new()).fold_field_expression(e), - Ok(FieldElementExpression::Number(Bn128Field::from(2))) + Propagator::default().fold_field_expression(e), + Ok(FieldElementExpression::value(Bn128Field::from(2))) ); } #[test] fn if_else_false() { let e = FieldElementExpression::conditional( - BooleanExpression::Value(false), - FieldElementExpression::Number(Bn128Field::from(2)), - FieldElementExpression::Number(Bn128Field::from(3)), + BooleanExpression::value(false), + FieldElementExpression::value(Bn128Field::from(2)), + FieldElementExpression::value(Bn128Field::from(3)), ConditionalKind::IfElse, ); assert_eq!( - Propagator::with_constants(&mut Constants::new()).fold_field_expression(e), - Ok(FieldElementExpression::Number(Bn128Field::from(3))) + Propagator::default().fold_field_expression(e), + Ok(FieldElementExpression::value(Bn128Field::from(3))) ); } #[test] fn select() { let e = FieldElementExpression::select( - ArrayExpressionInner::Value( - vec![ - FieldElementExpression::Number(Bn128Field::from(1)).into(), - FieldElementExpression::Number(Bn128Field::from(2)).into(), - FieldElementExpression::Number(Bn128Field::from(3)).into(), - ] - .into(), - ) - .annotate(Type::FieldElement, 3u32), - UExpressionInner::Add(box 1u32.into(), box 1u32.into()) - .annotate(UBitwidth::B32), + ArrayExpression::value(vec![ + FieldElementExpression::value(Bn128Field::from(1)).into(), + FieldElementExpression::value(Bn128Field::from(2)).into(), + FieldElementExpression::value(Bn128Field::from(3)).into(), + ]) + .annotate(ArrayType::new(Type::FieldElement, 3u32)), + UExpression::add(1u32.into(), 1u32.into()), ); assert_eq!( - Propagator::with_constants(&mut Constants::new()).fold_field_expression(e), - Ok(FieldElementExpression::Number(Bn128Field::from(3))) + Propagator::default().fold_field_expression(e), + Ok(FieldElementExpression::value(Bn128Field::from(3))) ); } } @@ -1726,73 +1780,66 @@ mod tests { #[test] fn not() { let e_true: BooleanExpression = - BooleanExpression::Not(box BooleanExpression::Value(false)); + BooleanExpression::not(BooleanExpression::value(false)); let e_false: BooleanExpression = - BooleanExpression::Not(box BooleanExpression::Value(true)); + BooleanExpression::not(BooleanExpression::value(true)); let e_default: BooleanExpression = - BooleanExpression::Not(box BooleanExpression::identifier("a".into())); + BooleanExpression::not(BooleanExpression::identifier("a".into())); assert_eq!( - Propagator::with_constants(&mut Constants::new()) - .fold_boolean_expression(e_true), - Ok(BooleanExpression::Value(true)) + Propagator::default().fold_boolean_expression(e_true), + Ok(BooleanExpression::value(true)) ); assert_eq!( - Propagator::with_constants(&mut Constants::new()) - .fold_boolean_expression(e_false), - Ok(BooleanExpression::Value(false)) + Propagator::default().fold_boolean_expression(e_false), + Ok(BooleanExpression::value(false)) ); assert_eq!( - Propagator::with_constants(&mut Constants::new()) - .fold_boolean_expression(e_default.clone()), + Propagator::default().fold_boolean_expression(e_default.clone()), Ok(e_default) ); } #[test] fn field_eq() { - let e_constant_true = BooleanExpression::FieldEq(EqExpression::new( - FieldElementExpression::Number(Bn128Field::from(2)), - FieldElementExpression::Number(Bn128Field::from(2)), + let e_constant_true = BooleanExpression::FieldEq(BinaryExpression::new( + FieldElementExpression::value(Bn128Field::from(2)), + FieldElementExpression::value(Bn128Field::from(2)), )); - let e_constant_false = BooleanExpression::FieldEq(EqExpression::new( - FieldElementExpression::Number(Bn128Field::from(4)), - FieldElementExpression::Number(Bn128Field::from(2)), + let e_constant_false = BooleanExpression::FieldEq(BinaryExpression::new( + FieldElementExpression::value(Bn128Field::from(4)), + FieldElementExpression::value(Bn128Field::from(2)), )); let e_identifier_true: BooleanExpression = - BooleanExpression::FieldEq(EqExpression::new( + BooleanExpression::FieldEq(BinaryExpression::new( FieldElementExpression::identifier("a".into()), FieldElementExpression::identifier("a".into()), )); let e_identifier_unchanged: BooleanExpression = - BooleanExpression::FieldEq(EqExpression::new( + BooleanExpression::FieldEq(BinaryExpression::new( FieldElementExpression::identifier("a".into()), FieldElementExpression::identifier("b".into()), )); assert_eq!( - Propagator::with_constants(&mut Constants::new()) - .fold_boolean_expression(e_constant_true), - Ok(BooleanExpression::Value(true)) + Propagator::default().fold_boolean_expression(e_constant_true), + Ok(BooleanExpression::value(true)) ); assert_eq!( - Propagator::with_constants(&mut Constants::new()) - .fold_boolean_expression(e_constant_false), - Ok(BooleanExpression::Value(false)) + Propagator::default().fold_boolean_expression(e_constant_false), + Ok(BooleanExpression::value(false)) ); assert_eq!( - Propagator::with_constants(&mut Constants::new()) - .fold_boolean_expression(e_identifier_true), - Ok(BooleanExpression::Value(true)) + Propagator::default().fold_boolean_expression(e_identifier_true), + Ok(BooleanExpression::value(true)) ); assert_eq!( - Propagator::with_constants(&mut Constants::new()) - .fold_boolean_expression(e_identifier_unchanged.clone()), + Propagator::default().fold_boolean_expression(e_identifier_unchanged.clone()), Ok(e_identifier_unchanged) ); } @@ -1800,263 +1847,227 @@ mod tests { #[test] fn bool_eq() { assert_eq!( - Propagator::::with_constants(&mut Constants::new()) - .fold_boolean_expression(BooleanExpression::BoolEq(EqExpression::new( - BooleanExpression::Value(false), - BooleanExpression::Value(false) - ))), - Ok(BooleanExpression::Value(true)) + Propagator::::default().fold_boolean_expression( + BooleanExpression::BoolEq(EqExpression::new( + BooleanExpression::value(false), + BooleanExpression::value(false) + )) + ), + Ok(BooleanExpression::value(true)) ); assert_eq!( - Propagator::::with_constants(&mut Constants::new()) - .fold_boolean_expression(BooleanExpression::BoolEq(EqExpression::new( - BooleanExpression::Value(true), - BooleanExpression::Value(true) - ))), - Ok(BooleanExpression::Value(true)) + Propagator::::default().fold_boolean_expression( + BooleanExpression::BoolEq(EqExpression::new( + BooleanExpression::value(true), + BooleanExpression::value(true) + )) + ), + Ok(BooleanExpression::value(true)) ); assert_eq!( - Propagator::::with_constants(&mut Constants::new()) - .fold_boolean_expression(BooleanExpression::BoolEq(EqExpression::new( - BooleanExpression::Value(true), - BooleanExpression::Value(false) - ))), - Ok(BooleanExpression::Value(false)) + Propagator::::default().fold_boolean_expression( + BooleanExpression::BoolEq(EqExpression::new( + BooleanExpression::value(true), + BooleanExpression::value(false) + )) + ), + Ok(BooleanExpression::value(false)) ); assert_eq!( - Propagator::::with_constants(&mut Constants::new()) - .fold_boolean_expression(BooleanExpression::BoolEq(EqExpression::new( - BooleanExpression::Value(false), - BooleanExpression::Value(true) - ))), - Ok(BooleanExpression::Value(false)) + Propagator::::default().fold_boolean_expression( + BooleanExpression::BoolEq(EqExpression::new( + BooleanExpression::value(false), + BooleanExpression::value(true) + )) + ), + Ok(BooleanExpression::value(false)) ); } #[test] fn array_eq() { - let e_constant_true = BooleanExpression::ArrayEq(EqExpression::new( - ArrayExpressionInner::Value( - vec![TypedExpressionOrSpread::Expression( - FieldElementExpression::Number(Bn128Field::from(2usize)).into(), - )] - .into(), - ) - .annotate(Type::FieldElement, 1u32), - ArrayExpressionInner::Value( - vec![TypedExpressionOrSpread::Expression( - FieldElementExpression::Number(Bn128Field::from(2usize)).into(), - )] - .into(), - ) - .annotate(Type::FieldElement, 1u32), + let e_constant_true = BooleanExpression::ArrayEq(BinaryExpression::new( + ArrayExpression::value(vec![TypedExpressionOrSpread::Expression( + FieldElementExpression::value(Bn128Field::from(2usize)).into(), + )]) + .annotate(ArrayType::new(Type::FieldElement, 1u32)), + ArrayExpression::value(vec![TypedExpressionOrSpread::Expression( + FieldElementExpression::value(Bn128Field::from(2usize)).into(), + )]) + .annotate(ArrayType::new(Type::FieldElement, 1u32)), )); - let e_constant_false = BooleanExpression::ArrayEq(EqExpression::new( - ArrayExpressionInner::Value( - vec![TypedExpressionOrSpread::Expression( - FieldElementExpression::Number(Bn128Field::from(2usize)).into(), - )] - .into(), - ) - .annotate(Type::FieldElement, 1u32), - ArrayExpressionInner::Value( - vec![TypedExpressionOrSpread::Expression( - FieldElementExpression::Number(Bn128Field::from(4usize)).into(), - )] - .into(), - ) - .annotate(Type::FieldElement, 1u32), + let e_constant_false = BooleanExpression::ArrayEq(BinaryExpression::new( + ArrayExpression::value(vec![TypedExpressionOrSpread::Expression( + FieldElementExpression::value(Bn128Field::from(2usize)).into(), + )]) + .annotate(ArrayType::new(Type::FieldElement, 1u32)), + ArrayExpression::value(vec![TypedExpressionOrSpread::Expression( + FieldElementExpression::value(Bn128Field::from(4usize)).into(), + )]) + .annotate(ArrayType::new(Type::FieldElement, 1u32)), )); let e_identifier_true: BooleanExpression = - BooleanExpression::ArrayEq(EqExpression::new( - ArrayExpression::identifier("a".into()).annotate(Type::FieldElement, 1u32), - ArrayExpression::identifier("a".into()).annotate(Type::FieldElement, 1u32), + BooleanExpression::ArrayEq(BinaryExpression::new( + ArrayExpression::identifier("a".into()) + .annotate(ArrayType::new(Type::FieldElement, 1u32)), + ArrayExpression::identifier("a".into()) + .annotate(ArrayType::new(Type::FieldElement, 1u32)), )); let e_identifier_unchanged: BooleanExpression = - BooleanExpression::ArrayEq(EqExpression::new( - ArrayExpression::identifier("a".into()).annotate(Type::FieldElement, 1u32), - ArrayExpression::identifier("b".into()).annotate(Type::FieldElement, 1u32), + BooleanExpression::ArrayEq(BinaryExpression::new( + ArrayExpression::identifier("a".into()) + .annotate(ArrayType::new(Type::FieldElement, 1u32)), + ArrayExpression::identifier("b".into()) + .annotate(ArrayType::new(Type::FieldElement, 1u32)), )); - let e_non_canonical_true = BooleanExpression::ArrayEq(EqExpression::new( - ArrayExpressionInner::Value( - vec![TypedExpressionOrSpread::Spread( - ArrayExpressionInner::Value( - vec![TypedExpressionOrSpread::Expression( - FieldElementExpression::Number(Bn128Field::from(2usize)).into(), - )] - .into(), - ) - .annotate(Type::FieldElement, 1u32) - .into(), - )] - .into(), - ) - .annotate(Type::FieldElement, 1u32), - ArrayExpressionInner::Value( - vec![TypedExpressionOrSpread::Expression( - FieldElementExpression::Number(Bn128Field::from(2usize)).into(), - )] + let e_non_canonical_true = BooleanExpression::ArrayEq(BinaryExpression::new( + ArrayExpression::value(vec![TypedExpressionOrSpread::Spread( + ArrayExpression::value(vec![TypedExpressionOrSpread::Expression( + FieldElementExpression::value(Bn128Field::from(2usize)).into(), + )]) + .annotate(ArrayType::new(Type::FieldElement, 1u32)) .into(), - ) - .annotate(Type::FieldElement, 1u32), + )]) + .annotate(ArrayType::new(Type::FieldElement, 1u32)), + ArrayExpression::value(vec![TypedExpressionOrSpread::Expression( + FieldElementExpression::value(Bn128Field::from(2usize)).into(), + )]) + .annotate(ArrayType::new(Type::FieldElement, 1u32)), )); - let e_non_canonical_false = BooleanExpression::ArrayEq(EqExpression::new( - ArrayExpressionInner::Value( - vec![TypedExpressionOrSpread::Spread( - ArrayExpressionInner::Value( - vec![TypedExpressionOrSpread::Expression( - FieldElementExpression::Number(Bn128Field::from(2usize)).into(), - )] - .into(), - ) - .annotate(Type::FieldElement, 1u32) - .into(), - )] - .into(), - ) - .annotate(Type::FieldElement, 1u32), - ArrayExpressionInner::Value( - vec![TypedExpressionOrSpread::Expression( - FieldElementExpression::Number(Bn128Field::from(4usize)).into(), - )] + let e_non_canonical_false = BooleanExpression::ArrayEq(BinaryExpression::new( + ArrayExpression::value(vec![TypedExpressionOrSpread::Spread( + ArrayExpression::value(vec![TypedExpressionOrSpread::Expression( + FieldElementExpression::value(Bn128Field::from(2usize)).into(), + )]) + .annotate(ArrayType::new(Type::FieldElement, 1u32)) .into(), - ) - .annotate(Type::FieldElement, 1u32), + )]) + .annotate(ArrayType::new(Type::FieldElement, 1u32)), + ArrayExpression::value(vec![TypedExpressionOrSpread::Expression( + FieldElementExpression::value(Bn128Field::from(4usize)).into(), + )]) + .annotate(ArrayType::new(Type::FieldElement, 1u32)), )); assert_eq!( - Propagator::with_constants(&mut Constants::new()) - .fold_boolean_expression(e_constant_true), - Ok(BooleanExpression::Value(true)) + Propagator::default().fold_boolean_expression(e_constant_true), + Ok(BooleanExpression::value(true)) ); assert_eq!( - Propagator::with_constants(&mut Constants::new()) - .fold_boolean_expression(e_constant_false), - Ok(BooleanExpression::Value(false)) + Propagator::default().fold_boolean_expression(e_constant_false), + Ok(BooleanExpression::value(false)) ); assert_eq!( - Propagator::with_constants(&mut Constants::new()) - .fold_boolean_expression(e_identifier_true), - Ok(BooleanExpression::Value(true)) + Propagator::default().fold_boolean_expression(e_identifier_true), + Ok(BooleanExpression::value(true)) ); assert_eq!( - Propagator::with_constants(&mut Constants::new()) - .fold_boolean_expression(e_identifier_unchanged.clone()), + Propagator::default().fold_boolean_expression(e_identifier_unchanged.clone()), Ok(e_identifier_unchanged) ); assert_eq!( - Propagator::with_constants(&mut Constants::new()) - .fold_boolean_expression(e_non_canonical_true), - Ok(BooleanExpression::Value(true)) + Propagator::default().fold_boolean_expression(e_non_canonical_true), + Ok(BooleanExpression::value(true)) ); assert_eq!( - Propagator::with_constants(&mut Constants::new()) - .fold_boolean_expression(e_non_canonical_false), - Ok(BooleanExpression::Value(false)) + Propagator::default().fold_boolean_expression(e_non_canonical_false), + Ok(BooleanExpression::value(false)) ); } #[test] fn lt() { - let e_true = BooleanExpression::FieldLt( - box FieldElementExpression::Number(Bn128Field::from(2)), - box FieldElementExpression::Number(Bn128Field::from(4)), + let e_true = BooleanExpression::field_lt( + FieldElementExpression::value(Bn128Field::from(2)), + FieldElementExpression::value(Bn128Field::from(4)), ); - let e_false = BooleanExpression::FieldLt( - box FieldElementExpression::Number(Bn128Field::from(4)), - box FieldElementExpression::Number(Bn128Field::from(2)), + let e_false = BooleanExpression::field_lt( + FieldElementExpression::value(Bn128Field::from(4)), + FieldElementExpression::value(Bn128Field::from(2)), ); assert_eq!( - Propagator::with_constants(&mut Constants::new()) - .fold_boolean_expression(e_true), - Ok(BooleanExpression::Value(true)) + Propagator::default().fold_boolean_expression(e_true), + Ok(BooleanExpression::value(true)) ); assert_eq!( - Propagator::with_constants(&mut Constants::new()) - .fold_boolean_expression(e_false), - Ok(BooleanExpression::Value(false)) + Propagator::default().fold_boolean_expression(e_false), + Ok(BooleanExpression::value(false)) ); } #[test] fn le() { - let e_true = BooleanExpression::FieldLe( - box FieldElementExpression::Number(Bn128Field::from(2)), - box FieldElementExpression::Number(Bn128Field::from(2)), + let e_true = BooleanExpression::field_le( + FieldElementExpression::value(Bn128Field::from(2)), + FieldElementExpression::value(Bn128Field::from(2)), ); - let e_false = BooleanExpression::FieldLe( - box FieldElementExpression::Number(Bn128Field::from(4)), - box FieldElementExpression::Number(Bn128Field::from(2)), + let e_false = BooleanExpression::field_le( + FieldElementExpression::value(Bn128Field::from(4)), + FieldElementExpression::value(Bn128Field::from(2)), ); assert_eq!( - Propagator::with_constants(&mut Constants::new()) - .fold_boolean_expression(e_true), - Ok(BooleanExpression::Value(true)) + Propagator::default().fold_boolean_expression(e_true), + Ok(BooleanExpression::value(true)) ); assert_eq!( - Propagator::with_constants(&mut Constants::new()) - .fold_boolean_expression(e_false), - Ok(BooleanExpression::Value(false)) + Propagator::default().fold_boolean_expression(e_false), + Ok(BooleanExpression::value(false)) ); } #[test] fn gt() { - let e_true = BooleanExpression::FieldGt( - box FieldElementExpression::Number(Bn128Field::from(5)), - box FieldElementExpression::Number(Bn128Field::from(4)), + let e_true = BooleanExpression::field_gt( + FieldElementExpression::value(Bn128Field::from(5)), + FieldElementExpression::value(Bn128Field::from(4)), ); - let e_false = BooleanExpression::FieldGt( - box FieldElementExpression::Number(Bn128Field::from(4)), - box FieldElementExpression::Number(Bn128Field::from(5)), + let e_false = BooleanExpression::field_gt( + FieldElementExpression::value(Bn128Field::from(4)), + FieldElementExpression::value(Bn128Field::from(5)), ); assert_eq!( - Propagator::with_constants(&mut Constants::new()) - .fold_boolean_expression(e_true), - Ok(BooleanExpression::Value(true)) + Propagator::default().fold_boolean_expression(e_true), + Ok(BooleanExpression::value(true)) ); assert_eq!( - Propagator::with_constants(&mut Constants::new()) - .fold_boolean_expression(e_false), - Ok(BooleanExpression::Value(false)) + Propagator::default().fold_boolean_expression(e_false), + Ok(BooleanExpression::value(false)) ); } #[test] fn ge() { - let e_true = BooleanExpression::FieldGe( - box FieldElementExpression::Number(Bn128Field::from(5)), - box FieldElementExpression::Number(Bn128Field::from(5)), + let e_true = BooleanExpression::field_ge( + FieldElementExpression::value(Bn128Field::from(5)), + FieldElementExpression::value(Bn128Field::from(5)), ); - let e_false = BooleanExpression::FieldGe( - box FieldElementExpression::Number(Bn128Field::from(4)), - box FieldElementExpression::Number(Bn128Field::from(5)), + let e_false = BooleanExpression::field_ge( + FieldElementExpression::value(Bn128Field::from(4)), + FieldElementExpression::value(Bn128Field::from(5)), ); assert_eq!( - Propagator::with_constants(&mut Constants::new()) - .fold_boolean_expression(e_true), - Ok(BooleanExpression::Value(true)) + Propagator::default().fold_boolean_expression(e_true), + Ok(BooleanExpression::value(true)) ); assert_eq!( - Propagator::with_constants(&mut Constants::new()) - .fold_boolean_expression(e_false), - Ok(BooleanExpression::Value(false)) + Propagator::default().fold_boolean_expression(e_false), + Ok(BooleanExpression::value(false)) ); } @@ -2065,68 +2076,76 @@ mod tests { let a_bool: Identifier = "a".into(); assert_eq!( - Propagator::::with_constants(&mut Constants::new()) - .fold_boolean_expression(BooleanExpression::And( - box BooleanExpression::Value(true), - box BooleanExpression::identifier(a_bool.clone()) - )), + Propagator::::default().fold_boolean_expression( + BooleanExpression::bitand( + BooleanExpression::value(true), + BooleanExpression::identifier(a_bool.clone()) + ) + ), Ok(BooleanExpression::identifier(a_bool.clone())) ); assert_eq!( - Propagator::::with_constants(&mut Constants::new()) - .fold_boolean_expression(BooleanExpression::And( - box BooleanExpression::identifier(a_bool.clone()), - box BooleanExpression::Value(true), - )), + Propagator::::default().fold_boolean_expression( + BooleanExpression::bitand( + BooleanExpression::identifier(a_bool.clone()), + BooleanExpression::value(true), + ) + ), Ok(BooleanExpression::identifier(a_bool.clone())) ); assert_eq!( - Propagator::::with_constants(&mut Constants::new()) - .fold_boolean_expression(BooleanExpression::And( - box BooleanExpression::Value(false), - box BooleanExpression::identifier(a_bool.clone()) - )), - Ok(BooleanExpression::Value(false)) + Propagator::::default().fold_boolean_expression( + BooleanExpression::bitand( + BooleanExpression::value(false), + BooleanExpression::identifier(a_bool.clone()) + ) + ), + Ok(BooleanExpression::value(false)) ); assert_eq!( - Propagator::::with_constants(&mut Constants::new()) - .fold_boolean_expression(BooleanExpression::And( - box BooleanExpression::identifier(a_bool.clone()), - box BooleanExpression::Value(false), - )), - Ok(BooleanExpression::Value(false)) + Propagator::::default().fold_boolean_expression( + BooleanExpression::bitand( + BooleanExpression::identifier(a_bool.clone()), + BooleanExpression::value(false), + ) + ), + Ok(BooleanExpression::value(false)) ); assert_eq!( - Propagator::::with_constants(&mut Constants::new()) - .fold_boolean_expression(BooleanExpression::And( - box BooleanExpression::Value(true), - box BooleanExpression::Value(false), - )), - Ok(BooleanExpression::Value(false)) + Propagator::::default().fold_boolean_expression( + BooleanExpression::bitand( + BooleanExpression::value(true), + BooleanExpression::value(false), + ) + ), + Ok(BooleanExpression::value(false)) ); assert_eq!( - Propagator::::with_constants(&mut Constants::new()) - .fold_boolean_expression(BooleanExpression::And( - box BooleanExpression::Value(false), - box BooleanExpression::Value(true), - )), - Ok(BooleanExpression::Value(false)) + Propagator::::default().fold_boolean_expression( + BooleanExpression::bitand( + BooleanExpression::value(false), + BooleanExpression::value(true), + ) + ), + Ok(BooleanExpression::value(false)) ); assert_eq!( - Propagator::::with_constants(&mut Constants::new()) - .fold_boolean_expression(BooleanExpression::And( - box BooleanExpression::Value(true), - box BooleanExpression::Value(true), - )), - Ok(BooleanExpression::Value(true)) + Propagator::::default().fold_boolean_expression( + BooleanExpression::bitand( + BooleanExpression::value(true), + BooleanExpression::value(true), + ) + ), + Ok(BooleanExpression::value(true)) ); assert_eq!( - Propagator::::with_constants(&mut Constants::new()) - .fold_boolean_expression(BooleanExpression::And( - box BooleanExpression::Value(false), - box BooleanExpression::Value(false), - )), - Ok(BooleanExpression::Value(false)) + Propagator::::default().fold_boolean_expression( + BooleanExpression::bitand( + BooleanExpression::value(false), + BooleanExpression::value(false), + ) + ), + Ok(BooleanExpression::value(false)) ); } @@ -2135,68 +2154,76 @@ mod tests { let a_bool: Identifier = "a".into(); assert_eq!( - Propagator::::with_constants(&mut Constants::new()) - .fold_boolean_expression(BooleanExpression::Or( - box BooleanExpression::Value(true), - box BooleanExpression::identifier(a_bool.clone()) - )), - Ok(BooleanExpression::Value(true)) + Propagator::::default().fold_boolean_expression( + BooleanExpression::bitor( + BooleanExpression::value(true), + BooleanExpression::identifier(a_bool.clone()) + ) + ), + Ok(BooleanExpression::value(true)) ); assert_eq!( - Propagator::::with_constants(&mut Constants::new()) - .fold_boolean_expression(BooleanExpression::Or( - box BooleanExpression::identifier(a_bool.clone()), - box BooleanExpression::Value(true), - )), - Ok(BooleanExpression::Value(true)) + Propagator::::default().fold_boolean_expression( + BooleanExpression::bitor( + BooleanExpression::identifier(a_bool.clone()), + BooleanExpression::value(true), + ) + ), + Ok(BooleanExpression::value(true)) ); assert_eq!( - Propagator::::with_constants(&mut Constants::new()) - .fold_boolean_expression(BooleanExpression::Or( - box BooleanExpression::Value(false), - box BooleanExpression::identifier(a_bool.clone()) - )), + Propagator::::default().fold_boolean_expression( + BooleanExpression::bitor( + BooleanExpression::value(false), + BooleanExpression::identifier(a_bool.clone()) + ) + ), Ok(BooleanExpression::identifier(a_bool.clone())) ); assert_eq!( - Propagator::::with_constants(&mut Constants::new()) - .fold_boolean_expression(BooleanExpression::Or( - box BooleanExpression::identifier(a_bool.clone()), - box BooleanExpression::Value(false), - )), + Propagator::::default().fold_boolean_expression( + BooleanExpression::bitor( + BooleanExpression::identifier(a_bool.clone()), + BooleanExpression::value(false), + ) + ), Ok(BooleanExpression::identifier(a_bool.clone())) ); assert_eq!( - Propagator::::with_constants(&mut Constants::new()) - .fold_boolean_expression(BooleanExpression::Or( - box BooleanExpression::Value(true), - box BooleanExpression::Value(false), - )), - Ok(BooleanExpression::Value(true)) + Propagator::::default().fold_boolean_expression( + BooleanExpression::bitor( + BooleanExpression::value(true), + BooleanExpression::value(false), + ) + ), + Ok(BooleanExpression::value(true)) ); assert_eq!( - Propagator::::with_constants(&mut Constants::new()) - .fold_boolean_expression(BooleanExpression::Or( - box BooleanExpression::Value(false), - box BooleanExpression::Value(true), - )), - Ok(BooleanExpression::Value(true)) + Propagator::::default().fold_boolean_expression( + BooleanExpression::bitor( + BooleanExpression::value(false), + BooleanExpression::value(true), + ) + ), + Ok(BooleanExpression::value(true)) ); assert_eq!( - Propagator::::with_constants(&mut Constants::new()) - .fold_boolean_expression(BooleanExpression::Or( - box BooleanExpression::Value(true), - box BooleanExpression::Value(true), - )), - Ok(BooleanExpression::Value(true)) + Propagator::::default().fold_boolean_expression( + BooleanExpression::bitor( + BooleanExpression::value(true), + BooleanExpression::value(true), + ) + ), + Ok(BooleanExpression::value(true)) ); assert_eq!( - Propagator::::with_constants(&mut Constants::new()) - .fold_boolean_expression(BooleanExpression::Or( - box BooleanExpression::Value(false), - box BooleanExpression::Value(false), - )), - Ok(BooleanExpression::Value(false)) + Propagator::::default().fold_boolean_expression( + BooleanExpression::bitor( + BooleanExpression::value(false), + BooleanExpression::value(false), + ) + ), + Ok(BooleanExpression::value(false)) ); } } diff --git a/zokrates_analysis/src/reducer/constants_reader.rs b/zokrates_analysis/src/reducer/constants_reader.rs index 4ee0d1359..ca882dfdd 100644 --- a/zokrates_analysis/src/reducer/constants_reader.rs +++ b/zokrates_analysis/src/reducer/constants_reader.rs @@ -2,14 +2,13 @@ use crate::reducer::ConstantDefinitions; use zokrates_ast::typed::{ - folder::*, ArrayExpression, ArrayExpressionInner, ArrayType, BooleanExpression, CoreIdentifier, - DeclarationConstant, Expr, FieldElementExpression, Id, Identifier, IdentifierExpression, - StructExpression, StructExpressionInner, StructType, TupleExpression, TupleExpressionInner, - TupleType, TypedProgram, TypedSymbolDeclaration, UBitwidth, UExpression, UExpressionInner, + folder::*, identifier::FrameIdentifier, CoreIdentifier, DeclarationConstant, Expr, Id, + Identifier, IdentifierExpression, IdentifierOrExpression, TypedExpression, TypedProgram, + TypedSymbolDeclaration, UExpression, UExpressionInner, }; use zokrates_field::Field; -use std::convert::{TryFrom, TryInto}; +use std::convert::TryFrom; pub struct ConstantsReader<'a, 'ast, T> { constants: &'a ConstantDefinitions<'ast, T>, @@ -43,7 +42,7 @@ impl<'a, 'ast, T: Field> Folder<'ast, T> for ConstantsReader<'a, 'ast, T> { match self.constants.get(&c).cloned() { Some(e) => match UExpression::try_from(e).unwrap().into_inner() { - UExpressionInner::Value(v) => DeclarationConstant::Concrete(v as u32), + UExpressionInner::Value(v) => DeclarationConstant::Concrete(v.value as u32), _ => unreachable!(), }, None => DeclarationConstant::Constant(c), @@ -53,155 +52,31 @@ impl<'a, 'ast, T: Field> Folder<'ast, T> for ConstantsReader<'a, 'ast, T> { } } - fn fold_field_expression( + fn fold_identifier_expression< + E: Expr<'ast, T> + Id<'ast, T> + From>, + >( &mut self, - e: FieldElementExpression<'ast, T>, - ) -> FieldElementExpression<'ast, T> { - match e { - FieldElementExpression::Identifier(IdentifierExpression { + ty: &E::Ty, + e: IdentifierExpression<'ast, E>, + ) -> IdentifierOrExpression<'ast, T, E> { + match e.id { + Identifier { id: - Identifier { + FrameIdentifier { id: CoreIdentifier::Constant(c), - version, + frame: _, }, - .. - }) => { + version, + } => { assert_eq!(version, 0); match self.constants.get(&c).cloned() { - Some(v) => v.try_into().unwrap(), - None => FieldElementExpression::identifier(Identifier::from( - CoreIdentifier::Constant(c), + Some(v) => IdentifierOrExpression::Expression(E::from(v).into_inner()), + None => IdentifierOrExpression::Identifier(IdentifierExpression::new( + CoreIdentifier::Constant(c).into(), )), } } - e => fold_field_expression(self, e), - } - } - - fn fold_boolean_expression( - &mut self, - e: BooleanExpression<'ast, T>, - ) -> BooleanExpression<'ast, T> { - match e { - BooleanExpression::Identifier(IdentifierExpression { - id: - Identifier { - id: CoreIdentifier::Constant(c), - version, - }, - .. - }) => { - assert_eq!(version, 0); - match self.constants.get(&c).cloned() { - Some(v) => v.try_into().unwrap(), - None => { - BooleanExpression::identifier(Identifier::from(CoreIdentifier::Constant(c))) - } - } - } - e => fold_boolean_expression(self, e), - } - } - - fn fold_uint_expression_inner( - &mut self, - ty: UBitwidth, - e: UExpressionInner<'ast, T>, - ) -> UExpressionInner<'ast, T> { - match e { - UExpressionInner::Identifier(IdentifierExpression { - id: - Identifier { - id: CoreIdentifier::Constant(c), - version, - }, - .. - }) => { - assert_eq!(version, 0); - match self.constants.get(&c).cloned() { - Some(v) => UExpression::try_from(v).unwrap().into_inner(), - None => UExpression::identifier(Identifier::from(CoreIdentifier::Constant(c))), - } - } - e => fold_uint_expression_inner(self, ty, e), - } - } - - fn fold_array_expression_inner( - &mut self, - ty: &ArrayType<'ast, T>, - e: ArrayExpressionInner<'ast, T>, - ) -> ArrayExpressionInner<'ast, T> { - match e { - ArrayExpressionInner::Identifier(IdentifierExpression { - id: - Identifier { - id: CoreIdentifier::Constant(c), - version, - }, - .. - }) => { - assert_eq!(version, 0); - match self.constants.get(&c).cloned() { - Some(v) => ArrayExpression::try_from(v).unwrap().into_inner(), - None => { - ArrayExpression::identifier(Identifier::from(CoreIdentifier::Constant(c))) - } - } - } - e => fold_array_expression_inner(self, ty, e), - } - } - - fn fold_tuple_expression_inner( - &mut self, - ty: &TupleType<'ast, T>, - e: TupleExpressionInner<'ast, T>, - ) -> TupleExpressionInner<'ast, T> { - match e { - TupleExpressionInner::Identifier(IdentifierExpression { - id: - Identifier { - id: CoreIdentifier::Constant(c), - version, - }, - .. - }) => { - assert_eq!(version, 0); - match self.constants.get(&c).cloned() { - Some(v) => TupleExpression::try_from(v).unwrap().into_inner(), - None => { - TupleExpression::identifier(Identifier::from(CoreIdentifier::Constant(c))) - } - } - } - e => fold_tuple_expression_inner(self, ty, e), - } - } - - fn fold_struct_expression_inner( - &mut self, - ty: &StructType<'ast, T>, - e: StructExpressionInner<'ast, T>, - ) -> StructExpressionInner<'ast, T> { - match e { - StructExpressionInner::Identifier(IdentifierExpression { - id: - Identifier { - id: CoreIdentifier::Constant(c), - version, - }, - .. - }) => { - assert_eq!(version, 0); - match self.constants.get(&c).cloned() { - Some(v) => StructExpression::try_from(v).unwrap().into_inner(), - None => { - StructExpression::identifier(Identifier::from(CoreIdentifier::Constant(c))) - } - } - } - e => fold_struct_expression_inner(self, ty, e), + _ => fold_identifier_expression(self, ty, e), } } } diff --git a/zokrates_analysis/src/reducer/constants_writer.rs b/zokrates_analysis/src/reducer/constants_writer.rs index d4e03d3d4..a96d0c8d5 100644 --- a/zokrates_analysis/src/reducer/constants_writer.rs +++ b/zokrates_analysis/src/reducer/constants_writer.rs @@ -3,18 +3,17 @@ use crate::reducer::{ constants_reader::ConstantsReader, reduce_function, ConstantDefinitions, Error, }; -use std::collections::{BTreeMap, HashSet}; +use std::collections::HashSet; use zokrates_ast::typed::{ - result_folder::*, types::ConcreteGenericsAssignment, Constant, OwnedTypedModuleId, Typed, - TypedConstant, TypedConstantSymbol, TypedConstantSymbolDeclaration, TypedModuleId, - TypedProgram, TypedSymbolDeclaration, UExpression, + result_folder::*, Constant, ModuleId, OwnedModuleId, Typed, TypedConstant, TypedConstantSymbol, + TypedConstantSymbolDeclaration, TypedProgram, TypedSymbolDeclaration, UExpression, }; use zokrates_field::Field; pub struct ConstantsWriter<'ast, T> { - treated: HashSet, + treated: HashSet, constants: ConstantDefinitions<'ast, T>, - location: OwnedTypedModuleId, + location: OwnedModuleId, program: TypedProgram<'ast, T>, } @@ -28,22 +27,19 @@ impl<'ast, T: Field> ConstantsWriter<'ast, T> { } } - fn change_location(&mut self, location: OwnedTypedModuleId) -> OwnedTypedModuleId { + fn change_location(&mut self, location: OwnedModuleId) -> OwnedModuleId { let prev = self.location.clone(); self.location = location; self.treated.insert(self.location.clone()); prev } - fn treated(&self, id: &TypedModuleId) -> bool { + fn treated(&self, id: &ModuleId) -> bool { self.treated.contains(id) } fn update_program(&mut self) { - let mut p = TypedProgram { - main: "".into(), - modules: BTreeMap::default(), - }; + let mut p = TypedProgram::default(); std::mem::swap(&mut self.program, &mut p); self.program = ConstantsReader::with_constants(&self.constants).read_into_program(p); } @@ -59,10 +55,7 @@ impl<'ast, T: Field> ConstantsWriter<'ast, T> { impl<'ast, T: Field> ResultFolder<'ast, T> for ConstantsWriter<'ast, T> { type Error = Error; - fn fold_module_id( - &mut self, - id: OwnedTypedModuleId, - ) -> Result { + fn fold_module_id(&mut self, id: OwnedModuleId) -> Result { // anytime we encounter a module id, visit the corresponding module if it hasn't been done yet if !self.treated(&id) { let current_m_id = self.change_location(id.clone()); @@ -114,19 +107,15 @@ impl<'ast, T: Field> ResultFolder<'ast, T> for ConstantsWriter<'ast, T> { // wrap this expression in a function let wrapper = TypedFunction { arguments: vec![], - statements: vec![TypedStatement::Return(c.expression)], + statements: vec![TypedStatement::ret(c.expression)], signature: DeclarationSignature::new().output(c.ty.clone()), }; - let mut inlined_wrapper = reduce_function( - wrapper, - ConcreteGenericsAssignment::default(), - &self.program, - )?; + let mut inlined_wrapper = reduce_function(wrapper, &self.program)?; + + if let TypedStatement::Return(ret) = inlined_wrapper.statements.pop().unwrap() { + let expression = ret.inner; - if let TypedStatement::Return(expression) = - inlined_wrapper.statements.pop().unwrap() - { if !expression.is_constant() { return Err(Error::ConstantReduction(id.id.to_string(), id.module)); }; diff --git a/zokrates_analysis/src/reducer/inline.rs b/zokrates_analysis/src/reducer/inline.rs index 31f237e82..254952498 100644 --- a/zokrates_analysis/src/reducer/inline.rs +++ b/zokrates_analysis/src/reducer/inline.rs @@ -15,25 +15,24 @@ // ``` // // Becomes -// ``` -// # Call foo::<42> with a_0 := x -// n_0 = 42 -// a_1 = a_0 -// n_1 = n_0 -// # Pop call with #CALL_RETURN_AT_INDEX_0_0 := a_1 +// inputs: [a] +// arguments: [x] +// generics_bindings: [n = 42] +// statements: +// n = 42 +// a = a +// n = n +// return_expression: a // Notes: -// - The body of the function is in SSA form -// - The return value(s) are assigned to internal variables - -use crate::reducer::Output; -use crate::reducer::ShallowTransformer; -use crate::reducer::Versions; +// - The body of the function is *not* in SSA form use zokrates_ast::common::FlatEmbed; use zokrates_ast::typed::types::{ConcreteGenericsAssignment, IntoType}; use zokrates_ast::typed::CoreIdentifier; -use zokrates_ast::typed::Identifier; + +use zokrates_ast::typed::TypedAssignee; +use zokrates_ast::typed::UBitwidth; use zokrates_ast::typed::{ ConcreteFunctionKey, ConcreteSignature, ConcreteVariable, DeclarationFunctionKey, Expr, Signature, Type, TypedExpression, TypedFunctionSymbol, TypedFunctionSymbolDeclaration, @@ -43,22 +42,12 @@ use zokrates_field::Field; pub enum InlineError<'ast, T> { Generic(DeclarationFunctionKey<'ast, T>, ConcreteFunctionKey<'ast>), - Flat( - FlatEmbed, - Vec, - Vec>, - Type<'ast, T>, - ), - NonConstant( - DeclarationFunctionKey<'ast, T>, - Vec>>, - Vec>, - Type<'ast, T>, - ), + Flat(FlatEmbed, Vec, Type<'ast, T>), + NonConstant, } fn get_canonical_function<'ast, T: Field>( - function_key: DeclarationFunctionKey<'ast, T>, + function_key: &DeclarationFunctionKey<'ast, T>, program: &TypedProgram<'ast, T>, ) -> TypedFunctionSymbolDeclaration<'ast, T> { let s = program @@ -66,30 +55,35 @@ fn get_canonical_function<'ast, T: Field>( .get(&function_key.module) .unwrap() .functions_iter() - .find(|d| d.key == function_key) + .find(|d| d.key == *function_key) .unwrap(); match &s.symbol { - TypedFunctionSymbol::There(key) => get_canonical_function(key.clone(), program), + TypedFunctionSymbol::There(key) => get_canonical_function(key, program), _ => s.clone(), } } -type InlineResult<'ast, T> = Result< - Output<(Vec>, TypedExpression<'ast, T>), Vec>>, - InlineError<'ast, T>, ->; +pub struct InlineValue<'ast, T> { + /// the pre-SSA input variables to assign the arguments to + pub input_variables: Vec>, + /// the pre-SSA statements for this call, including definition of the generic parameters + pub statements: Vec>, + /// the pre-SSA return value for this call + pub return_value: TypedExpression<'ast, T>, +} + +type InlineResult<'ast, T> = Result, InlineError<'ast, T>>; pub fn inline_call<'a, 'ast, T: Field, E: Expr<'ast, T>>( - k: DeclarationFunctionKey<'ast, T>, - generics: Vec>>, - arguments: Vec>, - output: &E::Ty, + k: &DeclarationFunctionKey<'ast, T>, + generics: &[Option>], + arguments: &[TypedExpression<'ast, T>], + output_ty: &E::Ty, program: &TypedProgram<'ast, T>, - versions: &'a mut Versions<'ast>, ) -> InlineResult<'ast, T> { use zokrates_ast::typed::Typed; - let output_type = output.clone().into_type(); + let output_type = output_ty.clone().into_type(); // we try to get concrete values for explicit generics let generics_values: Vec> = generics @@ -97,42 +91,29 @@ pub fn inline_call<'a, 'ast, T: Field, E: Expr<'ast, T>>( .map(|g| { g.as_ref() .map(|g| match g.as_inner() { - UExpressionInner::Value(v) => Ok(*v as u32), + UExpressionInner::Value(v) => Ok(v.value as u32), _ => Err(()), }) .transpose() }) .collect::>() - .map_err(|_| { - InlineError::NonConstant( - k.clone(), - generics.clone(), - arguments.clone(), - output_type.clone(), - ) - })?; + .map_err(|_| InlineError::NonConstant)?; // we infer a signature based on inputs and outputs - // this is where we could handle explicit annotations let inferred_signature = Signature::new() - .generics(generics.clone()) + .generics(generics.to_vec().clone()) .inputs(arguments.iter().map(|a| a.get_type()).collect()) .output(output_type.clone()); - // we try to get concrete values for the whole signature. if this fails we should propagate again + // we try to get concrete values for the whole signature let inferred_signature = match ConcreteSignature::try_from(inferred_signature) { Ok(s) => s, Err(_) => { - return Err(InlineError::NonConstant( - k, - generics, - arguments, - output_type, - )); + return Err(InlineError::NonConstant); } }; - let decl = get_canonical_function(k.clone(), program); + let decl = get_canonical_function(k, program); // get an assignment of generics for this call site let assignment: ConcreteGenericsAssignment<'ast> = k @@ -154,7 +135,6 @@ pub fn inline_call<'a, 'ast, T: Field, E: Expr<'ast, T>>( TypedFunctionSymbol::Flat(e) => Err(InlineError::Flat( e, e.generics::(&assignment), - arguments.clone(), output_type, )), _ => unreachable!(), @@ -162,59 +142,38 @@ pub fn inline_call<'a, 'ast, T: Field, E: Expr<'ast, T>>( assert_eq!(f.arguments.len(), arguments.len()); - let (ssa_f, incomplete_data) = match ShallowTransformer::transform(f, &assignment, versions) { - Output::Complete(v) => (v, None), - Output::Incomplete(statements, for_loop_versions) => (statements, Some(for_loop_versions)), - }; - - let call_log = TypedStatement::PushCallLog(decl.key.clone(), assignment.clone()); - - let input_bindings: Vec> = ssa_f + let generic_bindings = assignment.0.into_iter().map(|(identifier, value)| { + TypedStatement::definition( + TypedAssignee::Identifier(Variable::uint( + CoreIdentifier::from(identifier), + UBitwidth::B32, + )), + TypedExpression::from(UExpression::from(value)), + ) + }); + + let input_variables: Vec> = f .arguments .into_iter() .zip(inferred_signature.inputs.clone()) - .map(|(p, t)| ConcreteVariable::new(p.id.id, t, false)) - .zip(arguments.clone()) - .map(|(v, a)| TypedStatement::definition(Variable::from(v).into(), a)) + .map(|(p, t)| ConcreteVariable::new(p.id.id, t)) + .map(Variable::from) .collect(); - let (statements, mut returns): (Vec<_>, Vec<_>) = ssa_f - .statements - .into_iter() + let (statements, mut returns): (Vec<_>, Vec<_>) = generic_bindings + .chain(f.statements) .partition(|s| !matches!(s, TypedStatement::Return(..))); assert_eq!(returns.len(), 1); - let return_expression = match returns.pop().unwrap() { - TypedStatement::Return(e) => e, + let return_value = match returns.pop().unwrap() { + TypedStatement::Return(e) => e.inner, _ => unreachable!(), }; - let v: ConcreteVariable<'ast> = ConcreteVariable::new( - Identifier::from(CoreIdentifier::Call(0)).version( - *versions - .entry(CoreIdentifier::Call(0)) - .and_modify(|e| *e += 1) // if it was already declared, we increment - .or_insert(0), - ), - *inferred_signature.output.clone(), - false, - ); - - let expression = TypedExpression::from(Variable::from(v.clone())); - - let output_binding = TypedStatement::definition(Variable::from(v).into(), return_expression); - - let pop_log = TypedStatement::PopCallLog; - - let statements: Vec<_> = std::iter::once(call_log) - .chain(input_bindings) - .chain(statements) - .chain(std::iter::once(output_binding)) - .chain(std::iter::once(pop_log)) - .collect(); - - Ok(incomplete_data - .map(|d| Output::Incomplete((statements.clone(), expression.clone()), d)) - .unwrap_or_else(|| Output::Complete((statements, expression)))) + Ok(InlineValue { + input_variables, + statements, + return_value, + }) } diff --git a/zokrates_analysis/src/reducer/mod.rs b/zokrates_analysis/src/reducer/mod.rs index ea6feb536..2c2c37e07 100644 --- a/zokrates_analysis/src/reducer/mod.rs +++ b/zokrates_analysis/src/reducer/mod.rs @@ -3,40 +3,48 @@ // - free of function calls (except for low level calls) thanks to inlining // - free of for-loops thanks to unrolling -// The process happens in two steps -// 1. Shallow SSA for the `main` function -// We turn the `main` function into SSA form, but ignoring function calls and for loops -// 2. Unroll and inline -// We go through the shallow-SSA program and -// - unroll loops -// - inline function calls. This includes applying shallow-ssa on the target function +// The process happens in a greedy way, starting from the main function +// For each statement: +// * put it in ssa form +// * propagate it +// * inline it (calling this process recursively) +// * propagate again + +// if at any time a generic parameter or loop bound is not constant, error out, because it should have been propagated to a constant by the greedy approach mod constants_reader; mod constants_writer; mod inline; mod shallow_ssa; +use self::inline::InlineValue; use self::inline::{inline_call, InlineError}; use std::collections::HashMap; -use zokrates_ast::typed::result_folder::*; -use zokrates_ast::typed::types::ConcreteGenericsAssignment; -use zokrates_ast::typed::types::GGenericsAssignment; +use zokrates_ast::common::ResultFold; +use zokrates_ast::common::WithSpan; +use zokrates_ast::typed::DeclarationParameter; use zokrates_ast::typed::Folder; +use zokrates_ast::typed::SliceExpression; +use zokrates_ast::typed::SliceOrExpression; +use zokrates_ast::typed::{result_folder::*, ArrayExpression}; use zokrates_ast::typed::{CanonicalConstantIdentifier, EmbedCall, Variable}; +use zokrates_ast::typed::TypedAssignee; use zokrates_ast::typed::{ - ArrayExpressionInner, ArrayType, BlockExpression, CoreIdentifier, Expr, FunctionCall, - FunctionCallExpression, FunctionCallOrExpression, Id, Identifier, OwnedTypedModuleId, - TypedExpression, TypedFunction, TypedFunctionSymbol, TypedFunctionSymbolDeclaration, - TypedModule, TypedProgram, TypedStatement, UExpression, UExpressionInner, + BlockExpression, CoreIdentifier, Expr, FunctionCall, FunctionCallExpression, + FunctionCallOrExpression, Id, TypedExpression, TypedFunction, TypedFunctionSymbol, + TypedFunctionSymbolDeclaration, TypedModule, TypedProgram, TypedStatement, UExpression, + UExpressionInner, }; +use zokrates_ast::untyped::OwnedModuleId; use zokrates_field::Field; use self::constants_writer::ConstantsWriter; use self::shallow_ssa::ShallowTransformer; -use crate::propagation::{Constants, Propagator}; +use crate::propagation; +use crate::propagation::Propagator; use std::fmt; @@ -46,25 +54,15 @@ const MAX_FOR_LOOP_SIZE: u128 = 2u128.pow(20); pub type ConstantDefinitions<'ast, T> = HashMap, TypedExpression<'ast, T>>; -// An SSA version map, giving access to the latest version number for each identifier -pub type Versions<'ast> = HashMap, usize>; - -// A container to represent whether more treatment must be applied to the function #[derive(Debug, PartialEq, Eq)] -pub enum Output { - Complete(U), - Incomplete(U, V), -} - -#[derive(Debug, Clone, PartialEq, Eq)] pub enum Error { Incompatible(String), GenericsInMain, - // TODO: give more details about what's blocking the progress - NoProgress, LoopTooLarge(u128), - ConstantReduction(String, OwnedTypedModuleId), + ConstantReduction(String, OwnedModuleId), + NonConstant(String), Type(String), + Propagation(propagation::Error), } impl fmt::Display for Error { @@ -76,140 +74,59 @@ impl fmt::Display for Error { s ), Error::GenericsInMain => write!(f, "Cannot generate code for generic function"), - Error::NoProgress => write!(f, "Failed to unroll or inline program. Check that main function arguments aren't used as array size or for-loop bounds"), Error::LoopTooLarge(size) => write!(f, "Found a loop of size {}, which is larger than the maximum allowed of {}. Check the loop bounds, especially for underflows", size, MAX_FOR_LOOP_SIZE), Error::ConstantReduction(name, module) => write!(f, "Failed to reduce constant `{}` in module `{}` to a literal, try simplifying its declaration", name, module.display()), - Error::Type(message) => write!(f, "{}", message), - } - } -} - -#[derive(Debug, Default)] -struct Substitutions<'ast>(HashMap, HashMap>); - -impl<'ast> Substitutions<'ast> { - // create an equivalent substitution map where all paths - // are of length 1 - fn canonicalize(self) -> Self { - Substitutions( - self.0 - .into_iter() - .map(|(id, sub)| (id, Self::canonicalize_sub(sub))) - .collect(), - ) - } - - // canonicalize substitutions for a given id - fn canonicalize_sub(sub: HashMap) -> HashMap { - fn add_to_cache( - sub: &HashMap, - cache: HashMap, - k: usize, - ) -> HashMap { - match cache.contains_key(&k) { - // `k` is already in the cache, no changes to the cache - true => cache, - _ => match sub.get(&k) { - // `k` does not point to anything, no changes to the cache - None => cache, - // `k` points to some `v - Some(v) => { - // add `v` to the cache - let cache = add_to_cache(sub, cache, *v); - // `k` points to what `v` points to, or to `v` - let v = cache.get(v).cloned().unwrap_or(*v); - let mut cache = cache; - cache.insert(k, v); - cache - } - }, - } + Error::NonConstant(s) => write!(f, "{}", s), + Error::Type(s) => write!(f, "{}", s), + Error::Propagation(e) => write!(f, "{}", e), } - - sub.keys() - .fold(HashMap::new(), |cache, k| add_to_cache(&sub, cache, *k)) - } -} - -struct Sub<'a, 'ast> { - substitutions: &'a Substitutions<'ast>, -} - -impl<'a, 'ast> Sub<'a, 'ast> { - fn new(substitutions: &'a Substitutions<'ast>) -> Self { - Self { substitutions } } } -impl<'a, 'ast, T: Field> Folder<'ast, T> for Sub<'a, 'ast> { - fn fold_name(&mut self, id: Identifier<'ast>) -> Identifier<'ast> { - let version = self - .substitutions - .0 - .get(&id.id) - .map(|sub| sub.get(&id.version).cloned().unwrap_or(id.version)) - .unwrap_or(id.version); - id.version(version) - } -} - -fn register<'ast>( - substitutions: &mut Substitutions<'ast>, - substitute: &Versions<'ast>, - with: &Versions<'ast>, -) { - for (id, key, value) in substitute - .iter() - .filter_map(|(id, version)| with.get(id).map(|to| (id, version, to))) - .filter(|(_, key, value)| key != value) - { - let sub = substitutions.0.entry(id.clone()).or_default(); - - // redirect `k` to `v`, unless `v` is already redirected to `v0`, in which case we redirect to `v0` - - sub.insert(*key, *sub.get(value).unwrap_or(value)); +impl From for Error { + fn from(e: propagation::Error) -> Self { + Self::Propagation(e) } } #[derive(Debug)] struct Reducer<'ast, 'a, T> { - statement_buffer: Vec>, - for_loop_versions: Vec>, - for_loop_versions_after: Vec>, program: &'a TypedProgram<'ast, T>, - versions: &'a mut Versions<'ast>, - substitutions: &'a mut Substitutions<'ast>, - complete: bool, + propagator: Propagator<'ast, T>, + ssa: ShallowTransformer<'ast>, + statement_buffer: Vec>, } impl<'ast, 'a, T: Field> Reducer<'ast, 'a, T> { - fn new( - program: &'a TypedProgram<'ast, T>, - versions: &'a mut Versions<'ast>, - substitutions: &'a mut Substitutions<'ast>, - for_loop_versions: Vec>, - ) -> Self { - // we reverse the vector as it's cheaper to `pop` than to take from - // the head - let mut for_loop_versions = for_loop_versions; - - for_loop_versions.reverse(); - + fn new(program: &'a TypedProgram<'ast, T>) -> Self { Reducer { + propagator: Propagator::default(), + ssa: ShallowTransformer::default(), statement_buffer: vec![], - for_loop_versions_after: vec![], - for_loop_versions, - substitutions, program, - versions, - complete: true, } } + + fn push_call_frame(&mut self) { + self.ssa.push_call_frame(); + } + + fn pop_call_frame(&mut self) { + self.propagator.clear_call_frame(self.ssa.latest_frame); + self.ssa.pop_call_frame(); + } } impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Reducer<'ast, 'a, T> { type Error = Error; + fn fold_parameter( + &mut self, + p: DeclarationParameter<'ast, T>, + ) -> Result, Self::Error> { + Ok(self.ssa.fold_parameter(p)) + } + fn fold_function_call_expression< E: Id<'ast, T> + From> + Expr<'ast, T> + FunctionCall<'ast, T>, >( @@ -217,79 +134,131 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Reducer<'ast, 'a, T> { ty: &E::Ty, e: FunctionCallExpression<'ast, T, E>, ) -> Result, Self::Error> { - let generics = e + let span = e.get_span(); + + // generics are already in ssa form + let generics: Vec<_> = e .generics .into_iter() - .map(|g| g.map(|g| self.fold_uint_expression(g)).transpose()) + .map(|g| { + g.map(|g| { + let g = self.propagator.fold_uint_expression(g)?; + let g = self.fold_uint_expression(g)?; + + self.propagator + .fold_uint_expression(g) + .map_err(Self::Error::from) + }) + .transpose() + }) .collect::>()?; - let arguments = e + // arguments are already in ssa form + + let arguments: Vec<_> = e .arguments .into_iter() - .map(|e| self.fold_expression(e)) + .map(|e| { + let e = self.propagator.fold_expression(e)?; + let e = self.fold_expression(e)?; + + self.propagator + .fold_expression(e) + .map_err(Self::Error::from) + }) .collect::>()?; - let res = inline_call::<_, E>( - e.function_key.clone(), - generics, - arguments, - ty, - self.program, - self.versions, - ); + self.push_call_frame(); + + let res = inline_call::<_, E>(&e.function_key, &generics, &arguments, ty, self.program); + + let res = match res { + Ok(InlineValue { + input_variables, + statements, + return_value, + }) => { + // the lhs is from the inner call frame, the rhs is from the outer one, so only fold the lhs + let input_bindings: Vec<_> = input_variables + .into_iter() + .zip(arguments) + .map(|(v, a)| { + TypedStatement::definition(self.ssa.fold_assignee(v.into()), a).span(span) + }) + .collect(); + + let input_bindings = input_bindings + .into_iter() + .map(|s| self.propagator.fold_statement(s)) + .collect::, _>>()? + .into_iter() + .flatten() + .collect::>(); + + self.statement_buffer.extend(input_bindings); + + let statements = statements + .into_iter() + .map(|s| self.fold_statement(s)) + .collect::, _>>()? + .into_iter() + .flatten() + .collect::>(); - match res { - Ok(Output::Complete((statements, expression))) => { - self.complete &= true; - self.statement_buffer.extend(statements); - Ok(FunctionCallOrExpression::Expression( - E::from(expression).into_inner(), - )) - } - Ok(Output::Incomplete((statements, expression), delta_for_loop_versions)) => { - self.complete = false; self.statement_buffer.extend(statements); - self.for_loop_versions_after.extend(delta_for_loop_versions); + + let return_value = self.ssa.fold_expression(return_value); + + let return_value = self.propagator.fold_expression(return_value)?; + + let return_value = self.fold_expression(return_value)?; + + let return_value = self.propagator.fold_expression(return_value)?; + Ok(FunctionCallOrExpression::Expression( - E::from(expression.clone()).into_inner(), + E::from(return_value).into_inner(), )) } Err(InlineError::Generic(decl, conc)) => Err(Error::Incompatible(format!( "Call site `{}` incompatible with declaration `{}`", conc, decl ))), - Err(InlineError::NonConstant(key, generics, arguments, _)) => { - self.complete = false; + Err(InlineError::NonConstant) => Err(Error::NonConstant(format!( + "Generic parameters must be compile-time constants, found {}", + FunctionCallExpression::<_, E>::new(e.function_key, generics, arguments) + ))), + Err(InlineError::Flat(embed, generics, output_type)) => { + let identifier = self.ssa.issue_next_identifier(CoreIdentifier::Call); - Ok(FunctionCallOrExpression::Expression(E::function_call( - key, generics, arguments, - ))) - } - Err(InlineError::Flat(embed, generics, arguments, output_type)) => { - let identifier = Identifier::from(CoreIdentifier::Call(0)).version( - *self - .versions - .entry(CoreIdentifier::Call(0)) - .and_modify(|e| *e += 1) // if it was already declared, we increment - .or_insert(0), - ); - - let var = Variable::immutable(identifier.clone(), output_type); - let v = var.clone().into(); - - self.statement_buffer - .push(TypedStatement::embed_call_definition( - v, - EmbedCall::new(embed, generics, arguments), - )); - Ok(FunctionCallOrExpression::Expression(E::identifier( - identifier, - ))) + let var = Variable::new(identifier.clone(), output_type); + + let v: TypedAssignee<'ast, T> = var.clone().into(); + + let definition = TypedStatement::embed_call_definition( + v, + EmbedCall::new(embed, generics, arguments), + ) + .span(span); + + let definition = self.propagator.fold_statement(definition)?; + + self.statement_buffer.extend(definition); + + let e = match self.propagator.constants.get(&identifier) { + Some(v) => E::try_from(v.clone()).unwrap().into_inner(), + None => E::identifier(identifier), + }; + + Ok(FunctionCallOrExpression::Expression(e.span(span))) } - } + }; + + self.pop_call_frame(); + + res } - fn fold_block_expression>( + fn fold_block_expression>( &mut self, b: BlockExpression<'ast, T, E>, ) -> Result, Self::Error> { @@ -319,104 +288,108 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Reducer<'ast, 'a, T> { unreachable!("canonical constant identifiers should not be folded, they should be inlined") } + // here we implement fold_statement and not fold_statement_cases because we do not want the span of the input + // to be applied to all the outputs: a statement which contains a call which gets inline should not hide the + // inlined statements behind its own span fn fold_statement( &mut self, s: TypedStatement<'ast, T>, ) -> Result>, Self::Error> { let res = match s { - TypedStatement::For(v, from, to, statements) => { - let versions_before = self.for_loop_versions.pop().unwrap(); - - match (from.as_inner(), to.as_inner()) { - (UExpressionInner::Value(from), UExpressionInner::Value(to)) => { - let mut out_statements = vec![]; - - // get a fresh set of versions for all variables to use as a starting point inside the loop - self.versions.values_mut().for_each(|v| *v += 1); - - // add this set of versions to the substitution, pointing to the versions before the loop - register(self.substitutions, self.versions, &versions_before); - - // the versions after the loop are found by applying an offset of 1 to the versions before the loop - let versions_after = versions_before - .clone() - .into_iter() - .map(|(k, v)| (k, v + 1)) - .collect(); - - let mut transformer = ShallowTransformer::with_versions(self.versions); - - if to - from > MAX_FOR_LOOP_SIZE { - return Err(Error::LoopTooLarge(to.saturating_sub(*from))); - } - - for index in *from..*to { - let statements: Vec> = - std::iter::once(TypedStatement::definition( - v.clone().into(), - UExpression::from(index as u32).into(), - )) - .chain(statements.clone().into_iter()) - .flat_map(|s| transformer.fold_statement(s)) - .collect(); - - out_statements.extend(statements); - } - - let backups = transformer.for_loop_backups; - let blocked = transformer.blocked; - - // we know the final versions of the variables after full unrolling of the loop - // the versions after the loop need to point to these, so we add to the substitutions - register(self.substitutions, &versions_after, self.versions); - - // we may have found new for loops when unrolling this one, which means new backed up versions - // we insert these in our backup list and update our cursor - - self.for_loop_versions_after.extend(backups); + TypedStatement::For(s) => { + let from = self.ssa.fold_uint_expression(s.from); + let from = self.propagator.fold_uint_expression(from)?; + let from = self.fold_uint_expression(from)?; + let from = self.propagator.fold_uint_expression(from)?; - // if the ssa transform got blocked, the reduction is not complete - self.complete &= !blocked; + let to = self.ssa.fold_uint_expression(s.to); + let to = self.propagator.fold_uint_expression(to)?; + let to = self.fold_uint_expression(to)?; + let to = self.propagator.fold_uint_expression(to)?; - Ok(out_statements) - } - _ => { - let from = self.fold_uint_expression(from)?; - let to = self.fold_uint_expression(to)?; - self.complete = false; - self.for_loop_versions_after.push(versions_before); - Ok(vec![TypedStatement::For(v, from, to, statements)]) + match (from.as_inner(), to.as_inner()) { + (UExpressionInner::Value(from), UExpressionInner::Value(to)) + if to.value - from.value > MAX_FOR_LOOP_SIZE => + { + Err(Error::LoopTooLarge(to.value.saturating_sub(from.value))) } - } + (UExpressionInner::Value(from), UExpressionInner::Value(to)) => Ok((from.value + ..to.value) + .flat_map(|index| { + std::iter::once(TypedStatement::definition( + s.var.clone().into(), + UExpression::from(index as u32).into(), + )) + .chain(s.statements.clone()) + .map(|s| self.fold_statement(s)) + .collect::>() + }) + .collect::, _>>()? + .into_iter() + .flatten() + .collect::>()), + _ => Err(Error::NonConstant(format!( + "Expected loop bounds to be constant, found {}..{}", + from, to + ))), + }? + } + s => { + let statements = self.ssa.fold_statement(s); + + let statements = statements + .into_iter() + .map(|s| self.propagator.fold_statement(s)) + .collect::, _>>()? + .into_iter() + .flatten(); + + let statements = statements + .map(|s| fold_statement(self, s)) + .collect::, _>>()? + .into_iter() + .flatten(); + + let statements = statements + .map(|s| self.propagator.fold_statement(s)) + .collect::, _>>()? + .into_iter() + .flatten(); + + statements.collect() } - s => fold_statement(self, s), }; - res.map(|res| self.statement_buffer.drain(..).chain(res).collect()) + Ok(self.statement_buffer.drain(..).chain(res).collect()) } - fn fold_array_expression_inner( + fn fold_slice_expression( &mut self, - array_ty: &ArrayType<'ast, T>, - e: ArrayExpressionInner<'ast, T>, - ) -> Result, Self::Error> { - match e { - ArrayExpressionInner::Slice(box array, box from, box to) => { - let array = self.fold_array_expression(array)?; - let from = self.fold_uint_expression(from)?; - let to = self.fold_uint_expression(to)?; - - match (from.as_inner(), to.as_inner()) { - (UExpressionInner::Value(..), UExpressionInner::Value(..)) => { - Ok(ArrayExpressionInner::Slice(box array, box from, box to)) - } - _ => { - self.complete = false; - Ok(ArrayExpressionInner::Slice(box array, box from, box to)) - } - } - } - _ => fold_array_expression_inner(self, array_ty, e), + e: zokrates_ast::typed::SliceExpression<'ast, T>, + ) -> Result, Self::Error> { + let array = self.ssa.fold_array_expression(*e.array); + let array = self.propagator.fold_array_expression(array)?; + let array = self.fold_array_expression(array)?; + let array = self.propagator.fold_array_expression(array)?; + + let from = self.ssa.fold_uint_expression(*e.from); + let from = self.propagator.fold_uint_expression(from)?; + let from = self.fold_uint_expression(from)?; + let from = self.propagator.fold_uint_expression(from)?; + + let to = self.ssa.fold_uint_expression(*e.to); + let to = self.propagator.fold_uint_expression(to)?; + let to = self.fold_uint_expression(to)?; + let to = self.propagator.fold_uint_expression(to)?; + + match (from.as_inner(), to.as_inner()) { + (UExpressionInner::Value(..), UExpressionInner::Value(..)) => Ok( + SliceOrExpression::Slice(SliceExpression::new(array, from, to)), + ), + _ => Err(Error::NonConstant(format!( + "Slice bounds must be compile time constants, found {}", + ArrayExpression::slice(array, from, to) + ))), } } } @@ -443,7 +416,7 @@ pub fn reduce_program(p: TypedProgram) -> Result, E match main_function.signature.generics.len() { 0 => { - let main_function = reduce_function(main_function, GGenericsAssignment::default(), &p)?; + let main_function = Reducer::new(&p).fold_function(main_function)?; Ok(TypedProgram { main: p.main.clone(), @@ -459,6 +432,7 @@ pub fn reduce_program(p: TypedProgram) -> Result, E )] .into_iter() .collect(), + ..p }) } _ => Err(Error::GenericsInMain), @@ -467,91 +441,11 @@ pub fn reduce_program(p: TypedProgram) -> Result, E fn reduce_function<'ast, T: Field>( f: TypedFunction<'ast, T>, - generics: ConcreteGenericsAssignment<'ast>, program: &TypedProgram<'ast, T>, ) -> Result, Error> { - let mut versions = Versions::default(); - - let mut constants = Constants::default(); - - let f = match ShallowTransformer::transform(f, &generics, &mut versions) { - Output::Complete(f) => Ok(f), - Output::Incomplete(new_f, new_for_loop_versions) => { - let mut for_loop_versions = new_for_loop_versions; - - let mut f = new_f; - - let mut substitutions = Substitutions::default(); - - let mut hash = None; - - loop { - let mut reducer = Reducer::new( - program, - &mut versions, - &mut substitutions, - for_loop_versions, - ); - - let new_f = TypedFunction { - statements: f - .statements - .into_iter() - .map(|s| reducer.fold_statement(s)) - .collect::, _>>()? - .into_iter() - .flatten() - .collect(), - ..f - }; - - assert!(reducer.for_loop_versions.is_empty()); - - match reducer.complete { - true => { - substitutions = substitutions.canonicalize(); - - let new_f = Sub::new(&substitutions).fold_function(new_f); + assert!(f.signature.generics.is_empty()); - let new_f = Propagator::with_constants(&mut constants) - .fold_function(new_f) - .map_err(|e| Error::Incompatible(format!("{}", e)))?; - - break Ok(new_f); - } - false => { - for_loop_versions = reducer.for_loop_versions_after; - - let new_f = Sub::new(&substitutions).fold_function(new_f); - - f = Propagator::with_constants(&mut constants) - .fold_function(new_f) - .map_err(|e| Error::Incompatible(format!("{}", e)))?; - - let new_hash = Some(compute_hash(&f)); - - if new_hash == hash { - break Err(Error::NoProgress); - } else { - hash = new_hash - } - } - } - } - } - }?; - - Propagator::with_constants(&mut constants) - .fold_function(f) - .map_err(|e| Error::Incompatible(format!("{}", e))) -} - -fn compute_hash(f: &TypedFunction) -> u64 { - use std::collections::hash_map::DefaultHasher; - use std::hash::{Hash, Hasher}; - let mut s = DefaultHasher::new(); - f.hash(&mut s); - s.finish() + Reducer::new(program).fold_function(f) } #[cfg(test)] @@ -560,17 +454,16 @@ mod tests { use zokrates_ast::typed::types::DeclarationSignature; use zokrates_ast::typed::types::{DeclarationConstant, GTupleType}; use zokrates_ast::typed::{ - ArrayExpression, ArrayExpressionInner, DeclarationFunctionKey, DeclarationType, - DeclarationVariable, FieldElementExpression, GenericIdentifier, Identifier, - OwnedTypedModuleId, Select, TupleExpressionInner, TupleType, Type, TypedExpression, - TypedExpressionOrSpread, UBitwidth, UExpressionInner, Variable, + ArrayExpression, ArrayType, DeclarationFunctionKey, DeclarationType, DeclarationVariable, + FieldElementExpression, GenericIdentifier, Identifier, Select, TupleExpression, TupleType, + Type, TypedExpression, TypedExpressionOrSpread, UBitwidth, Variable, }; use zokrates_field::Bn128Field; use lazy_static::lazy_static; lazy_static! { - static ref MAIN_MODULE_ID: OwnedTypedModuleId = OwnedTypedModuleId::from("main"); + static ref MAIN_MODULE_ID: OwnedModuleId = OwnedModuleId::from("main"); } #[test] @@ -588,19 +481,16 @@ mod tests { // } // expected: - // def main(field a_0) -> field { - // a_1 = a_0; - // # PUSH CALL to foo - // a_3 := a_1; // input binding - // #RETURN_AT_INDEX_0_0 := a_3; - // # POP CALL - // a_2 = #RETURN_AT_INDEX_0_0; - // return a_2; + // def main(field a_f0_v0) -> field { + // a_f0_v1 = a_f0_v0; // redef + // a_f1_v0 = a_f0_v1; // input binding + // a_f0_v2 = a_f1_v0; // output binding + // return a_f0_v2; // } let foo: TypedFunction = TypedFunction { arguments: vec![DeclarationVariable::field_element("a").into()], - statements: vec![TypedStatement::Return( + statements: vec![TypedStatement::ret( FieldElementExpression::identifier("a".into()).into(), )], signature: DeclarationSignature::new() @@ -644,7 +534,7 @@ mod tests { .annotate(UBitwidth::B32) .into(), ), - TypedStatement::Return(FieldElementExpression::identifier("a".into()).into()), + TypedStatement::ret(FieldElementExpression::identifier("a".into()).into()), ], signature: DeclarationSignature::new() .inputs(vec![DeclarationType::FieldElement]) @@ -652,6 +542,7 @@ mod tests { }; let p = TypedProgram { + module_map: Default::default(), main: "main".into(), modules: vec![( "main".into(), @@ -691,32 +582,15 @@ mod tests { Variable::field_element(Identifier::from("a").version(1)).into(), FieldElementExpression::identifier("a".into()).into(), ), - TypedStatement::PushCallLog( - DeclarationFunctionKey::with_location("main", "foo").signature( - DeclarationSignature::new() - .inputs(vec![DeclarationType::FieldElement]) - .output(DeclarationType::FieldElement), - ), - GGenericsAssignment::default(), - ), TypedStatement::definition( - Variable::field_element(Identifier::from("a").version(3)).into(), + Variable::field_element(Identifier::from("a").in_frame(1)).into(), FieldElementExpression::identifier(Identifier::from("a").version(1)).into(), ), - TypedStatement::definition( - Variable::field_element(Identifier::from(CoreIdentifier::Call(0)).version(0)) - .into(), - FieldElementExpression::identifier(Identifier::from("a").version(3)).into(), - ), - TypedStatement::PopCallLog, TypedStatement::definition( Variable::field_element(Identifier::from("a").version(2)).into(), - FieldElementExpression::identifier( - Identifier::from(CoreIdentifier::Call(0)).version(0), - ) - .into(), + FieldElementExpression::identifier(Identifier::from("a").in_frame(1)).into(), ), - TypedStatement::Return( + TypedStatement::ret( FieldElementExpression::identifier(Identifier::from("a").version(2)).into(), ), ], @@ -726,6 +600,7 @@ mod tests { }; let expected: TypedProgram = TypedProgram { + module_map: Default::default(), main: "main".into(), modules: vec![( "main".into(), @@ -763,14 +638,11 @@ mod tests { // } // expected: - // def main(field a_0) -> field { - // field[1] b_0 = [42]; - // # PUSH CALL to foo::<1> - // a_0 = b_0; - // #RETURN_AT_INDEX_0_0 := a_0; - // # POP CALL - // b_1 = #RETURN_AT_INDEX_0_0; - // return a_2 + b_1[0]; + // def main(field a_f0_v0) -> field { + // field[1] b_f0_v0 = [a_f0_v0]; + // a_f1_v0 = b_f0_v0; + // b_f0_v1 = a_f1_v0; + // return a_f0_v0 + b_f0_v1[0]; // } let foo_signature = DeclarationSignature::new() @@ -793,9 +665,9 @@ mod tests { GenericIdentifier::with_name("K").with_index(0), ) .into()], - statements: vec![TypedStatement::Return( + statements: vec![TypedStatement::ret( ArrayExpression::identifier("a".into()) - .annotate(Type::FieldElement, 1u32) + .annotate(ArrayType::new(Type::FieldElement, 1u32)) .into(), )], signature: foo_signature.clone(), @@ -816,10 +688,10 @@ mod tests { ), TypedStatement::definition( Variable::array("b", Type::FieldElement, 1u32).into(), - ArrayExpressionInner::Value( - vec![FieldElementExpression::identifier("a".into()).into()].into(), - ) - .annotate(Type::FieldElement, 1u32) + ArrayExpression::value(vec![ + FieldElementExpression::identifier("a".into()).into() + ]) + .annotate(ArrayType::new(Type::FieldElement, 1u32)) .into(), ), TypedStatement::definition( @@ -829,10 +701,10 @@ mod tests { .signature(foo_signature.clone()), vec![None], vec![ArrayExpression::identifier("b".into()) - .annotate(Type::FieldElement, 1u32) + .annotate(ArrayType::new(Type::FieldElement, 1u32)) .into()], ) - .annotate(Type::FieldElement, 1u32) + .annotate(ArrayType::new(Type::FieldElement, 1u32)) .into(), ), TypedStatement::definition( @@ -841,11 +713,11 @@ mod tests { .annotate(UBitwidth::B32) .into(), ), - TypedStatement::Return( + TypedStatement::ret( (FieldElementExpression::identifier("a".into()) + FieldElementExpression::select( ArrayExpression::identifier("b".into()) - .annotate(Type::FieldElement, 1u32), + .annotate(ArrayType::new(Type::FieldElement, 1u32)), 0u32, )) .into(), @@ -857,6 +729,7 @@ mod tests { }; let p = TypedProgram { + module_map: Default::default(), main: "main".into(), modules: vec![( "main".into(), @@ -891,54 +764,31 @@ mod tests { statements: vec![ TypedStatement::definition( Variable::array("b", Type::FieldElement, 1u32).into(), - ArrayExpressionInner::Value( - vec![FieldElementExpression::identifier("a".into()).into()].into(), - ) - .annotate(Type::FieldElement, 1u32) + ArrayExpression::value(vec![ + FieldElementExpression::identifier("a".into()).into() + ]) + .annotate(ArrayType::new(Type::FieldElement, 1u32)) .into(), ), - TypedStatement::PushCallLog( - DeclarationFunctionKey::with_location("main", "foo") - .signature(foo_signature.clone()), - GGenericsAssignment( - vec![(GenericIdentifier::with_name("K").with_index(0), 1)] - .into_iter() - .collect(), - ), - ), TypedStatement::definition( - Variable::array(Identifier::from("a").version(1), Type::FieldElement, 1u32) + Variable::array(Identifier::from("a").in_frame(1), Type::FieldElement, 1u32) .into(), ArrayExpression::identifier("b".into()) - .annotate(Type::FieldElement, 1u32) + .annotate(ArrayType::new(Type::FieldElement, 1u32)) .into(), ), - TypedStatement::definition( - Variable::array( - Identifier::from(CoreIdentifier::Call(0)).version(0), - Type::FieldElement, - 1u32, - ) - .into(), - ArrayExpression::identifier(Identifier::from("a").version(1)) - .annotate(Type::FieldElement, 1u32) - .into(), - ), - TypedStatement::PopCallLog, TypedStatement::definition( Variable::array(Identifier::from("b").version(1), Type::FieldElement, 1u32) .into(), - ArrayExpression::identifier( - Identifier::from(CoreIdentifier::Call(0)).version(0), - ) - .annotate(Type::FieldElement, 1u32) - .into(), + ArrayExpression::identifier(Identifier::from("a").in_frame(1)) + .annotate(ArrayType::new(Type::FieldElement, 1u32)) + .into(), ), - TypedStatement::Return( + TypedStatement::ret( (FieldElementExpression::identifier("a".into()) + FieldElementExpression::select( ArrayExpression::identifier(Identifier::from("b").version(1)) - .annotate(Type::FieldElement, 1u32), + .annotate(ArrayType::new(Type::FieldElement, 1u32)), 0u32, )) .into(), @@ -950,6 +800,7 @@ mod tests { }; let expected = TypedProgram { + module_map: Default::default(), main: "main".into(), modules: vec![( "main".into(), @@ -987,14 +838,11 @@ mod tests { // } // expected: - // def main(field a_0) -> field { - // field[1] b_0 = [42]; - // # PUSH CALL to foo::<1> - // a_0 = b_0; - // #RETURN_AT_INDEX_0_0 := a_0; - // # POP CALL - // b_1 = #RETURN_AT_INDEX_0_0; - // return a_2 + b_1[0]; + // def main(field a) -> field { + // field[1] b = [a]; + // a_f1 = b; + // b_1 = a_f1; + // return a + b_1[0]; // } let foo_signature = DeclarationSignature::new() @@ -1017,14 +865,16 @@ mod tests { GenericIdentifier::with_name("K").with_index(0), ) .into()], - statements: vec![TypedStatement::Return( + statements: vec![TypedStatement::ret( ArrayExpression::identifier("a".into()) - .annotate(Type::FieldElement, 1u32) + .annotate(ArrayType::new(Type::FieldElement, 1u32)) .into(), )], signature: foo_signature.clone(), }; + use std::ops::Sub; + let main: TypedFunction = TypedFunction { arguments: vec![DeclarationVariable::field_element("a").into()], statements: vec![ @@ -1042,17 +892,16 @@ mod tests { Variable::array( "b", Type::FieldElement, - UExpressionInner::Sub( - box UExpression::identifier("n".into()).annotate(UBitwidth::B32), - box 1u32.into(), - ) - .annotate(UBitwidth::B32), + UExpression::sub( + UExpression::identifier("n".into()).annotate(UBitwidth::B32), + 1u32.into(), + ), ) .into(), - ArrayExpressionInner::Value( - vec![FieldElementExpression::identifier("a".into()).into()].into(), - ) - .annotate(Type::FieldElement, 1u32) + ArrayExpression::value(vec![ + FieldElementExpression::identifier("a".into()).into() + ]) + .annotate(ArrayType::new(Type::FieldElement, 1u32)) .into(), ), TypedStatement::definition( @@ -1062,10 +911,10 @@ mod tests { .signature(foo_signature.clone()), vec![None], vec![ArrayExpression::identifier("b".into()) - .annotate(Type::FieldElement, 1u32) + .annotate(ArrayType::new(Type::FieldElement, 1u32)) .into()], ) - .annotate(Type::FieldElement, 1u32) + .annotate(ArrayType::new(Type::FieldElement, 1u32)) .into(), ), TypedStatement::definition( @@ -1074,11 +923,11 @@ mod tests { .annotate(UBitwidth::B32) .into(), ), - TypedStatement::Return( + TypedStatement::ret( (FieldElementExpression::identifier("a".into()) + FieldElementExpression::select( ArrayExpression::identifier("b".into()) - .annotate(Type::FieldElement, 1u32), + .annotate(ArrayType::new(Type::FieldElement, 1u32)), 0u32, )) .into(), @@ -1090,6 +939,7 @@ mod tests { }; let p = TypedProgram { + module_map: Default::default(), main: "main".into(), modules: vec![( "main".into(), @@ -1124,54 +974,31 @@ mod tests { statements: vec![ TypedStatement::definition( Variable::array("b", Type::FieldElement, 1u32).into(), - ArrayExpressionInner::Value( - vec![FieldElementExpression::identifier("a".into()).into()].into(), - ) - .annotate(Type::FieldElement, 1u32) + ArrayExpression::value(vec![ + FieldElementExpression::identifier("a".into()).into() + ]) + .annotate(ArrayType::new(Type::FieldElement, 1u32)) .into(), ), - TypedStatement::PushCallLog( - DeclarationFunctionKey::with_location("main", "foo") - .signature(foo_signature.clone()), - GGenericsAssignment( - vec![(GenericIdentifier::with_name("K").with_index(0), 1)] - .into_iter() - .collect(), - ), - ), TypedStatement::definition( - Variable::array(Identifier::from("a").version(1), Type::FieldElement, 1u32) + Variable::array(Identifier::from("a").in_frame(1), Type::FieldElement, 1u32) .into(), ArrayExpression::identifier("b".into()) - .annotate(Type::FieldElement, 1u32) + .annotate(ArrayType::new(Type::FieldElement, 1u32)) .into(), ), - TypedStatement::definition( - Variable::array( - Identifier::from(CoreIdentifier::Call(0)).version(0), - Type::FieldElement, - 1u32, - ) - .into(), - ArrayExpression::identifier(Identifier::from("a").version(1)) - .annotate(Type::FieldElement, 1u32) - .into(), - ), - TypedStatement::PopCallLog, TypedStatement::definition( Variable::array(Identifier::from("b").version(1), Type::FieldElement, 1u32) .into(), - ArrayExpression::identifier( - Identifier::from(CoreIdentifier::Call(0)).version(0), - ) - .annotate(Type::FieldElement, 1u32) - .into(), + ArrayExpression::identifier(Identifier::from("a").in_frame(1)) + .annotate(ArrayType::new(Type::FieldElement, 1u32)) + .into(), ), - TypedStatement::Return( + TypedStatement::ret( (FieldElementExpression::identifier("a".into()) + FieldElementExpression::select( ArrayExpression::identifier(Identifier::from("b").version(1)) - .annotate(Type::FieldElement, 1u32), + .annotate(ArrayType::new(Type::FieldElement, 1u32)), 0u32, )) .into(), @@ -1183,6 +1010,7 @@ mod tests { }; let expected = TypedProgram { + module_map: Default::default(), main: "main".into(), modules: vec![( "main".into(), @@ -1226,10 +1054,6 @@ mod tests { // expected: // def main() { - // # PUSH CALL to foo::<1> - // # PUSH CALL to bar::<2> - // # POP CALL - // # POP CALL // return; // } @@ -1261,49 +1085,42 @@ mod tests { UExpression::identifier("K".into()).annotate(UBitwidth::B32), ) .into(), - ArrayExpressionInner::Slice( - box ArrayExpression::function_call( + ArrayExpression::slice( + ArrayExpression::function_call( DeclarationFunctionKey::with_location("main", "bar") .signature(foo_signature.clone()), vec![None], - vec![ArrayExpressionInner::Value( - vec![ - TypedExpressionOrSpread::Spread( - ArrayExpression::identifier("a".into()) - .annotate(Type::FieldElement, 1u32) - .into(), - ), - FieldElementExpression::Number(Bn128Field::from(0)).into(), - ] - .into(), - ) - .annotate( + vec![ArrayExpression::value(vec![ + TypedExpressionOrSpread::Spread( + ArrayExpression::identifier("a".into()) + .annotate(ArrayType::new(Type::FieldElement, 1u32)) + .into(), + ), + FieldElementExpression::value(Bn128Field::from(0)).into(), + ]) + .annotate(ArrayType::new( Type::FieldElement, UExpression::identifier("K".into()).annotate(UBitwidth::B32) + 1u32.into(), - ) + )) .into()], ) - .annotate( + .annotate(ArrayType::new( Type::FieldElement, UExpression::identifier("K".into()).annotate(UBitwidth::B32) + 1u32.into(), - ), - box 0u32.into(), - box UExpression::identifier("K".into()).annotate(UBitwidth::B32), - ) - .annotate( - Type::FieldElement, + )), + 0u32.into(), UExpression::identifier("K".into()).annotate(UBitwidth::B32), ) .into(), ), - TypedStatement::Return( + TypedStatement::ret( ArrayExpression::identifier("ret".into()) - .annotate( + .annotate(ArrayType::new( Type::FieldElement, UExpression::identifier("K".into()).annotate(UBitwidth::B32), - ) + )) .into(), ), ], @@ -1319,12 +1136,12 @@ mod tests { DeclarationConstant::Generic(GenericIdentifier::with_name("K").with_index(0)), ) .into()], - statements: vec![TypedStatement::Return( + statements: vec![TypedStatement::ret( ArrayExpression::identifier("a".into()) - .annotate( + .annotate(ArrayType::new( Type::FieldElement, UExpression::identifier("K".into()).annotate(UBitwidth::B32), - ) + )) .into(), )], signature: bar_signature.clone(), @@ -1339,17 +1156,18 @@ mod tests { DeclarationFunctionKey::with_location("main", "foo") .signature(foo_signature.clone()), vec![None], - vec![ArrayExpressionInner::Value( - vec![FieldElementExpression::Number(Bn128Field::from(1)).into()].into(), + vec![ArrayExpression::value(vec![FieldElementExpression::value( + Bn128Field::from(1), ) - .annotate(Type::FieldElement, 1u32) + .into()]) + .annotate(ArrayType::new(Type::FieldElement, 1u32)) .into()], ) - .annotate(Type::FieldElement, 1u32) + .annotate(ArrayType::new(Type::FieldElement, 1u32)) .into(), ), - TypedStatement::Return( - TupleExpressionInner::Value(vec![]) + TypedStatement::ret( + TupleExpression::value(vec![]) .annotate(TupleType::new(vec![])) .into(), ), @@ -1385,43 +1203,23 @@ mod tests { )] .into_iter() .collect(), + module_map: Default::default(), }; let reduced = reduce_program(p); let expected_main = TypedFunction { arguments: vec![], - statements: vec![ - TypedStatement::PushCallLog( - DeclarationFunctionKey::with_location("main", "foo") - .signature(foo_signature.clone()), - GGenericsAssignment( - vec![(GenericIdentifier::with_name("K").with_index(0), 1)] - .into_iter() - .collect(), - ), - ), - TypedStatement::PushCallLog( - DeclarationFunctionKey::with_location("main", "bar") - .signature(foo_signature.clone()), - GGenericsAssignment( - vec![(GenericIdentifier::with_name("K").with_index(0), 2)] - .into_iter() - .collect(), - ), - ), - TypedStatement::PopCallLog, - TypedStatement::PopCallLog, - TypedStatement::Return( - TupleExpressionInner::Value(vec![]) - .annotate(TupleType::new(vec![])) - .into(), - ), - ], + statements: vec![TypedStatement::ret( + TupleExpression::value(vec![]) + .annotate(TupleType::new(vec![])) + .into(), + )], signature: DeclarationSignature::new(), }; let expected = TypedProgram { + module_map: Default::default(), main: "main".into(), modules: vec![( "main".into(), @@ -1474,9 +1272,9 @@ mod tests { GenericIdentifier::with_name("K").with_index(0), ) .into()], - statements: vec![TypedStatement::Return( + statements: vec![TypedStatement::ret( ArrayExpression::identifier("a".into()) - .annotate(Type::FieldElement, 1u32) + .annotate(ArrayType::new(Type::FieldElement, 1u32)) .into(), )], signature: foo_signature.clone(), @@ -1491,15 +1289,15 @@ mod tests { DeclarationFunctionKey::with_location("main", "foo") .signature(foo_signature.clone()), vec![None], - vec![ArrayExpressionInner::Value(vec![].into()) - .annotate(Type::FieldElement, 0u32) + vec![ArrayExpression::value(vec![]) + .annotate(ArrayType::new(Type::FieldElement, 0u32)) .into()], ) - .annotate(Type::FieldElement, 1u32) + .annotate(ArrayType::new(Type::FieldElement, 1u32)) .into(), ), - TypedStatement::Return( - TupleExpressionInner::Value(vec![]) + TypedStatement::ret( + TupleExpression::value(vec![]) .annotate(TupleType::new(vec![])) .into(), ), @@ -1535,6 +1333,7 @@ mod tests { )] .into_iter() .collect(), + module_map: Default::default(), }; let reduced = reduce_program(p); diff --git a/zokrates_analysis/src/reducer/shallow_ssa.rs b/zokrates_analysis/src/reducer/shallow_ssa.rs index a071a0446..46f9cd962 100644 --- a/zokrates_analysis/src/reducer/shallow_ssa.rs +++ b/zokrates_analysis/src/reducer/shallow_ssa.rs @@ -1,7 +1,6 @@ -// The SSA transformation leaves gaps in the indices when it hits a for-loop, so that the body of the for-loop can -// modify the variables in scope. The state of the indices before all for-loops is returned to account for that possibility. -// Function calls are also left unvisited -// Saving the indices is not required for function calls, as they cannot modify their environment +// The SSA transformation +// * introduces new versions if and only if we are assigning to an identifier +// * does not visit the statements of loops // Example: // def main(field a) -> field { @@ -19,220 +18,226 @@ // u32 n_0 = 42; // a_1 = a_0 + 1; // field b_0 = foo(a_1); // we keep the function call as is -// # versions: {n: 0, a: 1, b: 0} // for u32 i_0 in 0..n_0 { // // we keep the loop body as is // } // return b_3; // we leave versions b_1 and b_2 to make b accessible and modifiable inside the for-loop // } +use std::collections::HashMap; + use zokrates_ast::typed::folder::*; -use zokrates_ast::typed::types::ConcreteGenericsAssignment; -use zokrates_ast::typed::types::Type; + use zokrates_ast::typed::*; use zokrates_field::Field; -use super::{Output, Versions}; - -pub struct ShallowTransformer<'ast, 'a> { - // version index for any variable name - pub versions: &'a mut Versions<'ast>, - // A backup of the versions before each for-loop - pub for_loop_backups: Vec>, - // whether all statements could be unrolled so far. Loops with variable bounds cannot. - pub blocked: bool, +// An SSA version map, giving access to the latest version number for each identifier +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Versions<'ast> { + map: HashMap, usize>>, } -impl<'ast, 'a> ShallowTransformer<'ast, 'a> { - pub fn with_versions(versions: &'a mut Versions<'ast>) -> Self { - ShallowTransformer { - versions, - for_loop_backups: Vec::default(), - blocked: false, +impl<'ast> Default for Versions<'ast> { + fn default() -> Self { + // create a call frame at index 0 + Self { + map: vec![(0, Default::default())].into_iter().collect(), } } +} - // increase all versions by 1 and return the old versions - fn create_version_gap(&mut self) -> Versions<'ast> { - let ret = self.versions.clone(); - self.versions.values_mut().for_each(|v| *v += 1); - ret - } +#[derive(Debug, Default)] +pub struct ShallowTransformer<'ast> { + // version index for any variable name + pub versions: Versions<'ast>, + pub frames: Vec, + pub latest_frame: usize, +} - fn issue_next_identifier(&mut self, c_id: CoreIdentifier<'ast>) -> Identifier<'ast> { - let version = *self - .versions +impl<'ast> ShallowTransformer<'ast> { + pub fn issue_next_identifier(&mut self, c_id: CoreIdentifier<'ast>) -> Identifier<'ast> { + let frame = self.frame(); + + let frame_versions = self.versions.map.entry(frame).or_default(); + + let version = frame_versions .entry(c_id.clone()) .and_modify(|e| *e += 1) // if it was already declared, we increment - .or_insert(0); // otherwise, we start from this version + .or_default(); // otherwise, we start from this version - Identifier::from(c_id).version(version) + Identifier::from(c_id.in_frame(frame)).version(*version) } fn issue_next_ssa_variable(&mut self, v: Variable<'ast, T>) -> Variable<'ast, T> { assert_eq!(v.id.version, 0); Variable { - id: self.issue_next_identifier(v.id.id), + id: self.issue_next_identifier(v.id.id.id), ..v } } - pub fn transform( - f: TypedFunction<'ast, T>, - generics: &ConcreteGenericsAssignment<'ast>, - versions: &'a mut Versions<'ast>, - ) -> Output, Vec>> { - let mut unroller = ShallowTransformer::with_versions(versions); + fn frame(&self) -> usize { + *self.frames.last().unwrap_or(&0) + } - let f = unroller.fold_function(f, generics); + pub fn push_call_frame(&mut self) { + self.latest_frame += 1; + self.frames.push(self.latest_frame); + self.versions + .map + .insert(self.latest_frame, Default::default()); + } - match unroller.blocked { - false => Output::Complete(f), - true => Output::Incomplete(f, unroller.for_loop_backups), - } + pub fn pop_call_frame(&mut self) { + let frame = self.frames.pop().unwrap(); + self.versions.map.remove(&frame); } - fn fold_function( + // fold an assignee replacing by the latest version. This is necessary because the trait implementation increases the ssa version for identifiers, + // but this should not be applied recursively to complex assignees + fn fold_assignee_no_ssa_increase( &mut self, - f: TypedFunction<'ast, T>, - generics: &ConcreteGenericsAssignment<'ast>, - ) -> TypedFunction<'ast, T> { - let mut f = f; - - f.statements = generics - .0 - .clone() - .into_iter() - .map(|(g, v)| { - TypedStatement::definition( - Variable::new(CoreIdentifier::from(g), Type::Uint(UBitwidth::B32), false) - .into(), - UExpression::from(v as u32).into(), - ) - }) - .chain(f.statements) - .collect(); + a: TypedAssignee<'ast, T>, + ) -> TypedAssignee<'ast, T> { + match a { + TypedAssignee::Identifier(v) => TypedAssignee::Identifier(self.fold_variable(v)), + TypedAssignee::Select(a, index) => TypedAssignee::select( + self.fold_assignee_no_ssa_increase(*a), + self.fold_uint_expression(*index), + ), + TypedAssignee::Member(s, m) => { + TypedAssignee::member(self.fold_assignee_no_ssa_increase(*s), m) + } + TypedAssignee::Element(s, index) => { + TypedAssignee::element(self.fold_assignee_no_ssa_increase(*s), index) + } + } + } +} - for arg in &f.arguments { - let _ = self.issue_next_identifier(arg.id.id.id.clone()); +impl<'ast, T: Field> Folder<'ast, T> for ShallowTransformer<'ast> { + fn fold_function(&mut self, f: TypedFunction<'ast, T>) -> TypedFunction<'ast, T> { + for g in &f.signature.generics { + let generic_parameter = match g.as_ref().unwrap() { + DeclarationConstant::Generic(g) => g, + _ => unreachable!(), + }; + let _ = self.issue_next_identifier(CoreIdentifier::from(generic_parameter.clone())); } fold_function(self, f) } - fn fold_assignee(&mut self, a: TypedAssignee<'ast, T>) -> TypedAssignee<'ast, T> { + fn fold_parameter( + &mut self, + p: DeclarationParameter<'ast, T>, + ) -> DeclarationParameter<'ast, T> { + DeclarationParameter { + id: DeclarationVariable { + id: self.issue_next_identifier(p.id.id.id.id), + ..p.id + }, + ..p + } + } + + fn fold_assignee(&mut self, a: TypedAssignee<'ast, T>) -> TypedAssignee<'ast, T> { match a { + // create a new version for assignments to identifiers TypedAssignee::Identifier(v) => { let v = self.issue_next_ssa_variable(v); TypedAssignee::Identifier(self.fold_variable(v)) } - a => fold_assignee(self, a), + // otherwise, simply replace by the current version + a => self.fold_assignee_no_ssa_increase(a), } } -} -impl<'ast, 'a, T: Field> Folder<'ast, T> for ShallowTransformer<'ast, 'a> { - fn fold_assembly_statement( - &mut self, - s: TypedAssemblyStatement<'ast, T>, - ) -> Vec> { - match s { - TypedAssemblyStatement::Assignment(a, e) => { - let e = self.fold_expression(e); - let a = self.fold_assignee(a); - vec![TypedAssemblyStatement::Assignment(a, e)] - } - s => fold_assembly_statement(self, s), - } - } - fn fold_statement(&mut self, s: TypedStatement<'ast, T>) -> Vec> { - match s { - TypedStatement::Definition(a, DefinitionRhs::Expression(e)) => { - let e = self.fold_expression(e); - let a = self.fold_assignee(a); - vec![TypedStatement::definition(a, e)] - } - TypedStatement::Definition(assignee, DefinitionRhs::EmbedCall(embed_call)) => { - let embed_call = self.fold_embed_call(embed_call); - let assignee = self.fold_assignee(assignee); - vec![TypedStatement::embed_call_definition(assignee, embed_call)] - } - TypedStatement::For(v, from, to, stats) => { - let from = self.fold_uint_expression(from); - let to = self.fold_uint_expression(to); - self.blocked = true; - let versions_before_loop = self.create_version_gap(); - self.for_loop_backups.push(versions_before_loop); - vec![TypedStatement::For(v, from, to, stats)] - } - s => fold_statement(self, s), - } + // only fold bounds of for loop statements + fn fold_for_statement(&mut self, s: ForStatement<'ast, T>) -> Vec> { + let from = self.fold_uint_expression(s.from); + let to = self.fold_uint_expression(s.to); + vec![TypedStatement::for_(s.var, from, to, s.statements)] } + // retrieve the latest version fn fold_name(&mut self, n: Identifier<'ast>) -> Identifier<'ast> { - let res = Identifier { - version: *self.versions.get(&(n.id)).unwrap_or(&0), - ..n - }; - res - } - - fn fold_function_call_expression< - E: Id<'ast, T> + From> + Expr<'ast, T> + FunctionCall<'ast, T>, - >( - &mut self, - ty: &E::Ty, - c: FunctionCallExpression<'ast, T, E>, - ) -> FunctionCallOrExpression<'ast, T, E> { - if !c.function_key.id.starts_with('_') { - self.blocked = true; - } - - fold_function_call_expression(self, ty, c) + let version = self + .versions + .map + .get(&self.frame()) + .unwrap() + .get(&n.id.id) + .cloned() + .unwrap_or(0); + + n.in_frame(self.frame()).version(version) } } #[cfg(test)] mod tests { use super::*; + use std::ops::*; use zokrates_ast::typed::types::DeclarationSignature; use zokrates_field::Bn128Field; mod normal { use super::*; #[test] - fn detect_non_constant_bound() { - let loops: Vec> = vec![TypedStatement::For( - Variable::new("i", Type::Uint(UBitwidth::B32), false), - UExpression::identifier("i".into()).annotate(UBitwidth::B32), - 2u32.into(), - vec![], - )]; + fn ignore_loop_content() { + // field foo = 0 + // u32 i = 4; + // for u32 i in i..2 { + // foo = 5; + // } - let statements = loops; + // should be left unchanged, as we do not visit the loop content nor the index variable let f = TypedFunction { arguments: vec![], - signature: DeclarationSignature::new(), - statements, + statements: vec![ + TypedStatement::definition( + TypedAssignee::Identifier(Variable::field_element(Identifier::from("foo"))), + FieldElementExpression::value(Bn128Field::from(4)).into(), + ), + TypedStatement::definition( + TypedAssignee::Identifier(Variable::uint( + Identifier::from("i"), + UBitwidth::B32, + )), + UExpression::from(0u32).into(), + ), + TypedStatement::for_( + Variable::new("i", Type::Uint(UBitwidth::B32)), + UExpression::identifier("i".into()).annotate(UBitwidth::B32), + 2u32.into(), + vec![TypedStatement::definition( + TypedAssignee::Identifier(Variable::field_element(Identifier::from( + "foo", + ))), + FieldElementExpression::value(Bn128Field::from(5)).into(), + )], + ), + TypedStatement::ret( + TupleExpression::value(vec![]) + .annotate(TupleType::new(vec![])) + .into(), + ), + ], + signature: DeclarationSignature::default(), }; - match ShallowTransformer::transform( - f, - &ConcreteGenericsAssignment::default(), - &mut Versions::default(), - ) { - Output::Incomplete(..) => {} - _ => unreachable!(), - }; + let mut ssa = ShallowTransformer::default(); + + assert_eq!(ssa.fold_function(f.clone()), f); } #[test] fn definition() { - // field a - // a = 5 + // field a = 5 // a = 6 // a @@ -241,13 +246,11 @@ mod tests { // a_1 = 6 // a_1 - let mut versions = Versions::new(); - - let mut u = ShallowTransformer::with_versions(&mut versions); + let mut u = ShallowTransformer::default(); let s = TypedStatement::definition( TypedAssignee::Identifier(Variable::field_element("a")), - FieldElementExpression::Number(Bn128Field::from(5)).into(), + FieldElementExpression::value(Bn128Field::from(5)).into(), ); assert_eq!( u.fold_statement(s), @@ -255,13 +258,13 @@ mod tests { TypedAssignee::Identifier(Variable::field_element( Identifier::from("a").version(0) )), - FieldElementExpression::Number(Bn128Field::from(5)).into() + FieldElementExpression::value(Bn128Field::from(5)).into() )] ); let s = TypedStatement::definition( TypedAssignee::Identifier(Variable::field_element("a")), - FieldElementExpression::Number(Bn128Field::from(6)).into(), + FieldElementExpression::value(Bn128Field::from(6)).into(), ); assert_eq!( u.fold_statement(s), @@ -269,7 +272,7 @@ mod tests { TypedAssignee::Identifier(Variable::field_element( Identifier::from("a").version(1) )), - FieldElementExpression::Number(Bn128Field::from(6)).into() + FieldElementExpression::value(Bn128Field::from(6)).into() )] ); @@ -283,21 +286,18 @@ mod tests { #[test] fn incremental_definition() { - // field a - // a = 5 + // field a = 5 // a = a + 1 // should be turned into // a_0 = 5 // a_1 = a_0 + 1 - let mut versions = Versions::new(); - - let mut u = ShallowTransformer::with_versions(&mut versions); + let mut u = ShallowTransformer::default(); let s = TypedStatement::definition( TypedAssignee::Identifier(Variable::field_element("a")), - FieldElementExpression::Number(Bn128Field::from(5)).into(), + FieldElementExpression::value(Bn128Field::from(5)).into(), ); assert_eq!( u.fold_statement(s), @@ -305,15 +305,15 @@ mod tests { TypedAssignee::Identifier(Variable::field_element( Identifier::from("a").version(0) )), - FieldElementExpression::Number(Bn128Field::from(5)).into() + FieldElementExpression::value(Bn128Field::from(5)).into() )] ); let s = TypedStatement::definition( TypedAssignee::Identifier(Variable::field_element("a")), - FieldElementExpression::Add( - box FieldElementExpression::identifier("a".into()), - box FieldElementExpression::Number(Bn128Field::from(1)), + FieldElementExpression::add( + FieldElementExpression::identifier("a".into()), + FieldElementExpression::value(Bn128Field::from(1)), ) .into(), ); @@ -323,9 +323,9 @@ mod tests { TypedAssignee::Identifier(Variable::field_element( Identifier::from("a").version(1) )), - FieldElementExpression::Add( - box FieldElementExpression::identifier(Identifier::from("a").version(0)), - box FieldElementExpression::Number(Bn128Field::from(1)) + FieldElementExpression::add( + FieldElementExpression::identifier(Identifier::from("a").version(0)), + FieldElementExpression::value(Bn128Field::from(1)) ) .into() )] @@ -342,13 +342,11 @@ mod tests { // a_0 = 2 // a_1 = foo(a_0) - let mut versions = Versions::new(); - - let mut u = ShallowTransformer::with_versions(&mut versions); + let mut u = ShallowTransformer::default(); let s = TypedStatement::definition( TypedAssignee::Identifier(Variable::field_element("a")), - FieldElementExpression::Number(Bn128Field::from(2)).into(), + FieldElementExpression::value(Bn128Field::from(2)).into(), ); assert_eq!( u.fold_statement(s), @@ -356,7 +354,7 @@ mod tests { TypedAssignee::Identifier(Variable::field_element( Identifier::from("a").version(0) )), - FieldElementExpression::Number(Bn128Field::from(2)).into() + FieldElementExpression::value(Bn128Field::from(2)).into() )] ); @@ -403,20 +401,15 @@ mod tests { // a_0 = [1, 1] // a_0[1] = 2 - let mut versions = Versions::new(); - - let mut u = ShallowTransformer::with_versions(&mut versions); + let mut u = ShallowTransformer::default(); let s = TypedStatement::definition( TypedAssignee::Identifier(Variable::array("a", Type::FieldElement, 2u32)), - ArrayExpressionInner::Value( - vec![ - FieldElementExpression::Number(Bn128Field::from(1)).into(), - FieldElementExpression::Number(Bn128Field::from(1)).into(), - ] - .into(), - ) - .annotate(Type::FieldElement, 2u32) + ArrayExpression::value(vec![ + FieldElementExpression::value(Bn128Field::from(1)).into(), + FieldElementExpression::value(Bn128Field::from(1)).into(), + ]) + .annotate(ArrayType::new(Type::FieldElement, 2u32)) .into(), ); @@ -428,24 +421,25 @@ mod tests { Type::FieldElement, 2u32 )), - ArrayExpressionInner::Value( - vec![ - FieldElementExpression::Number(Bn128Field::from(1)).into(), - FieldElementExpression::Number(Bn128Field::from(1)).into() - ] - .into() - ) - .annotate(Type::FieldElement, 2u32) + ArrayExpression::value(vec![ + FieldElementExpression::value(Bn128Field::from(1)).into(), + FieldElementExpression::value(Bn128Field::from(1)).into() + ]) + .annotate(ArrayType::new(Type::FieldElement, 2u32)) .into() )] ); let s: TypedStatement = TypedStatement::definition( TypedAssignee::Select( - box TypedAssignee::Identifier(Variable::array("a", Type::FieldElement, 2u32)), - box UExpression::from(1u32), + Box::new(TypedAssignee::Identifier(Variable::array( + "a", + Type::FieldElement, + 2u32, + ))), + Box::new(UExpression::from(1u32)), ), - FieldElementExpression::Number(Bn128Field::from(2)).into(), + FieldElementExpression::value(Bn128Field::from(2)).into(), ); assert_eq!(u.fold_statement(s.clone()), vec![s]); @@ -460,38 +454,30 @@ mod tests { // a_0 = [[0, 1], [2, 3]] // a_0 = [4, 5] - let mut versions = Versions::new(); - - let mut u = ShallowTransformer::with_versions(&mut versions); + let mut u = ShallowTransformer::default(); let array_of_array_ty = Type::array((Type::array((Type::FieldElement, 2u32)), 2u32)); let s = TypedStatement::definition( - TypedAssignee::Identifier(Variable::new("a", array_of_array_ty.clone(), true)), - ArrayExpressionInner::Value( - vec![ - ArrayExpressionInner::Value( - vec![ - FieldElementExpression::Number(Bn128Field::from(0)).into(), - FieldElementExpression::Number(Bn128Field::from(1)).into(), - ] - .into(), - ) - .annotate(Type::FieldElement, 2u32) - .into(), - ArrayExpressionInner::Value( - vec![ - FieldElementExpression::Number(Bn128Field::from(2)).into(), - FieldElementExpression::Number(Bn128Field::from(3)).into(), - ] - .into(), - ) - .annotate(Type::FieldElement, 2u32) - .into(), - ] + TypedAssignee::Identifier(Variable::new("a", array_of_array_ty.clone())), + ArrayExpression::value(vec![ + ArrayExpression::value(vec![ + FieldElementExpression::value(Bn128Field::from(0)).into(), + FieldElementExpression::value(Bn128Field::from(1)).into(), + ]) + .annotate(ArrayType::new(Type::FieldElement, 2u32)) .into(), - ) - .annotate(Type::array((Type::FieldElement, 2u32)), 2u32) + ArrayExpression::value(vec![ + FieldElementExpression::value(Bn128Field::from(2)).into(), + FieldElementExpression::value(Bn128Field::from(3)).into(), + ]) + .annotate(ArrayType::new(Type::FieldElement, 2u32)) + .into(), + ]) + .annotate(ArrayType::new( + Type::array((Type::FieldElement, 2u32)), + 2u32, + )) .into(), ); @@ -501,53 +487,39 @@ mod tests { TypedAssignee::Identifier(Variable::new( Identifier::from("a").version(0), array_of_array_ty.clone(), - true, )), - ArrayExpressionInner::Value( - vec![ - ArrayExpressionInner::Value( - vec![ - FieldElementExpression::Number(Bn128Field::from(0)).into(), - FieldElementExpression::Number(Bn128Field::from(1)).into(), - ] - .into() - ) - .annotate(Type::FieldElement, 2u32) - .into(), - ArrayExpressionInner::Value( - vec![ - FieldElementExpression::Number(Bn128Field::from(2)).into(), - FieldElementExpression::Number(Bn128Field::from(3)).into(), - ] - .into() - ) - .annotate(Type::FieldElement, 2u32) - .into(), - ] - .into() - ) - .annotate(Type::array((Type::FieldElement, 2u32)), 2u32) + ArrayExpression::value(vec![ + ArrayExpression::value(vec![ + FieldElementExpression::value(Bn128Field::from(0)).into(), + FieldElementExpression::value(Bn128Field::from(1)).into(), + ]) + .annotate(ArrayType::new(Type::FieldElement, 2u32)) + .into(), + ArrayExpression::value(vec![ + FieldElementExpression::value(Bn128Field::from(2)).into(), + FieldElementExpression::value(Bn128Field::from(3)).into(), + ]) + .annotate(ArrayType::new(Type::FieldElement, 2u32)) + .into(), + ]) + .annotate(ArrayType::new( + Type::array((Type::FieldElement, 2u32)), + 2u32 + )) .into(), )] ); let s: TypedStatement = TypedStatement::definition( - TypedAssignee::Select( - box TypedAssignee::Identifier(Variable::new( - "a", - array_of_array_ty.clone(), - true, - )), - box UExpression::from(1u32), + TypedAssignee::select( + TypedAssignee::Identifier(Variable::new("a", array_of_array_ty.clone())), + UExpression::from(1u32), ), - ArrayExpressionInner::Value( - vec![ - FieldElementExpression::Number(Bn128Field::from(4)).into(), - FieldElementExpression::Number(Bn128Field::from(5)).into(), - ] - .into(), - ) - .annotate(Type::FieldElement, 2u32) + ArrayExpression::value(vec![ + FieldElementExpression::value(Bn128Field::from(4)).into(), + FieldElementExpression::value(Bn128Field::from(5)).into(), + ]) + .annotate(ArrayType::new(Type::FieldElement, 2u32)) .into(), ); @@ -557,10 +529,10 @@ mod tests { mod for_loop { use super::*; - use zokrates_ast::typed::types::GGenericsAssignment; + #[test] fn treat_loop() { - // def main(field a) -> field { + // def main(field a) -> field { // u32 n = 42; // n = n; // a = a; @@ -575,24 +547,21 @@ mod tests { // return a; // } - // When called with K := 1, expected: + // expected: // def main(field a_0) -> field { - // u32 K = 1; // u32 n_0 = 42; // n_1 = n_0; // a_1 = a_0; - // # versions: {n: 1, a: 1, K: 0} // for u32 i_0 in n_1..n_1*n_1 { // a_0 = a_0; // } - // a_3 = a_2; - // # versions: {n: 2, a: 3, K: 1} - // for u32 i_0 in n_2..n_2*n_2 { + // a_2 = a_1; + // for u32 i_0 in n_1..n_1*n_1 { // a_0 = a_0; // } - // a_5 = a_4; - // return a_5; - // } # versions: {n: 3, a: 5, K: 2} + // a_3 = a_2; + // return a_3; + // } let f: TypedFunction = TypedFunction { arguments: vec![DeclarationVariable::field_element("a").into()], @@ -611,7 +580,7 @@ mod tests { Variable::field_element("a").into(), FieldElementExpression::identifier("a".into()).into(), ), - TypedStatement::For( + TypedStatement::for_( Variable::uint("i", UBitwidth::B32), UExpression::identifier("n".into()).annotate(UBitwidth::B32), UExpression::identifier("n".into()).annotate(UBitwidth::B32) @@ -625,7 +594,7 @@ mod tests { Variable::field_element("a").into(), FieldElementExpression::identifier("a".into()).into(), ), - TypedStatement::For( + TypedStatement::for_( Variable::uint("i", UBitwidth::B32), UExpression::identifier("n".into()).annotate(UBitwidth::B32), UExpression::identifier("n".into()).annotate(UBitwidth::B32) @@ -639,35 +608,18 @@ mod tests { Variable::field_element("a").into(), FieldElementExpression::identifier("a".into()).into(), ), - TypedStatement::Return(FieldElementExpression::identifier("a".into()).into()), + TypedStatement::ret(FieldElementExpression::identifier("a".into()).into()), ], signature: DeclarationSignature::new() - .generics(vec![Some( - GenericIdentifier::with_name("K").with_index(0).into(), - )]) .inputs(vec![DeclarationType::FieldElement]) .output(DeclarationType::FieldElement), }; - let mut versions = Versions::default(); - - let ssa = ShallowTransformer::transform( - f, - &GGenericsAssignment( - vec![(GenericIdentifier::with_name("K").with_index(0), 1)] - .into_iter() - .collect(), - ), - &mut versions, - ); + let mut ssa = ShallowTransformer::default(); let expected = TypedFunction { arguments: vec![DeclarationVariable::field_element("a").into()], statements: vec![ - TypedStatement::definition( - Variable::uint("K", UBitwidth::B32).into(), - TypedExpression::Uint(1u32.into()), - ), TypedStatement::definition( Variable::uint("n", UBitwidth::B32).into(), TypedExpression::Uint(42u32.into()), @@ -682,7 +634,7 @@ mod tests { Variable::field_element(Identifier::from("a").version(1)).into(), FieldElementExpression::identifier("a".into()).into(), ), - TypedStatement::For( + TypedStatement::for_( Variable::uint("i", UBitwidth::B32), UExpression::identifier(Identifier::from("n").version(1)) .annotate(UBitwidth::B32), @@ -696,16 +648,16 @@ mod tests { )], ), TypedStatement::definition( - Variable::field_element(Identifier::from("a").version(3)).into(), - FieldElementExpression::identifier(Identifier::from("a").version(2)).into(), + Variable::field_element(Identifier::from("a").version(2)).into(), + FieldElementExpression::identifier(Identifier::from("a").version(1)).into(), ), - TypedStatement::For( + TypedStatement::for_( Variable::uint("i", UBitwidth::B32), - UExpression::identifier(Identifier::from("n").version(2)) + UExpression::identifier(Identifier::from("n").version(1)) .annotate(UBitwidth::B32), - UExpression::identifier(Identifier::from("n").version(2)) + UExpression::identifier(Identifier::from("n").version(1)) .annotate(UBitwidth::B32) - * UExpression::identifier(Identifier::from("n").version(2)) + * UExpression::identifier(Identifier::from("n").version(1)) .annotate(UBitwidth::B32), vec![TypedStatement::definition( Variable::field_element("a").into(), @@ -713,46 +665,35 @@ mod tests { )], ), TypedStatement::definition( - Variable::field_element(Identifier::from("a").version(5)).into(), - FieldElementExpression::identifier(Identifier::from("a").version(4)).into(), + Variable::field_element(Identifier::from("a").version(3)).into(), + FieldElementExpression::identifier(Identifier::from("a").version(2)).into(), ), - TypedStatement::Return( - FieldElementExpression::identifier(Identifier::from("a").version(5)).into(), + TypedStatement::ret( + FieldElementExpression::identifier(Identifier::from("a").version(3)).into(), ), ], signature: DeclarationSignature::new() - .generics(vec![Some( - GenericIdentifier::with_name("K").with_index(0).into(), - )]) .inputs(vec![DeclarationType::FieldElement]) .output(DeclarationType::FieldElement), }; - assert_eq!( - versions, - vec![("n".into(), 3), ("a".into(), 5), ("K".into(), 2)] - .into_iter() - .collect::() - ); + let res = ssa.fold_function(f); - let expected = Output::Incomplete( - expected, - vec![ - vec![("n".into(), 1), ("a".into(), 1), ("K".into(), 0)] - .into_iter() - .collect::(), - vec![("n".into(), 2), ("a".into(), 3), ("K".into(), 1)] - .into_iter() - .collect::(), - ], + assert_eq!( + ssa.versions.map, + vec![( + 0, + vec![("n".into(), 1), ("a".into(), 3)].into_iter().collect() + )] + .into_iter() + .collect() ); - assert_eq!(ssa, expected); + assert_eq!(res, expected); } } mod shadowing { - use zokrates_ast::typed::types::GGenericsAssignment; use super::*; @@ -764,11 +705,11 @@ mod tests { // return; // } - // should become + // should become (only the field variable is affected as shadowing is taken care of in semantics already) - // def main(field a_0) { - // field a_1 = 42; - // bool a_2 = true; + // def main(field a_s0_v0) { + // field a_s0_v1 = 42; + // bool a_s1_v0 = true // return; // } @@ -780,18 +721,20 @@ mod tests { TypedExpression::Uint(42u32.into()), ), TypedStatement::definition( - Variable::boolean("a").into(), - BooleanExpression::Value(true).into(), + Variable::boolean(CoreIdentifier::from(ShadowedIdentifier::shadow( + "a".into(), + 1, + ))) + .into(), + BooleanExpression::value(true).into(), ), - TypedStatement::Return( - TupleExpressionInner::Value(vec![]) + TypedStatement::ret( + TupleExpression::value(vec![]) .annotate(TupleType::new(vec![])) .into(), ), ], - signature: DeclarationSignature::new() - .generics(vec![]) - .inputs(vec![DeclarationType::FieldElement]), + signature: DeclarationSignature::new().inputs(vec![DeclarationType::FieldElement]), }; let expected: TypedFunction = TypedFunction { @@ -802,130 +745,30 @@ mod tests { TypedExpression::Uint(42u32.into()), ), TypedStatement::definition( - Variable::boolean(Identifier::from("a").version(2)).into(), - BooleanExpression::Value(true).into(), - ), - TypedStatement::Return( - TupleExpressionInner::Value(vec![]) - .annotate(TupleType::new(vec![])) - .into(), - ), - ], - signature: DeclarationSignature::new() - .generics(vec![]) - .inputs(vec![DeclarationType::FieldElement]), - }; - - let mut versions = Versions::default(); - - let ssa = - ShallowTransformer::transform(f, &GGenericsAssignment::default(), &mut versions); - - assert_eq!(ssa, Output::Complete(expected)); - } - - #[test] - fn next_scope() { - // def main(field a) { - // for u32 i in 0..1 { - // a = a + 1 - // field a = 42 - // } - // return a - // } - - // should become - - // def main(field a_0) { - // # versions: {a: 0} - // for u32 i in 0..1 { - // a_0 = a_0 - // field a_0 = 42 - // } - // return a_1 - // } - - let f: TypedFunction = TypedFunction { - arguments: vec![DeclarationVariable::field_element("a").into()], - statements: vec![ - TypedStatement::For( - Variable::uint("i", UBitwidth::B32), - 0u32.into(), - 1u32.into(), - vec![ - TypedStatement::definition( - Variable::field_element(Identifier::from("a")).into(), - FieldElementExpression::identifier("a".into()).into(), - ), - TypedStatement::definition( - Variable::field_element(Identifier::from("a")).into(), - FieldElementExpression::Number(42usize.into()).into(), - ), - ], - ), - TypedStatement::Return( - TupleExpressionInner::Value(vec![FieldElementExpression::identifier( + Variable::boolean(CoreIdentifier::from(ShadowedIdentifier::shadow( "a".into(), - ) - .into()]) - .annotate(TupleType::new(vec![Type::FieldElement])) + 1, + ))) .into(), + BooleanExpression::value(true).into(), ), - ], - signature: DeclarationSignature::new() - .generics(vec![]) - .inputs(vec![DeclarationType::FieldElement]) - .output(DeclarationType::FieldElement), - }; - - let expected: TypedFunction = TypedFunction { - arguments: vec![DeclarationVariable::field_element("a").into()], - statements: vec![ - TypedStatement::For( - Variable::uint("i", UBitwidth::B32), - 0u32.into(), - 1u32.into(), - vec![ - TypedStatement::definition( - Variable::field_element(Identifier::from("a")).into(), - FieldElementExpression::identifier(Identifier::from("a")).into(), - ), - TypedStatement::definition( - Variable::field_element(Identifier::from("a")).into(), - FieldElementExpression::Number(42usize.into()).into(), - ), - ], - ), - TypedStatement::Return( - TupleExpressionInner::Value(vec![FieldElementExpression::identifier( - Identifier::from("a").version(1), - ) - .into()]) - .annotate(TupleType::new(vec![Type::FieldElement])) - .into(), + TypedStatement::ret( + TupleExpression::value(vec![]) + .annotate(TupleType::new(vec![])) + .into(), ), ], - signature: DeclarationSignature::new() - .generics(vec![]) - .inputs(vec![DeclarationType::FieldElement]) - .output(DeclarationType::FieldElement), + signature: DeclarationSignature::new().inputs(vec![DeclarationType::FieldElement]), }; - let mut versions = Versions::default(); + let ssa = ShallowTransformer::default().fold_function(f); - let ssa = - ShallowTransformer::transform(f, &GGenericsAssignment::default(), &mut versions); - - assert_eq!( - ssa, - Output::Incomplete(expected, vec![vec![("a".into(), 0)].into_iter().collect()]) - ); + assert_eq!(ssa, expected); } } mod function_call { use super::*; - use zokrates_ast::typed::types::GGenericsAssignment; // test that function calls are left in #[test] fn treat_calls() { @@ -939,17 +782,12 @@ mod tests { // return a; // } - // When called with K := 1, expected: // def main(field a_0) -> field { - // K = 1; - // u32 n_0 = 42; - // n_1 = n_0; // a_1 = a_0; - // a_2 = foo::(a_1); - // n_2 = n_1; - // a_3 = a_2 * foo::(a_2); + // a_2 = foo::<42>(a_1); + // a_3 = a_2 * foo::<42>(a_2); // return a_3; - // } # versions: {n: 2, a: 3} + // } let f: TypedFunction = TypedFunction { arguments: vec![DeclarationVariable::field_element("a").into()], @@ -997,7 +835,7 @@ mod tests { )) .into(), ), - TypedStatement::Return(FieldElementExpression::identifier("a".into()).into()), + TypedStatement::ret(FieldElementExpression::identifier("a".into()).into()), ], signature: DeclarationSignature::new() .generics(vec![Some( @@ -1007,25 +845,9 @@ mod tests { .output(DeclarationType::FieldElement), }; - let mut versions = Versions::default(); - - let ssa = ShallowTransformer::transform( - f, - &GGenericsAssignment( - vec![(GenericIdentifier::with_name("K").with_index(0), 1)] - .into_iter() - .collect(), - ), - &mut versions, - ); - let expected = TypedFunction { arguments: vec![DeclarationVariable::field_element("a").into()], statements: vec![ - TypedStatement::definition( - Variable::uint("K", UBitwidth::B32).into(), - TypedExpression::Uint(1u32.into()), - ), TypedStatement::definition( Variable::uint("n", UBitwidth::B32).into(), TypedExpression::Uint(42u32.into()), @@ -1077,7 +899,7 @@ mod tests { )) .into(), ), - TypedStatement::Return( + TypedStatement::ret( FieldElementExpression::identifier(Identifier::from("a").version(3)).into(), ), ], @@ -1089,14 +911,23 @@ mod tests { .output(DeclarationType::FieldElement), }; + let mut ssa = ShallowTransformer::default(); + + let res = ssa.fold_function(f); + assert_eq!( - versions, - vec![("n".into(), 2), ("a".into(), 3), ("K".into(), 0)] - .into_iter() - .collect::() + ssa.versions.map, + vec![( + 0, + vec![("n".into(), 2), ("a".into(), 3), ("K".into(), 0)] + .into_iter() + .collect() + )] + .into_iter() + .collect() ); - assert_eq!(ssa, Output::Incomplete(expected, vec![],)); + assert_eq!(res, expected); } } } diff --git a/zokrates_analysis/src/struct_concretizer.rs b/zokrates_analysis/src/struct_concretizer.rs index 102cb4d8f..6e57c0484 100644 --- a/zokrates_analysis/src/struct_concretizer.rs +++ b/zokrates_analysis/src/struct_concretizer.rs @@ -1,5 +1,5 @@ // After all generics are inlined, a program should be completely "concrete", which means that all types must only contain -// litterals for array sizes. This is especially important to generate the ABI of the program. +// literals for array sizes. This is especially important to generate the ABI of the program. // It is direct to ensure that with most types, however the way structs are implemented requires a slightly different process: // Where for an array, `field[N]` ends up being propagated to `field[42]` which is direct to turn into a concrete type, // for structs, `Foo { field[N] a }` is propagated to `Foo<42> { field[N] a }`. The missing step is replacing `N` by `42` @@ -70,7 +70,7 @@ impl<'ast, T: Field> Folder<'ast, T> for StructConcretizer<'ast, T> { .collect(), generics: concrete_generics .into_iter() - .map(|g| Some(DeclarationConstant::Concrete(g as u32))) + .map(|g| Some(DeclarationConstant::Concrete(g))) .collect(), ..ty } @@ -82,9 +82,9 @@ impl<'ast, T: Field> Folder<'ast, T> for StructConcretizer<'ast, T> { ) -> DeclarationArrayType<'ast, T> { let size = ty.size.map_concrete(&self.generics).unwrap(); - DeclarationArrayType { - size: box DeclarationConstant::Concrete(size), - ty: box self.fold_declaration_type(*ty.ty), - } + DeclarationArrayType::new( + self.fold_declaration_type(*ty.ty), + DeclarationConstant::Concrete(size), + ) } } diff --git a/zokrates_analysis/src/uint_optimizer.rs b/zokrates_analysis/src/uint_optimizer.rs index ac96dbfe1..c006cdd67 100644 --- a/zokrates_analysis/src/uint_optimizer.rs +++ b/zokrates_analysis/src/uint_optimizer.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; use std::ops::{BitAnd, Shl, Shr}; -use zokrates_ast::common::FlatEmbed; +use zokrates_ast::common::{FlatEmbed, Fold, WithSpan}; use zokrates_ast::zir::folder::*; use zokrates_ast::zir::*; use zokrates_field::Field; @@ -55,7 +55,7 @@ fn force_no_reduce(e: UExpression) -> UExpression { } impl<'ast, T: Field> Folder<'ast, T> for UintOptimizer<'ast, T> { - fn fold_select_expression + Fold<'ast, T> + Select<'ast, T>>( + fn fold_select_expression + Fold + Select<'ast, T>>( &mut self, _: &E::Ty, e: SelectExpression<'ast, T, E>, @@ -66,43 +66,45 @@ impl<'ast, T: Field> Folder<'ast, T> for UintOptimizer<'ast, T> { SelectOrExpression::Select(SelectExpression::new(array, force_reduce(index))) } - fn fold_boolean_expression( + fn fold_boolean_expression_cases( &mut self, e: BooleanExpression<'ast, T>, ) -> BooleanExpression<'ast, T> { match e { - BooleanExpression::UintEq(box left, box right) => { - let left = self.fold_uint_expression(left); - let right = self.fold_uint_expression(right); + BooleanExpression::UintEq(e) => { + let left = self.fold_uint_expression(*e.left); + let right = self.fold_uint_expression(*e.right); let left = force_reduce(left); let right = force_reduce(right); - BooleanExpression::UintEq(box left, box right) + BooleanExpression::uint_eq(left, right) } - BooleanExpression::UintLt(box left, box right) => { - let left = self.fold_uint_expression(left); - let right = self.fold_uint_expression(right); + BooleanExpression::UintLt(e) => { + let left = self.fold_uint_expression(*e.left); + let right = self.fold_uint_expression(*e.right); let left = force_reduce(left); let right = force_reduce(right); - BooleanExpression::UintLt(box left, box right) + BooleanExpression::uint_lt(left, right) } - BooleanExpression::UintLe(box left, box right) => { - let left = self.fold_uint_expression(left); - let right = self.fold_uint_expression(right); + BooleanExpression::UintLe(e) => { + let left = self.fold_uint_expression(*e.left); + let right = self.fold_uint_expression(*e.right); let left = force_reduce(left); let right = force_reduce(right); - BooleanExpression::UintLe(box left, box right) + BooleanExpression::uint_le(left, right) } - e => fold_boolean_expression(self, e), + e => fold_boolean_expression_cases(self, e), } } fn fold_uint_expression(&mut self, e: UExpression<'ast, T>) -> UExpression<'ast, T> { + let span = e.get_span(); + if e.metadata.is_some() { return e; } @@ -120,7 +122,7 @@ impl<'ast, T: Field> Folder<'ast, T> for UintOptimizer<'ast, T> { use self::UExpressionInner::*; let res = match inner { - Value(v) => Value(v).annotate(range).with_max(v), + Value(v) => Value(v.clone()).annotate(range).with_max(v.value), Identifier(id) => Identifier(id.clone()).annotate(range).metadata( self.ids .get(&Variable::uint(id.id.clone(), range)) @@ -151,10 +153,10 @@ impl<'ast, T: Field> Folder<'ast, T> for UintOptimizer<'ast, T> { UExpression::select(values, index).with_max(max_value) } - Add(box left, box right) => { + Add(e) => { // reduce the two terms - let left = self.fold_uint_expression(left); - let right = self.fold_uint_expression(right); + let left = self.fold_uint_expression(*e.left); + let right = self.fold_uint_expression(*e.right); let left_max = left.metadata.clone().unwrap().max; let right_max = right.metadata.clone().unwrap().max; @@ -170,7 +172,7 @@ impl<'ast, T: Field> Folder<'ast, T> for UintOptimizer<'ast, T> { left_max .checked_add(&range_max.clone()) .map(|max| (false, true, max)) - .unwrap_or_else(|| (true, true, range_max.clone() + range_max)) + .unwrap_or_else(|| (true, true, range_max + range_max)) }) }); @@ -187,7 +189,7 @@ impl<'ast, T: Field> Folder<'ast, T> for UintOptimizer<'ast, T> { UExpression::add(left, right).with_max(max) } - Sub(box left, box right) => { + Sub(e) => { // let `target` the target bitwidth of `left` and `right` // `0 <= left <= max_left` // `0 <= right <= max_right` @@ -205,8 +207,8 @@ impl<'ast, T: Field> Folder<'ast, T> for UintOptimizer<'ast, T> { // smaller or equal to N for target in {8, 16, 32} // reduce the two terms - let left = self.fold_uint_expression(left); - let right = self.fold_uint_expression(right); + let left = self.fold_uint_expression(*e.left); + let right = self.fold_uint_expression(*e.right); let left_max = left.metadata.clone().unwrap().max; let right_bitwidth = right.metadata.clone().unwrap().bitwidth(); @@ -223,7 +225,7 @@ impl<'ast, T: Field> Folder<'ast, T> for UintOptimizer<'ast, T> { left_max .checked_add(&target_offset) .map(|max| (false, true, max)) - .unwrap_or_else(|| (true, true, range_max.clone() + target_offset)) + .unwrap_or_else(|| (true, true, range_max + target_offset)) } else { left_max .checked_add(&offset) @@ -254,31 +256,31 @@ impl<'ast, T: Field> Folder<'ast, T> for UintOptimizer<'ast, T> { UExpression::sub(left, right).with_max(max) } - Xor(box left, box right) => { + Xor(e) => { // reduce the two terms - let left = self.fold_uint_expression(left); - let right = self.fold_uint_expression(right); + let left = self.fold_uint_expression(*e.left); + let right = self.fold_uint_expression(*e.right); UExpression::xor(force_reduce(left), force_reduce(right)).with_max(range_max) } - And(box left, box right) => { + And(e) => { // reduce the two terms - let left = self.fold_uint_expression(left); - let right = self.fold_uint_expression(right); + let left = self.fold_uint_expression(*e.left); + let right = self.fold_uint_expression(*e.right); UExpression::and(force_reduce(left), force_reduce(right)).with_max(range_max) } - Or(box left, box right) => { + Or(e) => { // reduce the two terms - let left = self.fold_uint_expression(left); - let right = self.fold_uint_expression(right); + let left = self.fold_uint_expression(*e.left); + let right = self.fold_uint_expression(*e.right); UExpression::or(force_reduce(left), force_reduce(right)).with_max(range_max) } - Mult(box left, box right) => { + Mult(e) => { // reduce the two terms - let left = self.fold_uint_expression(left); - let right = self.fold_uint_expression(right); + let left = self.fold_uint_expression(*e.left); + let right = self.fold_uint_expression(*e.right); let left_max = left.metadata.clone().unwrap().max; let right_max = right.metadata.clone().unwrap().max; @@ -294,7 +296,7 @@ impl<'ast, T: Field> Folder<'ast, T> for UintOptimizer<'ast, T> { left_max .checked_mul(&range_max.clone()) .map(|max| (false, true, max)) - .unwrap_or_else(|| (true, true, range_max.clone() * range_max)) + .unwrap_or_else(|| (true, true, range_max * range_max)) }) }); @@ -311,52 +313,72 @@ impl<'ast, T: Field> Folder<'ast, T> for UintOptimizer<'ast, T> { UExpression::mult(left, right).with_max(max) } - Div(box left, box right) => { + Div(e) => { // reduce the two terms - let left = self.fold_uint_expression(left); - let right = self.fold_uint_expression(right); + let left = self.fold_uint_expression(*e.left); + let right = self.fold_uint_expression(*e.right); UExpression::div(force_reduce(left), force_reduce(right)).with_max(range_max) } - Rem(box left, box right) => { + Rem(e) => { // reduce the two terms - let left = self.fold_uint_expression(left); - let right = self.fold_uint_expression(right); + let left = self.fold_uint_expression(*e.left); + let right = self.fold_uint_expression(*e.right); UExpression::rem(force_reduce(left), force_reduce(right)).with_max(range_max) } - Not(box e) => { - let e = self.fold_uint_expression(e); + Not(e) => { + let inner = self.fold_uint_expression(*e.inner); - UExpressionInner::Not(box force_reduce(e)) - .annotate(range) - .with_max(range_max) + UExpression::not(force_reduce(inner)).with_max(range_max) } - LeftShift(box e, by) => { + LeftShift(e) => { // reduce both terms - let e = self.fold_uint_expression(e); - - let e_max: num_bigint::BigUint = e.metadata.as_ref().unwrap().max.to_biguint(); - let max = e_max - .shl(by as usize) - .bitand(&(2_u128.pow(range as u32) - 1).into()); - - let max = T::try_from(max).unwrap(); - - UExpression::left_shift(force_reduce(e), by).with_max(max) + let left = self.fold_uint_expression(*e.left); + let right = self.fold_uint_expression(*e.right); + + match right.into_inner() { + UExpressionInner::Value(by) => { + let e_max: num_bigint::BigUint = + left.metadata.as_ref().unwrap().max.to_biguint(); + let max = e_max + .shl(by.value as usize) + .bitand(&(2_u128.pow(range as u32) - 1).into()); + + let max = T::try_from(max).unwrap(); + + UExpression::left_shift( + force_reduce(left), + UExpression::value(by.value).annotate(UBitwidth::B32), + ) + .with_max(max) + } + _ => unreachable!(), + } } - RightShift(box e, by) => { + RightShift(e) => { // reduce both terms - let e = self.fold_uint_expression(e); - - let e_max: num_bigint::BigUint = e.metadata.as_ref().unwrap().max.to_biguint(); - let max = e_max - .bitand(&(2_u128.pow(range as u32) - 1).into()) - .shr(by as usize); - - let max = T::try_from(max).unwrap(); - - UExpression::right_shift(force_reduce(e), by).with_max(max) + let left = self.fold_uint_expression(*e.left); + let right = self.fold_uint_expression(*e.right); + + match right.into_inner() { + UExpressionInner::Value(by) => { + let e_max: num_bigint::BigUint = + left.metadata.as_ref().unwrap().max.to_biguint(); + let max = e_max + .bitand(&(2_u128.pow(range as u32) - 1).into()) + .shr(by.value as usize); + + let max = T::try_from(max).unwrap(); + + UExpression::right_shift( + force_reduce(left), + UExpression::value(by.value).annotate(UBitwidth::B32), + ) + .with_max(max) + } + _ => unreachable!(), + } } Conditional(e) => { let condition = self.fold_boolean_expression(*e.condition); @@ -379,44 +401,52 @@ impl<'ast, T: Field> Folder<'ast, T> for UintOptimizer<'ast, T> { assert!(res.metadata.is_some()); - res + res.span(span) } - fn fold_statement(&mut self, s: ZirStatement<'ast, T>) -> Vec> { - match s { - ZirStatement::Definition(a, e) => { - let e = self.fold_expression(e); + fn fold_return_statement(&mut self, s: ReturnStatement<'ast, T>) -> Vec> { + // we need to put back in range to return + vec![ZirStatement::ret( + s.inner + .into_iter() + .map(|e| match e { + ZirExpression::Uint(e) => { + let e = self.fold_uint_expression(e); + + let e = force_reduce(e); - let e = match e { - ZirExpression::Uint(i) => { - let i = force_no_reduce(i); - self.register(a.clone(), i.metadata.clone().unwrap()); - ZirExpression::Uint(i) + ZirExpression::Uint(e) } - e => e, - }; - vec![ZirStatement::Definition(a, e)] + e => self.fold_expression(e), + }) + .collect(), + )] + } + + fn fold_definition_statement( + &mut self, + s: DefinitionStatement<'ast, T>, + ) -> Vec> { + let e = self.fold_expression(s.rhs); + + let e = match e { + ZirExpression::Uint(i) => { + let i = force_no_reduce(i); + self.register(s.assignee.clone(), i.metadata.clone().unwrap()); + ZirExpression::Uint(i) } - // we need to put back in range to return - ZirStatement::Return(expressions) => vec![ZirStatement::Return( - expressions - .into_iter() - .map(|e| match e { - ZirExpression::Uint(e) => { - let e = self.fold_uint_expression(e); - - let e = force_reduce(e); - - ZirExpression::Uint(e) - } - e => self.fold_expression(e), - }) - .collect(), - )], - ZirStatement::MultipleDefinition( - lhs, - ZirExpressionList::EmbedCall(embed, generics, arguments), - ) => { + e => e, + }; + vec![ZirStatement::definition(s.assignee, e)] + } + + fn fold_multiple_definition_statement( + &mut self, + s: MultipleDefinitionStatement<'ast, T>, + ) -> Vec> { + let lhs = s.assignees; + match s.rhs { + ZirExpressionList::EmbedCall(embed, generics, arguments) => { match embed { FlatEmbed::U64FromBits => { assert_eq!(lhs.len(), 1); @@ -467,74 +497,68 @@ impl<'ast, T: Field> Folder<'ast, T> for UintOptimizer<'ast, T> { | FlatEmbed::U32ToBits | FlatEmbed::U64ToBits => { vec![ZirStatement::MultipleDefinition( - lhs, - ZirExpressionList::EmbedCall( - embed, - generics, - arguments - .into_iter() - .map(|e| match e { - ZirExpression::Uint(e) => { - let e = self.fold_uint_expression(e); - let e = force_reduce(e); - ZirExpression::Uint(e) - } - e => self.fold_expression(e), - }) - .collect(), + MultipleDefinitionStatement::new( + lhs, + ZirExpressionList::EmbedCall( + embed, + generics, + arguments + .into_iter() + .map(|e| match e { + ZirExpression::Uint(e) => { + let e = self.fold_uint_expression(e); + let e = force_reduce(e); + ZirExpression::Uint(e) + } + e => self.fold_expression(e), + }) + .collect(), + ), ), )] } _ => { vec![ZirStatement::MultipleDefinition( - lhs, - ZirExpressionList::EmbedCall( - embed, - generics, - arguments - .into_iter() - .map(|e| self.fold_expression(e)) - .collect(), + MultipleDefinitionStatement::new( + lhs, + ZirExpressionList::EmbedCall( + embed, + generics, + arguments + .into_iter() + .map(|e| self.fold_expression(e)) + .collect(), + ), ), )] } } } - ZirStatement::Assertion(BooleanExpression::UintEq(box left, box right), metadata) => { - let left = self.fold_uint_expression(left); - let right = self.fold_uint_expression(right); - - // we can only compare two unsigned integers if they are in range - let left = force_reduce(left); - let right = force_reduce(right); - - vec![ZirStatement::Assertion( - BooleanExpression::UintEq(box left, box right), - metadata, - )] - } - ZirStatement::Log(l, e) => vec![ZirStatement::Log( - l, - e.into_iter() - .map(|(t, e)| { - ( - t, - e.into_iter() - .map(|e| match e { - ZirExpression::Uint(e) => { - force_reduce(self.fold_uint_expression(e)).into() - } - e => self.fold_expression(e), - }) - .collect(), - ) - }) - .collect(), - )], - s => fold_statement(self, s), } } + fn fold_log_statement(&mut self, s: LogStatement<'ast, T>) -> Vec> { + vec![ZirStatement::Log(LogStatement::new( + s.format_string, + s.expressions + .into_iter() + .map(|(t, e)| { + ( + t, + e.into_iter() + .map(|e| match e { + ZirExpression::Uint(e) => { + force_reduce(self.fold_uint_expression(e)).into() + } + e => self.fold_expression(e), + }) + .collect(), + ) + }) + .collect(), + ))] + } + fn fold_parameter(&mut self, p: Parameter<'ast>) -> Parameter<'ast> { let id = match p.id.get_type() { Type::Uint(bitwidth) => { @@ -730,8 +754,8 @@ mod tests { assert_eq!( UintOptimizer::new() - .fold_uint_expression(UExpression::right_shift(left.clone(), right)), - UExpression::right_shift(left_expected, right_expected).with_max(output_max) + .fold_uint_expression(UExpression::right_shift(left.clone(), right.into())), + UExpression::right_shift(left_expected, right_expected.into()).with_max(output_max) ); } @@ -753,8 +777,8 @@ mod tests { assert_eq!( UintOptimizer::new() - .fold_uint_expression(UExpression::left_shift(left.clone(), right)), - UExpression::left_shift(left_expected, right_expected).with_max(output_max) + .fold_uint_expression(UExpression::left_shift(left.clone(), right.into())), + UExpression::left_shift(left_expected, right_expected.into()).with_max(output_max) ); } @@ -777,7 +801,7 @@ mod tests { assert_eq!( UintOptimizer::new() .fold_uint_expression(UExpression::conditional( - BooleanExpression::Value(true), + BooleanExpression::value(true), consequence, alternative )) diff --git a/zokrates_analysis/src/variable_write_remover.rs b/zokrates_analysis/src/variable_write_remover.rs index b218acc33..2d9ce8685 100644 --- a/zokrates_analysis/src/variable_write_remover.rs +++ b/zokrates_analysis/src/variable_write_remover.rs @@ -6,6 +6,7 @@ use std::collections::HashSet; use std::fmt; +use zokrates_ast::common::{Span, WithSpan}; use zokrates_ast::typed::result_folder::ResultFolder; use zokrates_ast::typed::result_folder::*; use zokrates_ast::typed::types::{MemberId, Type}; @@ -38,6 +39,7 @@ impl<'ast> VariableWriteRemover { indices: Vec>, new_expression: TypedExpression<'ast, T>, statements: &mut HashSet>, + span: Option, ) -> TypedExpression<'ast, T> { let mut indices = indices; @@ -54,26 +56,37 @@ impl<'ast> VariableWriteRemover { let tail = indices; match head { - Access::Select(box head) => { - statements.insert(TypedStatement::Assertion( - BooleanExpression::UintLt(box head.clone(), box size.into()), + Access::Select(head) => { + statements.insert(TypedStatement::assertion( + BooleanExpression::uint_lt( + head.clone(), + UExpression::from(size).span(span), + ) + .span(span), RuntimeError::SelectRangeCheck, )); - ArrayExpressionInner::Value( + ArrayExpression::value( (0..size) .map(|i| match inner_ty { Type::Int => unreachable!(), Type::Array(..) => ArrayExpression::conditional( - BooleanExpression::UintEq(EqExpression::new( - i.into(), + BooleanExpression::uint_eq( + UExpression::from(i).span(span), head.clone(), - )), + ) + .span(span), match Self::choose_many( - ArrayExpression::select(base.clone(), i).into(), + ArrayExpression::select( + base.clone(), + UExpression::from(i).span(span), + ) + .span(span) + .into(), tail.clone(), new_expression.clone(), statements, + span, ) { TypedExpression::Array(e) => e, e => unreachable!( @@ -81,20 +94,32 @@ impl<'ast> VariableWriteRemover { e.get_type() ), }, - ArrayExpression::select(base.clone(), i), + ArrayExpression::select( + base.clone(), + UExpression::from(i).span(span), + ) + .span(span), ConditionalKind::IfElse, ) .into(), Type::Struct(..) => StructExpression::conditional( - BooleanExpression::UintEq(EqExpression::new( - i.into(), + BooleanExpression::uint_eq( + UExpression::from(i).span(span), head.clone(), - )), + ) + .span(span), match Self::choose_many( - StructExpression::select(base.clone(), i).into(), + StructExpression::select( + base.clone(), + UExpression::from(i).span(span), + ) + .span(span) + .span(span) + .into(), tail.clone(), new_expression.clone(), statements, + span, ) { TypedExpression::Struct(e) => e, e => unreachable!( @@ -102,20 +127,31 @@ impl<'ast> VariableWriteRemover { e.get_type() ), }, - StructExpression::select(base.clone(), i), + StructExpression::select( + base.clone(), + UExpression::from(i).span(span), + ) + .span(span), ConditionalKind::IfElse, ) .into(), Type::Tuple(..) => TupleExpression::conditional( - BooleanExpression::UintEq(EqExpression::new( - i.into(), + BooleanExpression::uint_eq( + UExpression::from(i).span(span), head.clone(), - )), + ) + .span(span), match Self::choose_many( - TupleExpression::select(base.clone(), i).into(), + TupleExpression::select( + base.clone(), + UExpression::from(i).span(span), + ) + .span(span) + .into(), tail.clone(), new_expression.clone(), statements, + span, ) { TypedExpression::Tuple(e) => e, e => unreachable!( @@ -123,21 +159,31 @@ impl<'ast> VariableWriteRemover { e.get_type() ), }, - TupleExpression::select(base.clone(), i), + TupleExpression::select( + base.clone(), + UExpression::from(i).span(span), + ) + .span(span), ConditionalKind::IfElse, ) .into(), Type::FieldElement => FieldElementExpression::conditional( - BooleanExpression::UintEq(EqExpression::new( - i.into(), + BooleanExpression::uint_eq( + UExpression::from(i).span(span), head.clone(), - )), + ) + .span(span), match Self::choose_many( - FieldElementExpression::select(base.clone(), i) - .into(), + FieldElementExpression::select( + base.clone(), + UExpression::from(i).span(span), + ) + .span(span) + .into(), tail.clone(), new_expression.clone(), statements, + span, ) { TypedExpression::FieldElement(e) => e, e => unreachable!( @@ -145,20 +191,31 @@ impl<'ast> VariableWriteRemover { e.get_type() ), }, - FieldElementExpression::select(base.clone(), i), + FieldElementExpression::select( + base.clone(), + UExpression::from(i).span(span), + ) + .span(span), ConditionalKind::IfElse, ) .into(), Type::Boolean => BooleanExpression::conditional( - BooleanExpression::UintEq(EqExpression::new( - i.into(), + BooleanExpression::uint_eq( + UExpression::from(i).span(span), head.clone(), - )), + ) + .span(span), match Self::choose_many( - BooleanExpression::select(base.clone(), i).into(), + BooleanExpression::select( + base.clone(), + UExpression::from(i).span(span), + ) + .span(span) + .into(), tail.clone(), new_expression.clone(), statements, + span, ) { TypedExpression::Boolean(e) => e, e => unreachable!( @@ -166,20 +223,31 @@ impl<'ast> VariableWriteRemover { e.get_type() ), }, - BooleanExpression::select(base.clone(), i), + BooleanExpression::select( + base.clone(), + UExpression::from(i).span(span), + ) + .span(span), ConditionalKind::IfElse, ) .into(), Type::Uint(..) => UExpression::conditional( - BooleanExpression::UintEq(EqExpression::new( - i.into(), + BooleanExpression::uint_eq( + UExpression::from(i).span(span), head.clone(), - )), + ) + .span(span), match Self::choose_many( - UExpression::select(base.clone(), i).into(), + UExpression::select( + base.clone(), + UExpression::from(i).span(span), + ) + .span(span) + .into(), tail.clone(), new_expression.clone(), statements, + span, ) { TypedExpression::Uint(e) => e, e => unreachable!( @@ -187,15 +255,18 @@ impl<'ast> VariableWriteRemover { e.get_type() ), }, - UExpression::select(base.clone(), i), + UExpression::select( + base.clone(), + UExpression::from(i).span(span), + ) + .span(span), ConditionalKind::IfElse, ) .into(), }) - .collect::>() - .into(), + .collect::>(), ) - .annotate(inner_ty.clone(), size) + .annotate(ArrayType::new(inner_ty.clone(), size)) .into() } _ => unreachable!(), @@ -228,6 +299,7 @@ impl<'ast> VariableWriteRemover { tail.clone(), new_expression.clone(), statements, + span, ) } else { FieldElementExpression::member(base.clone(), member.id) @@ -242,9 +314,12 @@ impl<'ast> VariableWriteRemover { tail.clone(), new_expression.clone(), statements, + span, ) } else { - UExpression::member(base.clone(), member.id).into() + UExpression::member(base.clone(), member.id) + .span(span) + .into() } } Type::Boolean => { @@ -258,6 +333,7 @@ impl<'ast> VariableWriteRemover { tail.clone(), new_expression.clone(), statements, + span, ) } else { BooleanExpression::member(base.clone(), member.id) @@ -272,9 +348,12 @@ impl<'ast> VariableWriteRemover { tail.clone(), new_expression.clone(), statements, + span, ) } else { - ArrayExpression::member(base.clone(), member.id).into() + ArrayExpression::member(base.clone(), member.id) + .span(span) + .into() } } Type::Struct(..) => { @@ -288,9 +367,12 @@ impl<'ast> VariableWriteRemover { tail.clone(), new_expression.clone(), statements, + span, ) } else { - StructExpression::member(base.clone(), member.id).into() + StructExpression::member(base.clone(), member.id) + .span(span) + .into() } } Type::Tuple(..) => { @@ -301,9 +383,12 @@ impl<'ast> VariableWriteRemover { tail.clone(), new_expression.clone(), statements, + span, ) } else { - TupleExpression::member(base.clone(), member.id).into() + TupleExpression::member(base.clone(), member.id) + .span(span) + .into() } } }) @@ -341,9 +426,12 @@ impl<'ast> VariableWriteRemover { tail.clone(), new_expression.clone(), statements, + span, ) } else { - FieldElementExpression::element(base.clone(), i).into() + FieldElementExpression::element(base.clone(), i) + .span(span) + .into() } } Type::Uint(..) => { @@ -353,9 +441,10 @@ impl<'ast> VariableWriteRemover { tail.clone(), new_expression.clone(), statements, + span, ) } else { - UExpression::element(base.clone(), i).into() + UExpression::element(base.clone(), i).span(span).into() } } Type::Boolean => { @@ -366,9 +455,12 @@ impl<'ast> VariableWriteRemover { tail.clone(), new_expression.clone(), statements, + span, ) } else { - BooleanExpression::element(base.clone(), i).into() + BooleanExpression::element(base.clone(), i) + .span(span) + .into() } } Type::Array(..) => { @@ -378,9 +470,12 @@ impl<'ast> VariableWriteRemover { tail.clone(), new_expression.clone(), statements, + span, ) } else { - ArrayExpression::element(base.clone(), i).into() + ArrayExpression::element(base.clone(), i) + .span(span) + .into() } } Type::Struct(..) => { @@ -391,9 +486,12 @@ impl<'ast> VariableWriteRemover { tail.clone(), new_expression.clone(), statements, + span, ) } else { - StructExpression::element(base.clone(), i).into() + StructExpression::element(base.clone(), i) + .span(span) + .into() } } Type::Tuple(..) => { @@ -403,9 +501,12 @@ impl<'ast> VariableWriteRemover { tail.clone(), new_expression.clone(), statements, + span, ) } else { - TupleExpression::element(base.clone(), i).into() + TupleExpression::element(base.clone(), i) + .span(span) + .into() } } }) @@ -424,27 +525,28 @@ impl<'ast> VariableWriteRemover { #[derive(Clone, Debug)] enum Access<'ast, T: Field> { - Select(Box>), + Select(UExpression<'ast, T>), Member(MemberId), Element(u32), } + /// Turn an assignee into its representation as a base variable and a list accesses /// a[2][3][4] -> (a, [2, 3, 4]) fn linear(a: TypedAssignee) -> (Variable, Vec>) { match a { TypedAssignee::Identifier(v) => (v, vec![]), - TypedAssignee::Select(box array, box index) => { - let (v, mut indices) = linear(array); - indices.push(Access::Select(box index)); + TypedAssignee::Select(array, 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); + TypedAssignee::Member(s, m) => { + let (v, mut indices) = linear(*s); indices.push(Access::Member(m)); (v, indices) } - TypedAssignee::Element(box s, i) => { - let (v, mut indices) = linear(s); + TypedAssignee::Element(s, i) => { + let (v, mut indices) = linear(*s); indices.push(Access::Element(i)); (v, indices) } @@ -454,51 +556,58 @@ fn linear(a: TypedAssignee) -> (Variable, Vec>) { fn is_constant(assignee: &TypedAssignee) -> bool { match assignee { TypedAssignee::Identifier(_) => true, - TypedAssignee::Select(box assignee, box index) => match index.as_inner() { + TypedAssignee::Select(assignee, index) => match index.as_inner() { UExpressionInner::Value(_) => is_constant(assignee), _ => false, }, - TypedAssignee::Member(box assignee, _) => is_constant(assignee), - TypedAssignee::Element(box assignee, _) => is_constant(assignee), + TypedAssignee::Member(ref assignee, _) => is_constant(assignee), + TypedAssignee::Element(ref assignee, _) => is_constant(assignee), } } impl<'ast, T: Field> ResultFolder<'ast, T> for VariableWriteRemover { type Error = Error; - fn fold_assembly_statement( + fn fold_assembly_assignment( &mut self, - s: TypedAssemblyStatement<'ast, T>, + s: AssemblyAssignment<'ast, T>, ) -> Result>, Self::Error> { - match s { - TypedAssemblyStatement::Assignment(a, e) if is_constant(&a) => { - Ok(vec![TypedAssemblyStatement::Assignment(a, e)]) - } - TypedAssemblyStatement::Assignment(a, _) => Err(Error(format!( + match is_constant(&s.assignee) { + true => Ok(vec![TypedAssemblyStatement::Assignment(s)]), + false => Err(Error(format!( "Cannot assign to an assignee with a variable index `{}`", - a + s.assignee ))), - s => Ok(vec![s]), } } - fn fold_statement( + fn fold_assembly_constraint( + &mut self, + s: AssemblyConstraint<'ast, T>, + ) -> Result>, Self::Error> { + Ok(vec![TypedAssemblyStatement::Constraint(s)]) + } + + fn fold_definition_statement( &mut self, - s: TypedStatement<'ast, T>, + s: DefinitionStatement<'ast, T>, ) -> Result>, Self::Error> { - match s { - TypedStatement::Definition(assignee, DefinitionRhs::Expression(expr)) => { + let span = s.get_span(); + + match s.rhs { + DefinitionRhs::Expression(expr) => { + let a = s.assignee; let expr = self.fold_expression(expr)?; - if is_constant(&assignee) { - Ok(vec![TypedStatement::definition(assignee, expr)]) + if is_constant(&a) { + Ok(vec![TypedStatement::definition(a, expr).span(span)]) } 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 (variable, indices) = linear(assignee); + let (variable, indices) = linear(a); - let base = match variable.get_type() { + let base: TypedExpression<'ast, T> = match variable.get_type() { Type::Int => unreachable!(), Type::FieldElement => { FieldElementExpression::identifier(variable.id.clone()).into() @@ -508,7 +617,7 @@ impl<'ast, T: Field> ResultFolder<'ast, T> for VariableWriteRemover { .annotate(bitwidth) .into(), Type::Array(array_type) => ArrayExpression::identifier(variable.id.clone()) - .annotate(*array_type.ty, *array_type.size) + .annotate(array_type) .into(), Type::Struct(members) => StructExpression::identifier(variable.id.clone()) .annotate(members) @@ -518,31 +627,34 @@ impl<'ast, T: Field> ResultFolder<'ast, T> for VariableWriteRemover { .into(), }; + let base = base.span(span); + let base = self.fold_expression(base)?; let indices = indices .into_iter() .map(|a| match a { - Access::Select(box i) => { - Ok(Access::Select(box self.fold_uint_expression(i)?)) - } + Access::Select(i) => Ok(Access::Select(self.fold_uint_expression(i)?)), a => Ok(a), }) .collect::>()?; let mut range_checks = HashSet::new(); - let e = Self::choose_many(base, indices, expr, &mut range_checks); + let e = Self::choose_many(base, indices, expr, &mut range_checks, span); Ok(range_checks .into_iter() - .chain(std::iter::once(TypedStatement::definition( - TypedAssignee::Identifier(variable), - e, - ))) + .chain(std::iter::once( + TypedStatement::definition( + TypedAssignee::Identifier(variable.span(span)), + e, + ) + .span(span), + )) .collect()) } } - s => fold_statement(self, s), + _ => fold_definition_statement(self, s), } } } diff --git a/zokrates_analysis/src/zir_propagation.rs b/zokrates_analysis/src/zir_propagation.rs index 4a08a7144..a677520c8 100644 --- a/zokrates_analysis/src/zir_propagation.rs +++ b/zokrates_analysis/src/zir_propagation.rs @@ -2,12 +2,15 @@ use num::traits::Pow; use num_bigint::BigUint; use std::collections::HashMap; use std::fmt; -use std::ops::{BitAnd, BitOr, BitXor, Shl, Shr, Sub}; +use std::ops::*; +use zokrates_ast::common::{ResultFold, WithSpan}; use zokrates_ast::zir::types::UBitwidth; +use zokrates_ast::zir::AssertionStatement; +use zokrates_ast::zir::IfElseStatement; use zokrates_ast::zir::{ result_folder::*, Conditional, ConditionalExpression, ConditionalOrExpression, Constant, Expr, Id, IdentifierExpression, IdentifierOrExpression, SelectExpression, SelectOrExpression, - ZirAssemblyStatement, + ZirAssemblyStatement, ZirFunction, }; use zokrates_ast::zir::{ BooleanExpression, FieldElementExpression, Identifier, RuntimeError, UExpression, @@ -57,158 +60,182 @@ impl<'ast, T: Field> ZirPropagator<'ast, T> { impl<'ast, T: Field> ResultFolder<'ast, T> for ZirPropagator<'ast, T> { type Error = Error; - fn fold_assembly_statement( + fn fold_function( &mut self, - s: ZirAssemblyStatement<'ast, T>, + f: ZirFunction<'ast, T>, + ) -> Result, Self::Error> { + let (arguments, inputs) = f + .arguments + .into_iter() + .zip(f.signature.inputs.iter().cloned()) + .filter(|(p, _)| !self.constants.contains_key(&p.id.id)) + .unzip(); + Ok(ZirFunction { + arguments, + statements: f + .statements + .into_iter() + .map(|s| self.fold_statement(s)) + .collect::, _>>()? + .into_iter() + .flatten() + .collect(), + signature: f.signature.inputs(inputs), + }) + } + + fn fold_assembly_assignment( + &mut self, + s: zokrates_ast::zir::AssemblyAssignment<'ast, T>, ) -> Result>, Self::Error> { - match s { - ZirAssemblyStatement::Assignment(assignees, function) => { - let assignees: Vec<_> = assignees - .into_iter() - .map(|a| self.fold_assignee(a)) - .collect::>()?; - - let function = self.fold_function(function)?; - - match &function.statements.last().unwrap() { - ZirStatement::Return(values) => { - if values.iter().all(|v| v.is_constant()) { - self.constants.extend( - assignees - .into_iter() - .zip(values.iter()) - .map(|(a, v)| (a.id, v.clone())), - ); - Ok(vec![]) - } else { - assignees.iter().for_each(|a| { - self.constants.remove(&a.id); - }); - Ok(vec![ZirAssemblyStatement::Assignment(assignees, function)]) - } - } - _ => { - assignees.iter().for_each(|a| { - self.constants.remove(&a.id); - }); - Ok(vec![ZirAssemblyStatement::Assignment(assignees, function)]) - } + let assignees: Vec<_> = s + .assignee + .into_iter() + .map(|a| self.fold_assignee(a)) + .collect::>()?; + + let function = self.fold_function(s.expression)?; + + match &function.statements.last().unwrap() { + ZirStatement::Return(s) => { + if s.inner.iter().all(|v| v.is_constant()) { + self.constants.extend( + assignees + .into_iter() + .zip(s.inner.iter()) + .map(|(a, v)| (a.id, v.clone())), + ); + Ok(vec![]) + } else { + assignees.iter().for_each(|a| { + self.constants.remove(&a.id); + }); + Ok(vec![ZirAssemblyStatement::assignment(assignees, function)]) } } - ZirAssemblyStatement::Constraint(left, right, metadata) => { - let left = self.fold_field_expression(left)?; - let right = self.fold_field_expression(right)?; - - // a bit hacky, but we use a fake boolean expression to check this - let is_equal = BooleanExpression::FieldEq(box left.clone(), box right.clone()); - let is_equal = self.fold_boolean_expression(is_equal)?; - - match is_equal { - BooleanExpression::Value(true) => Ok(vec![]), - BooleanExpression::Value(false) => { - Err(Error::AssertionFailed(RuntimeError::SourceAssertion( - metadata - .message(Some(format!("In asm block: `{} !== {}`", left, right))), - ))) - } - _ => Ok(vec![ZirAssemblyStatement::Constraint( - left, right, metadata, - )]), - } + _ => { + assignees.iter().for_each(|a| { + self.constants.remove(&a.id); + }); + Ok(vec![ZirAssemblyStatement::assignment(assignees, function)]) + } + } + } + + fn fold_assembly_constraint( + &mut self, + s: zokrates_ast::zir::AssemblyConstraint<'ast, T>, + ) -> Result>, Self::Error> { + let left = self.fold_field_expression(s.left)?; + let right = self.fold_field_expression(s.right)?; + + // a bit hacky, but we use a fake boolean expression to check this + let is_equal = BooleanExpression::field_eq(left.clone(), right.clone()); + let is_equal = self.fold_boolean_expression(is_equal)?; + + match is_equal { + BooleanExpression::Value(v) if v.value => Ok(vec![]), + BooleanExpression::Value(v) if !v.value => { + Err(Error::AssertionFailed(RuntimeError::SourceAssertion( + s.metadata + .message(Some(format!("In asm block: `{} !== {}`", left, right))), + ))) } + _ => Ok(vec![ZirAssemblyStatement::constraint( + left, right, s.metadata, + )]), } } - fn fold_statement( + fn fold_assertion_statement( &mut self, - s: ZirStatement<'ast, T>, + s: AssertionStatement<'ast, T>, ) -> Result>, Self::Error> { - match s { - ZirStatement::Assertion(e, error) => match self.fold_boolean_expression(e)? { - BooleanExpression::Value(true) => Ok(vec![]), - BooleanExpression::Value(false) => Err(Error::AssertionFailed(error)), - e => Ok(vec![ZirStatement::Assertion(e, error)]), - }, - ZirStatement::Definition(a, e) => { - let e = self.fold_expression(e)?; - match e { - ZirExpression::FieldElement(FieldElementExpression::Number(..)) - | ZirExpression::Boolean(BooleanExpression::Value(..)) - | ZirExpression::Uint(UExpression { - inner: UExpressionInner::Value(..), - .. - }) => { - self.constants.insert(a.id, e); - Ok(vec![]) - } - _ => { - self.constants.remove(&a.id); - Ok(vec![ZirStatement::Definition(a, e)]) - } - } + match self.fold_boolean_expression(s.expression)? { + BooleanExpression::Value(v) if v.value => Ok(vec![]), + BooleanExpression::Value(v) if !v.value => Err(Error::AssertionFailed(s.error)), + e => Ok(vec![ZirStatement::assertion(e, s.error)]), + } + } + + fn fold_definition_statement( + &mut self, + s: zokrates_ast::zir::DefinitionStatement<'ast, T>, + ) -> Result>, Self::Error> { + let e = self.fold_expression(s.rhs)?; + match e { + ZirExpression::FieldElement(FieldElementExpression::Value(..)) + | ZirExpression::Boolean(BooleanExpression::Value(..)) + | ZirExpression::Uint(UExpression { + inner: UExpressionInner::Value(..), + .. + }) => { + self.constants.insert(s.assignee.id, e); + Ok(vec![]) + } + _ => { + self.constants.remove(&s.assignee.id); + Ok(vec![ZirStatement::definition(s.assignee, e)]) } - ZirStatement::IfElse(e, consequence, alternative) => { - match self.fold_boolean_expression(e)? { - BooleanExpression::Value(true) => Ok(consequence + } + } + + fn fold_if_else_statement( + &mut self, + s: zokrates_ast::zir::IfElseStatement<'ast, T>, + ) -> Result>, Self::Error> { + { + match self.fold_boolean_expression(s.condition)? { + BooleanExpression::Value(v) if v.value => Ok(s + .consequence + .into_iter() + .map(|s| self.fold_statement(s)) + .collect::, _>>()? + .into_iter() + .flatten() + .collect()), + BooleanExpression::Value(v) if !v.value => Ok(s + .alternative + .into_iter() + .map(|s| self.fold_statement(s)) + .collect::, _>>()? + .into_iter() + .flatten() + .collect()), + e => Ok(vec![ZirStatement::IfElse(IfElseStatement::new( + e, + s.consequence .into_iter() .map(|s| self.fold_statement(s)) .collect::, _>>()? .into_iter() .flatten() - .collect()), - BooleanExpression::Value(false) => Ok(alternative + .collect(), + s.alternative .into_iter() .map(|s| self.fold_statement(s)) .collect::, _>>()? .into_iter() .flatten() - .collect()), - e => Ok(vec![ZirStatement::IfElse( - e, - consequence - .into_iter() - .map(|s| self.fold_statement(s)) - .collect::, _>>()? - .into_iter() - .flatten() - .collect(), - alternative - .into_iter() - .map(|s| self.fold_statement(s)) - .collect::, _>>()? - .into_iter() - .flatten() - .collect(), - )]), - } - } - ZirStatement::MultipleDefinition(assignees, list) => { - for a in &assignees { - self.constants.remove(&a.id); - } - Ok(vec![ZirStatement::MultipleDefinition( - assignees, - self.fold_expression_list(list)?, - )]) + .collect(), + ))]), } - ZirStatement::Assembly(statements) => { - let statements: Vec<_> = statements - .into_iter() - .map(|s| self.fold_assembly_statement(s)) - .collect::, _>>()? - .into_iter() - .flatten() - .collect(); - match statements.len() { - 0 => Ok(vec![]), - _ => Ok(vec![ZirStatement::Assembly(statements)]), - } - } - _ => fold_statement(self, s), } } - fn fold_identifier_expression + Id<'ast, T> + ResultFold<'ast, T>>( + fn fold_multiple_definition_statement( + &mut self, + s: zokrates_ast::zir::MultipleDefinitionStatement<'ast, T>, + ) -> Result>, Self::Error> { + for a in &s.assignees { + self.constants.remove(&a.id); + } + fold_multiple_definition_statement(self, s) + } + + fn fold_identifier_expression< + E: Expr<'ast, T> + Id<'ast, T> + ResultFold, + >( &mut self, _: &E::Ty, id: IdentifierExpression<'ast, E>, @@ -219,169 +246,175 @@ impl<'ast, T: Field> ResultFolder<'ast, T> for ZirPropagator<'ast, T> { } } - fn fold_field_expression( + fn fold_field_expression_cases( &mut self, e: FieldElementExpression<'ast, T>, ) -> Result, Self::Error> { match e { - FieldElementExpression::Number(n) => Ok(FieldElementExpression::Number(n)), - FieldElementExpression::Add(box e1, box e2) => { - match ( - self.fold_field_expression(e1)?, - self.fold_field_expression(e2)?, - ) { - (FieldElementExpression::Number(n), e) - | (e, FieldElementExpression::Number(n)) - if n == T::from(0) => + FieldElementExpression::Value(n) => Ok(FieldElementExpression::Value(n)), + FieldElementExpression::Add(e) => { + let left = self.fold_field_expression(*e.left)?; + let right = self.fold_field_expression(*e.right)?; + + Ok(match (left, right) { + (FieldElementExpression::Value(n), e) + | (e, FieldElementExpression::Value(n)) + if n.value == T::from(0) => { - Ok(e) + e } - (FieldElementExpression::Number(n1), FieldElementExpression::Number(n2)) => { - Ok(FieldElementExpression::Number(n1 + n2)) + (FieldElementExpression::Value(n1), FieldElementExpression::Value(n2)) => { + FieldElementExpression::number(n1.value + n2.value) } - (e1, e2) => Ok(FieldElementExpression::Add(box e1, box e2)), + (e1, e2) => FieldElementExpression::add(e1, e2), } + .span(e.span)) } - FieldElementExpression::Sub(box e1, box e2) => { - match ( - self.fold_field_expression(e1)?, - self.fold_field_expression(e2)?, - ) { - (e, FieldElementExpression::Number(n)) if n == T::from(0) => Ok(e), - (FieldElementExpression::Number(n1), FieldElementExpression::Number(n2)) => { - Ok(FieldElementExpression::Number(n1 - n2)) + FieldElementExpression::Sub(e) => { + let left = self.fold_field_expression(*e.left)?; + let right = self.fold_field_expression(*e.right)?; + + Ok(match (left, right) { + (e, FieldElementExpression::Value(n)) if n.value == T::from(0) => e, + (FieldElementExpression::Value(n1), FieldElementExpression::Value(n2)) => { + FieldElementExpression::number(n1.value - n2.value) } - (e1, e2) => Ok(FieldElementExpression::Sub(box e1, box e2)), + (e1, e2) => FieldElementExpression::sub(e1, e2), } + .span(e.span)) } - FieldElementExpression::Mult(box e1, box e2) => { - match ( - self.fold_field_expression(e1)?, - self.fold_field_expression(e2)?, - ) { - (FieldElementExpression::Number(n), _) - | (_, FieldElementExpression::Number(n)) - if n == T::from(0) => + FieldElementExpression::Mult(e) => { + let left = self.fold_field_expression(*e.left)?; + let right = self.fold_field_expression(*e.right)?; + + Ok(match (left, right) { + (FieldElementExpression::Value(n), _) + | (_, FieldElementExpression::Value(n)) + if n.value == T::from(0) => { - Ok(FieldElementExpression::Number(T::from(0))) + FieldElementExpression::number(T::from(0)) } - (FieldElementExpression::Number(n), e) - | (e, FieldElementExpression::Number(n)) - if n == T::from(1) => + (FieldElementExpression::Value(n), e) + | (e, FieldElementExpression::Value(n)) + if n.value == T::from(1) => { - Ok(e) + e } - (FieldElementExpression::Number(n1), FieldElementExpression::Number(n2)) => { - Ok(FieldElementExpression::Number(n1 * n2)) + (FieldElementExpression::Value(n1), FieldElementExpression::Value(n2)) => { + FieldElementExpression::number(n1.value * n2.value) } - (e1, e2) => Ok(FieldElementExpression::Mult(box e1, box e2)), + (e1, e2) => FieldElementExpression::mul(e1, e2), } + .span(e.span)) } - FieldElementExpression::Div(box e1, box e2) => { - match ( - self.fold_field_expression(e1)?, - self.fold_field_expression(e2)?, - ) { - (_, FieldElementExpression::Number(n)) if n == T::from(0) => { + FieldElementExpression::Div(e) => { + let left = self.fold_field_expression(*e.left)?; + let right = self.fold_field_expression(*e.right)?; + + match (left, right) { + (_, FieldElementExpression::Value(n)) if n.value == T::from(0) => { Err(Error::DivisionByZero) } - (e, FieldElementExpression::Number(n)) if n == T::from(1) => Ok(e), - (FieldElementExpression::Number(n1), FieldElementExpression::Number(n2)) => { - Ok(FieldElementExpression::Number(n1 / n2)) + (e, FieldElementExpression::Value(n)) if n.value == T::from(1) => Ok(e), + (FieldElementExpression::Value(n1), FieldElementExpression::Value(n2)) => { + Ok(FieldElementExpression::number(n1.value / n2.value).span(e.span)) } - (e1, e2) => Ok(FieldElementExpression::Div(box e1, box e2)), + (e1, e2) => Ok(FieldElementExpression::div(e1, e2).span(e.span)), } } - FieldElementExpression::Pow(box e, box exponent) => { - let exponent = self.fold_uint_expression(exponent)?; - match (self.fold_field_expression(e)?, exponent.into_inner()) { - (_, UExpressionInner::Value(n2)) if n2 == 0 => { - Ok(FieldElementExpression::Number(T::from(1))) + FieldElementExpression::Pow(e) => { + let exponent = self.fold_uint_expression(*e.right)?; + match (self.fold_field_expression(*e.left)?, exponent.into_inner()) { + (_, UExpressionInner::Value(n2)) if n2.value == 0 => { + Ok(FieldElementExpression::number(T::from(1))) } - (e, UExpressionInner::Value(n2)) if n2 == 1 => Ok(e), - (FieldElementExpression::Number(n), UExpressionInner::Value(e)) => { - Ok(FieldElementExpression::Number(n.pow(e as usize))) + (e, UExpressionInner::Value(n2)) if n2.value == 1 => Ok(e), + (FieldElementExpression::Value(n), UExpressionInner::Value(e)) => Ok( + FieldElementExpression::number(n.value.pow(e.value as usize)), + ), + (e, exp) => { + Ok(FieldElementExpression::pow(e, exp.annotate(UBitwidth::B32)) + .into_inner()) } - (e, exp) => Ok(FieldElementExpression::Pow( - box e, - box exp.annotate(UBitwidth::B32), - )), } } - FieldElementExpression::Xor(box e1, box e2) => { - let e1 = self.fold_field_expression(e1)?; - let e2 = self.fold_field_expression(e2)?; + FieldElementExpression::Xor(e) => { + let e1 = self.fold_field_expression(*e.right)?; + let e2 = self.fold_field_expression(*e.left)?; match (e1, e2) { - (FieldElementExpression::Number(n1), FieldElementExpression::Number(n2)) => { - Ok(FieldElementExpression::Number( - T::try_from(n1.to_biguint().bitxor(n2.to_biguint())).unwrap(), + (FieldElementExpression::Value(n1), FieldElementExpression::Value(n2)) => { + Ok(FieldElementExpression::value( + T::try_from(n1.value.to_biguint().bitxor(n2.value.to_biguint())) + .unwrap(), )) } - (e1, e2) if e1.eq(&e2) => Ok(FieldElementExpression::Number(T::from(0))), - (e1, e2) => Ok(FieldElementExpression::Xor(box e1, box e2)), + (e1, e2) if e1.eq(&e2) => Ok(FieldElementExpression::value(T::from(0))), + (e1, e2) => Ok(FieldElementExpression::bitxor(e1, e2)), } } - FieldElementExpression::And(box e1, box e2) => { - let e1 = self.fold_field_expression(e1)?; - let e2 = self.fold_field_expression(e2)?; + FieldElementExpression::And(e) => { + let e1 = self.fold_field_expression(*e.left)?; + let e2 = self.fold_field_expression(*e.right)?; match (e1, e2) { - (_, FieldElementExpression::Number(n)) - | (FieldElementExpression::Number(n), _) - if n == T::from(0) => + (_, FieldElementExpression::Value(n)) + | (FieldElementExpression::Value(n), _) + if n.value == T::from(0) => { - Ok(FieldElementExpression::Number(n)) + Ok(FieldElementExpression::Value(n)) } - (FieldElementExpression::Number(n1), FieldElementExpression::Number(n2)) => { - Ok(FieldElementExpression::Number( - T::try_from(n1.to_biguint().bitand(n2.to_biguint())).unwrap(), + (FieldElementExpression::Value(n1), FieldElementExpression::Value(n2)) => { + Ok(FieldElementExpression::value( + T::try_from(n1.value.to_biguint().bitand(n2.value.to_biguint())) + .unwrap(), )) } - (e1, e2) => Ok(FieldElementExpression::And(box e1, box e2)), + (e1, e2) => Ok(FieldElementExpression::bitand(e1, e2)), } } - FieldElementExpression::Or(box e1, box e2) => { - let e1 = self.fold_field_expression(e1)?; - let e2 = self.fold_field_expression(e2)?; + FieldElementExpression::Or(e) => { + let e1 = self.fold_field_expression(*e.left)?; + let e2 = self.fold_field_expression(*e.right)?; match (e1, e2) { - (e, FieldElementExpression::Number(n)) - | (FieldElementExpression::Number(n), e) - if n == T::from(0) => + (e, FieldElementExpression::Value(n)) + | (FieldElementExpression::Value(n), e) + if n.value == T::from(0) => { Ok(e) } - (FieldElementExpression::Number(n1), FieldElementExpression::Number(n2)) => { - Ok(FieldElementExpression::Number( - T::try_from(n1.to_biguint().bitor(n2.to_biguint())).unwrap(), + (FieldElementExpression::Value(n1), FieldElementExpression::Value(n2)) => { + Ok(FieldElementExpression::value( + T::try_from(n1.value.to_biguint().bitor(n2.value.to_biguint())) + .unwrap(), )) } - (e1, e2) => Ok(FieldElementExpression::Or(box e1, box e2)), + (e1, e2) => Ok(FieldElementExpression::bitor(e1, e2)), } } - FieldElementExpression::LeftShift(box e, box by) => { - let e = self.fold_field_expression(e)?; - let by = self.fold_uint_expression(by)?; - match (e, by) { + FieldElementExpression::LeftShift(e) => { + let expr = self.fold_field_expression(*e.left)?; + let by = self.fold_uint_expression(*e.right)?; + match (expr, by) { ( e, UExpression { inner: UExpressionInner::Value(by), .. }, - ) if by == 0 => Ok(e), + ) if by.value == 0 => Ok(e), ( _, UExpression { inner: UExpressionInner::Value(by), .. }, - ) if by as usize >= T::get_required_bits() => { - Ok(FieldElementExpression::Number(T::from(0))) + ) if by.value as usize >= T::get_required_bits() => { + Ok(FieldElementExpression::value(T::from(0))) } ( - FieldElementExpression::Number(n), + FieldElementExpression::Value(n), UExpression { inner: UExpressionInner::Value(by), .. @@ -390,197 +423,206 @@ impl<'ast, T: Field> ResultFolder<'ast, T> for ZirPropagator<'ast, T> { let two = BigUint::from(2usize); let mask: BigUint = two.pow(T::get_required_bits()).sub(1usize); - Ok(FieldElementExpression::Number( - T::try_from(n.to_biguint().shl(by as usize).bitand(mask)).unwrap(), + Ok(FieldElementExpression::value( + T::try_from(n.value.to_biguint().shl(by.value as usize).bitand(mask)) + .unwrap(), )) } - (e, by) => Ok(FieldElementExpression::LeftShift(box e, box by)), + (expr, by) => Ok(FieldElementExpression::left_shift(expr, by)), } } - FieldElementExpression::RightShift(box e, box by) => { - let e = self.fold_field_expression(e)?; - let by = self.fold_uint_expression(by)?; - match (e, by) { + FieldElementExpression::RightShift(e) => { + let expr = self.fold_field_expression(*e.left)?; + let by = self.fold_uint_expression(*e.right)?; + match (expr, by) { ( e, UExpression { inner: UExpressionInner::Value(by), .. }, - ) if by == 0 => Ok(e), + ) if by.value == 0 => Ok(e), ( _, UExpression { inner: UExpressionInner::Value(by), .. }, - ) if by as usize >= T::get_required_bits() => { - Ok(FieldElementExpression::Number(T::from(0))) + ) if by.value as usize >= T::get_required_bits() => { + Ok(FieldElementExpression::value(T::from(0))) } ( - FieldElementExpression::Number(n), + FieldElementExpression::Value(n), UExpression { inner: UExpressionInner::Value(by), .. }, - ) => Ok(FieldElementExpression::Number( - T::try_from(n.to_biguint().shr(by as usize)).unwrap(), + ) => Ok(FieldElementExpression::value( + T::try_from(n.value.to_biguint().shr(by.value as usize)).unwrap(), )), - (e, by) => Ok(FieldElementExpression::RightShift(box e, box by)), + (expr, by) => Ok(FieldElementExpression::right_shift(expr, by)), } } - e => fold_field_expression(self, e), + e => fold_field_expression_cases(self, e), } } - fn fold_boolean_expression( + fn fold_boolean_expression_cases( &mut self, e: BooleanExpression<'ast, T>, ) -> Result, Error> { match e { BooleanExpression::Value(v) => Ok(BooleanExpression::Value(v)), - BooleanExpression::FieldLt(box e1, box e2) => { + BooleanExpression::FieldLt(e) => { match ( - self.fold_field_expression(e1)?, - self.fold_field_expression(e2)?, + self.fold_field_expression(*e.left)?, + self.fold_field_expression(*e.right)?, ) { - (FieldElementExpression::Number(n1), FieldElementExpression::Number(n2)) => { - Ok(BooleanExpression::Value(n1 < n2)) + (FieldElementExpression::Value(n1), FieldElementExpression::Value(n2)) => { + Ok(BooleanExpression::value(n1 < n2)) } - (_, FieldElementExpression::Number(c)) if c == T::zero() => { - Ok(BooleanExpression::Value(false)) + (_, FieldElementExpression::Value(c)) if c.value == T::zero() => { + Ok(BooleanExpression::value(false)) } - (FieldElementExpression::Number(c), _) if c == T::max_value() => { - Ok(BooleanExpression::Value(false)) + (FieldElementExpression::Value(c), _) if c.value == T::max_value() => { + Ok(BooleanExpression::value(false)) } - (e1, e2) => Ok(BooleanExpression::FieldLt(box e1, box e2)), + (e1, e2) => Ok(BooleanExpression::field_lt(e1, e2)), } } - BooleanExpression::FieldLe(box e1, box e2) => { + BooleanExpression::FieldLe(e) => { match ( - self.fold_field_expression(e1)?, - self.fold_field_expression(e2)?, + self.fold_field_expression(*e.left)?, + self.fold_field_expression(*e.right)?, ) { - (FieldElementExpression::Number(n1), FieldElementExpression::Number(n2)) => { - Ok(BooleanExpression::Value(n1 <= n2)) + (FieldElementExpression::Value(n1), FieldElementExpression::Value(n2)) => { + Ok(BooleanExpression::value(n1 <= n2)) } - (e1, e2) => Ok(BooleanExpression::FieldLe(box e1, box e2)), + (e1, e2) => Ok(BooleanExpression::field_le(e1, e2)), } } - BooleanExpression::FieldEq(box e1, box e2) => { + BooleanExpression::FieldEq(e) => { match ( - self.fold_field_expression(e1)?, - self.fold_field_expression(e2)?, + self.fold_field_expression(*e.left)?, + self.fold_field_expression(*e.right)?, ) { - (FieldElementExpression::Number(v1), FieldElementExpression::Number(v2)) => { - Ok(BooleanExpression::Value(v1.eq(&v2))) + (FieldElementExpression::Value(v1), FieldElementExpression::Value(v2)) => { + Ok(BooleanExpression::value(v1.eq(&v2))) } (e1, e2) => { if e1.eq(&e2) { - Ok(BooleanExpression::Value(true)) + Ok(BooleanExpression::value(true)) } else { - Ok(BooleanExpression::FieldEq(box e1, box e2)) + Ok(BooleanExpression::field_eq(e1, e2)) } } } } - BooleanExpression::UintLt(box e1, box e2) => { - let e1 = self.fold_uint_expression(e1)?; - let e2 = self.fold_uint_expression(e2)?; + BooleanExpression::UintLt(e) => { + let e1 = self.fold_uint_expression(*e.left)?; + let e2 = self.fold_uint_expression(*e.right)?; match (e1.as_inner(), e2.as_inner()) { (UExpressionInner::Value(v1), UExpressionInner::Value(v2)) => { - Ok(BooleanExpression::Value(v1 < v2)) + Ok(BooleanExpression::value(v1 < v2)) } - _ => Ok(BooleanExpression::UintLt(box e1, box e2)), + _ => Ok(BooleanExpression::uint_lt(e1, e2)), } } - BooleanExpression::UintLe(box e1, box e2) => { - let e1 = self.fold_uint_expression(e1)?; - let e2 = self.fold_uint_expression(e2)?; + BooleanExpression::UintLe(e) => { + let e1 = self.fold_uint_expression(*e.left)?; + let e2 = self.fold_uint_expression(*e.right)?; match (e1.as_inner(), e2.as_inner()) { (UExpressionInner::Value(v1), UExpressionInner::Value(v2)) => { - Ok(BooleanExpression::Value(v1 <= v2)) + Ok(BooleanExpression::value(v1 <= v2)) } - _ => Ok(BooleanExpression::UintLe(box e1, box e2)), + _ => Ok(BooleanExpression::uint_le(e1, e2)), } } - BooleanExpression::UintEq(box e1, box e2) => { - let e1 = self.fold_uint_expression(e1)?; - let e2 = self.fold_uint_expression(e2)?; + BooleanExpression::UintEq(e) => { + let e1 = self.fold_uint_expression(*e.left)?; + let e2 = self.fold_uint_expression(*e.right)?; match (e1.as_inner(), e2.as_inner()) { (UExpressionInner::Value(v1), UExpressionInner::Value(v2)) => { - Ok(BooleanExpression::Value(v1 == v2)) + Ok(BooleanExpression::value(v1 == v2)) } _ => { if e1.eq(&e2) { - Ok(BooleanExpression::Value(true)) + Ok(BooleanExpression::value(true)) } else { - Ok(BooleanExpression::UintEq(box e1, box e2)) + Ok(BooleanExpression::uint_eq(e1, e2)) } } } } - BooleanExpression::BoolEq(box e1, box e2) => { + BooleanExpression::BoolEq(e) => { match ( - self.fold_boolean_expression(e1)?, - self.fold_boolean_expression(e2)?, + self.fold_boolean_expression(*e.left)?, + self.fold_boolean_expression(*e.right)?, ) { (BooleanExpression::Value(v1), BooleanExpression::Value(v2)) => { - Ok(BooleanExpression::Value(v1 == v2)) + Ok(BooleanExpression::value(v1 == v2)) } (e1, e2) => { if e1.eq(&e2) { - Ok(BooleanExpression::Value(true)) + Ok(BooleanExpression::value(true)) } else { - Ok(BooleanExpression::BoolEq(box e1, box e2)) + Ok(BooleanExpression::bool_eq(e1, e2)) } } } } - BooleanExpression::Or(box e1, box e2) => { + BooleanExpression::Or(e) => { match ( - self.fold_boolean_expression(e1)?, - self.fold_boolean_expression(e2)?, + self.fold_boolean_expression(*e.left)?, + self.fold_boolean_expression(*e.right)?, ) { (BooleanExpression::Value(v1), BooleanExpression::Value(v2)) => { - Ok(BooleanExpression::Value(v1 || v2)) + Ok(BooleanExpression::value(v1.value || v2.value)) } - (_, BooleanExpression::Value(true)) | (BooleanExpression::Value(true), _) => { - Ok(BooleanExpression::Value(true)) + (_, BooleanExpression::Value(v)) | (BooleanExpression::Value(v), _) + if v.value => + { + Ok(BooleanExpression::value(true)) } - (e, BooleanExpression::Value(false)) | (BooleanExpression::Value(false), e) => { + (e, BooleanExpression::Value(v)) | (BooleanExpression::Value(v), e) + if !v.value => + { Ok(e) } - (e1, e2) => Ok(BooleanExpression::Or(box e1, box e2)), + (e1, e2) => Ok(BooleanExpression::bitor(e1, e2)), } } - BooleanExpression::And(box e1, box e2) => { + BooleanExpression::And(e) => { match ( - self.fold_boolean_expression(e1)?, - self.fold_boolean_expression(e2)?, + self.fold_boolean_expression(*e.left)?, + self.fold_boolean_expression(*e.right)?, ) { - (BooleanExpression::Value(true), e) | (e, BooleanExpression::Value(true)) => { + (BooleanExpression::Value(v), e) | (e, BooleanExpression::Value(v)) + if v.value => + { Ok(e) } - (BooleanExpression::Value(false), _) | (_, BooleanExpression::Value(false)) => { - Ok(BooleanExpression::Value(false)) + (BooleanExpression::Value(v), _) | (_, BooleanExpression::Value(v)) + if !v.value => + { + Ok(BooleanExpression::value(false)) } - (e1, e2) => Ok(BooleanExpression::And(box e1, box e2)), + (e1, e2) => Ok(BooleanExpression::bitand(e1, e2)), } } - BooleanExpression::Not(box e) => match self.fold_boolean_expression(e)? { - BooleanExpression::Value(v) => Ok(BooleanExpression::Value(!v)), - e => Ok(BooleanExpression::Not(box e)), + BooleanExpression::Not(e) => match self.fold_boolean_expression(*e.inner)? { + BooleanExpression::Value(v) => Ok(BooleanExpression::value(!v.value)), + e => Ok(BooleanExpression::not(e)), }, - e => fold_boolean_expression(self, e), + e => fold_boolean_expression_cases(self, e), } } fn fold_select_expression< - E: Clone + Expr<'ast, T> + ResultFold<'ast, T> + zokrates_ast::zir::Select<'ast, T>, + E: Clone + Expr<'ast, T> + ResultFold + zokrates_ast::zir::Select<'ast, T>, >( &mut self, _: &E::Ty, @@ -595,9 +637,9 @@ impl<'ast, T: Field> ResultFolder<'ast, T> for ZirPropagator<'ast, T> { match index.as_inner() { UExpressionInner::Value(v) => array - .get(*v as usize) + .get(v.value as usize) .cloned() - .ok_or(Error::OutOfBounds(*v as usize, array.len())) + .ok_or(Error::OutOfBounds(v.value as usize, array.len())) .map(|e| SelectOrExpression::Expression(e.into_inner())), _ => Ok(SelectOrExpression::Expression( E::select(array, index).into_inner(), @@ -605,185 +647,221 @@ impl<'ast, T: Field> ResultFolder<'ast, T> for ZirPropagator<'ast, T> { } } - fn fold_uint_expression_inner( + fn fold_uint_expression_cases( &mut self, bitwidth: UBitwidth, e: UExpressionInner<'ast, T>, ) -> Result, Self::Error> { match e { UExpressionInner::Value(v) => Ok(UExpressionInner::Value(v)), - UExpressionInner::Add(box e1, box e2) => { - let e1 = self.fold_uint_expression(e1)?; - let e2 = self.fold_uint_expression(e2)?; + UExpressionInner::Add(e) => { + let e1 = self.fold_uint_expression(*e.left)?; + let e2 = self.fold_uint_expression(*e.right)?; match (e1.into_inner(), e2.into_inner()) { - (UExpressionInner::Value(0), e) | (e, UExpressionInner::Value(0)) => Ok(e), - (UExpressionInner::Value(n1), UExpressionInner::Value(n2)) => Ok( - UExpressionInner::Value((n1 + n2) % 2_u128.pow(bitwidth.to_usize() as u32)), + (UExpressionInner::Value(v), e) | (e, UExpressionInner::Value(v)) + if v.value == 0 => + { + Ok(e) + } + (UExpressionInner::Value(n1), UExpressionInner::Value(n2)) => { + Ok(UExpression::value( + (n1.value + n2.value) % 2_u128.pow(bitwidth.to_usize() as u32), + )) + } + (e1, e2) => Ok( + UExpression::add(e1.annotate(bitwidth), e2.annotate(bitwidth)).into_inner(), ), - (e1, e2) => Ok(UExpressionInner::Add( - box e1.annotate(bitwidth), - box e2.annotate(bitwidth), - )), } } - UExpressionInner::Sub(box e1, box e2) => { - let e1 = self.fold_uint_expression(e1)?; - let e2 = self.fold_uint_expression(e2)?; + UExpressionInner::Sub(e) => { + let e1 = self.fold_uint_expression(*e.left)?; + let e2 = self.fold_uint_expression(*e.right)?; match (e1.into_inner(), e2.into_inner()) { - (e, UExpressionInner::Value(0)) => Ok(e), + (e, UExpressionInner::Value(v)) if v.value == 0 => Ok(e), (UExpressionInner::Value(n1), UExpressionInner::Value(n2)) => { - Ok(UExpressionInner::Value( - n1.wrapping_sub(n2) % 2_u128.pow(bitwidth.to_usize() as u32), + Ok(UExpression::value( + n1.value.wrapping_sub(n2.value) + % 2_u128.pow(bitwidth.to_usize() as u32), )) } - (e1, e2) => Ok(UExpressionInner::Sub( - box e1.annotate(bitwidth), - box e2.annotate(bitwidth), - )), + (e1, e2) => Ok( + UExpression::sub(e1.annotate(bitwidth), e2.annotate(bitwidth)).into_inner(), + ), } } - UExpressionInner::Mult(box e1, box e2) => { - let e1 = self.fold_uint_expression(e1)?; - let e2 = self.fold_uint_expression(e2)?; + UExpressionInner::Mult(e) => { + let e1 = self.fold_uint_expression(*e.left)?; + let e2 = self.fold_uint_expression(*e.right)?; match (e1.into_inner(), e2.into_inner()) { - (_, UExpressionInner::Value(0)) | (UExpressionInner::Value(0), _) => { - Ok(UExpressionInner::Value(0)) + (_, UExpressionInner::Value(v)) | (UExpressionInner::Value(v), _) + if v.value == 0 => + { + Ok(UExpression::value(0)) + } + (e, UExpressionInner::Value(v)) | (UExpressionInner::Value(v), e) + if v.value == 1 => + { + Ok(e) + } + (UExpressionInner::Value(n1), UExpressionInner::Value(n2)) => { + Ok(UExpression::value( + (n1.value * n2.value) % 2_u128.pow(bitwidth.to_usize() as u32), + )) } - (e, UExpressionInner::Value(1)) | (UExpressionInner::Value(1), e) => Ok(e), - (UExpressionInner::Value(n1), UExpressionInner::Value(n2)) => Ok( - UExpressionInner::Value((n1 * n2) % 2_u128.pow(bitwidth.to_usize() as u32)), + (e1, e2) => Ok( + UExpression::mult(e1.annotate(bitwidth), e2.annotate(bitwidth)) + .into_inner(), ), - (e1, e2) => Ok(UExpressionInner::Mult( - box e1.annotate(bitwidth), - box e2.annotate(bitwidth), - )), } } - UExpressionInner::Div(box e1, box e2) => { - let e1 = self.fold_uint_expression(e1)?; - let e2 = self.fold_uint_expression(e2)?; + UExpressionInner::Div(e) => { + let e1 = self.fold_uint_expression(*e.left)?; + let e2 = self.fold_uint_expression(*e.right)?; match (e1.into_inner(), e2.into_inner()) { - (_, UExpressionInner::Value(n)) if n == 0 => Err(Error::DivisionByZero), - (e, UExpressionInner::Value(n)) if n == 1 => Ok(e), - (UExpressionInner::Value(n1), UExpressionInner::Value(n2)) => Ok( - UExpressionInner::Value((n1 / n2) % 2_u128.pow(bitwidth.to_usize() as u32)), + (_, UExpressionInner::Value(n)) if n.value == 0 => Err(Error::DivisionByZero), + (e, UExpressionInner::Value(n)) if n.value == 1 => Ok(e), + (UExpressionInner::Value(n1), UExpressionInner::Value(n2)) => { + Ok(UExpression::value( + (n1.value / n2.value) % 2_u128.pow(bitwidth.to_usize() as u32), + )) + } + (e1, e2) => Ok( + UExpression::div(e1.annotate(bitwidth), e2.annotate(bitwidth)).into_inner(), ), - (e1, e2) => Ok(UExpressionInner::Div( - box e1.annotate(bitwidth), - box e2.annotate(bitwidth), - )), } } - UExpressionInner::Rem(box e1, box e2) => { - let e1 = self.fold_uint_expression(e1)?; - let e2 = self.fold_uint_expression(e2)?; + UExpressionInner::Rem(e) => { + let e1 = self.fold_uint_expression(*e.left)?; + let e2 = self.fold_uint_expression(*e.right)?; match (e1.into_inner(), e2.into_inner()) { - (UExpressionInner::Value(n1), UExpressionInner::Value(n2)) => Ok( - UExpressionInner::Value((n1 % n2) % 2_u128.pow(bitwidth.to_usize() as u32)), + (UExpressionInner::Value(n1), UExpressionInner::Value(n2)) => { + Ok(UExpression::value( + (n1.value % n2.value) % 2_u128.pow(bitwidth.to_usize() as u32), + )) + } + (e1, e2) => Ok( + UExpression::rem(e1.annotate(bitwidth), e2.annotate(bitwidth)).into_inner(), ), - (e1, e2) => Ok(UExpressionInner::Rem( - box e1.annotate(bitwidth), - box e2.annotate(bitwidth), - )), } } - UExpressionInner::Xor(box e1, box e2) => { - let e1 = self.fold_uint_expression(e1)?; - let e2 = self.fold_uint_expression(e2)?; + UExpressionInner::Xor(e) => { + let e1 = self.fold_uint_expression(*e.left)?; + let e2 = self.fold_uint_expression(*e.right)?; match (e1.into_inner(), e2.into_inner()) { (UExpressionInner::Value(n1), UExpressionInner::Value(n2)) => { - Ok(UExpressionInner::Value(n1 ^ n2)) + Ok(UExpression::value(n1.value ^ n2.value)) } - (e1, e2) if e1.eq(&e2) => Ok(UExpressionInner::Value(0)), - (e1, e2) => Ok(UExpressionInner::Xor( - box e1.annotate(bitwidth), - box e2.annotate(bitwidth), - )), + (e1, e2) if e1.eq(&e2) => Ok(UExpression::value(0)), + (e1, e2) => Ok( + UExpression::xor(e1.annotate(bitwidth), e2.annotate(bitwidth)).into_inner(), + ), } } - UExpressionInner::And(box e1, box e2) => { - let e1 = self.fold_uint_expression(e1)?; - let e2 = self.fold_uint_expression(e2)?; + UExpressionInner::And(e) => { + let e1 = self.fold_uint_expression(*e.left)?; + let e2 = self.fold_uint_expression(*e.right)?; match (e1.into_inner(), e2.into_inner()) { (e, UExpressionInner::Value(n)) | (UExpressionInner::Value(n), e) - if n == 2_u128.pow(bitwidth.to_usize() as u32) - 1 => + if n.value == 2_u128.pow(bitwidth.to_usize() as u32) - 1 => { Ok(e) } - (_, UExpressionInner::Value(0)) | (UExpressionInner::Value(0), _) => { - Ok(UExpressionInner::Value(0)) + (_, UExpressionInner::Value(v)) | (UExpressionInner::Value(v), _) + if v.value == 0 => + { + Ok(UExpression::value(0)) } (UExpressionInner::Value(n1), UExpressionInner::Value(n2)) => { - Ok(UExpressionInner::Value(n1 & n2)) + Ok(UExpression::value(n1.value & n2.value)) } - (e1, e2) => Ok(UExpressionInner::And( - box e1.annotate(bitwidth), - box e2.annotate(bitwidth), - )), + (e1, e2) => Ok( + UExpression::and(e1.annotate(bitwidth), e2.annotate(bitwidth)).into_inner(), + ), } } - UExpressionInner::Or(box e1, box e2) => { - let e1 = self.fold_uint_expression(e1)?; - let e2 = self.fold_uint_expression(e2)?; + UExpressionInner::Or(e) => { + let e1 = self.fold_uint_expression(*e.left)?; + let e2 = self.fold_uint_expression(*e.right)?; match (e1.into_inner(), e2.into_inner()) { - (e, UExpressionInner::Value(0)) | (UExpressionInner::Value(0), e) => Ok(e), + (e, UExpressionInner::Value(v)) | (UExpressionInner::Value(v), e) + if v.value == 0 => + { + Ok(e) + } (_, UExpressionInner::Value(n)) | (UExpressionInner::Value(n), _) - if n == 2_u128.pow(bitwidth.to_usize() as u32) - 1 => + if n.value == 2_u128.pow(bitwidth.to_usize() as u32) - 1 => { - Ok(UExpressionInner::Value(n)) + Ok(UExpression::value(n.value)) } (UExpressionInner::Value(n1), UExpressionInner::Value(n2)) => { - Ok(UExpressionInner::Value(n1 | n2)) + Ok(UExpression::value(n1.value | n2.value)) } - (e1, e2) => Ok(UExpressionInner::Or( - box e1.annotate(bitwidth), - box e2.annotate(bitwidth), - )), + (e1, e2) => Ok( + UExpression::or(e1.annotate(bitwidth), e2.annotate(bitwidth)).into_inner(), + ), } } - UExpressionInner::LeftShift(box e, by) => { - let e = self.fold_uint_expression(e)?; - match (e.into_inner(), by) { - (e, 0) => Ok(e), - (_, by) if by >= bitwidth as u32 => Ok(UExpressionInner::Value(0)), - (UExpressionInner::Value(n), by) => Ok(UExpressionInner::Value( - (n << by) & (2_u128.pow(bitwidth as u32) - 1), - )), - (e, by) => Ok(UExpressionInner::LeftShift(box e.annotate(bitwidth), by)), + UExpressionInner::LeftShift(e) => { + let left = self.fold_uint_expression(*e.left)?; + let right = self.fold_uint_expression(*e.right)?; + match (left.into_inner(), right.into_inner()) { + (e, UExpressionInner::Value(by)) if by.value == 0 => Ok(e), + (_, UExpressionInner::Value(by)) if by.value as u32 >= bitwidth as u32 => { + Ok(UExpression::value(0)) + } + (UExpressionInner::Value(n), UExpressionInner::Value(by)) => { + Ok(UExpression::value( + (n.value << by.value) & (2_u128.pow(bitwidth as u32) - 1), + )) + } + (e, by) => Ok(UExpression::left_shift( + e.annotate(bitwidth), + by.annotate(UBitwidth::B32), + ) + .into_inner()), } } - UExpressionInner::RightShift(box e, by) => { - let e = self.fold_uint_expression(e)?; - match (e.into_inner(), by) { - (e, 0) => Ok(e), - (_, by) if by >= bitwidth as u32 => Ok(UExpressionInner::Value(0)), - (UExpressionInner::Value(n), by) => Ok(UExpressionInner::Value(n >> by)), - (e, by) => Ok(UExpressionInner::RightShift(box e.annotate(bitwidth), by)), + UExpressionInner::RightShift(e) => { + let left = self.fold_uint_expression(*e.left)?; + let right = self.fold_uint_expression(*e.right)?; + match (left.into_inner(), right.into_inner()) { + (e, UExpressionInner::Value(by)) if by.value == 0 => Ok(e), + (_, UExpressionInner::Value(by)) if by.value as u32 >= bitwidth as u32 => { + Ok(UExpression::value(0)) + } + (UExpressionInner::Value(n), UExpressionInner::Value(by)) => { + Ok(UExpression::value(n.value >> by.value)) + } + (e, by) => Ok(UExpression::right_shift( + e.annotate(bitwidth), + by.annotate(UBitwidth::B32), + ) + .into_inner()), } } - UExpressionInner::Not(box e) => { - let e = self.fold_uint_expression(e)?; + UExpressionInner::Not(e) => { + let e = self.fold_uint_expression(*e.inner)?; match e.into_inner() { - UExpressionInner::Value(n) => Ok(UExpressionInner::Value( - !n & (2_u128.pow(bitwidth as u32) - 1), + UExpressionInner::Value(n) => Ok(UExpression::value( + !n.value & (2_u128.pow(bitwidth as u32) - 1), )), - e => Ok(UExpressionInner::Not(box e.annotate(bitwidth))), + e => Ok(UExpression::not(e.annotate(bitwidth)).into_inner()), } } - e => fold_uint_expression_inner(self, bitwidth, e), + e => fold_uint_expression_cases(self, bitwidth, e), } } fn fold_conditional_expression< - E: Expr<'ast, T> + ResultFold<'ast, T> + Conditional<'ast, T>, + E: Expr<'ast, T> + ResultFold + Conditional<'ast, T>, >( &mut self, _: &E::Ty, @@ -792,10 +870,10 @@ impl<'ast, T: Field> ResultFolder<'ast, T> for ZirPropagator<'ast, T> { let condition = self.fold_boolean_expression(*e.condition)?; match condition { - BooleanExpression::Value(true) => Ok(ConditionalOrExpression::Expression( + BooleanExpression::Value(v) if v.value => Ok(ConditionalOrExpression::Expression( e.consequence.fold(self)?.into_inner(), )), - BooleanExpression::Value(false) => Ok(ConditionalOrExpression::Expression( + BooleanExpression::Value(v) if !v.value => Ok(ConditionalOrExpression::Expression( e.alternative.fold(self)?.into_inner(), )), condition => { @@ -825,15 +903,15 @@ mod tests { #[test] fn propagation() { // assert([x, 1] == [y, 1]) - let statements = vec![ZirStatement::Assertion( - BooleanExpression::And( - box BooleanExpression::FieldEq( - box FieldElementExpression::identifier("x".into()), - box FieldElementExpression::identifier("y".into()), + let statements = vec![ZirStatement::assertion( + BooleanExpression::bitand( + BooleanExpression::field_eq( + FieldElementExpression::identifier("x".into()), + FieldElementExpression::identifier("y".into()), ), - box BooleanExpression::FieldEq( - box FieldElementExpression::Number(Bn128Field::from(1)), - box FieldElementExpression::Number(Bn128Field::from(1)), + BooleanExpression::field_eq( + FieldElementExpression::value(Bn128Field::from(1)), + FieldElementExpression::value(Bn128Field::from(1)), ), ), RuntimeError::mock(), @@ -851,10 +929,10 @@ mod tests { assert_eq!( statements, - vec![ZirStatement::Assertion( - BooleanExpression::FieldEq( - box FieldElementExpression::identifier("x".into()), - box FieldElementExpression::identifier("y".into()), + vec![ZirStatement::assertion( + BooleanExpression::field_eq( + FieldElementExpression::identifier("x".into()), + FieldElementExpression::identifier("y".into()), ), RuntimeError::mock() )] @@ -875,21 +953,21 @@ mod tests { assert_eq!( propagator.fold_field_expression(FieldElementExpression::select( vec![ - FieldElementExpression::Number(Bn128Field::from(1)), - FieldElementExpression::Number(Bn128Field::from(2)), + FieldElementExpression::value(Bn128Field::from(1)), + FieldElementExpression::value(Bn128Field::from(2)), ], - UExpressionInner::Value(1).annotate(UBitwidth::B32), + UExpression::value(1).annotate(UBitwidth::B32), )), - Ok(FieldElementExpression::Number(Bn128Field::from(2))) + Ok(FieldElementExpression::value(Bn128Field::from(2))) ); assert_eq!( propagator.fold_field_expression(FieldElementExpression::select( vec![ - FieldElementExpression::Number(Bn128Field::from(1)), - FieldElementExpression::Number(Bn128Field::from(2)), + FieldElementExpression::value(Bn128Field::from(1)), + FieldElementExpression::value(Bn128Field::from(2)), ], - UExpressionInner::Value(3).annotate(UBitwidth::B32), + UExpression::value(3).annotate(UBitwidth::B32), )), Err(Error::OutOfBounds(3, 2)) ); @@ -900,18 +978,18 @@ mod tests { let mut propagator = ZirPropagator::default(); assert_eq!( - propagator.fold_field_expression(FieldElementExpression::Add( - box FieldElementExpression::Number(Bn128Field::from(2)), - box FieldElementExpression::Number(Bn128Field::from(3)), + propagator.fold_field_expression(FieldElementExpression::add( + FieldElementExpression::value(Bn128Field::from(2)), + FieldElementExpression::value(Bn128Field::from(3)), )), - Ok(FieldElementExpression::Number(Bn128Field::from(5))) + Ok(FieldElementExpression::value(Bn128Field::from(5))) ); // a + 0 = a assert_eq!( - propagator.fold_field_expression(FieldElementExpression::Add( - box FieldElementExpression::identifier("a".into()), - box FieldElementExpression::Number(Bn128Field::from(0)), + propagator.fold_field_expression(FieldElementExpression::add( + FieldElementExpression::identifier("a".into()), + FieldElementExpression::value(Bn128Field::from(0)), )), Ok(FieldElementExpression::identifier("a".into())) ); @@ -922,18 +1000,18 @@ mod tests { let mut propagator = ZirPropagator::default(); assert_eq!( - propagator.fold_field_expression(FieldElementExpression::Sub( - box FieldElementExpression::Number(Bn128Field::from(3)), - box FieldElementExpression::Number(Bn128Field::from(2)), + propagator.fold_field_expression(FieldElementExpression::sub( + FieldElementExpression::value(Bn128Field::from(3)), + FieldElementExpression::value(Bn128Field::from(2)), )), - Ok(FieldElementExpression::Number(Bn128Field::from(1))) + Ok(FieldElementExpression::value(Bn128Field::from(1))) ); // a - 0 = a assert_eq!( - propagator.fold_field_expression(FieldElementExpression::Sub( - box FieldElementExpression::identifier("a".into()), - box FieldElementExpression::Number(Bn128Field::from(0)), + propagator.fold_field_expression(FieldElementExpression::sub( + FieldElementExpression::identifier("a".into()), + FieldElementExpression::value(Bn128Field::from(0)), )), Ok(FieldElementExpression::identifier("a".into())) ); @@ -944,27 +1022,27 @@ mod tests { let mut propagator = ZirPropagator::default(); assert_eq!( - propagator.fold_field_expression(FieldElementExpression::Mult( - box FieldElementExpression::Number(Bn128Field::from(3)), - box FieldElementExpression::Number(Bn128Field::from(2)), + propagator.fold_field_expression(FieldElementExpression::mul( + FieldElementExpression::value(Bn128Field::from(3)), + FieldElementExpression::value(Bn128Field::from(2)), )), - Ok(FieldElementExpression::Number(Bn128Field::from(6))) + Ok(FieldElementExpression::value(Bn128Field::from(6))) ); // a * 0 = 0 assert_eq!( - propagator.fold_field_expression(FieldElementExpression::Mult( - box FieldElementExpression::identifier("a".into()), - box FieldElementExpression::Number(Bn128Field::from(0)), + propagator.fold_field_expression(FieldElementExpression::mul( + FieldElementExpression::identifier("a".into()), + FieldElementExpression::value(Bn128Field::from(0)), )), - Ok(FieldElementExpression::Number(Bn128Field::from(0))) + Ok(FieldElementExpression::value(Bn128Field::from(0))) ); // a * 1 = a assert_eq!( - propagator.fold_field_expression(FieldElementExpression::Mult( - box FieldElementExpression::identifier("a".into()), - box FieldElementExpression::Number(Bn128Field::from(1)), + propagator.fold_field_expression(FieldElementExpression::mul( + FieldElementExpression::identifier("a".into()), + FieldElementExpression::value(Bn128Field::from(1)), )), Ok(FieldElementExpression::identifier("a".into())) ); @@ -975,25 +1053,25 @@ mod tests { let mut propagator = ZirPropagator::default(); assert_eq!( - propagator.fold_field_expression(FieldElementExpression::Div( - box FieldElementExpression::Number(Bn128Field::from(6)), - box FieldElementExpression::Number(Bn128Field::from(2)), + propagator.fold_field_expression(FieldElementExpression::div( + FieldElementExpression::value(Bn128Field::from(6)), + FieldElementExpression::value(Bn128Field::from(2)), )), - Ok(FieldElementExpression::Number(Bn128Field::from(3))) + Ok(FieldElementExpression::value(Bn128Field::from(3))) ); assert_eq!( - propagator.fold_field_expression(FieldElementExpression::Div( - box FieldElementExpression::identifier("a".into()), - box FieldElementExpression::Number(Bn128Field::from(1)), + propagator.fold_field_expression(FieldElementExpression::div( + FieldElementExpression::identifier("a".into()), + FieldElementExpression::value(Bn128Field::from(1)), )), Ok(FieldElementExpression::identifier("a".into())) ); assert_eq!( - propagator.fold_field_expression(FieldElementExpression::Div( - box FieldElementExpression::identifier("a".into()), - box FieldElementExpression::Number(Bn128Field::from(0)), + propagator.fold_field_expression(FieldElementExpression::div( + FieldElementExpression::identifier("a".into()), + FieldElementExpression::value(Bn128Field::from(0)), )), Err(Error::DivisionByZero) ); @@ -1004,27 +1082,27 @@ mod tests { let mut propagator = ZirPropagator::::default(); assert_eq!( - propagator.fold_field_expression(FieldElementExpression::Pow( - box FieldElementExpression::Number(Bn128Field::from(3)), - box UExpressionInner::Value(2).annotate(UBitwidth::B32), + propagator.fold_field_expression(FieldElementExpression::pow( + FieldElementExpression::value(Bn128Field::from(3)), + UExpression::value(2).annotate(UBitwidth::B32), )), - Ok(FieldElementExpression::Number(Bn128Field::from(9))) + Ok(FieldElementExpression::value(Bn128Field::from(9))) ); // a ** 0 = 1 assert_eq!( - propagator.fold_field_expression(FieldElementExpression::Pow( - box FieldElementExpression::identifier("a".into()), - box UExpressionInner::Value(0).annotate(UBitwidth::B32), + propagator.fold_field_expression(FieldElementExpression::pow( + FieldElementExpression::identifier("a".into()), + UExpression::value(0).annotate(UBitwidth::B32), )), - Ok(FieldElementExpression::Number(Bn128Field::from(1))) + Ok(FieldElementExpression::value(Bn128Field::from(1))) ); // a ** 1 = a assert_eq!( - propagator.fold_field_expression(FieldElementExpression::Pow( - box FieldElementExpression::identifier("a".into()), - box UExpressionInner::Value(1).annotate(UBitwidth::B32), + propagator.fold_field_expression(FieldElementExpression::pow( + FieldElementExpression::identifier("a".into()), + UExpression::value(1).annotate(UBitwidth::B32), )), Ok(FieldElementExpression::identifier("a".into())) ); @@ -1035,44 +1113,44 @@ mod tests { let mut propagator = ZirPropagator::::default(); assert_eq!( - propagator.fold_field_expression(FieldElementExpression::LeftShift( - box FieldElementExpression::identifier("a".into()), - box UExpressionInner::Value(0).annotate(UBitwidth::B32), + propagator.fold_field_expression(FieldElementExpression::left_shift( + FieldElementExpression::identifier("a".into()), + UExpression::value(0).annotate(UBitwidth::B32), )), Ok(FieldElementExpression::identifier("a".into())) ); assert_eq!( - propagator.fold_field_expression(FieldElementExpression::LeftShift( - box FieldElementExpression::Number(Bn128Field::from(2)), - box UExpressionInner::Value(2 as u128).annotate(UBitwidth::B32), + propagator.fold_field_expression(FieldElementExpression::left_shift( + FieldElementExpression::value(Bn128Field::from(2)), + UExpression::value(2_u128).annotate(UBitwidth::B32), )), - Ok(FieldElementExpression::Number(Bn128Field::from(8))) + Ok(FieldElementExpression::value(Bn128Field::from(8))) ); assert_eq!( - propagator.fold_field_expression(FieldElementExpression::LeftShift( - box FieldElementExpression::Number(Bn128Field::from(1)), - box UExpressionInner::Value((Bn128Field::get_required_bits() - 1) as u128).annotate(UBitwidth::B32), + propagator.fold_field_expression(FieldElementExpression::left_shift( + FieldElementExpression::value(Bn128Field::from(1)), + UExpression::value((Bn128Field::get_required_bits() - 1) as u128).annotate(UBitwidth::B32), )), - Ok(FieldElementExpression::Number(Bn128Field::try_from_dec_str("14474011154664524427946373126085988481658748083205070504932198000989141204992").unwrap())) + Ok(FieldElementExpression::value(Bn128Field::try_from_dec_str("14474011154664524427946373126085988481658748083205070504932198000989141204992").unwrap())) ); assert_eq!( - propagator.fold_field_expression(FieldElementExpression::LeftShift( - box FieldElementExpression::Number(Bn128Field::from(3)), - box UExpressionInner::Value((Bn128Field::get_required_bits() - 3) as u128).annotate(UBitwidth::B32), + propagator.fold_field_expression(FieldElementExpression::left_shift( + FieldElementExpression::value(Bn128Field::from(3)), + UExpression::value((Bn128Field::get_required_bits() - 3) as u128).annotate(UBitwidth::B32), )), - Ok(FieldElementExpression::Number(Bn128Field::try_from_dec_str("10855508365998393320959779844564491361244061062403802878699148500741855903744").unwrap())) + Ok(FieldElementExpression::value(Bn128Field::try_from_dec_str("10855508365998393320959779844564491361244061062403802878699148500741855903744").unwrap())) ); assert_eq!( - propagator.fold_field_expression(FieldElementExpression::LeftShift( - box FieldElementExpression::Number(Bn128Field::from(1)), - box UExpressionInner::Value((Bn128Field::get_required_bits()) as u128) + propagator.fold_field_expression(FieldElementExpression::left_shift( + FieldElementExpression::value(Bn128Field::from(1)), + UExpression::value((Bn128Field::get_required_bits()) as u128) .annotate(UBitwidth::B32), )), - Ok(FieldElementExpression::Number(Bn128Field::from(0))) + Ok(FieldElementExpression::value(Bn128Field::from(0))) ); } @@ -1081,61 +1159,61 @@ mod tests { let mut propagator = ZirPropagator::::default(); assert_eq!( - propagator.fold_field_expression(FieldElementExpression::RightShift( - box FieldElementExpression::identifier("a".into()), - box UExpressionInner::Value(0).annotate(UBitwidth::B32), + propagator.fold_field_expression(FieldElementExpression::right_shift( + FieldElementExpression::identifier("a".into()), + UExpression::value(0).annotate(UBitwidth::B32), )), Ok(FieldElementExpression::identifier("a".into())) ); assert_eq!( - propagator.fold_field_expression(FieldElementExpression::RightShift( - box FieldElementExpression::identifier("a".into()), - box UExpressionInner::Value(Bn128Field::get_required_bits() as u128) + propagator.fold_field_expression(FieldElementExpression::right_shift( + FieldElementExpression::identifier("a".into()), + UExpression::value(Bn128Field::get_required_bits() as u128) .annotate(UBitwidth::B32), )), - Ok(FieldElementExpression::Number(Bn128Field::from(0))) + Ok(FieldElementExpression::value(Bn128Field::from(0))) ); assert_eq!( - propagator.fold_field_expression(FieldElementExpression::RightShift( - box FieldElementExpression::Number(Bn128Field::from(3)), - box UExpressionInner::Value(1 as u128).annotate(UBitwidth::B32), + propagator.fold_field_expression(FieldElementExpression::right_shift( + FieldElementExpression::value(Bn128Field::from(3)), + UExpression::value(1_u128).annotate(UBitwidth::B32), )), - Ok(FieldElementExpression::Number(Bn128Field::from(1))) + Ok(FieldElementExpression::value(Bn128Field::from(1))) ); assert_eq!( - propagator.fold_field_expression(FieldElementExpression::RightShift( - box FieldElementExpression::Number(Bn128Field::from(2)), - box UExpressionInner::Value(2 as u128).annotate(UBitwidth::B32), + propagator.fold_field_expression(FieldElementExpression::right_shift( + FieldElementExpression::value(Bn128Field::from(2)), + UExpression::value(2_u128).annotate(UBitwidth::B32), )), - Ok(FieldElementExpression::Number(Bn128Field::from(0))) + Ok(FieldElementExpression::value(Bn128Field::from(0))) ); assert_eq!( - propagator.fold_field_expression(FieldElementExpression::RightShift( - box FieldElementExpression::Number(Bn128Field::from(2)), - box UExpressionInner::Value(4 as u128).annotate(UBitwidth::B32), + propagator.fold_field_expression(FieldElementExpression::right_shift( + FieldElementExpression::value(Bn128Field::from(2)), + UExpression::value(4_u128).annotate(UBitwidth::B32), )), - Ok(FieldElementExpression::Number(Bn128Field::from(0))) + Ok(FieldElementExpression::value(Bn128Field::from(0))) ); assert_eq!( - propagator.fold_field_expression(FieldElementExpression::RightShift( - box FieldElementExpression::Number(Bn128Field::max_value()), - box UExpressionInner::Value((Bn128Field::get_required_bits() - 1) as u128) + propagator.fold_field_expression(FieldElementExpression::right_shift( + FieldElementExpression::value(Bn128Field::max_value()), + UExpression::value((Bn128Field::get_required_bits() - 1) as u128) .annotate(UBitwidth::B32), )), - Ok(FieldElementExpression::Number(Bn128Field::from(1))) + Ok(FieldElementExpression::value(Bn128Field::from(1))) ); assert_eq!( - propagator.fold_field_expression(FieldElementExpression::RightShift( - box FieldElementExpression::Number(Bn128Field::max_value()), - box UExpressionInner::Value(Bn128Field::get_required_bits() as u128) + propagator.fold_field_expression(FieldElementExpression::right_shift( + FieldElementExpression::value(Bn128Field::max_value()), + UExpression::value(Bn128Field::get_required_bits() as u128) .annotate(UBitwidth::B32), )), - Ok(FieldElementExpression::Number(Bn128Field::from(0))) + Ok(FieldElementExpression::value(Bn128Field::from(0))) ); } @@ -1145,29 +1223,29 @@ mod tests { assert_eq!( propagator.fold_field_expression(FieldElementExpression::conditional( - BooleanExpression::Value(true), - FieldElementExpression::Number(Bn128Field::from(1)), - FieldElementExpression::Number(Bn128Field::from(2)), + BooleanExpression::value(true), + FieldElementExpression::value(Bn128Field::from(1)), + FieldElementExpression::value(Bn128Field::from(2)), )), - Ok(FieldElementExpression::Number(Bn128Field::from(1))) + Ok(FieldElementExpression::value(Bn128Field::from(1))) ); assert_eq!( propagator.fold_field_expression(FieldElementExpression::conditional( - BooleanExpression::Value(false), - FieldElementExpression::Number(Bn128Field::from(1)), - FieldElementExpression::Number(Bn128Field::from(2)), + BooleanExpression::value(false), + FieldElementExpression::value(Bn128Field::from(1)), + FieldElementExpression::value(Bn128Field::from(2)), )), - Ok(FieldElementExpression::Number(Bn128Field::from(2))) + Ok(FieldElementExpression::value(Bn128Field::from(2))) ); assert_eq!( propagator.fold_field_expression(FieldElementExpression::conditional( BooleanExpression::identifier("a".into()), - FieldElementExpression::Number(Bn128Field::from(2)), - FieldElementExpression::Number(Bn128Field::from(2)), + FieldElementExpression::value(Bn128Field::from(2)), + FieldElementExpression::value(Bn128Field::from(2)), )), - Ok(FieldElementExpression::Number(Bn128Field::from(2))) + Ok(FieldElementExpression::value(Bn128Field::from(2))) ); } } @@ -1186,21 +1264,21 @@ mod tests { assert_eq!( propagator.fold_boolean_expression(BooleanExpression::select( vec![ - BooleanExpression::Value(false), - BooleanExpression::Value(true), + BooleanExpression::value(false), + BooleanExpression::value(true) ], - UExpressionInner::Value(1).annotate(UBitwidth::B32), + UExpression::value(1).annotate(UBitwidth::B32), )), - Ok(BooleanExpression::Value(true)) + Ok(BooleanExpression::value(true)) ); assert_eq!( propagator.fold_boolean_expression(BooleanExpression::select( vec![ - BooleanExpression::Value(false), - BooleanExpression::Value(true), + BooleanExpression::value(false), + BooleanExpression::value(true) ], - UExpressionInner::Value(3).annotate(UBitwidth::B32), + UExpression::value(3).annotate(UBitwidth::B32), )), Err(Error::OutOfBounds(3, 2)) ); @@ -1211,35 +1289,35 @@ mod tests { let mut propagator = ZirPropagator::default(); assert_eq!( - propagator.fold_boolean_expression(BooleanExpression::FieldLt( - box FieldElementExpression::Number(Bn128Field::from(2)), - box FieldElementExpression::Number(Bn128Field::from(3)), + propagator.fold_boolean_expression(BooleanExpression::field_lt( + FieldElementExpression::value(Bn128Field::from(2)), + FieldElementExpression::value(Bn128Field::from(3)), )), - Ok(BooleanExpression::Value(true)) + Ok(BooleanExpression::value(true)) ); assert_eq!( - propagator.fold_boolean_expression(BooleanExpression::FieldLt( - box FieldElementExpression::Number(Bn128Field::from(3)), - box FieldElementExpression::Number(Bn128Field::from(3)), + propagator.fold_boolean_expression(BooleanExpression::field_lt( + FieldElementExpression::value(Bn128Field::from(3)), + FieldElementExpression::value(Bn128Field::from(3)), )), - Ok(BooleanExpression::Value(false)) + Ok(BooleanExpression::value(false)) ); assert_eq!( - propagator.fold_boolean_expression(BooleanExpression::FieldLt( - box FieldElementExpression::identifier("a".into()), - box FieldElementExpression::Number(Bn128Field::from(0)), + propagator.fold_boolean_expression(BooleanExpression::field_lt( + FieldElementExpression::identifier("a".into()), + FieldElementExpression::value(Bn128Field::from(0)), )), - Ok(BooleanExpression::Value(false)) + Ok(BooleanExpression::value(false)) ); assert_eq!( - propagator.fold_boolean_expression(BooleanExpression::FieldLt( - box FieldElementExpression::Number(Bn128Field::max_value()), - box FieldElementExpression::identifier("a".into()), + propagator.fold_boolean_expression(BooleanExpression::field_lt( + FieldElementExpression::value(Bn128Field::max_value()), + FieldElementExpression::identifier("a".into()), )), - Ok(BooleanExpression::Value(false)) + Ok(BooleanExpression::value(false)) ); } @@ -1248,19 +1326,19 @@ mod tests { let mut propagator = ZirPropagator::default(); assert_eq!( - propagator.fold_boolean_expression(BooleanExpression::FieldLe( - box FieldElementExpression::Number(Bn128Field::from(2)), - box FieldElementExpression::Number(Bn128Field::from(3)), + propagator.fold_boolean_expression(BooleanExpression::field_le( + FieldElementExpression::value(Bn128Field::from(2)), + FieldElementExpression::value(Bn128Field::from(3)), )), - Ok(BooleanExpression::Value(true)) + Ok(BooleanExpression::value(true)) ); assert_eq!( - propagator.fold_boolean_expression(BooleanExpression::FieldLe( - box FieldElementExpression::Number(Bn128Field::from(3)), - box FieldElementExpression::Number(Bn128Field::from(3)), + propagator.fold_boolean_expression(BooleanExpression::field_le( + FieldElementExpression::value(Bn128Field::from(3)), + FieldElementExpression::value(Bn128Field::from(3)), )), - Ok(BooleanExpression::Value(true)) + Ok(BooleanExpression::value(true)) ); } @@ -1269,19 +1347,19 @@ mod tests { let mut propagator = ZirPropagator::default(); assert_eq!( - propagator.fold_boolean_expression(BooleanExpression::FieldEq( - box FieldElementExpression::Number(Bn128Field::from(2)), - box FieldElementExpression::Number(Bn128Field::from(2)), + propagator.fold_boolean_expression(BooleanExpression::field_eq( + FieldElementExpression::value(Bn128Field::from(2)), + FieldElementExpression::value(Bn128Field::from(2)), )), - Ok(BooleanExpression::Value(true)) + Ok(BooleanExpression::value(true)) ); assert_eq!( - propagator.fold_boolean_expression(BooleanExpression::FieldEq( - box FieldElementExpression::Number(Bn128Field::from(3)), - box FieldElementExpression::Number(Bn128Field::from(2)), + propagator.fold_boolean_expression(BooleanExpression::field_eq( + FieldElementExpression::value(Bn128Field::from(3)), + FieldElementExpression::value(Bn128Field::from(2)), )), - Ok(BooleanExpression::Value(false)) + Ok(BooleanExpression::value(false)) ); } @@ -1290,19 +1368,19 @@ mod tests { let mut propagator = ZirPropagator::::default(); assert_eq!( - propagator.fold_boolean_expression(BooleanExpression::UintLt( - box UExpressionInner::Value(2).annotate(UBitwidth::B32), - box UExpressionInner::Value(3).annotate(UBitwidth::B32), + propagator.fold_boolean_expression(BooleanExpression::uint_lt( + UExpression::value(2).annotate(UBitwidth::B32), + UExpression::value(3).annotate(UBitwidth::B32), )), - Ok(BooleanExpression::Value(true)) + Ok(BooleanExpression::value(true)) ); assert_eq!( - propagator.fold_boolean_expression(BooleanExpression::UintLt( - box UExpressionInner::Value(3).annotate(UBitwidth::B32), - box UExpressionInner::Value(3).annotate(UBitwidth::B32), + propagator.fold_boolean_expression(BooleanExpression::uint_lt( + UExpression::value(3).annotate(UBitwidth::B32), + UExpression::value(3).annotate(UBitwidth::B32), )), - Ok(BooleanExpression::Value(false)) + Ok(BooleanExpression::value(false)) ); } @@ -1311,19 +1389,19 @@ mod tests { let mut propagator = ZirPropagator::::default(); assert_eq!( - propagator.fold_boolean_expression(BooleanExpression::UintLe( - box UExpressionInner::Value(2).annotate(UBitwidth::B32), - box UExpressionInner::Value(3).annotate(UBitwidth::B32), + propagator.fold_boolean_expression(BooleanExpression::uint_le( + UExpression::value(2).annotate(UBitwidth::B32), + UExpression::value(3).annotate(UBitwidth::B32), )), - Ok(BooleanExpression::Value(true)) + Ok(BooleanExpression::value(true)) ); assert_eq!( - propagator.fold_boolean_expression(BooleanExpression::UintLe( - box UExpressionInner::Value(3).annotate(UBitwidth::B32), - box UExpressionInner::Value(3).annotate(UBitwidth::B32), + propagator.fold_boolean_expression(BooleanExpression::uint_le( + UExpression::value(3).annotate(UBitwidth::B32), + UExpression::value(3).annotate(UBitwidth::B32), )), - Ok(BooleanExpression::Value(true)) + Ok(BooleanExpression::value(true)) ); } @@ -1332,19 +1410,19 @@ mod tests { let mut propagator = ZirPropagator::::default(); assert_eq!( - propagator.fold_boolean_expression(BooleanExpression::UintEq( - box UExpressionInner::Value(2).annotate(UBitwidth::B32), - box UExpressionInner::Value(2).annotate(UBitwidth::B32), + propagator.fold_boolean_expression(BooleanExpression::uint_eq( + UExpression::value(2).annotate(UBitwidth::B32), + UExpression::value(2).annotate(UBitwidth::B32), )), - Ok(BooleanExpression::Value(true)) + Ok(BooleanExpression::value(true)) ); assert_eq!( - propagator.fold_boolean_expression(BooleanExpression::UintEq( - box UExpressionInner::Value(2).annotate(UBitwidth::B32), - box UExpressionInner::Value(3).annotate(UBitwidth::B32), + propagator.fold_boolean_expression(BooleanExpression::uint_eq( + UExpression::value(2).annotate(UBitwidth::B32), + UExpression::value(3).annotate(UBitwidth::B32), )), - Ok(BooleanExpression::Value(false)) + Ok(BooleanExpression::value(false)) ); } @@ -1353,19 +1431,19 @@ mod tests { let mut propagator = ZirPropagator::::default(); assert_eq!( - propagator.fold_boolean_expression(BooleanExpression::BoolEq( - box BooleanExpression::Value(true), - box BooleanExpression::Value(true), + propagator.fold_boolean_expression(BooleanExpression::bool_eq( + BooleanExpression::value(true), + BooleanExpression::value(true), )), - Ok(BooleanExpression::Value(true)) + Ok(BooleanExpression::value(true)) ); assert_eq!( - propagator.fold_boolean_expression(BooleanExpression::BoolEq( - box BooleanExpression::Value(true), - box BooleanExpression::Value(false), + propagator.fold_boolean_expression(BooleanExpression::bool_eq( + BooleanExpression::value(true), + BooleanExpression::value(false), )), - Ok(BooleanExpression::Value(false)) + Ok(BooleanExpression::value(false)) ); } @@ -1374,35 +1452,35 @@ mod tests { let mut propagator = ZirPropagator::::default(); assert_eq!( - propagator.fold_boolean_expression(BooleanExpression::And( - box BooleanExpression::Value(true), - box BooleanExpression::Value(true), + propagator.fold_boolean_expression(BooleanExpression::bitand( + BooleanExpression::value(true), + BooleanExpression::value(true), )), - Ok(BooleanExpression::Value(true)) + Ok(BooleanExpression::value(true)) ); assert_eq!( - propagator.fold_boolean_expression(BooleanExpression::And( - box BooleanExpression::Value(true), - box BooleanExpression::Value(false), + propagator.fold_boolean_expression(BooleanExpression::bitand( + BooleanExpression::value(true), + BooleanExpression::value(false), )), - Ok(BooleanExpression::Value(false)) + Ok(BooleanExpression::value(false)) ); assert_eq!( - propagator.fold_boolean_expression(BooleanExpression::And( - box BooleanExpression::identifier("a".into()), - box BooleanExpression::Value(true), + propagator.fold_boolean_expression(BooleanExpression::bitand( + BooleanExpression::identifier("a".into()), + BooleanExpression::value(true) )), Ok(BooleanExpression::identifier("a".into())) ); assert_eq!( - propagator.fold_boolean_expression(BooleanExpression::And( - box BooleanExpression::identifier("a".into()), - box BooleanExpression::Value(false), + propagator.fold_boolean_expression(BooleanExpression::bitand( + BooleanExpression::identifier("a".into()), + BooleanExpression::value(false), )), - Ok(BooleanExpression::Value(false)) + Ok(BooleanExpression::value(false)) ); } @@ -1411,19 +1489,19 @@ mod tests { let mut propagator = ZirPropagator::::default(); assert_eq!( - propagator.fold_boolean_expression(BooleanExpression::Or( - box BooleanExpression::Value(true), - box BooleanExpression::Value(true), + propagator.fold_boolean_expression(BooleanExpression::bitor( + BooleanExpression::value(true), + BooleanExpression::value(true), )), - Ok(BooleanExpression::Value(true)) + Ok(BooleanExpression::value(true)) ); assert_eq!( - propagator.fold_boolean_expression(BooleanExpression::Or( - box BooleanExpression::Value(true), - box BooleanExpression::Value(false), + propagator.fold_boolean_expression(BooleanExpression::bitor( + BooleanExpression::value(true), + BooleanExpression::value(false), )), - Ok(BooleanExpression::Value(true)) + Ok(BooleanExpression::value(true)) ); } @@ -1432,17 +1510,17 @@ mod tests { let mut propagator = ZirPropagator::::default(); assert_eq!( - propagator.fold_boolean_expression(BooleanExpression::Not( - box BooleanExpression::Value(true), + propagator.fold_boolean_expression(BooleanExpression::not( + BooleanExpression::value(true) )), - Ok(BooleanExpression::Value(false)) + Ok(BooleanExpression::value(false)) ); assert_eq!( - propagator.fold_boolean_expression(BooleanExpression::Not( - box BooleanExpression::Value(false), + propagator.fold_boolean_expression(BooleanExpression::not( + BooleanExpression::value(false), )), - Ok(BooleanExpression::Value(true)) + Ok(BooleanExpression::value(true)) ); } @@ -1452,29 +1530,29 @@ mod tests { assert_eq!( propagator.fold_boolean_expression(BooleanExpression::conditional( - BooleanExpression::Value(true), - BooleanExpression::Value(true), - BooleanExpression::Value(false) + BooleanExpression::value(true), + BooleanExpression::value(true), + BooleanExpression::value(false) )), - Ok(BooleanExpression::Value(true)) + Ok(BooleanExpression::value(true)) ); assert_eq!( propagator.fold_boolean_expression(BooleanExpression::conditional( - BooleanExpression::Value(false), - BooleanExpression::Value(true), - BooleanExpression::Value(false) + BooleanExpression::value(false), + BooleanExpression::value(true), + BooleanExpression::value(false), )), - Ok(BooleanExpression::Value(false)) + Ok(BooleanExpression::value(false)) ); assert_eq!( propagator.fold_boolean_expression(BooleanExpression::conditional( BooleanExpression::identifier("a".into()), - BooleanExpression::Value(true), - BooleanExpression::Value(true) + BooleanExpression::value(true), + BooleanExpression::value(true), )), - Ok(BooleanExpression::Value(true)) + Ok(BooleanExpression::value(true)) ); } } @@ -1494,14 +1572,14 @@ mod tests { UBitwidth::B32, UExpression::select( vec![ - UExpressionInner::Value(1).annotate(UBitwidth::B32), - UExpressionInner::Value(2).annotate(UBitwidth::B32), + UExpression::value(1).annotate(UBitwidth::B32), + UExpression::value(2).annotate(UBitwidth::B32), ], - UExpressionInner::Value(1).annotate(UBitwidth::B32), + UExpression::value(1).annotate(UBitwidth::B32), ) .into_inner() ), - Ok(UExpressionInner::Value(2)) + Ok(UExpression::value(2)) ); assert_eq!( @@ -1509,10 +1587,10 @@ mod tests { UBitwidth::B32, UExpression::select( vec![ - UExpressionInner::Value(1).annotate(UBitwidth::B32), - UExpressionInner::Value(2).annotate(UBitwidth::B32), + UExpression::value(1).annotate(UBitwidth::B32), + UExpression::value(2).annotate(UBitwidth::B32), ], - UExpressionInner::Value(3).annotate(UBitwidth::B32), + UExpression::value(3).annotate(UBitwidth::B32), ) .into_inner() ), @@ -1527,22 +1605,24 @@ mod tests { assert_eq!( propagator.fold_uint_expression_inner( UBitwidth::B32, - UExpressionInner::Add( - box UExpressionInner::Value(2).annotate(UBitwidth::B32), - box UExpressionInner::Value(3).annotate(UBitwidth::B32), + UExpression::add( + UExpression::value(2).annotate(UBitwidth::B32), + UExpression::value(3).annotate(UBitwidth::B32), ) + .into_inner() ), - Ok(UExpressionInner::Value(5)) + Ok(UExpression::value(5)) ); // a + 0 = a assert_eq!( propagator.fold_uint_expression_inner( UBitwidth::B32, - UExpressionInner::Add( - box UExpression::identifier("a".into()).annotate(UBitwidth::B32), - box UExpressionInner::Value(0).annotate(UBitwidth::B32), + UExpression::add( + UExpression::identifier("a".into()).annotate(UBitwidth::B32), + UExpression::value(0).annotate(UBitwidth::B32), ) + .into_inner() ), Ok(UExpression::identifier("a".into())) ); @@ -1555,22 +1635,24 @@ mod tests { assert_eq!( propagator.fold_uint_expression_inner( UBitwidth::B32, - UExpressionInner::Sub( - box UExpressionInner::Value(3).annotate(UBitwidth::B32), - box UExpressionInner::Value(2).annotate(UBitwidth::B32), + UExpression::sub( + UExpression::value(3).annotate(UBitwidth::B32), + UExpression::value(2).annotate(UBitwidth::B32), ) + .into_inner() ), - Ok(UExpressionInner::Value(1)) + Ok(UExpression::value(1)) ); // a - 0 = a assert_eq!( propagator.fold_uint_expression_inner( UBitwidth::B32, - UExpressionInner::Sub( - box UExpression::identifier("a".into()).annotate(UBitwidth::B32), - box UExpressionInner::Value(0).annotate(UBitwidth::B32), + UExpression::sub( + UExpression::identifier("a".into()).annotate(UBitwidth::B32), + UExpression::value(0).annotate(UBitwidth::B32), ) + .into_inner() ), Ok(UExpression::identifier("a".into())) ); @@ -1583,22 +1665,24 @@ mod tests { assert_eq!( propagator.fold_uint_expression_inner( UBitwidth::B32, - UExpressionInner::Mult( - box UExpressionInner::Value(3).annotate(UBitwidth::B32), - box UExpressionInner::Value(2).annotate(UBitwidth::B32), + UExpression::mult( + UExpression::value(3).annotate(UBitwidth::B32), + UExpression::value(2).annotate(UBitwidth::B32), ) + .into_inner() ), - Ok(UExpressionInner::Value(6)) + Ok(UExpression::value(6)) ); // a * 1 = a assert_eq!( propagator.fold_uint_expression_inner( UBitwidth::B32, - UExpressionInner::Mult( - box UExpression::identifier("a".into()).annotate(UBitwidth::B32), - box UExpressionInner::Value(1).annotate(UBitwidth::B32), + UExpression::mult( + UExpression::identifier("a".into()).annotate(UBitwidth::B32), + UExpression::value(1).annotate(UBitwidth::B32), ) + .into_inner() ), Ok(UExpression::identifier("a".into())) ); @@ -1607,12 +1691,13 @@ mod tests { assert_eq!( propagator.fold_uint_expression_inner( UBitwidth::B32, - UExpressionInner::Mult( - box UExpression::identifier("a".into()).annotate(UBitwidth::B32), - box UExpressionInner::Value(0).annotate(UBitwidth::B32), + UExpression::mult( + UExpression::identifier("a".into()).annotate(UBitwidth::B32), + UExpression::value(0).annotate(UBitwidth::B32), ) + .into_inner() ), - Ok(UExpressionInner::Value(0)) + Ok(UExpression::value(0)) ); } @@ -1623,21 +1708,23 @@ mod tests { assert_eq!( propagator.fold_uint_expression_inner( UBitwidth::B32, - UExpressionInner::Div( - box UExpressionInner::Value(6).annotate(UBitwidth::B32), - box UExpressionInner::Value(2).annotate(UBitwidth::B32), + UExpression::div( + UExpression::value(6).annotate(UBitwidth::B32), + UExpression::value(2).annotate(UBitwidth::B32), ) + .into_inner() ), - Ok(UExpressionInner::Value(3)) + Ok(UExpression::value(3)) ); assert_eq!( propagator.fold_uint_expression_inner( UBitwidth::B32, - UExpressionInner::Div( - box UExpression::identifier("a".into()).annotate(UBitwidth::B32), - box UExpressionInner::Value(1).annotate(UBitwidth::B32), + UExpression::div( + UExpression::identifier("a".into()).annotate(UBitwidth::B32), + UExpression::value(1).annotate(UBitwidth::B32), ) + .into_inner() ), Ok(UExpression::identifier("a".into())) ); @@ -1645,10 +1732,11 @@ mod tests { assert_eq!( propagator.fold_uint_expression_inner( UBitwidth::B32, - UExpressionInner::Div( - box UExpression::identifier("a".into()).annotate(UBitwidth::B32), - box UExpressionInner::Value(0).annotate(UBitwidth::B32), + UExpression::div( + UExpression::identifier("a".into()).annotate(UBitwidth::B32), + UExpression::value(0).annotate(UBitwidth::B32), ) + .into_inner() ), Err(Error::DivisionByZero) ); @@ -1661,23 +1749,25 @@ mod tests { assert_eq!( propagator.fold_uint_expression_inner( UBitwidth::B32, - UExpressionInner::Rem( - box UExpressionInner::Value(2).annotate(UBitwidth::B32), - box UExpressionInner::Value(3).annotate(UBitwidth::B32), + UExpression::rem( + UExpression::value(2).annotate(UBitwidth::B32), + UExpression::value(3).annotate(UBitwidth::B32), ) + .into_inner() ), - Ok(UExpressionInner::Value(2)) + Ok(UExpression::value(2)) ); assert_eq!( propagator.fold_uint_expression_inner( UBitwidth::B32, - UExpressionInner::Rem( - box UExpressionInner::Value(3).annotate(UBitwidth::B32), - box UExpressionInner::Value(2).annotate(UBitwidth::B32), + UExpression::rem( + UExpression::value(3).annotate(UBitwidth::B32), + UExpression::value(2).annotate(UBitwidth::B32), ) + .into_inner() ), - Ok(UExpressionInner::Value(1)) + Ok(UExpression::value(1)) ); } @@ -1688,23 +1778,25 @@ mod tests { assert_eq!( propagator.fold_uint_expression_inner( UBitwidth::B32, - UExpressionInner::Xor( - box UExpressionInner::Value(2).annotate(UBitwidth::B32), - box UExpressionInner::Value(3).annotate(UBitwidth::B32), + UExpression::xor( + UExpression::value(2).annotate(UBitwidth::B32), + UExpression::value(3).annotate(UBitwidth::B32), ) + .into_inner() ), - Ok(UExpressionInner::Value(1)) + Ok(UExpression::value(1)) ); assert_eq!( propagator.fold_uint_expression_inner( UBitwidth::B32, - UExpressionInner::Xor( - box UExpression::identifier("a".into()).annotate(UBitwidth::B32), - box UExpression::identifier("a".into()).annotate(UBitwidth::B32), + UExpression::xor( + UExpression::identifier("a".into()).annotate(UBitwidth::B32), + UExpression::identifier("a".into()).annotate(UBitwidth::B32), ) + .into_inner() ), - Ok(UExpressionInner::Value(0)) + Ok(UExpression::value(0)) ); } @@ -1715,32 +1807,35 @@ mod tests { assert_eq!( propagator.fold_uint_expression_inner( UBitwidth::B32, - UExpressionInner::And( - box UExpressionInner::Value(2).annotate(UBitwidth::B32), - box UExpressionInner::Value(3).annotate(UBitwidth::B32), + UExpression::and( + UExpression::value(2).annotate(UBitwidth::B32), + UExpression::value(3).annotate(UBitwidth::B32), ) + .into_inner() ), - Ok(UExpressionInner::Value(2)) + Ok(UExpression::value(2)) ); assert_eq!( propagator.fold_uint_expression_inner( UBitwidth::B32, - UExpressionInner::And( - box UExpression::identifier("a".into()).annotate(UBitwidth::B32), - box UExpressionInner::Value(0).annotate(UBitwidth::B32), + UExpression::and( + UExpression::identifier("a".into()).annotate(UBitwidth::B32), + UExpression::value(0).annotate(UBitwidth::B32), ) + .into_inner() ), - Ok(UExpressionInner::Value(0)) + Ok(UExpression::value(0)) ); assert_eq!( propagator.fold_uint_expression_inner( UBitwidth::B32, - UExpressionInner::And( - box UExpression::identifier("a".into()).annotate(UBitwidth::B32), - box UExpressionInner::Value(u32::MAX as u128).annotate(UBitwidth::B32), + UExpression::and( + UExpression::identifier("a".into()).annotate(UBitwidth::B32), + UExpression::value(u32::MAX as u128).annotate(UBitwidth::B32), ) + .into_inner() ), Ok(UExpression::identifier("a".into())) ); @@ -1753,21 +1848,23 @@ mod tests { assert_eq!( propagator.fold_uint_expression_inner( UBitwidth::B32, - UExpressionInner::Or( - box UExpressionInner::Value(2).annotate(UBitwidth::B32), - box UExpressionInner::Value(3).annotate(UBitwidth::B32), + UExpression::or( + UExpression::value(2).annotate(UBitwidth::B32), + UExpression::value(3).annotate(UBitwidth::B32), ) + .into_inner() ), - Ok(UExpressionInner::Value(3)) + Ok(UExpression::value(3)) ); assert_eq!( propagator.fold_uint_expression_inner( UBitwidth::B32, - UExpressionInner::Or( - box UExpression::identifier("a".into()).annotate(UBitwidth::B32), - box UExpressionInner::Value(0).annotate(UBitwidth::B32), + UExpression::or( + UExpression::identifier("a".into()).annotate(UBitwidth::B32), + UExpression::value(0).annotate(UBitwidth::B32), ) + .into_inner() ), Ok(UExpression::identifier("a".into())) ); @@ -1775,12 +1872,13 @@ mod tests { assert_eq!( propagator.fold_uint_expression_inner( UBitwidth::B32, - UExpressionInner::Or( - box UExpression::identifier("a".into()).annotate(UBitwidth::B32), - box UExpressionInner::Value(u32::MAX as u128).annotate(UBitwidth::B32), + UExpression::or( + UExpression::identifier("a".into()).annotate(UBitwidth::B32), + UExpression::value(u32::MAX as u128).annotate(UBitwidth::B32), ) + .into_inner() ), - Ok(UExpressionInner::Value(u32::MAX as u128)) + Ok(UExpression::value(u32::MAX as u128)) ); } @@ -1791,34 +1889,37 @@ mod tests { assert_eq!( propagator.fold_uint_expression_inner( UBitwidth::B32, - UExpressionInner::LeftShift( - box UExpressionInner::Value(2).annotate(UBitwidth::B32), - 3, + UExpression::left_shift( + UExpression::value(2).annotate(UBitwidth::B32), + 3.into(), ) + .into_inner() ), - Ok(UExpressionInner::Value(16)) + Ok(UExpression::value(16)) ); assert_eq!( propagator.fold_uint_expression_inner( UBitwidth::B32, - UExpressionInner::LeftShift( - box UExpressionInner::Value(2).annotate(UBitwidth::B32), - 0, + UExpression::left_shift( + UExpression::value(2).annotate(UBitwidth::B32), + 0.into(), ) + .into_inner() ), - Ok(UExpressionInner::Value(2)) + Ok(UExpression::value(2)) ); assert_eq!( propagator.fold_uint_expression_inner( UBitwidth::B32, - UExpressionInner::LeftShift( - box UExpressionInner::Value(2).annotate(UBitwidth::B32), - 32, + UExpression::left_shift( + UExpression::value(2).annotate(UBitwidth::B32), + 32.into(), ) + .into_inner() ), - Ok(UExpressionInner::Value(0)) + Ok(UExpression::value(0)) ); } @@ -1829,34 +1930,37 @@ mod tests { assert_eq!( propagator.fold_uint_expression_inner( UBitwidth::B32, - UExpressionInner::RightShift( - box UExpressionInner::Value(4).annotate(UBitwidth::B32), - 2, + UExpression::right_shift( + UExpression::value(4).annotate(UBitwidth::B32), + 2.into(), ) + .into_inner() ), - Ok(UExpressionInner::Value(1)) + Ok(UExpression::value(1)) ); assert_eq!( propagator.fold_uint_expression_inner( UBitwidth::B32, - UExpressionInner::RightShift( - box UExpressionInner::Value(4).annotate(UBitwidth::B32), - 0, + UExpression::right_shift( + UExpression::value(4).annotate(UBitwidth::B32), + 0.into(), ) + .into_inner() ), - Ok(UExpressionInner::Value(4)) + Ok(UExpression::value(4)) ); assert_eq!( propagator.fold_uint_expression_inner( UBitwidth::B32, - UExpressionInner::RightShift( - box UExpressionInner::Value(4).annotate(UBitwidth::B32), - 32, + UExpression::right_shift( + UExpression::value(4).annotate(UBitwidth::B32), + 32.into(), ) + .into_inner() ), - Ok(UExpressionInner::Value(0)) + Ok(UExpression::value(0)) ); } @@ -1867,9 +1971,9 @@ mod tests { assert_eq!( propagator.fold_uint_expression_inner( UBitwidth::B32, - UExpressionInner::Not(box UExpressionInner::Value(2).annotate(UBitwidth::B32),) + UExpression::not(UExpression::value(2).annotate(UBitwidth::B32),).into_inner() ), - Ok(UExpressionInner::Value(4294967293)) + Ok(UExpression::value(4294967293)) ); } @@ -1881,26 +1985,26 @@ mod tests { propagator.fold_uint_expression_inner( UBitwidth::B32, UExpression::conditional( - BooleanExpression::Value(true), - UExpressionInner::Value(1).annotate(UBitwidth::B32), - UExpressionInner::Value(2).annotate(UBitwidth::B32), + BooleanExpression::value(true), + UExpression::value(1).annotate(UBitwidth::B32), + UExpression::value(2).annotate(UBitwidth::B32), ) .into_inner() ), - Ok(UExpressionInner::Value(1)) + Ok(UExpression::value(1)) ); assert_eq!( propagator.fold_uint_expression_inner( UBitwidth::B32, UExpression::conditional( - BooleanExpression::Value(false), - UExpressionInner::Value(1).annotate(UBitwidth::B32), - UExpressionInner::Value(2).annotate(UBitwidth::B32), + BooleanExpression::value(false), + UExpression::value(1).annotate(UBitwidth::B32), + UExpression::value(2).annotate(UBitwidth::B32), ) .into_inner() ), - Ok(UExpressionInner::Value(2)) + Ok(UExpression::value(2)) ); assert_eq!( @@ -1908,12 +2012,12 @@ mod tests { UBitwidth::B32, UExpression::conditional( BooleanExpression::identifier("a".into()), - UExpressionInner::Value(2).annotate(UBitwidth::B32), - UExpressionInner::Value(2).annotate(UBitwidth::B32), + UExpression::value(2).annotate(UBitwidth::B32), + UExpression::value(2).annotate(UBitwidth::B32), ) .into_inner() ), - Ok(UExpressionInner::Value(2)) + Ok(UExpression::value(2)) ); } } diff --git a/zokrates_ark/Cargo.toml b/zokrates_ark/Cargo.toml index 86508b552..b3da39979 100644 --- a/zokrates_ark/Cargo.toml +++ b/zokrates_ark/Cargo.toml @@ -1,9 +1,20 @@ [package] name = "zokrates_ark" -version = "0.1.1" +version = "0.1.4" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +default = [] +multicore = [ + "ark-ff/parallel", + "ark-ec/parallel", + "ark-groth16/parallel", + "ark-gm17/parallel", + "ark-marlin/parallel", + "ark-poly/parallel", + "ark-poly-commit/parallel", + "ark-crypto-primitives/parallel", +] [dependencies] zokrates_field = { version = "0.5", path = "../zokrates_field", default-features = false } @@ -17,7 +28,7 @@ ark-bls12-377 = { version = "^0.3.0", features = ["curve"], default-features = f ark-bw6-761 = { version = "^0.3.0", default-features = false } ark-gm17 = { version = "^0.3.0", default-features = false } ark-groth16 = { version = "^0.3.0", default-features = false } -ark-serialize = { version = "^0.3.0", default-features = false } +ark-serialize = { version = "^0.3.0", default-features = false, features = ["std"] } ark-relations = { version = "^0.3.0", default-features = false } ark-marlin = { git = "https://github.com/arkworks-rs/marlin", rev = "63cfd82", default-features = false } ark-poly = { version = "^0.3.0", default-features = false } diff --git a/zokrates_ark/src/gm17.rs b/zokrates_ark/src/gm17.rs index 0e119eee8..dabe52a2c 100644 --- a/zokrates_ark/src/gm17.rs +++ b/zokrates_ark/src/gm17.rs @@ -9,19 +9,18 @@ use zokrates_field::{ArkFieldExtensions, Field}; use crate::Computation; use crate::{parse_fr, parse_g1, parse_g2}; use crate::{serialization, Ark}; -use rand_0_8::{rngs::StdRng, SeedableRng}; +use rand_0_8::{CryptoRng, RngCore}; use zokrates_ast::ir::{ProgIterator, Statement, Witness}; use zokrates_proof_systems::gm17::{ProofPoints, VerificationKey, GM17}; use zokrates_proof_systems::Scheme; use zokrates_proof_systems::{Backend, NonUniversalBackend, Proof, SetupKeypair}; impl NonUniversalBackend for Ark { - fn setup<'a, I: IntoIterator>>( + fn setup<'a, I: IntoIterator>, R: RngCore + CryptoRng>( program: ProgIterator<'a, T, I>, + rng: &mut R, ) -> SetupKeypair { let computation = Computation::without_witness(program); - - let rng = &mut StdRng::from_entropy(); let (pk, vk) = ArkGM17::::circuit_specific_setup(computation, rng).unwrap(); let mut pk_vec: Vec = Vec::new(); @@ -41,10 +40,16 @@ impl NonUniversalBackend for Ark { } impl Backend for Ark { - fn generate_proof<'a, I: IntoIterator>>( + fn generate_proof< + 'a, + I: IntoIterator>, + R: std::io::Read, + G: RngCore + CryptoRng, + >( program: ProgIterator<'a, T, I>, witness: Witness, - proving_key: Vec, + proving_key: R, + rng: &mut G, ) -> Proof { let computation = Computation::with_witness(program, witness); @@ -54,14 +59,11 @@ impl Backend for Ark { .map(parse_fr::) .collect::>(); - let pk = ProvingKey::<::ArkEngine>::deserialize_unchecked( - &mut proving_key.as_slice(), - ) - .unwrap(); + let pk = + ProvingKey::<::ArkEngine>::deserialize_unchecked(proving_key) + .unwrap(); - let rng = &mut StdRng::from_entropy(); let proof = ArkGM17::::prove(&pk, computation, rng).unwrap(); - let proof_points = ProofPoints { a: parse_g1::(&proof.a), b: parse_g2::(&proof.b), @@ -110,6 +112,8 @@ impl Backend for Ark { #[cfg(test)] mod tests { + use rand_0_8::rngs::StdRng; + use rand_0_8::SeedableRng; use zokrates_ast::flat::{Parameter, Variable}; use zokrates_ast::ir::{Prog, Statement}; use zokrates_interpreter::Interpreter; @@ -120,20 +124,37 @@ mod tests { #[test] fn verify_bls12_377_field() { let program: Prog = Prog { + module_map: Default::default(), arguments: vec![Parameter::public(Variable::new(0))], return_count: 1, - statements: vec![Statement::constraint(Variable::new(0), Variable::public(0))], + statements: vec![Statement::constraint( + Variable::new(0), + Variable::public(0), + None, + )], + solvers: vec![], }; - let keypair = >::setup(program.clone()); + let rng = &mut StdRng::from_entropy(); + let keypair = + >::setup(program.clone(), rng); let interpreter = Interpreter::default(); let witness = interpreter - .execute(program.clone(), &[Bls12_377Field::from(42)]) + .execute( + &[Bls12_377Field::from(42)], + program.statements.iter(), + &program.arguments, + &program.solvers, + ) .unwrap(); - let proof = - >::generate_proof(program, witness, keypair.pk); + let proof = >::generate_proof( + program, + witness, + keypair.pk.as_slice(), + rng, + ); let ans = >::verify(keypair.vk, proof); assert!(ans); @@ -142,20 +163,36 @@ mod tests { #[test] fn verify_bw6_761_field() { let program: Prog = Prog { + module_map: Default::default(), arguments: vec![Parameter::public(Variable::new(0))], return_count: 1, - statements: vec![Statement::constraint(Variable::new(0), Variable::public(0))], + statements: vec![Statement::constraint( + Variable::new(0), + Variable::public(0), + None, + )], + solvers: vec![], }; - let keypair = >::setup(program.clone()); + let rng = &mut StdRng::from_entropy(); + let keypair = >::setup(program.clone(), rng); let interpreter = Interpreter::default(); let witness = interpreter - .execute(program.clone(), &[Bw6_761Field::from(42)]) + .execute( + &[Bw6_761Field::from(42)], + program.statements.iter(), + &program.arguments, + &program.solvers, + ) .unwrap(); - let proof = - >::generate_proof(program, witness, keypair.pk); + let proof = >::generate_proof( + program, + witness, + keypair.pk.as_slice(), + rng, + ); let ans = >::verify(keypair.vk, proof); assert!(ans); diff --git a/zokrates_ark/src/groth16.rs b/zokrates_ark/src/groth16.rs index 0de188453..460b93ea6 100644 --- a/zokrates_ark/src/groth16.rs +++ b/zokrates_ark/src/groth16.rs @@ -4,6 +4,7 @@ use ark_groth16::{ ProvingKey, VerifyingKey, }; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use std::io::Read; use zokrates_field::ArkFieldExtensions; use zokrates_field::Field; use zokrates_proof_systems::{Backend, NonUniversalBackend, Proof, SetupKeypair}; @@ -11,21 +12,23 @@ use zokrates_proof_systems::{Backend, NonUniversalBackend, Proof, SetupKeypair}; use crate::Computation; use crate::{parse_fr, serialization, Ark}; use crate::{parse_g1, parse_g2}; -use rand_0_8::{rngs::StdRng, SeedableRng}; +use rand_0_8::{CryptoRng, RngCore}; use zokrates_ast::ir::{ProgIterator, Statement, Witness}; use zokrates_proof_systems::groth16::{ProofPoints, VerificationKey, G16}; use zokrates_proof_systems::Scheme; -const G16_WARNING: &str = "WARNING: You are using the G16 scheme which is subject to malleability. See zokrates.github.io/toolbox/proving_schemes.html#g16-malleability for implications."; - impl Backend for Ark { - fn generate_proof<'a, I: IntoIterator>>( + fn generate_proof< + 'a, + I: IntoIterator>, + R: Read, + G: RngCore + CryptoRng, + >( program: ProgIterator<'a, T, I>, witness: Witness, - proving_key: Vec, + proving_key: R, + rng: &mut G, ) -> Proof { - println!("{}", G16_WARNING); - let computation = Computation::with_witness(program, witness); let inputs = computation @@ -34,12 +37,10 @@ impl Backend for Ark { .map(parse_fr::) .collect::>(); - let pk = ProvingKey::<::ArkEngine>::deserialize_unchecked( - &mut proving_key.as_slice(), - ) - .unwrap(); + let pk = + ProvingKey::<::ArkEngine>::deserialize_unchecked(proving_key) + .unwrap(); - let rng = &mut StdRng::from_entropy(); let proof = Groth16::::prove(&pk, computation, rng).unwrap(); let proof_points = ProofPoints { @@ -86,14 +87,11 @@ impl Backend for Ark { } impl NonUniversalBackend for Ark { - fn setup<'a, I: IntoIterator>>( + fn setup<'a, I: IntoIterator>, R: RngCore + CryptoRng>( program: ProgIterator<'a, T, I>, + rng: &mut R, ) -> SetupKeypair { - println!("{}", G16_WARNING); - let computation = Computation::without_witness(program); - - let rng = &mut StdRng::from_entropy(); let (pk, vk) = Groth16::::circuit_specific_setup(computation, rng).unwrap(); let mut pk_vec: Vec = Vec::new(); @@ -113,6 +111,8 @@ impl NonUniversalBackend for Ark { #[cfg(test)] mod tests { + use rand_0_8::rngs::StdRng; + use rand_0_8::SeedableRng; use zokrates_ast::flat::{Parameter, Variable}; use zokrates_ast::ir::{Prog, Statement}; use zokrates_interpreter::Interpreter; @@ -123,20 +123,37 @@ mod tests { #[test] fn verify_bls12_377_field() { let program: Prog = Prog { + module_map: Default::default(), arguments: vec![Parameter::public(Variable::new(0))], return_count: 1, - statements: vec![Statement::constraint(Variable::new(0), Variable::public(0))], + statements: vec![Statement::constraint( + Variable::new(0), + Variable::public(0), + None, + )], + solvers: vec![], }; - let keypair = >::setup(program.clone()); + let rng = &mut StdRng::from_entropy(); + let keypair = + >::setup(program.clone(), rng); let interpreter = Interpreter::default(); let witness = interpreter - .execute(program.clone(), &[Bls12_377Field::from(42)]) + .execute( + &[Bls12_377Field::from(42)], + program.statements.iter(), + &program.arguments, + &program.solvers, + ) .unwrap(); - let proof = - >::generate_proof(program, witness, keypair.pk); + let proof = >::generate_proof( + program, + witness, + keypair.pk.as_slice(), + rng, + ); let ans = >::verify(keypair.vk, proof); assert!(ans); @@ -145,20 +162,36 @@ mod tests { #[test] fn verify_bw6_761_field() { let program: Prog = Prog { + module_map: Default::default(), arguments: vec![Parameter::public(Variable::new(0))], return_count: 1, - statements: vec![Statement::constraint(Variable::new(0), Variable::public(0))], + statements: vec![Statement::constraint( + Variable::new(0), + Variable::public(0), + None, + )], + solvers: vec![], }; - let keypair = >::setup(program.clone()); + let rng = &mut StdRng::from_entropy(); + let keypair = >::setup(program.clone(), rng); let interpreter = Interpreter::default(); let witness = interpreter - .execute(program.clone(), &[Bw6_761Field::from(42)]) + .execute( + &[Bw6_761Field::from(42)], + program.statements.iter(), + &program.arguments, + &program.solvers, + ) .unwrap(); - let proof = - >::generate_proof(program, witness, keypair.pk); + let proof = >::generate_proof( + program, + witness, + keypair.pk.as_slice(), + rng, + ); let ans = >::verify(keypair.vk, proof); assert!(ans); diff --git a/zokrates_ark/src/lib.rs b/zokrates_ark/src/lib.rs index 425be3a8d..dba49e9a9 100644 --- a/zokrates_ark/src/lib.rs +++ b/zokrates_ark/src/lib.rs @@ -8,8 +8,8 @@ use ark_relations::r1cs::{ SynthesisError, Variable as ArkVariable, }; use std::collections::BTreeMap; -use zokrates_ast::common::Variable; -use zokrates_ast::ir::{CanonicalLinComb, ProgIterator, Statement, Witness}; +use zokrates_ast::common::flat::Variable; +use zokrates_ast::ir::{LinComb, ProgIterator, Statement, Witness}; use zokrates_field::{ArkFieldExtensions, Field}; pub use self::parse::*; @@ -39,12 +39,13 @@ impl<'a, T, I: IntoIterator>> Computation<'a, T, I> { } fn ark_combination( - l: CanonicalLinComb, + l: LinComb, cs: &mut ConstraintSystem<<::ArkEngine as PairingEngine>::Fr>, symbols: &mut BTreeMap, witness: &mut Witness, ) -> LinearCombination<<::ArkEngine as PairingEngine>::Fr> { - l.0.into_iter() + l.value + .into_iter() .map(|(k, v)| { ( v.into_ark(), @@ -112,25 +113,10 @@ impl<'a, T: Field + ArkFieldExtensions, I: IntoIterator> })); for statement in self.program.statements { - if let Statement::Constraint(quad, lin, _) = statement { - let a = ark_combination( - quad.left.clone().into_canonical(), - &mut cs, - &mut symbols, - &mut witness, - ); - let b = ark_combination( - quad.right.clone().into_canonical(), - &mut cs, - &mut symbols, - &mut witness, - ); - let c = ark_combination( - lin.into_canonical(), - &mut cs, - &mut symbols, - &mut witness, - ); + if let Statement::Constraint(s) = statement { + let a = ark_combination(s.quad.left, &mut cs, &mut symbols, &mut witness); + let b = ark_combination(s.quad.right, &mut cs, &mut symbols, &mut witness); + let c = ark_combination(s.lin, &mut cs, &mut symbols, &mut witness); cs.enforce_constraint(a, b, c)?; } @@ -150,7 +136,7 @@ impl<'a, T: Field + ArkFieldExtensions, I: IntoIterator> self.program .public_inputs_values(self.witness.as_ref().unwrap()) .iter() - .map(|v| v.clone().into_ark()) + .map(|v| v.into_ark()) .collect() } } diff --git a/zokrates_ark/src/marlin.rs b/zokrates_ark/src/marlin.rs index 24204a6cd..7b6c8e1a1 100644 --- a/zokrates_ark/src/marlin.rs +++ b/zokrates_ark/src/marlin.rs @@ -17,8 +17,9 @@ use ark_poly_commit::{ }; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use digest::Digest; -use rand_0_8::{Error, RngCore, SeedableRng}; +use rand_0_8::{CryptoRng, Error, RngCore, SeedableRng}; use sha3::Keccak256; +use std::io::Read; use std::marker::PhantomData; use zokrates_field::{ArkFieldExtensions, Field}; @@ -116,9 +117,7 @@ type MarlinInst = ArkMarlin< >; impl UniversalBackend for Ark { - fn universal_setup(size: u32) -> Vec { - let rng = &mut rand_0_8::rngs::StdRng::from_entropy(); - + fn universal_setup(size: u32, rng: &mut R) -> Vec { let srs = MarlinInst::::universal_setup( 2usize.pow(size), 2usize.pow(size), @@ -128,9 +127,7 @@ impl UniversalBackend for Ark .unwrap(); let mut res = vec![]; - srs.serialize(&mut res).unwrap(); - res } @@ -210,26 +207,29 @@ impl UniversalBackend for Ark } impl Backend for Ark { - fn generate_proof<'a, I: IntoIterator>>( + fn generate_proof< + 'a, + I: IntoIterator>, + R: Read, + G: RngCore + CryptoRng, + >( program: ProgIterator<'a, T, I>, witness: Witness, - proving_key: Vec, + proving_key: R, + rng: &mut G, ) -> Proof { let computation = Computation::with_witness(program, witness); - let rng = &mut rand_0_8::rngs::StdRng::from_entropy(); - let pk = IndexProverKey::< <::ArkEngine as PairingEngine>::Fr, MarlinKZG10< T::ArkEngine, DensePolynomial<<::ArkEngine as PairingEngine>::Fr>, >, - >::deserialize_unchecked(&mut proving_key.as_slice()) + >::deserialize_unchecked(proving_key) .unwrap(); let public_inputs = computation.public_inputs_values(); - let inputs = public_inputs.iter().map(parse_fr::).collect::>(); let proof = MarlinInst::::prove(&pk, computation, rng).unwrap(); @@ -386,6 +386,7 @@ impl Backend for Ark { #[cfg(test)] mod tests { + use rand_0_8::rngs::StdRng; use zokrates_ast::flat::{Parameter, Variable}; use zokrates_ast::ir::{Prog, QuadComb, Statement}; use zokrates_interpreter::Interpreter; @@ -397,31 +398,41 @@ mod tests { #[test] fn verify_bls12_377_field() { let program: Prog = Prog { + module_map: Default::default(), arguments: vec![Parameter::private(Variable::new(0))], return_count: 1, statements: vec![ Statement::constraint( - QuadComb::from_linear_combinations( - Variable::new(0).into(), - Variable::new(0).into(), - ), + QuadComb::new(Variable::new(0).into(), Variable::new(0).into()), Variable::new(1), + None, ), - Statement::constraint(Variable::new(1), Variable::public(0)), + Statement::constraint(Variable::new(1), Variable::public(0), None), ], + solvers: vec![], }; - let srs = >::universal_setup(5); + let rng = &mut StdRng::from_entropy(); + let srs = >::universal_setup(5, rng); let keypair = >::setup(srs, program.clone()).unwrap(); let interpreter = Interpreter::default(); let witness = interpreter - .execute(program.clone(), &[Bls12_377Field::from(42)]) + .execute( + &[Bls12_377Field::from(42)], + program.statements.iter(), + &program.arguments, + &program.solvers, + ) .unwrap(); - let proof = - >::generate_proof(program, witness, keypair.pk); + let proof = >::generate_proof( + program, + witness, + keypair.pk.as_slice(), + rng, + ); let ans = >::verify(keypair.vk, proof); assert!(ans); @@ -430,31 +441,41 @@ mod tests { #[test] fn verify_bw6_761_field() { let program: Prog = Prog { + module_map: Default::default(), arguments: vec![Parameter::private(Variable::new(0))], return_count: 1, statements: vec![ Statement::constraint( - QuadComb::from_linear_combinations( - Variable::new(0).into(), - Variable::new(0).into(), - ), + QuadComb::new(Variable::new(0).into(), Variable::new(0).into()), Variable::new(1), + None, ), - Statement::constraint(Variable::new(1), Variable::public(0)), + Statement::constraint(Variable::new(1), Variable::public(0), None), ], + solvers: vec![], }; - let srs = >::universal_setup(5); + let rng = &mut StdRng::from_entropy(); + let srs = >::universal_setup(5, rng); let keypair = >::setup(srs, program.clone()).unwrap(); let interpreter = Interpreter::default(); let witness = interpreter - .execute(program.clone(), &[Bw6_761Field::from(42)]) + .execute( + &[Bw6_761Field::from(42)], + program.statements.iter(), + &program.arguments, + &program.solvers, + ) .unwrap(); - let proof = - >::generate_proof(program, witness, keypair.pk); + let proof = >::generate_proof( + program, + witness, + keypair.pk.as_slice(), + rng, + ); let ans = >::verify(keypair.vk, proof); assert!(ans); diff --git a/zokrates_ast/Cargo.toml b/zokrates_ast/Cargo.toml index a41269c22..dbbb44bed 100644 --- a/zokrates_ast/Cargo.toml +++ b/zokrates_ast/Cargo.toml @@ -1,23 +1,24 @@ [package] name = "zokrates_ast" -version = "0.1.3" +version = "0.1.7" edition = "2021" [features] default = ["bellman", "ark"] -bellman = ["zokrates_field/bellman", "pairing_ce", "zokrates_embed/bellman"] +bellman = ["zokrates_field/bellman_extensions", "pairing_ce", "zokrates_embed/bellman"] ark = ["ark-bls12-377", "zokrates_embed/ark"] +bellperson = ["zokrates_field/bellperson_extensions"] [dependencies] +byteorder = "1.4.3" zokrates_pest_ast = { version = "0.3.0", path = "../zokrates_pest_ast" } cfg-if = "0.1" zokrates_field = { version = "0.5", path = "../zokrates_field", default-features = false } serde = { version = "1.0", features = ["derive"] } -csv = "1" serde_cbor = "0.11.2" num-bigint = { version = "0.2", default-features = false } serde_json = { version = "1.0", features = ["preserve_order"] } zokrates_embed = { version = "0.1.0", path = "../zokrates_embed", default-features = false } pairing_ce = { version = "^0.21", optional = true } ark-bls12-377 = { version = "^0.3.0", features = ["curve"], default-features = false, optional = true } -derivative = "2.2.0" \ No newline at end of file +derivative = "2.2.0" diff --git a/zokrates_ast/src/common/embed.rs b/zokrates_ast/src/common/embed.rs index 58294142f..de5d3ad07 100644 --- a/zokrates_ast/src/common/embed.rs +++ b/zokrates_ast/src/common/embed.rs @@ -1,5 +1,8 @@ -use crate::common::{Parameter, RuntimeError, Solver, Variable}; -use crate::flat::{flat_expression_from_bits, flat_expression_from_variable_summands}; +use crate::common::{ + flat::{Parameter, Variable}, + RuntimeError, Solver, +}; +use crate::flat::flat_expression_from_bits; use crate::flat::{FlatDirective, FlatExpression, FlatFunctionIterator, FlatStatement}; use crate::typed::types::{ ConcreteGenericsAssignment, DeclarationConstant, DeclarationSignature, DeclarationType, @@ -11,12 +14,16 @@ use crate::untyped::{ }; use serde::{Deserialize, Serialize}; use std::collections::HashMap; +use std::ops::*; use zokrates_field::Field; +use super::ModuleMap; + cfg_if::cfg_if! { if #[cfg(feature = "bellman")] { use pairing_ce::bn256::Bn256; use zokrates_embed::{bellman::{from_bellman, generate_sha256_round_constraints}}; + use crate::flat::flat_expression_from_variable_summands; } } @@ -294,7 +301,7 @@ impl FlatEmbed { ); assert_eq!(gen.len(), assignment.0.len()); - gen.map(|g| *assignment.0.get(&g).unwrap() as u32).collect() + gen.map(|g| *assignment.0.get(&g).unwrap()).collect() } pub fn id(&self) -> &'static str { @@ -348,15 +355,11 @@ pub fn sha256_round<'ast, T: Field>( let cs_indices = 0..variable_count; // 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: Vec<_> = input_indices - .clone() - .into_iter() - .map(|i| i + variable_count) - .collect(); + let input_argument_indices: Vec<_> = + input_indices.clone().map(|i| i + variable_count).collect(); // apply an offset of `variable_count` to get the indice of our dummy `current_hash` argument let current_hash_argument_indices: Vec<_> = current_hash_indices .clone() - .into_iter() .map(|i| i + variable_count) .collect(); // define parameters to the function based on the variables @@ -364,21 +367,18 @@ pub fn sha256_round<'ast, T: Field>( .clone() .into_iter() .chain(current_hash_argument_indices.clone()) - .map(|i| Parameter { - id: Variable::new(i), - private: true, - }) + .map(|i| Parameter::private(Variable::new(i))) .collect(); // define a binding of the first variable in the constraint system to one - let one_binding_statement = FlatStatement::Condition( + let one_binding_statement = FlatStatement::condition( Variable::new(0).into(), - FlatExpression::Number(T::from(1)), + FlatExpression::value(T::from(1)), RuntimeError::BellmanOneBinding, ); let input_binding_statements = // bind input and current_hash to inputs input_indices.chain(current_hash_indices).zip(input_argument_indices.clone().into_iter().chain(current_hash_argument_indices.clone())).map(|(cs_index, argument_index)| { - FlatStatement::Condition( + FlatStatement::condition( Variable::new(cs_index).into(), Variable::new(argument_index).into(), RuntimeError::BellmanInputBinding @@ -391,30 +391,30 @@ pub fn sha256_round<'ast, T: Field>( let rhs_b = flat_expression_from_variable_summands::(c.b.as_slice()); let lhs = flat_expression_from_variable_summands::(c.c.as_slice()); - FlatStatement::Condition( + FlatStatement::condition( lhs, - FlatExpression::Mult(box rhs_a, box rhs_b), + FlatExpression::mul(rhs_a, rhs_b), RuntimeError::BellmanConstraint, ) }); // define which subset of the witness is returned - let outputs = output_indices.map(|o| FlatExpression::Identifier(Variable::new(o))); + let outputs = output_indices.map(|o| FlatExpression::identifier(Variable::new(o))); // insert a directive to set the witness based on the bellman gadget and inputs - let directive_statement = FlatStatement::Directive(FlatDirective { - outputs: cs_indices.map(Variable::new).collect(), - inputs: input_argument_indices + let directive_statement = FlatStatement::Directive(FlatDirective::new( + cs_indices.map(Variable::new).collect(), + Solver::Sha256Round, + input_argument_indices .into_iter() .chain(current_hash_argument_indices) .map(|i| Variable::new(i).into()) .collect(), - solver: Solver::Sha256Round, - }); + )); // insert a statement to return the subset of the witness let return_statements = outputs .into_iter() .enumerate() - .map(|(index, e)| FlatStatement::Definition(Variable::public(index), e)); + .map(|(index, e)| FlatStatement::definition(Variable::public(index), e)); let statements = std::iter::once(directive_statement) .chain(std::iter::once(one_binding_statement)) .chain(input_binding_statements) @@ -425,6 +425,7 @@ pub fn sha256_round<'ast, T: Field>( arguments, statements, return_count, + module_map: ModuleMap::default(), } } @@ -467,9 +468,9 @@ pub fn snark_verify_bls12_377<'ast, T: Field>( .chain(vk_arguments) .collect(); - let one_binding_statement = FlatStatement::Condition( - FlatExpression::Identifier(Variable::new(0)), - FlatExpression::Number(T::from(1)), + let one_binding_statement = FlatStatement::condition( + FlatExpression::identifier(Variable::new(0)), + FlatExpression::value(T::from(1)), RuntimeError::ArkOneBinding, ); @@ -483,7 +484,7 @@ pub fn snark_verify_bls12_377<'ast, T: Field>( .chain(vk_argument_indices.clone()), ) .map(|(cs_index, argument_index)| { - FlatStatement::Condition( + FlatStatement::condition( Variable::new(cs_index).into(), Variable::new(argument_index).into(), RuntimeError::ArkInputBinding, @@ -499,29 +500,29 @@ pub fn snark_verify_bls12_377<'ast, T: Field>( let rhs_b = flat_expression_from_variable_summands::(c.b.as_slice()); let lhs = flat_expression_from_variable_summands::(c.c.as_slice()); - FlatStatement::Condition( + FlatStatement::condition( lhs, - FlatExpression::Mult(box rhs_a, box rhs_b), + FlatExpression::mul(rhs_a, rhs_b), RuntimeError::ArkConstraint, ) }) .collect(); - let return_statement = FlatStatement::Definition( + let return_statement = FlatStatement::definition( Variable::public(0), - FlatExpression::Identifier(Variable::new(out_index)), + FlatExpression::identifier(Variable::new(out_index)), ); // insert a directive to set the witness - let directive_statement = FlatStatement::Directive(FlatDirective { - outputs: cs_indices.map(Variable::new).collect(), - inputs: input_argument_indices + let directive_statement = FlatStatement::Directive(FlatDirective::new( + cs_indices.map(Variable::new).collect(), + Solver::SnarkVerifyBls12377(n), + input_argument_indices .chain(proof_argument_indices) .chain(vk_argument_indices) .map(|i| Variable::new(i).into()) .collect(), - solver: Solver::SnarkVerifyBls12377(n), - }); + )); let statements = std::iter::once(directive_statement) .chain(std::iter::once(one_binding_statement)) @@ -533,6 +534,7 @@ pub fn snark_verify_bls12_377<'ast, T: Field>( arguments, statements, return_count: 1, + module_map: ModuleMap::default(), } } @@ -562,14 +564,11 @@ pub fn unpack_to_bitwidth<'ast, T: Field>( let mut layout = HashMap::new(); - let arguments = vec![Parameter { - id: Variable::new(0), - private: true, - }]; + let arguments = vec![Parameter::private(Variable::new(0))]; // o0, ..., o253 = ToBits(i0) - let directive_inputs = vec![FlatExpression::Identifier(use_variable( + let directive_inputs = vec![FlatExpression::identifier(use_variable( &mut layout, "i0".into(), &mut counter, @@ -585,16 +584,16 @@ pub fn unpack_to_bitwidth<'ast, T: Field>( let outputs: Vec<_> = directive_outputs .iter() .enumerate() - .map(|(_, o)| FlatExpression::Identifier(*o)) + .map(|(_, o)| FlatExpression::identifier(*o)) .collect(); // o253, o252, ... o{253 - (bit_width - 1)} are bits let mut statements: Vec> = (0..bit_width) .map(|index| { - let bit = FlatExpression::Identifier(Variable::new(bit_width - index)); - FlatStatement::Condition( + let bit = FlatExpression::identifier(Variable::new(bit_width - index)); + FlatStatement::condition( bit.clone(), - FlatExpression::Mult(box bit.clone(), box bit.clone()), + FlatExpression::mul(bit.clone(), bit), RuntimeError::Bitness, ) }) @@ -603,39 +602,40 @@ pub fn unpack_to_bitwidth<'ast, T: Field>( // sum check: o253 + o252 * 2 + ... + o{253 - (bit_width - 1)} * 2**(bit_width - 1) let lhs_sum = flat_expression_from_bits( (0..bit_width) - .map(|i| FlatExpression::Identifier(Variable::new(i + 1))) + .map(|i| FlatExpression::identifier(Variable::new(i + 1))) .collect(), ); - statements.push(FlatStatement::Condition( + statements.push(FlatStatement::condition( lhs_sum, - FlatExpression::Mult( - box FlatExpression::Identifier(Variable::new(0)), - box FlatExpression::Number(T::from(1)), + FlatExpression::mul( + FlatExpression::identifier(Variable::new(0)), + FlatExpression::value(T::from(1)), ), RuntimeError::Sum, )); statements.insert( 0, - FlatStatement::Directive(FlatDirective { - inputs: directive_inputs, - outputs: directive_outputs, + FlatStatement::Directive(FlatDirective::new( + directive_outputs, solver, - }), + directive_inputs, + )), ); statements.extend( outputs .into_iter() .enumerate() - .map(|(index, e)| FlatStatement::Definition(Variable::public(index), e)), + .map(|(index, e)| FlatStatement::definition(Variable::public(index), e)), ); FlatFunctionIterator { arguments, statements: statements.into_iter(), return_count: bit_width, + module_map: ModuleMap::default(), } } @@ -661,7 +661,7 @@ mod tests { .map(|i| Variable::new(i + 1)) .collect(), Solver::bits(Bn128Field::get_required_bits()), - vec![Variable::new(0)] + vec![Variable::new(0).into()] )) ); assert_eq!( @@ -709,9 +709,9 @@ mod tests { // bellman variable #0: index 0 should equal 1 assert_eq!( compiled.statements[1], - FlatStatement::Condition( + FlatStatement::condition( Variable::new(0).into(), - FlatExpression::Number(Bn128Field::from(1)), + FlatExpression::value(Bn128Field::from(1)), RuntimeError::BellmanOneBinding ) ); @@ -719,7 +719,7 @@ mod tests { // bellman input #0: index 1 should equal zokrates input #0: index v_count assert_eq!( compiled.statements[2], - FlatStatement::Condition( + FlatStatement::condition( Variable::new(1).into(), Variable::new(26936).into(), RuntimeError::BellmanInputBinding diff --git a/zokrates_ast/src/common/expressions.rs b/zokrates_ast/src/common/expressions.rs new file mode 100644 index 000000000..01481ce6a --- /dev/null +++ b/zokrates_ast/src/common/expressions.rs @@ -0,0 +1,280 @@ +use derivative::Derivative; +use num_bigint::BigUint; +use serde::{Deserialize, Serialize}; + +use super::operators::OpEq; +use super::{operators::OperatorStr, Span, WithSpan}; +use std::fmt; +use std::marker::PhantomData; + +#[derive(Derivative)] +#[derivative(PartialOrd, PartialEq, Eq, Hash, Ord)] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct BinaryExpression { + #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Hash = "ignore")] + pub span: Option, + pub left: Box, + pub right: Box, + operator: PhantomData, + output: PhantomData, +} + +impl BinaryExpression { + pub fn new(left: L, right: R) -> Self { + Self { + span: None, + left: Box::new(left), + right: Box::new(right), + operator: PhantomData, + output: PhantomData, + } + } +} + +impl fmt::Display + for BinaryExpression +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "({} {} {})", self.left, Op::STR, self.right,) + } +} + +impl WithSpan for BinaryExpression { + fn span(mut self, span: Option) -> Self { + self.span = span; + self + } + + fn get_span(&self) -> Option { + self.span + } +} + +pub enum BinaryOrExpression { + Binary(BinaryExpression), + Expression(I), +} + +pub type EqExpression = BinaryExpression; + +#[derive(Derivative)] +#[derivative(PartialOrd, PartialEq, Eq, Hash, Ord)] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct UnaryExpression { + #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Hash = "ignore")] + pub span: Option, + pub inner: Box, + operator: PhantomData, + output: PhantomData, +} + +impl UnaryExpression { + pub fn new(inner: In) -> Self { + Self { + span: None, + inner: Box::new(inner), + operator: PhantomData, + output: PhantomData, + } + } +} + +impl fmt::Display + for UnaryExpression +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "({}{})", Op::STR, self.inner,) + } +} + +impl WithSpan for UnaryExpression { + fn span(mut self, span: Option) -> Self { + self.span = span; + self + } + + fn get_span(&self) -> Option { + self.span + } +} + +pub enum UnaryOrExpression { + Unary(UnaryExpression), + Expression(I), +} + +#[derive(Derivative)] +#[derivative(PartialOrd, PartialEq, Eq, Hash, Ord)] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct ValueExpression { + #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Hash = "ignore")] + pub span: Option, + pub value: V, +} + +impl ValueExpression { + pub fn new(value: V) -> Self { + Self { span: None, value } + } +} + +impl fmt::Display for ValueExpression { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.value,) + } +} + +pub type FieldValueExpression = ValueExpression; + +pub type BooleanValueExpression = ValueExpression; + +pub type UValueExpression = ValueExpression; + +pub type IntValueExpression = ValueExpression; + +pub enum ValueOrExpression { + Value(V), + Expression(I), +} + +#[derive(Derivative)] +#[derivative(PartialOrd, PartialEq, Eq, Hash, Ord)] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct IdentifierExpression { + #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Hash = "ignore")] + pub span: Option, + pub id: I, + pub ty: PhantomData, +} + +impl IdentifierExpression { + pub fn new(id: I) -> Self { + IdentifierExpression { + span: None, + id, + ty: PhantomData, + } + } +} + +impl fmt::Display for IdentifierExpression { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.id,) + } +} + +impl WithSpan for IdentifierExpression { + fn span(mut self, span: Option) -> Self { + self.span = span; + self + } + + fn get_span(&self) -> Option { + self.span + } +} + +pub enum IdentifierOrExpression { + Identifier(IdentifierExpression), + Expression(I), +} + +#[derive(Derivative)] +#[derivative(PartialOrd, PartialEq, Eq, Hash, Ord)] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct DefinitionStatement { + #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Hash = "ignore")] + pub span: Option, + pub assignee: A, + pub rhs: E, +} + +impl DefinitionStatement { + pub fn new(assignee: A, rhs: E) -> Self { + DefinitionStatement { + span: None, + assignee, + rhs, + } + } +} + +impl WithSpan for DefinitionStatement { + fn span(self, span: Option) -> Self { + Self { span, ..self } + } + + fn get_span(&self) -> Option { + self.span + } +} + +impl fmt::Display for DefinitionStatement { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{} = {}", self.assignee, self.rhs,) + } +} + +#[derive(Derivative)] +#[derivative(PartialOrd, PartialEq, Eq, Hash, Ord)] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct AssertionStatement { + #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Hash = "ignore")] + pub span: Option, + pub expression: B, + pub error: E, +} + +impl AssertionStatement { + pub fn new(expression: B, error: E) -> Self { + AssertionStatement { + span: None, + expression, + error, + } + } +} + +impl WithSpan for AssertionStatement { + fn span(self, span: Option) -> Self { + Self { span, ..self } + } + + fn get_span(&self) -> Option { + self.span + } +} + +#[derive(Derivative)] +#[derivative(PartialOrd, PartialEq, Eq, Hash, Ord)] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct ReturnStatement { + #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Hash = "ignore")] + pub span: Option, + pub inner: E, +} + +impl ReturnStatement { + pub fn new(e: E) -> Self { + ReturnStatement { + span: None, + inner: e, + } + } +} + +impl WithSpan for ReturnStatement { + fn span(self, span: Option) -> Self { + Self { span, ..self } + } + + fn get_span(&self) -> Option { + self.span + } +} + +impl fmt::Display for ReturnStatement { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "return {};", self.inner) + } +} diff --git a/zokrates_ast/src/common/flat/mod.rs b/zokrates_ast/src/common/flat/mod.rs new file mode 100644 index 000000000..d1892a6bb --- /dev/null +++ b/zokrates_ast/src/common/flat/mod.rs @@ -0,0 +1,5 @@ +pub mod parameter; +pub mod variable; + +pub use parameter::Parameter; +pub use variable::Variable; diff --git a/zokrates_ast/src/common/flat/parameter.rs b/zokrates_ast/src/common/flat/parameter.rs new file mode 100644 index 000000000..c4a86c962 --- /dev/null +++ b/zokrates_ast/src/common/flat/parameter.rs @@ -0,0 +1,63 @@ +use crate::common::{Span, WithSpan}; + +use super::variable::Variable; +use derivative::Derivative; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; +use std::fmt; + +#[derive(Derivative)] +#[derivative(PartialOrd, PartialEq, Eq, Hash, Ord)] +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +pub struct Parameter { + #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Hash = "ignore")] + pub span: Option, + pub id: Variable, + pub private: bool, +} + +impl WithSpan for Parameter { + fn span(mut self, span: Option) -> Self { + self.span = span; + self + } + + fn get_span(&self) -> Option { + self.span + } +} + +impl Parameter { + pub fn new(id: Variable, private: bool) -> Self { + Parameter { + id, + private, + span: None, + } + } + + pub fn public(v: Variable) -> Self { + Self::new(v, false) + } + + pub fn private(v: Variable) -> Self { + Self::new(v, true) + } +} + +impl fmt::Display for Parameter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let visibility = if self.private { "private " } else { "" }; + write!(f, "{}{}", visibility, self.id) + } +} + +impl Parameter { + pub fn apply_substitution(self, substitution: &HashMap) -> Parameter { + Parameter { + id: *substitution.get(&self.id).unwrap(), + private: self.private, + ..self + } + } +} diff --git a/zokrates_ast/src/common/flat/variable.rs b/zokrates_ast/src/common/flat/variable.rs new file mode 100644 index 000000000..ab460623c --- /dev/null +++ b/zokrates_ast/src/common/flat/variable.rs @@ -0,0 +1,102 @@ +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; +use std::fmt; +use std::io::{Read, Write}; + +// A variable in a constraint system +// id > 0 for intermediate variables +// id == 0 for ~one +// id < 0 for public outputs +#[derive(Serialize, Deserialize, Clone, PartialEq, Hash, Eq, Ord, PartialOrd, Copy)] +pub struct Variable { + pub id: isize, +} + +impl Variable { + pub fn new(id: usize) -> Self { + Variable { + id: 1 + id as isize, + } + } + + pub fn one() -> Self { + Variable { id: 0 } + } + + pub fn public(id: usize) -> Self { + Variable { + id: -(id as isize) - 1, + } + } + + pub fn id(&self) -> usize { + assert!(self.id > 0); + (self.id as usize) - 1 + } + + pub fn write(&self, mut writer: W) -> std::io::Result<()> { + writer.write_all(&self.id.to_le_bytes())?; + Ok(()) + } + + pub fn read(mut reader: R) -> std::io::Result { + let mut buf = [0; std::mem::size_of::()]; + reader.read_exact(&mut buf)?; + + Ok(Variable { + id: isize::from_le_bytes(buf), + }) + } +} + +impl fmt::Display for Variable { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.id { + 0 => write!(f, "~one"), + i if i > 0 => write!(f, "_{}", i - 1), + i => write!(f, "~out_{}", -(i + 1)), + } + } +} + +impl fmt::Debug for Variable { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.id { + 0 => write!(f, "~one"), + i if i > 0 => write!(f, "_{}", i - 1), + i => write!(f, "~out_{}", -(i + 1)), + } + } +} + +impl Variable { + pub fn apply_substitution(self, substitution: &HashMap) -> &Self { + substitution.get(&self).unwrap() + } + + pub fn is_output(&self) -> bool { + self.id < 0 + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn one() { + assert_eq!(format!("{}", Variable::one()), "~one"); + } + + #[test] + fn public() { + assert_eq!(format!("{}", Variable::public(0)), "~out_0"); + assert_eq!(format!("{}", Variable::public(42)), "~out_42"); + } + + #[test] + fn private() { + assert_eq!(format!("{}", Variable::new(0)), "_0"); + assert_eq!(format!("{}", Variable::new(42)), "_42"); + } +} diff --git a/zokrates_ast/src/common/fold.rs b/zokrates_ast/src/common/fold.rs new file mode 100644 index 000000000..98369bef1 --- /dev/null +++ b/zokrates_ast/src/common/fold.rs @@ -0,0 +1,7 @@ +pub trait Fold: Sized { + fn fold(self, f: &mut F) -> Self; +} + +pub trait ResultFold: Sized { + fn fold(self, f: &mut F) -> Result; +} diff --git a/zokrates_ast/src/common/mod.rs b/zokrates_ast/src/common/mod.rs index 13d23bfdb..186ea3caa 100644 --- a/zokrates_ast/src/common/mod.rs +++ b/zokrates_ast/src/common/mod.rs @@ -1,15 +1,28 @@ pub mod embed; mod error; +pub mod expressions; +pub mod flat; +mod fold; mod format_string; mod metadata; +pub mod operators; mod parameter; +mod position; mod solvers; +pub mod statements; +mod value; mod variable; pub use self::embed::FlatEmbed; pub use self::error::RuntimeError; +pub use self::fold::{Fold, ResultFold}; pub use self::metadata::SourceMetadata; pub use self::parameter::Parameter; -pub use self::solvers::Solver; +pub use self::position::{ + LocalSourceSpan, ModuleId, ModuleIdHash, ModuleMap, OwnedModuleId, Position, SourceSpan, Span, + WithSpan, +}; +pub use self::solvers::{RefCall, Solver}; +pub use self::value::Value; pub use self::variable::Variable; pub use format_string::FormatString; diff --git a/zokrates_ast/src/common/operators.rs b/zokrates_ast/src/common/operators.rs new file mode 100644 index 000000000..18a26cec2 --- /dev/null +++ b/zokrates_ast/src/common/operators.rs @@ -0,0 +1,143 @@ +pub trait OperatorStr { + const STR: &'static str; +} + +#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)] +pub struct OpAdd; + +impl OperatorStr for OpAdd { + const STR: &'static str = "+"; +} + +#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)] +pub struct OpSub; + +impl OperatorStr for OpSub { + const STR: &'static str = "-"; +} + +#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)] +pub struct OpFloorSub; + +impl OperatorStr for OpFloorSub { + const STR: &'static str = "- /* FLOOR_SUB */"; +} + +#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)] +pub struct OpMul; + +impl OperatorStr for OpMul { + const STR: &'static str = "*"; +} + +#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)] +pub struct OpDiv; + +impl OperatorStr for OpDiv { + const STR: &'static str = "/"; +} + +#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)] +pub struct OpRem; + +impl OperatorStr for OpRem { + const STR: &'static str = "%"; +} + +#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)] +pub struct OpPow; + +impl OperatorStr for OpPow { + const STR: &'static str = "**"; +} + +#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)] +pub struct OpEq; + +impl OperatorStr for OpEq { + const STR: &'static str = "=="; +} + +#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)] +pub struct OpLt; + +impl OperatorStr for OpLt { + const STR: &'static str = "<"; +} + +#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)] +pub struct OpLe; + +impl OperatorStr for OpLe { + const STR: &'static str = "<="; +} + +#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)] +pub struct OpGt; + +impl OperatorStr for OpGt { + const STR: &'static str = ">"; +} + +#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)] +pub struct OpGe; + +impl OperatorStr for OpGe { + const STR: &'static str = ">="; +} + +#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)] +pub struct OpXor; + +impl OperatorStr for OpXor { + const STR: &'static str = "^"; +} + +#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)] +pub struct OpOr; + +impl OperatorStr for OpOr { + const STR: &'static str = "|"; +} + +#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)] +pub struct OpAnd; + +impl OperatorStr for OpAnd { + const STR: &'static str = "&"; +} + +#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)] +pub struct OpLsh; + +impl OperatorStr for OpLsh { + const STR: &'static str = "<<"; +} + +#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)] +pub struct OpRsh; + +impl OperatorStr for OpRsh { + const STR: &'static str = ">>"; +} + +#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)] +pub struct OpNot; + +impl OperatorStr for OpNot { + const STR: &'static str = "!"; +} + +#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)] +pub struct OpNeg; + +impl OperatorStr for OpNeg { + const STR: &'static str = "-"; +} + +#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)] +pub struct OpPos; + +impl OperatorStr for OpPos { + const STR: &'static str = "+"; +} diff --git a/zokrates_ast/src/common/parameter.rs b/zokrates_ast/src/common/parameter.rs index 4b17395f4..e63b8be5c 100644 --- a/zokrates_ast/src/common/parameter.rs +++ b/zokrates_ast/src/common/parameter.rs @@ -1,46 +1,58 @@ -use super::variable::Variable; -use serde::{Deserialize, Serialize}; -use std::collections::HashMap; use std::fmt; -#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Clone, Copy)] -pub struct Parameter { - pub id: Variable, +use derivative::Derivative; +use serde::{Deserialize, Serialize}; + +use super::{Span, WithSpan}; + +#[derive(Derivative)] +#[derivative(PartialOrd, PartialEq, Hash, Eq)] +#[derive(Clone, Serialize, Deserialize, Debug)] +pub struct Parameter { + #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Hash = "ignore")] + pub span: Option, + pub id: V, pub private: bool, } -impl Parameter { - fn new(id: Variable, private: bool) -> Self { - Parameter { id, private } +impl From for Parameter { + fn from(v: V) -> Self { + Self::private(v) + } +} + +impl Parameter { + pub fn new(v: V, private: bool) -> Self { + Parameter { + span: None, + id: v, + private, + } } - pub fn public(v: Variable) -> Self { + pub fn public(v: V) -> Self { Self::new(v, false) } - pub fn private(v: Variable) -> Self { + pub fn private(v: V) -> Self { Self::new(v, true) } } -impl fmt::Display for Parameter { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let visibility = if self.private { "private " } else { "" }; - write!(f, "{}{}", visibility, self.id) +impl WithSpan for Parameter { + fn span(mut self, span: Option) -> Self { + self.span = span; + self } -} -impl fmt::Debug for Parameter { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Parameter(id: {:?})", self.id) + fn get_span(&self) -> Option { + self.span } } -impl Parameter { - pub fn apply_substitution(self, substitution: &HashMap) -> Parameter { - Parameter { - id: *substitution.get(&self.id).unwrap(), - private: self.private, - } +impl fmt::Display for Parameter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let visibility = if self.private { "private " } else { "" }; + write!(f, "{}{}", visibility, self.id) } } diff --git a/zokrates_ast/src/common/position.rs b/zokrates_ast/src/common/position.rs new file mode 100644 index 000000000..a817f0749 --- /dev/null +++ b/zokrates_ast/src/common/position.rs @@ -0,0 +1,242 @@ +use std::{ + collections::BTreeMap, + fmt, + path::{Path, PathBuf}, +}; + +use serde::{Deserialize, Serialize}; + +use super::FlatEmbed; + +#[derive(Clone, PartialEq, Eq, Copy, Hash, Default, PartialOrd, Ord, Deserialize, Serialize)] +pub struct LocalSourceSpan { + pub from: Position, + pub to: Position, +} + +pub type ModuleIdHash = u64; + +pub type ModuleId = Path; + +pub type OwnedModuleId = PathBuf; + +#[derive(Clone, PartialEq, Debug, Eq, Hash, Default, PartialOrd, Ord, Deserialize, Serialize)] +pub struct ModuleMap { + modules: BTreeMap, +} + +impl ModuleMap { + pub fn new>(i: I) -> Self { + Self { + modules: i.into_iter().map(|id| (hash(&id), id)).collect(), + } + } + + pub fn remap_prefix(self, prefix: &Path, to: &Path) -> Self { + Self { + modules: self + .modules + .into_iter() + .map(|(id, path)| { + ( + id, + path.strip_prefix(prefix) + .map(|path| to.join(path)) + .unwrap_or(path), + ) + }) + .collect(), + } + } +} + +#[derive(Clone, PartialEq, Eq, Copy, Hash, Default, PartialOrd, Ord, Deserialize, Serialize)] +pub struct Position { + pub line: usize, + pub col: usize, +} + +#[derive(Clone, PartialEq, Eq, Copy, Hash, PartialOrd, Ord, Deserialize, Serialize, Debug)] +pub enum Span { + Source(SourceSpan), + Embed(FlatEmbed), +} + +impl fmt::Display for Span { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Span::Source(s) => write!(f, "{}", s), + Span::Embed(e) => write!(f, "{:?}", e), + } + } +} + +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum ResolvedSpan { + Source(ResolvedSourceSpan), + Embed(FlatEmbed), +} + +impl fmt::Display for ResolvedSpan { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + ResolvedSpan::Source(s) => write!(f, "{}", s), + ResolvedSpan::Embed(e) => write!(f, "{:?}", e), + } + } +} + +impl Span { + pub fn resolve(self, map: &ModuleMap) -> ResolvedSpan { + match self { + Span::Source(s) => ResolvedSpan::Source(ResolvedSourceSpan { + module: map.modules.get(&s.module).cloned().unwrap(), + from: s.from, + to: s.to, + }), + Span::Embed(s) => ResolvedSpan::Embed(s), + } + } +} + +#[derive(Clone, PartialEq, Eq, Copy, Hash, Default, PartialOrd, Ord, Deserialize, Serialize)] +pub struct SourceSpan { + pub module: ModuleIdHash, + pub from: Position, + pub to: Position, +} + +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct ResolvedSourceSpan { + pub module: OwnedModuleId, + pub from: Position, + pub to: Position, +} + +impl From for Span { + fn from(span: SourceSpan) -> Self { + Self::Source(span) + } +} + +impl From for Span { + fn from(embed: FlatEmbed) -> Self { + Self::Embed(embed) + } +} + +impl SourceSpan { + pub fn mock() -> Self { + Self { + module: hash(&OwnedModuleId::default()), + from: Position::mock(), + to: Position::mock(), + } + } +} + +pub trait WithSpan: Sized { + fn span(self, _: Option) -> Self; + + fn with_span>(self, span: S) -> Self { + self.span(Some(span.into())) + } + + fn get_span(&self) -> Option; +} + +fn hash(id: &ModuleId) -> u64 { + use std::collections::hash_map::DefaultHasher; + use std::hash::{Hash, Hasher}; + + let mut hasher = DefaultHasher::new(); + id.hash(&mut hasher); + hasher.finish() +} + +impl LocalSourceSpan { + pub fn in_module(self, module_id: &ModuleId) -> SourceSpan { + SourceSpan { + module: hash(module_id), + from: self.from, + to: self.to, + } + } + + pub fn mock() -> Self { + Self { + from: Position::mock(), + to: Position::mock(), + } + } +} + +impl Position { + pub fn col(&self, delta: isize) -> Position { + assert!(self.col <= isize::max_value() as usize); + assert!(self.col as isize >= delta); + Position { + line: self.line, + col: (self.col as isize + delta) as usize, + } + } + + pub fn mock() -> Self { + Position { line: 42, col: 42 } + } +} +impl fmt::Display for Position { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}:{}", self.line, self.col) + } +} +impl fmt::Debug for Position { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self) + } +} + +impl fmt::Display for SourceSpan { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.from) + } +} +impl fmt::Debug for SourceSpan { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self) + } +} + +impl fmt::Display for ResolvedSourceSpan { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "{}:{} (until {})", + self.module.display(), + self.from, + self.to + ) + } +} + +#[test] +fn position_col() { + let pos = Position { + line: 100, + col: 258, + }; + assert_eq!( + pos.col(26), + Position { + line: 100, + col: 284, + } + ); + assert_eq!( + pos.col(-23), + Position { + line: 100, + col: 235, + } + ); +} diff --git a/zokrates_ast/src/common/solvers.rs b/zokrates_ast/src/common/solvers.rs index 9b4f5c900..eaaf2a70b 100644 --- a/zokrates_ast/src/common/solvers.rs +++ b/zokrates_ast/src/common/solvers.rs @@ -2,6 +2,12 @@ use crate::zir::ZirFunction; use serde::{Deserialize, Serialize}; use std::fmt; +#[derive(Clone, PartialEq, Debug, Serialize, Deserialize, Hash, Eq)] +pub struct RefCall { + pub index: usize, + pub signature: (usize, usize), +} + #[derive(Clone, PartialEq, Debug, Serialize, Deserialize, Hash, Eq)] pub enum Solver<'ast, T> { ConditionEq, @@ -14,6 +20,7 @@ pub enum Solver<'ast, T> { EuclideanDiv, #[serde(borrow)] Zir(ZirFunction<'ast, T>), + Ref(RefCall), #[cfg(feature = "bellman")] Sha256Round, #[cfg(feature = "ark")] @@ -32,6 +39,7 @@ impl<'ast, T> fmt::Display for Solver<'ast, T> { Solver::ShaCh => write!(f, "ShaCh"), Solver::EuclideanDiv => write!(f, "EuclideanDiv"), Solver::Zir(_) => write!(f, "Zir(..)"), + Solver::Ref(call) => write!(f, "Ref@{}", call.index), #[cfg(feature = "bellman")] Solver::Sha256Round => write!(f, "Sha256Round"), #[cfg(feature = "ark")] @@ -51,7 +59,8 @@ impl<'ast, T> Solver<'ast, T> { Solver::ShaAndXorAndXorAnd => (3, 1), Solver::ShaCh => (3, 1), Solver::EuclideanDiv => (2, 2), - Solver::Zir(f) => (f.arguments.len(), 1), + Solver::Zir(f) => (f.signature.inputs.len(), f.signature.outputs.len()), + Solver::Ref(c) => c.signature, #[cfg(feature = "bellman")] Solver::Sha256Round => (768, 26935), #[cfg(feature = "ark")] diff --git a/zokrates_ast/src/common/statements.rs b/zokrates_ast/src/common/statements.rs new file mode 100644 index 000000000..ba67b8283 --- /dev/null +++ b/zokrates_ast/src/common/statements.rs @@ -0,0 +1,278 @@ +use derivative::Derivative; +use serde::{Deserialize, Serialize}; + +use crate::Solver; + +use super::{FormatString, SourceMetadata}; +use super::{Span, WithSpan}; +use std::fmt; + +#[derive(Derivative)] +#[derivative(PartialOrd, PartialEq, Eq, Hash, Ord)] +#[derive(Clone, Debug)] +pub struct DefinitionStatement { + #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Hash = "ignore")] + pub span: Option, + pub assignee: A, + pub rhs: E, +} + +impl DefinitionStatement { + pub fn new(assignee: A, rhs: E) -> Self { + DefinitionStatement { + span: None, + assignee, + rhs, + } + } +} + +impl WithSpan for DefinitionStatement { + fn span(self, span: Option) -> Self { + Self { span, ..self } + } + + fn get_span(&self) -> Option { + self.span + } +} + +impl fmt::Display for DefinitionStatement { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{} = {};", self.assignee, self.rhs,) + } +} + +#[derive(Derivative)] +#[derivative(PartialOrd, PartialEq, Eq, Hash, Ord)] +#[derive(Clone, Debug)] +pub struct AssertionStatement { + #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Hash = "ignore")] + pub span: Option, + pub expression: B, + pub error: E, +} + +impl AssertionStatement { + pub fn new(expression: B, error: E) -> Self { + AssertionStatement { + span: None, + expression, + error, + } + } +} + +impl WithSpan for AssertionStatement { + fn span(self, span: Option) -> Self { + Self { span, ..self } + } + + fn get_span(&self) -> Option { + self.span + } +} + +#[derive(Derivative)] +#[derivative(PartialOrd, PartialEq, Eq, Hash, Ord)] +#[derive(Clone, Debug)] +pub struct ReturnStatement { + #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Hash = "ignore")] + pub span: Option, + pub inner: E, +} + +impl ReturnStatement { + pub fn new(e: E) -> Self { + ReturnStatement { + span: None, + inner: e, + } + } +} + +impl WithSpan for ReturnStatement { + fn span(self, span: Option) -> Self { + Self { span, ..self } + } + + fn get_span(&self) -> Option { + self.span + } +} + +impl fmt::Display for ReturnStatement { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "return {};", self.inner) + } +} + +#[derive(Derivative)] +#[derivative(PartialOrd, PartialEq, Eq, Hash, Ord)] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct LogStatement { + #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Hash = "ignore")] + pub span: Option, + pub format_string: FormatString, + pub expressions: Vec, +} + +impl LogStatement { + pub fn new(format_string: FormatString, expressions: Vec) -> Self { + LogStatement { + span: None, + format_string, + expressions, + } + } +} + +impl WithSpan for LogStatement { + fn span(self, span: Option) -> Self { + Self { span, ..self } + } + + fn get_span(&self) -> Option { + self.span + } +} + +impl fmt::Display for LogStatement { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "log({}, {});", + self.format_string, + self.expressions + .iter() + .map(|e| e.to_string()) + .collect::>() + .join(", ") + ) + } +} + +#[derive(Derivative, Clone, Debug, Serialize, Deserialize)] +#[derivative(Hash, PartialEq, Eq)] +pub struct DirectiveStatement { + #[derivative(Hash = "ignore", PartialEq = "ignore")] + pub span: Option, + pub inputs: Vec, + pub outputs: Vec, + pub solver: S, +} + +impl<'ast, T, I, O> DirectiveStatement> { + pub fn new(outputs: Vec, solver: Solver<'ast, T>, inputs: Vec) -> Self { + let (in_len, out_len) = solver.get_signature(); + assert_eq!(in_len, inputs.len()); + assert_eq!(out_len, outputs.len()); + Self { + span: None, + inputs, + outputs, + solver, + } + } +} + +impl WithSpan for DirectiveStatement { + fn span(mut self, span: Option) -> Self { + self.span = span; + self + } + + fn get_span(&self) -> Option { + self.span + } +} + +impl fmt::Display + for DirectiveStatement +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "# {} = {}({})", + self.outputs + .iter() + .map(|o| format!("{}", o)) + .collect::>() + .join(", "), + self.solver, + self.inputs + .iter() + .map(|i| format!("{}", i)) + .collect::>() + .join(", ") + ) + } +} + +#[derive(Derivative)] +#[derivative(PartialEq, Eq, Hash, PartialOrd, Ord)] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct AssemblyAssignment { + #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Hash = "ignore")] + pub span: Option, + pub assignee: A, + pub expression: E, +} + +impl AssemblyAssignment { + pub fn new(assignee: A, expression: E) -> Self { + Self { + span: None, + assignee, + expression, + } + } +} + +impl WithSpan for AssemblyAssignment { + fn span(self, span: Option) -> Self { + Self { span, ..self } + } + + fn get_span(&self) -> Option { + self.span + } +} + +#[derive(Derivative)] +#[derivative(PartialEq, Eq, Hash, PartialOrd, Ord)] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct AssemblyConstraint { + #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Hash = "ignore")] + pub span: Option, + pub left: E, + pub right: E, + pub metadata: SourceMetadata, +} + +impl AssemblyConstraint { + pub fn new(left: E, right: E, metadata: SourceMetadata) -> Self { + Self { + span: None, + left, + right, + metadata, + } + } +} + +impl WithSpan for AssemblyConstraint { + fn span(self, span: Option) -> Self { + Self { span, ..self } + } + + fn get_span(&self) -> Option { + self.span + } +} + +impl fmt::Display for AssemblyConstraint { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{} === {};", self.left, self.right) + } +} diff --git a/zokrates_ast/src/common/value.rs b/zokrates_ast/src/common/value.rs new file mode 100644 index 000000000..af204a813 --- /dev/null +++ b/zokrates_ast/src/common/value.rs @@ -0,0 +1,3 @@ +pub trait Value { + type Value: Clone; +} diff --git a/zokrates_ast/src/common/variable.rs b/zokrates_ast/src/common/variable.rs index 983e9e178..c5556805a 100644 --- a/zokrates_ast/src/common/variable.rs +++ b/zokrates_ast/src/common/variable.rs @@ -1,111 +1,42 @@ +use derivative::Derivative; use serde::{Deserialize, Serialize}; -use std::collections::HashMap; use std::fmt; -// A variable in a constraint system -// id > 0 for intermediate variables -// id == 0 for ~one -// id < 0 for public outputs -#[derive(Serialize, Deserialize, Clone, PartialEq, Hash, Eq, Ord, PartialOrd, Copy)] -pub struct Variable { - pub id: isize, -} - -impl Variable { - pub fn new(id: usize) -> Self { - Variable { - id: 1 + id as isize, - } - } +use super::{Span, WithSpan}; - pub fn one() -> Self { - Variable { id: 0 } - } - - pub fn public(id: usize) -> Self { - Variable { - id: -(id as isize) - 1, - } - } +#[derive(Derivative)] +#[derivative(PartialOrd, PartialEq, Hash, Eq, Ord)] +#[derive(Clone, Serialize, Deserialize, Debug)] +pub struct Variable { + #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Hash = "ignore")] + pub span: Option, + pub id: I, + pub ty: T, +} - pub fn id(&self) -> usize { - assert!(self.id > 0); - (self.id as usize) - 1 +impl WithSpan for Variable { + fn span(mut self, span: Option) -> Self { + self.span = span; + self } - pub fn try_from_human_readable(s: &str) -> Result { - if s == "~one" { - return Ok(Variable::one()); - } - - let mut public = s.split("~out_"); - match public.nth(1) { - Some(v) => { - let v = v.parse().map_err(|_| s)?; - Ok(Variable::public(v)) - } - None => { - let mut private = s.split('_'); - match private.nth(1) { - Some(v) => { - let v = v.parse().map_err(|_| s)?; - Ok(Variable::new(v)) - } - None => Err(s), - } - } - } + fn get_span(&self) -> Option { + self.span } } -impl fmt::Display for Variable { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self.id { - 0 => write!(f, "~one"), - i if i > 0 => write!(f, "_{}", i - 1), - i => write!(f, "~out_{}", -(i + 1)), +impl Variable { + pub fn new>(id: J, ty: T) -> Self { + Self { + span: None, + id: id.into(), + ty, } } } -impl fmt::Debug for Variable { +impl fmt::Display for Variable { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self.id { - 0 => write!(f, "~one"), - i if i > 0 => write!(f, "_{}", i - 1), - i => write!(f, "~out_{}", -(i + 1)), - } - } -} - -impl Variable { - pub fn apply_substitution(self, substitution: &HashMap) -> &Self { - substitution.get(&self).unwrap() - } - - pub fn is_output(&self) -> bool { - self.id < 0 - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn one() { - assert_eq!(format!("{}", Variable::one()), "~one"); - } - - #[test] - fn public() { - assert_eq!(format!("{}", Variable::public(0)), "~out_0"); - assert_eq!(format!("{}", Variable::public(42)), "~out_42"); - } - - #[test] - fn private() { - assert_eq!(format!("{}", Variable::new(0)), "_0"); - assert_eq!(format!("{}", Variable::new(42)), "_42"); + write!(f, "{} {}", self.ty, self.id,) } } diff --git a/zokrates_ast/src/flat/folder.rs b/zokrates_ast/src/flat/folder.rs index ce50d7dac..539e02ebe 100644 --- a/zokrates_ast/src/flat/folder.rs +++ b/zokrates_ast/src/flat/folder.rs @@ -1,9 +1,18 @@ // Generic walk through an IR AST. Not mutating in place use super::*; -use crate::common::Variable; +use crate::common::{ + expressions::{BinaryOrExpression, IdentifierOrExpression}, + flat::Variable, + Fold, WithSpan, +}; use zokrates_field::Field; +impl<'ast, T: Field, F: Folder<'ast, T>> Fold for FlatExpression { + fn fold(self, f: &mut F) -> Self { + f.fold_expression(self) + } +} pub trait Folder<'ast, T: Field>: Sized { fn fold_program(&mut self, p: FlatProg<'ast, T>) -> FlatProg<'ast, T> { fold_program(self, p) @@ -25,6 +34,20 @@ pub trait Folder<'ast, T: Field>: Sized { fold_expression(self, e) } + fn fold_binary_expression, R: Fold, E>( + &mut self, + e: BinaryExpression, + ) -> BinaryOrExpression> { + fold_binary_expression(self, e) + } + + fn fold_identifier_expression( + &mut self, + e: IdentifierExpression>, + ) -> IdentifierOrExpression, FlatExpression> { + fold_identifier_expression(self, e) + } + fn fold_directive(&mut self, d: FlatDirective<'ast, T>) -> FlatDirective<'ast, T> { fold_directive(self, d) } @@ -45,7 +68,7 @@ pub fn fold_program<'ast, T: Field, F: Folder<'ast, T>>( .into_iter() .flat_map(|s| f.fold_statement(s)) .collect(), - return_count: p.return_count, + ..p } } @@ -54,25 +77,27 @@ pub fn fold_statement<'ast, T: Field, F: Folder<'ast, T>>( s: FlatStatement<'ast, T>, ) -> Vec> { match s { - FlatStatement::Block(statements) => vec![FlatStatement::Block( + FlatStatement::Condition(s) => vec![FlatStatement::condition( + f.fold_expression(s.quad), + f.fold_expression(s.lin), + s.error, + )], + FlatStatement::Block(statements) => vec![FlatStatement::block( statements + .inner .into_iter() .flat_map(|s| f.fold_statement(s)) .collect(), )], - FlatStatement::Condition(left, right, error) => vec![FlatStatement::Condition( - f.fold_expression(left), - f.fold_expression(right), - error, - )], - FlatStatement::Definition(v, e) => vec![FlatStatement::Definition( - f.fold_variable(v), - f.fold_expression(e), + FlatStatement::Definition(s) => vec![FlatStatement::definition( + f.fold_variable(s.assignee), + f.fold_expression(s.rhs), )], FlatStatement::Directive(d) => vec![FlatStatement::Directive(f.fold_directive(d))], - FlatStatement::Log(s, e) => vec![FlatStatement::Log( - s, - e.into_iter() + FlatStatement::Log(s) => vec![FlatStatement::log( + s.format_string, + s.expressions + .into_iter() .map(|(t, e)| (t, e.into_iter().map(|e| f.fold_expression(e)).collect())) .collect(), )], @@ -84,20 +109,45 @@ pub fn fold_expression<'ast, T: Field, F: Folder<'ast, T>>( e: FlatExpression, ) -> FlatExpression { match e { - FlatExpression::Number(n) => FlatExpression::Number(n), - FlatExpression::Identifier(id) => FlatExpression::Identifier(f.fold_variable(id)), - FlatExpression::Add(box left, box right) => { - FlatExpression::Add(box f.fold_expression(left), box f.fold_expression(right)) - } - FlatExpression::Sub(box left, box right) => { - FlatExpression::Sub(box f.fold_expression(left), box f.fold_expression(right)) - } - FlatExpression::Mult(box left, box right) => { - FlatExpression::Mult(box f.fold_expression(left), box f.fold_expression(right)) - } + FlatExpression::Value(n) => FlatExpression::Value(n), + FlatExpression::Identifier(id) => match f.fold_identifier_expression(id) { + IdentifierOrExpression::Identifier(e) => FlatExpression::Identifier(e), + IdentifierOrExpression::Expression(e) => e, + }, + FlatExpression::Add(e) => match f.fold_binary_expression(e) { + BinaryOrExpression::Binary(e) => FlatExpression::Add(e), + BinaryOrExpression::Expression(e) => e, + }, + FlatExpression::Sub(e) => match f.fold_binary_expression(e) { + BinaryOrExpression::Binary(e) => FlatExpression::Sub(e), + BinaryOrExpression::Expression(e) => e, + }, + FlatExpression::Mult(e) => match f.fold_binary_expression(e) { + BinaryOrExpression::Binary(e) => FlatExpression::Mult(e), + BinaryOrExpression::Expression(e) => e, + }, } } +fn fold_identifier_expression<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + e: IdentifierExpression>, +) -> IdentifierOrExpression, FlatExpression> { + let id = f.fold_variable(e.id); + + IdentifierOrExpression::Identifier(IdentifierExpression { id, ..e }) +} + +fn fold_binary_expression<'ast, T: Field, F: Folder<'ast, T>, Op, L: Fold, R: Fold, E>( + f: &mut F, + e: BinaryExpression, +) -> BinaryOrExpression> { + let left = e.left.fold(f); + let right = e.right.fold(f); + + BinaryOrExpression::Binary(BinaryExpression::new(left, right).span(e.span)) +} + pub fn fold_directive<'ast, T: Field, F: Folder<'ast, T>>( f: &mut F, ds: FlatDirective<'ast, T>, @@ -116,7 +166,7 @@ pub fn fold_directive<'ast, T: Field, F: Folder<'ast, T>>( pub fn fold_argument<'ast, T: Field, F: Folder<'ast, T>>(f: &mut F, a: Parameter) -> Parameter { Parameter { id: f.fold_variable(a.id), - private: a.private, + ..a } } diff --git a/zokrates_ast/src/flat/mod.rs b/zokrates_ast/src/flat/mod.rs index 015e670a5..44bd42573 100644 --- a/zokrates_ast/src/flat/mod.rs +++ b/zokrates_ast/src/flat/mod.rs @@ -8,11 +8,20 @@ pub mod folder; pub mod utils; +use crate::common; +pub use crate::common::flat::Parameter; +pub use crate::common::flat::Variable; +use crate::common::statements::DirectiveStatement; use crate::common::FormatString; -pub use crate::common::Parameter; +use crate::common::ModuleMap; pub use crate::common::RuntimeError; -pub use crate::common::Variable; +use crate::common::{ + expressions::{BinaryExpression, IdentifierExpression, ValueExpression}, + operators::*, +}; +use crate::common::{Span, WithSpan}; +use derivative::Derivative; pub use utils::{ flat_expression_from_bits, flat_expression_from_expression_summands, flat_expression_from_variable_summands, @@ -32,6 +41,8 @@ pub type FlatProgIterator<'ast, T, I> = FlatFunctionIterator<'ast, T, I>; #[derive(Clone, PartialEq, Eq, Debug)] pub struct FlatFunctionIterator<'ast, T, I: IntoIterator>> { + /// The map of the modules for sourcemaps + pub module_map: ModuleMap, /// Arguments of the function pub arguments: Vec, /// Vector of statements that are executed when running the function @@ -46,6 +57,7 @@ impl<'ast, T, I: IntoIterator>> FlatFunctionIterat statements: self.statements.into_iter().collect(), arguments: self.arguments, return_count: self.return_count, + module_map: self.module_map, } } } @@ -70,45 +82,155 @@ impl<'ast, T: Field> fmt::Display for FlatFunction<'ast, T> { } } -/// Calculates a flattened function based on a R1CS (A, B, C) and returns that flattened function: -/// * The Rank 1 Constraint System (R1CS) is defined as: -/// * `* = ` for a witness `x` -/// * Since the matrices in R1CS are usually sparse, the following encoding is used: -/// * For each constraint (i.e., row in the R1CS), only non-zero values are supplied and encoded as a tuple (index, value). -/// -/// # Arguments -/// -/// * r1cs - R1CS in standard JSON data format +pub type DefinitionStatement = + common::expressions::DefinitionStatement>; +pub type LogStatement = common::statements::LogStatement<(ConcreteType, Vec>)>; +pub type FlatDirective<'ast, T> = + common::statements::DirectiveStatement, Variable, Solver<'ast, T>>; -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Derivative)] +#[derivative(PartialEq, Hash)] +#[derive(Clone, Debug)] +pub struct BlockStatement<'ast, T> { + #[derivative(PartialEq = "ignore", Hash = "ignore")] + pub span: Option, + pub inner: Vec>, +} + +impl<'ast, T> BlockStatement<'ast, T> { + pub fn new(inner: Vec>) -> Self { + BlockStatement { span: None, inner } + } +} + +impl WithSpan for AssertionStatement { + fn span(self, span: Option) -> Self { + Self { span, ..self } + } + + fn get_span(&self) -> Option { + self.span + } +} + +#[derive(Derivative)] +#[derivative(PartialEq, Hash)] +#[derive(Clone, Debug)] +pub struct AssertionStatement { + #[derivative(PartialEq = "ignore", Hash = "ignore")] + pub span: Option, + pub quad: FlatExpression, + pub lin: FlatExpression, + pub error: RuntimeError, +} + +impl AssertionStatement { + pub fn new(lin: FlatExpression, quad: FlatExpression, error: RuntimeError) -> Self { + AssertionStatement { + span: None, + quad, + lin, + error, + } + } +} + +impl<'ast, T> WithSpan for BlockStatement<'ast, T> { + fn span(self, span: Option) -> Self { + Self { span, ..self } + } + + fn get_span(&self) -> Option { + self.span + } +} + +#[derive(Derivative)] +#[derivative(PartialEq, Hash)] +#[derive(Clone, Debug)] pub enum FlatStatement<'ast, T> { - Block(Vec>), - Condition(FlatExpression, FlatExpression, RuntimeError), - Definition(Variable, FlatExpression), + Condition(AssertionStatement), + Definition(DefinitionStatement), Directive(FlatDirective<'ast, T>), - Log(FormatString, Vec<(ConcreteType, Vec>)>), + Log(LogStatement), + Block(BlockStatement<'ast, T>), +} + +impl<'ast, T> FlatStatement<'ast, T> { + pub fn definition(assignee: Variable, rhs: FlatExpression) -> Self { + Self::Definition(DefinitionStatement::new(assignee, rhs)) + } + + pub fn condition(lin: FlatExpression, quad: FlatExpression, error: RuntimeError) -> Self { + Self::Condition(AssertionStatement::new(lin, quad, error)) + } + + pub fn log( + format_string: FormatString, + expressions: Vec<(ConcreteType, Vec>)>, + ) -> Self { + Self::Log(LogStatement::new(format_string, expressions)) + } + + pub fn directive( + outputs: Vec, + solver: Solver<'ast, T>, + inputs: Vec>, + ) -> Self { + Self::Directive(DirectiveStatement::new(outputs, solver, inputs)) + } + + pub fn block(inner: Vec>) -> Self { + Self::Block(BlockStatement::new(inner)) + } +} + +impl<'ast, T> WithSpan for FlatStatement<'ast, T> { + fn span(self, span: Option) -> Self { + use FlatStatement::*; + + match self { + Condition(e) => Condition(e.span(span)), + Definition(e) => Definition(e.span(span)), + Directive(e) => Directive(e.span(span)), + Log(e) => Log(e.span(span)), + Block(e) => Block(e.span(span)), + } + } + + fn get_span(&self) -> Option { + use FlatStatement::*; + + match self { + Condition(e) => e.get_span(), + Definition(e) => e.get_span(), + Directive(e) => e.get_span(), + Log(e) => e.get_span(), + Block(e) => e.get_span(), + } + } } impl<'ast, T: Field> fmt::Display for FlatStatement<'ast, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - FlatStatement::Block(ref statements) => { + FlatStatement::Definition(ref e) => write!(f, "{}", e), + FlatStatement::Condition(ref s) => { + write!(f, "{} == {} // {}", s.lin, s.quad, s.error) + } + FlatStatement::Block(ref s) => { writeln!(f, "{{")?; - for s in statements { + for s in &s.inner { writeln!(f, "{}", s)?; } writeln!(f, "}}") } - FlatStatement::Definition(ref lhs, ref rhs) => write!(f, "{} = {}", lhs, rhs), - FlatStatement::Condition(ref lhs, ref rhs, ref message) => { - write!(f, "{} == {} // {}", lhs, rhs, message) - } FlatStatement::Directive(ref d) => write!(f, "{}", d), - FlatStatement::Log(ref l, ref expressions) => write!( + FlatStatement::Log(ref s) => write!( f, "log(\"{}\"), {})", - l, - expressions + s.format_string, + s.expressions .iter() .map(|(_, e)| format!( "[{}]", @@ -130,20 +252,20 @@ impl<'ast, T: Field> FlatStatement<'ast, T> { substitution: &'ast HashMap, ) -> FlatStatement { match self { - FlatStatement::Block(statements) => FlatStatement::Block( - statements + FlatStatement::Definition(s) => FlatStatement::definition( + *s.assignee.apply_substitution(substitution), + s.rhs.apply_substitution(substitution), + ), + FlatStatement::Block(s) => FlatStatement::block( + s.inner .into_iter() .map(|s| s.apply_substitution(substitution)) .collect(), ), - FlatStatement::Definition(id, x) => FlatStatement::Definition( - *id.apply_substitution(substitution), - x.apply_substitution(substitution), - ), - FlatStatement::Condition(x, y, message) => FlatStatement::Condition( - x.apply_substitution(substitution), - y.apply_substitution(substitution), - message, + FlatStatement::Condition(s) => FlatStatement::condition( + s.quad.apply_substitution(substitution), + s.lin.apply_substitution(substitution), + s.error, ), FlatStatement::Directive(d) => { let outputs = d @@ -163,9 +285,10 @@ impl<'ast, T: Field> FlatStatement<'ast, T> { ..d }) } - FlatStatement::Log(l, e) => FlatStatement::Log( - l, - e.into_iter() + FlatStatement::Log(s) => FlatStatement::Log(LogStatement::new( + s.format_string, + s.expressions + .into_iter() .map(|(t, e)| { ( t, @@ -175,112 +298,98 @@ impl<'ast, T: Field> FlatStatement<'ast, T> { ) }) .collect(), - ), + )), } } } -#[derive(Clone, Hash, Debug, PartialEq, Eq)] -pub struct FlatDirective<'ast, T> { - pub inputs: Vec>, - pub outputs: Vec, - pub solver: Solver<'ast, T>, +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub enum FlatExpression { + Value(ValueExpression), + Identifier(IdentifierExpression), + Add(BinaryExpression), + Sub(BinaryExpression), + Mult(BinaryExpression), } -impl<'ast, T> FlatDirective<'ast, T> { - pub fn new>>( - outputs: Vec, - solver: Solver<'ast, T>, - inputs: Vec, - ) -> Self { - let (in_len, out_len) = solver.get_signature(); - assert_eq!(in_len, inputs.len()); - assert_eq!(out_len, outputs.len()); - FlatDirective { - solver, - inputs: inputs.into_iter().map(|i| i.into()).collect(), - outputs, - } +impl std::ops::Add for FlatExpression { + type Output = Self; + + fn add(self, other: Self) -> Self::Output { + FlatExpression::Add(BinaryExpression::new(self, other)) } } -impl<'ast, T: Field> fmt::Display for FlatDirective<'ast, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "# {} = {}({})", - self.outputs - .iter() - .map(|o| o.to_string()) - .collect::>() - .join(", "), - self.solver, - self.inputs - .iter() - .map(|i| i.to_string()) - .collect::>() - .join(", ") - ) +impl std::ops::Sub for FlatExpression { + type Output = Self; + + fn sub(self, other: Self) -> Self::Output { + FlatExpression::Sub(BinaryExpression::new(self, other)) } } -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub enum FlatExpression { - Number(T), - Identifier(Variable), - Add(Box>, Box>), - Sub(Box>, Box>), - Mult(Box>, Box>), +impl std::ops::Mul for FlatExpression { + type Output = Self; + + fn mul(self, other: Self) -> Self::Output { + FlatExpression::Mult(BinaryExpression::new(self, other)) + } } impl From for FlatExpression { fn from(other: T) -> Self { - Self::Number(other) + Self::value(other) } } -impl FlatExpression { - pub fn apply_substitution( - self, - substitution: &HashMap, - ) -> FlatExpression { +impl BinaryExpression, FlatExpression, FlatExpression> { + fn apply_substitution(self, substitution: &HashMap) -> Self { + let left = self.left.apply_substitution(substitution); + let right = self.right.apply_substitution(substitution); + + Self::new(left, right).span(self.span) + } +} + +impl IdentifierExpression> { + fn apply_substitution(self, substitution: &HashMap) -> Self { + let id = *self.id.apply_substitution(substitution); + + IdentifierExpression { id, ..self } + } +} + +impl FlatExpression { + pub fn identifier(v: Variable) -> Self { + Self::Identifier(IdentifierExpression::new(v)) + } + + pub fn value(t: T) -> Self { + Self::Value(ValueExpression::new(t)) + } + + pub fn apply_substitution(self, substitution: &HashMap) -> Self { match self { - e @ FlatExpression::Number(_) => e, + e @ FlatExpression::Value(_) => e, FlatExpression::Identifier(id) => { - FlatExpression::Identifier(*id.apply_substitution(substitution)) + FlatExpression::Identifier(id.apply_substitution(substitution)) } - FlatExpression::Add(e1, e2) => FlatExpression::Add( - box e1.apply_substitution(substitution), - box e2.apply_substitution(substitution), - ), - FlatExpression::Sub(e1, e2) => FlatExpression::Sub( - box e1.apply_substitution(substitution), - box e2.apply_substitution(substitution), - ), - FlatExpression::Mult(e1, e2) => FlatExpression::Mult( - box e1.apply_substitution(substitution), - box e2.apply_substitution(substitution), - ), + FlatExpression::Add(e) => FlatExpression::Add(e.apply_substitution(substitution)), + FlatExpression::Sub(e) => FlatExpression::Sub(e.apply_substitution(substitution)), + FlatExpression::Mult(e) => FlatExpression::Mult(e.apply_substitution(substitution)), } } pub fn is_linear(&self) -> bool { match *self { - FlatExpression::Number(_) | FlatExpression::Identifier(_) => true, - FlatExpression::Add(ref x, ref y) | FlatExpression::Sub(ref x, ref y) => { - x.is_linear() && y.is_linear() - } - FlatExpression::Mult(ref x, ref y) => matches!( - (x.clone(), y.clone()), - (box FlatExpression::Number(_), box FlatExpression::Number(_)) - | ( - box FlatExpression::Number(_), - box FlatExpression::Identifier(_) - ) - | ( - box FlatExpression::Identifier(_), - box FlatExpression::Number(_) - ) + FlatExpression::Value(_) | FlatExpression::Identifier(_) => true, + FlatExpression::Add(ref e) => e.left.is_linear() && e.right.is_linear(), + FlatExpression::Sub(ref e) => e.left.is_linear() && e.right.is_linear(), + FlatExpression::Mult(ref e) => matches!( + (&*e.left, &*e.right), + (FlatExpression::Value(_), FlatExpression::Value(_)) + | (FlatExpression::Value(_), FlatExpression::Identifier(_)) + | (FlatExpression::Identifier(_), FlatExpression::Value(_)) ), } } @@ -289,18 +398,18 @@ impl FlatExpression { impl fmt::Display for FlatExpression { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - FlatExpression::Number(ref i) => write!(f, "{}", i), + FlatExpression::Value(ref i) => write!(f, "{}", i), FlatExpression::Identifier(ref var) => write!(f, "{}", var), - FlatExpression::Add(ref lhs, ref rhs) => write!(f, "({} + {})", lhs, rhs), - FlatExpression::Sub(ref lhs, ref rhs) => write!(f, "({} - {})", lhs, rhs), - FlatExpression::Mult(ref lhs, ref rhs) => write!(f, "({} * {})", lhs, rhs), + FlatExpression::Add(ref e) => write!(f, "{}", e), + FlatExpression::Sub(ref e) => write!(f, "{}", e), + FlatExpression::Mult(ref e) => write!(f, "{}", e), } } } impl From for FlatExpression { fn from(v: Variable) -> FlatExpression { - FlatExpression::Identifier(v) + FlatExpression::identifier(v) } } @@ -314,3 +423,27 @@ impl fmt::Display for Error { write!(f, "{}", self.message) } } + +impl WithSpan for FlatExpression { + fn span(self, span: Option) -> Self { + use FlatExpression::*; + match self { + Add(e) => Add(e.span(span)), + Sub(e) => Sub(e.span(span)), + Mult(e) => Mult(e.span(span)), + Value(e) => Value(e.span(span)), + Identifier(e) => Identifier(e.span(span)), + } + } + + fn get_span(&self) -> Option { + use FlatExpression::*; + match self { + Add(e) => e.get_span(), + Sub(e) => e.get_span(), + Mult(e) => e.get_span(), + Value(e) => e.get_span(), + Identifier(e) => e.get_span(), + } + } +} diff --git a/zokrates_ast/src/flat/utils.rs b/zokrates_ast/src/flat/utils.rs index 03239687c..7d1f1ff57 100644 --- a/zokrates_ast/src/flat/utils.rs +++ b/zokrates_ast/src/flat/utils.rs @@ -1,4 +1,5 @@ use crate::flat::{FlatExpression, Variable}; +use std::ops::*; use zokrates_field::Field; // util to convert a vector of `(coefficient, expression)` to a flat_expression @@ -7,16 +8,16 @@ pub fn flat_expression_from_expression_summands FlatExpression { match v.len() { - 0 => FlatExpression::Number(T::zero()), + 0 => FlatExpression::value(T::zero()), 1 => { let (val, var) = v[0].clone(); - FlatExpression::Mult(box FlatExpression::Number(val), box var.into()) + FlatExpression::mul(FlatExpression::value(val), var.into()) } n => { let (u, v) = v.split_at(n / 2); - FlatExpression::Add( - box flat_expression_from_expression_summands(u), - box flat_expression_from_expression_summands(v), + FlatExpression::add( + flat_expression_from_expression_summands(u), + flat_expression_from_expression_summands(v), ) } } @@ -34,19 +35,19 @@ pub fn flat_expression_from_bits(v: Vec>) -> FlatExp pub fn flat_expression_from_variable_summands(v: &[(T, usize)]) -> FlatExpression { match v.len() { - 0 => FlatExpression::Number(T::zero()), + 0 => FlatExpression::value(T::zero()), 1 => { - let (val, var) = v[0].clone(); - FlatExpression::Mult( - box FlatExpression::Number(val), - box FlatExpression::Identifier(Variable::new(var)), + let (val, var) = v[0]; + FlatExpression::mul( + FlatExpression::value(val), + FlatExpression::identifier(Variable::new(var)), ) } n => { let (u, v) = v.split_at(n / 2); - FlatExpression::Add( - box flat_expression_from_variable_summands(u), - box flat_expression_from_variable_summands(v), + FlatExpression::add( + flat_expression_from_variable_summands(u), + flat_expression_from_variable_summands(v), ) } } diff --git a/zokrates_ast/src/ir/check.rs b/zokrates_ast/src/ir/check.rs index 41cac7b0d..e4c1652ae 100644 --- a/zokrates_ast/src/ir/check.rs +++ b/zokrates_ast/src/ir/check.rs @@ -1,5 +1,5 @@ use crate::ir::folder::Folder; -use crate::ir::Directive; +use crate::ir::DirectiveStatement; use crate::ir::Parameter; use crate::ir::ProgIterator; use crate::ir::Statement; @@ -42,8 +42,11 @@ impl<'ast, T: Field> Folder<'ast, T> for UnconstrainedVariableDetector { self.variables.remove(&v); v } - fn fold_directive(&mut self, d: Directive<'ast, T>) -> Directive<'ast, T> { + fn fold_directive_statement( + &mut self, + d: DirectiveStatement<'ast, T>, + ) -> Vec> { self.variables.extend(d.outputs.iter()); - d + vec![Statement::Directive(d)] } } diff --git a/zokrates_ast/src/ir/clean.rs b/zokrates_ast/src/ir/clean.rs index b4fb8f445..1c58faff6 100644 --- a/zokrates_ast/src/ir/clean.rs +++ b/zokrates_ast/src/ir/clean.rs @@ -1,3 +1,5 @@ +use crate::common::WithSpan; + use super::folder::Folder; use super::{ProgIterator, Statement}; use zokrates_field::Field; @@ -8,20 +10,27 @@ pub struct Cleaner; impl<'ast, T: Field, I: IntoIterator>> ProgIterator<'ast, T, I> { pub fn clean(self) -> ProgIterator<'ast, T, impl IntoIterator>> { ProgIterator { + module_map: self.module_map, arguments: self.arguments, return_count: self.return_count, statements: self .statements .into_iter() .flat_map(|s| Cleaner::default().fold_statement(s)), + solvers: self.solvers, } } } impl<'ast, T: Field> Folder<'ast, T> for Cleaner { fn fold_statement(&mut self, s: Statement<'ast, T>) -> Vec> { + if s.get_span().is_none() { + eprintln!("Internal compiler warning: found a statement without source information. Please open an issue https://github.com/Zokrates/ZoKrates/issues/new?template=bug_report.md"); + } + match s { - Statement::Block(statements) => statements + Statement::Block(s) => s + .inner .into_iter() .flat_map(|s| self.fold_statement(s)) .collect(), diff --git a/zokrates_ast/src/ir/expression.rs b/zokrates_ast/src/ir/expression.rs index a32a1293c..b3dd59478 100644 --- a/zokrates_ast/src/ir/expression.rs +++ b/zokrates_ast/src/ir/expression.rs @@ -1,23 +1,35 @@ use super::Witness; -use crate::common::Variable; +use crate::common::{flat::Variable, Span, WithSpan}; +use derivative::Derivative; use serde::{Deserialize, Serialize}; use std::collections::btree_map::{BTreeMap, Entry}; use std::fmt; -use std::hash::Hash; use std::ops::{Add, Div, Mul, Sub}; use zokrates_field::Field; -#[derive(Debug, Clone, Serialize, Deserialize, Hash, PartialEq, Eq)] +#[derive(Derivative)] +#[derivative(PartialEq, Hash)] +#[derive(Debug, Clone, Serialize, Deserialize, Eq)] pub struct QuadComb { + #[derivative(PartialEq = "ignore", Hash = "ignore")] + pub span: Option, pub left: LinComb, pub right: LinComb, } -impl QuadComb { - pub fn from_linear_combinations(left: LinComb, right: LinComb) -> Self { - QuadComb { left, right } +impl WithSpan for QuadComb { + fn span(mut self, span: Option) -> Self { + self.span = span; + self + } + + fn get_span(&self) -> Option { + self.span } +} +impl QuadComb { + #[allow(clippy::result_large_err)] pub fn try_linear(self) -> Result, Self> { // identify `(k * ~ONE) * (lincomb)` and `(lincomb) * (k * ~ONE)` and return (k * lincomb) // if not, error out with the input @@ -30,7 +42,7 @@ impl QuadComb { Ok(coefficient) => Ok(self.right * &coefficient), Err(left) => match self.right.try_constant() { Ok(coefficient) => Ok(left * &coefficient), - Err(right) => Err(QuadComb::from_linear_combinations(left, right)), + Err(right) => Err(QuadComb::new(left, right)), }, } } @@ -44,7 +56,7 @@ impl From for LinComb { impl>> From for QuadComb { fn from(x: U) -> QuadComb { - QuadComb::from_linear_combinations(LinComb::one(), x.into()) + QuadComb::new(LinComb::one(), x.into()) } } @@ -54,21 +66,80 @@ impl fmt::Display for QuadComb { } } -#[derive(Clone, Debug, Serialize, Deserialize, Hash, PartialEq, Eq)] -pub struct LinComb(pub Vec<(Variable, T)>); +#[derive(Derivative)] +#[derivative(PartialEq, Hash)] +#[derive(Clone, Debug, Serialize, Deserialize, Eq)] +pub struct LinComb { + #[derivative(PartialEq = "ignore", Hash = "ignore")] + pub span: Option, + pub value: Vec<(Variable, T)>, +} + +#[derive(Derivative)] +#[derivative(PartialEq, Hash)] +#[derive(Clone, Debug, Serialize, Deserialize, Eq)] +pub struct CanonicalLinComb { + #[derivative(PartialEq = "ignore", Hash = "ignore")] + pub span: Option, + pub value: BTreeMap, +} + +impl WithSpan for CanonicalLinComb { + fn span(mut self, span: Option) -> Self { + self.span = span; + self + } -#[derive(PartialEq, PartialOrd, Clone, Eq, Ord, Hash, Debug, Serialize, Deserialize)] -pub struct CanonicalLinComb(pub BTreeMap); + fn get_span(&self) -> Option { + self.span + } +} -#[derive(PartialEq, PartialOrd, Clone, Eq, Ord, Hash, Debug, Serialize, Deserialize)] +#[derive(Derivative)] +#[derivative(PartialEq, Hash)] +#[derive(Clone, Debug, Serialize, Deserialize, Eq)] pub struct CanonicalQuadComb { + #[derivative(PartialEq = "ignore", Hash = "ignore")] + span: Option, left: CanonicalLinComb, right: CanonicalLinComb, } +impl WithSpan for CanonicalQuadComb { + fn span(mut self, span: Option) -> Self { + self.span = span; + self + } + + fn get_span(&self) -> Option { + self.span + } +} + +impl CanonicalQuadComb { + pub fn new(left: CanonicalLinComb, right: CanonicalLinComb) -> Self { + Self { + span: None, + left, + right, + } + } +} + +impl QuadComb { + pub fn new(left: LinComb, right: LinComb) -> Self { + Self { + span: None, + left, + right, + } + } +} + impl From> for QuadComb { fn from(q: CanonicalQuadComb) -> Self { QuadComb { + span: q.span, left: q.left.into(), right: q.right.into(), } @@ -77,42 +148,66 @@ impl From> for QuadComb { impl From> for LinComb { fn from(l: CanonicalLinComb) -> Self { - LinComb(l.0.into_iter().collect()) + LinComb { + span: l.span, + value: l.value.into_iter().collect(), + } + } +} + +impl CanonicalLinComb { + pub fn new(value: BTreeMap) -> Self { + Self { span: None, value } } } impl LinComb { + pub fn new(value: Vec<(Variable, T)>) -> Self { + Self { span: None, value } + } + pub fn summand>(mult: U, var: Variable) -> LinComb { let res = vec![(var, mult.into())]; - LinComb(res) + LinComb::new(res) } pub fn zero() -> LinComb { - LinComb(Vec::new()) + LinComb::new(Vec::new()) } pub fn is_zero(&self) -> bool { - self.0.is_empty() + self.value.is_empty() + } +} + +impl WithSpan for LinComb { + fn span(mut self, span: Option) -> Self { + self.span = span; + self + } + + fn get_span(&self) -> Option { + self.span } } impl LinComb { pub fn try_constant(self) -> Result { - match self.0.len() { + match self.value.len() { // if the lincomb is empty, it is reduceable to 0 0 => Ok(T::zero()), _ => { // take the first variable in the lincomb - let first = &self.0[0].0; + let first = &self.value[0].0; if first != &Variable::one() { return Err(self); } // all terms must contain the same variable - if self.0.iter().all(|element| element.0 == *first) { - Ok(self.0.into_iter().fold(T::zero(), |acc, e| acc + e.1)) + if self.value.iter().all(|element| element.0 == *first) { + Ok(self.value.into_iter().fold(T::zero(), |acc, e| acc + e.1)) } else { Err(self) } @@ -121,26 +216,26 @@ impl LinComb { } pub fn is_assignee(&self, witness: &Witness) -> bool { - self.0.len() == 1 - && self.0.get(0).unwrap().1 == T::from(1) - && !witness.0.contains_key(&self.0.get(0).unwrap().0) + self.value.len() == 1 + && self.value.get(0).unwrap().1 == T::from(1) + && !witness.0.contains_key(&self.value.get(0).unwrap().0) } pub fn try_summand(self) -> Result<(Variable, T), Self> { - match self.0.len() { + match self.value.len() { // if the lincomb is empty, it is not reduceable to a summand 0 => Err(self), _ => { // take the first variable in the lincomb - let first = &self.0[0].0; + let first = &self.value[0].0; - if self.0.iter().all(|element| + if self.value.iter().all(|element| // all terms must contain the same variable element.0 == *first) { Ok(( *first, - self.0.into_iter().fold(T::zero(), |acc, e| acc + e.1), + self.value.into_iter().fold(T::zero(), |acc, e| acc + e.1), )) } else { Err(self) @@ -156,32 +251,34 @@ impl LinComb { impl LinComb { pub fn into_canonical(self) -> CanonicalLinComb { - CanonicalLinComb( - self.0 - .into_iter() - .fold(BTreeMap::new(), |mut acc, (val, coeff)| { - // if we're adding 0 times some variable, we can ignore this term - if coeff != T::zero() { - match acc.entry(val) { - Entry::Occupied(o) => { - // if the new value is non zero, update, else remove the term entirely - if o.get().clone() + coeff.clone() != T::zero() { - *o.into_mut() = o.get().clone() + coeff; - } else { - o.remove(); - } - } - Entry::Vacant(v) => { - // We checked earlier but let's make sure we're not creating zero-coeff terms - assert!(coeff != T::zero()); - v.insert(coeff); + let span = self.get_span(); + + CanonicalLinComb::new(self.value.into_iter().fold( + BTreeMap::::new(), + |mut acc, (val, coeff)| { + // if we're adding 0 times some variable, we can ignore this term + if coeff != T::zero() { + match acc.entry(val) { + Entry::Occupied(o) => { + // if the new value is non zero, update, else remove the term entirely + if *o.get() + coeff != T::zero() { + *o.into_mut() = *o.get() + coeff; + } else { + o.remove(); } } + Entry::Vacant(v) => { + // We checked earlier but let's make sure we're not creating zero-coeff terms + assert!(coeff != T::zero()); + v.insert(coeff); + } } + } - acc - }), - ) + acc + }, + )) + .span(span) } pub fn reduce(self) -> Self { @@ -191,10 +288,8 @@ impl LinComb { impl QuadComb { pub fn into_canonical(self) -> CanonicalQuadComb { - CanonicalQuadComb { - left: self.left.into_canonical(), - right: self.right.into_canonical(), - } + CanonicalQuadComb::new(self.left.into_canonical(), self.right.into_canonical()) + .span(self.span) } pub fn reduce(self) -> Self { @@ -209,7 +304,7 @@ impl fmt::Display for LinComb { false => write!( f, "{}", - self.0 + self.value .iter() .map(|(k, v)| format!("{} * {}", v.to_compact_dec_string(), k)) .collect::>() @@ -222,7 +317,7 @@ impl fmt::Display for LinComb { impl From for LinComb { fn from(v: Variable) -> LinComb { let r = vec![(v, T::one())]; - LinComb(r) + LinComb::new(r) } } @@ -230,9 +325,9 @@ impl Add> for LinComb { type Output = LinComb; fn add(self, other: LinComb) -> LinComb { - let mut res = self.0; - res.extend(other.0); - LinComb(res) + let mut res = self.value; + res.extend(other.value); + LinComb::new(res) } } @@ -241,9 +336,14 @@ impl Sub> for LinComb { fn sub(self, other: LinComb) -> LinComb { // Concatenate with second vector that have negative coeffs - let mut res = self.0; - res.extend(other.0.into_iter().map(|(var, val)| (var, T::zero() - val))); - LinComb(res) + let mut res = self.value; + res.extend( + other + .value + .into_iter() + .map(|(var, val)| (var, T::zero() - val)), + ); + LinComb::new(res) } } @@ -255,10 +355,10 @@ impl Mul<&T> for LinComb { return self; } - LinComb( - self.0 + LinComb::new( + self.value .into_iter() - .map(|(var, coeff)| (var, coeff * scalar.clone())) + .map(|(var, coeff)| (var, coeff * scalar)) .collect(), ) } @@ -299,7 +399,7 @@ mod tests { (Variable::new(42), Bn128Field::from(1)), ]; - assert_eq!(c, LinComb(expected_vec)); + assert_eq!(c, LinComb::new(expected_vec)); } #[test] fn sub() { @@ -312,7 +412,7 @@ mod tests { (Variable::new(42), Bn128Field::from(-1)), ]; - assert_eq!(c, LinComb(expected_vec)); + assert_eq!(c, LinComb::new(expected_vec)); } #[test] @@ -331,35 +431,26 @@ mod tests { fn from_linear() { let a: LinComb = LinComb::summand(3, Variable::new(42)) + LinComb::summand(4, Variable::new(33)); - let expected = QuadComb { - left: LinComb::one(), - right: a.clone(), - }; + let expected = QuadComb::new(LinComb::one(), a.clone()); assert_eq!(QuadComb::from(a), expected); } #[test] fn zero() { let a: LinComb = LinComb::zero(); - let expected: QuadComb = QuadComb { - left: LinComb::one(), - right: LinComb::zero(), - }; + let expected: QuadComb = QuadComb::new(LinComb::one(), LinComb::zero()); assert_eq!(QuadComb::from(a), expected); } #[test] fn display() { - let a: QuadComb = QuadComb { - left: LinComb::summand(3, Variable::new(42)) - + LinComb::summand(4, Variable::new(33)), - right: LinComb::summand(1, Variable::new(21)), - }; + let a: QuadComb = QuadComb::new( + LinComb::summand(3, Variable::new(42)) + LinComb::summand(4, Variable::new(33)), + LinComb::summand(1, Variable::new(21)), + ); assert_eq!(&a.to_string(), "(3 * _42 + 4 * _33) * (1 * _21)"); - let a: QuadComb = QuadComb { - left: LinComb::zero(), - right: LinComb::summand(1, Variable::new(21)), - }; + let a: QuadComb = + QuadComb::new(LinComb::zero(), LinComb::summand(1, Variable::new(21))); assert_eq!(&a.to_string(), "(0) * (1 * _21)"); } } @@ -369,7 +460,7 @@ mod tests { #[test] fn try_summand() { - let summand = LinComb(vec![ + let summand = LinComb::new(vec![ (Variable::new(42), Bn128Field::from(1)), (Variable::new(42), Bn128Field::from(2)), (Variable::new(42), Bn128Field::from(3)), @@ -379,14 +470,14 @@ mod tests { Ok((Variable::new(42), Bn128Field::from(6))) ); - let not_summand = LinComb(vec![ + let not_summand = LinComb::new(vec![ (Variable::new(41), Bn128Field::from(1)), (Variable::new(42), Bn128Field::from(2)), (Variable::new(42), Bn128Field::from(3)), ]); assert!(not_summand.try_summand().is_err()); - let empty: LinComb = LinComb(vec![]); + let empty: LinComb = LinComb::new(vec![]); assert!(empty.try_summand().is_err()); } } diff --git a/zokrates_ast/src/ir/folder.rs b/zokrates_ast/src/ir/folder.rs index 6e67c15de..3b17c722f 100644 --- a/zokrates_ast/src/ir/folder.rs +++ b/zokrates_ast/src/ir/folder.rs @@ -1,7 +1,7 @@ // Generic walk through an IR AST. Not mutating in place use super::*; -use crate::common::Variable; +use crate::common::{flat::Variable, WithSpan}; use zokrates_field::Field; pub trait Folder<'ast, T: Field>: Sized { @@ -21,6 +21,29 @@ pub trait Folder<'ast, T: Field>: Sized { fold_statement(self, s) } + fn fold_statement_cases(&mut self, s: Statement<'ast, T>) -> Vec> { + fold_statement_cases(self, s) + } + + fn fold_constraint_statement(&mut self, s: ConstraintStatement) -> Vec> { + fold_constraint_statement(self, s) + } + + fn fold_directive_statement( + &mut self, + s: DirectiveStatement<'ast, T>, + ) -> Vec> { + fold_directive_statement(self, s) + } + + fn fold_log_statement(&mut self, s: LogStatement) -> Vec> { + fold_log_statement(self, s) + } + + fn fold_block_statement(&mut self, s: BlockStatement<'ast, T>) -> Vec> { + fold_block_statement(self, s) + } + fn fold_linear_combination(&mut self, e: LinComb) -> LinComb { fold_linear_combination(self, e) } @@ -28,10 +51,6 @@ pub trait Folder<'ast, T: Field>: Sized { fn fold_quadratic_combination(&mut self, es: QuadComb) -> QuadComb { fold_quadratic_combination(self, es) } - - fn fold_directive(&mut self, d: Directive<'ast, T>) -> Directive<'ast, T> { - fold_directive(self, d) - } } pub fn fold_program<'ast, T: Field, F: Folder<'ast, T>>( @@ -49,40 +68,73 @@ pub fn fold_program<'ast, T: Field, F: Folder<'ast, T>>( .into_iter() .flat_map(|s| f.fold_statement(s)) .collect(), - return_count: p.return_count, + ..p } } -pub fn fold_statement<'ast, T: Field, F: Folder<'ast, T>>( +pub fn fold_constraint_statement<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + s: ConstraintStatement, +) -> Vec> { + vec![Statement::constraint( + f.fold_quadratic_combination(s.quad), + f.fold_linear_combination(s.lin), + s.error, + )] +} + +pub fn fold_log_statement<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + s: LogStatement, +) -> Vec> { + vec![Statement::log( + s.format_string, + s.expressions + .into_iter() + .map(|(t, e)| { + ( + t, + e.into_iter() + .map(|e| f.fold_linear_combination(e)) + .collect(), + ) + }) + .collect(), + )] +} + +pub fn fold_block_statement<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + s: BlockStatement<'ast, T>, +) -> Vec> { + vec![Statement::block( + s.inner + .into_iter() + .flat_map(|s| f.fold_statement(s)) + .collect(), + )] +} + +fn fold_statement<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + s: Statement<'ast, T>, +) -> Vec> { + let span = s.get_span(); + f.fold_statement_cases(s) + .into_iter() + .map(|s| s.span(span)) + .collect() +} + +pub fn fold_statement_cases<'ast, T: Field, F: Folder<'ast, T>>( f: &mut F, s: Statement<'ast, T>, ) -> Vec> { match s { - Statement::Block(statements) => vec![Statement::Block( - statements - .into_iter() - .flat_map(|s| f.fold_statement(s)) - .collect(), - )], - Statement::Constraint(quad, lin, message) => vec![Statement::Constraint( - f.fold_quadratic_combination(quad), - f.fold_linear_combination(lin), - message, - )], - Statement::Directive(dir) => vec![Statement::Directive(f.fold_directive(dir))], - Statement::Log(l, e) => vec![Statement::Log( - l, - e.into_iter() - .map(|(t, e)| { - ( - t, - e.into_iter() - .map(|e| f.fold_linear_combination(e)) - .collect(), - ) - }) - .collect(), - )], + Statement::Constraint(s) => f.fold_constraint_statement(s), + Statement::Directive(s) => f.fold_directive_statement(s), + Statement::Log(s) => f.fold_log_statement(s), + Statement::Block(s) => f.fold_block_statement(s), } } @@ -90,28 +142,31 @@ pub fn fold_linear_combination<'ast, T: Field, F: Folder<'ast, T>>( f: &mut F, e: LinComb, ) -> LinComb { - LinComb( - e.0.into_iter() + LinComb::new( + e.value + .into_iter() .map(|(variable, coefficient)| (f.fold_variable(variable), coefficient)) .collect(), ) + .span(e.span) } pub fn fold_quadratic_combination<'ast, T: Field, F: Folder<'ast, T>>( f: &mut F, e: QuadComb, ) -> QuadComb { - QuadComb { - left: f.fold_linear_combination(e.left), - right: f.fold_linear_combination(e.right), - } + QuadComb::new( + f.fold_linear_combination(e.left), + f.fold_linear_combination(e.right), + ) + .span(e.span) } -pub fn fold_directive<'ast, T: Field, F: Folder<'ast, T>>( +pub fn fold_directive_statement<'ast, T: Field, F: Folder<'ast, T>>( f: &mut F, - ds: Directive<'ast, T>, -) -> Directive<'ast, T> { - Directive { + ds: DirectiveStatement<'ast, T>, +) -> Vec> { + vec![Statement::Directive(DirectiveStatement { inputs: ds .inputs .into_iter() @@ -119,13 +174,13 @@ pub fn fold_directive<'ast, T: Field, F: Folder<'ast, T>>( .collect(), outputs: ds.outputs.into_iter().map(|o| f.fold_variable(o)).collect(), ..ds - } + })] } pub fn fold_argument<'ast, T: Field, F: Folder<'ast, T>>(f: &mut F, a: Parameter) -> Parameter { Parameter { id: f.fold_variable(a.id), - private: a.private, + ..a } } diff --git a/zokrates_ast/src/ir/from_flat.rs b/zokrates_ast/src/ir/from_flat.rs index fc961cd85..f7f8c42f8 100644 --- a/zokrates_ast/src/ir/from_flat.rs +++ b/zokrates_ast/src/ir/from_flat.rs @@ -1,5 +1,8 @@ +use crate::common::statements::LogStatement; +use crate::common::WithSpan; use crate::flat::{FlatDirective, FlatExpression, FlatProgIterator, FlatStatement, Variable}; -use crate::ir::{Directive, LinComb, ProgIterator, QuadComb, Statement}; +use crate::ir::{DirectiveStatement, LinComb, ProgIterator, QuadComb, Statement}; +use std::ops::*; use zokrates_field::Field; impl QuadComb { @@ -8,9 +11,7 @@ impl QuadComb { match flat_expression.is_linear() { true => LinComb::from(flat_expression).into(), false => match flat_expression { - FlatExpression::Mult(box e1, box e2) => { - QuadComb::from_linear_combinations(e1.into(), e2.into()) - } + FlatExpression::Mult(e) => QuadComb::new((*e.left).into(), (*e.right).into()), e => unimplemented!("{}", e), }, } @@ -24,71 +25,76 @@ pub fn from_flat<'ast, T: Field, I: IntoIterator>> statements: flat_prog_iterator.statements.into_iter().map(Into::into), arguments: flat_prog_iterator.arguments, return_count: flat_prog_iterator.return_count, + module_map: flat_prog_iterator.module_map, + solvers: vec![], } } impl From> for LinComb { fn from(flat_expression: FlatExpression) -> LinComb { + let span = flat_expression.get_span(); + match flat_expression { - FlatExpression::Number(ref n) if *n == T::from(0) => LinComb::zero(), - FlatExpression::Number(n) => LinComb::summand(n, Variable::one()), - FlatExpression::Identifier(id) => LinComb::from(id), - FlatExpression::Add(box e1, box e2) => LinComb::from(e1) + LinComb::from(e2), - FlatExpression::Sub(box e1, box e2) => LinComb::from(e1) - LinComb::from(e2), - FlatExpression::Mult( - box FlatExpression::Number(n1), - box FlatExpression::Identifier(v1), - ) - | FlatExpression::Mult( - box FlatExpression::Identifier(v1), - box FlatExpression::Number(n1), - ) => LinComb::summand(n1, v1), - FlatExpression::Mult( - box FlatExpression::Number(n1), - box FlatExpression::Number(n2), - ) => LinComb::summand(n1 * n2, Variable::one()), - e => unreachable!("{}", e), + FlatExpression::Value(ref n) if n.value == T::from(0) => LinComb::zero(), + FlatExpression::Value(n) => LinComb::summand(n.value, Variable::one()), + FlatExpression::Identifier(id) => LinComb::from(id.id), + FlatExpression::Add(e) => LinComb::from(*e.left) + LinComb::from(*e.right), + FlatExpression::Sub(e) => LinComb::from(*e.left) - LinComb::from(*e.right), + FlatExpression::Mult(e) => match (*e.left, *e.right) { + (FlatExpression::Value(n1), FlatExpression::Identifier(v1)) + | (FlatExpression::Identifier(v1), FlatExpression::Value(n1)) => { + LinComb::summand(n1.value, v1.id) + } + (FlatExpression::Value(n1), FlatExpression::Value(n2)) => { + LinComb::summand(n1.value * n2.value, Variable::one()) + } + (left, right) => unreachable!("{}", FlatExpression::mul(left, right).span(e.span)), + }, } + .span(span) } } impl<'ast, T: Field> From> for Statement<'ast, T> { fn from(flat_statement: FlatStatement<'ast, T>) -> Statement<'ast, T> { + let span = flat_statement.get_span(); + match flat_statement { - FlatStatement::Block(statements) => { - Statement::Block(statements.into_iter().map(Statement::from).collect()) - } - FlatStatement::Condition(linear, quadratic, message) => match quadratic { - FlatExpression::Mult(box lhs, box rhs) => Statement::Constraint( - QuadComb::from_linear_combinations(lhs.into(), rhs.into()), - linear.into(), - Some(message), + FlatStatement::Condition(s) => match s.quad { + FlatExpression::Mult(e) => Statement::constraint( + QuadComb::new((*e.left).into(), (*e.right).into()).span(e.span), + LinComb::from(s.lin), + Some(s.error), ), - e => Statement::Constraint(LinComb::from(e).into(), linear.into(), Some(message)), + e => Statement::constraint(LinComb::from(e), s.lin, Some(s.error)), }, - FlatStatement::Definition(var, quadratic) => match quadratic { - FlatExpression::Mult(box lhs, box rhs) => Statement::Constraint( - QuadComb::from_linear_combinations(lhs.into(), rhs.into()), - var.into(), + FlatStatement::Block(statements) => { + Statement::block(statements.inner.into_iter().map(Statement::from).collect()) + } + FlatStatement::Definition(s) => match s.rhs { + FlatExpression::Mult(e) => Statement::constraint( + QuadComb::new((*e.left).into(), (*e.right).into()).span(e.span), + s.assignee, None, ), - e => Statement::Constraint(LinComb::from(e).into(), var.into(), None), + e => Statement::constraint(LinComb::from(e), s.assignee, None), }, FlatStatement::Directive(ds) => Statement::Directive(ds.into()), - FlatStatement::Log(l, expressions) => Statement::Log( - l, - expressions + FlatStatement::Log(s) => Statement::Log(LogStatement::new( + s.format_string, + s.expressions .into_iter() .map(|(t, e)| (t, e.into_iter().map(LinComb::from).collect())) .collect(), - ), + )), } + .span(span) } } -impl<'ast, T: Field> From> for Directive<'ast, T> { - fn from(ds: FlatDirective<'ast, T>) -> Directive { - Directive { +impl<'ast, T: Field> From> for DirectiveStatement<'ast, T> { + fn from(ds: FlatDirective) -> DirectiveStatement { + DirectiveStatement { inputs: ds .inputs .into_iter() @@ -96,6 +102,7 @@ impl<'ast, T: Field> From> for Directive<'ast, T> { .collect(), solver: ds.solver, outputs: ds.outputs, + span: ds.span, } } } @@ -108,7 +115,7 @@ mod tests { #[test] fn zero() { // 0 - let zero = FlatExpression::Number(Bn128Field::from(0)); + let zero = FlatExpression::value(Bn128Field::from(0)); let expected: LinComb = LinComb::zero(); assert_eq!(LinComb::from(zero), expected); } @@ -116,7 +123,7 @@ mod tests { #[test] fn one() { // 1 - let one = FlatExpression::Number(Bn128Field::from(1)); + let one = FlatExpression::value(Bn128Field::from(1)); let expected: LinComb = Variable::one().into(); assert_eq!(LinComb::from(one), expected); } @@ -124,7 +131,7 @@ mod tests { #[test] fn forty_two() { // 42 - let one = FlatExpression::Number(Bn128Field::from(42)); + let one = FlatExpression::value(Bn128Field::from(42)); let expected: LinComb = LinComb::summand(42, Variable::one()); assert_eq!(LinComb::from(one), expected); } @@ -132,9 +139,9 @@ mod tests { #[test] fn add() { // x + y - let add = FlatExpression::Add( - box FlatExpression::Identifier(Variable::new(42)), - box FlatExpression::Identifier(Variable::new(21)), + let add = FlatExpression::add( + FlatExpression::identifier(Variable::new(42)), + FlatExpression::identifier(Variable::new(21)), ); let expected: LinComb = LinComb::summand(1, Variable::new(42)) + LinComb::summand(1, Variable::new(21)); @@ -144,14 +151,14 @@ mod tests { #[test] fn linear_combination() { // 42*x + 21*y - let add = FlatExpression::Add( - box FlatExpression::Mult( - box FlatExpression::Number(Bn128Field::from(42)), - box FlatExpression::Identifier(Variable::new(42)), + let add = FlatExpression::add( + FlatExpression::mul( + FlatExpression::value(Bn128Field::from(42)), + FlatExpression::identifier(Variable::new(42)), ), - box FlatExpression::Mult( - box FlatExpression::Number(Bn128Field::from(21)), - box FlatExpression::Identifier(Variable::new(21)), + FlatExpression::mul( + FlatExpression::value(Bn128Field::from(21)), + FlatExpression::identifier(Variable::new(21)), ), ); let expected: LinComb = @@ -162,14 +169,14 @@ mod tests { #[test] fn linear_combination_inverted() { // x*42 + y*21 - let add = FlatExpression::Add( - box FlatExpression::Mult( - box FlatExpression::Identifier(Variable::new(42)), - box FlatExpression::Number(Bn128Field::from(42)), + let add = FlatExpression::add( + FlatExpression::mul( + FlatExpression::identifier(Variable::new(42)), + FlatExpression::value(Bn128Field::from(42)), ), - box FlatExpression::Mult( - box FlatExpression::Identifier(Variable::new(21)), - box FlatExpression::Number(Bn128Field::from(21)), + FlatExpression::mul( + FlatExpression::identifier(Variable::new(21)), + FlatExpression::value(Bn128Field::from(21)), ), ); let expected: LinComb = diff --git a/zokrates_ast/src/ir/mod.rs b/zokrates_ast/src/ir/mod.rs index 78b48f808..46c99b13f 100644 --- a/zokrates_ast/src/ir/mod.rs +++ b/zokrates_ast/src/ir/mod.rs @@ -1,10 +1,9 @@ -use crate::common::FormatString; +use crate::common::{FormatString, ModuleMap, Span, WithSpan}; use crate::typed::ConcreteType; use derivative::Derivative; use serde::{Deserialize, Serialize}; use std::collections::BTreeSet; use std::fmt; -use std::hash::Hash; use zokrates_field::Field; mod check; @@ -14,100 +13,186 @@ pub mod folder; pub mod from_flat; mod serialize; pub mod smtlib2; +mod solver_indexer; pub mod visitor; mod witness; pub use self::expression::QuadComb; pub use self::expression::{CanonicalLinComb, LinComb}; -pub use self::serialize::ProgEnum; -pub use crate::common::Parameter; +pub use self::serialize::{ProgEnum, ProgHeader}; +pub use crate::common::flat::Parameter; +pub use crate::common::flat::Variable; pub use crate::common::RuntimeError; pub use crate::common::Solver; -pub use crate::common::Variable; pub use self::witness::Witness; +pub type LogStatement = crate::common::statements::LogStatement<(ConcreteType, Vec>)>; +pub type DirectiveStatement<'ast, T> = + crate::common::statements::DirectiveStatement, Variable, Solver<'ast, T>>; + +#[derive(Derivative, Clone, Debug, Serialize, Deserialize)] +#[derivative(Hash, PartialEq, Eq)] +pub struct ConstraintStatement { + #[derivative(Hash = "ignore", PartialEq = "ignore")] + pub span: Option, + pub quad: QuadComb, + pub lin: LinComb, + #[derivative(Hash = "ignore", PartialEq = "ignore")] + pub error: Option, +} + +impl ConstraintStatement { + pub fn new(quad: QuadComb, lin: LinComb, error: Option) -> Self { + Self { + span: None, + quad, + lin, + error, + } + } +} + +impl WithSpan for ConstraintStatement { + fn span(mut self, span: Option) -> Self { + self.span = span; + self + } + + fn get_span(&self) -> Option { + self.span + } +} + +impl fmt::Display for ConstraintStatement { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "{} == {}{}", + self.quad, + self.lin, + self.error + .as_ref() + .map(|e| format!(" // {}", e)) + .unwrap_or_else(|| "".to_string()) + ) + } +} + +#[derive(Derivative, Clone, Debug, Serialize, Deserialize)] +#[derivative(Hash, PartialEq, Eq)] +pub struct BlockStatement<'ast, T> { + #[derivative(Hash = "ignore", PartialEq = "ignore")] + pub span: Option, + #[serde(borrow)] + pub inner: Vec>, +} + +impl<'ast, T> BlockStatement<'ast, T> { + pub fn new(inner: Vec>) -> Self { + Self { span: None, inner } + } +} + +impl<'ast, T> WithSpan for BlockStatement<'ast, T> { + fn span(mut self, span: Option) -> Self { + self.span = span; + self + } + + fn get_span(&self) -> Option { + self.span + } +} + +impl<'ast, T: Field> fmt::Display for BlockStatement<'ast, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + writeln!(f, "{{")?; + for s in &self.inner { + writeln!(f, "{}", s)?; + } + write!(f, "}}") + } +} + +#[allow(clippy::large_enum_variant)] #[derive(Debug, Serialize, Deserialize, Clone, Derivative)] #[derivative(Hash, PartialEq, Eq)] pub enum Statement<'ast, T> { #[serde(skip)] - Block(Vec>), - Constraint( - QuadComb, - LinComb, - #[derivative(Hash = "ignore")] Option, - ), + Block(BlockStatement<'ast, T>), + Constraint(ConstraintStatement), #[serde(borrow)] - Directive(Directive<'ast, T>), - Log(FormatString, Vec<(ConcreteType, Vec>)>), + Directive(DirectiveStatement<'ast, T>), + Log(LogStatement), } pub type PublicInputs = BTreeSet; +impl<'ast, T> WithSpan for Statement<'ast, T> { + fn span(self, span: Option) -> Self { + match self { + Statement::Constraint(c) => Statement::Constraint(c.span(span)), + Statement::Directive(c) => Statement::Directive(c.span(span)), + Statement::Log(c) => Statement::Log(c.span(span)), + Statement::Block(c) => Statement::Block(c.span(span)), + } + } + + fn get_span(&self) -> Option { + match self { + Statement::Constraint(c) => c.get_span(), + Statement::Directive(c) => c.get_span(), + Statement::Log(c) => c.get_span(), + Statement::Block(c) => c.get_span(), + } + } +} + impl<'ast, T: Field> Statement<'ast, T> { pub fn definition>>(v: Variable, e: U) -> Self { - Statement::Constraint(e.into(), v.into(), None) + Statement::constraint(e, v, None) } - pub fn constraint>, V: Into>>(quad: U, lin: V) -> Self { - Statement::Constraint(quad.into(), lin.into(), None) + pub fn constraint>, V: Into>>( + quad: U, + lin: V, + error: Option, + ) -> Self { + Statement::Constraint(ConstraintStatement::new(quad.into(), lin.into(), error)) } -} -#[derive(Clone, Debug, Serialize, Deserialize, Hash, PartialEq, Eq)] -pub struct Directive<'ast, T> { - pub inputs: Vec>, - pub outputs: Vec, - #[serde(borrow)] - pub solver: Solver<'ast, T>, -} + pub fn log( + format_string: FormatString, + expressions: Vec<(ConcreteType, Vec>)>, + ) -> Self { + Statement::Log(LogStatement::new(format_string, expressions)) + } -impl<'ast, T: Field> fmt::Display for Directive<'ast, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "# {} = {}({})", - self.outputs - .iter() - .map(|o| format!("{}", o)) - .collect::>() - .join(", "), - self.solver, - self.inputs - .iter() - .map(|i| format!("{}", i)) - .collect::>() - .join(", ") - ) + pub fn block(inner: Vec>) -> Self { + Statement::Block(BlockStatement::new(inner)) + } + + pub fn directive( + outputs: Vec, + solver: Solver<'ast, T>, + inputs: Vec>, + ) -> Self { + Statement::Directive(DirectiveStatement::new(outputs, solver, inputs)) } } impl<'ast, T: Field> fmt::Display for Statement<'ast, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - Statement::Block(ref statements) => { - writeln!(f, "{{")?; - for s in statements { - writeln!(f, "{}", s)?; - } - write!(f, "}}") - } - Statement::Constraint(ref quad, ref lin, ref error) => write!( - f, - "{} == {}{}", - quad, - lin, - error - .as_ref() - .map(|e| format!(" // {}", e)) - .unwrap_or_else(|| "".to_string()) - ), + Statement::Constraint(ref s) => write!(f, "{}", s), + Statement::Block(ref s) => write!(f, "{}", s), Statement::Directive(ref s) => write!(f, "{}", s), - Statement::Log(ref s, ref expressions) => write!( + Statement::Log(ref s) => write!( f, "log(\"{}\", {})", - s, - expressions + s.format_string, + s.expressions .iter() .map(|(_, l)| format!( "[{}]", @@ -123,29 +208,54 @@ impl<'ast, T: Field> fmt::Display for Statement<'ast, T> { } } -pub type Prog<'ast, T> = ProgIterator<'ast, T, Vec>>; - -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] pub struct ProgIterator<'ast, T, I: IntoIterator>> { + pub module_map: ModuleMap, pub arguments: Vec, pub return_count: usize, pub statements: I, + #[serde(borrow)] + pub solvers: Vec>, +} + +pub type Prog<'ast, T> = ProgIterator<'ast, T, Vec>>; + +impl<'ast, T> Default for Prog<'ast, T> { + fn default() -> Self { + Self { + module_map: Default::default(), + arguments: Default::default(), + return_count: Default::default(), + statements: Default::default(), + solvers: Default::default(), + } + } } impl<'ast, T, I: IntoIterator>> ProgIterator<'ast, T, I> { - pub fn new(arguments: Vec, statements: I, return_count: usize) -> Self { + pub fn new( + arguments: Vec, + statements: I, + return_count: usize, + module_map: ModuleMap, + solvers: Vec>, + ) -> Self { Self { arguments, return_count, statements, + module_map, + solvers, } } - pub fn collect(self) -> ProgIterator<'ast, T, Vec>> { + pub fn collect(self) -> Prog<'ast, T> { ProgIterator { - statements: self.statements.into_iter().collect::>(), + statements: self.statements.into_iter().collect(), arguments: self.arguments, return_count: self.return_count, + module_map: self.module_map, + solvers: self.solvers, } } @@ -164,14 +274,15 @@ impl<'ast, T, I: IntoIterator>> ProgIterator<'ast, T, .map(|a| a.id) .collect() } -} -impl<'ast, T: Field, I: IntoIterator>> ProgIterator<'ast, T, I> { - pub fn public_inputs_values(&self, witness: &Witness) -> Vec { + pub fn public_inputs_values(&self, witness: &Witness) -> Vec + where + T: Field, + { self.arguments .iter() .filter(|p| !p.private) - .map(|p| witness.0.get(&p.id).unwrap().clone()) + .map(|p| *witness.0.get(&p.id).unwrap()) .chain(witness.return_values()) .collect() } @@ -184,16 +295,6 @@ impl<'ast, T> Prog<'ast, T> { .filter(|s| matches!(s, Statement::Constraint(..))) .count() } - - pub fn into_prog_iter( - self, - ) -> ProgIterator<'ast, T, impl IntoIterator>> { - ProgIterator { - statements: self.statements.into_iter(), - arguments: self.arguments, - return_count: self.return_count, - } - } } impl<'ast, T: Field> fmt::Display for Prog<'ast, T> { @@ -233,12 +334,9 @@ mod tests { #[test] fn print_constraint() { - let c: Statement = Statement::Constraint( - QuadComb::from_linear_combinations( - Variable::new(42).into(), - Variable::new(42).into(), - ), - Variable::new(42).into(), + let c: Statement = Statement::constraint( + QuadComb::new(Variable::new(42).into(), Variable::new(42).into()), + Variable::new(42), None, ); assert_eq!(format!("{}", c), "(1 * _42) * (1 * _42) == 1 * _42") diff --git a/zokrates_ast/src/ir/serialize.rs b/zokrates_ast/src/ir/serialize.rs index 09d003900..4e5ff7a23 100644 --- a/zokrates_ast/src/ir/serialize.rs +++ b/zokrates_ast/src/ir/serialize.rs @@ -1,14 +1,17 @@ -use crate::ir::check::UnconstrainedVariableDetector; +use crate::ir::{check::UnconstrainedVariableDetector, solver_indexer::SolverIndexer}; use super::{ProgIterator, Statement}; +use crate::ir::ModuleMap; +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; +use serde::Deserialize; use serde_cbor::{self, StreamDeserializer}; -use std::io::{Read, Write}; +use std::io::{Read, Seek, Write}; use zokrates_field::*; type DynamicError = Box; const ZOKRATES_MAGIC: &[u8; 4] = &[0x5a, 0x4f, 0x4b, 0]; -const ZOKRATES_VERSION_2: &[u8; 4] = &[0, 0, 0, 2]; +const FILE_VERSION: &[u8; 4] = &[3, 0, 0, 0]; #[derive(PartialEq, Eq, Debug)] pub enum ProgEnum< @@ -17,11 +20,15 @@ pub enum ProgEnum< Bn128I: IntoIterator>, Bls12_377I: IntoIterator>, Bw6_761I: IntoIterator>, + PallasI: IntoIterator>, + VestaI: IntoIterator>, > { Bls12_381Program(ProgIterator<'ast, Bls12_381Field, Bls12_381I>), Bn128Program(ProgIterator<'ast, Bn128Field, Bn128I>), Bls12_377Program(ProgIterator<'ast, Bls12_377Field, Bls12_377I>), Bw6_761Program(ProgIterator<'ast, Bw6_761Field, Bw6_761I>), + PallasProgram(ProgIterator<'ast, PallasField, PallasI>), + VestaProgram(ProgIterator<'ast, VestaField, VestaI>), } type MemoryProgEnum<'ast> = ProgEnum< @@ -30,6 +37,8 @@ type MemoryProgEnum<'ast> = ProgEnum< Vec>, Vec>, Vec>, + Vec>, + Vec>, >; impl< @@ -38,7 +47,9 @@ impl< Bn128I: IntoIterator>, Bls12_377I: IntoIterator>, Bw6_761I: IntoIterator>, - > ProgEnum<'ast, Bls12_381I, Bn128I, Bls12_377I, Bw6_761I> + PallasI: IntoIterator>, + VestaI: IntoIterator>, + > ProgEnum<'ast, Bls12_381I, Bn128I, Bls12_377I, Bw6_761I, PallasI, VestaI> { pub fn collect(self) -> MemoryProgEnum<'ast> { match self { @@ -46,6 +57,8 @@ impl< ProgEnum::Bn128Program(p) => ProgEnum::Bn128Program(p.collect()), ProgEnum::Bls12_377Program(p) => ProgEnum::Bls12_377Program(p.collect()), ProgEnum::Bw6_761Program(p) => ProgEnum::Bw6_761Program(p.collect()), + ProgEnum::PallasProgram(p) => ProgEnum::PallasProgram(p.collect()), + ProgEnum::VestaProgram(p) => ProgEnum::VestaProgram(p.collect()), } } pub fn curve(&self) -> &'static str { @@ -54,37 +67,209 @@ impl< ProgEnum::Bls12_381Program(_) => Bls12_381Field::name(), ProgEnum::Bls12_377Program(_) => Bls12_377Field::name(), ProgEnum::Bw6_761Program(_) => Bw6_761Field::name(), + ProgEnum::PallasProgram(_) => Bls12_377Field::name(), + ProgEnum::VestaProgram(_) => Bw6_761Field::name(), } } } +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[repr(u32)] +pub enum SectionType { + Parameters = 1, + Constraints = 2, + Solvers = 3, + Modules = 4, +} + +impl TryFrom for SectionType { + type Error = String; + + fn try_from(value: u32) -> Result { + match value { + 1 => Ok(SectionType::Parameters), + 2 => Ok(SectionType::Constraints), + 3 => Ok(SectionType::Solvers), + 4 => Ok(SectionType::Modules), + _ => Err("invalid section type".to_string()), + } + } +} + +#[derive(Debug, Clone)] +pub struct Section { + pub ty: SectionType, + pub offset: u64, + pub length: u64, +} + +impl Section { + pub fn new(ty: SectionType) -> Self { + Self { + ty, + offset: 0, + length: 0, + } + } + + pub fn set_offset(&mut self, offset: u64) { + self.offset = offset; + } + + pub fn set_length(&mut self, length: u64) { + self.length = length; + } +} + +#[derive(Debug, Clone)] +pub struct ProgHeader { + pub magic: [u8; 4], + pub version: [u8; 4], + pub curve_id: [u8; 4], + pub constraint_count: u32, + pub return_count: u32, + pub sections: [Section; 4], +} + +impl ProgHeader { + pub fn write(&self, mut w: W) -> std::io::Result<()> { + w.write_all(&self.magic)?; + w.write_all(&self.version)?; + w.write_all(&self.curve_id)?; + w.write_u32::(self.constraint_count)?; + w.write_u32::(self.return_count)?; + + for s in &self.sections { + w.write_u32::(s.ty as u32)?; + w.write_u64::(s.offset)?; + w.write_u64::(s.length)?; + } + + Ok(()) + } + + pub fn read(mut r: R) -> std::io::Result { + let mut magic = [0; 4]; + r.read_exact(&mut magic)?; + + let mut version = [0; 4]; + r.read_exact(&mut version)?; + + let mut curve_id = [0; 4]; + r.read_exact(&mut curve_id)?; + + let constraint_count = r.read_u32::()?; + let return_count = r.read_u32::()?; + + let parameters = Self::read_section(r.by_ref())?; + let constraints = Self::read_section(r.by_ref())?; + let solvers = Self::read_section(r.by_ref())?; + let module_map = Self::read_section(r.by_ref())?; + + Ok(ProgHeader { + magic, + version, + curve_id, + constraint_count, + return_count, + sections: [parameters, constraints, solvers, module_map], + }) + } + + fn read_section(mut r: R) -> std::io::Result
{ + let id = r.read_u32::()?; + let mut section = Section::new( + SectionType::try_from(id) + .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?, + ); + section.set_offset(r.read_u64::()?); + section.set_length(r.read_u64::()?); + Ok(section) + } +} + impl<'ast, T: Field, I: IntoIterator>> ProgIterator<'ast, T, I> { /// serialize a program iterator, returning the number of constraints serialized /// Note that we only return constraints, not other statements such as directives - pub fn serialize(self, mut w: W) -> Result { + pub fn serialize(self, mut w: W) -> Result { use super::folder::Folder; - w.write_all(ZOKRATES_MAGIC)?; - w.write_all(ZOKRATES_VERSION_2)?; - w.write_all(&T::id())?; + // reserve bytes for the header + w.write_all(&[0u8; std::mem::size_of::()])?; + + // write parameters section + let parameters = { + let mut section = Section::new(SectionType::Parameters); + section.set_offset(w.stream_position()?); - serde_cbor::to_writer(&mut w, &self.arguments)?; - serde_cbor::to_writer(&mut w, &self.return_count)?; + serde_cbor::to_writer(&mut w, &self.arguments)?; + section.set_length(w.stream_position()? - section.offset); + section + }; + + let mut solver_indexer: SolverIndexer<'ast, T> = SolverIndexer::default(); let mut unconstrained_variable_detector = UnconstrainedVariableDetector::new(&self); + let mut count: usize = 0; - let statements = self.statements.into_iter(); + // write constraints section + let constraints = { + let mut section = Section::new(SectionType::Constraints); + section.set_offset(w.stream_position()?); - let mut count = 0; - for s in statements { - if matches!(s, Statement::Constraint(..)) { - count += 1; - } - let s = unconstrained_variable_detector.fold_statement(s); - for s in s { - serde_cbor::to_writer(&mut w, &s)?; + let statements = self.statements.into_iter(); + for s in statements { + if matches!(s, Statement::Constraint(..)) { + count += 1; + } + let s: Vec> = solver_indexer + .fold_statement(s) + .into_iter() + .flat_map(|s| unconstrained_variable_detector.fold_statement(s)) + .collect(); + for s in s { + serde_cbor::to_writer(&mut w, &s)?; + } } - } + + section.set_length(w.stream_position()? - section.offset); + section + }; + + // write solvers section + let solvers = { + let mut section = Section::new(SectionType::Solvers); + section.set_offset(w.stream_position()?); + + serde_cbor::to_writer(&mut w, &solver_indexer.solvers)?; + + section.set_length(w.stream_position()? - section.offset); + section + }; + + // write module map section + let module_map = { + let mut section = Section::new(SectionType::Solvers); + section.set_offset(w.stream_position()?); + + serde_cbor::to_writer(&mut w, &self.module_map)?; + + section.set_length(w.stream_position()? - section.offset); + section + }; + + let header = ProgHeader { + magic: *ZOKRATES_MAGIC, + version: *FILE_VERSION, + curve_id: T::id(), + constraint_count: count as u32, + return_count: self.return_count as u32, + sections: [parameters, constraints, solvers, module_map], + }; + + // rewind to write the header + w.rewind()?; + header.write(&mut w)?; unconstrained_variable_detector .finalize() @@ -103,138 +288,103 @@ impl<'de, R: serde_cbor::de::Read<'de>, T: serde::Deserialize<'de>> Iterator type Item = T; fn next(&mut self) -> Option { - self.s.next().transpose().unwrap() + self.s.next().and_then(|v| v.ok()) } } -impl<'de, R: Read> +impl<'de, R: Read + Seek> ProgEnum< 'de, UnwrappedStreamDeserializer<'de, serde_cbor::de::IoRead, Statement<'de, Bls12_381Field>>, UnwrappedStreamDeserializer<'de, serde_cbor::de::IoRead, Statement<'de, Bn128Field>>, UnwrappedStreamDeserializer<'de, serde_cbor::de::IoRead, Statement<'de, Bls12_377Field>>, UnwrappedStreamDeserializer<'de, serde_cbor::de::IoRead, Statement<'de, Bw6_761Field>>, + UnwrappedStreamDeserializer<'de, serde_cbor::de::IoRead, Statement<'de, PallasField>>, + UnwrappedStreamDeserializer<'de, serde_cbor::de::IoRead, Statement<'de, VestaField>>, > { + fn read( + mut r: R, + header: &ProgHeader, + ) -> ProgIterator< + 'de, + T, + UnwrappedStreamDeserializer<'de, serde_cbor::de::IoRead, Statement<'de, T>>, + > { + let parameters = { + let section = &header.sections[0]; + r.seek(std::io::SeekFrom::Start(section.offset)).unwrap(); + + let mut p = serde_cbor::Deserializer::from_reader(r.by_ref()); + Vec::deserialize(&mut p) + .map_err(|_| String::from("Cannot read parameters")) + .unwrap() + }; + + let solvers = { + let section = &header.sections[2]; + r.seek(std::io::SeekFrom::Start(section.offset)).unwrap(); + + let mut p = serde_cbor::Deserializer::from_reader(r.by_ref()); + Vec::deserialize(&mut p) + .map_err(|_| String::from("Cannot read solvers")) + .unwrap() + }; + + let module_map = { + let section = &header.sections[3]; + r.seek(std::io::SeekFrom::Start(section.offset)).unwrap(); + + let mut p = serde_cbor::Deserializer::from_reader(r.by_ref()); + ModuleMap::deserialize(&mut p) + .map_err(|_| String::from("Cannot read module map")) + .unwrap() + }; + + let statements_deserializer = { + let section = &header.sections[1]; + r.seek(std::io::SeekFrom::Start(section.offset)).unwrap(); + + let p = serde_cbor::Deserializer::from_reader(r); + let s = p.into_iter::>(); + + UnwrappedStreamDeserializer { s } + }; + + ProgIterator::new( + parameters, + statements_deserializer, + header.return_count as usize, + module_map, + solvers, + ) + } + pub fn deserialize(mut r: R) -> Result { + let header = ProgHeader::read(&mut r).map_err(|_| String::from("Invalid header"))?; + // Check the magic number, `ZOK` - let mut magic = [0; 4]; - r.read_exact(&mut magic) - .map_err(|_| String::from("Cannot read magic number"))?; - - if &magic == ZOKRATES_MAGIC { - // Check the version, 2 - let mut version = [0; 4]; - r.read_exact(&mut version) - .map_err(|_| String::from("Cannot read version"))?; - - if &version == ZOKRATES_VERSION_2 { - // Check the curve identifier, deserializing accordingly - let mut curve = [0; 4]; - r.read_exact(&mut curve) - .map_err(|_| String::from("Cannot read curve identifier"))?; - - use serde::de::Deserializer; - let mut p = serde_cbor::Deserializer::from_reader(r); - - struct ArgumentsVisitor; - - impl<'de> serde::de::Visitor<'de> for ArgumentsVisitor { - type Value = Vec; - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("seq of flat param") - } - - fn visit_seq(self, mut seq: A) -> Result - where - A: serde::de::SeqAccess<'de>, - { - let mut res = vec![]; - while let Some(e) = seq.next_element().unwrap() { - res.push(e); - } - Ok(res) - } - } + if &header.magic != ZOKRATES_MAGIC { + return Err("Invalid magic number".to_string()); + } - let arguments = p.deserialize_seq(ArgumentsVisitor).unwrap(); - - struct ReturnCountVisitor; - - impl<'de> serde::de::Visitor<'de> for ReturnCountVisitor { - type Value = usize; - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("usize") - } - - fn visit_u32(self, v: u32) -> Result - where - E: serde::de::Error, - { - Ok(v as usize) - } - - fn visit_u8(self, v: u8) -> Result - where - E: serde::de::Error, - { - Ok(v as usize) - } - - fn visit_u16(self, v: u16) -> Result - where - E: serde::de::Error, - { - Ok(v as usize) - } - } + // Check the file version + if &header.version != FILE_VERSION { + return Err("Invalid file version".to_string()); + } - let return_count = p.deserialize_u32(ReturnCountVisitor).unwrap(); - - match curve { - m if m == Bls12_381Field::id() => { - let s = p.into_iter::>(); - - Ok(ProgEnum::Bls12_381Program(ProgIterator::new( - arguments, - UnwrappedStreamDeserializer { s }, - return_count, - ))) - } - m if m == Bn128Field::id() => { - let s = p.into_iter::>(); - - Ok(ProgEnum::Bn128Program(ProgIterator::new( - arguments, - UnwrappedStreamDeserializer { s }, - return_count, - ))) - } - m if m == Bls12_377Field::id() => { - let s = p.into_iter::>(); - - Ok(ProgEnum::Bls12_377Program(ProgIterator::new( - arguments, - UnwrappedStreamDeserializer { s }, - return_count, - ))) - } - m if m == Bw6_761Field::id() => { - let s = p.into_iter::>(); - - Ok(ProgEnum::Bw6_761Program(ProgIterator::new( - arguments, - UnwrappedStreamDeserializer { s }, - return_count, - ))) - } - _ => Err(String::from("Unknown curve identifier")), - } - } else { - Err(String::from("Unknown version")) + match header.curve_id { + m if m == Bls12_381Field::id() => { + Ok(ProgEnum::Bls12_381Program(Self::read(r, &header))) + } + m if m == Bn128Field::id() => Ok(ProgEnum::Bn128Program(Self::read(r, &header))), + m if m == Bls12_377Field::id() => { + Ok(ProgEnum::Bls12_377Program(Self::read(r, &header))) } - } else { - Err(String::from("Wrong magic number")) + m if m == Bw6_761Field::id() => Ok(ProgEnum::Bw6_761Program(Self::read(r, &header))), + m if m == PallasField::id() => Ok(ProgEnum::PallasProgram(Self::read(r, &header))), + m if m == VestaField::id() => Ok(ProgEnum::VestaProgram(Self::read(r, &header))), + _ => Err(String::from("Unknown curve identifier")), } } } diff --git a/zokrates_ast/src/ir/smtlib2.rs b/zokrates_ast/src/ir/smtlib2.rs index bc1188518..4d43d0d28 100644 --- a/zokrates_ast/src/ir/smtlib2.rs +++ b/zokrates_ast/src/ir/smtlib2.rs @@ -79,11 +79,11 @@ impl<'ast, T: Field> SMTLib2 for Statement<'ast, T> { fn to_smtlib2(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Statement::Block(..) => unreachable!(), - Statement::Constraint(ref quad, ref lin, _) => { + Statement::Constraint(ref s) => { write!(f, "(= (mod ")?; - quad.to_smtlib2(f)?; + s.quad.to_smtlib2(f)?; write!(f, " |~prime|) (mod ")?; - lin.to_smtlib2(f)?; + s.lin.to_smtlib2(f)?; write!(f, " |~prime|))") } Statement::Directive(ref s) => s.to_smtlib2(f), @@ -92,7 +92,7 @@ impl<'ast, T: Field> SMTLib2 for Statement<'ast, T> { } } -impl<'ast, T: Field> SMTLib2 for Directive<'ast, T> { +impl<'ast, T: Field> SMTLib2 for DirectiveStatement<'ast, T> { fn to_smtlib2(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "") } @@ -109,15 +109,20 @@ impl SMTLib2 for LinComb { match self.is_zero() { true => write!(f, "0"), false => { - if self.0.len() > 1 { + if self.value.len() > 1 { write!(f, "(+")?; - for expr in self.0.iter() { + for expr in self.value.iter() { write!(f, " ")?; format_prefix_op_smtlib2(f, "*", &expr.0, &expr.1.to_biguint())?; } write!(f, ")") } else { - format_prefix_op_smtlib2(f, "*", &self.0[0].0, &self.0[0].1.to_biguint()) + format_prefix_op_smtlib2( + f, + "*", + &self.value[0].0, + &self.value[0].1.to_biguint(), + ) } } } diff --git a/zokrates_ast/src/ir/solver_indexer.rs b/zokrates_ast/src/ir/solver_indexer.rs new file mode 100644 index 000000000..2ef8994ae --- /dev/null +++ b/zokrates_ast/src/ir/solver_indexer.rs @@ -0,0 +1,57 @@ +use crate::common::RefCall; +use crate::ir::folder::Folder; +use crate::ir::Solver; +use crate::zir::ZirFunction; +use std::collections::hash_map::DefaultHasher; +use std::collections::hash_map::Entry; +use std::collections::HashMap; +use zokrates_field::Field; + +use super::DirectiveStatement; +use super::Statement; + +type Hash = u64; + +fn hash(f: &ZirFunction) -> Hash { + use std::hash::Hash; + use std::hash::Hasher; + let mut hasher = DefaultHasher::new(); + f.hash(&mut hasher); + hasher.finish() +} + +#[derive(Debug, Default)] +pub struct SolverIndexer<'ast, T> { + pub solvers: Vec>, + pub index_map: HashMap, +} + +impl<'ast, T: Field> Folder<'ast, T> for SolverIndexer<'ast, T> { + fn fold_directive_statement( + &mut self, + d: DirectiveStatement<'ast, T>, + ) -> Vec> { + let signature = d.solver.get_signature(); + let res = match d.solver { + Solver::Zir(f) => { + let h = hash(&f); + let index = match self.index_map.entry(h) { + Entry::Occupied(v) => *v.get(), + Entry::Vacant(entry) => { + let index = self.solvers.len(); + entry.insert(index); + self.solvers.push(Solver::Zir(f)); + index + } + }; + DirectiveStatement::new( + d.outputs, + Solver::Ref(RefCall { index, signature }), + d.inputs, + ) + } + _ => d, + }; + vec![Statement::Directive(res)] + } +} diff --git a/zokrates_ast/src/ir/visitor.rs b/zokrates_ast/src/ir/visitor.rs index d3894ca6b..175c48bfe 100644 --- a/zokrates_ast/src/ir/visitor.rs +++ b/zokrates_ast/src/ir/visitor.rs @@ -1,7 +1,7 @@ // Generic walk through an IR AST. Not mutating in place use super::*; -use crate::common::Variable; +use crate::common::flat::Variable; use zokrates_field::Field; pub trait Visitor: Sized { @@ -33,8 +33,8 @@ pub trait Visitor: Sized { visit_quadratic_combination(self, es) } - fn visit_directive(&mut self, d: &Directive) { - visit_directive(self, d) + fn visit_directive_statement(&mut self, d: &DirectiveStatement) { + visit_directive_statement(self, d) } fn visit_runtime_error(&mut self, e: &RuntimeError) { @@ -53,21 +53,21 @@ pub fn visit_module>(f: &mut F, p: &Prog) { pub fn visit_statement>(f: &mut F, s: &Statement) { match s { - Statement::Block(statements) => { - for s in statements { + Statement::Block(s) => { + for s in &s.inner { f.visit_statement(s); } } - Statement::Constraint(quad, lin, error) => { - f.visit_quadratic_combination(quad); - f.visit_linear_combination(lin); - if let Some(error) = error.as_ref() { + Statement::Constraint(s) => { + f.visit_quadratic_combination(&s.quad); + f.visit_linear_combination(&s.lin); + if let Some(error) = s.error.as_ref() { f.visit_runtime_error(error); } } - Statement::Directive(dir) => f.visit_directive(dir), - Statement::Log(_, expressions) => { - for (_, e) in expressions { + Statement::Directive(dir) => f.visit_directive_statement(dir), + Statement::Log(s) => { + for (_, e) in &s.expressions { for e in e { f.visit_linear_combination(e); } @@ -77,7 +77,7 @@ pub fn visit_statement>(f: &mut F, s: &Statement) { } pub fn visit_linear_combination>(f: &mut F, e: &LinComb) { - for expr in e.0.iter() { + for expr in e.value.iter() { f.visit_variable(&expr.0); f.visit_value(&expr.1); } @@ -88,7 +88,7 @@ pub fn visit_quadratic_combination>(f: &mut F, e: &QuadC f.visit_linear_combination(&e.right); } -pub fn visit_directive>(f: &mut F, ds: &Directive) { +pub fn visit_directive_statement>(f: &mut F, ds: &DirectiveStatement) { for expr in ds.inputs.iter() { f.visit_quadratic_combination(expr); } diff --git a/zokrates_ast/src/ir/witness.rs b/zokrates_ast/src/ir/witness.rs index 366c62d8d..b8117279f 100644 --- a/zokrates_ast/src/ir/witness.rs +++ b/zokrates_ast/src/ir/witness.rs @@ -1,4 +1,4 @@ -use crate::common::Variable; +use crate::common::flat::Variable; use std::collections::{BTreeMap, HashMap}; use std::fmt; use std::io; @@ -41,54 +41,44 @@ impl Witness { Witness(BTreeMap::new()) } - pub fn write(&self, writer: W) -> io::Result<()> { - let mut wtr = csv::WriterBuilder::new() - .delimiter(b' ') - .flexible(true) - .has_headers(false) - .from_writer(writer); + pub fn write(&self, mut writer: W) -> io::Result<()> { + let length = self.0.len(); + writer.write_all(&length.to_le_bytes())?; - // Write each line of the witness to the file for (variable, value) in &self.0 { - wtr.serialize((variable.to_string(), value.to_dec_string()))?; + variable.write(&mut writer)?; + value.write(&mut writer)?; } - Ok(()) } pub fn read(mut reader: R) -> io::Result { - let mut rdr = csv::ReaderBuilder::new() - .delimiter(b' ') - .flexible(true) - .has_headers(false) - .from_reader(&mut reader); - - let map = rdr - .deserialize::<(String, String)>() - .map(|r| { - r.map(|(variable, value)| { - let variable = Variable::try_from_human_readable(&variable).map_err(|why| { - io::Error::new( - io::ErrorKind::Other, - format!("Invalid variable in witness: {}", why), - ) - })?; - let value = T::try_from_dec_str(&value).map_err(|_| { - io::Error::new( - io::ErrorKind::Other, - format!("Invalid value in witness: {}", value), - ) - })?; - Ok((variable, value)) - }) - .map_err(|e| match e.into_kind() { - csv::ErrorKind::Io(e) => e, - e => io::Error::new(io::ErrorKind::Other, format!("{:?}", e)), - })? - }) - .collect::>>()?; + let mut witness = Self::empty(); + + let mut buf = [0; std::mem::size_of::()]; + reader.read_exact(&mut buf)?; + + let length: usize = usize::from_le_bytes(buf); + + for _ in 0..length { + let var = Variable::read(&mut reader)?; + let val = T::read(&mut reader)?; - Ok(Witness(map)) + witness.insert(var, val); + } + + Ok(witness) + } + + pub fn write_json(&self, writer: W) -> io::Result<()> { + let map = self + .0 + .iter() + .map(|(k, v)| (k.to_string(), serde_json::json!(v.to_dec_string()))) + .collect::>(); + + serde_json::to_writer_pretty(writer, &map)?; + Ok(()) } } @@ -138,32 +128,29 @@ mod tests { } #[test] - fn wrong_value() { - let mut buff = Cursor::new(vec![]); - - buff.write_all("_1 123bug".as_ref()).unwrap(); - buff.set_position(0); - - assert!(Witness::::read(buff).is_err()); - } - - #[test] - fn wrong_variable() { - let mut buff = Cursor::new(vec![]); - - buff.write_all("_1bug 123".as_ref()).unwrap(); - buff.set_position(0); - - assert!(Witness::::read(buff).is_err()); - } - - #[test] - fn not_csv() { - let mut buff = Cursor::new(vec![]); - buff.write_all("whatwhat".as_ref()).unwrap(); - buff.set_position(0); + fn serialize_json() { + let w = Witness( + vec![ + (Variable::new(42), Bn128Field::from(42)), + (Variable::public(8), Bn128Field::from(8)), + (Variable::one(), Bn128Field::from(1)), + ] + .into_iter() + .collect(), + ); - assert!(Witness::::read(buff).is_err()); + let mut buf = Cursor::new(vec![]); + w.write_json(&mut buf).unwrap(); + + let output = String::from_utf8(buf.into_inner()).unwrap(); + assert_eq!( + output.as_str(), + r#"{ + "~out_8": "8", + "~one": "1", + "_42": "42" +}"# + ) } } } diff --git a/zokrates_ast/src/lib.rs b/zokrates_ast/src/lib.rs index 797b85619..084173f84 100644 --- a/zokrates_ast/src/lib.rs +++ b/zokrates_ast/src/lib.rs @@ -1,5 +1,3 @@ -#![feature(box_patterns, box_syntax)] - pub mod common; pub mod flat; pub mod ir; diff --git a/zokrates_ast/src/typed/abi.rs b/zokrates_ast/src/typed/abi.rs index 253d27e28..88a0da9e4 100644 --- a/zokrates_ast/src/typed/abi.rs +++ b/zokrates_ast/src/typed/abi.rs @@ -22,7 +22,7 @@ impl Abi { ConcreteSignature { generics: vec![], inputs: self.inputs.iter().map(|i| i.ty.clone()).collect(), - output: box self.output.clone(), + output: Box::new(self.output.clone()), } } } @@ -49,14 +49,14 @@ mod tests { ConcreteFunctionKey::with_location("main", "main").into(), TypedFunctionSymbol::Here(TypedFunction { arguments: vec![ - DeclarationParameter { - id: DeclarationVariable::new("a", DeclarationType::FieldElement, true), - private: true, - }, - DeclarationParameter { - id: DeclarationVariable::new("b", DeclarationType::Boolean, false), - private: false, - }, + DeclarationParameter::private(DeclarationVariable::new( + "a", + DeclarationType::FieldElement, + )), + DeclarationParameter::public(DeclarationVariable::new( + "b", + DeclarationType::Boolean, + )), ], statements: vec![], signature: ConcreteSignature::new() @@ -73,6 +73,7 @@ mod tests { let typed_ast: TypedProgram = TypedProgram { main: "main".into(), modules, + module_map: Default::default(), }; let abi: Abi = typed_ast.abi(); diff --git a/zokrates_ast/src/typed/folder.rs b/zokrates_ast/src/typed/folder.rs index d3e87fcd0..424109bf3 100644 --- a/zokrates_ast/src/typed/folder.rs +++ b/zokrates_ast/src/typed/folder.rs @@ -1,45 +1,47 @@ +use crate::common::expressions::{ + BooleanValueExpression, EqExpression, FieldValueExpression, IntValueExpression, + UnaryOrExpression, ValueOrExpression, +}; // Generic walk through a typed AST. Not mutating in place - -use crate::typed::types::*; +use crate::common::{expressions::BinaryOrExpression, Fold}; use crate::typed::*; use zokrates_field::Field; -pub trait Fold<'ast, T: Field>: Sized { - fn fold>(self, f: &mut F) -> Self; -} +use super::identifier::FrameIdentifier; +use super::types::{DeclarationStructMember, DeclarationTupleType, StructMember}; -impl<'ast, T: Field> Fold<'ast, T> for FieldElementExpression<'ast, T> { - fn fold>(self, f: &mut F) -> Self { +impl<'ast, T: Field, F: Folder<'ast, T>> Fold for FieldElementExpression<'ast, T> { + fn fold(self, f: &mut F) -> Self { f.fold_field_expression(self) } } -impl<'ast, T: Field> Fold<'ast, T> for BooleanExpression<'ast, T> { - fn fold>(self, f: &mut F) -> Self { +impl<'ast, T: Field, F: Folder<'ast, T>> Fold for BooleanExpression<'ast, T> { + fn fold(self, f: &mut F) -> Self { f.fold_boolean_expression(self) } } -impl<'ast, T: Field> Fold<'ast, T> for UExpression<'ast, T> { - fn fold>(self, f: &mut F) -> Self { +impl<'ast, T: Field, F: Folder<'ast, T>> Fold for UExpression<'ast, T> { + fn fold(self, f: &mut F) -> Self { f.fold_uint_expression(self) } } -impl<'ast, T: Field> Fold<'ast, T> for StructExpression<'ast, T> { - fn fold>(self, f: &mut F) -> Self { +impl<'ast, T: Field, F: Folder<'ast, T>> Fold for StructExpression<'ast, T> { + fn fold(self, f: &mut F) -> Self { f.fold_struct_expression(self) } } -impl<'ast, T: Field> Fold<'ast, T> for ArrayExpression<'ast, T> { - fn fold>(self, f: &mut F) -> Self { +impl<'ast, T: Field, F: Folder<'ast, T>> Fold for ArrayExpression<'ast, T> { + fn fold(self, f: &mut F) -> Self { f.fold_array_expression(self) } } -impl<'ast, T: Field> Fold<'ast, T> for TupleExpression<'ast, T> { - fn fold>(self, f: &mut F) -> Self { +impl<'ast, T: Field, F: Folder<'ast, T>> Fold for TupleExpression<'ast, T> { + fn fold(self, f: &mut F) -> Self { f.fold_tuple_expression(self) } } @@ -128,33 +130,28 @@ pub trait Folder<'ast, T: Field>: Sized { } fn fold_name(&mut self, n: Identifier<'ast>) -> Identifier<'ast> { - let id = match n.id { - CoreIdentifier::Constant(c) => { - CoreIdentifier::Constant(self.fold_canonical_constant_identifier(c)) - } - id => id, + let id = match n.id.id.clone() { + CoreIdentifier::Constant(c) => FrameIdentifier { + id: CoreIdentifier::Constant(self.fold_canonical_constant_identifier(c)), + frame: 0, + }, + _ => n.id, }; Identifier { id, ..n } } fn fold_variable(&mut self, v: Variable<'ast, T>) -> Variable<'ast, T> { - Variable { - id: self.fold_name(v.id), - _type: self.fold_type(v._type), - is_mutable: v.is_mutable, - } + let span = v.get_span(); + Variable::new(self.fold_name(v.id), self.fold_type(v.ty)).span(span) } fn fold_declaration_variable( &mut self, v: DeclarationVariable<'ast, T>, ) -> DeclarationVariable<'ast, T> { - DeclarationVariable { - id: self.fold_name(v.id), - _type: self.fold_declaration_type(v._type), - is_mutable: v.is_mutable, - } + let span = v.get_span(); + DeclarationVariable::new(self.fold_name(v.id), self.fold_declaration_type(v.ty)).span(span) } fn fold_type(&mut self, t: Type<'ast, T>) -> Type<'ast, T> { @@ -170,8 +167,8 @@ pub trait Folder<'ast, T: Field>: Sized { fn fold_array_type(&mut self, t: ArrayType<'ast, T>) -> ArrayType<'ast, T> { ArrayType { - ty: box self.fold_type(*t.ty), - size: box self.fold_uint_expression(*t.size), + ty: Box::new(self.fold_type(*t.ty)), + size: Box::new(self.fold_uint_expression(*t.size)), } } @@ -192,7 +189,7 @@ pub trait Folder<'ast, T: Field>: Sized { .members .into_iter() .map(|m| StructMember { - ty: box self.fold_type(*m.ty), + ty: Box::new(self.fold_type(*m.ty)), ..m }) .collect(), @@ -216,8 +213,8 @@ pub trait Folder<'ast, T: Field>: Sized { t: DeclarationArrayType<'ast, T>, ) -> DeclarationArrayType<'ast, T> { DeclarationArrayType { - ty: box self.fold_declaration_type(*t.ty), - size: box self.fold_declaration_constant(*t.size), + ty: Box::new(self.fold_declaration_type(*t.ty)), + size: Box::new(self.fold_declaration_constant(*t.size)), } } @@ -248,7 +245,7 @@ pub trait Folder<'ast, T: Field>: Sized { .members .into_iter() .map(|m| DeclarationStructMember { - ty: box self.fold_declaration_type(*m.ty), + ty: Box::new(self.fold_declaration_type(*m.ty)), ..m }) .collect(), @@ -260,6 +257,27 @@ pub trait Folder<'ast, T: Field>: Sized { fold_assignee(self, a) } + fn fold_assembly_block( + &mut self, + s: AssemblyBlockStatement<'ast, T>, + ) -> Vec> { + fold_assembly_block(self, s) + } + + fn fold_assembly_assignment( + &mut self, + s: AssemblyAssignment<'ast, T>, + ) -> Vec> { + fold_assembly_assignment(self, s) + } + + fn fold_assembly_constraint( + &mut self, + s: AssemblyConstraint<'ast, T>, + ) -> Vec> { + fold_assembly_constraint(self, s) + } + fn fold_assembly_statement( &mut self, s: TypedAssemblyStatement<'ast, T>, @@ -267,10 +285,50 @@ pub trait Folder<'ast, T: Field>: Sized { fold_assembly_statement(self, s) } + fn fold_assembly_statement_cases( + &mut self, + s: TypedAssemblyStatement<'ast, T>, + ) -> Vec> { + fold_assembly_statement_cases(self, s) + } + fn fold_statement(&mut self, s: TypedStatement<'ast, T>) -> Vec> { fold_statement(self, s) } + fn fold_statement_cases(&mut self, s: TypedStatement<'ast, T>) -> Vec> { + fold_statement_cases(self, s) + } + + fn fold_definition_statement( + &mut self, + s: DefinitionStatement<'ast, T>, + ) -> Vec> { + fold_definition_statement(self, s) + } + + fn fold_return_statement( + &mut self, + s: ReturnStatement<'ast, T>, + ) -> Vec> { + fold_return_statement(self, s) + } + + fn fold_assertion_statement( + &mut self, + s: AssertionStatement<'ast, T>, + ) -> Vec> { + fold_assertion_statement(self, s) + } + + fn fold_log_statement(&mut self, s: LogStatement<'ast, T>) -> Vec> { + fold_log_statement(self, s) + } + + fn fold_for_statement(&mut self, s: ForStatement<'ast, T>) -> Vec> { + fold_for_statement(self, s) + } + fn fold_definition_rhs(&mut self, rhs: DefinitionRhs<'ast, T>) -> DefinitionRhs<'ast, T> { fold_definition_rhs(self, rhs) } @@ -309,7 +367,7 @@ pub trait Folder<'ast, T: Field>: Sized { } } - fn fold_module_id(&mut self, i: OwnedTypedModuleId) -> OwnedTypedModuleId { + fn fold_module_id(&mut self, i: OwnedModuleId) -> OwnedModuleId { i } @@ -317,7 +375,7 @@ pub trait Folder<'ast, T: Field>: Sized { fold_expression(self, e) } - fn fold_block_expression>( + fn fold_block_expression>( &mut self, block: BlockExpression<'ast, T, E>, ) -> BlockExpression<'ast, T, E> { @@ -326,7 +384,7 @@ pub trait Folder<'ast, T: Field>: Sized { fn fold_conditional_expression< E: Expr<'ast, T> - + Fold<'ast, T> + + Fold + Block<'ast, T> + Conditional<'ast, T> + From>, @@ -338,6 +396,35 @@ pub trait Folder<'ast, T: Field>: Sized { fold_conditional_expression(self, ty, e) } + fn fold_binary_expression< + L: Expr<'ast, T> + Fold, + R: Expr<'ast, T> + Fold, + E: Expr<'ast, T> + Fold, + Op, + >( + &mut self, + ty: &E::Ty, + e: BinaryExpression, + ) -> BinaryOrExpression { + fold_binary_expression(self, ty, e) + } + + fn fold_eq_expression + Fold>( + &mut self, + e: EqExpression>, + ) -> BinaryOrExpression, BooleanExpression<'ast, T>> + { + fold_binary_expression(self, &Type::Boolean, e) + } + + fn fold_unary_expression + Fold, E: Expr<'ast, T> + Fold, Op>( + &mut self, + ty: &E::Ty, + e: UnaryExpression, + ) -> UnaryOrExpression { + fold_unary_expression(self, ty, e) + } + fn fold_member_expression< E: Expr<'ast, T> + Member<'ast, T> + From>, >( @@ -348,6 +435,17 @@ pub trait Folder<'ast, T: Field>: Sized { fold_member_expression(self, ty, e) } + fn fold_slice_expression(&mut self, e: SliceExpression<'ast, T>) -> SliceOrExpression<'ast, T> { + fold_slice_expression(self, e) + } + + fn fold_repeat_expression( + &mut self, + e: RepeatExpression<'ast, T>, + ) -> RepeatOrExpression<'ast, T> { + fold_repeat_expression(self, e) + } + fn fold_identifier_expression< E: Expr<'ast, T> + Id<'ast, T> + From>, >( @@ -368,13 +466,6 @@ pub trait Folder<'ast, T: Field>: Sized { fold_element_expression(self, ty, e) } - fn fold_eq_expression + PartialEq + Constant + Fold<'ast, T>>( - &mut self, - e: EqExpression, - ) -> EqOrBoolean<'ast, T, E> { - fold_eq_expression(self, e) - } - fn fold_function_call_expression< E: Id<'ast, T> + From> + Expr<'ast, T> + FunctionCall<'ast, T>, >( @@ -414,6 +505,13 @@ pub trait Folder<'ast, T: Field>: Sized { fold_int_expression(self, e) } + fn fold_field_expression_cases( + &mut self, + e: FieldElementExpression<'ast, T>, + ) -> FieldElementExpression<'ast, T> { + fold_field_expression_cases(self, e) + } + fn fold_field_expression( &mut self, e: FieldElementExpression<'ast, T>, @@ -421,6 +519,13 @@ pub trait Folder<'ast, T: Field>: Sized { fold_field_expression(self, e) } + fn fold_boolean_expression_cases( + &mut self, + e: BooleanExpression<'ast, T>, + ) -> BooleanExpression<'ast, T> { + fold_boolean_expression_cases(self, e) + } + fn fold_boolean_expression( &mut self, e: BooleanExpression<'ast, T>, @@ -432,6 +537,14 @@ pub trait Folder<'ast, T: Field>: Sized { fold_uint_expression(self, e) } + fn fold_uint_expression_cases( + &mut self, + bitwidth: UBitwidth, + e: UExpressionInner<'ast, T>, + ) -> UExpressionInner<'ast, T> { + fold_uint_expression_cases(self, bitwidth, e) + } + fn fold_uint_expression_inner( &mut self, bitwidth: UBitwidth, @@ -440,6 +553,14 @@ pub trait Folder<'ast, T: Field>: Sized { fold_uint_expression_inner(self, bitwidth, e) } + fn fold_array_expression_cases( + &mut self, + ty: &ArrayType<'ast, T>, + e: ArrayExpressionInner<'ast, T>, + ) -> ArrayExpressionInner<'ast, T> { + fold_array_expression_cases(self, ty, e) + } + fn fold_array_expression_inner( &mut self, ty: &ArrayType<'ast, T>, @@ -448,6 +569,14 @@ pub trait Folder<'ast, T: Field>: Sized { fold_array_expression_inner(self, ty, e) } + fn fold_tuple_expression_cases( + &mut self, + ty: &TupleType<'ast, T>, + e: TupleExpressionInner<'ast, T>, + ) -> TupleExpressionInner<'ast, T> { + fold_tuple_expression_cases(self, ty, e) + } + fn fold_tuple_expression_inner( &mut self, ty: &TupleType<'ast, T>, @@ -456,6 +585,14 @@ pub trait Folder<'ast, T: Field>: Sized { fold_tuple_expression_inner(self, ty, e) } + fn fold_struct_expression_cases( + &mut self, + ty: &StructType<'ast, T>, + e: StructExpressionInner<'ast, T>, + ) -> StructExpressionInner<'ast, T> { + fold_struct_expression_cases(self, ty, e) + } + fn fold_struct_expression_inner( &mut self, ty: &StructType<'ast, T>, @@ -463,6 +600,51 @@ pub trait Folder<'ast, T: Field>: Sized { ) -> StructExpressionInner<'ast, T> { fold_struct_expression_inner(self, ty, e) } + + fn fold_field_value_expression( + &mut self, + v: FieldValueExpression, + ) -> ValueOrExpression, FieldElementExpression<'ast, T>> { + fold_field_value_expression(self, v) + } + + fn fold_boolean_value_expression( + &mut self, + v: BooleanValueExpression, + ) -> ValueOrExpression> { + fold_boolean_value_expression(self, v) + } + + fn fold_integer_value_expression( + &mut self, + v: IntValueExpression, + ) -> ValueOrExpression> { + fold_integer_value_expression(self, v) + } + + fn fold_struct_value_expression( + &mut self, + ty: &StructType<'ast, T>, + v: StructValueExpression<'ast, T>, + ) -> ValueOrExpression, StructExpressionInner<'ast, T>> { + fold_struct_value_expression(self, ty, v) + } + + fn fold_array_value_expression( + &mut self, + ty: &ArrayType<'ast, T>, + v: ArrayValueExpression<'ast, T>, + ) -> ValueOrExpression, ArrayExpressionInner<'ast, T>> { + fold_array_value_expression(self, ty, v) + } + + fn fold_tuple_value_expression( + &mut self, + ty: &TupleType<'ast, T>, + v: TupleValueExpression<'ast, T>, + ) -> ValueOrExpression, TupleExpressionInner<'ast, T>> { + fold_tuple_value_expression(self, ty, v) + } } pub fn fold_module<'ast, T: Field, F: Folder<'ast, T>>( @@ -522,60 +704,136 @@ pub fn fold_definition_rhs<'ast, T: Field, F: Folder<'ast, T>>( } } -pub fn fold_assembly_statement<'ast, T: Field, F: Folder<'ast, T>>( +pub fn fold_return_statement<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + s: ReturnStatement<'ast, T>, +) -> Vec> { + vec![TypedStatement::Return(ReturnStatement::new( + f.fold_expression(s.inner), + ))] +} + +pub fn fold_definition_statement<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + s: DefinitionStatement<'ast, T>, +) -> Vec> { + let rhs = f.fold_definition_rhs(s.rhs); + vec![TypedStatement::Definition( + DefinitionStatement::new(f.fold_assignee(s.assignee), rhs).span(s.span), + )] +} + +pub fn fold_assertion_statement<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + s: AssertionStatement<'ast, T>, +) -> Vec> { + vec![TypedStatement::Assertion( + AssertionStatement::new(f.fold_boolean_expression(s.expression), s.error).span(s.span), + )] +} + +pub fn fold_for_statement<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + s: ForStatement<'ast, T>, +) -> Vec> { + vec![TypedStatement::For(ForStatement::new( + f.fold_variable(s.var), + f.fold_uint_expression(s.from), + f.fold_uint_expression(s.to), + s.statements + .into_iter() + .flat_map(|s| f.fold_statement(s)) + .collect(), + ))] +} + +pub fn fold_log_statement<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + s: LogStatement<'ast, T>, +) -> Vec> { + vec![TypedStatement::Log(LogStatement::new( + s.format_string, + s.expressions + .into_iter() + .map(|e| f.fold_expression(e)) + .collect(), + ))] +} + +pub fn fold_statement_cases<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + s: TypedStatement<'ast, T>, +) -> Vec> { + match s { + TypedStatement::Return(s) => f.fold_return_statement(s), + TypedStatement::Definition(s) => f.fold_definition_statement(s), + TypedStatement::Assertion(s) => f.fold_assertion_statement(s), + TypedStatement::For(s) => f.fold_for_statement(s), + TypedStatement::Log(s) => f.fold_log_statement(s), + TypedStatement::Assembly(s) => f.fold_assembly_block(s), + } +} + +pub fn fold_assembly_block<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + s: AssemblyBlockStatement<'ast, T>, +) -> Vec> { + vec![TypedStatement::Assembly(AssemblyBlockStatement::new( + s.inner + .into_iter() + .flat_map(|s| f.fold_assembly_statement(s)) + .collect(), + ))] +} + +pub fn fold_assembly_assignment<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + s: AssemblyAssignment<'ast, T>, +) -> Vec> { + let assignee = f.fold_assignee(s.assignee); + let expression = f.fold_expression(s.expression); + vec![TypedAssemblyStatement::assignment(assignee, expression)] +} + +pub fn fold_assembly_constraint<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + s: AssemblyConstraint<'ast, T>, +) -> Vec> { + let left = f.fold_field_expression(s.left); + let right = f.fold_field_expression(s.right); + vec![TypedAssemblyStatement::constraint(left, right, s.metadata)] +} + +fn fold_assembly_statement<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + s: TypedAssemblyStatement<'ast, T>, +) -> Vec> { + let span = s.get_span(); + f.fold_assembly_statement_cases(s) + .into_iter() + .map(|s| s.span(span)) + .collect() +} + +pub fn fold_assembly_statement_cases<'ast, T: Field, F: Folder<'ast, T>>( f: &mut F, s: TypedAssemblyStatement<'ast, T>, ) -> Vec> { match s { - TypedAssemblyStatement::Assignment(a, e) => { - vec![TypedAssemblyStatement::Assignment( - f.fold_assignee(a), - f.fold_expression(e), - )] - } - TypedAssemblyStatement::Constraint(lhs, rhs, metadata) => { - vec![TypedAssemblyStatement::Constraint( - f.fold_field_expression(lhs), - f.fold_field_expression(rhs), - metadata, - )] - } + TypedAssemblyStatement::Assignment(s) => f.fold_assembly_assignment(s), + TypedAssemblyStatement::Constraint(s) => f.fold_assembly_constraint(s), } } -pub fn fold_statement<'ast, T: Field, F: Folder<'ast, T>>( +fn fold_statement<'ast, T: Field, F: Folder<'ast, T>>( f: &mut F, s: TypedStatement<'ast, T>, ) -> Vec> { - let res = match s { - TypedStatement::Return(e) => TypedStatement::Return(f.fold_expression(e)), - TypedStatement::Definition(a, e) => { - TypedStatement::Definition(f.fold_assignee(a), f.fold_definition_rhs(e)) - } - TypedStatement::Assertion(e, error) => { - TypedStatement::Assertion(f.fold_boolean_expression(e), error) - } - TypedStatement::For(v, from, to, statements) => TypedStatement::For( - f.fold_variable(v), - f.fold_uint_expression(from), - f.fold_uint_expression(to), - statements - .into_iter() - .flat_map(|s| f.fold_statement(s)) - .collect(), - ), - TypedStatement::Log(s, e) => { - TypedStatement::Log(s, e.into_iter().map(|e| f.fold_expression(e)).collect()) - } - TypedStatement::Assembly(statements) => TypedStatement::Assembly( - statements - .into_iter() - .flat_map(|s| f.fold_assembly_statement(s)) - .collect(), - ), - s => s, - }; - vec![res] + let span = s.get_span(); + f.fold_statement_cases(s) + .into_iter() + .map(|s| s.span(span)) + .collect() } pub fn fold_identifier_expression< @@ -620,7 +878,16 @@ pub fn fold_expression<'ast, T: Field, F: Folder<'ast, T>>( } } -pub fn fold_array_expression_inner<'ast, T: Field, F: Folder<'ast, T>>( +fn fold_array_expression_inner<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + ty: &ArrayType<'ast, T>, + e: ArrayExpressionInner<'ast, T>, +) -> ArrayExpressionInner<'ast, T> { + let span = e.get_span(); + f.fold_array_expression_cases(ty, e).span(span) +} + +pub fn fold_array_expression_cases<'ast, T: Field, F: Folder<'ast, T>>( f: &mut F, ty: &ArrayType<'ast, T>, e: ArrayExpressionInner<'ast, T>, @@ -633,16 +900,14 @@ pub fn fold_array_expression_inner<'ast, T: Field, F: Folder<'ast, T>>( IdentifierOrExpression::Expression(u) => u, }, Block(block) => Block(f.fold_block_expression(block)), - Value(exprs) => Value( - exprs - .into_iter() - .map(|e| f.fold_expression_or_spread(e)) - .collect(), - ), FunctionCall(function_call) => match f.fold_function_call_expression(ty, function_call) { FunctionCallOrExpression::FunctionCall(function_call) => FunctionCall(function_call), FunctionCallOrExpression::Expression(u) => u, }, + Value(function_call) => match f.fold_array_value_expression(ty, function_call) { + ValueOrExpression::Value(value) => Value(value), + ValueOrExpression::Expression(e) => e, + }, Conditional(c) => match f.fold_conditional_expression(ty, c) { ConditionalOrExpression::Conditional(s) => Conditional(s), ConditionalOrExpression::Expression(u) => u, @@ -655,17 +920,14 @@ pub fn fold_array_expression_inner<'ast, T: Field, F: Folder<'ast, T>>( MemberOrExpression::Member(m) => Member(m), MemberOrExpression::Expression(u) => u, }, - Slice(box array, box from, box to) => { - let array = f.fold_array_expression(array); - let from = f.fold_uint_expression(from); - let to = f.fold_uint_expression(to); - Slice(box array, box from, box to) - } - Repeat(box e, box count) => { - let e = f.fold_expression(e); - let count = f.fold_uint_expression(count); - Repeat(box e, box count) - } + Slice(s) => match f.fold_slice_expression(s) { + SliceOrExpression::Slice(m) => Slice(m), + SliceOrExpression::Expression(u) => u, + }, + Repeat(s) => match f.fold_repeat_expression(s) { + RepeatOrExpression::Repeat(m) => Repeat(m), + RepeatOrExpression::Expression(u) => u, + }, Element(m) => match f.fold_element_expression(ty, m) { ElementOrExpression::Element(m) => Element(m), ElementOrExpression::Expression(u) => u, @@ -673,7 +935,16 @@ pub fn fold_array_expression_inner<'ast, T: Field, F: Folder<'ast, T>>( } } -pub fn fold_struct_expression_inner<'ast, T: Field, F: Folder<'ast, T>>( +fn fold_struct_expression_inner<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + ty: &StructType<'ast, T>, + e: StructExpressionInner<'ast, T>, +) -> StructExpressionInner<'ast, T> { + let span = e.get_span(); + f.fold_struct_expression_cases(ty, e).span(span) +} + +pub fn fold_struct_expression_cases<'ast, T: Field, F: Folder<'ast, T>>( f: &mut F, ty: &StructType<'ast, T>, e: StructExpressionInner<'ast, T>, @@ -686,7 +957,10 @@ pub fn fold_struct_expression_inner<'ast, T: Field, F: Folder<'ast, T>>( IdentifierOrExpression::Expression(u) => u, }, Block(block) => Block(f.fold_block_expression(block)), - Value(exprs) => Value(exprs.into_iter().map(|e| f.fold_expression(e)).collect()), + Value(function_call) => match f.fold_struct_value_expression(ty, function_call) { + ValueOrExpression::Value(value) => Value(value), + ValueOrExpression::Expression(e) => e, + }, FunctionCall(function_call) => match f.fold_function_call_expression(ty, function_call) { FunctionCallOrExpression::FunctionCall(function_call) => FunctionCall(function_call), FunctionCallOrExpression::Expression(u) => u, @@ -710,7 +984,16 @@ pub fn fold_struct_expression_inner<'ast, T: Field, F: Folder<'ast, T>>( } } -pub fn fold_tuple_expression_inner<'ast, T: Field, F: Folder<'ast, T>>( +fn fold_tuple_expression_inner<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + ty: &TupleType<'ast, T>, + e: TupleExpressionInner<'ast, T>, +) -> TupleExpressionInner<'ast, T> { + let span = e.get_span(); + f.fold_tuple_expression_cases(ty, e).span(span) +} + +pub fn fold_tuple_expression_cases<'ast, T: Field, F: Folder<'ast, T>>( f: &mut F, ty: &TupleType<'ast, T>, e: TupleExpressionInner<'ast, T>, @@ -723,7 +1006,10 @@ pub fn fold_tuple_expression_inner<'ast, T: Field, F: Folder<'ast, T>>( IdentifierOrExpression::Identifier(i) => Identifier(i), IdentifierOrExpression::Expression(u) => u, }, - Value(exprs) => Value(exprs.into_iter().map(|e| f.fold_expression(e)).collect()), + Value(function_call) => match f.fold_tuple_value_expression(ty, function_call) { + ValueOrExpression::Value(value) => Value(value), + ValueOrExpression::Expression(e) => e, + }, FunctionCall(function_call) => match f.fold_function_call_expression(ty, function_call) { FunctionCallOrExpression::FunctionCall(function_call) => FunctionCall(function_call), FunctionCallOrExpression::Expression(u) => u, @@ -747,7 +1033,15 @@ pub fn fold_tuple_expression_inner<'ast, T: Field, F: Folder<'ast, T>>( } } -pub fn fold_field_expression<'ast, T: Field, F: Folder<'ast, T>>( +fn fold_field_expression<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + e: FieldElementExpression<'ast, T>, +) -> FieldElementExpression<'ast, T> { + let span = e.get_span(); + f.fold_field_expression_cases(e).span(span) +} + +pub fn fold_field_expression_cases<'ast, T: Field, F: Folder<'ast, T>>( f: &mut F, e: FieldElementExpression<'ast, T>, ) -> FieldElementExpression<'ast, T> { @@ -759,72 +1053,58 @@ pub fn fold_field_expression<'ast, T: Field, F: Folder<'ast, T>>( IdentifierOrExpression::Expression(u) => u, }, Block(block) => Block(f.fold_block_expression(block)), - Number(n) => Number(n), - Add(box e1, box e2) => { - let e1 = f.fold_field_expression(e1); - let e2 = f.fold_field_expression(e2); - Add(box e1, box e2) - } - Sub(box e1, box e2) => { - let e1 = f.fold_field_expression(e1); - let e2 = f.fold_field_expression(e2); - Sub(box e1, box e2) - } - Mult(box e1, box e2) => { - let e1 = f.fold_field_expression(e1); - let e2 = f.fold_field_expression(e2); - Mult(box e1, box e2) - } - Div(box e1, box e2) => { - let e1 = f.fold_field_expression(e1); - let e2 = f.fold_field_expression(e2); - Div(box e1, box e2) - } - Pow(box e1, box e2) => { - let e1 = f.fold_field_expression(e1); - let e2 = f.fold_uint_expression(e2); - Pow(box e1, box e2) - } - Neg(box e) => { - let e = f.fold_field_expression(e); - - Neg(box e) - } - Pos(box e) => { - let e = f.fold_field_expression(e); - - Pos(box e) - } - And(box left, box right) => { - let left = f.fold_field_expression(left); - let right = f.fold_field_expression(right); - - And(box left, box right) - } - Or(box left, box right) => { - let left = f.fold_field_expression(left); - let right = f.fold_field_expression(right); - - Or(box left, box right) - } - Xor(box left, box right) => { - let left = f.fold_field_expression(left); - let right = f.fold_field_expression(right); - - Xor(box left, box right) - } - LeftShift(box e, box by) => { - let e = f.fold_field_expression(e); - let by = f.fold_uint_expression(by); - - LeftShift(box e, box by) - } - RightShift(box e, box by) => { - let e = f.fold_field_expression(e); - let by = f.fold_uint_expression(by); - - RightShift(box e, box by) - } + Value(value) => match f.fold_field_value_expression(value) { + ValueOrExpression::Value(value) => Value(value), + ValueOrExpression::Expression(e) => e, + }, + Add(e) => match f.fold_binary_expression(&Type::FieldElement, e) { + BinaryOrExpression::Binary(e) => Add(e), + BinaryOrExpression::Expression(u) => u, + }, + Sub(e) => match f.fold_binary_expression(&Type::FieldElement, e) { + BinaryOrExpression::Binary(e) => Sub(e), + BinaryOrExpression::Expression(u) => u, + }, + Mult(e) => match f.fold_binary_expression(&Type::FieldElement, e) { + BinaryOrExpression::Binary(e) => Mult(e), + BinaryOrExpression::Expression(u) => u, + }, + Div(e) => match f.fold_binary_expression(&Type::FieldElement, e) { + BinaryOrExpression::Binary(e) => Div(e), + BinaryOrExpression::Expression(u) => u, + }, + Pow(e) => match f.fold_binary_expression(&Type::FieldElement, e) { + BinaryOrExpression::Binary(e) => Pow(e), + BinaryOrExpression::Expression(u) => u, + }, + And(e) => match f.fold_binary_expression(&Type::FieldElement, e) { + BinaryOrExpression::Binary(e) => And(e), + BinaryOrExpression::Expression(u) => u, + }, + Or(e) => match f.fold_binary_expression(&Type::FieldElement, e) { + BinaryOrExpression::Binary(e) => Or(e), + BinaryOrExpression::Expression(u) => u, + }, + Xor(e) => match f.fold_binary_expression(&Type::FieldElement, e) { + BinaryOrExpression::Binary(e) => Xor(e), + BinaryOrExpression::Expression(u) => u, + }, + LeftShift(e) => match f.fold_binary_expression(&Type::FieldElement, e) { + BinaryOrExpression::Binary(e) => LeftShift(e), + BinaryOrExpression::Expression(u) => u, + }, + RightShift(e) => match f.fold_binary_expression(&Type::FieldElement, e) { + BinaryOrExpression::Binary(e) => RightShift(e), + BinaryOrExpression::Expression(u) => u, + }, + Neg(e) => match f.fold_unary_expression(&Type::FieldElement, e) { + UnaryOrExpression::Unary(e) => Neg(e), + UnaryOrExpression::Expression(u) => u, + }, + Pos(e) => match f.fold_unary_expression(&Type::FieldElement, e) { + UnaryOrExpression::Unary(e) => Pos(e), + UnaryOrExpression::Expression(u) => u, + }, Conditional(c) => match f.fold_conditional_expression(&Type::FieldElement, c) { ConditionalOrExpression::Conditional(s) => Conditional(s), ConditionalOrExpression::Expression(u) => u, @@ -855,19 +1135,53 @@ pub fn fold_field_expression<'ast, T: Field, F: Folder<'ast, T>>( pub fn fold_conditional_expression< 'ast, T: Field, - E: Expr<'ast, T> + Fold<'ast, T> + Conditional<'ast, T> + From>, + E: Expr<'ast, T> + Fold + Conditional<'ast, T> + From>, F: Folder<'ast, T>, >( f: &mut F, _: &E::Ty, e: ConditionalExpression<'ast, T, E>, ) -> ConditionalOrExpression<'ast, T, E> { - ConditionalOrExpression::Conditional(ConditionalExpression::new( - f.fold_boolean_expression(*e.condition), - e.consequence.fold(f), - e.alternative.fold(f), - e.kind, - )) + ConditionalOrExpression::Conditional( + ConditionalExpression::new( + f.fold_boolean_expression(*e.condition), + e.consequence.fold(f), + e.alternative.fold(f), + e.kind, + ) + .span(e.span), + ) +} + +pub fn fold_binary_expression< + 'ast, + T: Field, + L: Expr<'ast, T> + Fold + From>, + R: Expr<'ast, T> + Fold + From>, + E: Expr<'ast, T> + Fold + From>, + F: Folder<'ast, T>, + Op, +>( + f: &mut F, + _: &E::Ty, + e: BinaryExpression, +) -> BinaryOrExpression { + BinaryOrExpression::Binary(BinaryExpression::new(e.left.fold(f), e.right.fold(f))) +} + +pub fn fold_unary_expression< + 'ast, + T: Field, + In: Expr<'ast, T> + Fold + From>, + E: Expr<'ast, T> + Fold + From>, + F: Folder<'ast, T>, + Op, +>( + f: &mut F, + _: &E::Ty, + e: UnaryExpression, +) -> UnaryOrExpression { + UnaryOrExpression::Unary(UnaryExpression::new(e.inner.fold(f))) } pub fn fold_member_expression< @@ -886,6 +1200,27 @@ pub fn fold_member_expression< )) } +pub fn fold_slice_expression<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + e: SliceExpression<'ast, T>, +) -> SliceOrExpression<'ast, T> { + SliceOrExpression::Slice(SliceExpression::new( + f.fold_array_expression(*e.array), + f.fold_uint_expression(*e.from), + f.fold_uint_expression(*e.to), + )) +} + +pub fn fold_repeat_expression<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + e: RepeatExpression<'ast, T>, +) -> RepeatOrExpression<'ast, T> { + RepeatOrExpression::Repeat(RepeatExpression::new( + f.fold_expression(*e.e), + f.fold_uint_expression(*e.count), + )) +} + pub fn fold_element_expression< 'ast, T: Field, @@ -896,17 +1231,9 @@ pub fn fold_element_expression< _: &E::Ty, e: ElementExpression<'ast, T, E>, ) -> ElementOrExpression<'ast, T, E> { - ElementOrExpression::Element(ElementExpression::new( - f.fold_tuple_expression(*e.tuple), - e.index, - )) -} - -pub fn fold_eq_expression<'ast, T: Field, E: Fold<'ast, T>, F: Folder<'ast, T>>( - f: &mut F, - e: EqExpression, -) -> EqOrBoolean<'ast, T, E> { - EqOrBoolean::Eq(EqExpression::new(e.left.fold(f), e.right.fold(f))) + ElementOrExpression::Element( + ElementExpression::new(f.fold_tuple_expression(*e.tuple), e.index).span(e.span), + ) } pub fn fold_select_expression< @@ -919,10 +1246,13 @@ pub fn fold_select_expression< _: &E::Ty, e: SelectExpression<'ast, T, E>, ) -> SelectOrExpression<'ast, T, E> { - SelectOrExpression::Select(SelectExpression::new( - f.fold_array_expression(*e.array), - f.fold_uint_expression(*e.index), - )) + SelectOrExpression::Select( + SelectExpression::new( + f.fold_array_expression(*e.array), + f.fold_uint_expression(*e.index), + ) + .span(e.span), + ) } pub fn fold_int_expression<'ast, T: Field, F: Folder<'ast, T>>( @@ -932,7 +1262,15 @@ pub fn fold_int_expression<'ast, T: Field, F: Folder<'ast, T>>( unreachable!() } -pub fn fold_boolean_expression<'ast, T: Field, F: Folder<'ast, T>>( +fn fold_boolean_expression<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + e: BooleanExpression<'ast, T>, +) -> BooleanExpression<'ast, T> { + let span = e.get_span(); + f.fold_boolean_expression_cases(e).span(span) +} + +pub fn fold_boolean_expression_cases<'ast, T: Field, F: Folder<'ast, T>>( f: &mut F, e: BooleanExpression<'ast, T>, ) -> BooleanExpression<'ast, T> { @@ -944,85 +1282,62 @@ pub fn fold_boolean_expression<'ast, T: Field, F: Folder<'ast, T>>( IdentifierOrExpression::Expression(u) => u, }, Block(block) => BooleanExpression::Block(f.fold_block_expression(block)), - Value(v) => BooleanExpression::Value(v), + Value(e) => match f.fold_boolean_value_expression(e) { + ValueOrExpression::Value(e) => Value(e), + ValueOrExpression::Expression(u) => u, + }, FieldEq(e) => match f.fold_eq_expression(e) { - EqOrBoolean::Eq(e) => BooleanExpression::FieldEq(e), - EqOrBoolean::Boolean(u) => u, + BinaryOrExpression::Binary(e) => FieldEq(e), + BinaryOrExpression::Expression(u) => u, }, BoolEq(e) => match f.fold_eq_expression(e) { - EqOrBoolean::Eq(e) => BooleanExpression::BoolEq(e), - EqOrBoolean::Boolean(u) => u, + BinaryOrExpression::Binary(e) => BoolEq(e), + BinaryOrExpression::Expression(u) => u, }, ArrayEq(e) => match f.fold_eq_expression(e) { - EqOrBoolean::Eq(e) => BooleanExpression::ArrayEq(e), - EqOrBoolean::Boolean(u) => u, + BinaryOrExpression::Binary(e) => ArrayEq(e), + BinaryOrExpression::Expression(u) => u, }, StructEq(e) => match f.fold_eq_expression(e) { - EqOrBoolean::Eq(e) => BooleanExpression::StructEq(e), - EqOrBoolean::Boolean(u) => u, + BinaryOrExpression::Binary(e) => StructEq(e), + BinaryOrExpression::Expression(u) => u, }, TupleEq(e) => match f.fold_eq_expression(e) { - EqOrBoolean::Eq(e) => BooleanExpression::TupleEq(e), - EqOrBoolean::Boolean(u) => u, + BinaryOrExpression::Binary(e) => TupleEq(e), + BinaryOrExpression::Expression(u) => u, }, UintEq(e) => match f.fold_eq_expression(e) { - EqOrBoolean::Eq(e) => BooleanExpression::UintEq(e), - EqOrBoolean::Boolean(u) => u, + BinaryOrExpression::Binary(e) => UintEq(e), + BinaryOrExpression::Expression(u) => u, + }, + FieldLt(e) => match f.fold_binary_expression(&Type::Boolean, e) { + BinaryOrExpression::Binary(e) => FieldLt(e), + BinaryOrExpression::Expression(u) => u, + }, + FieldLe(e) => match f.fold_binary_expression(&Type::Boolean, e) { + BinaryOrExpression::Binary(e) => FieldLe(e), + BinaryOrExpression::Expression(u) => u, + }, + UintLt(e) => match f.fold_binary_expression(&Type::Boolean, e) { + BinaryOrExpression::Binary(e) => UintLt(e), + BinaryOrExpression::Expression(u) => u, + }, + UintLe(e) => match f.fold_binary_expression(&Type::Boolean, e) { + BinaryOrExpression::Binary(e) => UintLe(e), + BinaryOrExpression::Expression(u) => u, + }, + Or(e) => match f.fold_binary_expression(&Type::Boolean, e) { + BinaryOrExpression::Binary(e) => Or(e), + BinaryOrExpression::Expression(u) => u, + }, + And(e) => match f.fold_binary_expression(&Type::Boolean, e) { + BinaryOrExpression::Binary(e) => And(e), + BinaryOrExpression::Expression(u) => u, + }, + Not(e) => match f.fold_unary_expression(&Type::Boolean, e) { + UnaryOrExpression::Unary(e) => Not(e), + UnaryOrExpression::Expression(u) => u, }, - FieldLt(box e1, box e2) => { - let e1 = f.fold_field_expression(e1); - let e2 = f.fold_field_expression(e2); - FieldLt(box e1, box e2) - } - FieldLe(box e1, box e2) => { - let e1 = f.fold_field_expression(e1); - let e2 = f.fold_field_expression(e2); - FieldLe(box e1, box e2) - } - FieldGt(box e1, box e2) => { - let e1 = f.fold_field_expression(e1); - let e2 = f.fold_field_expression(e2); - FieldGt(box e1, box e2) - } - FieldGe(box e1, box e2) => { - let e1 = f.fold_field_expression(e1); - let e2 = f.fold_field_expression(e2); - FieldGe(box e1, box e2) - } - UintLt(box e1, box e2) => { - let e1 = f.fold_uint_expression(e1); - let e2 = f.fold_uint_expression(e2); - UintLt(box e1, box e2) - } - UintLe(box e1, box e2) => { - let e1 = f.fold_uint_expression(e1); - let e2 = f.fold_uint_expression(e2); - UintLe(box e1, box e2) - } - UintGt(box e1, box e2) => { - let e1 = f.fold_uint_expression(e1); - let e2 = f.fold_uint_expression(e2); - UintGt(box e1, box e2) - } - UintGe(box e1, box e2) => { - let e1 = f.fold_uint_expression(e1); - let e2 = f.fold_uint_expression(e2); - UintGe(box e1, box e2) - } - Or(box e1, box e2) => { - let e1 = f.fold_boolean_expression(e1); - let e2 = f.fold_boolean_expression(e2); - Or(box e1, box e2) - } - And(box e1, box e2) => { - let e1 = f.fold_boolean_expression(e1); - let e2 = f.fold_boolean_expression(e2); - And(box e1, box e2) - } - Not(box e) => { - let e = f.fold_boolean_expression(e); - Not(box e) - } FunctionCall(function_call) => { match f.fold_function_call_expression(&Type::Boolean, function_call) { FunctionCallOrExpression::FunctionCall(function_call) => { @@ -1060,7 +1375,16 @@ pub fn fold_uint_expression<'ast, T: Field, F: Folder<'ast, T>>( } } -pub fn fold_uint_expression_inner<'ast, T: Field, F: Folder<'ast, T>>( +fn fold_uint_expression_inner<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + ty: UBitwidth, + e: UExpressionInner<'ast, T>, +) -> UExpressionInner<'ast, T> { + let span = e.get_span(); + f.fold_uint_expression_cases(ty, e).span(span) +} + +pub fn fold_uint_expression_cases<'ast, T: Field, F: Folder<'ast, T>>( f: &mut F, ty: UBitwidth, e: UExpressionInner<'ast, T>, @@ -1074,87 +1398,62 @@ pub fn fold_uint_expression_inner<'ast, T: Field, F: Folder<'ast, T>>( }, Block(block) => Block(f.fold_block_expression(block)), Value(v) => Value(v), - Add(box left, box right) => { - let left = f.fold_uint_expression(left); - let right = f.fold_uint_expression(right); - - Add(box left, box right) - } - Sub(box left, box right) => { - let left = f.fold_uint_expression(left); - let right = f.fold_uint_expression(right); - - Sub(box left, box right) - } - FloorSub(box left, box right) => { - let left = f.fold_uint_expression(left); - let right = f.fold_uint_expression(right); - - FloorSub(box left, box right) - } - Mult(box left, box right) => { - let left = f.fold_uint_expression(left); - let right = f.fold_uint_expression(right); - - Mult(box left, box right) - } - Div(box left, box right) => { - let left = f.fold_uint_expression(left); - let right = f.fold_uint_expression(right); - - Div(box left, box right) - } - Rem(box left, box right) => { - let left = f.fold_uint_expression(left); - let right = f.fold_uint_expression(right); - - Rem(box left, box right) - } - Xor(box left, box right) => { - let left = f.fold_uint_expression(left); - let right = f.fold_uint_expression(right); - - Xor(box left, box right) - } - And(box left, box right) => { - let left = f.fold_uint_expression(left); - let right = f.fold_uint_expression(right); - - And(box left, box right) - } - Or(box left, box right) => { - let left = f.fold_uint_expression(left); - let right = f.fold_uint_expression(right); - - Or(box left, box right) - } - LeftShift(box e, box by) => { - let e = f.fold_uint_expression(e); - let by = f.fold_uint_expression(by); - - LeftShift(box e, box by) - } - RightShift(box e, box by) => { - let e = f.fold_uint_expression(e); - let by = f.fold_uint_expression(by); - - RightShift(box e, box by) - } - Not(box e) => { - let e = f.fold_uint_expression(e); - - Not(box e) - } - Neg(box e) => { - let e = f.fold_uint_expression(e); - - Neg(box e) - } - Pos(box e) => { - let e = f.fold_uint_expression(e); - - Pos(box e) - } + Add(e) => match f.fold_binary_expression(&ty, e) { + BinaryOrExpression::Binary(e) => Add(e), + BinaryOrExpression::Expression(u) => u, + }, + Sub(e) => match f.fold_binary_expression(&ty, e) { + BinaryOrExpression::Binary(e) => Sub(e), + BinaryOrExpression::Expression(u) => u, + }, + FloorSub(e) => match f.fold_binary_expression(&ty, e) { + BinaryOrExpression::Binary(e) => FloorSub(e), + BinaryOrExpression::Expression(u) => u, + }, + Mult(e) => match f.fold_binary_expression(&ty, e) { + BinaryOrExpression::Binary(e) => Mult(e), + BinaryOrExpression::Expression(u) => u, + }, + Div(e) => match f.fold_binary_expression(&ty, e) { + BinaryOrExpression::Binary(e) => Div(e), + BinaryOrExpression::Expression(u) => u, + }, + Rem(e) => match f.fold_binary_expression(&ty, e) { + BinaryOrExpression::Binary(e) => Rem(e), + BinaryOrExpression::Expression(u) => u, + }, + Xor(e) => match f.fold_binary_expression(&ty, e) { + BinaryOrExpression::Binary(e) => Xor(e), + BinaryOrExpression::Expression(u) => u, + }, + And(e) => match f.fold_binary_expression(&ty, e) { + BinaryOrExpression::Binary(e) => And(e), + BinaryOrExpression::Expression(u) => u, + }, + Or(e) => match f.fold_binary_expression(&ty, e) { + BinaryOrExpression::Binary(e) => Or(e), + BinaryOrExpression::Expression(u) => u, + }, + LeftShift(e) => match f.fold_binary_expression(&ty, e) { + BinaryOrExpression::Binary(e) => LeftShift(e), + BinaryOrExpression::Expression(u) => u, + }, + RightShift(e) => match f.fold_binary_expression(&ty, e) { + BinaryOrExpression::Binary(e) => RightShift(e), + BinaryOrExpression::Expression(u) => u, + }, + Not(e) => match f.fold_unary_expression(&ty, e) { + UnaryOrExpression::Unary(e) => Not(e), + UnaryOrExpression::Expression(u) => u, + }, + Neg(e) => match f.fold_unary_expression(&ty, e) { + UnaryOrExpression::Unary(e) => Neg(e), + UnaryOrExpression::Expression(u) => u, + }, + Pos(e) => match f.fold_unary_expression(&ty, e) { + UnaryOrExpression::Unary(e) => Pos(e), + UnaryOrExpression::Expression(u) => u, + }, FunctionCall(function_call) => match f.fold_function_call_expression(&ty, function_call) { FunctionCallOrExpression::FunctionCall(function_call) => FunctionCall(function_call), FunctionCallOrExpression::Expression(u) => u, @@ -1178,18 +1477,19 @@ pub fn fold_uint_expression_inner<'ast, T: Field, F: Folder<'ast, T>>( } } -pub fn fold_block_expression<'ast, T: Field, E: Fold<'ast, T>, F: Folder<'ast, T>>( +pub fn fold_block_expression<'ast, T: Field, E: Fold, F: Folder<'ast, T>>( f: &mut F, block: BlockExpression<'ast, T, E>, ) -> BlockExpression<'ast, T, E> { - BlockExpression { - statements: block + BlockExpression::new( + block .statements .into_iter() .flat_map(|s| f.fold_statement(s)) .collect(), - value: box block.value.fold(f), - } + block.value.fold(f), + ) + .span(block.span) } pub fn fold_declaration_function_key<'ast, T: Field, F: Folder<'ast, T>>( @@ -1213,17 +1513,20 @@ pub fn fold_function_call_expression< _: &E::Ty, e: FunctionCallExpression<'ast, T, E>, ) -> FunctionCallOrExpression<'ast, T, E> { - FunctionCallOrExpression::FunctionCall(FunctionCallExpression::new( - f.fold_declaration_function_key(e.function_key), - e.generics - .into_iter() - .map(|g| g.map(|g| f.fold_uint_expression(g))) - .collect(), - e.arguments - .into_iter() - .map(|e| f.fold_expression(e)) - .collect(), - )) + FunctionCallOrExpression::FunctionCall( + FunctionCallExpression::new( + f.fold_declaration_function_key(e.function_key), + e.generics + .into_iter() + .map(|g| g.map(|g| f.fold_uint_expression(g))) + .collect(), + e.arguments + .into_iter() + .map(|e| f.fold_expression(e)) + .collect(), + ) + .span(e.span), + ) } pub fn fold_function<'ast, T: Field, F: Folder<'ast, T>>( @@ -1256,7 +1559,7 @@ fn fold_signature<'ast, T: Field, F: Folder<'ast, T>>( .into_iter() .map(|o| f.fold_declaration_type(o)) .collect(), - output: box f.fold_declaration_type(*s.output), + output: Box::new(f.fold_declaration_type(*s.output)), } } @@ -1281,7 +1584,7 @@ pub fn fold_array_expression<'ast, T: Field, F: Folder<'ast, T>>( ArrayExpression { inner: f.fold_array_expression_inner(&ty, e.inner), - ty: box ty, + ty: Box::new(ty), } } @@ -1307,6 +1610,64 @@ pub fn fold_tuple_expression<'ast, T: Field, F: Folder<'ast, T>>( } } +pub fn fold_integer_value_expression<'ast, T: Field, F: Folder<'ast, T>>( + _f: &mut F, + a: IntValueExpression, +) -> ValueOrExpression> { + ValueOrExpression::Value(a) +} + +pub fn fold_boolean_value_expression<'ast, T: Field, F: Folder<'ast, T>>( + _f: &mut F, + a: BooleanValueExpression, +) -> ValueOrExpression> { + ValueOrExpression::Value(a) +} + +pub fn fold_field_value_expression<'ast, T: Field, F: Folder<'ast, T>>( + _f: &mut F, + a: FieldValueExpression, +) -> ValueOrExpression, FieldElementExpression<'ast, T>> { + ValueOrExpression::Value(a) +} + +pub fn fold_struct_value_expression<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + _ty: &StructType<'ast, T>, + a: StructValueExpression<'ast, T>, +) -> ValueOrExpression, StructExpressionInner<'ast, T>> { + ValueOrExpression::Value(StructValueExpression { + value: a.value.into_iter().map(|v| f.fold_expression(v)).collect(), + ..a + }) +} + +pub fn fold_array_value_expression<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + _ty: &ArrayType<'ast, T>, + a: ArrayValueExpression<'ast, T>, +) -> ValueOrExpression, ArrayExpressionInner<'ast, T>> { + ValueOrExpression::Value(ArrayValueExpression { + value: a + .value + .into_iter() + .map(|v| f.fold_expression_or_spread(v)) + .collect(), + ..a + }) +} + +pub fn fold_tuple_value_expression<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + _ty: &TupleType<'ast, T>, + a: TupleValueExpression<'ast, T>, +) -> ValueOrExpression, TupleExpressionInner<'ast, T>> { + ValueOrExpression::Value(TupleValueExpression { + value: a.value.into_iter().map(|v| f.fold_expression(v)).collect(), + ..a + }) +} + pub fn fold_constant<'ast, T: Field, F: Folder<'ast, T>>( f: &mut F, c: TypedConstant<'ast, T>, @@ -1348,12 +1709,13 @@ pub fn fold_assignee<'ast, T: Field, F: Folder<'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_uint_expression(index)) - } - TypedAssignee::Member(box s, m) => TypedAssignee::Member(box f.fold_assignee(s), m), - TypedAssignee::Element(box s, index) => { - TypedAssignee::Element(box f.fold_assignee(s), index) + TypedAssignee::Select(a, index) => TypedAssignee::Select( + Box::new(f.fold_assignee(*a)), + Box::new(f.fold_uint_expression(*index)), + ), + TypedAssignee::Member(s, m) => TypedAssignee::Member(Box::new(f.fold_assignee(*s)), m), + TypedAssignee::Element(s, index) => { + TypedAssignee::Element(Box::new(f.fold_assignee(*s)), index) } } } @@ -1369,5 +1731,6 @@ pub fn fold_program<'ast, T: Field, F: Folder<'ast, T>>( .map(|(module_id, module)| (f.fold_module_id(module_id), f.fold_module(module))) .collect(), main: f.fold_module_id(p.main), + ..p } } diff --git a/zokrates_ast/src/typed/identifier.rs b/zokrates_ast/src/typed/identifier.rs index 772eb2bf2..f4e433db6 100644 --- a/zokrates_ast/src/typed/identifier.rs +++ b/zokrates_ast/src/typed/identifier.rs @@ -8,7 +8,7 @@ pub type SourceIdentifier<'ast> = std::borrow::Cow<'ast, str>; pub enum CoreIdentifier<'ast> { #[serde(borrow)] Source(ShadowedIdentifier<'ast>), - Call(usize), + Call, Constant(CanonicalConstantIdentifier<'ast>), Condition(usize), } @@ -17,25 +17,56 @@ impl<'ast> fmt::Display for CoreIdentifier<'ast> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { CoreIdentifier::Source(s) => write!(f, "{}", s), - CoreIdentifier::Call(i) => write!(f, "#CALL_RETURN_AT_INDEX_{}", i), + CoreIdentifier::Call => write!(f, "#CALL_RETURN"), CoreIdentifier::Constant(c) => write!(f, "{}/{}", c.module.display(), c.id), CoreIdentifier::Condition(i) => write!(f, "#CONDITION_{}", i), } } } -impl<'ast> From> for CoreIdentifier<'ast> { - fn from(s: CanonicalConstantIdentifier<'ast>) -> CoreIdentifier<'ast> { - CoreIdentifier::Constant(s) +impl<'ast> FrameIdentifier<'ast> { + pub fn in_frame(self, frame: usize) -> FrameIdentifier<'ast> { + FrameIdentifier { frame, ..self } } } +impl<'ast> Identifier<'ast> { + pub fn in_frame(self, frame: usize) -> Identifier<'ast> { + Identifier { + id: self.id.in_frame(frame), + ..self + } + } +} + +impl<'ast> CoreIdentifier<'ast> { + pub fn in_frame(self, frame: usize) -> FrameIdentifier<'ast> { + FrameIdentifier { id: self, frame } + } +} + +impl<'ast> From> for FrameIdentifier<'ast> { + fn from(s: CanonicalConstantIdentifier<'ast>) -> FrameIdentifier<'ast> { + FrameIdentifier::from(CoreIdentifier::Constant(s)) + } +} + +/// A identifier for a variable in a given call frame +#[derive(Debug, PartialEq, Clone, Hash, Eq, PartialOrd, Ord, Serialize, Deserialize)] +pub struct FrameIdentifier<'ast> { + /// the id of the variable + #[serde(borrow)] + pub id: CoreIdentifier<'ast>, + /// the frame of the variable + pub frame: usize, +} + /// A identifier for a variable #[derive(Debug, PartialEq, Clone, Hash, Eq, PartialOrd, Ord, Serialize, Deserialize)] pub struct Identifier<'ast> { /// the id of the variable #[serde(borrow)] - pub id: CoreIdentifier<'ast>, + pub id: FrameIdentifier<'ast>, /// the version of the variable, used after SSA transformation pub version: usize, } @@ -58,7 +89,7 @@ impl<'ast> fmt::Display for ShadowedIdentifier<'ast> { if self.shadow == 0 { write!(f, "{}", self.id) } else { - write!(f, "{}_{}", self.id, self.shadow) + write!(f, "{}_s{}", self.id, self.shadow) } } } @@ -68,20 +99,45 @@ impl<'ast> fmt::Display for Identifier<'ast> { if self.version == 0 { write!(f, "{}", self.id) } else { - write!(f, "{}_{}", self.id, self.version) + write!(f, "{}_v{}", self.id, self.version) + } + } +} + +impl<'ast> fmt::Display for FrameIdentifier<'ast> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.frame == 0 { + write!(f, "{}", self.id) + } else { + write!(f, "{}_f{}", self.id, self.frame) } } } impl<'ast> From> for Identifier<'ast> { fn from(id: CanonicalConstantIdentifier<'ast>) -> Identifier<'ast> { - Identifier::from(CoreIdentifier::Constant(id)) + Identifier::from(FrameIdentifier::from(CoreIdentifier::Constant(id))) + } +} + +impl<'ast> From> for Identifier<'ast> { + fn from(id: FrameIdentifier<'ast>) -> Identifier<'ast> { + Identifier { id, version: 0 } } } impl<'ast> From> for Identifier<'ast> { fn from(id: CoreIdentifier<'ast>) -> Identifier<'ast> { - Identifier { id, version: 0 } + Identifier { + id: FrameIdentifier::from(id), + version: 0, + } + } +} + +impl<'ast> From> for FrameIdentifier<'ast> { + fn from(id: CoreIdentifier<'ast>) -> FrameIdentifier<'ast> { + FrameIdentifier { id, frame: 0 } } } @@ -107,6 +163,6 @@ impl<'ast> From<&'ast str> for CoreIdentifier<'ast> { impl<'ast> From<&'ast str> for Identifier<'ast> { fn from(id: &'ast str) -> Identifier<'ast> { - Identifier::from(CoreIdentifier::from(id)) + Identifier::from(FrameIdentifier::from(CoreIdentifier::from(id))) } } diff --git a/zokrates_ast/src/typed/integer.rs b/zokrates_ast/src/typed/integer.rs index 507ce9174..d5ba9ad58 100644 --- a/zokrates_ast/src/typed/integer.rs +++ b/zokrates_ast/src/typed/integer.rs @@ -8,14 +8,21 @@ use crate::typed::{ ArrayExpression, ArrayExpressionInner, BooleanExpression, Conditional, ConditionalExpression, Expr, FieldElementExpression, Select, SelectExpression, StructExpression, StructExpressionInner, TupleExpression, TupleExpressionInner, Typed, TypedExpression, - TypedExpressionOrSpread, TypedSpread, UExpression, UExpressionInner, + TypedExpressionOrSpread, TypedSpread, UExpression, }; + +use crate::common::{operators::*, WithSpan}; + use num_bigint::BigUint; use std::convert::TryFrom; use std::fmt; -use std::ops::{Add, Div, Mul, Neg, Not, Rem, Sub}; +use std::ops::*; use zokrates_field::Field; +use crate::common::expressions::*; + +use super::{ArrayValueExpression, RepeatExpression}; + type TypedExpressionPair<'ast, T> = (TypedExpression<'ast, T>, TypedExpression<'ast, T>); impl<'ast, T: Field> TypedExpressionOrSpread<'ast, T> { @@ -103,7 +110,7 @@ impl<'ast, T: Clone> IntegerInference for StructType<'ast, T> { .zip(other.members.into_iter()) .map(|(m_t, m_u)| match m_t.ty.get_common_pattern(*m_u.ty) { Ok(ty) => DeclarationStructMember { - ty: box ty, + ty: Box::new(ty), id: m_t.id, }, Err(..) => unreachable!( @@ -274,30 +281,107 @@ impl<'ast, T: Field> TypedExpression<'ast, T> { #[derive(Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)] pub enum IntExpression<'ast, T> { - Value(BigUint), - Pos(Box>), - Neg(Box>), - Add(Box>, Box>), - Sub(Box>, Box>), - Mult(Box>, Box>), - Div(Box>, Box>), - Rem(Box>, Box>), - Pow(Box>, Box>), + Value(IntValueExpression), + Pos(UnaryExpression, IntExpression<'ast, T>>), + Neg(UnaryExpression, IntExpression<'ast, T>>), + Not(UnaryExpression, IntExpression<'ast, T>>), + Add( + BinaryExpression< + OpAdd, + IntExpression<'ast, T>, + IntExpression<'ast, T>, + IntExpression<'ast, T>, + >, + ), + Sub( + BinaryExpression< + OpSub, + IntExpression<'ast, T>, + IntExpression<'ast, T>, + IntExpression<'ast, T>, + >, + ), + Mult( + BinaryExpression< + OpMul, + IntExpression<'ast, T>, + IntExpression<'ast, T>, + IntExpression<'ast, T>, + >, + ), + Div( + BinaryExpression< + OpDiv, + IntExpression<'ast, T>, + IntExpression<'ast, T>, + IntExpression<'ast, T>, + >, + ), + Rem( + BinaryExpression< + OpRem, + IntExpression<'ast, T>, + IntExpression<'ast, T>, + IntExpression<'ast, T>, + >, + ), + Pow( + BinaryExpression< + OpPow, + IntExpression<'ast, T>, + IntExpression<'ast, T>, + IntExpression<'ast, T>, + >, + ), + Xor( + BinaryExpression< + OpXor, + IntExpression<'ast, T>, + IntExpression<'ast, T>, + IntExpression<'ast, T>, + >, + ), + And( + BinaryExpression< + OpAnd, + IntExpression<'ast, T>, + IntExpression<'ast, T>, + IntExpression<'ast, T>, + >, + ), + Or( + BinaryExpression< + OpOr, + IntExpression<'ast, T>, + IntExpression<'ast, T>, + IntExpression<'ast, T>, + >, + ), + LeftShift( + BinaryExpression< + OpLsh, + IntExpression<'ast, T>, + UExpression<'ast, T>, + IntExpression<'ast, T>, + >, + ), + RightShift( + BinaryExpression< + OpRsh, + IntExpression<'ast, T>, + UExpression<'ast, T>, + IntExpression<'ast, T>, + >, + ), Conditional(ConditionalExpression<'ast, T, IntExpression<'ast, T>>), Select(SelectExpression<'ast, T, IntExpression<'ast, T>>), - Xor(Box>, Box>), - And(Box>, Box>), - Or(Box>, Box>), - Not(Box>), - LeftShift(Box>, Box>), - RightShift(Box>, Box>), } impl<'ast, T> Add for IntExpression<'ast, T> { type Output = Self; fn add(self, other: Self) -> Self { - IntExpression::Add(box self, box other) + IntExpression::Add(BinaryExpression::new(self, other)) } } @@ -305,7 +389,7 @@ impl<'ast, T> Sub for IntExpression<'ast, T> { type Output = Self; fn sub(self, other: Self) -> Self { - IntExpression::Sub(box self, box other) + IntExpression::Sub(BinaryExpression::new(self, other)) } } @@ -313,7 +397,7 @@ impl<'ast, T> Mul for IntExpression<'ast, T> { type Output = Self; fn mul(self, other: Self) -> Self { - IntExpression::Mult(box self, box other) + IntExpression::Mult(BinaryExpression::new(self, other)) } } @@ -321,7 +405,7 @@ impl<'ast, T> Div for IntExpression<'ast, T> { type Output = Self; fn div(self, other: Self) -> Self { - IntExpression::Div(box self, box other) + IntExpression::Div(BinaryExpression::new(self, other)) } } @@ -329,7 +413,7 @@ impl<'ast, T> Rem for IntExpression<'ast, T> { type Output = Self; fn rem(self, other: Self) -> Self { - IntExpression::Rem(box self, box other) + IntExpression::Rem(BinaryExpression::new(self, other)) } } @@ -337,7 +421,7 @@ impl<'ast, T> Not for IntExpression<'ast, T> { type Output = Self; fn not(self) -> Self { - IntExpression::Not(box self) + IntExpression::Not(UnaryExpression::new(self)) } } @@ -345,37 +429,37 @@ impl<'ast, T> Neg for IntExpression<'ast, T> { type Output = Self; fn neg(self) -> Self { - IntExpression::Neg(box self) + IntExpression::Neg(UnaryExpression::new(self)) } } impl<'ast, T> IntExpression<'ast, T> { pub fn pow(self, other: Self) -> Self { - IntExpression::Pow(box self, box other) + IntExpression::Pow(BinaryExpression::new(self, other)) } pub fn and(self, other: Self) -> Self { - IntExpression::And(box self, box other) + IntExpression::And(BinaryExpression::new(self, other)) } pub fn xor(self, other: Self) -> Self { - IntExpression::Xor(box self, box other) + IntExpression::Xor(BinaryExpression::new(self, other)) } pub fn or(self, other: Self) -> Self { - IntExpression::Or(box self, box other) + IntExpression::Or(BinaryExpression::new(self, other)) } pub fn left_shift(self, by: UExpression<'ast, T>) -> Self { - IntExpression::LeftShift(box self, box by) + IntExpression::LeftShift(BinaryExpression::new(self, by)) } pub fn right_shift(self, by: UExpression<'ast, T>) -> Self { - IntExpression::RightShift(box self, box by) + IntExpression::RightShift(BinaryExpression::new(self, by)) } pub fn pos(self) -> Self { - IntExpression::Pos(box self) + IntExpression::Pos(UnaryExpression::new(self)) } } @@ -383,21 +467,21 @@ impl<'ast, T: fmt::Display> fmt::Display for IntExpression<'ast, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { IntExpression::Value(ref v) => write!(f, "{}", v), - IntExpression::Pos(ref e) => write!(f, "(+{})", e), - IntExpression::Neg(ref e) => write!(f, "(-{})", e), - IntExpression::Div(ref lhs, ref rhs) => write!(f, "({} / {})", lhs, rhs), - IntExpression::Rem(ref lhs, ref rhs) => write!(f, "({} % {})", lhs, rhs), - IntExpression::Pow(ref lhs, ref rhs) => write!(f, "({} ** {})", lhs, rhs), + IntExpression::Pos(ref e) => write!(f, "{}", e), + IntExpression::Neg(ref e) => write!(f, "{}", e), + IntExpression::Div(ref e) => write!(f, "{}", e), + IntExpression::Rem(ref e) => write!(f, "{}", e), + IntExpression::Pow(ref e) => write!(f, "{}", e), IntExpression::Select(ref select) => write!(f, "{}", select), - IntExpression::Add(ref lhs, ref rhs) => write!(f, "({} + {})", lhs, rhs), - IntExpression::And(ref lhs, ref rhs) => write!(f, "({} & {})", lhs, rhs), - IntExpression::Or(ref lhs, ref rhs) => write!(f, "({} | {})", lhs, rhs), - IntExpression::Xor(ref lhs, ref rhs) => write!(f, "({} ^ {})", lhs, rhs), - IntExpression::Sub(ref lhs, ref rhs) => write!(f, "({} - {})", lhs, rhs), - IntExpression::Mult(ref lhs, ref rhs) => write!(f, "({} * {})", lhs, rhs), - IntExpression::RightShift(ref e, ref by) => write!(f, "({} >> {})", e, by), - IntExpression::LeftShift(ref e, ref by) => write!(f, "({} << {})", e, by), - IntExpression::Not(ref e) => write!(f, "!{}", e), + IntExpression::Add(ref e) => write!(f, "{}", e), + IntExpression::And(ref e) => write!(f, "{}", e), + IntExpression::Or(ref e) => write!(f, "{}", e), + IntExpression::Xor(ref e) => write!(f, "{}", e), + IntExpression::Sub(ref e) => write!(f, "{}", e), + IntExpression::Mult(ref e) => write!(f, "{}", e), + IntExpression::RightShift(ref e) => write!(f, "{}", e), + IntExpression::LeftShift(ref e) => write!(f, "{}", e), + IntExpression::Not(ref e) => write!(f, "{}", e), IntExpression::Conditional(ref c) => write!(f, "{}", c), } } @@ -424,48 +508,52 @@ impl<'ast, T: Field> FieldElementExpression<'ast, T> { } pub fn try_from_int(i: IntExpression<'ast, T>) -> Result> { + let span = i.get_span(); + match i { - IntExpression::Value(i) => Ok(Self::Number(T::try_from(i.clone()).map_err(|_| i)?)), - IntExpression::Add(box e1, box e2) => Ok(Self::Add( - box Self::try_from_int(e1)?, - box Self::try_from_int(e2)?, + IntExpression::Value(i) => Ok(Self::Value(ValueExpression::new( + T::try_from(i.value.clone()).map_err(|_| IntExpression::Value(i))?, + ))), + IntExpression::Add(e) => Ok(Self::add( + Self::try_from_int(*e.left)?, + Self::try_from_int(*e.right)?, )), - IntExpression::Sub(box e1, box e2) => Ok(Self::Sub( - box Self::try_from_int(e1)?, - box Self::try_from_int(e2)?, + IntExpression::Sub(e) => Ok(Self::sub( + Self::try_from_int(*e.left)?, + Self::try_from_int(*e.right)?, )), - IntExpression::Mult(box e1, box e2) => Ok(Self::Mult( - box Self::try_from_int(e1)?, - box Self::try_from_int(e2)?, + IntExpression::Mult(e) => Ok(Self::mul( + Self::try_from_int(*e.left)?, + Self::try_from_int(*e.right)?, )), - IntExpression::Pow(box e1, box e2) => Ok(Self::Pow( - box Self::try_from_int(e1)?, - box UExpression::try_from_int(e2, &UBitwidth::B32)?, + IntExpression::Pow(e) => Ok(Self::pow( + Self::try_from_int(*e.left)?, + UExpression::try_from_int(*e.right, &UBitwidth::B32)?, )), - IntExpression::Div(box e1, box e2) => Ok(Self::Div( - box Self::try_from_int(e1)?, - box Self::try_from_int(e2)?, + IntExpression::Div(e) => Ok(Self::div( + Self::try_from_int(*e.left)?, + Self::try_from_int(*e.right)?, )), - IntExpression::And(box e1, box e2) => Ok(Self::And( - box Self::try_from_int(e1)?, - box Self::try_from_int(e2)?, + IntExpression::And(e) => Ok(Self::bitand( + Self::try_from_int(*e.left)?, + Self::try_from_int(*e.right)?, )), - IntExpression::Or(box e1, box e2) => Ok(Self::Or( - box Self::try_from_int(e1)?, - box Self::try_from_int(e2)?, + IntExpression::Or(e) => Ok(Self::bitor( + Self::try_from_int(*e.left)?, + Self::try_from_int(*e.right)?, )), - IntExpression::Xor(box e1, box e2) => Ok(Self::Xor( - box Self::try_from_int(e1)?, - box Self::try_from_int(e2)?, + IntExpression::Xor(e) => Ok(Self::bitxor( + Self::try_from_int(*e.left)?, + Self::try_from_int(*e.right)?, )), - IntExpression::LeftShift(box e1, box e2) => { - Ok(Self::LeftShift(box Self::try_from_int(e1)?, box e2)) + IntExpression::LeftShift(e) => { + Ok(Self::left_shift(Self::try_from_int(*e.left)?, *e.right)) } - IntExpression::RightShift(box e1, box e2) => { - Ok(Self::RightShift(box Self::try_from_int(e1)?, box e2)) + IntExpression::RightShift(e) => { + Ok(Self::right_shift(Self::try_from_int(*e.left)?, *e.right)) } - IntExpression::Pos(box e) => Ok(Self::Pos(box Self::try_from_int(e)?)), - IntExpression::Neg(box e) => Ok(Self::Neg(box Self::try_from_int(e)?)), + IntExpression::Pos(e) => Ok(Self::pos(Self::try_from_int(*e.inner)?)), + IntExpression::Neg(e) => Ok(Self::neg(Self::try_from_int(*e.inner)?)), IntExpression::Conditional(c) => Ok(Self::Conditional(ConditionalExpression::new( *c.condition, Self::try_from_int(*c.consequence)?, @@ -481,6 +569,7 @@ impl<'ast, T: Field> FieldElementExpression<'ast, T> { match array.into_inner() { ArrayExpressionInner::Value(values) => { let values = values + .value .into_iter() .map(|v| { TypedExpressionOrSpread::align_to_type( @@ -501,8 +590,8 @@ impl<'ast, T: Field> FieldElementExpression<'ast, T> { }) .collect::, _>>()?; Ok(FieldElementExpression::select( - ArrayExpressionInner::Value(values.into()) - .annotate(Type::FieldElement, size), + ArrayExpression::value(values) + .annotate(ArrayType::new(Type::FieldElement, size)), index, )) } @@ -511,6 +600,7 @@ impl<'ast, T: Field> FieldElementExpression<'ast, T> { } i => Err(i), } + .map(|e| e.span(span)) } } @@ -537,54 +627,56 @@ impl<'ast, T: Field> UExpression<'ast, T> { ) -> Result> { use self::IntExpression::*; + let span = i.get_span(); + match i { Value(i) => { - if i <= BigUint::from(2u128.pow(bitwidth.to_usize() as u32) - 1) { - Ok(UExpressionInner::Value( - u128::from_str_radix(&i.to_str_radix(16), 16).unwrap(), + if i.value <= BigUint::from(2u128.pow(bitwidth.to_usize() as u32) - 1) { + Ok(UExpression::value( + u128::from_str_radix(&i.value.to_str_radix(16), 16).unwrap(), ) .annotate(*bitwidth)) } else { Err(Value(i)) } } - Add(box e1, box e2) => { - Ok(Self::try_from_int(e1, bitwidth)? + Self::try_from_int(e2, bitwidth)?) - } - Pos(box e) => Ok(Self::pos(Self::try_from_int(e, bitwidth)?)), - Neg(box e) => Ok(Self::neg(Self::try_from_int(e, bitwidth)?)), - Sub(box e1, box e2) => { - Ok(Self::try_from_int(e1, bitwidth)? - Self::try_from_int(e2, bitwidth)?) - } - Mult(box e1, box e2) => { - Ok(Self::try_from_int(e1, bitwidth)? * Self::try_from_int(e2, bitwidth)?) - } - Div(box e1, box e2) => { - Ok(Self::try_from_int(e1, bitwidth)? / Self::try_from_int(e2, bitwidth)?) - } - Rem(box e1, box e2) => { - Ok(Self::try_from_int(e1, bitwidth)? % Self::try_from_int(e2, bitwidth)?) - } - And(box e1, box e2) => Ok(UExpression::and( - Self::try_from_int(e1, bitwidth)?, - Self::try_from_int(e2, bitwidth)?, + Add(e) => Ok( + Self::try_from_int(*e.left, bitwidth)? + Self::try_from_int(*e.right, bitwidth)? + ), + Pos(e) => Ok(Self::pos(Self::try_from_int(*e.inner, bitwidth)?)), + Neg(e) => Ok(Self::neg(Self::try_from_int(*e.inner, bitwidth)?)), + Sub(e) => Ok( + Self::try_from_int(*e.left, bitwidth)? - Self::try_from_int(*e.right, bitwidth)? + ), + Mult(e) => Ok( + Self::try_from_int(*e.left, bitwidth)? * Self::try_from_int(*e.right, bitwidth)? + ), + Div(e) => Ok( + Self::try_from_int(*e.left, bitwidth)? / Self::try_from_int(*e.right, bitwidth)? + ), + Rem(e) => Ok( + Self::try_from_int(*e.left, bitwidth)? % Self::try_from_int(*e.right, bitwidth)? + ), + And(e) => Ok(UExpression::and( + Self::try_from_int(*e.left, bitwidth)?, + Self::try_from_int(*e.right, bitwidth)?, )), - Or(box e1, box e2) => Ok(UExpression::or( - Self::try_from_int(e1, bitwidth)?, - Self::try_from_int(e2, bitwidth)?, + Or(e) => Ok(UExpression::or( + Self::try_from_int(*e.left, bitwidth)?, + Self::try_from_int(*e.right, bitwidth)?, )), - Not(box e) => Ok(!Self::try_from_int(e, bitwidth)?), - Xor(box e1, box e2) => Ok(UExpression::xor( - Self::try_from_int(e1, bitwidth)?, - Self::try_from_int(e2, bitwidth)?, + Not(e) => Ok(!Self::try_from_int(*e.inner, bitwidth)?), + Xor(e) => Ok(UExpression::xor( + Self::try_from_int(*e.left, bitwidth)?, + Self::try_from_int(*e.right, bitwidth)?, )), - RightShift(box e1, box e2) => Ok(UExpression::right_shift( - Self::try_from_int(e1, bitwidth)?, - e2, + RightShift(e) => Ok(UExpression::right_shift( + Self::try_from_int(*e.left, bitwidth)?, + *e.right, )), - LeftShift(box e1, box e2) => Ok(UExpression::left_shift( - Self::try_from_int(e1, bitwidth)?, - e2, + LeftShift(e) => Ok(UExpression::left_shift( + Self::try_from_int(*e.left, bitwidth)?, + *e.right, )), Conditional(c) => Ok(UExpression::conditional( *c.condition, @@ -600,6 +692,7 @@ impl<'ast, T: Field> UExpression<'ast, T> { match array.into_inner() { ArrayExpressionInner::Value(values) => { let values = values + .value .into_iter() .map(|v| { TypedExpressionOrSpread::align_to_type( @@ -620,8 +713,8 @@ impl<'ast, T: Field> UExpression<'ast, T> { }) .collect::, _>>()?; Ok(UExpression::select( - ArrayExpressionInner::Value(values.into()) - .annotate(Type::Uint(*bitwidth), size), + ArrayExpression::value(values) + .annotate(ArrayType::new(Type::Uint(*bitwidth), size)), index, )) } @@ -630,6 +723,7 @@ impl<'ast, T: Field> UExpression<'ast, T> { } i => Err(i), } + .map(|e| e.span(span)) } } @@ -649,6 +743,8 @@ impl<'ast, T: Field> ArrayExpression<'ast, T> { array: Self, target_array_ty: &GArrayType, ) -> Result> { + let span = array.get_span(); + let array_ty = array.ty().clone(); // elements must fit in the target type @@ -659,6 +755,7 @@ impl<'ast, T: Field> ArrayExpression<'ast, T> { _ => { // try to convert all elements to the target type inline_array + .value .into_iter() .map(|v| { TypedExpressionOrSpread::align_to_type(v, target_array_ty).map_err( @@ -671,37 +768,43 @@ impl<'ast, T: Field> ArrayExpression<'ast, T> { ) }) .collect::, _>>() - .map(|v| v.into()) + .map(ArrayValueExpression::new) } }?; - let inner_ty = res.0[0].get_type().0; + let inner_ty = res.value[0].get_type().0; - Ok(ArrayExpressionInner::Value(res).annotate(inner_ty, *array_ty.size)) + let array_ty = ArrayType::new(inner_ty, *array_ty.size); + + Ok(ArrayExpressionInner::Value(res).annotate(array_ty)) } - ArrayExpressionInner::Repeat(box e, box count) => { + ArrayExpressionInner::Repeat(r) => { match &*target_array_ty.ty { - GType::Int => Ok(ArrayExpressionInner::Repeat(box e, box count) - .annotate(Type::Int, *array_ty.size)), + GType::Int => { + let array_ty = ArrayType::new(Type::Int, *array_ty.size); + + Ok(ArrayExpressionInner::Repeat(r).annotate(array_ty)) + } // try to align the repeated element to the target type - t => TypedExpression::align_to_type(e, t) + t => TypedExpression::align_to_type(*r.e, t) .map(|e| { let ty = e.get_type().clone(); - ArrayExpressionInner::Repeat(box e, box count) - .annotate(ty, *array_ty.size) + ArrayExpressionInner::Repeat(RepeatExpression::new(e, *r.count)) + .annotate(ArrayType::new(ty, *array_ty.size)) }) .map_err(|(e, _)| e), } } a => { if *target_array_ty.ty == *array_ty.ty { - Ok(a.annotate(*array_ty.ty, *array_ty.size)) + Ok(a.annotate(array_ty)) } else { - Err(a.annotate(*array_ty.ty, *array_ty.size).into()) + Err(a.annotate(array_ty).into()) } } } + .map(|e| e.span(span)) } } @@ -710,6 +813,8 @@ impl<'ast, T: Field> StructExpression<'ast, T> { struc: Self, target_struct_ty: &GStructType, ) -> Result> { + let span = struc.get_span(); + let struct_ty = struc.ty().clone(); if struct_ty.members.len() != target_struct_ty.members.len() { @@ -724,7 +829,7 @@ impl<'ast, T: Field> StructExpression<'ast, T> { TypedExpression::align_to_type(value, &*target_member.ty) }) .collect::, _>>() - .map(|v| StructExpressionInner::Value(v).annotate(struct_ty.clone())) + .map(|v| StructExpression::value(v).annotate(struct_ty.clone())) .map_err(|(v, _)| v), s => { if struct_ty @@ -739,6 +844,7 @@ impl<'ast, T: Field> StructExpression<'ast, T> { } } } + .map(|e| e.span(span)) } pub fn try_from_typed>>( @@ -757,6 +863,8 @@ impl<'ast, T: Field> TupleExpression<'ast, T> { tuple: Self, target_tuple_ty: >upleType, ) -> Result> { + let span = tuple.get_span(); + let tuple_ty = tuple.ty().clone(); if tuple_ty.elements.len() != target_tuple_ty.elements.len() { @@ -771,7 +879,7 @@ impl<'ast, T: Field> TupleExpression<'ast, T> { .collect::, _>>() .map(|v| { let ty = TupleType::new(v.iter().map(|e| e.get_type()).collect()); - TupleExpressionInner::Value(v).annotate(ty) + TupleExpression::value(v).annotate(ty) }) .map_err(|(v, _)| v), s => { @@ -787,6 +895,7 @@ impl<'ast, T: Field> TupleExpression<'ast, T> { } } } + .map(|e| e.span(span)) } pub fn try_from_typed>>( @@ -800,9 +909,9 @@ impl<'ast, T: Field> TupleExpression<'ast, T> { } } -impl<'ast, T> From for IntExpression<'ast, T> { +impl<'ast, T: Field> From for IntExpression<'ast, T> { fn from(v: BigUint) -> Self { - IntExpression::Value(v) + IntExpression::value(v) } } @@ -816,11 +925,13 @@ mod tests { fn field_from_int() { let n: IntExpression = BigUint::from(42usize).into(); let n_a: ArrayExpression = - ArrayExpressionInner::Value(vec![n.clone().into()].into()).annotate(Type::Int, 1u32); + ArrayExpressionInner::Value(ValueExpression::new(vec![n.clone().into()])) + .annotate(ArrayType::new(Type::Int, 1u32)); let t: FieldElementExpression = Bn128Field::from(42).into(); let t_a: ArrayExpression = - ArrayExpressionInner::Value(vec![t.clone().into()].into()) - .annotate(Type::FieldElement, 1u32); + ArrayExpressionInner::Value(ValueExpression::new(vec![t.clone().into()])) + .annotate(ArrayType::new(Type::FieldElement, 1u32)); + let i: UExpression = 42u32.into(); let c: BooleanExpression = true.into(); @@ -876,11 +987,12 @@ mod tests { fn uint_from_int() { let n: IntExpression = BigUint::from(42usize).into(); let n_a: ArrayExpression = - ArrayExpressionInner::Value(vec![n.clone().into()].into()).annotate(Type::Int, 1u32); + ArrayExpressionInner::Value(ValueExpression::new(vec![n.clone().into()])) + .annotate(ArrayType::new(Type::Int, 1u32)); let t: UExpression = 42u32.into(); let t_a: ArrayExpression = - ArrayExpressionInner::Value(vec![t.clone().into()].into()) - .annotate(Type::Uint(UBitwidth::B32), 1u32); + ArrayExpressionInner::Value(ValueExpression::new(vec![t.clone().into()])) + .annotate(ArrayType::new(Type::Uint(UBitwidth::B32), 1u32)); let i: UExpression = 0u32.into(); let c: BooleanExpression = true.into(); diff --git a/zokrates_ast/src/typed/mod.rs b/zokrates_ast/src/typed/mod.rs index 003e43c47..11786660c 100644 --- a/zokrates_ast/src/typed/mod.rs +++ b/zokrates_ast/src/typed/mod.rs @@ -27,16 +27,23 @@ pub use self::types::{ UBitwidth, }; use self::types::{ConcreteArrayType, ConcreteStructType}; -use crate::typed::types::{ConcreteGenericsAssignment, IntoType}; + +use crate::common::expressions::{ + self, BinaryExpression, BooleanValueExpression, FieldValueExpression, UnaryExpression, + ValueExpression, +}; +use crate::common::{self, ModuleMap, Span, Value, WithSpan}; +pub use crate::common::{ModuleId, OwnedModuleId}; +use crate::typed::types::IntoType; pub use self::variable::{ConcreteVariable, DeclarationVariable, GVariable, Variable}; use std::marker::PhantomData; -use std::path::{Path, PathBuf}; +use std::ops::Deref; pub use crate::typed::integer::IntExpression; pub use crate::typed::uint::{bitwidth, UExpression, UExpressionInner, UMetadata}; -use crate::common::{FlatEmbed, FormatString, SourceMetadata}; +use crate::common::{operators::*, FlatEmbed, FormatString, SourceMetadata}; use std::collections::BTreeMap; use std::convert::{TryFrom, TryInto}; @@ -44,20 +51,17 @@ use std::fmt; pub use crate::typed::types::{ArrayType, FunctionKey, MemberId}; +use derivative::Derivative; +use num_bigint::BigUint; use zokrates_field::Field; pub use self::folder::Folder; use crate::typed::abi::{Abi, AbiInput}; -use std::ops::{Add, Div, Mul, Sub}; pub use self::identifier::Identifier; -/// An identifier for a `TypedModule`. Typically a path or uri. -pub type OwnedTypedModuleId = PathBuf; -pub type TypedModuleId = Path; - /// A collection of `TypedModule`s -pub type TypedModules<'ast, T> = BTreeMap>; +pub type TypedModules<'ast, T> = BTreeMap>; /// A collection of `TypedFunctionSymbol`s /// # Remarks @@ -80,12 +84,16 @@ pub type TypedConstantSymbols<'ast, T> = Vec<( )>; /// A typed program as a collection of modules, one of them being the main -#[derive(PartialEq, Eq, Debug, Clone)] +#[derive(PartialEq, Eq, Debug, Clone, Default)] pub struct TypedProgram<'ast, T> { + pub module_map: ModuleMap, pub modules: TypedModules<'ast, T>, - pub main: OwnedTypedModuleId, + pub main: OwnedModuleId, } +pub type IdentifierOrExpression<'ast, T, E> = + expressions::IdentifierOrExpression, E, >::Inner>; + impl<'ast, T: Field> TypedProgram<'ast, T> { pub fn abi(&self) -> Abi { let main = &self.modules[&self.main] @@ -107,7 +115,7 @@ impl<'ast, T: Field> TypedProgram<'ast, T> { crate::typed::types::try_from_g_type::< DeclarationConstant<'ast, T>, UExpression<'ast, T>, - >(p.id._type.clone()) + >(p.id.ty.clone()) .unwrap(), ) .map(|ty| AbiInput { @@ -353,19 +361,8 @@ impl<'ast, T: fmt::Display> fmt::Display for TypedFunction<'ast, T> { writeln!(f)?; - let mut tab = 0; - for s in &self.statements { - if let TypedStatement::PopCallLog = s { - tab -= 1; - }; - - s.fmt_indented(f, 1 + tab)?; - writeln!(f)?; - - if let TypedStatement::PushCallLog(..) = s { - tab += 1; - }; + writeln!(f, "{}", s)?; } writeln!(f, "}}")?; @@ -408,6 +405,20 @@ pub enum TypedAssignee<'ast, T> { Element(Box>, u32), } +impl<'ast, T> TypedAssignee<'ast, T> { + pub fn select(self, index: UExpression<'ast, T>) -> Self { + Self::Select(Box::new(self), Box::new(index)) + } + + pub fn member(self, member: MemberId) -> Self { + Self::Member(Box::new(self), member) + } + + pub fn element(self, index: u32) -> Self { + Self::Element(Box::new(self), index) + } +} + #[derive(Clone, PartialEq, Hash, Eq, Debug, PartialOrd, Ord)] pub struct TypedSpread<'ast, T> { pub array: ArrayExpression<'ast, T>, @@ -510,7 +521,7 @@ impl<'ast, T: Clone> TypedExpressionOrSpread<'ast, T> { impl<'ast, T: fmt::Display> fmt::Display for TypedExpressionOrSpread<'ast, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - TypedExpressionOrSpread::Expression(e) => write!(f, "{}", e), + TypedExpressionOrSpread::Expression(ref e) => write!(f, "{}", e), TypedExpressionOrSpread::Spread(s) => write!(f, "{}", s), } } @@ -653,137 +664,242 @@ impl<'ast, T: fmt::Display> fmt::Display for DefinitionRhs<'ast, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { DefinitionRhs::EmbedCall(c) => write!(f, "{}", c), - DefinitionRhs::Expression(e) => write!(f, "{}", e), + DefinitionRhs::Expression(ref e) => write!(f, "{}", e), } } } +pub type DefinitionStatement<'ast, T> = + common::statements::DefinitionStatement, DefinitionRhs<'ast, T>>; +pub type AssertionStatement<'ast, T> = + common::statements::AssertionStatement, RuntimeError>; +pub type ReturnStatement<'ast, T> = common::statements::ReturnStatement>; +pub type LogStatement<'ast, T> = common::statements::LogStatement>; + +#[derive(Derivative)] +#[derivative(PartialOrd, PartialEq, Eq, Hash, Ord)] +#[derive(Clone, Debug)] +pub struct ForStatement<'ast, T> { + #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Hash = "ignore")] + pub span: Option, + pub var: Variable<'ast, T>, + pub from: UExpression<'ast, T>, + pub to: UExpression<'ast, T>, + pub statements: Vec>, +} + +impl<'ast, T> ForStatement<'ast, T> { + fn new( + var: Variable<'ast, T>, + from: UExpression<'ast, T>, + to: UExpression<'ast, T>, + statements: Vec>, + ) -> Self { + Self { + span: None, + var, + from, + to, + statements, + } + } +} + +impl<'ast, T> WithSpan for ForStatement<'ast, T> { + fn span(self, span: Option) -> Self { + Self { span, ..self } + } + + fn get_span(&self) -> Option { + self.span + } +} + +#[derive(Derivative)] +#[derivative(PartialOrd, PartialEq, Eq, Hash, Ord)] +#[derive(Clone, Debug)] +pub struct AssemblyBlockStatement<'ast, T> { + #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Hash = "ignore")] + pub span: Option, + pub inner: Vec>, +} + +impl<'ast, T> AssemblyBlockStatement<'ast, T> { + pub fn new(inner: Vec>) -> Self { + Self { span: None, inner } + } +} + +pub type AssemblyConstraint<'ast, T> = + crate::common::statements::AssemblyConstraint>; +pub type AssemblyAssignment<'ast, T> = + crate::common::statements::AssemblyAssignment, TypedExpression<'ast, T>>; + #[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)] pub enum TypedAssemblyStatement<'ast, T> { - Assignment(TypedAssignee<'ast, T>, TypedExpression<'ast, T>), - Constraint( - FieldElementExpression<'ast, T>, - FieldElementExpression<'ast, T>, - SourceMetadata, - ), + Assignment(AssemblyAssignment<'ast, T>), + Constraint(AssemblyConstraint<'ast, T>), +} + +impl<'ast, T> WithSpan for TypedAssemblyStatement<'ast, T> { + fn span(self, span: Option) -> Self { + match self { + TypedAssemblyStatement::Assignment(s) => { + TypedAssemblyStatement::Assignment(s.span(span)) + } + TypedAssemblyStatement::Constraint(s) => { + TypedAssemblyStatement::Constraint(s.span(span)) + } + } + } + + fn get_span(&self) -> Option { + match self { + TypedAssemblyStatement::Assignment(s) => s.get_span(), + TypedAssemblyStatement::Constraint(s) => s.get_span(), + } + } +} + +impl<'ast, T> TypedAssemblyStatement<'ast, T> { + pub fn assignment( + assignee: TypedAssignee<'ast, T>, + expression: TypedExpression<'ast, T>, + ) -> Self { + TypedAssemblyStatement::Assignment(AssemblyAssignment::new(assignee, expression)) + } + + pub fn constraint( + left: FieldElementExpression<'ast, T>, + right: FieldElementExpression<'ast, T>, + metadata: SourceMetadata, + ) -> Self { + TypedAssemblyStatement::Constraint(AssemblyConstraint::new(left, right, metadata)) + } } impl<'ast, T: fmt::Display> fmt::Display for TypedAssemblyStatement<'ast, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - TypedAssemblyStatement::Assignment(ref lhs, ref rhs) => { - write!(f, "{} <-- {};", lhs, rhs) + TypedAssemblyStatement::Assignment(ref s) => { + write!(f, "{} <-- {};", s.assignee, s.expression) } - TypedAssemblyStatement::Constraint(ref lhs, ref rhs, _) => { - write!(f, "{} === {};", lhs, rhs) + TypedAssemblyStatement::Constraint(ref s) => { + write!(f, "{}", s) } } } } +impl<'ast, T> WithSpan for AssemblyBlockStatement<'ast, T> { + fn span(self, span: Option) -> Self { + Self { span, ..self } + } + + fn get_span(&self) -> Option { + self.span + } +} + /// A statement in a `TypedFunction` #[allow(clippy::large_enum_variant)] #[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)] pub enum TypedStatement<'ast, T> { - Return(TypedExpression<'ast, T>), - Definition(TypedAssignee<'ast, T>, DefinitionRhs<'ast, T>), - Assertion(BooleanExpression<'ast, T>, RuntimeError), - For( - Variable<'ast, T>, - UExpression<'ast, T>, - UExpression<'ast, T>, - Vec>, - ), - Log(FormatString, Vec>), - // Aux - PushCallLog( - DeclarationFunctionKey<'ast, T>, - ConcreteGenericsAssignment<'ast>, - ), - PopCallLog, - Assembly(Vec>), + Return(ReturnStatement<'ast, T>), + Definition(DefinitionStatement<'ast, T>), + Assertion(AssertionStatement<'ast, T>), + For(ForStatement<'ast, T>), + Log(LogStatement<'ast, T>), + Assembly(AssemblyBlockStatement<'ast, T>), +} + +impl<'ast, T> WithSpan for TypedStatement<'ast, T> { + fn span(self, span: Option) -> Self { + use TypedStatement::*; + + match self { + Return(e) => Return(e.span(span)), + Definition(e) => Definition(e.span(span)), + Assertion(e) => Assertion(e.span(span)), + For(e) => For(e.span(span)), + Log(e) => Log(e.span(span)), + Assembly(e) => Assembly(e.span(span)), + } + } + + fn get_span(&self) -> Option { + use TypedStatement::*; + + match self { + Return(e) => e.get_span(), + Definition(e) => e.get_span(), + Assertion(e) => e.get_span(), + For(e) => e.get_span(), + Log(e) => e.get_span(), + Assembly(e) => e.get_span(), + } + } } impl<'ast, T> TypedStatement<'ast, T> { pub fn definition(a: TypedAssignee<'ast, T>, e: TypedExpression<'ast, T>) -> Self { - Self::Definition(a, e.into()) + Self::Definition(DefinitionStatement::new(a, e.into())) + } + + pub fn for_( + var: Variable<'ast, T>, + from: UExpression<'ast, T>, + to: UExpression<'ast, T>, + statements: Vec>, + ) -> Self { + Self::For(ForStatement::new(var, from, to, statements)) + } + + pub fn assertion(e: BooleanExpression<'ast, T>, error: RuntimeError) -> Self { + Self::Assertion(AssertionStatement::new(e, error)) + } + + pub fn ret(e: TypedExpression<'ast, T>) -> Self { + Self::Return(ReturnStatement::new(e)) } pub fn embed_call_definition(a: TypedAssignee<'ast, T>, c: EmbedCall<'ast, T>) -> Self { - Self::Definition(a, c.into()) + Self::Definition(DefinitionStatement::new(a, c.into())) } -} -impl<'ast, T: fmt::Display> TypedStatement<'ast, T> { - fn fmt_indented(&self, f: &mut fmt::Formatter, depth: usize) -> fmt::Result { - match self { - TypedStatement::For(variable, from, to, statements) => { - write!(f, "{}", "\t".repeat(depth))?; - writeln!(f, "for {} in {}..{} {{", variable, from, to)?; - for s in statements { - s.fmt_indented(f, depth + 1)?; - writeln!(f)?; - } - write!(f, "{}}}", "\t".repeat(depth)) - } - TypedStatement::Assembly(statements) => { - write!(f, "{}", "\t".repeat(depth))?; - writeln!(f, "asm {{")?; - for s in statements { - writeln!(f, "{}{}", "\t".repeat(depth + 1), s)?; - } - write!(f, "{}}}", "\t".repeat(depth)) - } - s => write!(f, "{}{}", "\t".repeat(depth), s), - } + pub fn log(format_string: FormatString, expressions: Vec>) -> Self { + Self::Log(LogStatement::new(format_string, expressions)) } } impl<'ast, T: fmt::Display> fmt::Display for TypedStatement<'ast, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - TypedStatement::Return(ref e) => { - write!(f, "return {};", e) + TypedStatement::Return(ref s) => { + write!(f, "{}", s) } - TypedStatement::Definition(ref lhs, ref rhs) => write!(f, "{} = {};", lhs, rhs), - TypedStatement::Assertion(ref e, ref error) => { - write!(f, "assert({}", e)?; - match error { - RuntimeError::SourceAssertion(metadata) => match &metadata.message { + TypedStatement::Definition(ref s) => write!(f, "{}", s), + TypedStatement::Assertion(ref s) => { + write!(f, "assert({}", s.expression)?; + match s.error { + RuntimeError::SourceAssertion(ref metadata) => match &metadata.message { Some(m) => write!(f, ", \"{}\");", m), None => write!(f, ");"), }, - error => write!(f, "); // {}", error), + ref error => write!(f, "); // {}", error), } } - TypedStatement::For(ref var, ref start, ref stop, ref list) => { - writeln!(f, "for {} in {}..{} {{", var, start, stop)?; - for l in list { + TypedStatement::For(ref s) => { + writeln!(f, "for {} in {}..{} {{", s.var, s.from, s.to)?; + for l in &s.statements { writeln!(f, "\t\t{}", l)?; } write!(f, "\t}}") } - TypedStatement::Log(ref l, ref expressions) => write!( - f, - "log({}, {})", - l, - expressions - .iter() - .map(|e| e.to_string()) - .collect::>() - .join(", ") - ), - TypedStatement::PushCallLog(ref key, ref generics) => write!( - f, - "// PUSH CALL TO {}/{}::<{}>", - key.module.display(), - key.id, - generics, - ), - TypedStatement::PopCallLog => write!(f, "// POP CALL",), - TypedStatement::Assembly(ref statements) => { + TypedStatement::Log(ref s) => write!(f, "{}", s), + TypedStatement::Assembly(ref s) => { writeln!(f, "asm {{")?; - for s in statements { + for s in &s.inner { writeln!(f, "\t\t{}", s)?; } write!(f, "\t}}") @@ -809,9 +925,9 @@ pub enum TypedExpression<'ast, T> { Int(IntExpression<'ast, T>), } -impl<'ast, T> TypedExpression<'ast, T> { +impl<'ast, T: Field> TypedExpression<'ast, T> { pub fn empty_tuple() -> TypedExpression<'ast, T> { - TypedExpression::Tuple(TupleExpressionInner::Value(vec![]).annotate(TupleType::new(vec![]))) + TypedExpression::Tuple(TupleExpression::value(vec![]).annotate(TupleType::new(vec![]))) } } @@ -955,65 +1071,112 @@ impl<'ast, T: Clone> Typed<'ast, T> for BooleanExpression<'ast, T> { } } -#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)] -pub struct EqExpression { - pub left: Box, - pub right: Box, +#[derive(Derivative)] +#[derivative(PartialOrd, PartialEq, Eq, Hash, Ord)] +#[derive(Clone, Debug)] +pub struct BlockExpression<'ast, T, E> { + #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Hash = "ignore")] + pub span: Option, + pub statements: Vec>, + pub value: Box, } -impl EqExpression { - pub fn new(left: E, right: E) -> Self { - EqExpression { - left: box left, - right: box right, +impl<'ast, T, E> BlockExpression<'ast, T, E> { + pub fn new(statements: Vec>, value: E) -> Self { + BlockExpression { + span: None, + statements, + value: Box::new(value), } } } -impl fmt::Display for EqExpression { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "({} == {})", self.left, self.right) +#[derive(Derivative)] +#[derivative(PartialOrd, PartialEq, Eq, Hash, Ord)] +#[derive(Clone, Debug)] +pub struct SliceExpression<'ast, T> { + #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Hash = "ignore")] + pub span: Option, + pub array: Box>, + pub from: Box>, + pub to: Box>, +} + +impl<'ast, T> SliceExpression<'ast, T> { + pub fn new( + array: ArrayExpression<'ast, T>, + from: UExpression<'ast, T>, + to: UExpression<'ast, T>, + ) -> Self { + SliceExpression { + span: None, + array: Box::new(array), + from: Box::new(from), + to: Box::new(to), + } } } -#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)] -pub struct BlockExpression<'ast, T, E> { - pub statements: Vec>, - pub value: Box, +impl<'ast, T> WithSpan for SliceExpression<'ast, T> { + fn span(self, span: Option) -> Self { + Self { span, ..self } + } + + fn get_span(&self) -> Option { + self.span + } } -impl<'ast, T, E> BlockExpression<'ast, T, E> { - pub fn new(statements: Vec>, value: E) -> Self { - BlockExpression { - statements, - value: box value, - } +impl<'ast, T: fmt::Display> fmt::Display for SliceExpression<'ast, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}[{}..{}]", self.array, self.from, self.to) } } -#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)] -pub struct IdentifierExpression<'ast, E> { - pub id: Identifier<'ast>, - ty: PhantomData, +#[derive(Derivative)] +#[derivative(PartialOrd, PartialEq, Eq, Hash, Ord)] +#[derive(Clone, Debug)] +pub struct RepeatExpression<'ast, T> { + #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Hash = "ignore")] + pub span: Option, + pub count: Box>, + pub e: Box>, } -impl<'ast, E> IdentifierExpression<'ast, E> { - pub fn new(id: Identifier<'ast>) -> Self { - IdentifierExpression { - id, - ty: PhantomData, +impl<'ast, T> RepeatExpression<'ast, T> { + pub fn new(e: TypedExpression<'ast, T>, count: UExpression<'ast, T>) -> Self { + RepeatExpression { + span: None, + e: Box::new(e), + count: Box::new(count), } } } -impl<'ast, E> fmt::Display for IdentifierExpression<'ast, E> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.id) +impl<'ast, T> WithSpan for RepeatExpression<'ast, T> { + fn span(self, span: Option) -> Self { + Self { span, ..self } + } + + fn get_span(&self) -> Option { + self.span } } -#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)] +impl<'ast, T: fmt::Display> fmt::Display for RepeatExpression<'ast, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{}; {}]", self.e, self.count) + } +} + +pub type IdentifierExpression<'ast, E> = expressions::IdentifierExpression, E>; + +#[derive(Derivative)] +#[derivative(PartialOrd, PartialEq, Eq, Hash, Ord)] +#[derive(Clone, Debug)] pub struct MemberExpression<'ast, T, E> { + #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Hash = "ignore")] + pub span: Option, pub struc: Box>, pub id: MemberId, ty: PhantomData, @@ -1022,7 +1185,8 @@ pub struct MemberExpression<'ast, T, E> { impl<'ast, T, E> MemberExpression<'ast, T, E> { pub fn new(struc: StructExpression<'ast, T>, id: MemberId) -> Self { MemberExpression { - struc: box struc, + span: None, + struc: Box::new(struc), id, ty: PhantomData, } @@ -1035,8 +1199,12 @@ impl<'ast, T: fmt::Display, E> fmt::Display for MemberExpression<'ast, T, E> { } } -#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)] +#[derive(Derivative)] +#[derivative(PartialOrd, PartialEq, Eq, Hash, Ord)] +#[derive(Clone, Debug)] pub struct SelectExpression<'ast, T, E> { + #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Hash = "ignore")] + pub span: Option, pub array: Box>, pub index: Box>, ty: PhantomData, @@ -1045,8 +1213,9 @@ pub struct SelectExpression<'ast, T, E> { impl<'ast, T, E> SelectExpression<'ast, T, E> { pub fn new(array: ArrayExpression<'ast, T>, index: UExpression<'ast, T>) -> Self { SelectExpression { - array: box array, - index: box index, + span: None, + array: Box::new(array), + index: Box::new(index), ty: PhantomData, } } @@ -1058,8 +1227,12 @@ impl<'ast, T: fmt::Display, E> fmt::Display for SelectExpression<'ast, T, E> { } } -#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)] +#[derive(Derivative)] +#[derivative(PartialOrd, PartialEq, Eq, Hash, Ord)] +#[derive(Clone, Debug)] pub struct ElementExpression<'ast, T, E> { + #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Hash = "ignore")] + pub span: Option, pub tuple: Box>, pub index: u32, ty: PhantomData, @@ -1068,7 +1241,8 @@ pub struct ElementExpression<'ast, T, E> { impl<'ast, T, E> ElementExpression<'ast, T, E> { pub fn new(tuple: TupleExpression<'ast, T>, index: u32) -> Self { ElementExpression { - tuple: box tuple, + span: None, + tuple: Box::new(tuple), index, ty: PhantomData, } @@ -1087,8 +1261,12 @@ pub enum ConditionalKind { Ternary, } -#[derive(Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord)] +#[derive(Derivative)] +#[derivative(PartialOrd, PartialEq, Eq, Hash, Ord)] +#[derive(Clone, Debug)] pub struct ConditionalExpression<'ast, T, E> { + #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Hash = "ignore")] + pub span: Option, pub condition: Box>, pub consequence: Box, pub alternative: Box, @@ -1103,9 +1281,10 @@ impl<'ast, T, E> ConditionalExpression<'ast, T, E> { kind: ConditionalKind, ) -> Self { ConditionalExpression { - condition: box condition, - consequence: box consequence, - alternative: box alternative, + span: None, + condition: Box::new(condition), + consequence: Box::new(consequence), + alternative: Box::new(alternative), kind, } } @@ -1130,8 +1309,12 @@ impl<'ast, T: fmt::Display, E: fmt::Display> fmt::Display for ConditionalExpress } } -#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)] +#[derive(Derivative)] +#[derivative(PartialOrd, PartialEq, Eq, Hash, Ord)] +#[derive(Clone, Debug)] pub struct FunctionCallExpression<'ast, T, E> { + #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Hash = "ignore")] + pub span: Option, pub function_key: DeclarationFunctionKey<'ast, T>, pub generics: Vec>>, pub arguments: Vec>, @@ -1145,6 +1328,7 @@ impl<'ast, T, E> FunctionCallExpression<'ast, T, E> { arguments: Vec>, ) -> Self { FunctionCallExpression { + span: None, function_key, generics, arguments, @@ -1186,51 +1370,21 @@ impl<'ast, T: fmt::Display, E> fmt::Display for FunctionCallExpression<'ast, T, #[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)] pub enum FieldElementExpression<'ast, T> { Block(BlockExpression<'ast, T, Self>), - Number(T), + Value(FieldValueExpression), Identifier(IdentifierExpression<'ast, Self>), - Add( - Box>, - Box>, - ), - Sub( - Box>, - Box>, - ), - Mult( - Box>, - Box>, - ), - Div( - Box>, - Box>, - ), - Pow( - Box>, - Box>, - ), - And( - Box>, - Box>, - ), - Or( - Box>, - Box>, - ), - Xor( - Box>, - Box>, - ), - LeftShift( - Box>, - Box>, - ), - RightShift( - Box>, - Box>, - ), + Add(BinaryExpression), + Sub(BinaryExpression), + Mult(BinaryExpression), + Div(BinaryExpression), + Pow(BinaryExpression, Self>), + And(BinaryExpression), + Or(BinaryExpression), + Xor(BinaryExpression), + LeftShift(BinaryExpression, Self>), + RightShift(BinaryExpression, Self>), Conditional(ConditionalExpression<'ast, T, Self>), - Neg(Box>), - Pos(Box>), + Neg(UnaryExpression), + Pos(UnaryExpression), FunctionCall(FunctionCallExpression<'ast, T, Self>), Member(MemberExpression<'ast, T, Self>), Select(SelectExpression<'ast, T, Self>), @@ -1242,14 +1396,14 @@ impl<'ast, T: Field> From> for TupleExpression<'ast, T> { match assignee { TypedAssignee::Identifier(v) => { let inner = TupleExpression::identifier(v.id); - match v._type { + match v.ty { GType::Tuple(tuple_ty) => inner.annotate(tuple_ty), _ => unreachable!(), } } - TypedAssignee::Select(box a, box index) => TupleExpression::select(a.into(), index), - TypedAssignee::Member(box a, id) => TupleExpression::member(a.into(), id), - TypedAssignee::Element(box a, index) => TupleExpression::element(a.into(), index), + TypedAssignee::Select(a, index) => TupleExpression::select((*a).into(), *index), + TypedAssignee::Member(a, id) => TupleExpression::member((*a).into(), id), + TypedAssignee::Element(a, index) => TupleExpression::element((*a).into(), index), } } } @@ -1259,14 +1413,14 @@ impl<'ast, T: Field> From> for StructExpression<'ast, T> match assignee { TypedAssignee::Identifier(v) => { let inner = StructExpression::identifier(v.id); - match v._type { + match v.ty { GType::Struct(struct_ty) => inner.annotate(struct_ty), _ => unreachable!(), } } - TypedAssignee::Select(box a, box index) => StructExpression::select(a.into(), index), - TypedAssignee::Member(box a, id) => StructExpression::member(a.into(), id), - TypedAssignee::Element(box a, index) => StructExpression::element(a.into(), index), + TypedAssignee::Select(a, index) => StructExpression::select((*a).into(), *index), + TypedAssignee::Member(a, id) => StructExpression::member((*a).into(), id), + TypedAssignee::Element(a, index) => StructExpression::element((*a).into(), index), } } } @@ -1276,14 +1430,14 @@ impl<'ast, T: Field> From> for ArrayExpression<'ast, T> { match assignee { TypedAssignee::Identifier(v) => { let inner = ArrayExpression::identifier(v.id); - match v._type { - GType::Array(array_ty) => inner.annotate(*array_ty.ty, *array_ty.size), + match v.ty { + GType::Array(array_ty) => inner.annotate(array_ty), _ => unreachable!(), } } - TypedAssignee::Select(box a, box index) => ArrayExpression::select(a.into(), index), - TypedAssignee::Member(box a, id) => ArrayExpression::member(a.into(), id), - TypedAssignee::Element(box a, index) => ArrayExpression::element(a.into(), index), + TypedAssignee::Select(a, index) => ArrayExpression::select((*a).into(), *index), + TypedAssignee::Member(a, id) => ArrayExpression::member((*a).into(), id), + TypedAssignee::Element(a, index) => ArrayExpression::element((*a).into(), index), } } } @@ -1292,58 +1446,98 @@ impl<'ast, T: Field> From> for FieldElementExpression<'as fn from(assignee: TypedAssignee<'ast, T>) -> Self { match assignee { TypedAssignee::Identifier(v) => FieldElementExpression::identifier(v.id), - TypedAssignee::Element(box a, index) => { - FieldElementExpression::element(a.into(), index) - } - TypedAssignee::Member(box a, id) => FieldElementExpression::member(a.into(), id), - TypedAssignee::Select(box a, box index) => { - FieldElementExpression::select(a.into(), index) - } + TypedAssignee::Element(a, index) => FieldElementExpression::element((*a).into(), index), + TypedAssignee::Member(a, id) => FieldElementExpression::member((*a).into(), id), + TypedAssignee::Select(a, index) => FieldElementExpression::select((*a).into(), *index), } } } -impl<'ast, T> Add for FieldElementExpression<'ast, T> { +impl<'ast, T> std::ops::Add for FieldElementExpression<'ast, T> { type Output = Self; fn add(self, other: Self) -> Self { - FieldElementExpression::Add(box self, box other) + FieldElementExpression::Add(BinaryExpression::new(self, other)) } } -impl<'ast, T> Sub for FieldElementExpression<'ast, T> { +impl<'ast, T: Field> std::ops::Sub for FieldElementExpression<'ast, T> { type Output = Self; fn sub(self, other: Self) -> Self { - FieldElementExpression::Sub(box self, box other) + FieldElementExpression::Sub(BinaryExpression::new(self, other)) } } -impl<'ast, T> Mul for FieldElementExpression<'ast, T> { +impl<'ast, T: Field> std::ops::Mul for FieldElementExpression<'ast, T> { type Output = Self; fn mul(self, other: Self) -> Self { - FieldElementExpression::Mult(box self, box other) + FieldElementExpression::Mult(BinaryExpression::new(self, other)) } } -impl<'ast, T> Div for FieldElementExpression<'ast, T> { +impl<'ast, T: Field> std::ops::Div for FieldElementExpression<'ast, T> { type Output = Self; fn div(self, other: Self) -> Self { - FieldElementExpression::Div(box self, box other) + FieldElementExpression::Div(BinaryExpression::new(self, other)) + } +} + +impl<'ast, T: Field> std::ops::BitAnd for FieldElementExpression<'ast, T> { + type Output = Self; + + fn bitand(self, other: Self) -> Self { + FieldElementExpression::And(BinaryExpression::new(self, other)) + } +} + +impl<'ast, T: Field> std::ops::BitOr for FieldElementExpression<'ast, T> { + type Output = Self; + + fn bitor(self, other: Self) -> Self { + FieldElementExpression::Or(BinaryExpression::new(self, other)) + } +} + +impl<'ast, T: Field> std::ops::BitXor for FieldElementExpression<'ast, T> { + type Output = Self; + + fn bitxor(self, other: Self) -> Self { + FieldElementExpression::Xor(BinaryExpression::new(self, other)) } } -impl<'ast, T> FieldElementExpression<'ast, T> { +impl<'ast, T> std::ops::Neg for FieldElementExpression<'ast, T> { + type Output = Self; + + fn neg(self) -> Self { + FieldElementExpression::Neg(UnaryExpression::new(self)) + } +} + +impl<'ast, T: Field> FieldElementExpression<'ast, T> { pub fn pow(self, other: UExpression<'ast, T>) -> Self { - FieldElementExpression::Pow(box self, box other) + FieldElementExpression::Pow(BinaryExpression::new(self, other)) + } + + pub fn pos(self) -> Self { + FieldElementExpression::Pos(UnaryExpression::new(self)) + } + + pub fn left_shift(self, by: UExpression<'ast, T>) -> Self { + FieldElementExpression::LeftShift(BinaryExpression::new(self, by)) + } + + pub fn right_shift(self, by: UExpression<'ast, T>) -> Self { + FieldElementExpression::RightShift(BinaryExpression::new(self, by)) } } -impl<'ast, T> From for FieldElementExpression<'ast, T> { +impl<'ast, T: Clone> From for FieldElementExpression<'ast, T> { fn from(n: T) -> Self { - FieldElementExpression::Number(n) + FieldElementExpression::Value(ValueExpression::new(n)) } } @@ -1352,42 +1546,41 @@ impl<'ast, T> From for FieldElementExpression<'ast, T> { pub enum BooleanExpression<'ast, T> { Block(BlockExpression<'ast, T, Self>), Identifier(IdentifierExpression<'ast, Self>), - Value(bool), + Value(BooleanValueExpression), FieldLt( - Box>, - Box>, + BinaryExpression< + OpLt, + FieldElementExpression<'ast, T>, + FieldElementExpression<'ast, T>, + Self, + >, ), FieldLe( - Box>, - Box>, - ), - FieldGe( - Box>, - Box>, - ), - FieldGt( - Box>, - Box>, + BinaryExpression< + OpLe, + FieldElementExpression<'ast, T>, + FieldElementExpression<'ast, T>, + Self, + >, ), - UintLt(Box>, Box>), - UintLe(Box>, Box>), - UintGe(Box>, Box>), - UintGt(Box>, Box>), - FieldEq(EqExpression>), - BoolEq(EqExpression>), - ArrayEq(EqExpression>), - StructEq(EqExpression>), - TupleEq(EqExpression>), - UintEq(EqExpression>), - Or( - Box>, - Box>, + UintLt(BinaryExpression, UExpression<'ast, T>, Self>), + UintLe(BinaryExpression, UExpression<'ast, T>, Self>), + FieldEq( + BinaryExpression< + OpEq, + FieldElementExpression<'ast, T>, + FieldElementExpression<'ast, T>, + Self, + >, ), - And( - Box>, - Box>, - ), - Not(Box>), + BoolEq(BinaryExpression, BooleanExpression<'ast, T>, Self>), + ArrayEq(BinaryExpression, ArrayExpression<'ast, T>, Self>), + StructEq(BinaryExpression, StructExpression<'ast, T>, Self>), + TupleEq(BinaryExpression, TupleExpression<'ast, T>, Self>), + UintEq(BinaryExpression, UExpression<'ast, T>, Self>), + Or(BinaryExpression, BooleanExpression<'ast, T>, Self>), + And(BinaryExpression, BooleanExpression<'ast, T>, Self>), + Not(UnaryExpression), Conditional(ConditionalExpression<'ast, T, Self>), Member(MemberExpression<'ast, T, Self>), FunctionCall(FunctionCallExpression<'ast, T, Self>), @@ -1397,7 +1590,104 @@ pub enum BooleanExpression<'ast, T> { impl<'ast, T> From for BooleanExpression<'ast, T> { fn from(b: bool) -> Self { - BooleanExpression::Value(b) + BooleanExpression::Value(ValueExpression::new(b)) + } +} + +impl<'ast, T> std::ops::Not for BooleanExpression<'ast, T> { + type Output = Self; + + fn not(self) -> Self { + Self::Not(UnaryExpression::new(self)) + } +} + +impl<'ast, T> std::ops::BitAnd for BooleanExpression<'ast, T> { + type Output = Self; + + fn bitand(self, other: Self) -> Self { + Self::And(BinaryExpression::new(self, other)) + } +} + +impl<'ast, T> std::ops::BitOr for BooleanExpression<'ast, T> { + type Output = Self; + + fn bitor(self, other: Self) -> Self { + Self::Or(BinaryExpression::new(self, other)) + } +} + +impl<'ast, T> BooleanExpression<'ast, T> { + pub fn uint_eq(left: UExpression<'ast, T>, right: UExpression<'ast, T>) -> Self { + Self::UintEq(BinaryExpression::new(left, right)) + } + + pub fn bool_eq(left: BooleanExpression<'ast, T>, right: BooleanExpression<'ast, T>) -> Self { + Self::BoolEq(BinaryExpression::new(left, right)) + } + + pub fn field_eq( + left: FieldElementExpression<'ast, T>, + right: FieldElementExpression<'ast, T>, + ) -> Self { + Self::FieldEq(BinaryExpression::new(left, right)) + } + + pub fn struct_eq(left: StructExpression<'ast, T>, right: StructExpression<'ast, T>) -> Self { + Self::StructEq(BinaryExpression::new(left, right)) + } + + pub fn array_eq(left: ArrayExpression<'ast, T>, right: ArrayExpression<'ast, T>) -> Self { + Self::ArrayEq(BinaryExpression::new(left, right)) + } + + pub fn tuple_eq(left: TupleExpression<'ast, T>, right: TupleExpression<'ast, T>) -> Self { + Self::TupleEq(BinaryExpression::new(left, right)) + } + + pub fn uint_lt(left: UExpression<'ast, T>, right: UExpression<'ast, T>) -> Self { + Self::UintLt(BinaryExpression::new(left, right)) + } + + pub fn uint_le(left: UExpression<'ast, T>, right: UExpression<'ast, T>) -> Self { + Self::UintLe(BinaryExpression::new(left, right)) + } + + pub fn uint_gt(left: UExpression<'ast, T>, right: UExpression<'ast, T>) -> Self { + Self::UintLt(BinaryExpression::new(right, left)) + } + + pub fn uint_ge(left: UExpression<'ast, T>, right: UExpression<'ast, T>) -> Self { + Self::UintLe(BinaryExpression::new(right, left)) + } + + pub fn field_lt( + left: FieldElementExpression<'ast, T>, + right: FieldElementExpression<'ast, T>, + ) -> Self { + Self::FieldLt(BinaryExpression::new(left, right)) + } + + pub fn field_le( + left: FieldElementExpression<'ast, T>, + right: FieldElementExpression<'ast, T>, + ) -> Self { + Self::FieldLe(BinaryExpression::new(left, right)) + } + + pub fn field_gt( + left: FieldElementExpression<'ast, T>, + right: FieldElementExpression<'ast, T>, + ) -> Self { + Self::FieldLt(BinaryExpression::new(right, left)) + } + + pub fn field_ge( + left: FieldElementExpression<'ast, T>, + right: FieldElementExpression<'ast, T>, + ) -> Self { + Self::FieldLe(BinaryExpression::new(right, left)) } } @@ -1412,52 +1702,60 @@ pub struct ArrayExpression<'ast, T> { pub inner: ArrayExpressionInner<'ast, T>, } -#[derive(Debug, PartialEq, Eq, Hash, Clone, PartialOrd, Ord)] -pub struct ArrayValue<'ast, T>(pub Vec>); +type ArrayValueExpression<'ast, T> = ValueExpression>>; -impl<'ast, T> From>> for ArrayValue<'ast, T> { - fn from(array: Vec>) -> Self { - Self(array) - } -} - -impl<'ast, T> IntoIterator for ArrayValue<'ast, T> { +impl<'ast, T> IntoIterator for ArrayValueExpression<'ast, T> { type Item = TypedExpressionOrSpread<'ast, T>; type IntoIter = std::vec::IntoIter; fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() + self.value.into_iter() } } -impl<'ast, T: Field> ArrayValue<'ast, T> { +impl<'ast, T> Deref for ArrayValueExpression<'ast, T> { + type Target = [TypedExpressionOrSpread<'ast, T>]; + + fn deref(&self) -> &Self::Target { + &self.value[..] + } +} + +impl<'ast, T> std::iter::FromIterator> + for ArrayValueExpression<'ast, T> +{ + fn from_iter>>(iter: I) -> Self { + Self::new(iter.into_iter().collect()) + } +} + +impl<'ast, T: Field> ArrayValueExpression<'ast, T> { fn expression_at_aux< + 'a, U: Select<'ast, T> + From> + Into>, >( v: TypedExpressionOrSpread<'ast, T>, - ) -> Vec> { + ) -> Vec> { match v { - TypedExpressionOrSpread::Expression(e) => vec![Some(e.into())], + TypedExpressionOrSpread::Expression(e) => vec![e], TypedExpressionOrSpread::Spread(s) => match s.array.size().into_inner() { UExpressionInner::Value(size) => { let array_ty = s.array.ty().clone(); match s.array.into_inner() { - ArrayExpressionInner::Value(v) => { - v.into_iter().flat_map(Self::expression_at_aux).collect() - } - a => (0..size) + ArrayExpressionInner::Value(v) => v + .value + .into_iter() + .flat_map(Self::expression_at_aux::) + .collect(), + a => (0..size.value) .map(|i| { - Some(U::select( - a.clone() - .annotate(*array_ty.ty.clone(), *array_ty.size.clone()), - i as u32, - )) + U::select(a.clone().annotate(array_ty.clone()), i as u32).into() }) .collect(), } } - _ => vec![None], + _ => unreachable!(), }, } } @@ -1465,27 +1763,16 @@ impl<'ast, T: Field> ArrayValue<'ast, T> { pub fn expression_at< U: Select<'ast, T> + From> + Into>, >( - &self, + self, index: usize, - ) -> Option { - self.0 - .iter() - .flat_map(|v| Self::expression_at_aux(v.clone())) - .take_while(|e| e.is_some()) - .map(|e| e.unwrap()) + ) -> U { + self.into_iter() + .flat_map(|v| Self::expression_at_aux::(v)) .nth(index) - } -} - -impl<'ast, T> ArrayValue<'ast, T> { - fn iter(&self) -> std::slice::Iter> { - self.0.iter() - } -} - -impl<'ast, T> std::iter::FromIterator> for ArrayValue<'ast, T> { - fn from_iter>>(iter: I) -> Self { - Self(iter.into_iter().collect()) + .unwrap() + .clone() + .try_into() + .unwrap() } } @@ -1493,28 +1780,20 @@ impl<'ast, T> std::iter::FromIterator> for Arra pub enum ArrayExpressionInner<'ast, T> { Block(BlockExpression<'ast, T, ArrayExpression<'ast, T>>), Identifier(IdentifierExpression<'ast, ArrayExpression<'ast, T>>), - Value(ArrayValue<'ast, T>), + Value(ArrayValueExpression<'ast, T>), FunctionCall(FunctionCallExpression<'ast, T, ArrayExpression<'ast, T>>), Conditional(ConditionalExpression<'ast, T, ArrayExpression<'ast, T>>), Member(MemberExpression<'ast, T, ArrayExpression<'ast, T>>), Select(SelectExpression<'ast, T, ArrayExpression<'ast, T>>), Element(ElementExpression<'ast, T, ArrayExpression<'ast, T>>), - Slice( - Box>, - Box>, - Box>, - ), - Repeat(Box>, Box>), + Slice(SliceExpression<'ast, T>), + Repeat(RepeatExpression<'ast, T>), } impl<'ast, T> ArrayExpressionInner<'ast, T> { - pub fn annotate>>( - self, - ty: Type<'ast, T>, - size: S, - ) -> ArrayExpression<'ast, T> { + pub fn annotate(self, ty: ArrayType<'ast, T>) -> ArrayExpression<'ast, T> { ArrayExpression { - ty: box (ty, size.into()).into(), + ty: Box::new(ty), inner: self, } } @@ -1528,6 +1807,24 @@ impl<'ast, T: Clone> ArrayExpression<'ast, T> { pub fn size(&self) -> UExpression<'ast, T> { *self.ty.size.clone() } + + pub fn slice( + array: ArrayExpression<'ast, T>, + from: UExpression<'ast, T>, + to: UExpression<'ast, T>, + ) -> Self { + let inner = array.inner_type().clone(); + let size = to.clone() - from.clone(); + let array_ty = ArrayType::new(inner, size); + ArrayExpressionInner::Slice(SliceExpression::new(array, from, to)).annotate(array_ty) + } + + pub fn repeat(e: TypedExpression<'ast, T>, count: UExpression<'ast, T>) -> Self { + let inner = e.get_type().clone(); + let size = count.clone(); + let array_ty = ArrayType::new(inner, size); + ArrayExpressionInner::Repeat(RepeatExpression::new(e, count)).annotate(array_ty) + } } #[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)] @@ -1536,6 +1833,31 @@ pub struct StructExpression<'ast, T> { inner: StructExpressionInner<'ast, T>, } +type StructValueExpression<'ast, T> = ValueExpression>>; + +impl<'ast, T> IntoIterator for StructValueExpression<'ast, T> { + type Item = TypedExpression<'ast, T>; + type IntoIter = std::vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.value.into_iter() + } +} + +impl<'ast, T> Deref for StructValueExpression<'ast, T> { + type Target = [TypedExpression<'ast, T>]; + + fn deref(&self) -> &Self::Target { + &self.value[..] + } +} + +impl<'ast, T> std::iter::FromIterator> for StructValueExpression<'ast, T> { + fn from_iter>>(iter: I) -> Self { + Self::new(iter.into_iter().collect()) + } +} + impl<'ast, T> StructExpression<'ast, T> { pub fn ty(&self) -> &StructType<'ast, T> { &self.ty @@ -1558,7 +1880,7 @@ impl<'ast, T> StructExpression<'ast, T> { pub enum StructExpressionInner<'ast, T> { Block(BlockExpression<'ast, T, StructExpression<'ast, T>>), Identifier(IdentifierExpression<'ast, StructExpression<'ast, T>>), - Value(Vec>), + Value(TupleValueExpression<'ast, T>), FunctionCall(FunctionCallExpression<'ast, T, StructExpression<'ast, T>>), Conditional(ConditionalExpression<'ast, T, StructExpression<'ast, T>>), Member(MemberExpression<'ast, T, StructExpression<'ast, T>>), @@ -1596,11 +1918,13 @@ impl<'ast, T> TupleExpression<'ast, T> { } } +type TupleValueExpression<'ast, T> = ValueExpression>>; + #[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)] pub enum TupleExpressionInner<'ast, T> { Block(BlockExpression<'ast, T, TupleExpression<'ast, T>>), Identifier(IdentifierExpression<'ast, TupleExpression<'ast, T>>), - Value(Vec>), + Value(TupleValueExpression<'ast, T>), FunctionCall(FunctionCallExpression<'ast, T, TupleExpression<'ast, T>>), Conditional(ConditionalExpression<'ast, T, TupleExpression<'ast, T>>), Member(MemberExpression<'ast, T, TupleExpression<'ast, T>>), @@ -1765,7 +2089,7 @@ impl<'ast, T: fmt::Display, E: fmt::Display> fmt::Display for BlockExpression<'a .map(|s| s.to_string()) .chain(std::iter::once(self.value.to_string())) .collect::>() - .join("\n") + .join("\n"), ) } } @@ -1774,21 +2098,21 @@ impl<'ast, T: fmt::Display> fmt::Display for FieldElementExpression<'ast, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { FieldElementExpression::Block(ref block) => write!(f, "{}", block), - FieldElementExpression::Number(ref i) => write!(f, "{}f", i), + FieldElementExpression::Value(ref i) => write!(f, "{}f", i), FieldElementExpression::Identifier(ref var) => write!(f, "{}", var), - FieldElementExpression::Add(ref lhs, ref rhs) => write!(f, "({} + {})", lhs, rhs), - FieldElementExpression::Sub(ref lhs, ref rhs) => write!(f, "({} - {})", lhs, rhs), - FieldElementExpression::Mult(ref lhs, ref rhs) => write!(f, "({} * {})", lhs, rhs), - FieldElementExpression::Div(ref lhs, ref rhs) => write!(f, "({} / {})", lhs, rhs), - FieldElementExpression::Pow(ref lhs, ref rhs) => write!(f, "{}**{}", lhs, rhs), - FieldElementExpression::Neg(ref e) => write!(f, "(-{})", e), - FieldElementExpression::Pos(ref e) => write!(f, "(+{})", e), - FieldElementExpression::And(ref lhs, ref rhs) => write!(f, "({} & {})", lhs, rhs), - FieldElementExpression::Or(ref lhs, ref rhs) => write!(f, "({} | {})", lhs, rhs), - FieldElementExpression::Xor(ref lhs, ref rhs) => write!(f, "({} ^ {})", lhs, rhs), - FieldElementExpression::RightShift(ref e, ref by) => write!(f, "({} >> {})", e, by), - FieldElementExpression::LeftShift(ref e, ref by) => write!(f, "({} << {})", e, by), + FieldElementExpression::Add(ref e) => write!(f, "{}", e), + FieldElementExpression::Sub(ref e) => write!(f, "{}", e), + FieldElementExpression::Mult(ref e) => write!(f, "{}", e), + FieldElementExpression::Div(ref e) => write!(f, "{}", e), + FieldElementExpression::Pow(ref e) => write!(f, "{}", e), + FieldElementExpression::Neg(ref e) => write!(f, "{}", e), + FieldElementExpression::Pos(ref e) => write!(f, "{}", e), FieldElementExpression::Conditional(ref c) => write!(f, "{}", c), + FieldElementExpression::And(ref e) => write!(f, "{}", e), + FieldElementExpression::Or(ref e) => write!(f, "{}", e), + FieldElementExpression::Xor(ref e) => write!(f, "{}", e), + FieldElementExpression::LeftShift(ref e) => write!(f, "{}", e), + FieldElementExpression::RightShift(ref e) => write!(f, "{}", e), FieldElementExpression::FunctionCall(ref function_call) => { write!(f, "{}", function_call) } @@ -1805,22 +2129,22 @@ impl<'ast, T: fmt::Display> fmt::Display for UExpression<'ast, T> { UExpressionInner::Block(ref block) => write!(f, "{}", block,), UExpressionInner::Value(ref v) => write!(f, "{}", v), UExpressionInner::Identifier(ref var) => write!(f, "{}", var), - UExpressionInner::Add(ref lhs, ref rhs) => write!(f, "({} + {})", lhs, rhs), - UExpressionInner::And(ref lhs, ref rhs) => write!(f, "({} & {})", lhs, rhs), - UExpressionInner::Or(ref lhs, ref rhs) => write!(f, "({} | {})", lhs, rhs), - UExpressionInner::Xor(ref lhs, ref rhs) => write!(f, "({} ^ {})", lhs, rhs), - UExpressionInner::Sub(ref lhs, ref rhs) => write!(f, "({} - {})", lhs, rhs), - UExpressionInner::Mult(ref lhs, ref rhs) => write!(f, "({} * {})", lhs, rhs), - UExpressionInner::FloorSub(ref lhs, ref rhs) => { - write!(f, "(FLOOR_SUB({}, {}))", lhs, rhs) + UExpressionInner::Add(ref e) => write!(f, "{}", e), + UExpressionInner::And(ref e) => write!(f, "{}", e), + UExpressionInner::Or(ref e) => write!(f, "{}", e), + UExpressionInner::Xor(ref e) => write!(f, "{}", e), + UExpressionInner::Sub(ref e) => write!(f, "{}", e), + UExpressionInner::Mult(ref e) => write!(f, "{}", e), + UExpressionInner::FloorSub(ref e) => { + write!(f, "{}", e) } - UExpressionInner::Div(ref lhs, ref rhs) => write!(f, "({} / {})", lhs, rhs), - UExpressionInner::Rem(ref lhs, ref rhs) => write!(f, "({} % {})", lhs, rhs), - UExpressionInner::RightShift(ref e, ref by) => write!(f, "({} >> {})", e, by), - UExpressionInner::LeftShift(ref e, ref by) => write!(f, "({} << {})", e, by), - UExpressionInner::Not(ref e) => write!(f, "!{}", e), - UExpressionInner::Neg(ref e) => write!(f, "(-{})", e), - UExpressionInner::Pos(ref e) => write!(f, "(+{})", e), + UExpressionInner::Div(ref e) => write!(f, "{}", e), + UExpressionInner::Rem(ref e) => write!(f, "{}", e), + UExpressionInner::RightShift(ref e) => write!(f, "{}", e), + UExpressionInner::LeftShift(ref e) => write!(f, "{}", e), + UExpressionInner::Not(ref e) => write!(f, "{}", e), + UExpressionInner::Neg(ref e) => write!(f, "{}", e), + UExpressionInner::Pos(ref e) => write!(f, "{}", e), UExpressionInner::Select(ref select) => write!(f, "{}", select), UExpressionInner::FunctionCall(ref function_call) => write!(f, "{}", function_call), UExpressionInner::Conditional(ref c) => write!(f, "{}", c), @@ -1832,27 +2156,23 @@ impl<'ast, T: fmt::Display> fmt::Display for UExpression<'ast, T> { impl<'ast, T: fmt::Display> fmt::Display for BooleanExpression<'ast, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { + match &self { BooleanExpression::Block(ref block) => write!(f, "{}", block,), BooleanExpression::Identifier(ref var) => write!(f, "{}", var), - BooleanExpression::FieldLt(ref lhs, ref rhs) => write!(f, "({} < {})", lhs, rhs), - BooleanExpression::FieldLe(ref lhs, ref rhs) => write!(f, "({} <= {})", lhs, rhs), - BooleanExpression::FieldGe(ref lhs, ref rhs) => write!(f, "({} >= {})", lhs, rhs), - BooleanExpression::FieldGt(ref lhs, ref rhs) => write!(f, "({} > {})", lhs, rhs), - BooleanExpression::UintLt(ref lhs, ref rhs) => write!(f, "({} < {})", lhs, rhs), - BooleanExpression::UintLe(ref lhs, ref rhs) => write!(f, "({} <= {})", lhs, rhs), - BooleanExpression::UintGe(ref lhs, ref rhs) => write!(f, "({} >= {})", lhs, rhs), - BooleanExpression::UintGt(ref lhs, ref rhs) => write!(f, "({} > {})", lhs, rhs), + BooleanExpression::FieldLt(ref e) => write!(f, "{}", e), + BooleanExpression::FieldLe(ref e) => write!(f, "{}", e), + BooleanExpression::UintLt(ref e) => write!(f, "{}", e), + BooleanExpression::UintLe(ref e) => write!(f, "{}", e), BooleanExpression::FieldEq(ref e) => write!(f, "{}", e), BooleanExpression::BoolEq(ref e) => write!(f, "{}", e), BooleanExpression::ArrayEq(ref e) => write!(f, "{}", e), BooleanExpression::StructEq(ref e) => write!(f, "{}", e), BooleanExpression::TupleEq(ref e) => write!(f, "{}", e), BooleanExpression::UintEq(ref e) => write!(f, "{}", e), - BooleanExpression::Or(ref lhs, ref rhs) => write!(f, "({} || {})", lhs, rhs), - BooleanExpression::And(ref lhs, ref rhs) => write!(f, "({} && {})", lhs, rhs), - BooleanExpression::Not(ref exp) => write!(f, "!{}", exp), - BooleanExpression::Value(b) => write!(f, "{}", b), + BooleanExpression::Or(ref e) => write!(f, "{}", e), + BooleanExpression::And(ref e) => write!(f, "{}", e), + BooleanExpression::Not(ref exp) => write!(f, "{}", exp), + BooleanExpression::Value(ref b) => write!(f, "{}", b), BooleanExpression::FunctionCall(ref function_call) => write!(f, "{}", function_call), BooleanExpression::Conditional(ref c) => write!(f, "{}", c), BooleanExpression::Member(ref m) => write!(f, "{}", m), @@ -1880,12 +2200,8 @@ impl<'ast, T: fmt::Display> fmt::Display for ArrayExpressionInner<'ast, T> { ArrayExpressionInner::Conditional(ref c) => write!(f, "{}", c), ArrayExpressionInner::Member(ref m) => write!(f, "{}", m), ArrayExpressionInner::Select(ref select) => write!(f, "{}", select), - ArrayExpressionInner::Slice(ref a, ref from, ref to) => { - write!(f, "{}[{}..{}]", a, from, to) - } - ArrayExpressionInner::Repeat(ref e, ref count) => { - write!(f, "[{}; {}]", e, count) - } + ArrayExpressionInner::Slice(ref e) => write!(f, "{}", e), + ArrayExpressionInner::Repeat(ref e) => write!(f, "{}", e), ArrayExpressionInner::Element(ref element) => write!(f, "{}", element), } } @@ -1898,9 +2214,7 @@ impl<'ast, T: Field> From> for TypedExpression<'ast, T> { match v.get_type() { Type::FieldElement => FieldElementExpression::identifier(v.id).into(), Type::Boolean => BooleanExpression::identifier(v.id).into(), - Type::Array(ty) => ArrayExpression::identifier(v.id) - .annotate(*ty.ty, *ty.size) - .into(), + Type::Array(ty) => ArrayExpression::identifier(v.id).annotate(ty).into(), Type::Struct(ty) => StructExpression::identifier(v.id).annotate(ty).into(), Type::Tuple(ty) => TupleExpression::identifier(v.id).annotate(ty).into(), Type::Uint(w) => UExpression::identifier(v.id).annotate(w).into(), @@ -1909,10 +2223,507 @@ impl<'ast, T: Field> From> for TypedExpression<'ast, T> { } } +// TODO: MACROS + +impl<'ast, T> WithSpan for TypedExpression<'ast, T> { + fn span(self, span: Option) -> Self { + use TypedExpression::*; + match self { + Boolean(e) => Boolean(e.span(span)), + FieldElement(e) => FieldElement(e.span(span)), + Uint(e) => Uint(e.span(span)), + Array(e) => Array(e.span(span)), + Struct(e) => Struct(e.span(span)), + Tuple(e) => Tuple(e.span(span)), + Int(e) => Int(e.span(span)), + } + } + + fn get_span(&self) -> Option { + use TypedExpression::*; + match self { + Boolean(e) => e.get_span(), + FieldElement(e) => e.get_span(), + Uint(e) => e.get_span(), + Array(e) => e.get_span(), + Struct(e) => e.get_span(), + Tuple(e) => e.get_span(), + Int(e) => e.get_span(), + } + } +} + +impl<'ast, T> WithSpan for FieldElementExpression<'ast, T> { + fn span(self, span: Option) -> Self { + use FieldElementExpression::*; + match self { + Select(e) => Select(e.span(span)), + Block(e) => Block(e.span(span)), + Identifier(e) => Identifier(e.span(span)), + Conditional(e) => Conditional(e.span(span)), + FunctionCall(e) => FunctionCall(e.span(span)), + Member(e) => Member(e.span(span)), + Element(e) => Element(e.span(span)), + Add(e) => Add(e.span(span)), + Value(e) => Value(e.span(span)), + Mult(e) => Mult(e.span(span)), + Sub(e) => Sub(e.span(span)), + Pow(e) => Pow(e.span(span)), + Div(e) => Div(e.span(span)), + Pos(e) => Pos(e.span(span)), + Neg(e) => Neg(e.span(span)), + And(e) => And(e.span(span)), + Or(e) => Or(e.span(span)), + Xor(e) => Xor(e.span(span)), + LeftShift(e) => LeftShift(e.span(span)), + RightShift(e) => RightShift(e.span(span)), + } + } + + fn get_span(&self) -> Option { + use FieldElementExpression::*; + match self { + Select(e) => e.get_span(), + Block(e) => e.get_span(), + Identifier(e) => e.get_span(), + Conditional(e) => e.get_span(), + FunctionCall(e) => e.get_span(), + Member(e) => e.get_span(), + Element(e) => e.get_span(), + Add(e) => e.get_span(), + Value(e) => e.get_span(), + Sub(e) => e.get_span(), + Mult(e) => e.get_span(), + Div(e) => e.get_span(), + Pow(e) => e.get_span(), + Neg(e) => e.get_span(), + Pos(e) => e.get_span(), + And(e) => e.get_span(), + Or(e) => e.get_span(), + Xor(e) => e.get_span(), + LeftShift(e) => e.get_span(), + RightShift(e) => e.get_span(), + } + } +} + +impl<'ast, T> WithSpan for BooleanExpression<'ast, T> { + fn span(self, span: Option) -> Self { + use BooleanExpression::*; + match self { + Select(e) => Select(e.span(span)), + Block(e) => Block(e.span(span)), + Identifier(e) => Identifier(e.span(span)), + Conditional(e) => Conditional(e.span(span)), + FunctionCall(e) => FunctionCall(e.span(span)), + Member(e) => Member(e.span(span)), + Element(e) => Element(e.span(span)), + Value(e) => Value(e.span(span)), + FieldLt(e) => FieldLt(e.span(span)), + FieldLe(e) => FieldLe(e.span(span)), + UintLt(e) => UintLt(e.span(span)), + UintLe(e) => UintLe(e.span(span)), + FieldEq(e) => FieldEq(e.span(span)), + BoolEq(e) => BoolEq(e.span(span)), + ArrayEq(e) => ArrayEq(e.span(span)), + StructEq(e) => StructEq(e.span(span)), + TupleEq(e) => TupleEq(e.span(span)), + UintEq(e) => UintEq(e.span(span)), + Or(e) => Or(e.span(span)), + And(e) => And(e.span(span)), + Not(e) => Not(e.span(span)), + } + } + + fn get_span(&self) -> Option { + use BooleanExpression::*; + match self { + Select(e) => e.get_span(), + Block(e) => e.get_span(), + Identifier(e) => e.get_span(), + Conditional(e) => e.get_span(), + FunctionCall(e) => e.get_span(), + Member(e) => e.get_span(), + Element(e) => e.get_span(), + Value(e) => e.get_span(), + FieldLt(e) => e.get_span(), + FieldLe(e) => e.get_span(), + UintLt(e) => e.get_span(), + UintLe(e) => e.get_span(), + FieldEq(e) => e.get_span(), + BoolEq(e) => e.get_span(), + ArrayEq(e) => e.get_span(), + StructEq(e) => e.get_span(), + TupleEq(e) => e.get_span(), + UintEq(e) => e.get_span(), + Or(e) => e.get_span(), + And(e) => e.get_span(), + Not(e) => e.get_span(), + } + } +} + +impl<'ast, T> WithSpan for UExpressionInner<'ast, T> { + fn span(self, span: Option) -> Self { + use UExpressionInner::*; + match self { + Select(e) => Select(e.span(span)), + Block(e) => Block(e.span(span)), + Identifier(e) => Identifier(e.span(span)), + Conditional(e) => Conditional(e.span(span)), + FunctionCall(e) => FunctionCall(e.span(span)), + Member(e) => Member(e.span(span)), + Element(e) => Element(e.span(span)), + Value(e) => Value(e.span(span)), + Add(e) => Add(e.span(span)), + Sub(e) => Sub(e.span(span)), + FloorSub(e) => FloorSub(e.span(span)), + Mult(e) => Mult(e.span(span)), + Div(e) => Div(e.span(span)), + Rem(e) => Rem(e.span(span)), + Xor(e) => Xor(e.span(span)), + And(e) => And(e.span(span)), + Or(e) => Or(e.span(span)), + Not(e) => Not(e.span(span)), + Neg(e) => Neg(e.span(span)), + Pos(e) => Pos(e.span(span)), + LeftShift(e) => LeftShift(e.span(span)), + RightShift(e) => RightShift(e.span(span)), + } + } + + fn get_span(&self) -> Option { + use UExpressionInner::*; + match self { + Select(e) => e.get_span(), + Block(e) => e.get_span(), + Identifier(e) => e.get_span(), + Conditional(e) => e.get_span(), + FunctionCall(e) => e.get_span(), + Member(e) => e.get_span(), + Element(e) => e.get_span(), + Value(e) => e.get_span(), + Add(e) => e.get_span(), + Sub(e) => e.get_span(), + FloorSub(e) => e.get_span(), + Mult(e) => e.get_span(), + Div(e) => e.get_span(), + Rem(e) => e.get_span(), + Xor(e) => e.get_span(), + And(e) => e.get_span(), + Or(e) => e.get_span(), + Not(e) => e.get_span(), + Neg(e) => e.get_span(), + Pos(e) => e.get_span(), + LeftShift(e) => e.get_span(), + RightShift(e) => e.get_span(), + } + } +} + +impl<'ast, T> WithSpan for ArrayExpressionInner<'ast, T> { + fn span(self, span: Option) -> Self { + use ArrayExpressionInner::*; + match self { + Select(e) => Select(e.span(span)), + Block(e) => Block(e.span(span)), + Identifier(e) => Identifier(e.span(span)), + Conditional(e) => Conditional(e.span(span)), + FunctionCall(e) => FunctionCall(e.span(span)), + Member(e) => Member(e.span(span)), + Element(e) => Element(e.span(span)), + Value(e) => Value(e.span(span)), + Slice(e) => Slice(e.span(span)), + Repeat(e) => Repeat(e.span(span)), + } + } + + fn get_span(&self) -> Option { + use ArrayExpressionInner::*; + match self { + Select(e) => e.get_span(), + Block(e) => e.get_span(), + Identifier(e) => e.get_span(), + Conditional(e) => e.get_span(), + FunctionCall(e) => e.get_span(), + Member(e) => e.get_span(), + Element(e) => e.get_span(), + Value(e) => e.get_span(), + Slice(e) => e.get_span(), + Repeat(e) => e.get_span(), + } + } +} + +impl<'ast, T> WithSpan for StructExpressionInner<'ast, T> { + fn span(self, span: Option) -> Self { + use StructExpressionInner::*; + match self { + Select(e) => Select(e.span(span)), + Block(e) => Block(e.span(span)), + Identifier(e) => Identifier(e.span(span)), + Conditional(e) => Conditional(e.span(span)), + FunctionCall(e) => FunctionCall(e.span(span)), + Member(e) => Member(e.span(span)), + Element(e) => Element(e.span(span)), + Value(e) => Value(e.span(span)), + } + } + + fn get_span(&self) -> Option { + use StructExpressionInner::*; + match self { + Select(e) => e.get_span(), + Block(e) => e.get_span(), + Identifier(e) => e.get_span(), + Conditional(e) => e.get_span(), + FunctionCall(e) => e.get_span(), + Member(e) => e.get_span(), + Element(e) => e.get_span(), + Value(e) => e.get_span(), + } + } +} + +impl<'ast, T> WithSpan for TupleExpressionInner<'ast, T> { + fn span(self, span: Option) -> Self { + use TupleExpressionInner::*; + match self { + Select(e) => Select(e.span(span)), + Block(e) => Block(e.span(span)), + Identifier(e) => Identifier(e.span(span)), + Conditional(e) => Conditional(e.span(span)), + FunctionCall(e) => FunctionCall(e.span(span)), + Member(e) => Member(e.span(span)), + Element(e) => Element(e.span(span)), + Value(e) => Value(e.span(span)), + } + } + + fn get_span(&self) -> Option { + use TupleExpressionInner::*; + match self { + Select(e) => e.get_span(), + Block(e) => e.get_span(), + Identifier(e) => e.get_span(), + Conditional(e) => e.get_span(), + FunctionCall(e) => e.get_span(), + Member(e) => e.get_span(), + Element(e) => e.get_span(), + Value(e) => e.get_span(), + } + } +} + +impl<'ast, T> WithSpan for IntExpression<'ast, T> { + fn span(self, span: Option) -> Self { + use IntExpression::*; + match self { + Conditional(e) => Conditional(e.span(span)), + Select(e) => Select(e.span(span)), + Value(e) => Value(e.span(span)), + Pos(e) => Pos(e.span(span)), + Neg(e) => Neg(e.span(span)), + Not(e) => Not(e.span(span)), + Add(e) => Add(e.span(span)), + Sub(e) => Sub(e.span(span)), + Mult(e) => Mult(e.span(span)), + Div(e) => Div(e.span(span)), + Rem(e) => Rem(e.span(span)), + Pow(e) => Pow(e.span(span)), + Xor(e) => Xor(e.span(span)), + And(e) => And(e.span(span)), + Or(e) => Or(e.span(span)), + LeftShift(e) => LeftShift(e.span(span)), + RightShift(e) => RightShift(e.span(span)), + } + } + + fn get_span(&self) -> Option { + use IntExpression::*; + match self { + Conditional(e) => e.get_span(), + Select(e) => e.get_span(), + Value(e) => e.get_span(), + Pos(e) => e.get_span(), + Neg(e) => e.get_span(), + Not(e) => e.get_span(), + Add(e) => e.get_span(), + Sub(e) => e.get_span(), + Mult(e) => e.get_span(), + Div(e) => e.get_span(), + Rem(e) => e.get_span(), + Pow(e) => e.get_span(), + Xor(e) => e.get_span(), + And(e) => e.get_span(), + Or(e) => e.get_span(), + LeftShift(e) => e.get_span(), + RightShift(e) => e.get_span(), + } + } +} + +impl<'ast, T> WithSpan for TupleExpression<'ast, T> { + fn span(self, span: Option) -> Self { + TupleExpression { + inner: self.inner.span(span), + ..self + } + } + + fn get_span(&self) -> Option { + self.inner.get_span() + } +} + +impl<'ast, T> WithSpan for StructExpression<'ast, T> { + fn span(self, span: Option) -> Self { + StructExpression { + inner: self.inner.span(span), + ..self + } + } + + fn get_span(&self) -> Option { + self.inner.get_span() + } +} + +impl<'ast, T> WithSpan for ArrayExpression<'ast, T> { + fn span(self, span: Option) -> Self { + ArrayExpression { + inner: self.inner.span(span), + ..self + } + } + + fn get_span(&self) -> Option { + self.inner.get_span() + } +} + +impl<'ast, T> WithSpan for UExpression<'ast, T> { + fn span(self, span: Option) -> Self { + UExpression { + inner: self.inner.span(span), + ..self + } + } + + fn get_span(&self) -> Option { + self.inner.get_span() + } +} + +impl<'ast, T, E> WithSpan for ConditionalExpression<'ast, T, E> { + fn span(mut self, span: Option) -> Self { + self.span = span; + self + } + + fn get_span(&self) -> Option { + self.span + } +} + +impl WithSpan for ValueExpression { + fn span(mut self, span: Option) -> Self { + self.span = span; + self + } + + fn get_span(&self) -> Option { + self.span + } +} + +impl<'ast, T, E> WithSpan for SelectExpression<'ast, T, E> { + fn span(mut self, span: Option) -> Self { + self.span = span; + self + } + + fn get_span(&self) -> Option { + self.span + } +} + +impl<'ast, T, E> WithSpan for ElementExpression<'ast, T, E> { + fn span(mut self, span: Option) -> Self { + self.span = span; + self + } + + fn get_span(&self) -> Option { + self.span + } +} + +impl<'ast, T, E> WithSpan for MemberExpression<'ast, T, E> { + fn span(mut self, span: Option) -> Self { + self.span = span; + self + } + + fn get_span(&self) -> Option { + self.span + } +} + +impl<'ast, T, E> WithSpan for FunctionCallExpression<'ast, T, E> { + fn span(mut self, span: Option) -> Self { + self.span = span; + self + } + + fn get_span(&self) -> Option { + self.span + } +} + +impl<'ast, T, E> WithSpan for BlockExpression<'ast, T, E> { + fn span(mut self, span: Option) -> Self { + self.span = span; + self + } + + fn get_span(&self) -> Option { + self.span + } +} + +impl<'ast, T: Clone> Value for FieldElementExpression<'ast, T> { + type Value = T; +} + +impl<'ast, T> Value for BooleanExpression<'ast, T> { + type Value = bool; +} + +impl<'ast, T> Value for UExpression<'ast, T> { + type Value = u128; +} + +impl<'ast, T: Clone> Value for ArrayExpression<'ast, T> { + type Value = Vec>; +} + +impl<'ast, T: Clone> Value for StructExpression<'ast, T> { + type Value = Vec>; +} + +impl<'ast, T: Clone> Value for TupleExpression<'ast, T> { + type Value = Vec>; +} + +impl<'ast, T> Value for IntExpression<'ast, T> { + type Value = BigUint; +} + // Common behaviour across expressions -pub trait Expr<'ast, T>: fmt::Display + From> { - type Inner; +pub trait Expr<'ast, T>: Value + WithSpan + fmt::Display + From> { + type Inner: WithSpan; type Ty: Clone + IntoType>; type ConcreteTy: Clone + IntoType; @@ -1923,9 +2734,11 @@ pub trait Expr<'ast, T>: fmt::Display + From> { fn as_inner(&self) -> &Self::Inner; fn as_inner_mut(&mut self) -> &mut Self::Inner; + + fn value(_: Self::Value) -> Self::Inner; } -impl<'ast, T: Field> Expr<'ast, T> for FieldElementExpression<'ast, T> { +impl<'ast, T: fmt::Display + Clone> Expr<'ast, T> for FieldElementExpression<'ast, T> { type Inner = Self; type Ty = Type<'ast, T>; type ConcreteTy = ConcreteType; @@ -1945,9 +2758,13 @@ impl<'ast, T: Field> Expr<'ast, T> for FieldElementExpression<'ast, T> { fn as_inner_mut(&mut self) -> &mut Self::Inner { self } + + fn value(v: ::Value) -> Self::Inner { + Self::Value(ValueExpression::new(v)) + } } -impl<'ast, T: Field> Expr<'ast, T> for BooleanExpression<'ast, T> { +impl<'ast, T: fmt::Display + Clone> Expr<'ast, T> for BooleanExpression<'ast, T> { type Inner = Self; type Ty = Type<'ast, T>; type ConcreteTy = ConcreteType; @@ -1967,9 +2784,13 @@ impl<'ast, T: Field> Expr<'ast, T> for BooleanExpression<'ast, T> { fn as_inner_mut(&mut self) -> &mut Self::Inner { self } + + fn value(v: ::Value) -> Self::Inner { + Self::Value(ValueExpression::new(v)) + } } -impl<'ast, T: Field> Expr<'ast, T> for UExpression<'ast, T> { +impl<'ast, T: fmt::Display + Clone> Expr<'ast, T> for UExpression<'ast, T> { type Inner = UExpressionInner<'ast, T>; type Ty = UBitwidth; type ConcreteTy = UBitwidth; @@ -1989,9 +2810,13 @@ impl<'ast, T: Field> Expr<'ast, T> for UExpression<'ast, T> { fn as_inner_mut(&mut self) -> &mut Self::Inner { &mut self.inner } + + fn value(v: Self::Value) -> Self::Inner { + UExpressionInner::Value(ValueExpression::new(v)) + } } -impl<'ast, T: Field> Expr<'ast, T> for StructExpression<'ast, T> { +impl<'ast, T: fmt::Display + Clone> Expr<'ast, T> for StructExpression<'ast, T> { type Inner = StructExpressionInner<'ast, T>; type Ty = StructType<'ast, T>; type ConcreteTy = ConcreteStructType; @@ -2011,9 +2836,13 @@ impl<'ast, T: Field> Expr<'ast, T> for StructExpression<'ast, T> { fn as_inner_mut(&mut self) -> &mut Self::Inner { &mut self.inner } + + fn value(v: Self::Value) -> Self::Inner { + StructExpressionInner::Value(ValueExpression::new(v)) + } } -impl<'ast, T: Field> Expr<'ast, T> for ArrayExpression<'ast, T> { +impl<'ast, T: Clone + fmt::Display> Expr<'ast, T> for ArrayExpression<'ast, T> { type Inner = ArrayExpressionInner<'ast, T>; type Ty = ArrayType<'ast, T>; type ConcreteTy = ConcreteArrayType; @@ -2033,9 +2862,13 @@ impl<'ast, T: Field> Expr<'ast, T> for ArrayExpression<'ast, T> { fn as_inner_mut(&mut self) -> &mut Self::Inner { &mut self.inner } + + fn value(v: Self::Value) -> Self::Inner { + ArrayExpressionInner::Value(ValueExpression::new(v)) + } } -impl<'ast, T: Field> Expr<'ast, T> for TupleExpression<'ast, T> { +impl<'ast, T: fmt::Display + Clone> Expr<'ast, T> for TupleExpression<'ast, T> { type Inner = TupleExpressionInner<'ast, T>; type Ty = TupleType<'ast, T>; type ConcreteTy = ConcreteTupleType; @@ -2055,9 +2888,13 @@ impl<'ast, T: Field> Expr<'ast, T> for TupleExpression<'ast, T> { fn as_inner_mut(&mut self) -> &mut Self::Inner { &mut self.inner } + + fn value(v: Self::Value) -> Self::Inner { + TupleExpressionInner::Value(ValueExpression::new(v)) + } } -impl<'ast, T: Field> Expr<'ast, T> for IntExpression<'ast, T> { +impl<'ast, T: fmt::Display + Clone> Expr<'ast, T> for IntExpression<'ast, T> { type Inner = Self; type Ty = Type<'ast, T>; type ConcreteTy = ConcreteType; @@ -2077,6 +2914,10 @@ impl<'ast, T: Field> Expr<'ast, T> for IntExpression<'ast, T> { fn as_inner_mut(&mut self) -> &mut Self::Inner { self } + + fn value(v: as Value>::Value) -> Self { + IntExpression::Value(ValueExpression::new(v)) + } } // Enums types to enable returning e.g a member expression OR another type of expression of this type @@ -2089,20 +2930,19 @@ pub enum SelectOrExpression<'ast, T, E: Expr<'ast, T>> { Select(SelectExpression<'ast, T, E>), Expression(E::Inner), } - -pub enum EqOrBoolean<'ast, T, E> { - Eq(EqExpression), - Boolean(BooleanExpression<'ast, T>), -} - pub enum MemberOrExpression<'ast, T, E: Expr<'ast, T>> { Member(MemberExpression<'ast, T, E>), Expression(E::Inner), } -pub enum IdentifierOrExpression<'ast, T, E: Expr<'ast, T>> { - Identifier(IdentifierExpression<'ast, E>), - Expression(E::Inner), +pub enum RepeatOrExpression<'ast, T> { + Repeat(RepeatExpression<'ast, T>), + Expression(ArrayExpressionInner<'ast, T>), +} + +pub enum SliceOrExpression<'ast, T> { + Slice(SliceExpression<'ast, T>), + Expression(ArrayExpressionInner<'ast, T>), } pub enum ElementOrExpression<'ast, T, E: Expr<'ast, T>> { @@ -2115,6 +2955,22 @@ pub enum ConditionalOrExpression<'ast, T, E: Expr<'ast, T>> { Expression(E::Inner), } +pub trait Basic<'ast, T> { + type ZirExpressionType: WithSpan + Value + From>; +} + +impl<'ast, T: Clone> Basic<'ast, T> for FieldElementExpression<'ast, T> { + type ZirExpressionType = crate::zir::FieldElementExpression<'ast, T>; +} + +impl<'ast, T> Basic<'ast, T> for BooleanExpression<'ast, T> { + type ZirExpressionType = crate::zir::BooleanExpression<'ast, T>; +} + +impl<'ast, T> Basic<'ast, T> for UExpression<'ast, T> { + type ZirExpressionType = crate::zir::UExpression<'ast, T>; +} + pub trait Conditional<'ast, T> { fn conditional( condition: BooleanExpression<'ast, T>, @@ -2191,22 +3047,21 @@ impl<'ast, T> Conditional<'ast, T> for UExpression<'ast, T> { } } -impl<'ast, T: Clone> Conditional<'ast, T> for ArrayExpression<'ast, T> { +impl<'ast, T: Clone + fmt::Display> Conditional<'ast, T> for ArrayExpression<'ast, T> { fn conditional( condition: BooleanExpression<'ast, T>, consequence: Self, alternative: Self, kind: ConditionalKind, ) -> Self { - let ty = consequence.inner_type().clone(); - let size = consequence.size(); + let ty = consequence.ty().clone(); ArrayExpressionInner::Conditional(ConditionalExpression::new( condition, consequence, alternative, kind, )) - .annotate(ty, size) + .annotate(ty) } } @@ -2295,13 +3150,9 @@ impl<'ast, T: Clone> Select<'ast, T> for UExpression<'ast, T> { impl<'ast, T: Clone> Select<'ast, T> for ArrayExpression<'ast, T> { fn select>>(array: ArrayExpression<'ast, T>, index: I) -> Self { - let (ty, size) = match array.inner_type() { - Type::Array(array_type) => (array_type.ty.clone(), array_type.size.clone()), - _ => unreachable!(), - }; + let array_ty = array.inner_type().clone().try_into().unwrap(); - ArrayExpressionInner::Select(SelectExpression::new(array, index.into())) - .annotate(*ty, *size) + ArrayExpressionInner::Select(SelectExpression::new(array, index.into())).annotate(array_ty) } } @@ -2345,56 +3196,60 @@ impl<'ast, T> Member<'ast, T> for BooleanExpression<'ast, T> { impl<'ast, T: Clone> Member<'ast, T> for UExpression<'ast, T> { fn member(s: StructExpression<'ast, T>, id: MemberId) -> Self { - let ty = s.ty().members.iter().find(|member| id == member.id); - let bitwidth = match ty { - Some(crate::typed::types::StructMember { - ty: box Type::Uint(bitwidth), - .. - }) => *bitwidth, - _ => unreachable!(), - }; + let ty = *s + .ty() + .members + .iter() + .find(|member| id == member.id) + .unwrap() + .ty + .clone(); + let bitwidth: UBitwidth = ty.try_into().unwrap(); UExpressionInner::Member(MemberExpression::new(s, id)).annotate(bitwidth) } } impl<'ast, T: Clone> Member<'ast, T> for ArrayExpression<'ast, T> { fn member(s: StructExpression<'ast, T>, id: MemberId) -> Self { - let ty = s.ty().members.iter().find(|member| id == member.id); - let (ty, size) = match ty { - Some(crate::typed::types::StructMember { - ty: box Type::Array(array_ty), - .. - }) => (*array_ty.ty.clone(), array_ty.size.clone()), - _ => unreachable!(), - }; - ArrayExpressionInner::Member(MemberExpression::new(s, id)).annotate(ty, *size) + let ty = *s + .ty() + .members + .iter() + .find(|member| id == member.id) + .unwrap() + .ty + .clone(); + let array_ty: ArrayType<'ast, T> = ty.try_into().unwrap(); + ArrayExpressionInner::Member(MemberExpression::new(s, id)).annotate(array_ty) } } impl<'ast, T: Clone> Member<'ast, T> for StructExpression<'ast, T> { fn member(s: StructExpression<'ast, T>, id: MemberId) -> Self { - let ty = s.ty().members.iter().find(|member| id == member.id); - let struct_ty = match ty { - Some(crate::typed::types::StructMember { - ty: box Type::Struct(struct_ty), - .. - }) => struct_ty.clone(), - _ => unreachable!(), - }; + let ty = *s + .ty() + .members + .iter() + .find(|member| id == member.id) + .unwrap() + .ty + .clone(); + let struct_ty = ty.try_into().unwrap(); StructExpressionInner::Member(MemberExpression::new(s, id)).annotate(struct_ty) } } impl<'ast, T: Clone> Member<'ast, T> for TupleExpression<'ast, T> { fn member(s: StructExpression<'ast, T>, id: MemberId) -> Self { - let ty = s.ty().members.iter().find(|member| id == member.id); - let tuple_ty = match ty { - Some(crate::typed::types::StructMember { - ty: box Type::Tuple(tuple_ty), - .. - }) => tuple_ty.clone(), - _ => unreachable!(), - }; + let ty = *s + .ty() + .members + .iter() + .find(|member| id == member.id) + .unwrap() + .ty + .clone(); + let tuple_ty = ty.try_into().unwrap(); TupleExpressionInner::Member(MemberExpression::new(s, id)).annotate(tuple_ty) } } @@ -2428,12 +3283,9 @@ impl<'ast, T: Clone> Element<'ast, T> for UExpression<'ast, T> { impl<'ast, T: Clone> Element<'ast, T> for ArrayExpression<'ast, T> { fn element(s: TupleExpression<'ast, T>, id: u32) -> Self { - let ty = &s.ty().elements[id as usize]; - let (ty, size) = match ty { - Type::Array(array_ty) => (*array_ty.ty.clone(), array_ty.size.clone()), - _ => unreachable!(), - }; - ArrayExpressionInner::Element(ElementExpression::new(s, id)).annotate(ty, *size) + let ty = s.ty().elements[id as usize].clone(); + let array_ty = ty.try_into().unwrap(); + ArrayExpressionInner::Element(ElementExpression::new(s, id)).annotate(array_ty) } } @@ -2593,8 +3445,7 @@ impl<'ast, T: Field> Block<'ast, T> for UExpression<'ast, T> { impl<'ast, T: Field> Block<'ast, T> for ArrayExpression<'ast, T> { fn block(statements: Vec>, value: Self) -> Self { let array_ty = value.ty().clone(); - ArrayExpressionInner::Block(BlockExpression::new(statements, value)) - .annotate(*array_ty.ty, *array_ty.size) + ArrayExpressionInner::Block(BlockExpression::new(statements, value)).annotate(array_ty) } } @@ -2613,6 +3464,20 @@ impl<'ast, T: Field> Block<'ast, T> for StructExpression<'ast, T> { } } +impl<'ast, T: Field> Block<'ast, T> for TypedExpression<'ast, T> { + fn block(statements: Vec>, value: Self) -> Self { + match value { + TypedExpression::Boolean(e) => BooleanExpression::block(statements, e).into(), + TypedExpression::FieldElement(e) => FieldElementExpression::block(statements, e).into(), + TypedExpression::Uint(e) => UExpression::block(statements, e).into(), + TypedExpression::Array(e) => ArrayExpression::block(statements, e).into(), + TypedExpression::Struct(e) => StructExpression::block(statements, e).into(), + TypedExpression::Tuple(e) => TupleExpression::block(statements, e).into(), + TypedExpression::Int(e) => unreachable!("{}", e), + } + } +} + pub trait Constant: Sized { // return whether this is constant fn is_constant(&self) -> bool; @@ -2626,7 +3491,7 @@ pub trait Constant: Sized { impl<'ast, T: Field> Constant for FieldElementExpression<'ast, T> { fn is_constant(&self) -> bool { - matches!(self, FieldElementExpression::Number(..)) + matches!(self, FieldElementExpression::Value(..)) } } @@ -2645,16 +3510,14 @@ impl<'ast, T: Field> Constant for UExpression<'ast, T> { impl<'ast, T: Field> Constant for ArrayExpression<'ast, T> { fn is_constant(&self) -> bool { match self.as_inner() { - ArrayExpressionInner::Value(v) => v.0.iter().all(|e| match e { + ArrayExpressionInner::Value(v) => v.iter().all(|e| match e { TypedExpressionOrSpread::Expression(e) => e.is_constant(), TypedExpressionOrSpread::Spread(s) => s.array.is_constant(), }), - ArrayExpressionInner::Slice(box a, box from, box to) => { - from.is_constant() && to.is_constant() && a.is_constant() - } - ArrayExpressionInner::Repeat(box e, box count) => { - count.is_constant() && e.is_constant() + ArrayExpressionInner::Slice(e) => { + e.from.is_constant() && e.to.is_constant() && e.array.is_constant() } + ArrayExpressionInner::Repeat(e) => e.count.is_constant() && e.e.is_constant(), _ => false, } } @@ -2664,41 +3527,41 @@ impl<'ast, T: Field> Constant for ArrayExpression<'ast, T> { e: TypedExpressionOrSpread, ) -> Vec> { match e { - TypedExpressionOrSpread::Expression(e) => vec![e], + TypedExpressionOrSpread::Expression(e) => vec![e.into_canonical_constant()], TypedExpressionOrSpread::Spread(s) => match s.array.into_inner() { ArrayExpressionInner::Value(v) => v .into_iter() .flat_map(into_canonical_constant_aux) .collect(), - ArrayExpressionInner::Slice(box v, box from, box to) => { - let from = match from.into_inner() { + ArrayExpressionInner::Slice(e) => { + let from = match e.from.into_inner() { UExpressionInner::Value(v) => v, _ => unreachable!(), }; - let to = match to.into_inner() { + let to = match e.to.into_inner() { UExpressionInner::Value(v) => v, _ => unreachable!(), }; - let v = match v.into_inner() { + let v = match e.array.into_inner() { ArrayExpressionInner::Value(v) => v, _ => unreachable!(), }; v.into_iter() .flat_map(into_canonical_constant_aux) - .skip(from as usize) - .take(to as usize - from as usize) + .skip(from.value as usize) + .take(to.value as usize - from.value as usize) .collect() } - ArrayExpressionInner::Repeat(box e, box count) => { - let count = match count.into_inner() { + ArrayExpressionInner::Repeat(e) => { + let count = match e.count.into_inner() { UExpressionInner::Value(count) => count, _ => unreachable!(), }; - vec![e; count as usize] + vec![e.e.into_canonical_constant(); count.value as usize] } a => unreachable!("{}", a), }, @@ -2708,53 +3571,49 @@ impl<'ast, T: Field> Constant for ArrayExpression<'ast, T> { let array_ty = self.ty().clone(); match self.into_inner() { - ArrayExpressionInner::Value(v) => ArrayExpressionInner::Value( + ArrayExpressionInner::Value(v) => ArrayExpression::value( v.into_iter() .flat_map(into_canonical_constant_aux) .map(|e| e.into()) - .collect::>() - .into(), + .collect::>(), ) - .annotate(*array_ty.ty, *array_ty.size), - ArrayExpressionInner::Slice(box a, box from, box to) => { - let from = match from.into_inner() { - UExpressionInner::Value(from) => from as usize, + .annotate(array_ty), + ArrayExpressionInner::Slice(e) => { + let from = match e.from.into_inner() { + UExpressionInner::Value(from) => from.value as usize, _ => unreachable!("should be a uint value"), }; - let to = match to.into_inner() { - UExpressionInner::Value(to) => to as usize, + let to = match e.to.into_inner() { + UExpressionInner::Value(to) => to.value as usize, _ => unreachable!("should be a uint value"), }; - let v = match a.into_inner() { + let v = match e.array.into_inner() { ArrayExpressionInner::Value(v) => v, _ => unreachable!("should be an array value"), }; - ArrayExpressionInner::Value( + ArrayExpression::value( v.into_iter() .flat_map(into_canonical_constant_aux) .map(|e| e.into()) .skip(from) .take(to - from) - .collect::>() - .into(), + .collect::>(), ) - .annotate(*array_ty.ty, *array_ty.size) + .annotate(array_ty) } - ArrayExpressionInner::Repeat(box e, box count) => { - let count = match count.into_inner() { - UExpressionInner::Value(from) => from as usize, + ArrayExpressionInner::Repeat(e) => { + let count = match e.count.into_inner() { + UExpressionInner::Value(from) => from.value as usize, _ => unreachable!("should be a uint value"), }; - let e = e.into_canonical_constant(); + let e = e.e.into_canonical_constant(); - ArrayExpressionInner::Value( - vec![TypedExpressionOrSpread::Expression(e); count].into(), - ) - .annotate(*array_ty.ty, *array_ty.size) + ArrayExpression::value(vec![TypedExpressionOrSpread::Expression(e); count]) + .annotate(array_ty) } _ => unreachable!(), } @@ -2773,7 +3632,7 @@ impl<'ast, T: Field> Constant for StructExpression<'ast, T> { let struct_ty = self.ty().clone(); match self.into_inner() { - StructExpressionInner::Value(expressions) => StructExpressionInner::Value( + StructExpressionInner::Value(expressions) => StructExpression::value( expressions .into_iter() .map(|e| e.into_canonical_constant()) @@ -2797,7 +3656,7 @@ impl<'ast, T: Field> Constant for TupleExpression<'ast, T> { let tuple_ty = self.ty().clone(); match self.into_inner() { - TupleExpressionInner::Value(expressions) => TupleExpressionInner::Value( + TupleExpressionInner::Value(expressions) => TupleExpression::value( expressions .into_iter() .map(|e| e.into_canonical_constant()) diff --git a/zokrates_ast/src/typed/parameter.rs b/zokrates_ast/src/typed/parameter.rs index 45b0dcae4..4b8332eb1 100644 --- a/zokrates_ast/src/typed/parameter.rs +++ b/zokrates_ast/src/typed/parameter.rs @@ -1,33 +1,5 @@ use crate::typed::types::DeclarationConstant; use crate::typed::GVariable; -use std::fmt; - -#[derive(Clone, PartialEq, Eq, Hash)] -pub struct GParameter<'ast, S> { - pub id: GVariable<'ast, S>, - pub private: bool, -} - -impl<'ast, S> From> for GParameter<'ast, S> { - fn from(v: GVariable<'ast, S>) -> Self { - GParameter { - id: v, - private: true, - } - } -} +pub type GParameter<'ast, S> = crate::common::Parameter>; pub type DeclarationParameter<'ast, T> = GParameter<'ast, DeclarationConstant<'ast, T>>; - -impl<'ast, S: fmt::Display> fmt::Display for GParameter<'ast, S> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let visibility = if self.private { "private " } else { "" }; - write!(f, "{}{} {}", visibility, self.id._type, self.id.id) - } -} - -impl<'ast, S: fmt::Debug> fmt::Debug for GParameter<'ast, S> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Parameter(variable: {:?})", self.id) - } -} diff --git a/zokrates_ast/src/typed/result_folder.rs b/zokrates_ast/src/typed/result_folder.rs index e4146c504..d8541add0 100644 --- a/zokrates_ast/src/typed/result_folder.rs +++ b/zokrates_ast/src/typed/result_folder.rs @@ -1,45 +1,57 @@ // Generic walk through a typed AST. Not mutating in place +use crate::common::expressions::{ + BinaryOrExpression, EqExpression, UnaryOrExpression, ValueOrExpression, +}; +use crate::common::ResultFold; use crate::typed::types::*; use crate::typed::*; use zokrates_field::Field; -pub trait ResultFold<'ast, T: Field>: Sized { - fn fold>(self, f: &mut F) -> Result; -} +use super::identifier::FrameIdentifier; -impl<'ast, T: Field> ResultFold<'ast, T> for FieldElementExpression<'ast, T> { - fn fold>(self, f: &mut F) -> Result { +impl<'ast, T: Field, F: ResultFolder<'ast, T>> ResultFold + for FieldElementExpression<'ast, T> +{ + fn fold(self, f: &mut F) -> Result { f.fold_field_expression(self) } } -impl<'ast, T: Field> ResultFold<'ast, T> for BooleanExpression<'ast, T> { - fn fold>(self, f: &mut F) -> Result { +impl<'ast, T: Field, F: ResultFolder<'ast, T>> ResultFold + for BooleanExpression<'ast, T> +{ + fn fold(self, f: &mut F) -> Result { f.fold_boolean_expression(self) } } -impl<'ast, T: Field> ResultFold<'ast, T> for UExpression<'ast, T> { - fn fold>(self, f: &mut F) -> Result { +impl<'ast, T: Field, F: ResultFolder<'ast, T>> ResultFold for UExpression<'ast, T> { + fn fold(self, f: &mut F) -> Result { f.fold_uint_expression(self) } } -impl<'ast, T: Field> ResultFold<'ast, T> for ArrayExpression<'ast, T> { - fn fold>(self, f: &mut F) -> Result { - f.fold_array_expression(self) +impl<'ast, T: Field, F: ResultFolder<'ast, T>> ResultFold + for StructExpression<'ast, T> +{ + fn fold(self, f: &mut F) -> Result { + f.fold_struct_expression(self) } } -impl<'ast, T: Field> ResultFold<'ast, T> for StructExpression<'ast, T> { - fn fold>(self, f: &mut F) -> Result { - f.fold_struct_expression(self) +impl<'ast, T: Field, F: ResultFolder<'ast, T>> ResultFold + for ArrayExpression<'ast, T> +{ + fn fold(self, f: &mut F) -> Result { + f.fold_array_expression(self) } } -impl<'ast, T: Field> ResultFold<'ast, T> for TupleExpression<'ast, T> { - fn fold>(self, f: &mut F) -> Result { +impl<'ast, T: Field, F: ResultFolder<'ast, T>> ResultFold + for TupleExpression<'ast, T> +{ + fn fold(self, f: &mut F) -> Result { f.fold_tuple_expression(self) } } @@ -151,38 +163,36 @@ pub trait ResultFolder<'ast, T: Field>: Sized { }) } - fn fold_module_id(&mut self, i: OwnedTypedModuleId) -> Result { + fn fold_module_id(&mut self, i: OwnedModuleId) -> Result { Ok(i) } fn fold_name(&mut self, n: Identifier<'ast>) -> Result, Self::Error> { - let id = match n.id { - CoreIdentifier::Constant(c) => { - CoreIdentifier::Constant(self.fold_canonical_constant_identifier(c)?) - } - id => id, + let id = match n.id.id.clone() { + CoreIdentifier::Constant(c) => FrameIdentifier { + id: CoreIdentifier::Constant(self.fold_canonical_constant_identifier(c)?), + frame: 0, + }, + _ => n.id, }; Ok(Identifier { id, ..n }) } fn fold_variable(&mut self, v: Variable<'ast, T>) -> Result, Self::Error> { - Ok(Variable { - id: self.fold_name(v.id)?, - _type: self.fold_type(v._type)?, - is_mutable: v.is_mutable, - }) + let span = v.get_span(); + Ok(Variable::new(self.fold_name(v.id)?, self.fold_type(v.ty)?).span(span)) } fn fold_declaration_variable( &mut self, v: DeclarationVariable<'ast, T>, ) -> Result, Self::Error> { - Ok(DeclarationVariable { - id: self.fold_name(v.id)?, - _type: self.fold_declaration_type(v._type)?, - is_mutable: v.is_mutable, - }) + let span = v.get_span(); + Ok( + DeclarationVariable::new(self.fold_name(v.id)?, self.fold_declaration_type(v.ty)?) + .span(span), + ) } fn fold_type(&mut self, t: Type<'ast, T>) -> Result, Self::Error> { @@ -197,7 +207,7 @@ pub trait ResultFolder<'ast, T: Field>: Sized { } fn fold_conditional_expression< - E: Expr<'ast, T> + PartialEq + Conditional<'ast, T> + ResultFold<'ast, T>, + E: Expr<'ast, T> + PartialEq + Conditional<'ast, T> + ResultFold, >( &mut self, ty: &E::Ty, @@ -206,14 +216,55 @@ pub trait ResultFolder<'ast, T: Field>: Sized { fold_conditional_expression(self, ty, e) } - fn fold_block_expression>( + #[allow(clippy::type_complexity)] + fn fold_binary_expression< + L: Expr<'ast, T> + PartialEq + ResultFold, + R: Expr<'ast, T> + PartialEq + ResultFold, + E: Expr<'ast, T> + PartialEq + ResultFold, + Op: OperatorStr, + >( + &mut self, + ty: &E::Ty, + e: BinaryExpression, + ) -> Result, Self::Error> { + fold_binary_expression(self, ty, e) + } + + #[allow(clippy::type_complexity)] + fn fold_eq_expression< + E: Expr<'ast, T> + Constant + Typed<'ast, T> + PartialEq + ResultFold, + >( + &mut self, + e: EqExpression>, + ) -> Result< + BinaryOrExpression, BooleanExpression<'ast, T>>, + Self::Error, + > { + fold_binary_expression(self, &Type::Boolean, e) + } + + fn fold_unary_expression< + In: Expr<'ast, T> + PartialEq + ResultFold, + E: Expr<'ast, T> + PartialEq + ResultFold, + Op, + >( + &mut self, + ty: &E::Ty, + e: UnaryExpression, + ) -> Result, Self::Error> { + fold_unary_expression(self, ty, e) + } + + fn fold_block_expression>( &mut self, block: BlockExpression<'ast, T, E>, ) -> Result, Self::Error> { fold_block_expression(self, block) } - fn fold_identifier_expression + Id<'ast, T> + ResultFold<'ast, T>>( + fn fold_identifier_expression< + E: Expr<'ast, T> + Id<'ast, T> + ResultFold, + >( &mut self, ty: &E::Ty, id: IdentifierExpression<'ast, E>, @@ -231,6 +282,20 @@ pub trait ResultFolder<'ast, T: Field>: Sized { fold_member_expression(self, ty, e) } + fn fold_slice_expression( + &mut self, + e: SliceExpression<'ast, T>, + ) -> Result, Self::Error> { + fold_slice_expression(self, e) + } + + fn fold_repeat_expression( + &mut self, + e: RepeatExpression<'ast, T>, + ) -> Result, Self::Error> { + fold_repeat_expression(self, e) + } + fn fold_element_expression< E: Expr<'ast, T> + Element<'ast, T> + From>, >( @@ -241,15 +306,6 @@ pub trait ResultFolder<'ast, T: Field>: Sized { fold_element_expression(self, ty, e) } - fn fold_eq_expression< - E: Expr<'ast, T> + Typed<'ast, T> + PartialEq + Constant + ResultFold<'ast, T>, - >( - &mut self, - e: EqExpression, - ) -> Result, Self::Error> { - fold_eq_expression(self, e) - } - fn fold_select_expression< E: Expr<'ast, T> + Select<'ast, T> @@ -278,8 +334,8 @@ pub trait ResultFolder<'ast, T: Field>: Sized { t: ArrayType<'ast, T>, ) -> Result, Self::Error> { Ok(ArrayType { - ty: box self.fold_type(*t.ty)?, - size: box self.fold_uint_expression(*t.size)?, + ty: Box::new(self.fold_type(*t.ty)?), + size: Box::new(self.fold_uint_expression(*t.size)?), }) } @@ -311,8 +367,10 @@ pub trait ResultFolder<'ast, T: Field>: Sized { .into_iter() .map(|m| { let id = m.id; - self.fold_type(*m.ty) - .map(|ty| StructMember { ty: box ty, id }) + self.fold_type(*m.ty).map(|ty| StructMember { + ty: Box::new(ty), + id, + }) }) .collect::>()?, ..t @@ -338,8 +396,8 @@ pub trait ResultFolder<'ast, T: Field>: Sized { t: DeclarationArrayType<'ast, T>, ) -> Result, Self::Error> { Ok(DeclarationArrayType { - ty: box self.fold_declaration_type(*t.ty)?, - size: box self.fold_declaration_constant(*t.size)?, + ty: Box::new(self.fold_declaration_type(*t.ty)?), + size: Box::new(self.fold_declaration_constant(*t.size)?), }) } @@ -372,7 +430,10 @@ pub trait ResultFolder<'ast, T: Field>: Sized { .map(|m| { let id = m.id; self.fold_declaration_type(*m.ty) - .map(|ty| DeclarationStructMember { ty: box ty, id }) + .map(|ty| DeclarationStructMember { + ty: Box::new(ty), + id, + }) }) .collect::>()?, ..t @@ -386,6 +447,27 @@ pub trait ResultFolder<'ast, T: Field>: Sized { fold_assignee(self, a) } + fn fold_assembly_block( + &mut self, + s: AssemblyBlockStatement<'ast, T>, + ) -> Result>, Self::Error> { + fold_assembly_block(self, s) + } + + fn fold_assembly_assignment( + &mut self, + s: AssemblyAssignment<'ast, T>, + ) -> Result>, Self::Error> { + fold_assembly_assignment(self, s) + } + + fn fold_assembly_constraint( + &mut self, + s: AssemblyConstraint<'ast, T>, + ) -> Result>, Self::Error> { + fold_assembly_constraint(self, s) + } + fn fold_assembly_statement( &mut self, s: TypedAssemblyStatement<'ast, T>, @@ -393,6 +475,13 @@ pub trait ResultFolder<'ast, T: Field>: Sized { fold_assembly_statement(self, s) } + fn fold_assembly_statement_cases( + &mut self, + s: TypedAssemblyStatement<'ast, T>, + ) -> Result>, Self::Error> { + fold_assembly_statement_cases(self, s) + } + fn fold_statement( &mut self, s: TypedStatement<'ast, T>, @@ -400,6 +489,48 @@ pub trait ResultFolder<'ast, T: Field>: Sized { fold_statement(self, s) } + fn fold_statement_cases( + &mut self, + s: TypedStatement<'ast, T>, + ) -> Result>, Self::Error> { + fold_statement_cases(self, s) + } + + fn fold_definition_statement( + &mut self, + s: DefinitionStatement<'ast, T>, + ) -> Result>, Self::Error> { + fold_definition_statement(self, s) + } + + fn fold_return_statement( + &mut self, + s: ReturnStatement<'ast, T>, + ) -> Result>, Self::Error> { + fold_return_statement(self, s) + } + + fn fold_assertion_statement( + &mut self, + s: AssertionStatement<'ast, T>, + ) -> Result>, Self::Error> { + fold_assertion_statement(self, s) + } + + fn fold_log_statement( + &mut self, + s: LogStatement<'ast, T>, + ) -> Result>, Self::Error> { + fold_log_statement(self, s) + } + + fn fold_for_statement( + &mut self, + s: ForStatement<'ast, T>, + ) -> Result>, Self::Error> { + fold_for_statement(self, s) + } + fn fold_definition_rhs( &mut self, rhs: DefinitionRhs<'ast, T>, @@ -478,12 +609,28 @@ pub trait ResultFolder<'ast, T: Field>: Sized { ) -> Result, Self::Error> { fold_field_expression(self, e) } + + fn fold_field_expression_cases( + &mut self, + e: FieldElementExpression<'ast, T>, + ) -> Result, Self::Error> { + fold_field_expression_cases(self, e) + } + fn fold_boolean_expression( &mut self, e: BooleanExpression<'ast, T>, ) -> Result, Self::Error> { fold_boolean_expression(self, e) } + + fn fold_boolean_expression_cases( + &mut self, + e: BooleanExpression<'ast, T>, + ) -> Result, Self::Error> { + fold_boolean_expression_cases(self, e) + } + fn fold_uint_expression( &mut self, e: UExpression<'ast, T>, @@ -499,6 +646,14 @@ pub trait ResultFolder<'ast, T: Field>: Sized { fold_uint_expression_inner(self, bitwidth, e) } + fn fold_uint_expression_cases( + &mut self, + bitwidth: UBitwidth, + e: UExpressionInner<'ast, T>, + ) -> Result, Self::Error> { + fold_uint_expression_cases(self, bitwidth, e) + } + fn fold_array_expression_inner( &mut self, ty: &ArrayType<'ast, T>, @@ -506,6 +661,15 @@ pub trait ResultFolder<'ast, T: Field>: Sized { ) -> Result, Self::Error> { fold_array_expression_inner(self, ty, e) } + + fn fold_array_expression_cases( + &mut self, + ty: &ArrayType<'ast, T>, + e: ArrayExpressionInner<'ast, T>, + ) -> Result, Self::Error> { + fold_array_expression_cases(self, ty, e) + } + fn fold_struct_expression_inner( &mut self, ty: &StructType<'ast, T>, @@ -514,6 +678,14 @@ pub trait ResultFolder<'ast, T: Field>: Sized { fold_struct_expression_inner(self, ty, e) } + fn fold_struct_expression_cases( + &mut self, + ty: &StructType<'ast, T>, + e: StructExpressionInner<'ast, T>, + ) -> Result, Self::Error> { + fold_struct_expression_cases(self, ty, e) + } + fn fold_tuple_expression_inner( &mut self, ty: &TupleType<'ast, T>, @@ -521,71 +693,186 @@ pub trait ResultFolder<'ast, T: Field>: Sized { ) -> Result, Self::Error> { fold_tuple_expression_inner(self, ty, e) } + + fn fold_tuple_expression_cases( + &mut self, + ty: &TupleType<'ast, T>, + e: TupleExpressionInner<'ast, T>, + ) -> Result, Self::Error> { + fold_tuple_expression_cases(self, ty, e) + } + + fn fold_struct_value_expression( + &mut self, + ty: &StructType<'ast, T>, + v: StructValueExpression<'ast, T>, + ) -> Result< + ValueOrExpression, StructExpressionInner<'ast, T>>, + Self::Error, + > { + fold_struct_value_expression(self, ty, v) + } + + fn fold_array_value_expression( + &mut self, + ty: &ArrayType<'ast, T>, + v: ArrayValueExpression<'ast, T>, + ) -> Result< + ValueOrExpression, ArrayExpressionInner<'ast, T>>, + Self::Error, + > { + fold_array_value_expression(self, ty, v) + } + + fn fold_tuple_value_expression( + &mut self, + ty: &TupleType<'ast, T>, + v: TupleValueExpression<'ast, T>, + ) -> Result< + ValueOrExpression, TupleExpressionInner<'ast, T>>, + Self::Error, + > { + fold_tuple_value_expression(self, ty, v) + } } -pub fn fold_assembly_statement<'ast, T: Field, F: ResultFolder<'ast, T>>( +pub fn fold_statement_cases<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + s: TypedStatement<'ast, T>, +) -> Result>, F::Error> { + match s { + TypedStatement::Return(s) => f.fold_return_statement(s), + TypedStatement::Definition(s) => f.fold_definition_statement(s), + TypedStatement::Assertion(s) => f.fold_assertion_statement(s), + TypedStatement::For(s) => f.fold_for_statement(s), + TypedStatement::Log(s) => f.fold_log_statement(s), + TypedStatement::Assembly(s) => f.fold_assembly_block(s), + } +} + +pub fn fold_assembly_block<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + s: AssemblyBlockStatement<'ast, T>, +) -> Result>, F::Error> { + Ok(vec![TypedStatement::Assembly(AssemblyBlockStatement::new( + s.inner + .into_iter() + .map(|s| f.fold_assembly_statement(s)) + .collect::, _>>()? + .into_iter() + .flatten() + .collect(), + ))]) +} + +pub fn fold_assembly_assignment<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + s: AssemblyAssignment<'ast, T>, +) -> Result>, F::Error> { + let assignee = f.fold_assignee(s.assignee)?; + let expression = f.fold_expression(s.expression)?; + Ok(vec![TypedAssemblyStatement::assignment( + assignee, expression, + )]) +} + +pub fn fold_assembly_constraint<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + s: AssemblyConstraint<'ast, T>, +) -> Result>, F::Error> { + let left = f.fold_field_expression(s.left)?; + let right = f.fold_field_expression(s.right)?; + Ok(vec![TypedAssemblyStatement::constraint( + left, right, s.metadata, + )]) +} + +fn fold_assembly_statement<'ast, T: Field, F: ResultFolder<'ast, T>>( f: &mut F, s: TypedAssemblyStatement<'ast, T>, ) -> Result>, F::Error> { - Ok(match s { - TypedAssemblyStatement::Assignment(a, e) => { - vec![TypedAssemblyStatement::Assignment( - f.fold_assignee(a)?, - f.fold_expression(e)?, - )] - } - TypedAssemblyStatement::Constraint(lhs, rhs, metadata) => { - vec![TypedAssemblyStatement::Constraint( - f.fold_field_expression(lhs)?, - f.fold_field_expression(rhs)?, - metadata, - )] - } - }) + let span = s.get_span(); + f.fold_assembly_statement_cases(s) + .map(|s| s.into_iter().map(|s| s.span(span)).collect()) +} + +pub fn fold_assembly_statement_cases<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + s: TypedAssemblyStatement<'ast, T>, +) -> Result>, F::Error> { + match s { + TypedAssemblyStatement::Assignment(s) => f.fold_assembly_assignment(s), + TypedAssemblyStatement::Constraint(s) => f.fold_assembly_constraint(s), + } } pub fn fold_statement<'ast, T: Field, F: ResultFolder<'ast, T>>( f: &mut F, s: TypedStatement<'ast, T>, ) -> Result>, F::Error> { - let res = match s { - TypedStatement::Return(e) => TypedStatement::Return(f.fold_expression(e)?), - TypedStatement::Definition(a, e) => { - TypedStatement::Definition(f.fold_assignee(a)?, f.fold_definition_rhs(e)?) - } - TypedStatement::Assertion(e, error) => { - TypedStatement::Assertion(f.fold_boolean_expression(e)?, error) - } - TypedStatement::For(v, from, to, statements) => TypedStatement::For( - f.fold_variable(v)?, - f.fold_uint_expression(from)?, - f.fold_uint_expression(to)?, - statements - .into_iter() - .map(|s| f.fold_statement(s)) - .collect::, _>>()? - .into_iter() - .flatten() - .collect(), - ), - TypedStatement::Log(s, e) => TypedStatement::Log( - s, - e.into_iter() - .map(|e| f.fold_expression(e)) - .collect::, _>>()?, - ), - TypedStatement::Assembly(statements) => TypedStatement::Assembly( - statements - .into_iter() - .map(|s| f.fold_assembly_statement(s)) - .collect::, _>>()? - .into_iter() - .flatten() - .collect(), - ), - s => s, - }; - Ok(vec![res]) + let span = s.get_span(); + f.fold_statement_cases(s) + .map(|s| s.into_iter().map(|s| s.span(span)).collect()) +} + +pub fn fold_return_statement<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + s: ReturnStatement<'ast, T>, +) -> Result>, F::Error> { + Ok(vec![TypedStatement::Return(ReturnStatement::new( + f.fold_expression(s.inner)?, + ))]) +} + +pub fn fold_definition_statement<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + s: DefinitionStatement<'ast, T>, +) -> Result>, F::Error> { + let rhs = f.fold_definition_rhs(s.rhs)?; + Ok(vec![TypedStatement::Definition(DefinitionStatement::new( + f.fold_assignee(s.assignee)?, + rhs, + ))]) +} + +pub fn fold_assertion_statement<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + s: AssertionStatement<'ast, T>, +) -> Result>, F::Error> { + Ok(vec![TypedStatement::Assertion( + AssertionStatement::new(f.fold_boolean_expression(s.expression)?, s.error).span(s.span), + )]) +} + +pub fn fold_for_statement<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + s: ForStatement<'ast, T>, +) -> Result>, F::Error> { + Ok(vec![TypedStatement::For(ForStatement::new( + f.fold_variable(s.var)?, + f.fold_uint_expression(s.from)?, + f.fold_uint_expression(s.to)?, + s.statements + .into_iter() + .map(|s| f.fold_statement(s)) + .collect::, _>>()? + .into_iter() + .flatten() + .collect(), + ))]) +} + +pub fn fold_log_statement<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + s: LogStatement<'ast, T>, +) -> Result>, F::Error> { + Ok(vec![TypedStatement::Log(LogStatement::new( + s.format_string, + s.expressions + .into_iter() + .map(|e| f.fold_expression(e)) + .collect::>()?, + ))]) } pub fn fold_definition_rhs<'ast, T: Field, F: ResultFolder<'ast, T>>( @@ -612,7 +899,16 @@ pub fn fold_embed_call<'ast, T: Field, F: ResultFolder<'ast, T>>( }) } -pub fn fold_array_expression_inner<'ast, T: Field, F: ResultFolder<'ast, T>>( +fn fold_array_expression_inner<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + ty: &ArrayType<'ast, T>, + e: ArrayExpressionInner<'ast, T>, +) -> Result, F::Error> { + let span = e.get_span(); + f.fold_array_expression_cases(ty, e).map(|e| e.span(span)) +} + +pub fn fold_array_expression_cases<'ast, T: Field, F: ResultFolder<'ast, T>>( f: &mut F, ty: &ArrayType<'ast, T>, e: ArrayExpressionInner<'ast, T>, @@ -625,16 +921,14 @@ pub fn fold_array_expression_inner<'ast, T: Field, F: ResultFolder<'ast, T>>( IdentifierOrExpression::Identifier(i) => ArrayExpressionInner::Identifier(i), IdentifierOrExpression::Expression(u) => u, }, - Value(exprs) => Value( - exprs - .into_iter() - .map(|e| f.fold_expression_or_spread(e)) - .collect::>()?, - ), FunctionCall(function_call) => match f.fold_function_call_expression(ty, function_call)? { FunctionCallOrExpression::FunctionCall(c) => FunctionCall(c), FunctionCallOrExpression::Expression(u) => u, }, + Value(value) => match f.fold_array_value_expression(ty, value)? { + ValueOrExpression::Value(c) => Value(c), + ValueOrExpression::Expression(u) => u, + }, Conditional(c) => match f.fold_conditional_expression(ty, c)? { ConditionalOrExpression::Conditional(c) => Conditional(c), ConditionalOrExpression::Expression(u) => u, @@ -647,17 +941,14 @@ pub fn fold_array_expression_inner<'ast, T: Field, F: ResultFolder<'ast, T>>( SelectOrExpression::Select(m) => Select(m), SelectOrExpression::Expression(u) => u, }, - Slice(box array, box from, box to) => { - let array = f.fold_array_expression(array)?; - let from = f.fold_uint_expression(from)?; - let to = f.fold_uint_expression(to)?; - Slice(box array, box from, box to) - } - Repeat(box e, box count) => { - let e = f.fold_expression(e)?; - let count = f.fold_uint_expression(count)?; - Repeat(box e, box count) - } + Slice(s) => match f.fold_slice_expression(s)? { + SliceOrExpression::Slice(m) => Slice(m), + SliceOrExpression::Expression(u) => u, + }, + Repeat(s) => match f.fold_repeat_expression(s)? { + RepeatOrExpression::Repeat(m) => Repeat(m), + RepeatOrExpression::Expression(u) => u, + }, Element(element) => match f.fold_element_expression(ty, element)? { ElementOrExpression::Element(m) => Element(m), ElementOrExpression::Expression(u) => u, @@ -672,18 +963,78 @@ pub fn fold_assignee<'ast, T: Field, F: ResultFolder<'ast, T>>( ) -> Result, F::Error> { match a { TypedAssignee::Identifier(v) => Ok(TypedAssignee::Identifier(f.fold_variable(v)?)), - TypedAssignee::Select(box a, box index) => Ok(TypedAssignee::Select( - box f.fold_assignee(a)?, - box f.fold_uint_expression(index)?, + TypedAssignee::Select(a, index) => Ok(TypedAssignee::Select( + Box::new(f.fold_assignee(*a)?), + Box::new(f.fold_uint_expression(*index)?), + )), + TypedAssignee::Member(s, m) => Ok(TypedAssignee::Member(Box::new(f.fold_assignee(*s)?), m)), + TypedAssignee::Element(s, index) => Ok(TypedAssignee::Element( + Box::new(f.fold_assignee(*s)?), + index, )), - TypedAssignee::Member(box s, m) => Ok(TypedAssignee::Member(box f.fold_assignee(s)?, m)), - TypedAssignee::Element(box s, index) => { - Ok(TypedAssignee::Element(box f.fold_assignee(s)?, index)) - } } } -pub fn fold_struct_expression_inner<'ast, T: Field, F: ResultFolder<'ast, T>>( +pub fn fold_struct_value_expression<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + _: &StructType<'ast, T>, + a: StructValueExpression<'ast, T>, +) -> Result< + ValueOrExpression, StructExpressionInner<'ast, T>>, + F::Error, +> { + Ok(ValueOrExpression::Value(StructValueExpression { + value: a + .value + .into_iter() + .map(|v| f.fold_expression(v)) + .collect::, _>>()?, + ..a + })) +} + +pub fn fold_array_value_expression<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + _: &ArrayType<'ast, T>, + a: ArrayValueExpression<'ast, T>, +) -> Result, ArrayExpressionInner<'ast, T>>, F::Error> +{ + Ok(ValueOrExpression::Value(ArrayValueExpression { + value: a + .value + .into_iter() + .map(|v| f.fold_expression_or_spread(v)) + .collect::, _>>()?, + ..a + })) +} + +pub fn fold_tuple_value_expression<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + _: &TupleType<'ast, T>, + a: TupleValueExpression<'ast, T>, +) -> Result, TupleExpressionInner<'ast, T>>, F::Error> +{ + Ok(ValueOrExpression::Value(TupleValueExpression { + value: a + .value + .into_iter() + .map(|v| f.fold_expression(v)) + .collect::, _>>()?, + ..a + })) +} + +fn fold_struct_expression_inner<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + ty: &StructType<'ast, T>, + e: StructExpressionInner<'ast, T>, +) -> Result, F::Error> { + let span = e.get_span(); + f.fold_struct_expression_cases(ty, e).map(|e| e.span(span)) +} + +pub fn fold_struct_expression_cases<'ast, T: Field, F: ResultFolder<'ast, T>>( f: &mut F, ty: &StructType<'ast, T>, e: StructExpressionInner<'ast, T>, @@ -696,12 +1047,10 @@ pub fn fold_struct_expression_inner<'ast, T: Field, F: ResultFolder<'ast, T>>( IdentifierOrExpression::Expression(u) => u, }, Block(block) => Block(f.fold_block_expression(block)?), - Value(exprs) => Value( - exprs - .into_iter() - .map(|e| f.fold_expression(e)) - .collect::>()?, - ), + Value(value) => match f.fold_struct_value_expression(ty, value)? { + ValueOrExpression::Value(c) => Value(c), + ValueOrExpression::Expression(u) => u, + }, FunctionCall(function_call) => match f.fold_function_call_expression(ty, function_call)? { FunctionCallOrExpression::FunctionCall(c) => FunctionCall(c), FunctionCallOrExpression::Expression(u) => u, @@ -726,7 +1075,16 @@ pub fn fold_struct_expression_inner<'ast, T: Field, F: ResultFolder<'ast, T>>( Ok(e) } -pub fn fold_tuple_expression_inner<'ast, T: Field, F: ResultFolder<'ast, T>>( +fn fold_tuple_expression_inner<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + ty: &TupleType<'ast, T>, + e: TupleExpressionInner<'ast, T>, +) -> Result, F::Error> { + let span = e.get_span(); + f.fold_tuple_expression_cases(ty, e).map(|e| e.span(span)) +} + +pub fn fold_tuple_expression_cases<'ast, T: Field, F: ResultFolder<'ast, T>>( f: &mut F, ty: &TupleType<'ast, T>, e: TupleExpressionInner<'ast, T>, @@ -739,12 +1097,10 @@ pub fn fold_tuple_expression_inner<'ast, T: Field, F: ResultFolder<'ast, T>>( IdentifierOrExpression::Identifier(i) => Identifier(i), IdentifierOrExpression::Expression(u) => u, }, - Value(exprs) => Value( - exprs - .into_iter() - .map(|e| f.fold_expression(e)) - .collect::>()?, - ), + Value(value) => match f.fold_tuple_value_expression(ty, value)? { + ValueOrExpression::Value(c) => Value(c), + ValueOrExpression::Expression(u) => u, + }, FunctionCall(function_call) => match f.fold_function_call_expression(ty, function_call)? { FunctionCallOrExpression::FunctionCall(c) => FunctionCall(c), FunctionCallOrExpression::Expression(u) => u, @@ -769,7 +1125,15 @@ pub fn fold_tuple_expression_inner<'ast, T: Field, F: ResultFolder<'ast, T>>( Ok(e) } -pub fn fold_field_expression<'ast, T: Field, F: ResultFolder<'ast, T>>( +fn fold_field_expression<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + e: FieldElementExpression<'ast, T>, +) -> Result, F::Error> { + let span = e.get_span(); + f.fold_field_expression_cases(e).map(|e| e.span(span)) +} + +pub fn fold_field_expression_cases<'ast, T: Field, F: ResultFolder<'ast, T>>( f: &mut F, e: FieldElementExpression<'ast, T>, ) -> Result, F::Error> { @@ -781,72 +1145,55 @@ pub fn fold_field_expression<'ast, T: Field, F: ResultFolder<'ast, T>>( IdentifierOrExpression::Expression(u) => u, }, Block(block) => Block(f.fold_block_expression(block)?), - Number(n) => Number(n), - Add(box e1, box e2) => { - let e1 = f.fold_field_expression(e1)?; - let e2 = f.fold_field_expression(e2)?; - Add(box e1, box e2) - } - Sub(box e1, box e2) => { - let e1 = f.fold_field_expression(e1)?; - let e2 = f.fold_field_expression(e2)?; - Sub(box e1, box e2) - } - Mult(box e1, box e2) => { - let e1 = f.fold_field_expression(e1)?; - let e2 = f.fold_field_expression(e2)?; - Mult(box e1, box e2) - } - Div(box e1, box e2) => { - let e1 = f.fold_field_expression(e1)?; - let e2 = f.fold_field_expression(e2)?; - Div(box e1, box e2) - } - Pow(box e1, box e2) => { - let e1 = f.fold_field_expression(e1)?; - let e2 = f.fold_uint_expression(e2)?; - Pow(box e1, box e2) - } - Neg(box e) => { - let e = f.fold_field_expression(e)?; - - Neg(box e) - } - Pos(box e) => { - let e = f.fold_field_expression(e)?; - - Pos(box e) - } - And(box left, box right) => { - let left = f.fold_field_expression(left)?; - let right = f.fold_field_expression(right)?; - - And(box left, box right) - } - Or(box left, box right) => { - let left = f.fold_field_expression(left)?; - let right = f.fold_field_expression(right)?; - - Or(box left, box right) - } - Xor(box left, box right) => { - let left = f.fold_field_expression(left)?; - let right = f.fold_field_expression(right)?; - - Xor(box left, box right) - } - LeftShift(box e, box by) => { - let e = f.fold_field_expression(e)?; - let by = f.fold_uint_expression(by)?; - - LeftShift(box e, box by) - } - RightShift(box e, box by) => { - let e = f.fold_field_expression(e)?; - let by = f.fold_uint_expression(by)?; - - RightShift(box e, box by) - } + Value(n) => Value(n), + Add(e) => match f.fold_binary_expression(&Type::FieldElement, e)? { + BinaryOrExpression::Binary(e) => Add(e), + BinaryOrExpression::Expression(u) => u, + }, + Sub(e) => match f.fold_binary_expression(&Type::FieldElement, e)? { + BinaryOrExpression::Binary(e) => Sub(e), + BinaryOrExpression::Expression(u) => u, + }, + Mult(e) => match f.fold_binary_expression(&Type::FieldElement, e)? { + BinaryOrExpression::Binary(e) => Mult(e), + BinaryOrExpression::Expression(u) => u, + }, + Div(e) => match f.fold_binary_expression(&Type::FieldElement, e)? { + BinaryOrExpression::Binary(e) => Div(e), + BinaryOrExpression::Expression(u) => u, + }, + Pow(e) => match f.fold_binary_expression(&Type::FieldElement, e)? { + BinaryOrExpression::Binary(e) => Pow(e), + BinaryOrExpression::Expression(u) => u, + }, + And(e) => match f.fold_binary_expression(&Type::FieldElement, e)? { + BinaryOrExpression::Binary(e) => And(e), + BinaryOrExpression::Expression(u) => u, + }, + Or(e) => match f.fold_binary_expression(&Type::FieldElement, e)? { + BinaryOrExpression::Binary(e) => Or(e), + BinaryOrExpression::Expression(u) => u, + }, + Xor(e) => match f.fold_binary_expression(&Type::FieldElement, e)? { + BinaryOrExpression::Binary(e) => Xor(e), + BinaryOrExpression::Expression(u) => u, + }, + LeftShift(e) => match f.fold_binary_expression(&Type::FieldElement, e)? { + BinaryOrExpression::Binary(e) => LeftShift(e), + BinaryOrExpression::Expression(u) => u, + }, + RightShift(e) => match f.fold_binary_expression(&Type::FieldElement, e)? { + BinaryOrExpression::Binary(e) => RightShift(e), + BinaryOrExpression::Expression(u) => u, + }, + Neg(e) => match f.fold_unary_expression(&Type::FieldElement, e)? { + UnaryOrExpression::Unary(e) => Neg(e), + UnaryOrExpression::Expression(u) => u, + }, + Pos(e) => match f.fold_unary_expression(&Type::FieldElement, e)? { + UnaryOrExpression::Unary(e) => Pos(e), + UnaryOrExpression::Expression(u) => u, + }, Conditional(c) => match f.fold_conditional_expression(&Type::FieldElement, c)? { ConditionalOrExpression::Conditional(c) => Conditional(c), ConditionalOrExpression::Expression(u) => u, @@ -880,12 +1227,17 @@ pub fn fold_int_expression<'ast, T: Field, F: ResultFolder<'ast, T>>( unreachable!() } -pub fn fold_block_expression<'ast, T: Field, E: ResultFold<'ast, T>, F: ResultFolder<'ast, T>>( +pub fn fold_block_expression< + 'ast, + T: Field, + E: ResultFold, + F: ResultFolder<'ast, T>, +>( f: &mut F, block: BlockExpression<'ast, T, E>, ) -> Result, F::Error> { - Ok(BlockExpression { - statements: block + Ok(BlockExpression::new( + block .statements .into_iter() .map(|s| f.fold_statement(s)) @@ -893,8 +1245,9 @@ pub fn fold_block_expression<'ast, T: Field, E: ResultFold<'ast, T>, F: ResultFo .into_iter() .flatten() .collect(), - value: box block.value.fold(f)?, - }) + block.value.fold(f)?, + ) + .span(block.span)) } pub fn fold_conditional_expression< @@ -903,7 +1256,7 @@ pub fn fold_conditional_expression< E: Expr<'ast, T> + Conditional<'ast, T> + PartialEq - + ResultFold<'ast, T> + + ResultFold + From>, F: ResultFolder<'ast, T>, >( @@ -917,7 +1270,44 @@ pub fn fold_conditional_expression< e.consequence.fold(f)?, e.alternative.fold(f)?, e.kind, - ), + ) + .span(e.span), + )) +} + +#[allow(clippy::type_complexity)] +pub fn fold_binary_expression< + 'ast, + T: Field, + L: Expr<'ast, T> + PartialEq + ResultFold + From>, + R: Expr<'ast, T> + PartialEq + ResultFold + From>, + E: Expr<'ast, T> + PartialEq + ResultFold + From>, + F: ResultFolder<'ast, T>, + Op: OperatorStr, +>( + f: &mut F, + _: &E::Ty, + e: BinaryExpression, +) -> Result, F::Error> { + Ok(BinaryOrExpression::Binary( + BinaryExpression::new(e.left.fold(f)?, e.right.fold(f)?).span(e.span), + )) +} + +pub fn fold_unary_expression< + 'ast, + T: Field, + In: Expr<'ast, T> + PartialEq + ResultFold + From>, + E: Expr<'ast, T> + PartialEq + ResultFold + From>, + F: ResultFolder<'ast, T>, + Op, +>( + f: &mut F, + _: &E::Ty, + e: UnaryExpression, +) -> Result, F::Error> { + Ok(UnaryOrExpression::Unary( + UnaryExpression::new(e.inner.fold(f)?).span(e.span), )) } @@ -931,9 +1321,29 @@ pub fn fold_member_expression< _: &E::Ty, e: MemberExpression<'ast, T, E>, ) -> Result, F::Error> { - Ok(MemberOrExpression::Member(MemberExpression::new( - f.fold_struct_expression(*e.struc)?, - e.id, + Ok(MemberOrExpression::Member( + MemberExpression::new(f.fold_struct_expression(*e.struc)?, e.id).span(e.span), + )) +} + +pub fn fold_slice_expression<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + e: SliceExpression<'ast, T>, +) -> Result, F::Error> { + Ok(SliceOrExpression::Slice(SliceExpression::new( + f.fold_array_expression(*e.array)?, + f.fold_uint_expression(*e.from)?, + f.fold_uint_expression(*e.to)?, + ))) +} + +pub fn fold_repeat_expression<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + e: RepeatExpression<'ast, T>, +) -> Result, F::Error> { + Ok(RepeatOrExpression::Repeat(RepeatExpression::new( + f.fold_expression(*e.e)?, + f.fold_uint_expression(*e.count)?, ))) } @@ -948,20 +1358,10 @@ pub fn fold_identifier_expression< e: IdentifierExpression<'ast, E>, ) -> Result, F::Error> { Ok(IdentifierOrExpression::Identifier( - IdentifierExpression::new(f.fold_name(e.id)?), + IdentifierExpression::new(f.fold_name(e.id)?).span(e.span), )) } -pub fn fold_eq_expression<'ast, T: Field, E: ResultFold<'ast, T>, F: ResultFolder<'ast, T>>( - f: &mut F, - e: EqExpression, -) -> Result, F::Error> { - Ok(EqOrBoolean::Eq(EqExpression::new( - e.left.fold(f)?, - e.right.fold(f)?, - ))) -} - pub fn fold_select_expression< 'ast, T: Field, @@ -975,10 +1375,13 @@ pub fn fold_select_expression< _: &E::Ty, e: SelectExpression<'ast, T, E>, ) -> Result, F::Error> { - Ok(SelectOrExpression::Select(SelectExpression::new( - f.fold_array_expression(*e.array)?, - f.fold_uint_expression(*e.index)?, - ))) + Ok(SelectOrExpression::Select( + SelectExpression::new( + f.fold_array_expression(*e.array)?, + f.fold_uint_expression(*e.index)?, + ) + .span(e.span), + )) } pub fn fold_element_expression< @@ -991,10 +1394,9 @@ pub fn fold_element_expression< _: &E::Ty, e: ElementExpression<'ast, T, E>, ) -> Result, F::Error> { - Ok(ElementOrExpression::Element(ElementExpression::new( - f.fold_tuple_expression(*e.tuple)?, - e.index, - ))) + Ok(ElementOrExpression::Element( + ElementExpression::new(f.fold_tuple_expression(*e.tuple)?, e.index).span(e.span), + )) } pub fn fold_function_call_expression< @@ -1007,20 +1409,31 @@ pub fn fold_function_call_expression< _: &E::Ty, e: FunctionCallExpression<'ast, T, E>, ) -> Result, F::Error> { - Ok(FunctionCallOrExpression::Expression(E::function_call( - f.fold_declaration_function_key(e.function_key)?, - e.generics - .into_iter() - .map(|g| g.map(|g| f.fold_uint_expression(g)).transpose()) - .collect::>()?, - e.arguments - .into_iter() - .map(|e| f.fold_expression(e)) - .collect::>()?, - ))) + Ok(FunctionCallOrExpression::Expression( + E::function_call( + f.fold_declaration_function_key(e.function_key)?, + e.generics + .into_iter() + .map(|g| g.map(|g| f.fold_uint_expression(g)).transpose()) + .collect::>()?, + e.arguments + .into_iter() + .map(|e| f.fold_expression(e)) + .collect::>()?, + ) + .span(e.span), + )) } -pub fn fold_boolean_expression<'ast, T: Field, F: ResultFolder<'ast, T>>( +fn fold_boolean_expression<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + e: BooleanExpression<'ast, T>, +) -> Result, F::Error> { + let span = e.get_span(); + f.fold_boolean_expression_cases(e).map(|e| e.span(span)) +} + +pub fn fold_boolean_expression_cases<'ast, T: Field, F: ResultFolder<'ast, T>>( f: &mut F, e: BooleanExpression<'ast, T>, ) -> Result, F::Error> { @@ -1034,83 +1447,57 @@ pub fn fold_boolean_expression<'ast, T: Field, F: ResultFolder<'ast, T>>( Block(block) => Block(f.fold_block_expression(block)?), Value(v) => Value(v), FieldEq(e) => match f.fold_eq_expression(e)? { - EqOrBoolean::Eq(e) => FieldEq(e), - EqOrBoolean::Boolean(u) => u, + BinaryOrExpression::Binary(e) => FieldEq(e), + BinaryOrExpression::Expression(u) => u, }, BoolEq(e) => match f.fold_eq_expression(e)? { - EqOrBoolean::Eq(e) => BoolEq(e), - EqOrBoolean::Boolean(u) => u, + BinaryOrExpression::Binary(e) => BoolEq(e), + BinaryOrExpression::Expression(u) => u, }, ArrayEq(e) => match f.fold_eq_expression(e)? { - EqOrBoolean::Eq(e) => ArrayEq(e), - EqOrBoolean::Boolean(u) => u, + BinaryOrExpression::Binary(e) => ArrayEq(e), + BinaryOrExpression::Expression(u) => u, }, StructEq(e) => match f.fold_eq_expression(e)? { - EqOrBoolean::Eq(e) => StructEq(e), - EqOrBoolean::Boolean(u) => u, + BinaryOrExpression::Binary(e) => StructEq(e), + BinaryOrExpression::Expression(u) => u, }, TupleEq(e) => match f.fold_eq_expression(e)? { - EqOrBoolean::Eq(e) => TupleEq(e), - EqOrBoolean::Boolean(u) => u, + BinaryOrExpression::Binary(e) => TupleEq(e), + BinaryOrExpression::Expression(u) => u, }, UintEq(e) => match f.fold_eq_expression(e)? { - EqOrBoolean::Eq(e) => UintEq(e), - EqOrBoolean::Boolean(u) => u, + BinaryOrExpression::Binary(e) => UintEq(e), + BinaryOrExpression::Expression(u) => u, + }, + FieldLt(e) => match f.fold_binary_expression(&Type::Boolean, e)? { + BinaryOrExpression::Binary(e) => FieldLt(e), + BinaryOrExpression::Expression(u) => u, + }, + FieldLe(e) => match f.fold_binary_expression(&Type::Boolean, e)? { + BinaryOrExpression::Binary(e) => FieldLe(e), + BinaryOrExpression::Expression(u) => u, + }, + UintLt(e) => match f.fold_binary_expression(&Type::Boolean, e)? { + BinaryOrExpression::Binary(e) => UintLt(e), + BinaryOrExpression::Expression(u) => u, + }, + UintLe(e) => match f.fold_binary_expression(&Type::Boolean, e)? { + BinaryOrExpression::Binary(e) => UintLe(e), + BinaryOrExpression::Expression(u) => u, + }, + Or(e) => match f.fold_binary_expression(&Type::Boolean, e)? { + BinaryOrExpression::Binary(e) => Or(e), + BinaryOrExpression::Expression(u) => u, + }, + And(e) => match f.fold_binary_expression(&Type::Boolean, e)? { + BinaryOrExpression::Binary(e) => And(e), + BinaryOrExpression::Expression(u) => u, + }, + Not(e) => match f.fold_unary_expression(&Type::Boolean, e)? { + UnaryOrExpression::Unary(e) => Not(e), + UnaryOrExpression::Expression(u) => u, }, - FieldLt(box e1, box e2) => { - let e1 = f.fold_field_expression(e1)?; - let e2 = f.fold_field_expression(e2)?; - FieldLt(box e1, box e2) - } - FieldLe(box e1, box e2) => { - let e1 = f.fold_field_expression(e1)?; - let e2 = f.fold_field_expression(e2)?; - FieldLe(box e1, box e2) - } - FieldGt(box e1, box e2) => { - let e1 = f.fold_field_expression(e1)?; - let e2 = f.fold_field_expression(e2)?; - FieldGt(box e1, box e2) - } - FieldGe(box e1, box e2) => { - let e1 = f.fold_field_expression(e1)?; - let e2 = f.fold_field_expression(e2)?; - FieldGe(box e1, box e2) - } - UintLt(box e1, box e2) => { - let e1 = f.fold_uint_expression(e1)?; - let e2 = f.fold_uint_expression(e2)?; - UintLt(box e1, box e2) - } - UintLe(box e1, box e2) => { - let e1 = f.fold_uint_expression(e1)?; - let e2 = f.fold_uint_expression(e2)?; - UintLe(box e1, box e2) - } - UintGt(box e1, box e2) => { - let e1 = f.fold_uint_expression(e1)?; - let e2 = f.fold_uint_expression(e2)?; - UintGt(box e1, box e2) - } - UintGe(box e1, box e2) => { - let e1 = f.fold_uint_expression(e1)?; - let e2 = f.fold_uint_expression(e2)?; - UintGe(box e1, box e2) - } - Or(box e1, box e2) => { - let e1 = f.fold_boolean_expression(e1)?; - let e2 = f.fold_boolean_expression(e2)?; - Or(box e1, box e2) - } - And(box e1, box e2) => { - let e1 = f.fold_boolean_expression(e1)?; - let e2 = f.fold_boolean_expression(e2)?; - And(box e1, box e2) - } - Not(box e) => { - let e = f.fold_boolean_expression(e)?; - Not(box e) - } FunctionCall(function_call) => { match f.fold_function_call_expression(&Type::Boolean, function_call)? { FunctionCallOrExpression::FunctionCall(c) => FunctionCall(c), @@ -1134,6 +1521,7 @@ pub fn fold_boolean_expression<'ast, T: Field, F: ResultFolder<'ast, T>>( ElementOrExpression::Expression(u) => u, }, }; + Ok(e) } @@ -1147,7 +1535,16 @@ pub fn fold_uint_expression<'ast, T: Field, F: ResultFolder<'ast, T>>( }) } -pub fn fold_uint_expression_inner<'ast, T: Field, F: ResultFolder<'ast, T>>( +fn fold_uint_expression_inner<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + ty: UBitwidth, + e: UExpressionInner<'ast, T>, +) -> Result, F::Error> { + let span = e.get_span(); + f.fold_uint_expression_cases(ty, e).map(|e| e.span(span)) +} + +pub fn fold_uint_expression_cases<'ast, T: Field, F: ResultFolder<'ast, T>>( f: &mut F, ty: UBitwidth, e: UExpressionInner<'ast, T>, @@ -1161,87 +1558,62 @@ pub fn fold_uint_expression_inner<'ast, T: Field, F: ResultFolder<'ast, T>>( }, Block(block) => Block(f.fold_block_expression(block)?), Value(v) => Value(v), - Add(box left, box right) => { - let left = f.fold_uint_expression(left)?; - let right = f.fold_uint_expression(right)?; - - Add(box left, box right) - } - Sub(box left, box right) => { - let left = f.fold_uint_expression(left)?; - let right = f.fold_uint_expression(right)?; - - Sub(box left, box right) - } - FloorSub(box left, box right) => { - let left = f.fold_uint_expression(left)?; - let right = f.fold_uint_expression(right)?; - - FloorSub(box left, box right) - } - Mult(box left, box right) => { - let left = f.fold_uint_expression(left)?; - let right = f.fold_uint_expression(right)?; - - Mult(box left, box right) - } - Div(box left, box right) => { - let left = f.fold_uint_expression(left)?; - let right = f.fold_uint_expression(right)?; - - Div(box left, box right) - } - Rem(box left, box right) => { - let left = f.fold_uint_expression(left)?; - let right = f.fold_uint_expression(right)?; - - Rem(box left, box right) - } - Xor(box left, box right) => { - let left = f.fold_uint_expression(left)?; - let right = f.fold_uint_expression(right)?; - - Xor(box left, box right) - } - And(box left, box right) => { - let left = f.fold_uint_expression(left)?; - let right = f.fold_uint_expression(right)?; - - And(box left, box right) - } - Or(box left, box right) => { - let left = f.fold_uint_expression(left)?; - let right = f.fold_uint_expression(right)?; - - Or(box left, box right) - } - LeftShift(box e, box by) => { - let e = f.fold_uint_expression(e)?; - let by = f.fold_uint_expression(by)?; - - LeftShift(box e, box by) - } - RightShift(box e, box by) => { - let e = f.fold_uint_expression(e)?; - let by = f.fold_uint_expression(by)?; - - RightShift(box e, box by) - } - Not(box e) => { - let e = f.fold_uint_expression(e)?; - - Not(box e) - } - Neg(box e) => { - let e = f.fold_uint_expression(e)?; - - Neg(box e) - } - Pos(box e) => { - let e = f.fold_uint_expression(e)?; - - Pos(box e) - } + Add(e) => match f.fold_binary_expression(&ty, e)? { + BinaryOrExpression::Binary(e) => Add(e), + BinaryOrExpression::Expression(u) => u, + }, + Sub(e) => match f.fold_binary_expression(&ty, e)? { + BinaryOrExpression::Binary(e) => Sub(e), + BinaryOrExpression::Expression(u) => u, + }, + FloorSub(e) => match f.fold_binary_expression(&ty, e)? { + BinaryOrExpression::Binary(e) => FloorSub(e), + BinaryOrExpression::Expression(u) => u, + }, + Mult(e) => match f.fold_binary_expression(&ty, e)? { + BinaryOrExpression::Binary(e) => Mult(e), + BinaryOrExpression::Expression(u) => u, + }, + Div(e) => match f.fold_binary_expression(&ty, e)? { + BinaryOrExpression::Binary(e) => Div(e), + BinaryOrExpression::Expression(u) => u, + }, + Rem(e) => match f.fold_binary_expression(&ty, e)? { + BinaryOrExpression::Binary(e) => Rem(e), + BinaryOrExpression::Expression(u) => u, + }, + Xor(e) => match f.fold_binary_expression(&ty, e)? { + BinaryOrExpression::Binary(e) => Xor(e), + BinaryOrExpression::Expression(u) => u, + }, + And(e) => match f.fold_binary_expression(&ty, e)? { + BinaryOrExpression::Binary(e) => And(e), + BinaryOrExpression::Expression(u) => u, + }, + Or(e) => match f.fold_binary_expression(&ty, e)? { + BinaryOrExpression::Binary(e) => Or(e), + BinaryOrExpression::Expression(u) => u, + }, + LeftShift(e) => match f.fold_binary_expression(&ty, e)? { + BinaryOrExpression::Binary(e) => LeftShift(e), + BinaryOrExpression::Expression(u) => u, + }, + RightShift(e) => match f.fold_binary_expression(&ty, e)? { + BinaryOrExpression::Binary(e) => RightShift(e), + BinaryOrExpression::Expression(u) => u, + }, + Pos(e) => match f.fold_unary_expression(&ty, e)? { + UnaryOrExpression::Unary(e) => Pos(e), + UnaryOrExpression::Expression(u) => u, + }, + Neg(e) => match f.fold_unary_expression(&ty, e)? { + UnaryOrExpression::Unary(e) => Neg(e), + UnaryOrExpression::Expression(u) => u, + }, + Not(e) => match f.fold_unary_expression(&ty, e)? { + UnaryOrExpression::Unary(e) => Not(e), + UnaryOrExpression::Expression(u) => u, + }, FunctionCall(function_call) => { match f.fold_function_call_expression(&ty, function_call)? { FunctionCallOrExpression::FunctionCall(c) => FunctionCall(c), @@ -1265,6 +1637,7 @@ pub fn fold_uint_expression_inner<'ast, T: Field, F: ResultFolder<'ast, T>>( ElementOrExpression::Expression(u) => u, }, }; + Ok(e) } @@ -1316,7 +1689,7 @@ pub fn fold_signature<'ast, T: Field, F: ResultFolder<'ast, T>>( .into_iter() .map(|o| f.fold_declaration_type(o)) .collect::>()?, - output: box f.fold_declaration_type(*s.output)?, + output: Box::new(f.fold_declaration_type(*s.output)?), }) } @@ -1358,7 +1731,7 @@ pub fn fold_array_expression<'ast, T: Field, F: ResultFolder<'ast, T>>( Ok(ArrayExpression { inner: f.fold_array_expression_inner(&ty, e.inner)?, - ty: box ty, + ty: Box::new(ty), }) } @@ -1480,5 +1853,6 @@ pub fn fold_program<'ast, T: Field, F: ResultFolder<'ast, T>>( f.fold_module(module).map(|m| (module_id, m)) }) .collect::>()?, + ..p }) } diff --git a/zokrates_ast/src/typed/types.rs b/zokrates_ast/src/typed/types.rs index a453fef3f..614880c12 100644 --- a/zokrates_ast/src/typed/types.rs +++ b/zokrates_ast/src/typed/types.rs @@ -1,5 +1,6 @@ +use crate::common::expressions::ValueExpression; use crate::typed::{ - CoreIdentifier, Identifier, OwnedTypedModuleId, TypedExpression, UExpression, UExpressionInner, + CoreIdentifier, Identifier, OwnedModuleId, TypedExpression, UExpression, UExpressionInner, }; use crate::typed::{TryFrom, TryInto}; use serde::{de::Error, ser::SerializeMap, Deserialize, Deserializer, Serialize, Serializer}; @@ -125,7 +126,7 @@ pub type ConstantIdentifier<'ast> = &'ast str; #[derive(Clone, PartialEq, Eq, Debug, Hash, PartialOrd, Ord, Serialize, Deserialize)] pub struct CanonicalConstantIdentifier<'ast> { - pub module: OwnedTypedModuleId, + pub module: OwnedModuleId, #[serde(borrow)] pub id: ConstantIdentifier<'ast>, } @@ -137,7 +138,7 @@ impl<'ast> fmt::Display for CanonicalConstantIdentifier<'ast> { } impl<'ast> CanonicalConstantIdentifier<'ast> { - pub fn new(id: ConstantIdentifier<'ast>, module: OwnedTypedModuleId) -> Self { + pub fn new(id: ConstantIdentifier<'ast>, module: OwnedModuleId) -> Self { CanonicalConstantIdentifier { module, id } } } @@ -188,7 +189,7 @@ impl<'ast, T: PartialEq> PartialEq> for DeclarationConstant inner: UExpressionInner::Value(v), .. }, - ) => *c == *v as u32, + ) => *c == v.value as u32, (DeclarationConstant::Expression(TypedExpression::Uint(e0)), e1) => e0 == e1, (DeclarationConstant::Expression(..), _) => false, // type error _ => true, @@ -233,7 +234,7 @@ impl<'ast, T: fmt::Display> fmt::Display for DeclarationConstant<'ast, T> { impl<'ast, T> From for UExpression<'ast, T> { fn from(i: u32) -> Self { - UExpressionInner::Value(i as u128).annotate(UBitwidth::B32) + UExpressionInner::Value(ValueExpression::new(i as u128)).annotate(UBitwidth::B32) } } @@ -241,13 +242,14 @@ impl<'ast, T: Field> From> for UExpression<'ast, T> fn from(c: DeclarationConstant<'ast, T>) -> Self { match c { DeclarationConstant::Generic(g) => { - UExpression::identifier(CoreIdentifier::from(g).into()).annotate(UBitwidth::B32) + UExpression::identifier(Identifier::from(CoreIdentifier::from(g))) + .annotate(UBitwidth::B32) } DeclarationConstant::Concrete(v) => { - UExpressionInner::Value(v as u128).annotate(UBitwidth::B32) + UExpression::value(v as u128).annotate(UBitwidth::B32) } DeclarationConstant::Constant(v) => { - UExpression::identifier(CoreIdentifier::from(v).into()).annotate(UBitwidth::B32) + UExpression::identifier(FrameIdentifier::from(v).into()).annotate(UBitwidth::B32) } DeclarationConstant::Expression(e) => e.try_into().unwrap(), } @@ -261,7 +263,7 @@ impl<'ast, T> TryInto for UExpression<'ast, T> { assert_eq!(self.bitwidth, UBitwidth::B32); match self.into_inner() { - UExpressionInner::Value(v) => Ok(v as u32), + UExpressionInner::Value(v) => Ok(v.value as u32), _ => Err(SpecializationError), } } @@ -280,7 +282,7 @@ impl<'ast, T> TryInto for DeclarationConstant<'ast, T> { pub type MemberId = String; -#[allow(clippy::derive_hash_xor_eq)] +#[allow(clippy::derived_hash_with_manual_eq)] #[derive(Debug, Clone, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord)] pub struct GStructMember { #[serde(rename = "name")] @@ -304,7 +306,7 @@ fn try_from_g_struct_member, U>( ) -> Result, SpecializationError> { Ok(GStructMember { id: t.id, - ty: box try_from_g_type(*t.ty)?, + ty: Box::new(try_from_g_type(*t.ty)?), }) } @@ -322,7 +324,7 @@ impl<'ast, T> From for StructMember<'ast, T> { } } -#[allow(clippy::derive_hash_xor_eq)] +#[allow(clippy::derived_hash_with_manual_eq)] #[derive(Clone, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord, Debug)] pub struct GArrayType { pub size: Box, @@ -370,8 +372,8 @@ fn try_from_g_array_type, U>( t: GArrayType, ) -> Result, SpecializationError> { Ok(GArrayType { - size: box (*t.size).try_into().map_err(|_| SpecializationError)?, - ty: box try_from_g_type(*t.ty)?, + size: Box::new((*t.size).try_into().map_err(|_| SpecializationError)?), + ty: Box::new(try_from_g_type(*t.ty)?), }) } @@ -389,7 +391,7 @@ impl<'ast, T> From for ArrayType<'ast, T> { } } -#[allow(clippy::derive_hash_xor_eq)] +#[allow(clippy::derived_hash_with_manual_eq)] #[derive(Clone, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord, Debug)] pub struct GTupleType { pub elements: Vec>, @@ -468,6 +470,42 @@ impl TryFrom> for GTupleType { } } +impl TryFrom> for GStructType { + type Error = (); + + fn try_from(t: GType) -> Result { + if let GType::Struct(t) = t { + Ok(t) + } else { + Err(()) + } + } +} + +impl TryFrom> for GArrayType { + type Error = (); + + fn try_from(t: GType) -> Result { + if let GType::Array(t) = t { + Ok(t) + } else { + Err(()) + } + } +} + +impl TryFrom> for UBitwidth { + type Error = (); + + fn try_from(t: GType) -> Result { + if let GType::Uint(t) = t { + Ok(t) + } else { + Err(()) + } + } +} + #[derive(Debug, Clone, Hash, Serialize, Deserialize, PartialOrd, Ord, Eq, PartialEq)] pub struct StructLocation { #[serde(skip)] @@ -641,7 +679,7 @@ impl fmt::Display for UBitwidth { } } -#[allow(clippy::derive_hash_xor_eq)] +#[allow(clippy::derived_hash_with_manual_eq)] #[derive(Clone, Eq, Hash, PartialOrd, Ord, Debug)] pub enum GType { FieldElement, @@ -819,8 +857,8 @@ impl<'ast, T> From for DeclarationType<'ast, T> { impl> From<(GType, U)> for GArrayType { fn from(tup: (GType, U)) -> Self { GArrayType { - ty: box tup.0, - size: box tup.1.into(), + ty: Box::new(tup.0), + size: Box::new(tup.1.into()), } } } @@ -828,8 +866,8 @@ impl> From<(GType, U)> for GArrayType { impl GArrayType { pub fn new>(ty: GType, size: U) -> Self { GArrayType { - ty: box ty, - size: box size.into(), + ty: Box::new(ty), + size: Box::new(size.into()), } } } @@ -904,6 +942,23 @@ impl GType { } } +impl GType { + pub fn is_composite_of_field(&self) -> bool { + match self { + GType::Array(array_type) => array_type.ty.is_composite_of_field(), + GType::Tuple(tuple_typle) => tuple_typle + .elements + .iter() + .all(|e| e.is_composite_of_field()), + GType::Struct(struct_type) => struct_type + .members + .iter() + .all(|m| m.ty.is_composite_of_field()), + other => other.eq(&Self::FieldElement), + } + } +} + impl<'ast, T: fmt::Display + PartialEq + fmt::Debug> Type<'ast, T> { pub fn can_be_specialized_to(&self, other: &DeclarationType<'ast, T>) -> bool { use self::GType::*; @@ -919,7 +974,7 @@ impl<'ast, T: fmt::Display + PartialEq + fmt::Debug> Type<'ast, T> { match (&l.size.as_inner(), &*r.size) { // compare the sizes for concrete ones (UExpressionInner::Value(v), DeclarationConstant::Concrete(c)) => { - (*v as u32) == *c + (v.value as u32) == *c } _ => true, } @@ -967,7 +1022,7 @@ pub type FunctionIdentifier<'ast> = &'ast str; #[derive(PartialEq, Eq, Hash, Debug, Clone, PartialOrd, Ord)] pub struct GFunctionKey<'ast, S> { - pub module: OwnedTypedModuleId, + pub module: OwnedModuleId, pub id: FunctionIdentifier<'ast>, pub signature: GSignature, } @@ -1045,7 +1100,7 @@ impl<'ast, T> From> for DeclarationFunctionKey<'ast, T } impl<'ast, S> GFunctionKey<'ast, S> { - pub fn with_location, U: Into>>( + pub fn with_location, U: Into>>( module: T, id: U, ) -> Self { @@ -1066,7 +1121,7 @@ impl<'ast, S> GFunctionKey<'ast, S> { self } - pub fn module>(mut self, module: T) -> Self { + pub fn module>(mut self, module: T) -> Self { self.module = module.into(); self } @@ -1099,7 +1154,7 @@ pub fn check_generic<'ast, T, S: Clone + PartialEq + PartialEq>( DeclarationConstant::Constant(..) => true, DeclarationConstant::Expression(e) => match e { TypedExpression::Uint(e) => match e.as_inner() { - UExpressionInner::Value(v) => *value == *v as u32, + UExpressionInner::Value(v) => *value == v.value as u32, _ => true, }, _ => unreachable!(), @@ -1144,8 +1199,7 @@ pub fn check_type<'ast, T, S: Clone + PartialEq + PartialEq>( impl<'ast, T: Field> From> for UExpression<'ast, T> { fn from(c: CanonicalConstantIdentifier<'ast>) -> Self { - UExpression::identifier(Identifier::from(CoreIdentifier::Constant(c))) - .annotate(UBitwidth::B32) + UExpression::identifier(Identifier::from(FrameIdentifier::from(c))).annotate(UBitwidth::B32) } } @@ -1207,8 +1261,12 @@ pub fn specialize_declaration_type< .into_iter() .map(|m| { let id = m.id; - specialize_declaration_type(*m.ty, &inside_generics) - .map(|ty| GStructMember { ty: box ty, id }) + specialize_declaration_type(*m.ty, &inside_generics).map(|ty| { + GStructMember { + ty: Box::new(ty), + id, + } + }) }) .collect::>()?, generics: s0 @@ -1230,7 +1288,8 @@ pub use self::signature::{ try_from_g_signature, ConcreteSignature, DeclarationSignature, GSignature, Signature, }; -use super::{Id, ShadowedIdentifier}; +use super::identifier::FrameIdentifier; +use super::{Expr, Id, ShadowedIdentifier}; pub mod signature { use super::*; @@ -1248,7 +1307,7 @@ pub mod signature { Self { generics: vec![], inputs: vec![], - output: box GType::Tuple(GTupleType::new(vec![])), + output: Box::new(GType::Tuple(GTupleType::new(vec![]))), } } } @@ -1397,7 +1456,7 @@ pub mod signature { .into_iter() .map(try_from_g_type) .collect::>()?, - output: box try_from_g_type(*t.output)?, + output: Box::new(try_from_g_type(*t.output)?), }) } diff --git a/zokrates_ast/src/typed/uint.rs b/zokrates_ast/src/typed/uint.rs index c2120fc6f..a04550a4c 100644 --- a/zokrates_ast/src/typed/uint.rs +++ b/zokrates_ast/src/typed/uint.rs @@ -1,5 +1,5 @@ -use crate::typed::types::UBitwidth; use crate::typed::*; +use crate::{common::expressions::UValueExpression, typed::types::UBitwidth}; use std::ops::{Add, Div, Mul, Neg, Not, Rem, Sub}; use zokrates_field::Field; @@ -12,10 +12,12 @@ impl<'ast, T> Add for UExpression<'ast, T> { let bitwidth = self.bitwidth; assert_eq!(bitwidth, other.bitwidth); + // we apply a basic simplification here which enables more precise comparison of array sizes during semantic checking + // this could be done by the caller by calling propagation, but it is deemed simple enough to be done here match (self.as_inner(), other.as_inner()) { - (UExpressionInner::Value(0), _) => other, - (_, UExpressionInner::Value(0)) => self, - _ => UExpressionInner::Add(box self, box other).annotate(bitwidth), + (UExpressionInner::Value(v), _) if v.value == 0 => other, + (_, UExpressionInner::Value(v)) if v.value == 0 => self, + _ => UExpressionInner::Add(BinaryExpression::new(self, other)).annotate(bitwidth), } } } @@ -26,7 +28,7 @@ impl<'ast, T> Sub for UExpression<'ast, T> { fn sub(self, other: Self) -> UExpression<'ast, T> { let bitwidth = self.bitwidth; assert_eq!(bitwidth, other.bitwidth); - UExpressionInner::Sub(box self, box other).annotate(bitwidth) + UExpressionInner::Sub(BinaryExpression::new(self, other)).annotate(bitwidth) } } @@ -36,7 +38,7 @@ impl<'ast, T> Mul for UExpression<'ast, T> { fn mul(self, other: Self) -> UExpression<'ast, T> { let bitwidth = self.bitwidth; assert_eq!(bitwidth, other.bitwidth); - UExpressionInner::Mult(box self, box other).annotate(bitwidth) + UExpressionInner::Mult(BinaryExpression::new(self, other)).annotate(bitwidth) } } @@ -46,7 +48,7 @@ impl<'ast, T> Div for UExpression<'ast, T> { fn div(self, other: Self) -> UExpression<'ast, T> { let bitwidth = self.bitwidth; assert_eq!(bitwidth, other.bitwidth); - UExpressionInner::Div(box self, box other).annotate(bitwidth) + UExpressionInner::Div(BinaryExpression::new(self, other)).annotate(bitwidth) } } @@ -56,7 +58,7 @@ impl<'ast, T> Rem for UExpression<'ast, T> { fn rem(self, other: Self) -> UExpression<'ast, T> { let bitwidth = self.bitwidth; assert_eq!(bitwidth, other.bitwidth); - UExpressionInner::Rem(box self, box other).annotate(bitwidth) + UExpressionInner::Rem(BinaryExpression::new(self, other)).annotate(bitwidth) } } @@ -65,7 +67,7 @@ impl<'ast, T> Not for UExpression<'ast, T> { fn not(self) -> UExpression<'ast, T> { let bitwidth = self.bitwidth; - UExpressionInner::Not(box self).annotate(bitwidth) + UExpressionInner::Not(UnaryExpression::new(self)).annotate(bitwidth) } } @@ -74,7 +76,7 @@ impl<'ast, T> Neg for UExpression<'ast, T> { fn neg(self) -> UExpression<'ast, T> { let bitwidth = self.bitwidth; - UExpressionInner::Neg(box self).annotate(bitwidth) + UExpressionInner::Neg(UnaryExpression::new(self)).annotate(bitwidth) } } @@ -82,48 +84,48 @@ impl<'ast, T: Field> UExpression<'ast, T> { pub fn xor(self, other: Self) -> UExpression<'ast, T> { let bitwidth = self.bitwidth; assert_eq!(bitwidth, other.bitwidth); - UExpressionInner::Xor(box self, box other).annotate(bitwidth) + UExpressionInner::Xor(BinaryExpression::new(self, other)).annotate(bitwidth) } pub fn or(self, other: Self) -> UExpression<'ast, T> { let bitwidth = self.bitwidth; assert_eq!(bitwidth, other.bitwidth); - UExpressionInner::Or(box self, box other).annotate(bitwidth) + UExpressionInner::Or(BinaryExpression::new(self, other)).annotate(bitwidth) } pub fn and(self, other: Self) -> UExpression<'ast, T> { let bitwidth = self.bitwidth; assert_eq!(bitwidth, other.bitwidth); - UExpressionInner::And(box self, box other).annotate(bitwidth) + UExpressionInner::And(BinaryExpression::new(self, other)).annotate(bitwidth) } pub fn pos(self) -> UExpression<'ast, T> { let bitwidth = self.bitwidth; - UExpressionInner::Pos(box self).annotate(bitwidth) + UExpressionInner::Pos(UnaryExpression::new(self)).annotate(bitwidth) } pub fn left_shift(self, by: UExpression<'ast, T>) -> UExpression<'ast, T> { let bitwidth = self.bitwidth; assert_eq!(by.bitwidth, UBitwidth::B32); - UExpressionInner::LeftShift(box self, box by).annotate(bitwidth) + UExpressionInner::LeftShift(BinaryExpression::new(self, by)).annotate(bitwidth) } pub fn right_shift(self, by: UExpression<'ast, T>) -> UExpression<'ast, T> { let bitwidth = self.bitwidth; assert_eq!(by.bitwidth, UBitwidth::B32); - UExpressionInner::RightShift(box self, box by).annotate(bitwidth) + UExpressionInner::RightShift(BinaryExpression::new(self, by)).annotate(bitwidth) } pub fn floor_sub(self, other: Self) -> UExpression<'ast, T> { let bitwidth = self.bitwidth; assert_eq!(bitwidth, other.bitwidth); - UExpressionInner::FloorSub(box self, box other).annotate(bitwidth) + UExpressionInner::FloorSub(BinaryExpression::new(self, other)).annotate(bitwidth) } } -impl<'ast, T: Field> From for UExpressionInner<'ast, T> { +impl<'ast, T> From for UExpressionInner<'ast, T> { fn from(e: u128) -> Self { - UExpressionInner::Value(e) + UExpressionInner::Value(ValueExpression::new(e)) } } @@ -142,20 +144,20 @@ pub struct UExpression<'ast, T> { impl<'ast, T> From for UExpression<'ast, T> { fn from(u: u16) -> Self { - UExpressionInner::Value(u as u128).annotate(UBitwidth::B16) + UExpressionInner::Value(ValueExpression::new(u as u128)).annotate(UBitwidth::B16) } } impl<'ast, T> From for UExpression<'ast, T> { fn from(u: u8) -> Self { - UExpressionInner::Value(u as u128).annotate(UBitwidth::B8) + UExpressionInner::Value(ValueExpression::new(u as u128)).annotate(UBitwidth::B8) } } impl<'ast, T> PartialEq for UExpression<'ast, T> { fn eq(&self, other: &u32) -> bool { match self.as_inner() { - UExpressionInner::Value(v) => *v == *other as u128, + UExpressionInner::Value(v) => v.value == *other as u128, _ => true, } } @@ -165,22 +167,33 @@ impl<'ast, T> PartialEq for UExpression<'ast, T> { pub enum UExpressionInner<'ast, T> { Block(BlockExpression<'ast, T, UExpression<'ast, T>>), Identifier(IdentifierExpression<'ast, UExpression<'ast, T>>), - Value(u128), - Add(Box>, Box>), - Sub(Box>, Box>), - FloorSub(Box>, Box>), - Mult(Box>, Box>), - Div(Box>, Box>), - Rem(Box>, Box>), - Xor(Box>, Box>), - And(Box>, Box>), - Or(Box>, Box>), - Not(Box>), - Neg(Box>), - Pos(Box>), + Value(UValueExpression), + Add(BinaryExpression, UExpression<'ast, T>, UExpression<'ast, T>>), + Sub(BinaryExpression, UExpression<'ast, T>, UExpression<'ast, T>>), + FloorSub( + BinaryExpression< + OpFloorSub, + UExpression<'ast, T>, + UExpression<'ast, T>, + UExpression<'ast, T>, + >, + ), + Mult(BinaryExpression, UExpression<'ast, T>, UExpression<'ast, T>>), + Div(BinaryExpression, UExpression<'ast, T>, UExpression<'ast, T>>), + Rem(BinaryExpression, UExpression<'ast, T>, UExpression<'ast, T>>), + Xor(BinaryExpression, UExpression<'ast, T>, UExpression<'ast, T>>), + And(BinaryExpression, UExpression<'ast, T>, UExpression<'ast, T>>), + Or(BinaryExpression, UExpression<'ast, T>, UExpression<'ast, T>>), + Not(UnaryExpression, UExpression<'ast, T>>), + Neg(UnaryExpression, UExpression<'ast, T>>), + Pos(UnaryExpression, UExpression<'ast, T>>), FunctionCall(FunctionCallExpression<'ast, T, UExpression<'ast, T>>), - LeftShift(Box>, Box>), - RightShift(Box>, Box>), + LeftShift( + BinaryExpression, UExpression<'ast, T>, UExpression<'ast, T>>, + ), + RightShift( + BinaryExpression, UExpression<'ast, T>, UExpression<'ast, T>>, + ), Conditional(ConditionalExpression<'ast, T, UExpression<'ast, T>>), Member(MemberExpression<'ast, T, UExpression<'ast, T>>), Select(SelectExpression<'ast, T, UExpression<'ast, T>>), diff --git a/zokrates_ast/src/typed/utils/mod.rs b/zokrates_ast/src/typed/utils/mod.rs index 6ec6885c2..ad2c406f0 100644 --- a/zokrates_ast/src/typed/utils/mod.rs +++ b/zokrates_ast/src/typed/utils/mod.rs @@ -1,13 +1,13 @@ use super::{ - ArrayExpression, ArrayExpressionInner, ArrayValue, BooleanExpression, Conditional, - ConditionalKind, Expr, FieldElementExpression, Id, Identifier, Select, Typed, TypedExpression, - TypedExpressionOrSpread, UBitwidth, UExpression, UExpressionInner, + ArrayExpression, ArrayExpressionInner, BooleanExpression, Conditional, ConditionalKind, Expr, + FieldElementExpression, GArrayType, Id, Identifier, Select, Typed, TypedExpression, + TypedExpressionOrSpread, UBitwidth, UExpression, ValueExpression, }; use zokrates_field::Field; pub fn f<'ast, T, U: TryInto>(v: U) -> FieldElementExpression<'ast, T> { - FieldElementExpression::Number(v.try_into().map_err(|_| ()).unwrap()) + FieldElementExpression::Value(ValueExpression::new(v.try_into().map_err(|_| ()).unwrap())) } pub fn a_id<'ast, T: Field, I: TryInto>>(v: I) -> ArrayExpressionInner<'ast, T> { @@ -16,24 +16,26 @@ pub fn a_id<'ast, T: Field, I: TryInto>>(v: I) -> ArrayExpressi pub fn a< 'ast, - T, + T: Field, E: Typed<'ast, T> + Expr<'ast, T> + Into>, const N: usize, >( values: [E; N], ) -> ArrayExpression<'ast, T> { let ty = values[0].get_type(); - ArrayExpressionInner::Value(ArrayValue( + + let array_ty = GArrayType::new(ty, N as u32); + ArrayExpression::value( values .into_iter() .map(|e| TypedExpressionOrSpread::Expression(e.into())) .collect(), - )) - .annotate(ty, N as u32) + ) + .annotate(array_ty) } -pub fn u_32<'ast, T, U: TryInto>(v: U) -> UExpression<'ast, T> { - UExpressionInner::Value(v.try_into().map_err(|_| ()).unwrap() as u128).annotate(UBitwidth::B32) +pub fn u_32<'ast, T: Field, U: TryInto>(v: U) -> UExpression<'ast, T> { + UExpression::value(v.try_into().map_err(|_| ()).unwrap() as u128).annotate(UBitwidth::B32) } pub fn conditional<'ast, T, E: Conditional<'ast, T>>( diff --git a/zokrates_ast/src/typed/variable.rs b/zokrates_ast/src/typed/variable.rs index d47d48728..0ad50061c 100644 --- a/zokrates_ast/src/typed/variable.rs +++ b/zokrates_ast/src/typed/variable.rs @@ -1,17 +1,11 @@ +use crate::common::WithSpan; use crate::typed::types::{DeclarationConstant, GStructType, UBitwidth}; use crate::typed::types::{GType, SpecializationError}; use crate::typed::Identifier; use crate::typed::UExpression; use crate::typed::{TryFrom, TryInto}; -use std::fmt; - -#[derive(Clone, PartialEq, Hash, Eq, PartialOrd, Ord, Debug)] -pub struct GVariable<'ast, S> { - pub id: Identifier<'ast>, - pub _type: GType, - pub is_mutable: bool, -} +pub type GVariable<'ast, S> = crate::common::Variable, GType>; pub type DeclarationVariable<'ast, T> = GVariable<'ast, DeclarationConstant<'ast, T>>; pub type ConcreteVariable<'ast> = GVariable<'ast, u32>; pub type Variable<'ast, T> = GVariable<'ast, UExpression<'ast, T>>; @@ -20,84 +14,56 @@ impl<'ast, T> TryFrom> for ConcreteVariable<'ast> { type Error = SpecializationError; fn try_from(v: Variable<'ast, T>) -> Result { - let _type = v._type.try_into()?; + let span = v.get_span(); - Ok(Self { - _type, - id: v.id, - is_mutable: v.is_mutable, - }) + let ty = v.ty.try_into()?; + + Ok(Self::new(v.id, ty).span(span)) } } impl<'ast, T> From> for Variable<'ast, T> { fn from(v: ConcreteVariable<'ast>) -> Self { - let _type = v._type.into(); + let span = v.get_span(); + + let ty = v.ty.into(); - Self { - _type, - id: v.id, - is_mutable: v.is_mutable, - } + Self::new(v.id, ty).span(span) } } pub fn try_from_g_variable, U>( v: GVariable, ) -> Result, SpecializationError> { - let _type = crate::typed::types::try_from_g_type(v._type)?; + let span = v.get_span(); - Ok(GVariable { - _type, - id: v.id, - is_mutable: v.is_mutable, - }) + let ty = crate::typed::types::try_from_g_type(v.ty)?; + + Ok(GVariable::new(v.id, ty).span(span)) } impl<'ast, S: Clone> GVariable<'ast, S> { pub fn field_element>>(id: I) -> Self { - Self::immutable(id, GType::FieldElement) + Self::new(id, GType::FieldElement) } pub fn boolean>>(id: I) -> Self { - Self::immutable(id, GType::Boolean) + Self::new(id, GType::Boolean) } pub fn uint>, W: Into>(id: I, bitwidth: W) -> Self { - Self::immutable(id, GType::uint(bitwidth)) + Self::new(id, GType::uint(bitwidth)) } pub fn array>, U: Into>(id: I, ty: GType, size: U) -> Self { - Self::immutable(id, GType::array((ty, size.into()))) + Self::new(id, GType::array((ty, size.into()))) } pub fn struc>>(id: I, ty: GStructType) -> Self { - Self::immutable(id, GType::Struct(ty)) - } - - pub fn immutable>>(id: I, _type: GType) -> Self { - Self::new(id, _type, false) - } - - pub fn mutable>>(id: I, _type: GType) -> Self { - Self::new(id, _type, true) - } - - pub fn new>>(id: I, _type: GType, is_mutable: bool) -> Self { - GVariable { - id: id.into(), - _type, - is_mutable, - } + Self::new(id, GType::Struct(ty)) } pub fn get_type(&self) -> GType { - self._type.clone() - } -} - -impl<'ast, S: fmt::Display> fmt::Display for GVariable<'ast, S> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{} {}", self._type, self.id,) + self.ty.clone() } } diff --git a/zokrates_ast/src/untyped/from_ast.rs b/zokrates_ast/src/untyped/from_ast.rs index 88c12d6ce..ff37ce6ba 100644 --- a/zokrates_ast/src/untyped/from_ast.rs +++ b/zokrates_ast/src/untyped/from_ast.rs @@ -31,13 +31,13 @@ fn import_directive_to_symbol_vec( source, id: untyped::SymbolIdentifier::from(id).alias(alias), } - .span(span.clone()); + .span(span); vec![untyped::SymbolDeclaration { id: alias.unwrap_or(id), symbol: untyped::Symbol::Here(untyped::SymbolDefinition::Import(import)), } - .span(span.clone())] + .span(span)] } pest::ImportDirective::From(import) => { let span = import.span; @@ -57,13 +57,13 @@ fn import_directive_to_symbol_vec( id: untyped::SymbolIdentifier::from(symbol.id.span.as_str()) .alias(Some(alias)), } - .span(span.clone()); + .span(span); untyped::SymbolDeclaration { id: alias, symbol: untyped::Symbol::Here(untyped::SymbolDefinition::Import(import)), } - .span(span.clone()) + .span(span) }) .collect() } @@ -90,7 +90,7 @@ impl<'ast> From> for untyped::SymbolDeclarationNode .map(untyped::StructDefinitionFieldNode::from) .collect(), } - .span(span.clone()); + .span(span); untyped::SymbolDeclaration { id, @@ -125,7 +125,7 @@ impl<'ast> From> for untyped::SymbolDeclarationNo ty: definition.id.ty.into(), expression: definition.expression.into(), } - .span(span.clone()); + .span(span); untyped::SymbolDeclaration { id, @@ -150,7 +150,7 @@ impl<'ast> From> for untyped::SymbolDeclarationNode<' .collect(), ty: definition.ty.into(), } - .span(span.clone()); + .span(span); untyped::SymbolDeclaration { id, @@ -199,7 +199,7 @@ impl<'ast> From> for untyped::SymbolDeclarationNo statements: function.statements.into_iter().map(|s| s.into()).collect(), signature, } - .span(span.clone()); + .span(span); untyped::SymbolDeclaration { id, @@ -296,14 +296,14 @@ impl<'ast> From> for untyped::StatementNode<'ast untyped::UnresolvedTypeNode::from(i.ty), i.mutable.is_some(), ) - .span(i.span.clone()), + .span(i.span), e, ), pest::TypedIdentifierOrAssignee::Assignee(a) => { untyped::Statement::Assignment(untyped::AssigneeNode::from(a), e) } } - .span(definition.span.clone()) + .span(definition.span) } } @@ -390,85 +390,85 @@ impl<'ast> From> for untyped::ExpressionNode<'ast> use crate::untyped::NodeValue; match expression.op { pest::BinaryOperator::Add => untyped::Expression::Add( - box untyped::ExpressionNode::from(*expression.left), - box untyped::ExpressionNode::from(*expression.right), + Box::new(untyped::ExpressionNode::from(*expression.left)), + Box::new(untyped::ExpressionNode::from(*expression.right)), ), pest::BinaryOperator::Sub => untyped::Expression::Sub( - box untyped::ExpressionNode::from(*expression.left), - box untyped::ExpressionNode::from(*expression.right), + Box::new(untyped::ExpressionNode::from(*expression.left)), + Box::new(untyped::ExpressionNode::from(*expression.right)), ), pest::BinaryOperator::Mul => untyped::Expression::Mult( - box untyped::ExpressionNode::from(*expression.left), - box untyped::ExpressionNode::from(*expression.right), + Box::new(untyped::ExpressionNode::from(*expression.left)), + Box::new(untyped::ExpressionNode::from(*expression.right)), ), pest::BinaryOperator::Div => untyped::Expression::Div( - box untyped::ExpressionNode::from(*expression.left), - box untyped::ExpressionNode::from(*expression.right), + Box::new(untyped::ExpressionNode::from(*expression.left)), + Box::new(untyped::ExpressionNode::from(*expression.right)), ), pest::BinaryOperator::Rem => untyped::Expression::Rem( - box untyped::ExpressionNode::from(*expression.left), - box untyped::ExpressionNode::from(*expression.right), + Box::new(untyped::ExpressionNode::from(*expression.left)), + Box::new(untyped::ExpressionNode::from(*expression.right)), ), pest::BinaryOperator::Eq => untyped::Expression::Eq( - box untyped::ExpressionNode::from(*expression.left), - box untyped::ExpressionNode::from(*expression.right), + Box::new(untyped::ExpressionNode::from(*expression.left)), + Box::new(untyped::ExpressionNode::from(*expression.right)), ), pest::BinaryOperator::Lt => untyped::Expression::Lt( - box untyped::ExpressionNode::from(*expression.left), - box untyped::ExpressionNode::from(*expression.right), + Box::new(untyped::ExpressionNode::from(*expression.left)), + Box::new(untyped::ExpressionNode::from(*expression.right)), ), pest::BinaryOperator::Lte => untyped::Expression::Le( - box untyped::ExpressionNode::from(*expression.left), - box untyped::ExpressionNode::from(*expression.right), + Box::new(untyped::ExpressionNode::from(*expression.left)), + Box::new(untyped::ExpressionNode::from(*expression.right)), ), pest::BinaryOperator::Gt => untyped::Expression::Gt( - box untyped::ExpressionNode::from(*expression.left), - box untyped::ExpressionNode::from(*expression.right), + Box::new(untyped::ExpressionNode::from(*expression.left)), + Box::new(untyped::ExpressionNode::from(*expression.right)), ), pest::BinaryOperator::Gte => untyped::Expression::Ge( - box untyped::ExpressionNode::from(*expression.left), - box untyped::ExpressionNode::from(*expression.right), + Box::new(untyped::ExpressionNode::from(*expression.left)), + Box::new(untyped::ExpressionNode::from(*expression.right)), ), pest::BinaryOperator::And => untyped::Expression::And( - box untyped::ExpressionNode::from(*expression.left), - box untyped::ExpressionNode::from(*expression.right), + Box::new(untyped::ExpressionNode::from(*expression.left)), + Box::new(untyped::ExpressionNode::from(*expression.right)), ), pest::BinaryOperator::Or => untyped::Expression::Or( - box untyped::ExpressionNode::from(*expression.left), - box untyped::ExpressionNode::from(*expression.right), + Box::new(untyped::ExpressionNode::from(*expression.left)), + Box::new(untyped::ExpressionNode::from(*expression.right)), ), pest::BinaryOperator::Pow => untyped::Expression::Pow( - box untyped::ExpressionNode::from(*expression.left), - box untyped::ExpressionNode::from(*expression.right), + Box::new(untyped::ExpressionNode::from(*expression.left)), + Box::new(untyped::ExpressionNode::from(*expression.right)), ), pest::BinaryOperator::BitXor => untyped::Expression::BitXor( - box untyped::ExpressionNode::from(*expression.left), - box untyped::ExpressionNode::from(*expression.right), + Box::new(untyped::ExpressionNode::from(*expression.left)), + Box::new(untyped::ExpressionNode::from(*expression.right)), ), pest::BinaryOperator::LeftShift => untyped::Expression::LeftShift( - box untyped::ExpressionNode::from(*expression.left), - box untyped::ExpressionNode::from(*expression.right), + Box::new(untyped::ExpressionNode::from(*expression.left)), + Box::new(untyped::ExpressionNode::from(*expression.right)), ), pest::BinaryOperator::RightShift => untyped::Expression::RightShift( - box untyped::ExpressionNode::from(*expression.left), - box untyped::ExpressionNode::from(*expression.right), + Box::new(untyped::ExpressionNode::from(*expression.left)), + Box::new(untyped::ExpressionNode::from(*expression.right)), ), pest::BinaryOperator::BitAnd => untyped::Expression::BitAnd( - box untyped::ExpressionNode::from(*expression.left), - box untyped::ExpressionNode::from(*expression.right), + Box::new(untyped::ExpressionNode::from(*expression.left)), + Box::new(untyped::ExpressionNode::from(*expression.right)), ), pest::BinaryOperator::BitOr => untyped::Expression::BitOr( - box untyped::ExpressionNode::from(*expression.left), - box untyped::ExpressionNode::from(*expression.right), + Box::new(untyped::ExpressionNode::from(*expression.left)), + Box::new(untyped::ExpressionNode::from(*expression.right)), ), // rewrite (a != b)` as `!(a == b)` - pest::BinaryOperator::NotEq => untyped::Expression::Not( - box untyped::Expression::Eq( - box untyped::ExpressionNode::from(*expression.left), - box untyped::ExpressionNode::from(*expression.right), + pest::BinaryOperator::NotEq => untyped::Expression::Not(Box::new( + untyped::Expression::Eq( + Box::new(untyped::ExpressionNode::from(*expression.left)), + Box::new(untyped::ExpressionNode::from(*expression.right)), ) - .span(expression.span.clone()), - ), + .span(expression.span), + )), } .span(expression.span) } @@ -477,22 +477,22 @@ impl<'ast> From> for untyped::ExpressionNode<'ast> impl<'ast> From> for untyped::ExpressionNode<'ast> { fn from(expression: pest::IfElseExpression<'ast>) -> untyped::ExpressionNode<'ast> { use crate::untyped::NodeValue; - untyped::Expression::Conditional(box ConditionalExpression { - condition: box untyped::ExpressionNode::from(*expression.condition), + untyped::Expression::Conditional(Box::new(ConditionalExpression { + condition: Box::new(untyped::ExpressionNode::from(*expression.condition)), consequence_statements: expression .consequence_statements .into_iter() .map(untyped::StatementNode::from) .collect(), - consequence: box untyped::ExpressionNode::from(*expression.consequence), + consequence: Box::new(untyped::ExpressionNode::from(*expression.consequence)), alternative_statements: expression .alternative_statements .into_iter() .map(untyped::StatementNode::from) .collect(), - alternative: box untyped::ExpressionNode::from(*expression.alternative), + alternative: Box::new(untyped::ExpressionNode::from(*expression.alternative)), kind: untyped::ConditionalKind::IfElse, - }) + })) .span(expression.span) } } @@ -500,14 +500,14 @@ impl<'ast> From> for untyped::ExpressionNode<'ast> impl<'ast> From> for untyped::ExpressionNode<'ast> { fn from(expression: pest::TernaryExpression<'ast>) -> untyped::ExpressionNode<'ast> { use crate::untyped::NodeValue; - untyped::Expression::Conditional(box ConditionalExpression { - condition: box untyped::ExpressionNode::from(*expression.condition), + untyped::Expression::Conditional(Box::new(ConditionalExpression { + condition: Box::new(untyped::ExpressionNode::from(*expression.condition)), consequence_statements: vec![], - consequence: box untyped::ExpressionNode::from(*expression.consequence), + consequence: Box::new(untyped::ExpressionNode::from(*expression.consequence)), alternative_statements: vec![], - alternative: box untyped::ExpressionNode::from(*expression.alternative), + alternative: Box::new(untyped::ExpressionNode::from(*expression.alternative)), kind: untyped::ConditionalKind::Ternary, - }) + })) .span(expression.span) } } @@ -617,7 +617,8 @@ impl<'ast> From> for untyped::ExpressionN let value = untyped::ExpressionNode::from(*initializer.value); let count = untyped::ExpressionNode::from(*initializer.count); - untyped::Expression::ArrayInitializer(box value, box count).span(initializer.span) + untyped::Expression::ArrayInitializer(Box::new(value), Box::new(count)) + .span(initializer.span) } } @@ -674,18 +675,20 @@ impl<'ast> From> for untyped::ExpressionNode<'ast> ) .span(a.span), pest::Access::Select(a) => untyped::Expression::Select( - box acc, - box untyped::RangeOrExpression::from(a.expression), + Box::new(acc), + Box::new(untyped::RangeOrExpression::from(a.expression)), ) .span(a.span), pest::Access::Dot(m) => match m.inner { pest::IdentifierOrDecimal::Identifier(id) => { - untyped::Expression::Member(box acc, box id.span.as_str()).span(m.span) - } - pest::IdentifierOrDecimal::Decimal(id) => { - untyped::Expression::Element(box acc, id.span.as_str().parse().unwrap()) + untyped::Expression::Member(Box::new(acc), Box::new(id.span.as_str())) .span(m.span) } + pest::IdentifierOrDecimal::Decimal(id) => untyped::Expression::Element( + Box::new(acc), + id.span.as_str().parse().unwrap(), + ) + .span(m.span), }, }) } @@ -783,19 +786,19 @@ impl<'ast> From> for untyped::AssigneeNode<'ast> { assignee.accesses.into_iter().fold(a, |acc, s| { match s { pest::AssigneeAccess::Select(s) => untyped::Assignee::Select( - box acc, - box untyped::RangeOrExpression::from(s.expression), + Box::new(acc), + Box::new(untyped::RangeOrExpression::from(s.expression)), ), pest::AssigneeAccess::Dot(a) => match a.inner { pest::IdentifierOrDecimal::Identifier(id) => { - untyped::Assignee::Member(box acc, box id.span.as_str()) + untyped::Assignee::Member(Box::new(acc), Box::new(id.span.as_str())) } pest::IdentifierOrDecimal::Decimal(id) => { - untyped::Assignee::Element(box acc, id.span.as_str().parse().unwrap()) + untyped::Assignee::Element(Box::new(acc), id.span.as_str().parse().unwrap()) } }, } - .span(span.clone()) + .span(span) }) } } @@ -861,10 +864,10 @@ impl<'ast> From> for untyped::UnresolvedTypeNode<'ast> { .rev() .fold(None, |acc, s| match acc { None => Some(UnresolvedType::array(inner_type.clone(), s)), - Some(acc) => Some(UnresolvedType::array(acc.span(span.clone()), s)), + Some(acc) => Some(UnresolvedType::array(acc.span(span), s)), }) .unwrap() - .span(span.clone()) + .span(span) } pest::Type::Struct(s) => UnresolvedType::User( s.id.span.as_str().to_string(), @@ -1032,29 +1035,33 @@ mod tests { ( "field[2]", untyped::UnresolvedType::Array( - box untyped::UnresolvedType::FieldElement.mock(), + Box::new(untyped::UnresolvedType::FieldElement.mock()), untyped::Expression::IntConstant(2usize.into()).mock(), ), ), ( "field[2][3]", untyped::UnresolvedType::Array( - box untyped::UnresolvedType::Array( - box untyped::UnresolvedType::FieldElement.mock(), - untyped::Expression::IntConstant(3usize.into()).mock(), - ) - .mock(), + Box::new( + untyped::UnresolvedType::Array( + Box::new(untyped::UnresolvedType::FieldElement.mock()), + untyped::Expression::IntConstant(3usize.into()).mock(), + ) + .mock(), + ), untyped::Expression::IntConstant(2usize.into()).mock(), ), ), ( "bool[2][3u32]", untyped::UnresolvedType::Array( - box untyped::UnresolvedType::Array( - box untyped::UnresolvedType::Boolean.mock(), - untyped::Expression::U32Constant(3u32).mock(), - ) - .mock(), + Box::new( + untyped::UnresolvedType::Array( + Box::new(untyped::UnresolvedType::Boolean.mock()), + untyped::Expression::U32Constant(3u32).mock(), + ) + .mock(), + ), untyped::Expression::IntConstant(2usize.into()).mock(), ), ), @@ -1099,59 +1106,59 @@ mod tests { ( "a[3]", untyped::Expression::Select( - box untyped::Expression::Identifier("a").into(), - box untyped::RangeOrExpression::Expression( + Box::new(untyped::Expression::Identifier("a").into()), + Box::new(untyped::RangeOrExpression::Expression( untyped::Expression::IntConstant(3usize.into()).into(), ), - ), + )), ), ( "a[3][4]", untyped::Expression::Select( - box untyped::Expression::Select( - box untyped::Expression::Identifier("a").into(), - box untyped::RangeOrExpression::Expression( + Box::new(untyped::Expression::Select( + Box::new(untyped::Expression::Identifier("a").into()), + Box::new(untyped::RangeOrExpression::Expression( untyped::Expression::IntConstant(3usize.into()).into(), - ), + )), ) - .into(), - box untyped::RangeOrExpression::Expression( + .into()), + Box::new(untyped::RangeOrExpression::Expression( untyped::Expression::IntConstant(4usize.into()).into(), - ), + )), ), ), ( "a(3)[4]", untyped::Expression::Select( - box untyped::Expression::FunctionCall( - box untyped::Expression::Identifier("a").mock(), + Box::new(untyped::Expression::FunctionCall( + Box::new(untyped::Expression::Identifier("a").mock()), None, vec![untyped::Expression::IntConstant(3usize.into()).into()], ) - .into(), - box untyped::RangeOrExpression::Expression( + .into()), + Box::new(untyped::RangeOrExpression::Expression( untyped::Expression::IntConstant(4usize.into()).into(), - ), + )), ), ), ( "a(3)[4][5]", untyped::Expression::Select( - box untyped::Expression::Select( - box untyped::Expression::FunctionCall( - box untyped::Expression::Identifier("a").mock(), + Box::new(untyped::Expression::Select( + Box::new(untyped::Expression::FunctionCall( + Box::new(untyped::Expression::Identifier("a").mock()), None, vec![untyped::Expression::IntConstant(3usize.into()).into()], ) - .into(), - box untyped::RangeOrExpression::Expression( + .into()), + Box::new(untyped::RangeOrExpression::Expression( untyped::Expression::IntConstant(4usize.into()).into(), - ), + )), ) - .into(), - box untyped::RangeOrExpression::Expression( + .into()), + Box::new(untyped::RangeOrExpression::Expression( untyped::Expression::IntConstant(5usize.into()).into(), - ), + )), ), ), ]; @@ -1172,13 +1179,15 @@ mod tests { assert_eq!( untyped::Module::from(ast), wrap(untyped::Expression::FunctionCall( - box untyped::Expression::Select( - box untyped::Expression::Identifier("a").mock(), - box untyped::RangeOrExpression::Expression( - untyped::Expression::IntConstant(2u32.into()).mock() + Box::new( + untyped::Expression::Select( + Box::new(untyped::Expression::Identifier("a").mock()), + Box::new(untyped::RangeOrExpression::Expression( + untyped::Expression::IntConstant(2u32.into()).mock() + )) ) - ) - .mock(), + .mock() + ), None, vec![untyped::Expression::IntConstant(3u32.into()).mock()], )) @@ -1194,12 +1203,14 @@ mod tests { assert_eq!( untyped::Module::from(ast), wrap(untyped::Expression::FunctionCall( - box untyped::Expression::FunctionCall( - box untyped::Expression::Identifier("a").mock(), - None, - vec![untyped::Expression::IntConstant(2u32.into()).mock()] - ) - .mock(), + Box::new( + untyped::Expression::FunctionCall( + Box::new(untyped::Expression::Identifier("a").mock()), + None, + vec![untyped::Expression::IntConstant(2u32.into()).mock()] + ) + .mock() + ), None, vec![untyped::Expression::IntConstant(3u32.into()).mock()], )) @@ -1219,10 +1230,10 @@ mod tests { lhs: pest::TypedIdentifierOrAssignee::Assignee(pest::Assignee { id: pest::IdentifierExpression { value: String::from("a"), - span: span.clone(), + span, }, accesses: vec![], - span: span.clone(), + span, }), expression: pest::Expression::Literal(pest::LiteralExpression::DecimalLiteral( pest::DecimalLiteralExpression { @@ -1230,10 +1241,10 @@ mod tests { span: Span::new("1", 0, 1).unwrap(), }, suffix: None, - span: span.clone(), + span, }, )), - span: span.clone(), + span, }; let statement = untyped::StatementNode::from(definition); @@ -1250,32 +1261,30 @@ mod tests { let definition = pest::DefinitionStatement { lhs: pest::TypedIdentifierOrAssignee::TypedIdentifier(pest::TypedIdentifier { - ty: pest::Type::Basic(pest::BasicType::Field(pest::FieldType { - span: span.clone(), - })), + ty: pest::Type::Basic(pest::BasicType::Field(pest::FieldType { span })), identifier: pest::IdentifierExpression { value: String::from("a"), - span: span.clone(), + span, }, mutable: None, - span: span.clone(), + span, }), expression: pest::Expression::Postfix(pest::PostfixExpression { - base: box pest::Expression::Identifier(pest::IdentifierExpression { + base: Box::new(pest::Expression::Identifier(pest::IdentifierExpression { value: String::from("foo"), - span: span.clone(), - }), + span, + })), accesses: vec![pest::Access::Call(pest::CallAccess { explicit_generics: None, arguments: pest::Arguments { expressions: vec![], - span: span.clone(), + span, }, - span: span.clone(), + span, })], - span: span.clone(), + span, }), - span: span.clone(), + span, }; let statement = untyped::StatementNode::from(definition); diff --git a/zokrates_ast/src/untyped/mod.rs b/zokrates_ast/src/untyped/mod.rs index 07541edec..c0f77ea64 100644 --- a/zokrates_ast/src/untyped/mod.rs +++ b/zokrates_ast/src/untyped/mod.rs @@ -8,17 +8,17 @@ mod from_ast; mod node; pub mod parameter; -mod position; pub mod types; pub mod variable; pub use self::node::{Node, NodeValue}; pub use self::parameter::{Parameter, ParameterNode}; -pub use self::position::Position; use self::types::{UnresolvedSignature, UnresolvedType, UserTypeId}; pub use self::variable::{Variable, VariableNode}; use crate::common::FlatEmbed; -use std::path::{Path, PathBuf}; +pub use crate::common::Position; +pub use crate::common::{ModuleId, OwnedModuleId}; +use std::path::Path; use std::fmt; @@ -28,10 +28,6 @@ use std::collections::HashMap; /// An identifier of a function or a variable pub type Identifier<'ast> = &'ast str; -/// The identifier of a `Module`, typically a path or uri -pub type OwnedModuleId = PathBuf; -pub type ModuleId = Path; - /// A collection of `Module`s pub type Modules<'ast> = HashMap>; diff --git a/zokrates_ast/src/untyped/node.rs b/zokrates_ast/src/untyped/node.rs index 62ef299df..fbff15dd8 100644 --- a/zokrates_ast/src/untyped/node.rs +++ b/zokrates_ast/src/untyped/node.rs @@ -1,26 +1,25 @@ +use crate::common::LocalSourceSpan as Span; use std::fmt; -use zokrates_pest_ast::Span; +use zokrates_pest_ast::Span as PestSpan; #[derive(Clone)] pub struct Node { - pub start: Position, - pub end: Position, + pub span: Span, pub value: T, } impl Node { pub fn mock(e: T) -> Self { Self { - start: Position::mock(), - end: Position::mock(), + span: Span::mock(), value: e, } } } impl Node { - pub fn pos(&self) -> (Position, Position) { - (self.start, self.end) + pub fn span(&self) -> Span { + self.span } } @@ -37,8 +36,11 @@ impl fmt::Debug for Node { } impl Node { - pub fn new(start: Position, end: Position, value: T) -> Node { - Node { start, end, value } + pub fn new(from: Position, to: Position, value: T) -> Node { + Node { + span: Span { from, to }, + value, + } } } @@ -56,7 +58,7 @@ pub trait NodeValue: fmt::Display + fmt::Debug + Sized + PartialEq { Node::new(Position::mock(), Position::mock(), self) } - fn span(self, span: Span) -> Node { + fn span(self, span: PestSpan) -> Node { let from = span.start_pos().line_col(); let to = span.end_pos().line_col(); diff --git a/zokrates_ast/src/untyped/types.rs b/zokrates_ast/src/untyped/types.rs index 0f6c4ba45..f2a87ad86 100644 --- a/zokrates_ast/src/untyped/types.rs +++ b/zokrates_ast/src/untyped/types.rs @@ -69,7 +69,7 @@ impl<'ast> fmt::Display for UnresolvedType<'ast> { impl<'ast> UnresolvedType<'ast> { pub fn array(ty: UnresolvedTypeNode<'ast>, size: ExpressionNode<'ast>) -> Self { - UnresolvedType::Array(box ty, size) + UnresolvedType::Array(Box::new(ty), size) } } diff --git a/zokrates_ast/src/untyped/variable.rs b/zokrates_ast/src/untyped/variable.rs index edbc7f4cf..61f86f5dc 100644 --- a/zokrates_ast/src/untyped/variable.rs +++ b/zokrates_ast/src/untyped/variable.rs @@ -8,7 +8,7 @@ use super::Identifier; pub struct Variable<'ast> { pub is_mutable: bool, pub id: Identifier<'ast>, - pub _type: UnresolvedTypeNode<'ast>, + pub ty: UnresolvedTypeNode<'ast>, } pub type VariableNode<'ast> = Node>; @@ -22,7 +22,7 @@ impl<'ast> Variable<'ast> { Variable { is_mutable, id: id.into(), - _type: t, + ty: t, } } @@ -35,13 +35,13 @@ impl<'ast> Variable<'ast> { } pub fn get_type(&self) -> &UnresolvedType<'ast> { - &self._type.value + &self.ty.value } } impl<'ast> fmt::Display for Variable<'ast> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{} {}", self._type, self.id,) + write!(f, "{} {}", self.ty, self.id,) } } @@ -50,7 +50,7 @@ impl<'ast> fmt::Debug for Variable<'ast> { write!( f, "Variable(type: {:?}, id: {:?}, is_mutable: {:?})", - self._type, self.id, self.is_mutable + self.ty, self.id, self.is_mutable ) } } diff --git a/zokrates_ast/src/zir/canonicalizer.rs b/zokrates_ast/src/zir/canonicalizer.rs new file mode 100644 index 000000000..61bf1970a --- /dev/null +++ b/zokrates_ast/src/zir/canonicalizer.rs @@ -0,0 +1,91 @@ +use super::{Folder, Identifier, Parameter, Variable, ZirAssignee}; +use std::collections::HashMap; +use zokrates_field::Field; + +#[derive(Default)] +pub struct ZirCanonicalizer<'ast> { + identifier_map: HashMap, usize>, +} + +impl<'ast, T: Field> Folder<'ast, T> for ZirCanonicalizer<'ast> { + fn fold_parameter(&mut self, p: Parameter<'ast>) -> Parameter<'ast> { + let new_id = self.identifier_map.len(); + self.identifier_map.insert(p.id.id.clone(), new_id); + + Parameter { + id: Variable::with_id_and_type(Identifier::internal(new_id), p.id.ty), + ..p + } + } + fn fold_assignee(&mut self, a: ZirAssignee<'ast>) -> ZirAssignee<'ast> { + let new_id = self.identifier_map.len(); + self.identifier_map.insert(a.id.clone(), new_id); + ZirAssignee::with_id_and_type(Identifier::internal(new_id), a.ty) + } + fn fold_name(&mut self, n: Identifier<'ast>) -> Identifier<'ast> { + match self.identifier_map.get(&n) { + Some(v) => Identifier::internal(*v), + None => unreachable!(), + } + } +} + +#[cfg(test)] +mod tests { + use crate::zir::{ + FieldElementExpression, IdentifierExpression, Signature, Type, ZirAssignee, ZirFunction, + ZirStatement, + }; + + use super::*; + use zokrates_field::Bn128Field; + + #[test] + fn canonicalize() { + let func = ZirFunction:: { + arguments: vec![Parameter::new(Variable::field_element("a"), true)], + statements: vec![ + ZirStatement::definition( + ZirAssignee::field_element("b"), + FieldElementExpression::Identifier(IdentifierExpression::new("a".into())) + .into(), + ), + ZirStatement::ret(vec![FieldElementExpression::Identifier( + IdentifierExpression::new("b".into()), + ) + .into()]), + ], + signature: Signature::new() + .inputs(vec![Type::FieldElement]) + .outputs(vec![Type::FieldElement]), + }; + + let mut canonicalizer = ZirCanonicalizer::default(); + let result = canonicalizer.fold_function(func); + + let expected = ZirFunction:: { + arguments: vec![Parameter::new( + Variable::field_element(Identifier::internal(0usize)), + true, + )], + statements: vec![ + ZirStatement::definition( + ZirAssignee::field_element(Identifier::internal(1usize)), + FieldElementExpression::Identifier(IdentifierExpression::new( + Identifier::internal(0usize), + )) + .into(), + ), + ZirStatement::ret(vec![FieldElementExpression::Identifier( + IdentifierExpression::new(Identifier::internal(1usize)), + ) + .into()]), + ], + signature: Signature::new() + .inputs(vec![Type::FieldElement]) + .outputs(vec![Type::FieldElement]), + }; + + assert_eq!(result, expected); + } +} diff --git a/zokrates_ast/src/zir/folder.rs b/zokrates_ast/src/zir/folder.rs index 770eb0f03..b536ccc78 100644 --- a/zokrates_ast/src/zir/folder.rs +++ b/zokrates_ast/src/zir/folder.rs @@ -1,27 +1,25 @@ // Generic walk through ZIR. Not mutating in place +use crate::common::expressions::{BinaryOrExpression, IdentifierOrExpression, UnaryOrExpression}; +use crate::common::{Fold, WithSpan}; use crate::zir::types::UBitwidth; use crate::zir::*; use zokrates_field::Field; -pub trait Fold<'ast, T: Field>: Sized { - fn fold>(self, f: &mut F) -> Self; -} - -impl<'ast, T: Field> Fold<'ast, T> for FieldElementExpression<'ast, T> { - fn fold>(self, f: &mut F) -> Self { +impl<'ast, T: Field, F: Folder<'ast, T>> Fold for FieldElementExpression<'ast, T> { + fn fold(self, f: &mut F) -> Self { f.fold_field_expression(self) } } -impl<'ast, T: Field> Fold<'ast, T> for BooleanExpression<'ast, T> { - fn fold>(self, f: &mut F) -> Self { +impl<'ast, T: Field, F: Folder<'ast, T>> Fold for BooleanExpression<'ast, T> { + fn fold(self, f: &mut F) -> Self { f.fold_boolean_expression(self) } } -impl<'ast, T: Field> Fold<'ast, T> for UExpression<'ast, T> { - fn fold>(self, f: &mut F) -> Self { +impl<'ast, T: Field, F: Folder<'ast, T>> Fold for UExpression<'ast, T> { + fn fold(self, f: &mut F) -> Self { f.fold_uint_expression(self) } } @@ -56,6 +54,20 @@ pub trait Folder<'ast, T: Field>: Sized { self.fold_variable(a) } + fn fold_assembly_constraint( + &mut self, + s: AssemblyConstraint<'ast, T>, + ) -> Vec> { + fold_assembly_constraint(self, s) + } + + fn fold_assembly_assignment( + &mut self, + s: AssemblyAssignment<'ast, T>, + ) -> Vec> { + fold_assembly_assignment(self, s) + } + fn fold_assembly_statement( &mut self, s: ZirAssemblyStatement<'ast, T>, @@ -63,19 +75,73 @@ pub trait Folder<'ast, T: Field>: Sized { fold_assembly_statement(self, s) } + fn fold_assembly_statement_cases( + &mut self, + s: ZirAssemblyStatement<'ast, T>, + ) -> Vec> { + fold_assembly_statement_cases(self, s) + } + fn fold_statement(&mut self, s: ZirStatement<'ast, T>) -> Vec> { fold_statement(self, s) } + fn fold_statement_cases(&mut self, s: ZirStatement<'ast, T>) -> Vec> { + fold_statement_cases(self, s) + } + + fn fold_definition_statement( + &mut self, + s: DefinitionStatement<'ast, T>, + ) -> Vec> { + fold_definition_statement(self, s) + } + + fn fold_if_else_statement( + &mut self, + s: IfElseStatement<'ast, T>, + ) -> Vec> { + fold_if_else_statement(self, s) + } + + fn fold_multiple_definition_statement( + &mut self, + s: MultipleDefinitionStatement<'ast, T>, + ) -> Vec> { + fold_multiple_definition_statement(self, s) + } + + fn fold_assertion_statement( + &mut self, + s: AssertionStatement<'ast, T>, + ) -> Vec> { + fold_assertion_statement(self, s) + } + + fn fold_return_statement(&mut self, s: ReturnStatement<'ast, T>) -> Vec> { + fold_return_statement(self, s) + } + + fn fold_log_statement(&mut self, s: LogStatement<'ast, T>) -> Vec> { + fold_log_statement(self, s) + } + + fn fold_assembly_block( + &mut self, + s: AssemblyBlockStatement<'ast, T>, + ) -> Vec> { + fold_assembly_block(self, s) + } + fn fold_identifier_expression + Id<'ast, T>>( &mut self, ty: &E::Ty, e: IdentifierExpression<'ast, E>, - ) -> IdentifierOrExpression<'ast, T, E> { + ) -> IdentifierOrExpression, E, E::Inner> { fold_identifier_expression(self, ty, e) } - fn fold_conditional_expression + Fold<'ast, T> + Conditional<'ast, T>>( + fn fold_conditional_expression + Fold + Conditional<'ast, T>>( &mut self, ty: &E::Ty, e: ConditionalExpression<'ast, T, E>, @@ -83,7 +149,7 @@ pub trait Folder<'ast, T: Field>: Sized { fold_conditional_expression(self, ty, e) } - fn fold_select_expression + Fold<'ast, T> + Select<'ast, T>>( + fn fold_select_expression + Fold + Select<'ast, T>>( &mut self, ty: &E::Ty, e: SelectExpression<'ast, T, E>, @@ -91,6 +157,27 @@ pub trait Folder<'ast, T: Field>: Sized { fold_select_expression(self, ty, e) } + fn fold_binary_expression< + L: Expr<'ast, T> + Fold, + R: Expr<'ast, T> + Fold, + E: Expr<'ast, T> + Fold, + Op, + >( + &mut self, + ty: &E::Ty, + e: BinaryExpression, + ) -> BinaryOrExpression { + fold_binary_expression(self, ty, e) + } + + fn fold_unary_expression + Fold, E: Expr<'ast, T> + Fold, Op>( + &mut self, + ty: &E::Ty, + e: UnaryExpression, + ) -> UnaryOrExpression { + fold_unary_expression(self, ty, e) + } + fn fold_expression(&mut self, e: ZirExpression<'ast, T>) -> ZirExpression<'ast, T> { match e { ZirExpression::FieldElement(e) => self.fold_field_expression(e).into(), @@ -140,23 +227,66 @@ pub trait Folder<'ast, T: Field>: Sized { ) -> UExpressionInner<'ast, T> { fold_uint_expression_inner(self, bitwidth, e) } + + fn fold_field_expression_cases( + &mut self, + e: FieldElementExpression<'ast, T>, + ) -> FieldElementExpression<'ast, T> { + fold_field_expression_cases(self, e) + } + + fn fold_boolean_expression_cases( + &mut self, + e: BooleanExpression<'ast, T>, + ) -> BooleanExpression<'ast, T> { + fold_boolean_expression_cases(self, e) + } + + fn fold_uint_expression_cases( + &mut self, + bitwidth: UBitwidth, + e: UExpressionInner<'ast, T>, + ) -> UExpressionInner<'ast, T> { + fold_uint_expression_cases(self, bitwidth, e) + } } -pub fn fold_assembly_statement<'ast, T: Field, F: Folder<'ast, T>>( +pub fn fold_assembly_assignment<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + s: AssemblyAssignment<'ast, T>, +) -> Vec> { + let assignees = s.assignee.into_iter().map(|a| f.fold_assignee(a)).collect(); + let expression = f.fold_function(s.expression); + vec![ZirAssemblyStatement::assignment(assignees, expression)] +} + +pub fn fold_assembly_constraint<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + s: AssemblyConstraint<'ast, T>, +) -> Vec> { + let left = f.fold_field_expression(s.left); + let right = f.fold_field_expression(s.right); + vec![ZirAssemblyStatement::constraint(left, right, s.metadata)] +} + +fn fold_assembly_statement<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + s: ZirAssemblyStatement<'ast, T>, +) -> Vec> { + let span = s.get_span(); + f.fold_assembly_statement_cases(s) + .into_iter() + .map(|s| s.span(span)) + .collect() +} + +fn fold_assembly_statement_cases<'ast, T: Field, F: Folder<'ast, T>>( f: &mut F, s: ZirAssemblyStatement<'ast, T>, ) -> Vec> { match s { - ZirAssemblyStatement::Assignment(assignees, function) => { - let assignees = assignees.into_iter().map(|a| f.fold_assignee(a)).collect(); - let function = f.fold_function(function); - vec![ZirAssemblyStatement::Assignment(assignees, function)] - } - ZirAssemblyStatement::Constraint(lhs, rhs, metadata) => { - let lhs = f.fold_field_expression(lhs); - let rhs = f.fold_field_expression(rhs); - vec![ZirAssemblyStatement::Constraint(lhs, rhs, metadata)] - } + ZirAssemblyStatement::Assignment(s) => f.fold_assembly_assignment(s), + ZirAssemblyStatement::Constraint(s) => f.fold_assembly_constraint(s), } } @@ -164,48 +294,119 @@ pub fn fold_statement<'ast, T: Field, F: Folder<'ast, T>>( f: &mut F, s: ZirStatement<'ast, T>, ) -> Vec> { - let res = match s { - ZirStatement::Return(expressions) => ZirStatement::Return( - expressions - .into_iter() - .map(|e| f.fold_expression(e)) - .collect(), - ), - ZirStatement::Definition(a, e) => { - ZirStatement::Definition(f.fold_assignee(a), f.fold_expression(e)) - } - ZirStatement::IfElse(condition, consequence, alternative) => ZirStatement::IfElse( - f.fold_boolean_expression(condition), - consequence - .into_iter() - .flat_map(|e| f.fold_statement(e)) - .collect(), - alternative - .into_iter() - .flat_map(|e| f.fold_statement(e)) - .collect(), - ), - ZirStatement::Assertion(e, error) => { - ZirStatement::Assertion(f.fold_boolean_expression(e), error) - } - ZirStatement::MultipleDefinition(variables, elist) => ZirStatement::MultipleDefinition( - variables.into_iter().map(|v| f.fold_variable(v)).collect(), - f.fold_expression_list(elist), - ), - ZirStatement::Log(l, e) => ZirStatement::Log( - l, - e.into_iter() - .map(|(t, e)| (t, e.into_iter().map(|e| f.fold_expression(e)).collect())) - .collect(), - ), - ZirStatement::Assembly(statements) => ZirStatement::Assembly( - statements + let span = s.get_span(); + f.fold_statement_cases(s) + .into_iter() + .map(|s| s.span(span)) + .collect() +} + +pub fn fold_statement_cases<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + s: ZirStatement<'ast, T>, +) -> Vec> { + let span = s.get_span(); + + match s { + ZirStatement::Return(s) => f.fold_return_statement(s), + ZirStatement::Definition(s) => f.fold_definition_statement(s), + ZirStatement::IfElse(s) => f.fold_if_else_statement(s), + ZirStatement::Assertion(s) => f.fold_assertion_statement(s), + ZirStatement::MultipleDefinition(s) => f.fold_multiple_definition_statement(s), + ZirStatement::Log(s) => f.fold_log_statement(s), + ZirStatement::Assembly(s) => f.fold_assembly_block(s), + } + .into_iter() + .map(|s| s.span(span)) + .collect() +} + +pub fn fold_multiple_definition_statement<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + s: MultipleDefinitionStatement<'ast, T>, +) -> Vec> { + let expression_list = f.fold_expression_list(s.rhs); + vec![ZirStatement::MultipleDefinition( + MultipleDefinitionStatement::new( + s.assignees .into_iter() - .flat_map(|s| f.fold_assembly_statement(s)) + .map(|v| f.fold_variable(v)) .collect(), + expression_list, ), - }; - vec![res] + )] +} + +pub fn fold_if_else_statement<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + s: IfElseStatement<'ast, T>, +) -> Vec> { + vec![ZirStatement::IfElse(IfElseStatement::new( + f.fold_boolean_expression(s.condition), + s.consequence + .into_iter() + .flat_map(|e| f.fold_statement(e)) + .collect(), + s.alternative + .into_iter() + .flat_map(|e| f.fold_statement(e)) + .collect(), + ))] +} + +pub fn fold_definition_statement<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + s: DefinitionStatement<'ast, T>, +) -> Vec> { + let rhs = f.fold_expression(s.rhs); + vec![ZirStatement::Definition(DefinitionStatement::new( + f.fold_assignee(s.assignee), + rhs, + ))] +} + +pub fn fold_assertion_statement<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + s: AssertionStatement<'ast, T>, +) -> Vec> { + vec![ZirStatement::Assertion(AssertionStatement::new( + f.fold_boolean_expression(s.expression), + s.error, + ))] +} + +pub fn fold_return_statement<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + s: ReturnStatement<'ast, T>, +) -> Vec> { + vec![ZirStatement::Return(ReturnStatement::new( + s.inner.into_iter().map(|e| f.fold_expression(e)).collect(), + ))] +} + +pub fn fold_log_statement<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + s: LogStatement<'ast, T>, +) -> Vec> { + vec![ZirStatement::Log(LogStatement::new( + s.format_string, + s.expressions + .into_iter() + .map(|(t, e)| (t, e.into_iter().map(|e| f.fold_expression(e)).collect())) + .collect(), + ))] +} + +pub fn fold_assembly_block<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + s: AssemblyBlockStatement<'ast, T>, +) -> Vec> { + vec![ZirStatement::Assembly(AssemblyBlockStatement::new( + s.inner + .into_iter() + .flat_map(|s| f.fold_assembly_statement(s)) + .collect(), + ))] } pub fn fold_identifier_expression< @@ -217,16 +418,24 @@ pub fn fold_identifier_expression< f: &mut F, _: &E::Ty, e: IdentifierExpression<'ast, E>, -) -> IdentifierOrExpression<'ast, T, E> { +) -> IdentifierOrExpression, E, E::Inner> { IdentifierOrExpression::Identifier(IdentifierExpression::new(f.fold_name(e.id))) } -pub fn fold_field_expression<'ast, T: Field, F: Folder<'ast, T>>( +fn fold_field_expression<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + e: FieldElementExpression<'ast, T>, +) -> FieldElementExpression<'ast, T> { + let span = e.get_span(); + f.fold_field_expression_cases(e).span(span) +} + +pub fn fold_field_expression_cases<'ast, T: Field, F: Folder<'ast, T>>( f: &mut F, e: FieldElementExpression<'ast, T>, ) -> FieldElementExpression<'ast, T> { match e { - FieldElementExpression::Number(n) => FieldElementExpression::Number(n), + FieldElementExpression::Value(n) => FieldElementExpression::Value(n), FieldElementExpression::Identifier(id) => { match f.fold_identifier_expression(&Type::FieldElement, id) { IdentifierOrExpression::Identifier(i) => FieldElementExpression::Identifier(i), @@ -239,60 +448,49 @@ pub fn fold_field_expression<'ast, T: Field, F: Folder<'ast, T>>( SelectOrExpression::Expression(u) => u, } } - FieldElementExpression::Add(box e1, box e2) => { - let e1 = f.fold_field_expression(e1); - let e2 = f.fold_field_expression(e2); - FieldElementExpression::Add(box e1, box e2) - } - FieldElementExpression::Sub(box e1, box e2) => { - let e1 = f.fold_field_expression(e1); - let e2 = f.fold_field_expression(e2); - FieldElementExpression::Sub(box e1, box e2) - } - FieldElementExpression::Mult(box e1, box e2) => { - let e1 = f.fold_field_expression(e1); - let e2 = f.fold_field_expression(e2); - FieldElementExpression::Mult(box e1, box e2) - } - FieldElementExpression::Div(box e1, box e2) => { - let e1 = f.fold_field_expression(e1); - let e2 = f.fold_field_expression(e2); - FieldElementExpression::Div(box e1, box e2) - } - FieldElementExpression::Pow(box e1, box e2) => { - let e1 = f.fold_field_expression(e1); - let e2 = f.fold_uint_expression(e2); - FieldElementExpression::Pow(box e1, box e2) - } - FieldElementExpression::And(box left, box right) => { - let left = f.fold_field_expression(left); - let right = f.fold_field_expression(right); - - FieldElementExpression::And(box left, box right) - } - FieldElementExpression::Or(box left, box right) => { - let left = f.fold_field_expression(left); - let right = f.fold_field_expression(right); - - FieldElementExpression::Or(box left, box right) - } - FieldElementExpression::Xor(box left, box right) => { - let left = f.fold_field_expression(left); - let right = f.fold_field_expression(right); - - FieldElementExpression::Xor(box left, box right) - } - FieldElementExpression::LeftShift(box e, box by) => { - let e = f.fold_field_expression(e); - let by = f.fold_uint_expression(by); - - FieldElementExpression::LeftShift(box e, box by) + FieldElementExpression::Add(e) => match f.fold_binary_expression(&Type::FieldElement, e) { + BinaryOrExpression::Binary(e) => FieldElementExpression::Add(e), + BinaryOrExpression::Expression(e) => e, + }, + FieldElementExpression::Sub(e) => match f.fold_binary_expression(&Type::FieldElement, e) { + BinaryOrExpression::Binary(e) => FieldElementExpression::Sub(e), + BinaryOrExpression::Expression(e) => e, + }, + FieldElementExpression::Mult(e) => match f.fold_binary_expression(&Type::FieldElement, e) { + BinaryOrExpression::Binary(e) => FieldElementExpression::Mult(e), + BinaryOrExpression::Expression(e) => e, + }, + FieldElementExpression::Div(e) => match f.fold_binary_expression(&Type::FieldElement, e) { + BinaryOrExpression::Binary(e) => FieldElementExpression::Div(e), + BinaryOrExpression::Expression(e) => e, + }, + FieldElementExpression::Pow(e) => match f.fold_binary_expression(&Type::FieldElement, e) { + BinaryOrExpression::Binary(e) => FieldElementExpression::Pow(e), + BinaryOrExpression::Expression(e) => e, + }, + FieldElementExpression::And(e) => match f.fold_binary_expression(&Type::FieldElement, e) { + BinaryOrExpression::Binary(e) => FieldElementExpression::And(e), + BinaryOrExpression::Expression(e) => e, + }, + FieldElementExpression::Or(e) => match f.fold_binary_expression(&Type::FieldElement, e) { + BinaryOrExpression::Binary(e) => FieldElementExpression::Or(e), + BinaryOrExpression::Expression(e) => e, + }, + FieldElementExpression::Xor(e) => match f.fold_binary_expression(&Type::FieldElement, e) { + BinaryOrExpression::Binary(e) => FieldElementExpression::Xor(e), + BinaryOrExpression::Expression(e) => e, + }, + FieldElementExpression::LeftShift(e) => { + match f.fold_binary_expression(&Type::FieldElement, e) { + BinaryOrExpression::Binary(e) => FieldElementExpression::LeftShift(e), + BinaryOrExpression::Expression(e) => e, + } } - FieldElementExpression::RightShift(box e, box by) => { - let e = f.fold_field_expression(e); - let by = f.fold_uint_expression(by); - - FieldElementExpression::RightShift(box e, box by) + FieldElementExpression::RightShift(e) => { + match f.fold_binary_expression(&Type::FieldElement, e) { + BinaryOrExpression::Binary(e) => FieldElementExpression::RightShift(e), + BinaryOrExpression::Expression(e) => e, + } } FieldElementExpression::Conditional(c) => { match f.fold_conditional_expression(&Type::FieldElement, c) { @@ -303,10 +501,20 @@ pub fn fold_field_expression<'ast, T: Field, F: Folder<'ast, T>>( } } -pub fn fold_boolean_expression<'ast, T: Field, F: Folder<'ast, T>>( +fn fold_boolean_expression<'ast, T: Field, F: Folder<'ast, T>>( f: &mut F, e: BooleanExpression<'ast, T>, ) -> BooleanExpression<'ast, T> { + let span = e.get_span(); + f.fold_boolean_expression_cases(e).span(span) +} + +pub fn fold_boolean_expression_cases<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + e: BooleanExpression<'ast, T>, +) -> BooleanExpression<'ast, T> { + use BooleanExpression::*; + match e { BooleanExpression::Value(v) => BooleanExpression::Value(v), BooleanExpression::Identifier(id) => match f.fold_identifier_expression(&Type::Boolean, id) @@ -318,55 +526,46 @@ pub fn fold_boolean_expression<'ast, T: Field, F: Folder<'ast, T>>( SelectOrExpression::Select(s) => BooleanExpression::Select(s), SelectOrExpression::Expression(u) => u, }, - BooleanExpression::FieldEq(box e1, box e2) => { - let e1 = f.fold_field_expression(e1); - let e2 = f.fold_field_expression(e2); - BooleanExpression::FieldEq(box e1, box e2) - } - BooleanExpression::BoolEq(box e1, box e2) => { - let e1 = f.fold_boolean_expression(e1); - let e2 = f.fold_boolean_expression(e2); - BooleanExpression::BoolEq(box e1, box e2) - } - BooleanExpression::UintEq(box e1, box e2) => { - let e1 = f.fold_uint_expression(e1); - let e2 = f.fold_uint_expression(e2); - BooleanExpression::UintEq(box e1, box e2) - } - BooleanExpression::FieldLt(box e1, box e2) => { - let e1 = f.fold_field_expression(e1); - let e2 = f.fold_field_expression(e2); - BooleanExpression::FieldLt(box e1, box e2) - } - BooleanExpression::UintLt(box e1, box e2) => { - let e1 = f.fold_uint_expression(e1); - let e2 = f.fold_uint_expression(e2); - BooleanExpression::UintLt(box e1, box e2) - } - BooleanExpression::FieldLe(box e1, box e2) => { - let e1 = f.fold_field_expression(e1); - let e2 = f.fold_field_expression(e2); - BooleanExpression::FieldLe(box e1, box e2) - } - BooleanExpression::UintLe(box e1, box e2) => { - let e1 = f.fold_uint_expression(e1); - let e2 = f.fold_uint_expression(e2); - BooleanExpression::UintLe(box e1, box e2) - } - BooleanExpression::Or(box e1, box e2) => { - let e1 = f.fold_boolean_expression(e1); - let e2 = f.fold_boolean_expression(e2); - BooleanExpression::Or(box e1, box e2) - } - BooleanExpression::And(box e1, box e2) => { - let e1 = f.fold_boolean_expression(e1); - let e2 = f.fold_boolean_expression(e2); - BooleanExpression::And(box e1, box e2) - } - BooleanExpression::Not(box e) => { - let e = f.fold_boolean_expression(e); - BooleanExpression::Not(box e) - } + FieldEq(e) => match f.fold_binary_expression(&Type::Boolean, e) { + BinaryOrExpression::Binary(e) => FieldEq(e), + BinaryOrExpression::Expression(u) => u, + }, + BoolEq(e) => match f.fold_binary_expression(&Type::Boolean, e) { + BinaryOrExpression::Binary(e) => BoolEq(e), + BinaryOrExpression::Expression(u) => u, + }, + UintEq(e) => match f.fold_binary_expression(&Type::Boolean, e) { + BinaryOrExpression::Binary(e) => UintEq(e), + BinaryOrExpression::Expression(u) => u, + }, + FieldLt(e) => match f.fold_binary_expression(&Type::Boolean, e) { + BinaryOrExpression::Binary(e) => FieldLt(e), + BinaryOrExpression::Expression(u) => u, + }, + FieldLe(e) => match f.fold_binary_expression(&Type::Boolean, e) { + BinaryOrExpression::Binary(e) => FieldLe(e), + BinaryOrExpression::Expression(u) => u, + }, + UintLt(e) => match f.fold_binary_expression(&Type::Boolean, e) { + BinaryOrExpression::Binary(e) => UintLt(e), + BinaryOrExpression::Expression(u) => u, + }, + UintLe(e) => match f.fold_binary_expression(&Type::Boolean, e) { + BinaryOrExpression::Binary(e) => UintLe(e), + BinaryOrExpression::Expression(u) => u, + }, + Or(e) => match f.fold_binary_expression(&Type::Boolean, e) { + BinaryOrExpression::Binary(e) => Or(e), + BinaryOrExpression::Expression(u) => u, + }, + And(e) => match f.fold_binary_expression(&Type::Boolean, e) { + BinaryOrExpression::Binary(e) => And(e), + BinaryOrExpression::Expression(u) => u, + }, + Not(e) => match f.fold_unary_expression(&Type::Boolean, e) { + UnaryOrExpression::Unary(e) => Not(e), + UnaryOrExpression::Expression(u) => u, + }, BooleanExpression::Conditional(c) => match f.fold_conditional_expression(&Type::Boolean, c) { ConditionalOrExpression::Conditional(s) => BooleanExpression::Conditional(s), @@ -385,86 +584,78 @@ pub fn fold_uint_expression<'ast, T: Field, F: Folder<'ast, T>>( } } -pub fn fold_uint_expression_inner<'ast, T: Field, F: Folder<'ast, T>>( +fn fold_uint_expression_inner<'ast, T: Field, F: Folder<'ast, T>>( f: &mut F, ty: UBitwidth, e: UExpressionInner<'ast, T>, ) -> UExpressionInner<'ast, T> { + let span = e.get_span(); + f.fold_uint_expression_cases(ty, e).span(span) +} + +pub fn fold_uint_expression_cases<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + ty: UBitwidth, + e: UExpressionInner<'ast, T>, +) -> UExpressionInner<'ast, T> { + use UExpressionInner::*; + match e { - UExpressionInner::Value(v) => UExpressionInner::Value(v), - UExpressionInner::Identifier(id) => match f.fold_identifier_expression(&ty, id) { + Value(v) => UExpressionInner::Value(v), + Identifier(id) => match f.fold_identifier_expression(&ty, id) { IdentifierOrExpression::Identifier(i) => UExpressionInner::Identifier(i), IdentifierOrExpression::Expression(e) => e, }, - UExpressionInner::Select(e) => match f.fold_select_expression(&ty, e) { + Select(e) => match f.fold_select_expression(&ty, e) { SelectOrExpression::Select(s) => UExpressionInner::Select(s), SelectOrExpression::Expression(u) => u, }, - UExpressionInner::Add(box left, box right) => { - let left = f.fold_uint_expression(left); - let right = f.fold_uint_expression(right); - - UExpressionInner::Add(box left, box right) - } - UExpressionInner::Sub(box left, box right) => { - let left = f.fold_uint_expression(left); - let right = f.fold_uint_expression(right); - - UExpressionInner::Sub(box left, box right) - } - UExpressionInner::Mult(box left, box right) => { - let left = f.fold_uint_expression(left); - let right = f.fold_uint_expression(right); - - UExpressionInner::Mult(box left, box right) - } - UExpressionInner::Div(box left, box right) => { - let left = f.fold_uint_expression(left); - let right = f.fold_uint_expression(right); - - UExpressionInner::Div(box left, box right) - } - UExpressionInner::Rem(box left, box right) => { - let left = f.fold_uint_expression(left); - let right = f.fold_uint_expression(right); - - UExpressionInner::Rem(box left, box right) - } - UExpressionInner::Xor(box left, box right) => { - let left = f.fold_uint_expression(left); - let right = f.fold_uint_expression(right); - - UExpressionInner::Xor(box left, box right) - } - UExpressionInner::And(box left, box right) => { - let left = f.fold_uint_expression(left); - let right = f.fold_uint_expression(right); - - UExpressionInner::And(box left, box right) - } - UExpressionInner::Or(box left, box right) => { - let left = f.fold_uint_expression(left); - let right = f.fold_uint_expression(right); - - UExpressionInner::Or(box left, box right) - } - UExpressionInner::LeftShift(box e, by) => { - let e = f.fold_uint_expression(e); - - UExpressionInner::LeftShift(box e, by) - } - UExpressionInner::RightShift(box e, by) => { - let e = f.fold_uint_expression(e); - - UExpressionInner::RightShift(box e, by) - } - UExpressionInner::Not(box e) => { - let e = f.fold_uint_expression(e); - - UExpressionInner::Not(box e) - } + Add(e) => match f.fold_binary_expression(&ty, e) { + BinaryOrExpression::Binary(e) => Add(e), + BinaryOrExpression::Expression(u) => u, + }, + Sub(e) => match f.fold_binary_expression(&ty, e) { + BinaryOrExpression::Binary(e) => Sub(e), + BinaryOrExpression::Expression(u) => u, + }, + Mult(e) => match f.fold_binary_expression(&ty, e) { + BinaryOrExpression::Binary(e) => Mult(e), + BinaryOrExpression::Expression(u) => u, + }, + Div(e) => match f.fold_binary_expression(&ty, e) { + BinaryOrExpression::Binary(e) => Div(e), + BinaryOrExpression::Expression(u) => u, + }, + Rem(e) => match f.fold_binary_expression(&ty, e) { + BinaryOrExpression::Binary(e) => Rem(e), + BinaryOrExpression::Expression(u) => u, + }, + Xor(e) => match f.fold_binary_expression(&ty, e) { + BinaryOrExpression::Binary(e) => Xor(e), + BinaryOrExpression::Expression(u) => u, + }, + And(e) => match f.fold_binary_expression(&ty, e) { + BinaryOrExpression::Binary(e) => And(e), + BinaryOrExpression::Expression(u) => u, + }, + Or(e) => match f.fold_binary_expression(&ty, e) { + BinaryOrExpression::Binary(e) => Or(e), + BinaryOrExpression::Expression(u) => u, + }, + LeftShift(e) => match f.fold_binary_expression(&ty, e) { + BinaryOrExpression::Binary(e) => LeftShift(e), + BinaryOrExpression::Expression(u) => u, + }, + RightShift(e) => match f.fold_binary_expression(&ty, e) { + BinaryOrExpression::Binary(e) => RightShift(e), + BinaryOrExpression::Expression(u) => u, + }, + Not(e) => match f.fold_unary_expression(&ty, e) { + UnaryOrExpression::Unary(e) => Not(e), + UnaryOrExpression::Expression(u) => u, + }, UExpressionInner::Conditional(c) => match f.fold_conditional_expression(&ty, c) { - ConditionalOrExpression::Conditional(s) => UExpressionInner::Conditional(s), + ConditionalOrExpression::Conditional(s) => Conditional(s), ConditionalOrExpression::Expression(u) => u, }, } @@ -495,13 +686,14 @@ pub fn fold_program<'ast, T: Field, F: Folder<'ast, T>>( ) -> ZirProgram<'ast, T> { ZirProgram { main: f.fold_function(p.main), + ..p } } pub fn fold_conditional_expression< 'ast, T: Field, - E: Expr<'ast, T> + Fold<'ast, T> + Conditional<'ast, T>, + E: Expr<'ast, T> + Fold + Conditional<'ast, T>, F: Folder<'ast, T>, >( f: &mut F, @@ -518,7 +710,7 @@ pub fn fold_conditional_expression< pub fn fold_select_expression< 'ast, T: Field, - E: Expr<'ast, T> + Fold<'ast, T> + Select<'ast, T>, + E: Expr<'ast, T> + Fold + Select<'ast, T>, F: Folder<'ast, T>, >( f: &mut F, @@ -530,3 +722,34 @@ pub fn fold_select_expression< e.index.fold(f), )) } + +pub fn fold_binary_expression< + 'ast, + T: Field, + L: Expr<'ast, T> + Fold + From>, + R: Expr<'ast, T> + Fold + From>, + E: Expr<'ast, T> + Fold + From>, + F: Folder<'ast, T>, + Op, +>( + f: &mut F, + _: &E::Ty, + e: BinaryExpression, +) -> BinaryOrExpression { + BinaryOrExpression::Binary(BinaryExpression::new(e.left.fold(f), e.right.fold(f)).span(e.span)) +} + +pub fn fold_unary_expression< + 'ast, + T: Field, + In: Expr<'ast, T> + Fold + From>, + E: Expr<'ast, T> + Fold + From>, + F: Folder<'ast, T>, + Op, +>( + f: &mut F, + _: &E::Ty, + e: UnaryExpression, +) -> UnaryOrExpression { + UnaryOrExpression::Unary(UnaryExpression::new(e.inner.fold(f)).span(e.span)) +} diff --git a/zokrates_ast/src/zir/identifier.rs b/zokrates_ast/src/zir/identifier.rs index 249b2630e..3d56b07ef 100644 --- a/zokrates_ast/src/zir/identifier.rs +++ b/zokrates_ast/src/zir/identifier.rs @@ -4,13 +4,14 @@ use std::fmt; use crate::typed::Identifier as CoreIdentifier; -#[derive(Debug, PartialEq, Clone, Hash, Eq, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Clone, Hash, Eq, PartialOrd, Ord, Serialize, Deserialize)] pub enum Identifier<'ast> { #[serde(borrow)] Source(SourceIdentifier<'ast>), + Internal(usize), } -#[derive(Debug, PartialEq, Clone, Hash, Eq, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Clone, Hash, Eq, PartialOrd, Ord, Serialize, Deserialize)] pub enum SourceIdentifier<'ast> { #[serde(borrow)] Basic(CoreIdentifier<'ast>), @@ -19,21 +20,42 @@ pub enum SourceIdentifier<'ast> { Element(Box>, u32), } -impl<'ast> fmt::Display for SourceIdentifier<'ast> { +impl<'ast> Identifier<'ast> { + pub fn internal>(id: T) -> Self { + Identifier::Internal(id.into()) + } +} + +impl<'ast> SourceIdentifier<'ast> { + pub fn select(self, index: u32) -> Self { + Self::Select(Box::new(self), index) + } + + pub fn member(self, member: MemberId) -> Self { + Self::Member(Box::new(self), member) + } + + pub fn element(self, index: u32) -> Self { + Self::Element(Box::new(self), index) + } +} + +impl<'ast> fmt::Display for Identifier<'ast> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - SourceIdentifier::Basic(i) => write!(f, "{}", i), - SourceIdentifier::Select(box i, index) => write!(f, "{}~{}", i, index), - SourceIdentifier::Member(box i, m) => write!(f, "{}.{}", i, m), - SourceIdentifier::Element(box i, index) => write!(f, "{}.{}", i, index), + Identifier::Source(s) => write!(f, "{}", s), + Identifier::Internal(i) => write!(f, "i{}", i), } } } -impl<'ast> fmt::Display for Identifier<'ast> { +impl<'ast> fmt::Display for SourceIdentifier<'ast> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - Identifier::Source(s) => write!(f, "{}", s), + SourceIdentifier::Basic(i) => write!(f, "{}", i), + SourceIdentifier::Select(i, index) => write!(f, "{}~{}", i, index), + SourceIdentifier::Member(i, m) => write!(f, "{}.{}", i, m), + SourceIdentifier::Element(i, index) => write!(f, "{}.{}", i, index), } } } diff --git a/zokrates_ast/src/zir/lqc.rs b/zokrates_ast/src/zir/lqc.rs index 121b2a396..e34877c5a 100644 --- a/zokrates_ast/src/zir/lqc.rs +++ b/zokrates_ast/src/zir/lqc.rs @@ -43,7 +43,7 @@ impl<'ast, T: Field> std::ops::Sub for LinQuadComb<'ast, T> { linear: { let mut l = self.linear; other.linear.iter_mut().for_each(|(c, _)| { - *c = T::zero() - &*c; + *c = T::zero() - *c; }); l.append(&mut other.linear); l @@ -51,7 +51,7 @@ impl<'ast, T: Field> std::ops::Sub for LinQuadComb<'ast, T> { quadratic: { let mut q = self.quadratic; other.quadratic.iter_mut().for_each(|(c, _, _)| { - *c = T::zero() - &*c; + *c = T::zero() - *c; }); q.append(&mut other.quadratic); q @@ -68,18 +68,18 @@ impl<'ast, T: Field> LinQuadComb<'ast, T> { } Ok(Self { - constant: self.constant.clone() * rhs.constant.clone(), + constant: self.constant * rhs.constant, linear: { // lin0 * const1 + lin1 * const0 self.linear .clone() .into_iter() - .map(|(c, i)| (c * rhs.constant.clone(), i)) + .map(|(c, i)| (c * rhs.constant, i)) .chain( rhs.linear .clone() .into_iter() - .map(|(c, i)| (c * self.constant.clone(), i)), + .map(|(c, i)| (c * self.constant, i)), ) .collect() }, @@ -87,16 +87,16 @@ impl<'ast, T: Field> LinQuadComb<'ast, T> { // quad0 * const1 + quad1 * const0 + lin0 * lin1 self.quadratic .into_iter() - .map(|(c, i0, i1)| (c * rhs.constant.clone(), i0, i1)) + .map(|(c, i0, i1)| (c * rhs.constant, i0, i1)) .chain( rhs.quadratic .into_iter() - .map(|(c, i0, i1)| (c * self.constant.clone(), i0, i1)), + .map(|(c, i0, i1)| (c * self.constant, i0, i1)), ) .chain(self.linear.iter().flat_map(|(cl, l)| { rhs.linear .iter() - .map(|(cr, r)| (cl.clone() * cr.clone(), l.clone(), r.clone())) + .map(|(cr, r)| (*cl * *cr, l.clone(), r.clone())) })) .collect() }, @@ -109,23 +109,23 @@ impl<'ast, T: Field> TryFrom> for LinQuadComb<'a fn try_from(e: FieldElementExpression<'ast, T>) -> Result { match e { - FieldElementExpression::Number(v) => Ok(Self { - constant: v, + FieldElementExpression::Value(v) => Ok(Self { + constant: v.value, ..Self::default() }), FieldElementExpression::Identifier(id) => Ok(Self { linear: vec![(T::one(), id.id)], ..Self::default() }), - FieldElementExpression::Add(box left, box right) => { - Ok(Self::try_from(left)? + Self::try_from(right)?) + FieldElementExpression::Add(e) => { + Ok(Self::try_from(*e.left)? + Self::try_from(*e.right)?) } - FieldElementExpression::Sub(box left, box right) => { - Ok(Self::try_from(left)? - Self::try_from(right)?) + FieldElementExpression::Sub(e) => { + Ok(Self::try_from(*e.left)? - Self::try_from(*e.right)?) } - FieldElementExpression::Mult(box left, box right) => { - let left = Self::try_from(left)?; - let right = Self::try_from(right)?; + FieldElementExpression::Mult(e) => { + let left = Self::try_from(*e.left)?; + let right = Self::try_from(*e.right)?; left.try_mul(right) } @@ -137,30 +137,31 @@ impl<'ast, T: Field> TryFrom> for LinQuadComb<'a #[cfg(test)] mod tests { use super::*; - use crate::zir::Id; + use crate::zir::{Expr, Id}; + use std::ops::*; use zokrates_field::Bn128Field; #[test] fn add() { // (2 + 2*a) - let a = LinQuadComb::try_from(FieldElementExpression::Add( - box FieldElementExpression::Number(Bn128Field::from(2)), - box FieldElementExpression::Mult( - box FieldElementExpression::Number(Bn128Field::from(2)), - box FieldElementExpression::identifier("a".into()), + let a = LinQuadComb::try_from(FieldElementExpression::add( + FieldElementExpression::value(Bn128Field::from(2)), + FieldElementExpression::mul( + FieldElementExpression::value(Bn128Field::from(2)), + FieldElementExpression::identifier("a".into()), ), )) .unwrap(); // (2 + 2*a*b) - let b = LinQuadComb::try_from(FieldElementExpression::Add( - box FieldElementExpression::Number(Bn128Field::from(2)), - box FieldElementExpression::Mult( - box FieldElementExpression::Mult( - box FieldElementExpression::Number(Bn128Field::from(2)), - box FieldElementExpression::identifier("a".into()), + let b = LinQuadComb::try_from(FieldElementExpression::add( + FieldElementExpression::value(Bn128Field::from(2)), + FieldElementExpression::mul( + FieldElementExpression::mul( + FieldElementExpression::value(Bn128Field::from(2)), + FieldElementExpression::identifier("a".into()), ), - box FieldElementExpression::identifier("b".into()), + FieldElementExpression::identifier("b".into()), ), )) .unwrap(); @@ -186,24 +187,24 @@ mod tests { #[test] fn sub() { // (2 + 2*a) - let a = LinQuadComb::try_from(FieldElementExpression::Add( - box FieldElementExpression::Number(Bn128Field::from(2)), - box FieldElementExpression::Mult( - box FieldElementExpression::Number(Bn128Field::from(2)), - box FieldElementExpression::identifier("a".into()), + let a = LinQuadComb::try_from(FieldElementExpression::add( + FieldElementExpression::value(Bn128Field::from(2)), + FieldElementExpression::mul( + FieldElementExpression::value(Bn128Field::from(2)), + FieldElementExpression::identifier("a".into()), ), )) .unwrap(); // (2 + 2*a*b) - let b = LinQuadComb::try_from(FieldElementExpression::Add( - box FieldElementExpression::Number(Bn128Field::from(2)), - box FieldElementExpression::Mult( - box FieldElementExpression::Mult( - box FieldElementExpression::Number(Bn128Field::from(2)), - box FieldElementExpression::identifier("a".into()), + let b = LinQuadComb::try_from(FieldElementExpression::add( + FieldElementExpression::value(Bn128Field::from(2)), + FieldElementExpression::mul( + FieldElementExpression::mul( + FieldElementExpression::value(Bn128Field::from(2)), + FieldElementExpression::identifier("a".into()), ), - box FieldElementExpression::identifier("b".into()), + FieldElementExpression::identifier("b".into()), ), )) .unwrap(); @@ -227,23 +228,23 @@ mod tests { } #[test] - fn mult() { + fn mul() { // (2 + 2*a) - let a = LinQuadComb::try_from(FieldElementExpression::Add( - box FieldElementExpression::Number(Bn128Field::from(2)), - box FieldElementExpression::Mult( - box FieldElementExpression::Number(Bn128Field::from(2)), - box FieldElementExpression::identifier("a".into()), + let a = LinQuadComb::try_from(FieldElementExpression::add( + FieldElementExpression::value(Bn128Field::from(2)), + FieldElementExpression::mul( + FieldElementExpression::value(Bn128Field::from(2)), + FieldElementExpression::identifier("a".into()), ), )) .unwrap(); // (2 + 2*b) - let b = LinQuadComb::try_from(FieldElementExpression::Add( - box FieldElementExpression::Number(Bn128Field::from(2)), - box FieldElementExpression::Mult( - box FieldElementExpression::Number(Bn128Field::from(2)), - box FieldElementExpression::identifier("b".into()), + let b = LinQuadComb::try_from(FieldElementExpression::add( + FieldElementExpression::value(Bn128Field::from(2)), + FieldElementExpression::mul( + FieldElementExpression::value(Bn128Field::from(2)), + FieldElementExpression::identifier("b".into()), ), )) .unwrap(); @@ -266,13 +267,13 @@ mod tests { } #[test] - fn mult_degree_error() { + fn mul_degree_error() { // 2*a*b - let a = LinQuadComb::try_from(FieldElementExpression::Add( - box FieldElementExpression::Number(Bn128Field::from(2)), - box FieldElementExpression::Mult( - box FieldElementExpression::identifier("a".into()), - box FieldElementExpression::identifier("b".into()), + let a = LinQuadComb::try_from(FieldElementExpression::add( + FieldElementExpression::value(Bn128Field::from(2)), + FieldElementExpression::mul( + FieldElementExpression::identifier("a".into()), + FieldElementExpression::identifier("b".into()), ), )) .unwrap(); diff --git a/zokrates_ast/src/zir/mod.rs b/zokrates_ast/src/zir/mod.rs index 60dc1467f..5ae001bc1 100644 --- a/zokrates_ast/src/zir/mod.rs +++ b/zokrates_ast/src/zir/mod.rs @@ -1,3 +1,4 @@ +pub mod canonicalizer; pub mod folder; mod from_typed; mod identifier; @@ -11,13 +12,20 @@ mod variable; pub use self::parameter::Parameter; pub use self::types::{Type, UBitwidth}; pub use self::variable::Variable; -use crate::common::{FlatEmbed, FormatString, SourceMetadata}; +use crate::common::expressions::{BooleanValueExpression, UnaryExpression}; +use crate::common::SourceMetadata; +use crate::common::{self, FlatEmbed, ModuleMap, Span, Value, WithSpan}; +use crate::common::{ + expressions::{self, BinaryExpression, ValueExpression}, + operators::*, +}; use crate::typed::ConcreteType; pub use crate::zir::uint::{ShouldReduce, UExpression, UExpressionInner, UMetadata}; use crate::zir::types::Signature; use std::fmt; -use std::marker::PhantomData; + +use derivative::Derivative; use zokrates_field::Field; pub use self::folder::Folder; @@ -25,9 +33,12 @@ pub use self::identifier::{Identifier, SourceIdentifier}; use serde::{Deserialize, Serialize}; /// A typed program as a collection of modules, one of them being the main -#[derive(PartialEq, Eq, Debug, Clone)] +#[derive(Derivative)] +#[derivative(PartialEq, Hash)] +#[derive(Clone, Debug)] pub struct ZirProgram<'ast, T> { pub main: ZirFunction<'ast, T>, + pub module_map: ModuleMap, } impl<'ast, T: fmt::Display> fmt::Display for ZirProgram<'ast, T> { @@ -36,10 +47,11 @@ impl<'ast, T: fmt::Display> fmt::Display for ZirProgram<'ast, T> { } } /// A typed function -#[derive(Clone, PartialEq, Hash, Eq, Serialize, Deserialize)] +#[derive(Derivative)] +#[derivative(PartialEq, Hash, Eq)] +#[derive(Clone, Serialize, Deserialize)] pub struct ZirFunction<'ast, T> { /// Arguments of the function - #[serde(borrow)] pub arguments: Vec>, /// Vector of statements that are executed when running the function #[serde(borrow)] @@ -48,6 +60,9 @@ pub struct ZirFunction<'ast, T> { pub signature: Signature, } +pub type IdentifierOrExpression<'ast, T, E> = + expressions::IdentifierOrExpression, E, >::Inner>; + impl<'ast, T: fmt::Display> fmt::Display for ZirFunction<'ast, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { writeln!( @@ -117,58 +132,263 @@ impl RuntimeError { } } +pub type AssemblyConstraint<'ast, T> = + crate::common::statements::AssemblyConstraint>; +pub type AssemblyAssignment<'ast, T> = + crate::common::statements::AssemblyAssignment>, ZirFunction<'ast, T>>; + #[derive(Clone, PartialEq, Hash, Eq, Debug, Serialize, Deserialize)] pub enum ZirAssemblyStatement<'ast, T> { - Assignment( - #[serde(borrow)] Vec>, - ZirFunction<'ast, T>, - ), - Constraint( - FieldElementExpression<'ast, T>, - FieldElementExpression<'ast, T>, - SourceMetadata, - ), + #[serde(borrow)] + Assignment(AssemblyAssignment<'ast, T>), + Constraint(AssemblyConstraint<'ast, T>), +} + +impl<'ast, T> ZirAssemblyStatement<'ast, T> { + pub fn assignment(assignee: Vec>, expression: ZirFunction<'ast, T>) -> Self { + ZirAssemblyStatement::Assignment(AssemblyAssignment::new(assignee, expression)) + } + + pub fn constraint( + left: FieldElementExpression<'ast, T>, + right: FieldElementExpression<'ast, T>, + metadata: SourceMetadata, + ) -> Self { + ZirAssemblyStatement::Constraint(AssemblyConstraint::new(left, right, metadata)) + } +} + +impl<'ast, T> WithSpan for ZirAssemblyStatement<'ast, T> { + fn span(self, span: Option) -> Self { + match self { + ZirAssemblyStatement::Assignment(s) => ZirAssemblyStatement::Assignment(s.span(span)), + ZirAssemblyStatement::Constraint(s) => ZirAssemblyStatement::Constraint(s.span(span)), + } + } + + fn get_span(&self) -> Option { + match self { + ZirAssemblyStatement::Assignment(s) => s.get_span(), + ZirAssemblyStatement::Constraint(s) => s.get_span(), + } + } } impl<'ast, T: fmt::Display> fmt::Display for ZirAssemblyStatement<'ast, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - ZirAssemblyStatement::Assignment(ref lhs, ref rhs) => { + ZirAssemblyStatement::Assignment(ref s) => { write!( f, "{} <-- {};", - lhs.iter() + s.assignee + .iter() .map(|a| a.to_string()) .collect::>() .join(", "), - rhs + s.expression ) } - ZirAssemblyStatement::Constraint(ref lhs, ref rhs, _) => { - write!(f, "{} === {};", lhs, rhs) + ZirAssemblyStatement::Constraint(ref s) => { + write!(f, "{}", s) } } } } +pub type DefinitionStatement<'ast, T> = + common::expressions::DefinitionStatement, ZirExpression<'ast, T>>; +pub type AssertionStatement<'ast, T> = + common::expressions::AssertionStatement, RuntimeError>; +pub type ReturnStatement<'ast, T> = + common::expressions::ReturnStatement>>; +pub type LogStatement<'ast, T> = + common::statements::LogStatement<(ConcreteType, Vec>)>; + +#[derive(Derivative)] +#[derivative(PartialEq, Hash)] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct IfElseStatement<'ast, T> { + #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Hash = "ignore")] + pub span: Option, + #[serde(borrow)] + pub condition: BooleanExpression<'ast, T>, + pub consequence: Vec>, + pub alternative: Vec>, +} + +impl<'ast, T> IfElseStatement<'ast, T> { + pub fn new( + condition: BooleanExpression<'ast, T>, + consequence: Vec>, + alternative: Vec>, + ) -> Self { + Self { + span: None, + condition, + consequence, + alternative, + } + } +} + +impl<'ast, T> WithSpan for IfElseStatement<'ast, T> { + fn span(self, span: Option) -> Self { + Self { span, ..self } + } + + fn get_span(&self) -> Option { + self.span + } +} + +#[derive(Derivative)] +#[derivative(PartialEq, Hash)] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct MultipleDefinitionStatement<'ast, T> { + #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Hash = "ignore")] + pub span: Option, + #[serde(borrow)] + pub assignees: Vec>, + pub rhs: ZirExpressionList<'ast, T>, +} + +impl<'ast, T> MultipleDefinitionStatement<'ast, T> { + pub fn new(assignees: Vec>, rhs: ZirExpressionList<'ast, T>) -> Self { + Self { + span: None, + assignees, + rhs, + } + } +} + +impl<'ast, T> WithSpan for MultipleDefinitionStatement<'ast, T> { + fn span(mut self, span: Option) -> Self { + self.span = span; + self + } + + fn get_span(&self) -> Option { + self.span + } +} + +impl<'ast, T: fmt::Display> fmt::Display for MultipleDefinitionStatement<'ast, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for (i, id) in self.assignees.iter().enumerate() { + write!(f, "{}", id)?; + if i < self.assignees.len() - 1 { + write!(f, ", ")?; + } + } + write!(f, " = {}", self.rhs) + } +} + +#[derive(Derivative)] +#[derivative(PartialEq, Hash)] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct AssemblyBlockStatement<'ast, T> { + #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Hash = "ignore")] + pub span: Option, + #[serde(borrow)] + pub inner: Vec>, +} + +impl<'ast, T> AssemblyBlockStatement<'ast, T> { + pub fn new(inner: Vec>) -> Self { + Self { span: None, inner } + } +} + +impl<'ast, T> WithSpan for AssemblyBlockStatement<'ast, T> { + fn span(mut self, span: Option) -> Self { + self.span = span; + self + } + + fn get_span(&self) -> Option { + self.span + } +} + /// A statement in a `ZirFunction` -#[derive(Clone, PartialEq, Hash, Eq, Debug, Serialize, Deserialize)] +#[derive(Derivative)] +#[derivative(PartialEq, Hash)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub enum ZirStatement<'ast, T> { - Return(Vec>), - Definition(ZirAssignee<'ast>, ZirExpression<'ast, T>), - IfElse( - BooleanExpression<'ast, T>, - Vec>, - Vec>, - ), - Assertion(BooleanExpression<'ast, T>, RuntimeError), - MultipleDefinition(Vec>, ZirExpressionList<'ast, T>), - Log( - FormatString, - Vec<(ConcreteType, Vec>)>, - ), + Return(ReturnStatement<'ast, T>), + Definition(DefinitionStatement<'ast, T>), + IfElse(IfElseStatement<'ast, T>), + Assertion(AssertionStatement<'ast, T>), + MultipleDefinition(MultipleDefinitionStatement<'ast, T>), + Log(LogStatement<'ast, T>), #[serde(borrow)] - Assembly(Vec>), + Assembly(AssemblyBlockStatement<'ast, T>), +} + +impl<'ast, T> ZirStatement<'ast, T> { + pub fn definition(a: ZirAssignee<'ast>, e: ZirExpression<'ast, T>) -> Self { + Self::Definition(DefinitionStatement::new(a, e)) + } + + pub fn multiple_definition( + assignees: Vec>, + e: ZirExpressionList<'ast, T>, + ) -> Self { + Self::MultipleDefinition(MultipleDefinitionStatement::new(assignees, e)) + } + + pub fn assertion(e: BooleanExpression<'ast, T>, error: RuntimeError) -> Self { + Self::Assertion(AssertionStatement::new(e, error)) + } + + pub fn ret(e: Vec>) -> Self { + Self::Return(ReturnStatement::new(e)) + } + + pub fn assembly(s: Vec>) -> Self { + Self::Assembly(AssemblyBlockStatement::new(s)) + } + + pub fn if_else( + condition: BooleanExpression<'ast, T>, + consequence: Vec>, + alternative: Vec>, + ) -> Self { + Self::IfElse(IfElseStatement::new(condition, consequence, alternative)) + } +} + +impl<'ast, T> WithSpan for ZirStatement<'ast, T> { + fn span(self, span: Option) -> Self { + use ZirStatement::*; + + match self { + Return(e) => Return(e.span(span)), + Definition(e) => Definition(e.span(span)), + Assertion(e) => Assertion(e.span(span)), + IfElse(e) => IfElse(e.span(span)), + MultipleDefinition(e) => MultipleDefinition(e.span(span)), + Log(e) => Log(e.span(span)), + Assembly(e) => Assembly(e.span(span)), + } + } + + fn get_span(&self) -> Option { + use ZirStatement::*; + + match self { + Return(e) => e.get_span(), + Definition(e) => e.get_span(), + Assertion(e) => e.get_span(), + IfElse(e) => e.get_span(), + MultipleDefinition(e) => e.get_span(), + Log(e) => e.get_span(), + Assembly(e) => e.get_span(), + } + } } impl<'ast, T: fmt::Display> fmt::Display for ZirStatement<'ast, T> { @@ -180,14 +400,15 @@ impl<'ast, T: fmt::Display> fmt::Display for ZirStatement<'ast, T> { impl<'ast, T: fmt::Display> ZirStatement<'ast, T> { fn fmt_indented(&self, f: &mut fmt::Formatter, depth: usize) -> fmt::Result { write!(f, "{}", "\t".repeat(depth))?; + match self { - ZirStatement::Return(ref exprs) => { + ZirStatement::Return(ref s) => { write!(f, "return")?; - if !exprs.is_empty() { + if !s.inner.is_empty() { write!( f, " {}", - exprs + s.inner .iter() .map(|e| e.to_string()) .collect::>() @@ -196,43 +417,37 @@ impl<'ast, T: fmt::Display> ZirStatement<'ast, T> { } write!(f, ";") } - ZirStatement::Definition(ref lhs, ref rhs) => { - write!(f, "{} = {};", lhs, rhs) + ZirStatement::Definition(ref s) => { + write!(f, "{};", s) } - ZirStatement::IfElse(ref condition, ref consequence, ref alternative) => { - writeln!(f, "if {} {{", condition)?; - for s in consequence { + ZirStatement::IfElse(ref s) => { + writeln!(f, "if {} {{", s.condition)?; + for s in &s.consequence { s.fmt_indented(f, depth + 1)?; writeln!(f)?; } writeln!(f, "{}}} else {{", "\t".repeat(depth))?; - for s in alternative { + for s in &s.alternative { s.fmt_indented(f, depth + 1)?; writeln!(f)?; } write!(f, "{}}}", "\t".repeat(depth)) } - ZirStatement::Assertion(ref e, ref error) => { - write!(f, "assert({}", e)?; - match error { + ZirStatement::Assertion(ref s) => { + write!(f, "assert({}", s.expression)?; + match &s.error { RuntimeError::SourceAssertion(message) => write!(f, ", \"{}\");", message), error => write!(f, "); // {}", error), } } - ZirStatement::MultipleDefinition(ref ids, ref rhs) => { - for (i, id) in ids.iter().enumerate() { - write!(f, "{}", id)?; - if i < ids.len() - 1 { - write!(f, ", ")?; - } - } - write!(f, " = {};", rhs) + ZirStatement::MultipleDefinition(ref s) => { + write!(f, "{};", s) } - ZirStatement::Log(ref l, ref expressions) => write!( + ZirStatement::Log(ref e) => write!( f, "log(\"{}\"), {});", - l, - expressions + e.format_string, + e.expressions .iter() .map(|(_, e)| format!( "[{}]", @@ -244,9 +459,9 @@ impl<'ast, T: fmt::Display> ZirStatement<'ast, T> { .collect::>() .join(", ") ), - ZirStatement::Assembly(statements) => { + ZirStatement::Assembly(s) => { writeln!(f, "asm {{")?; - for s in statements { + for s in &s.inner { writeln!(f, "{}{}", "\t".repeat(depth + 1), s)?; } write!(f, "{}}}", "\t".repeat(depth)) @@ -259,30 +474,12 @@ pub trait Typed { fn get_type(&self) -> Type; } -#[derive(Debug, Clone, PartialEq, Hash, Eq, Serialize, Deserialize)] -pub struct IdentifierExpression<'ast, E> { - #[serde(borrow)] - pub id: Identifier<'ast>, - ty: PhantomData, -} - -impl<'ast, E> fmt::Display for IdentifierExpression<'ast, E> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.id) - } -} - -impl<'ast, E> IdentifierExpression<'ast, E> { - pub fn new(id: Identifier<'ast>) -> Self { - IdentifierExpression { - id, - ty: PhantomData, - } - } -} - -#[derive(Debug, Clone, PartialEq, Hash, Eq, Serialize, Deserialize)] +#[derive(Derivative)] +#[derivative(PartialEq, Hash)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct ConditionalExpression<'ast, T, E> { + #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Hash = "ignore")] + pub span: Option, #[serde(borrow)] pub condition: Box>, pub consequence: Box, @@ -292,9 +489,10 @@ pub struct ConditionalExpression<'ast, T, E> { impl<'ast, T, E> ConditionalExpression<'ast, T, E> { pub fn new(condition: BooleanExpression<'ast, T>, consequence: E, alternative: E) -> Self { ConditionalExpression { - condition: box condition, - consequence: box consequence, - alternative: box alternative, + span: None, + condition: Box::new(condition), + consequence: Box::new(consequence), + alternative: Box::new(alternative), } } } @@ -304,13 +502,28 @@ impl<'ast, T: fmt::Display, E: fmt::Display> fmt::Display for ConditionalExpress write!( f, "{} ? {} : {}", - self.condition, self.consequence, self.alternative + self.condition, self.consequence, self.alternative, ) } } -#[derive(Debug, Clone, PartialEq, Hash, Eq, Serialize, Deserialize)] +impl<'ast, T, E> WithSpan for ConditionalExpression<'ast, T, E> { + fn span(mut self, span: Option) -> Self { + self.span = span; + self + } + + fn get_span(&self) -> Option { + self.span + } +} + +#[derive(Derivative)] +#[derivative(PartialEq, Hash)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct SelectExpression<'ast, T, E> { + #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Hash = "ignore")] + pub span: Option, pub array: Vec, #[serde(borrow)] pub index: Box>, @@ -319,8 +532,9 @@ pub struct SelectExpression<'ast, T, E> { impl<'ast, T, E> SelectExpression<'ast, T, E> { pub fn new(array: Vec, index: UExpression<'ast, T>) -> Self { SelectExpression { + span: None, array, - index: box index, + index: Box::new(index), } } } @@ -340,12 +554,46 @@ impl<'ast, T: fmt::Display, E: fmt::Display> fmt::Display for SelectExpression<' } } +impl<'ast, T, E> WithSpan for SelectExpression<'ast, T, E> { + fn span(mut self, span: Option) -> Self { + self.span = span; + self + } + + fn get_span(&self) -> Option { + self.span + } +} + /// A typed expression -#[derive(Clone, PartialEq, Hash, Eq, Serialize, Deserialize)] +#[derive(Derivative)] +#[derivative(PartialEq, Hash)] +#[derive(Clone, Serialize, Deserialize)] pub enum ZirExpression<'ast, T> { + #[serde(borrow)] Boolean(BooleanExpression<'ast, T>), FieldElement(FieldElementExpression<'ast, T>), - Uint(#[serde(borrow)] UExpression<'ast, T>), + Uint(UExpression<'ast, T>), +} + +impl<'ast, T> WithSpan for ZirExpression<'ast, T> { + fn span(self, span: Option) -> Self { + use ZirExpression::*; + match self { + Boolean(e) => Boolean(e.span(span)), + FieldElement(e) => FieldElement(e.span(span)), + Uint(e) => Uint(e.span(span)), + } + } + + fn get_span(&self) -> Option { + use ZirExpression::*; + match self { + Boolean(e) => e.get_span(), + FieldElement(e) => e.get_span(), + Uint(e) => e.get_span(), + } + } } impl<'ast, T: Field> From> for ZirExpression<'ast, T> { @@ -418,7 +666,9 @@ pub trait MultiTyped { fn get_types(&self) -> &Vec; } -#[derive(Clone, PartialEq, Hash, Eq, Serialize, Deserialize)] +#[derive(Derivative)] +#[derivative(PartialEq, Hash)] +#[derive(Clone, Serialize, Deserialize)] pub enum ZirExpressionList<'ast, T> { EmbedCall( FlatEmbed, @@ -427,111 +677,126 @@ pub enum ZirExpressionList<'ast, T> { ), } +pub type IdentifierExpression<'ast, E> = expressions::IdentifierExpression, E>; + /// An expression of type `field` -#[derive(Clone, PartialEq, Hash, Eq, Debug, Serialize, Deserialize)] +#[derive(Derivative)] +#[derivative(PartialEq, Eq, Hash)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub enum FieldElementExpression<'ast, T> { - Number(T), + Value(ValueExpression), #[serde(borrow)] Identifier(IdentifierExpression<'ast, Self>), Select(SelectExpression<'ast, T, Self>), - Add( - Box>, - Box>, - ), - Sub( - Box>, - Box>, - ), - Mult( - Box>, - Box>, - ), - Div( - Box>, - Box>, - ), - Pow( - Box>, - #[serde(borrow)] Box>, - ), - And( - Box>, - Box>, - ), - Or( - Box>, - Box>, - ), - Xor( - Box>, - Box>, - ), - LeftShift( - Box>, - Box>, - ), - RightShift( - Box>, - Box>, - ), + Add(BinaryExpression), + Sub(BinaryExpression), + Mult(BinaryExpression), + Div(BinaryExpression), + Pow(BinaryExpression, Self>), + And(BinaryExpression), + Or(BinaryExpression), + Xor(BinaryExpression), + LeftShift(BinaryExpression, Self>), + RightShift(BinaryExpression, Self>), Conditional(ConditionalExpression<'ast, T, FieldElementExpression<'ast, T>>), } impl<'ast, T> FieldElementExpression<'ast, T> { + pub fn number(n: T) -> Self { + Self::Value(ValueExpression::new(n)) + } + + pub fn pow(self, right: UExpression<'ast, T>) -> Self { + Self::Pow(BinaryExpression::new(self, right)) + } + pub fn is_linear(&self) -> bool { match self { - FieldElementExpression::Number(_) => true, + FieldElementExpression::Value(_) => true, FieldElementExpression::Identifier(_) => true, - FieldElementExpression::Add(box left, box right) => { - left.is_linear() && right.is_linear() - } - FieldElementExpression::Sub(box left, box right) => { - left.is_linear() && right.is_linear() - } - FieldElementExpression::Mult(box left, box right) => matches!( - (left, right), - (FieldElementExpression::Number(_), _) | (_, FieldElementExpression::Number(_)) + FieldElementExpression::Add(e) => e.left.is_linear() && e.right.is_linear(), + FieldElementExpression::Sub(e) => e.left.is_linear() && e.right.is_linear(), + FieldElementExpression::Mult(e) => matches!( + (&*e.left, &*e.right), + (FieldElementExpression::Value(_), _) | (_, FieldElementExpression::Value(_)) ), _ => false, } } + + pub fn left_shift(self, by: UExpression<'ast, T>) -> Self { + FieldElementExpression::LeftShift(BinaryExpression::new(self, by)) + } + + pub fn right_shift(self, by: UExpression<'ast, T>) -> Self { + FieldElementExpression::RightShift(BinaryExpression::new(self, by)) + } +} + +impl<'ast, T: Field> std::ops::BitAnd for FieldElementExpression<'ast, T> { + type Output = Self; + + fn bitand(self, other: Self) -> Self { + FieldElementExpression::And(BinaryExpression::new(self, other)) + } +} + +impl<'ast, T: Field> std::ops::BitOr for FieldElementExpression<'ast, T> { + type Output = Self; + + fn bitor(self, other: Self) -> Self { + FieldElementExpression::Or(BinaryExpression::new(self, other)) + } +} + +impl<'ast, T: Field> std::ops::BitXor for FieldElementExpression<'ast, T> { + type Output = Self; + + fn bitxor(self, other: Self) -> Self { + FieldElementExpression::Xor(BinaryExpression::new(self, other)) + } } /// An expression of type `bool` -#[derive(Clone, PartialEq, Hash, Eq, Debug, Serialize, Deserialize)] +#[derive(Derivative)] +#[derivative(PartialEq, Hash)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub enum BooleanExpression<'ast, T> { - Value(bool), + Value(BooleanValueExpression), #[serde(borrow)] Identifier(IdentifierExpression<'ast, Self>), Select(SelectExpression<'ast, T, Self>), FieldLt( - Box>, - Box>, + BinaryExpression< + OpLt, + FieldElementExpression<'ast, T>, + FieldElementExpression<'ast, T>, + Self, + >, ), FieldLe( - Box>, - Box>, + BinaryExpression< + OpLe, + FieldElementExpression<'ast, T>, + FieldElementExpression<'ast, T>, + Self, + >, ), FieldEq( - Box>, - Box>, - ), - UintLt(Box>, Box>), - UintLe(Box>, Box>), - UintEq(Box>, Box>), - BoolEq( - Box>, - Box>, - ), - Or( - Box>, - Box>, - ), - And( - Box>, - Box>, + BinaryExpression< + OpEq, + FieldElementExpression<'ast, T>, + FieldElementExpression<'ast, T>, + Self, + >, ), - Not(Box>), + UintLt(BinaryExpression, UExpression<'ast, T>, Self>), + UintLe(BinaryExpression, UExpression<'ast, T>, Self>), + UintEq(BinaryExpression, UExpression<'ast, T>, Self>), + BoolEq(BinaryExpression), + Or(BinaryExpression), + And(BinaryExpression), + Not(UnaryExpression), Conditional(ConditionalExpression<'ast, T, BooleanExpression<'ast, T>>), } @@ -544,9 +809,9 @@ impl<'ast, T> Iterator for ConjunctionIterator> { fn next(&mut self) -> Option { self.current.pop().and_then(|n| match n { - BooleanExpression::And(box left, box right) => { - self.current.push(left); - self.current.push(right); + BooleanExpression::And(e) => { + self.current.push(*e.left); + self.current.push(*e.right); self.next() } n => Some(n), @@ -593,23 +858,19 @@ impl<'ast, T> From> for UExpression<'ast, T> { impl<'ast, T: fmt::Display> fmt::Display for FieldElementExpression<'ast, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - FieldElementExpression::Number(ref i) => write!(f, "{}", i), + FieldElementExpression::Value(ref i) => write!(f, "{}", i), FieldElementExpression::Identifier(ref var) => write!(f, "{}", var), FieldElementExpression::Select(ref e) => write!(f, "{}", e), - FieldElementExpression::Add(ref lhs, ref rhs) => write!(f, "({} + {})", lhs, rhs), - FieldElementExpression::Sub(ref lhs, ref rhs) => write!(f, "({} - {})", lhs, rhs), - FieldElementExpression::Mult(ref lhs, ref rhs) => write!(f, "({} * {})", lhs, rhs), - FieldElementExpression::Div(ref lhs, ref rhs) => write!(f, "({} / {})", lhs, rhs), - FieldElementExpression::Pow(ref lhs, ref rhs) => write!(f, "{}**{}", lhs, rhs), - FieldElementExpression::And(ref lhs, ref rhs) => write!(f, "({} & {})", lhs, rhs), - FieldElementExpression::Or(ref lhs, ref rhs) => write!(f, "({} | {})", lhs, rhs), - FieldElementExpression::Xor(ref lhs, ref rhs) => write!(f, "({} ^ {})", lhs, rhs), - FieldElementExpression::LeftShift(ref lhs, ref rhs) => { - write!(f, "({} << {})", lhs, rhs) - } - FieldElementExpression::RightShift(ref lhs, ref rhs) => { - write!(f, "({} >> {})", lhs, rhs) - } + FieldElementExpression::Add(ref e) => write!(f, "{}", e), + FieldElementExpression::Sub(ref e) => write!(f, "{}", e), + FieldElementExpression::Mult(ref e) => write!(f, "{}", e), + FieldElementExpression::Div(ref e) => write!(f, "{}", e), + FieldElementExpression::Pow(ref e) => write!(f, "{}", e), + FieldElementExpression::And(ref e) => write!(f, "{}", e), + FieldElementExpression::Or(ref e) => write!(f, "{}", e), + FieldElementExpression::Xor(ref e) => write!(f, "{}", e), + FieldElementExpression::LeftShift(ref e) => write!(f, "{}", e), + FieldElementExpression::RightShift(ref e) => write!(f, "{}", e), FieldElementExpression::Conditional(ref c) => { write!(f, "{}", c) } @@ -623,17 +884,17 @@ impl<'ast, T: fmt::Display> fmt::Display for UExpression<'ast, T> { UExpressionInner::Value(ref v) => write!(f, "{}", v), UExpressionInner::Identifier(ref var) => write!(f, "{}", var), UExpressionInner::Select(ref e) => write!(f, "{}", e), - UExpressionInner::Add(ref lhs, ref rhs) => write!(f, "({} + {})", lhs, rhs), - UExpressionInner::Sub(ref lhs, ref rhs) => write!(f, "({} - {})", lhs, rhs), - UExpressionInner::Mult(ref lhs, ref rhs) => write!(f, "({} * {})", lhs, rhs), - UExpressionInner::Div(ref lhs, ref rhs) => write!(f, "({} * {})", lhs, rhs), - UExpressionInner::Rem(ref lhs, ref rhs) => write!(f, "({} % {})", lhs, rhs), - UExpressionInner::Xor(ref lhs, ref rhs) => write!(f, "({} ^ {})", lhs, rhs), - UExpressionInner::And(ref lhs, ref rhs) => write!(f, "({} & {})", lhs, rhs), - UExpressionInner::Or(ref lhs, ref rhs) => write!(f, "({} | {})", lhs, rhs), - UExpressionInner::LeftShift(ref e, ref by) => write!(f, "({} << {})", e, by), - UExpressionInner::RightShift(ref e, ref by) => write!(f, "({} >> {})", e, by), - UExpressionInner::Not(ref e) => write!(f, "!{}", e), + UExpressionInner::Add(ref e) => write!(f, "{}", e), + UExpressionInner::Sub(ref e) => write!(f, "{}", e), + UExpressionInner::Mult(ref e) => write!(f, "{}", e), + UExpressionInner::Div(ref e) => write!(f, "{}", e), + UExpressionInner::Rem(ref e) => write!(f, "{}", e), + UExpressionInner::Xor(ref e) => write!(f, "{}", e), + UExpressionInner::And(ref e) => write!(f, "{}", e), + UExpressionInner::Or(ref e) => write!(f, "{}", e), + UExpressionInner::LeftShift(ref e) => write!(f, "{}", e), + UExpressionInner::RightShift(ref e) => write!(f, "{}", e), + UExpressionInner::Not(ref e) => write!(f, "{}", e), UExpressionInner::Conditional(ref c) => { write!(f, "{}", c) } @@ -645,18 +906,18 @@ impl<'ast, T: fmt::Display> fmt::Display for BooleanExpression<'ast, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { BooleanExpression::Identifier(ref var) => write!(f, "{}", var), - BooleanExpression::Value(b) => write!(f, "{}", b), + BooleanExpression::Value(ref b) => write!(f, "{}", b), BooleanExpression::Select(ref e) => write!(f, "{}", e), - BooleanExpression::FieldLt(ref lhs, ref rhs) => write!(f, "({} < {})", lhs, rhs), - BooleanExpression::UintLt(ref lhs, ref rhs) => write!(f, "({} < {})", lhs, rhs), - BooleanExpression::FieldLe(ref lhs, ref rhs) => write!(f, "({} <= {})", lhs, rhs), - BooleanExpression::UintLe(ref lhs, ref rhs) => write!(f, "({} <= {})", lhs, rhs), - BooleanExpression::FieldEq(ref lhs, ref rhs) => write!(f, "({} == {})", lhs, rhs), - BooleanExpression::BoolEq(ref lhs, ref rhs) => write!(f, "({} == {})", lhs, rhs), - BooleanExpression::UintEq(ref lhs, ref rhs) => write!(f, "({} == {})", lhs, rhs), - BooleanExpression::Or(ref lhs, ref rhs) => write!(f, "({} || {})", lhs, rhs), - BooleanExpression::And(ref lhs, ref rhs) => write!(f, "({} && {})", lhs, rhs), - BooleanExpression::Not(ref exp) => write!(f, "!{}", exp), + BooleanExpression::FieldLt(ref e) => write!(f, "{}", e), + BooleanExpression::UintLt(ref e) => write!(f, "{}", e), + BooleanExpression::FieldLe(ref e) => write!(f, "{}", e), + BooleanExpression::UintLe(ref e) => write!(f, "{}", e), + BooleanExpression::FieldEq(ref e) => write!(f, "{}", e), + BooleanExpression::BoolEq(ref e) => write!(f, "{}", e), + BooleanExpression::UintEq(ref e) => write!(f, "{}", e), + BooleanExpression::Or(ref e) => write!(f, "{}", e), + BooleanExpression::And(ref e) => write!(f, "{}", e), + BooleanExpression::Not(ref exp) => write!(f, "{}", exp), BooleanExpression::Conditional(ref c) => { write!(f, "{}", c) } @@ -664,6 +925,69 @@ impl<'ast, T: fmt::Display> fmt::Display for BooleanExpression<'ast, T> { } } +impl<'ast, T> std::ops::Not for BooleanExpression<'ast, T> { + type Output = Self; + + fn not(self) -> Self { + Self::Not(UnaryExpression::new(self)) + } +} + +impl<'ast, T> std::ops::BitAnd for BooleanExpression<'ast, T> { + type Output = Self; + + fn bitand(self, other: Self) -> Self { + Self::And(BinaryExpression::new(self, other)) + } +} + +impl<'ast, T> std::ops::BitOr for BooleanExpression<'ast, T> { + type Output = Self; + + fn bitor(self, other: Self) -> Self { + Self::Or(BinaryExpression::new(self, other)) + } +} + +impl<'ast, T> BooleanExpression<'ast, T> { + pub fn uint_eq(left: UExpression<'ast, T>, right: UExpression<'ast, T>) -> Self { + Self::UintEq(BinaryExpression::new(left, right)) + } + + pub fn bool_eq(left: BooleanExpression<'ast, T>, right: BooleanExpression<'ast, T>) -> Self { + Self::BoolEq(BinaryExpression::new(left, right)) + } + + pub fn field_eq( + left: FieldElementExpression<'ast, T>, + right: FieldElementExpression<'ast, T>, + ) -> Self { + Self::FieldEq(BinaryExpression::new(left, right)) + } + + pub fn uint_lt(left: UExpression<'ast, T>, right: UExpression<'ast, T>) -> Self { + Self::UintLt(BinaryExpression::new(left, right)) + } + + pub fn uint_le(left: UExpression<'ast, T>, right: UExpression<'ast, T>) -> Self { + Self::UintLe(BinaryExpression::new(left, right)) + } + + pub fn field_lt( + left: FieldElementExpression<'ast, T>, + right: FieldElementExpression<'ast, T>, + ) -> Self { + Self::FieldLt(BinaryExpression::new(left, right)) + } + + pub fn field_le( + left: FieldElementExpression<'ast, T>, + right: FieldElementExpression<'ast, T>, + ) -> Self { + Self::FieldLe(BinaryExpression::new(left, right)) + } +} + impl<'ast, T: fmt::Display> fmt::Display for ZirExpressionList<'ast, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { @@ -709,8 +1033,52 @@ impl<'ast, T: fmt::Debug> fmt::Debug for ZirExpressionList<'ast, T> { } } +impl<'ast, T: Field> std::ops::Add for FieldElementExpression<'ast, T> { + type Output = Self; + + fn add(self, other: Self) -> Self { + FieldElementExpression::Add(BinaryExpression::new(self, other)) + } +} + +impl<'ast, T: Field> std::ops::Sub for FieldElementExpression<'ast, T> { + type Output = Self; + + fn sub(self, other: Self) -> Self { + FieldElementExpression::Sub(BinaryExpression::new(self, other)) + } +} + +impl<'ast, T: Field> std::ops::Mul for FieldElementExpression<'ast, T> { + type Output = Self; + + fn mul(self, other: Self) -> Self { + FieldElementExpression::Mult(BinaryExpression::new(self, other)) + } +} + +impl<'ast, T: Field> std::ops::Div for FieldElementExpression<'ast, T> { + type Output = Self; + + fn div(self, other: Self) -> Self { + FieldElementExpression::Div(BinaryExpression::new(self, other)) + } +} + +impl<'ast, T: Clone> Value for FieldElementExpression<'ast, T> { + type Value = T; +} + +impl<'ast, T> Value for BooleanExpression<'ast, T> { + type Value = bool; +} + +impl<'ast, T> Value for UExpression<'ast, T> { + type Value = u128; +} + // Common behaviour across expressions -pub trait Expr<'ast, T>: fmt::Display + PartialEq + From> { +pub trait Expr<'ast, T>: Value + fmt::Display + PartialEq + From> { type Inner; type Ty: Clone + IntoType; @@ -721,6 +1089,8 @@ pub trait Expr<'ast, T>: fmt::Display + PartialEq + From> fn as_inner(&self) -> &Self::Inner; fn as_inner_mut(&mut self) -> &mut Self::Inner; + + fn value(_: Self::Value) -> Self::Inner; } impl<'ast, T: Field> Expr<'ast, T> for FieldElementExpression<'ast, T> { @@ -742,6 +1112,10 @@ impl<'ast, T: Field> Expr<'ast, T> for FieldElementExpression<'ast, T> { fn as_inner_mut(&mut self) -> &mut Self::Inner { self } + + fn value(v: ::Value) -> Self::Inner { + Self::Value(ValueExpression::new(v)) + } } impl<'ast, T: Field> Expr<'ast, T> for BooleanExpression<'ast, T> { @@ -763,6 +1137,10 @@ impl<'ast, T: Field> Expr<'ast, T> for BooleanExpression<'ast, T> { fn as_inner_mut(&mut self) -> &mut Self::Inner { self } + + fn value(v: as Value>::Value) -> Self::Inner { + Self::Value(ValueExpression::new(v)) + } } impl<'ast, T: Field> Expr<'ast, T> for UExpression<'ast, T> { @@ -784,6 +1162,10 @@ impl<'ast, T: Field> Expr<'ast, T> for UExpression<'ast, T> { fn as_inner_mut(&mut self) -> &mut Self::Inner { &mut self.inner } + + fn value(v: Self::Value) -> Self::Inner { + UExpressionInner::Value(ValueExpression::new(v)) + } } pub trait Id<'ast, T>: Expr<'ast, T> { @@ -808,11 +1190,6 @@ impl<'ast, T: Field> Id<'ast, T> for UExpression<'ast, T> { } } -pub enum IdentifierOrExpression<'ast, T, E: Expr<'ast, T>> { - Identifier(IdentifierExpression<'ast, E>), - Expression(E::Inner), -} - pub trait Conditional<'ast, T> { fn conditional( condition: BooleanExpression<'ast, T>, @@ -929,9 +1306,150 @@ impl<'ast, T: Field> Constant for ZirExpression<'ast, T> { } } +impl<'ast, T> WithSpan for FieldElementExpression<'ast, T> { + fn span(self, span: Option) -> Self { + use FieldElementExpression::*; + match self { + Select(e) => Select(e.span(span)), + Identifier(e) => Identifier(e.span(span)), + Conditional(e) => Conditional(e.span(span)), + Add(e) => Add(e.span(span)), + Value(e) => Value(e.span(span)), + Sub(e) => Sub(e.span(span)), + Mult(e) => Mult(e.span(span)), + Div(e) => Div(e.span(span)), + Pow(e) => Pow(e.span(span)), + And(e) => And(e.span(span)), + Or(e) => Or(e.span(span)), + Xor(e) => Xor(e.span(span)), + LeftShift(e) => LeftShift(e.span(span)), + RightShift(e) => RightShift(e.span(span)), + } + } + + fn get_span(&self) -> Option { + use FieldElementExpression::*; + match self { + Select(e) => e.get_span(), + Identifier(e) => e.get_span(), + Conditional(e) => e.get_span(), + Add(e) => e.get_span(), + Value(e) => e.get_span(), + Sub(e) => e.get_span(), + Mult(e) => e.get_span(), + Div(e) => e.get_span(), + Pow(e) => e.get_span(), + And(e) => e.get_span(), + Or(e) => e.get_span(), + Xor(e) => e.get_span(), + LeftShift(e) => e.get_span(), + RightShift(e) => e.get_span(), + } + } +} + +impl<'ast, T> WithSpan for BooleanExpression<'ast, T> { + fn span(self, span: Option) -> Self { + use BooleanExpression::*; + match self { + Select(e) => Select(e.span(span)), + Identifier(e) => Identifier(e.span(span)), + Conditional(e) => Conditional(e.span(span)), + Value(e) => Value(e.span(span)), + FieldLt(e) => FieldLt(e.span(span)), + FieldLe(e) => FieldLe(e.span(span)), + FieldEq(e) => FieldEq(e.span(span)), + UintLt(e) => UintLt(e.span(span)), + UintLe(e) => UintLe(e.span(span)), + UintEq(e) => UintEq(e.span(span)), + BoolEq(e) => BoolEq(e.span(span)), + Or(e) => Or(e.span(span)), + And(e) => And(e.span(span)), + Not(e) => Not(e.span(span)), + } + } + + fn get_span(&self) -> Option { + use BooleanExpression::*; + match self { + Select(e) => e.get_span(), + Identifier(e) => e.get_span(), + Conditional(e) => e.get_span(), + Value(e) => e.get_span(), + FieldLt(e) => e.get_span(), + FieldLe(e) => e.get_span(), + FieldEq(e) => e.get_span(), + UintLt(e) => e.get_span(), + UintLe(e) => e.get_span(), + UintEq(e) => e.get_span(), + BoolEq(e) => e.get_span(), + Or(e) => e.get_span(), + And(e) => e.get_span(), + Not(e) => e.get_span(), + } + } +} + +impl<'ast, T> WithSpan for UExpression<'ast, T> { + fn span(self, span: Option) -> Self { + Self { + inner: self.inner.span(span), + ..self + } + } + + fn get_span(&self) -> Option { + self.inner.get_span() + } +} + +impl<'ast, T> WithSpan for UExpressionInner<'ast, T> { + fn span(self, span: Option) -> Self { + use UExpressionInner::*; + match self { + Select(e) => Select(e.span(span)), + Identifier(e) => Identifier(e.span(span)), + Conditional(e) => Conditional(e.span(span)), + Value(e) => Value(e.span(span)), + Add(e) => Add(e.span(span)), + Sub(e) => Sub(e.span(span)), + Mult(e) => Mult(e.span(span)), + Div(e) => Div(e.span(span)), + Rem(e) => Rem(e.span(span)), + Xor(e) => Xor(e.span(span)), + And(e) => And(e.span(span)), + Or(e) => Or(e.span(span)), + LeftShift(e) => LeftShift(e.span(span)), + RightShift(e) => RightShift(e.span(span)), + Not(e) => Not(e.span(span)), + } + } + + fn get_span(&self) -> Option { + use UExpressionInner::*; + match self { + Select(e) => e.get_span(), + Identifier(e) => e.get_span(), + Conditional(e) => e.get_span(), + Value(e) => e.get_span(), + Add(e) => e.get_span(), + Sub(e) => e.get_span(), + Mult(e) => e.get_span(), + Div(e) => e.get_span(), + Rem(e) => e.get_span(), + Xor(e) => e.get_span(), + And(e) => e.get_span(), + Or(e) => e.get_span(), + LeftShift(e) => e.get_span(), + RightShift(e) => e.get_span(), + Not(e) => e.get_span(), + } + } +} + impl<'ast, T: Field> Constant for FieldElementExpression<'ast, T> { fn is_constant(&self) -> bool { - matches!(self, FieldElementExpression::Number(..)) + matches!(self, FieldElementExpression::Value(..)) } } diff --git a/zokrates_ast/src/zir/parameter.rs b/zokrates_ast/src/zir/parameter.rs index 203a291a7..ac413e54a 100644 --- a/zokrates_ast/src/zir/parameter.rs +++ b/zokrates_ast/src/zir/parameter.rs @@ -1,33 +1,3 @@ -use crate::zir::Variable; -use serde::{Deserialize, Serialize}; -use std::fmt; +use super::Variable; -#[derive(Clone, PartialEq, Hash, Eq, Serialize, Deserialize)] -pub struct Parameter<'ast> { - #[serde(borrow)] - pub id: Variable<'ast>, - pub private: bool, -} - -impl<'ast> Parameter<'ast> { - #[cfg(test)] - pub fn private(v: Variable<'ast>) -> Self { - Parameter { - id: v, - private: true, - } - } -} - -impl<'ast> fmt::Display for Parameter<'ast> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let visibility = if self.private { "private " } else { "" }; - write!(f, "{}{} {}", visibility, self.id.get_type(), self.id.id) - } -} - -impl<'ast> fmt::Debug for Parameter<'ast> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Parameter(variable: {:?})", self.id) - } -} +pub type Parameter<'ast> = crate::common::Parameter>; diff --git a/zokrates_ast/src/zir/result_folder.rs b/zokrates_ast/src/zir/result_folder.rs index 6ea741cf6..d368d972d 100644 --- a/zokrates_ast/src/zir/result_folder.rs +++ b/zokrates_ast/src/zir/result_folder.rs @@ -1,27 +1,30 @@ // Generic walk through ZIR. Not mutating in place +use crate::common::expressions::{BinaryOrExpression, IdentifierOrExpression, UnaryOrExpression}; +use crate::common::ResultFold; +use crate::common::WithSpan; use crate::zir::types::UBitwidth; use crate::zir::*; use zokrates_field::Field; -pub trait ResultFold<'ast, T: Field>: Sized { - fn fold>(self, f: &mut F) -> Result; -} - -impl<'ast, T: Field> ResultFold<'ast, T> for FieldElementExpression<'ast, T> { - fn fold>(self, f: &mut F) -> Result { +impl<'ast, T: Field, F: ResultFolder<'ast, T>> ResultFold + for FieldElementExpression<'ast, T> +{ + fn fold(self, f: &mut F) -> Result { f.fold_field_expression(self) } } -impl<'ast, T: Field> ResultFold<'ast, T> for BooleanExpression<'ast, T> { - fn fold>(self, f: &mut F) -> Result { +impl<'ast, T: Field, F: ResultFolder<'ast, T>> ResultFold + for BooleanExpression<'ast, T> +{ + fn fold(self, f: &mut F) -> Result { f.fold_boolean_expression(self) } } -impl<'ast, T: Field> ResultFold<'ast, T> for UExpression<'ast, T> { - fn fold>(self, f: &mut F) -> Result { +impl<'ast, T: Field, F: ResultFolder<'ast, T>> ResultFold for UExpression<'ast, T> { + fn fold(self, f: &mut F) -> Result { f.fold_uint_expression(self) } } @@ -61,6 +64,20 @@ pub trait ResultFolder<'ast, T: Field>: Sized { self.fold_variable(a) } + fn fold_assembly_constraint( + &mut self, + s: AssemblyConstraint<'ast, T>, + ) -> Result>, Self::Error> { + fold_assembly_constraint(self, s) + } + + fn fold_assembly_assignment( + &mut self, + s: AssemblyAssignment<'ast, T>, + ) -> Result>, Self::Error> { + fold_assembly_assignment(self, s) + } + fn fold_assembly_statement( &mut self, s: ZirAssemblyStatement<'ast, T>, @@ -68,6 +85,13 @@ pub trait ResultFolder<'ast, T: Field>: Sized { fold_assembly_statement(self, s) } + fn fold_assembly_statement_cases( + &mut self, + s: ZirAssemblyStatement<'ast, T>, + ) -> Result>, Self::Error> { + fold_assembly_statement_cases(self, s) + } + fn fold_statement( &mut self, s: ZirStatement<'ast, T>, @@ -75,6 +99,62 @@ pub trait ResultFolder<'ast, T: Field>: Sized { fold_statement(self, s) } + fn fold_statement_cases( + &mut self, + s: ZirStatement<'ast, T>, + ) -> Result>, Self::Error> { + fold_statement_cases(self, s) + } + + fn fold_definition_statement( + &mut self, + s: DefinitionStatement<'ast, T>, + ) -> Result>, Self::Error> { + fold_definition_statement(self, s) + } + + fn fold_multiple_definition_statement( + &mut self, + s: MultipleDefinitionStatement<'ast, T>, + ) -> Result>, Self::Error> { + fold_multiple_definition_statement(self, s) + } + + fn fold_return_statement( + &mut self, + s: ReturnStatement<'ast, T>, + ) -> Result>, Self::Error> { + fold_return_statement(self, s) + } + + fn fold_log_statement( + &mut self, + s: LogStatement<'ast, T>, + ) -> Result>, Self::Error> { + fold_log_statement(self, s) + } + + fn fold_assembly_block( + &mut self, + s: AssemblyBlockStatement<'ast, T>, + ) -> Result>, Self::Error> { + fold_assembly_block(self, s) + } + + fn fold_assertion_statement( + &mut self, + s: AssertionStatement<'ast, T>, + ) -> Result>, Self::Error> { + fold_assertion_statement(self, s) + } + + fn fold_if_else_statement( + &mut self, + s: IfElseStatement<'ast, T>, + ) -> Result>, Self::Error> { + fold_if_else_statement(self, s) + } + fn fold_expression( &mut self, e: ZirExpression<'ast, T>, @@ -104,16 +184,18 @@ pub trait ResultFolder<'ast, T: Field>: Sized { } } - fn fold_identifier_expression + Id<'ast, T> + ResultFold<'ast, T>>( + fn fold_identifier_expression< + E: Expr<'ast, T> + Id<'ast, T> + ResultFold, + >( &mut self, ty: &E::Ty, id: IdentifierExpression<'ast, E>, - ) -> Result, Self::Error> { + ) -> Result, E, E::Inner>, Self::Error> { fold_identifier_expression(self, ty, id) } fn fold_conditional_expression< - E: Expr<'ast, T> + ResultFold<'ast, T> + Conditional<'ast, T>, + E: Expr<'ast, T> + ResultFold + Conditional<'ast, T>, >( &mut self, ty: &E::Ty, @@ -122,7 +204,35 @@ pub trait ResultFolder<'ast, T: Field>: Sized { fold_conditional_expression(self, ty, e) } - fn fold_select_expression + ResultFold<'ast, T> + Select<'ast, T>>( + #[allow(clippy::type_complexity)] + fn fold_binary_expression< + L: Expr<'ast, T> + PartialEq + ResultFold, + R: Expr<'ast, T> + PartialEq + ResultFold, + E: Expr<'ast, T> + PartialEq + ResultFold, + Op, + >( + &mut self, + ty: &E::Ty, + e: BinaryExpression, + ) -> Result, Self::Error> { + fold_binary_expression(self, ty, e) + } + + fn fold_unary_expression< + In: Expr<'ast, T> + PartialEq + ResultFold, + E: Expr<'ast, T> + PartialEq + ResultFold, + Op, + >( + &mut self, + ty: &E::Ty, + e: UnaryExpression, + ) -> Result, Self::Error> { + fold_unary_expression(self, ty, e) + } + + fn fold_select_expression< + E: Clone + Expr<'ast, T> + ResultFold + Select<'ast, T>, + >( &mut self, ty: &E::Ty, e: SelectExpression<'ast, T, E>, @@ -137,6 +247,13 @@ pub trait ResultFolder<'ast, T: Field>: Sized { fold_field_expression(self, e) } + fn fold_field_expression_cases( + &mut self, + e: FieldElementExpression<'ast, T>, + ) -> Result, Self::Error> { + fold_field_expression_cases(self, e) + } + fn fold_boolean_expression( &mut self, e: BooleanExpression<'ast, T>, @@ -144,6 +261,13 @@ pub trait ResultFolder<'ast, T: Field>: Sized { fold_boolean_expression(self, e) } + fn fold_boolean_expression_cases( + &mut self, + e: BooleanExpression<'ast, T>, + ) -> Result, Self::Error> { + fold_boolean_expression_cases(self, e) + } + fn fold_uint_expression( &mut self, e: UExpression<'ast, T>, @@ -158,102 +282,213 @@ pub trait ResultFolder<'ast, T: Field>: Sized { ) -> Result, Self::Error> { fold_uint_expression_inner(self, bitwidth, e) } + + fn fold_uint_expression_cases( + &mut self, + bitwidth: UBitwidth, + e: UExpressionInner<'ast, T>, + ) -> Result, Self::Error> { + fold_uint_expression_cases(self, bitwidth, e) + } +} + +pub fn fold_assembly_assignment<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + s: AssemblyAssignment<'ast, T>, +) -> Result>, F::Error> { + let assignees = s + .assignee + .into_iter() + .map(|a| f.fold_assignee(a)) + .collect::>()?; + let expression = f.fold_function(s.expression)?; + Ok(vec![ZirAssemblyStatement::assignment( + assignees, expression, + )]) +} + +pub fn fold_assembly_constraint<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + s: AssemblyConstraint<'ast, T>, +) -> Result>, F::Error> { + let left = f.fold_field_expression(s.left)?; + let right = f.fold_field_expression(s.right)?; + Ok(vec![ZirAssemblyStatement::constraint( + left, right, s.metadata, + )]) } -pub fn fold_assembly_statement<'ast, T: Field, F: ResultFolder<'ast, T>>( + +fn fold_assembly_statement<'ast, T: Field, F: ResultFolder<'ast, T>>( f: &mut F, s: ZirAssemblyStatement<'ast, T>, ) -> Result>, F::Error> { - Ok(match s { - ZirAssemblyStatement::Assignment(assignees, function) => { - let assignees = assignees - .into_iter() - .map(|a| f.fold_assignee(a)) - .collect::>()?; - let function = f.fold_function(function)?; - vec![ZirAssemblyStatement::Assignment(assignees, function)] - } - ZirAssemblyStatement::Constraint(lhs, rhs, metadata) => { - let lhs = f.fold_field_expression(lhs)?; - let rhs = f.fold_field_expression(rhs)?; - vec![ZirAssemblyStatement::Constraint(lhs, rhs, metadata)] - } - }) + let span = s.get_span(); + f.fold_assembly_statement_cases(s) + .map(|s| s.into_iter().map(|s| s.span(span)).collect()) +} + +pub fn fold_assembly_statement_cases<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + s: ZirAssemblyStatement<'ast, T>, +) -> Result>, F::Error> { + match s { + ZirAssemblyStatement::Assignment(s) => f.fold_assembly_assignment(s), + ZirAssemblyStatement::Constraint(s) => f.fold_assembly_constraint(s), + } } pub fn fold_statement<'ast, T: Field, F: ResultFolder<'ast, T>>( f: &mut F, s: ZirStatement<'ast, T>, ) -> Result>, F::Error> { - let res = match s { - ZirStatement::Return(expressions) => ZirStatement::Return( - expressions + let span = s.get_span(); + f.fold_statement_cases(s) + .map(|s| s.into_iter().map(|s| s.span(span)).collect()) +} + +pub fn fold_statement_cases<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + s: ZirStatement<'ast, T>, +) -> Result>, F::Error> { + let span = s.get_span(); + + match s { + ZirStatement::Return(s) => f.fold_return_statement(s), + ZirStatement::Definition(s) => f.fold_definition_statement(s), + ZirStatement::IfElse(s) => f.fold_if_else_statement(s), + ZirStatement::Assertion(s) => f.fold_assertion_statement(s), + ZirStatement::MultipleDefinition(s) => f.fold_multiple_definition_statement(s), + ZirStatement::Log(s) => f.fold_log_statement(s), + ZirStatement::Assembly(s) => f.fold_assembly_block(s), + } + .map(|s| s.into_iter().map(|s| s.span(span)).collect()) +} + +pub fn fold_return_statement<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + s: ReturnStatement<'ast, T>, +) -> Result>, F::Error> { + Ok(vec![ZirStatement::Return( + ReturnStatement::new( + s.inner .into_iter() .map(|e| f.fold_expression(e)) .collect::>()?, - ), - ZirStatement::Definition(a, e) => { - ZirStatement::Definition(f.fold_assignee(a)?, f.fold_expression(e)?) - } - ZirStatement::IfElse(condition, consequence, alternative) => ZirStatement::IfElse( - f.fold_boolean_expression(condition)?, - consequence + ) + .span(s.span), + )]) +} + +pub fn fold_definition_statement<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + s: DefinitionStatement<'ast, T>, +) -> Result>, F::Error> { + let rhs = f.fold_expression(s.rhs)?; + Ok(vec![ZirStatement::Definition( + DefinitionStatement::new(f.fold_assignee(s.assignee)?, rhs).span(s.span), + )]) +} + +pub fn fold_if_else_statement<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + s: IfElseStatement<'ast, T>, +) -> Result>, F::Error> { + Ok(vec![ZirStatement::IfElse( + IfElseStatement::new( + f.fold_boolean_expression(s.condition)?, + s.consequence .into_iter() .map(|s| f.fold_statement(s)) .collect::, _>>()? .into_iter() .flatten() .collect(), - alternative + s.alternative .into_iter() .map(|s| f.fold_statement(s)) .collect::, _>>()? .into_iter() .flatten() .collect(), - ), - ZirStatement::Assertion(e, error) => { - ZirStatement::Assertion(f.fold_boolean_expression(e)?, error) - } - ZirStatement::MultipleDefinition(variables, elist) => ZirStatement::MultipleDefinition( - variables + ) + .span(s.span), + )]) +} + +pub fn fold_assertion_statement<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + s: AssertionStatement<'ast, T>, +) -> Result>, F::Error> { + Ok(vec![ZirStatement::Assertion( + AssertionStatement::new(f.fold_boolean_expression(s.expression)?, s.error).span(s.span), + )]) +} + +pub fn fold_log_statement<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + s: LogStatement<'ast, T>, +) -> Result>, F::Error> { + let expressions = s + .expressions + .into_iter() + .map(|(t, e)| { + e.into_iter() + .map(|e| f.fold_expression(e)) + .collect::, _>>() + .map(|e| (t, e)) + }) + .collect::, _>>()?; + Ok(vec![ZirStatement::Log(LogStatement::new( + s.format_string, + expressions, + ))]) +} + +pub fn fold_assembly_block<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + s: AssemblyBlockStatement<'ast, T>, +) -> Result>, F::Error> { + Ok(vec![ZirStatement::Assembly(AssemblyBlockStatement::new( + s.inner + .into_iter() + .map(|s| f.fold_assembly_statement(s)) + .collect::, _>>()? + .into_iter() + .flatten() + .collect(), + ))]) +} + +pub fn fold_multiple_definition_statement<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + s: MultipleDefinitionStatement<'ast, T>, +) -> Result>, F::Error> { + let expression_list = f.fold_expression_list(s.rhs)?; + Ok(vec![ZirStatement::MultipleDefinition( + MultipleDefinitionStatement::new( + s.assignees .into_iter() .map(|v| f.fold_assignee(v)) .collect::>()?, - f.fold_expression_list(elist)?, + expression_list, ), - ZirStatement::Log(l, e) => { - let e = e - .into_iter() - .map(|(t, e)| { - e.into_iter() - .map(|e| f.fold_expression(e)) - .collect::, _>>() - .map(|e| (t, e)) - }) - .collect::, _>>()?; - - ZirStatement::Log(l, e) - } - ZirStatement::Assembly(statements) => { - let statements = statements - .into_iter() - .map(|s| f.fold_assembly_statement(s)) - .collect::, _>>()? - .into_iter() - .flatten() - .collect(); - ZirStatement::Assembly(statements) - } - }; - Ok(vec![res]) + )]) +} + +fn fold_field_expression<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + e: FieldElementExpression<'ast, T>, +) -> Result, F::Error> { + let span = e.get_span(); + f.fold_field_expression_cases(e).map(|e| e.span(span)) } -pub fn fold_field_expression<'ast, T: Field, F: ResultFolder<'ast, T>>( +pub fn fold_field_expression_cases<'ast, T: Field, F: ResultFolder<'ast, T>>( f: &mut F, e: FieldElementExpression<'ast, T>, ) -> Result, F::Error> { Ok(match e { - FieldElementExpression::Number(n) => FieldElementExpression::Number(n), + FieldElementExpression::Value(n) => FieldElementExpression::Value(n), FieldElementExpression::Identifier(id) => { match f.fold_identifier_expression(&Type::FieldElement, id)? { IdentifierOrExpression::Identifier(i) => FieldElementExpression::Identifier(i), @@ -266,60 +501,63 @@ pub fn fold_field_expression<'ast, T: Field, F: ResultFolder<'ast, T>>( SelectOrExpression::Expression(u) => u, } } - FieldElementExpression::Add(box e1, box e2) => { - let e1 = f.fold_field_expression(e1)?; - let e2 = f.fold_field_expression(e2)?; - FieldElementExpression::Add(box e1, box e2) - } - FieldElementExpression::Sub(box e1, box e2) => { - let e1 = f.fold_field_expression(e1)?; - let e2 = f.fold_field_expression(e2)?; - FieldElementExpression::Sub(box e1, box e2) + FieldElementExpression::Add(e) => { + match f.fold_binary_expression(&Type::FieldElement, e)? { + BinaryOrExpression::Binary(e) => FieldElementExpression::Add(e), + BinaryOrExpression::Expression(e) => e, + } } - FieldElementExpression::Mult(box e1, box e2) => { - let e1 = f.fold_field_expression(e1)?; - let e2 = f.fold_field_expression(e2)?; - FieldElementExpression::Mult(box e1, box e2) + FieldElementExpression::Sub(e) => { + match f.fold_binary_expression(&Type::FieldElement, e)? { + BinaryOrExpression::Binary(e) => FieldElementExpression::Sub(e), + BinaryOrExpression::Expression(e) => e, + } } - FieldElementExpression::Div(box e1, box e2) => { - let e1 = f.fold_field_expression(e1)?; - let e2 = f.fold_field_expression(e2)?; - FieldElementExpression::Div(box e1, box e2) + FieldElementExpression::Mult(e) => { + match f.fold_binary_expression(&Type::FieldElement, e)? { + BinaryOrExpression::Binary(e) => FieldElementExpression::Mult(e), + BinaryOrExpression::Expression(e) => e, + } } - FieldElementExpression::Pow(box e1, box e2) => { - let e1 = f.fold_field_expression(e1)?; - let e2 = f.fold_uint_expression(e2)?; - FieldElementExpression::Pow(box e1, box e2) + FieldElementExpression::Div(e) => { + match f.fold_binary_expression(&Type::FieldElement, e)? { + BinaryOrExpression::Binary(e) => FieldElementExpression::Div(e), + BinaryOrExpression::Expression(e) => e, + } } - FieldElementExpression::Xor(box left, box right) => { - let left = f.fold_field_expression(left)?; - let right = f.fold_field_expression(right)?; - - FieldElementExpression::Xor(box left, box right) + FieldElementExpression::Pow(e) => { + match f.fold_binary_expression(&Type::FieldElement, e)? { + BinaryOrExpression::Binary(e) => FieldElementExpression::Pow(e), + BinaryOrExpression::Expression(e) => e, + } } - FieldElementExpression::And(box left, box right) => { - let left = f.fold_field_expression(left)?; - let right = f.fold_field_expression(right)?; - - FieldElementExpression::And(box left, box right) + FieldElementExpression::And(e) => { + match f.fold_binary_expression(&Type::FieldElement, e)? { + BinaryOrExpression::Binary(e) => FieldElementExpression::And(e), + BinaryOrExpression::Expression(e) => e, + } } - FieldElementExpression::Or(box left, box right) => { - let left = f.fold_field_expression(left)?; - let right = f.fold_field_expression(right)?; - - FieldElementExpression::Or(box left, box right) + FieldElementExpression::Or(e) => match f.fold_binary_expression(&Type::FieldElement, e)? { + BinaryOrExpression::Binary(e) => FieldElementExpression::Or(e), + BinaryOrExpression::Expression(e) => e, + }, + FieldElementExpression::Xor(e) => { + match f.fold_binary_expression(&Type::FieldElement, e)? { + BinaryOrExpression::Binary(e) => FieldElementExpression::Xor(e), + BinaryOrExpression::Expression(e) => e, + } } - FieldElementExpression::LeftShift(box e, box by) => { - let e = f.fold_field_expression(e)?; - let by = f.fold_uint_expression(by)?; - - FieldElementExpression::LeftShift(box e, box by) + FieldElementExpression::LeftShift(e) => { + match f.fold_binary_expression(&Type::FieldElement, e)? { + BinaryOrExpression::Binary(e) => FieldElementExpression::LeftShift(e), + BinaryOrExpression::Expression(e) => e, + } } - FieldElementExpression::RightShift(box e, box by) => { - let e = f.fold_field_expression(e)?; - let by = f.fold_uint_expression(by)?; - - FieldElementExpression::RightShift(box e, box by) + FieldElementExpression::RightShift(e) => { + match f.fold_binary_expression(&Type::FieldElement, e)? { + BinaryOrExpression::Binary(e) => FieldElementExpression::RightShift(e), + BinaryOrExpression::Expression(e) => e, + } } FieldElementExpression::Conditional(c) => { match f.fold_conditional_expression(&Type::FieldElement, c)? { @@ -330,10 +568,20 @@ pub fn fold_field_expression<'ast, T: Field, F: ResultFolder<'ast, T>>( }) } -pub fn fold_boolean_expression<'ast, T: Field, F: ResultFolder<'ast, T>>( +fn fold_boolean_expression<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + e: BooleanExpression<'ast, T>, +) -> Result, F::Error> { + let span = e.get_span(); + f.fold_boolean_expression_cases(e).map(|e| e.span(span)) +} + +pub fn fold_boolean_expression_cases<'ast, T: Field, F: ResultFolder<'ast, T>>( f: &mut F, e: BooleanExpression<'ast, T>, ) -> Result, F::Error> { + use BooleanExpression::*; + Ok(match e { BooleanExpression::Value(v) => BooleanExpression::Value(v), BooleanExpression::Identifier(id) => { @@ -346,55 +594,46 @@ pub fn fold_boolean_expression<'ast, T: Field, F: ResultFolder<'ast, T>>( SelectOrExpression::Select(s) => BooleanExpression::Select(s), SelectOrExpression::Expression(u) => u, }, - BooleanExpression::FieldEq(box e1, box e2) => { - let e1 = f.fold_field_expression(e1)?; - let e2 = f.fold_field_expression(e2)?; - BooleanExpression::FieldEq(box e1, box e2) - } - BooleanExpression::BoolEq(box e1, box e2) => { - let e1 = f.fold_boolean_expression(e1)?; - let e2 = f.fold_boolean_expression(e2)?; - BooleanExpression::BoolEq(box e1, box e2) - } - BooleanExpression::UintEq(box e1, box e2) => { - let e1 = f.fold_uint_expression(e1)?; - let e2 = f.fold_uint_expression(e2)?; - BooleanExpression::UintEq(box e1, box e2) - } - BooleanExpression::FieldLt(box e1, box e2) => { - let e1 = f.fold_field_expression(e1)?; - let e2 = f.fold_field_expression(e2)?; - BooleanExpression::FieldLt(box e1, box e2) - } - BooleanExpression::UintLt(box e1, box e2) => { - let e1 = f.fold_uint_expression(e1)?; - let e2 = f.fold_uint_expression(e2)?; - BooleanExpression::UintLt(box e1, box e2) - } - BooleanExpression::FieldLe(box e1, box e2) => { - let e1 = f.fold_field_expression(e1)?; - let e2 = f.fold_field_expression(e2)?; - BooleanExpression::FieldLe(box e1, box e2) - } - BooleanExpression::UintLe(box e1, box e2) => { - let e1 = f.fold_uint_expression(e1)?; - let e2 = f.fold_uint_expression(e2)?; - BooleanExpression::UintLe(box e1, box e2) - } - BooleanExpression::Or(box e1, box e2) => { - let e1 = f.fold_boolean_expression(e1)?; - let e2 = f.fold_boolean_expression(e2)?; - BooleanExpression::Or(box e1, box e2) - } - BooleanExpression::And(box e1, box e2) => { - let e1 = f.fold_boolean_expression(e1)?; - let e2 = f.fold_boolean_expression(e2)?; - BooleanExpression::And(box e1, box e2) - } - BooleanExpression::Not(box e) => { - let e = f.fold_boolean_expression(e)?; - BooleanExpression::Not(box e) - } + FieldEq(e) => match f.fold_binary_expression(&Type::Boolean, e)? { + BinaryOrExpression::Binary(e) => FieldEq(e), + BinaryOrExpression::Expression(u) => u, + }, + BoolEq(e) => match f.fold_binary_expression(&Type::Boolean, e)? { + BinaryOrExpression::Binary(e) => BoolEq(e), + BinaryOrExpression::Expression(u) => u, + }, + UintEq(e) => match f.fold_binary_expression(&Type::Boolean, e)? { + BinaryOrExpression::Binary(e) => UintEq(e), + BinaryOrExpression::Expression(u) => u, + }, + FieldLt(e) => match f.fold_binary_expression(&Type::Boolean, e)? { + BinaryOrExpression::Binary(e) => FieldLt(e), + BinaryOrExpression::Expression(u) => u, + }, + FieldLe(e) => match f.fold_binary_expression(&Type::Boolean, e)? { + BinaryOrExpression::Binary(e) => FieldLe(e), + BinaryOrExpression::Expression(u) => u, + }, + UintLt(e) => match f.fold_binary_expression(&Type::Boolean, e)? { + BinaryOrExpression::Binary(e) => UintLt(e), + BinaryOrExpression::Expression(u) => u, + }, + UintLe(e) => match f.fold_binary_expression(&Type::Boolean, e)? { + BinaryOrExpression::Binary(e) => UintLe(e), + BinaryOrExpression::Expression(u) => u, + }, + Or(e) => match f.fold_binary_expression(&Type::Boolean, e)? { + BinaryOrExpression::Binary(e) => Or(e), + BinaryOrExpression::Expression(u) => u, + }, + And(e) => match f.fold_binary_expression(&Type::Boolean, e)? { + BinaryOrExpression::Binary(e) => And(e), + BinaryOrExpression::Expression(u) => u, + }, + Not(e) => match f.fold_unary_expression(&Type::Boolean, e)? { + UnaryOrExpression::Unary(e) => Not(e), + UnaryOrExpression::Expression(u) => u, + }, BooleanExpression::Conditional(c) => { match f.fold_conditional_expression(&Type::Boolean, c)? { ConditionalOrExpression::Conditional(s) => BooleanExpression::Conditional(s), @@ -414,86 +653,78 @@ pub fn fold_uint_expression<'ast, T: Field, F: ResultFolder<'ast, T>>( }) } -pub fn fold_uint_expression_inner<'ast, T: Field, F: ResultFolder<'ast, T>>( +fn fold_uint_expression_inner<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + ty: UBitwidth, + e: UExpressionInner<'ast, T>, +) -> Result, F::Error> { + let span = e.get_span(); + f.fold_uint_expression_cases(ty, e).map(|e| e.span(span)) +} + +pub fn fold_uint_expression_cases<'ast, T: Field, F: ResultFolder<'ast, T>>( f: &mut F, ty: UBitwidth, e: UExpressionInner<'ast, T>, ) -> Result, F::Error> { + use UExpressionInner::*; + Ok(match e { - UExpressionInner::Value(v) => UExpressionInner::Value(v), - UExpressionInner::Identifier(id) => match f.fold_identifier_expression(&ty, id)? { + Value(v) => UExpressionInner::Value(v), + Identifier(id) => match f.fold_identifier_expression(&ty, id)? { IdentifierOrExpression::Identifier(i) => UExpressionInner::Identifier(i), IdentifierOrExpression::Expression(e) => e, }, - UExpressionInner::Select(e) => match f.fold_select_expression(&ty, e)? { + Select(e) => match f.fold_select_expression(&ty, e)? { SelectOrExpression::Select(s) => UExpressionInner::Select(s), SelectOrExpression::Expression(u) => u, }, - UExpressionInner::Add(box left, box right) => { - let left = f.fold_uint_expression(left)?; - let right = f.fold_uint_expression(right)?; - - UExpressionInner::Add(box left, box right) - } - UExpressionInner::Sub(box left, box right) => { - let left = f.fold_uint_expression(left)?; - let right = f.fold_uint_expression(right)?; - - UExpressionInner::Sub(box left, box right) - } - UExpressionInner::Mult(box left, box right) => { - let left = f.fold_uint_expression(left)?; - let right = f.fold_uint_expression(right)?; - - UExpressionInner::Mult(box left, box right) - } - UExpressionInner::Div(box left, box right) => { - let left = f.fold_uint_expression(left)?; - let right = f.fold_uint_expression(right)?; - - UExpressionInner::Div(box left, box right) - } - UExpressionInner::Rem(box left, box right) => { - let left = f.fold_uint_expression(left)?; - let right = f.fold_uint_expression(right)?; - - UExpressionInner::Rem(box left, box right) - } - UExpressionInner::Xor(box left, box right) => { - let left = f.fold_uint_expression(left)?; - let right = f.fold_uint_expression(right)?; - - UExpressionInner::Xor(box left, box right) - } - UExpressionInner::And(box left, box right) => { - let left = f.fold_uint_expression(left)?; - let right = f.fold_uint_expression(right)?; - - UExpressionInner::And(box left, box right) - } - UExpressionInner::Or(box left, box right) => { - let left = f.fold_uint_expression(left)?; - let right = f.fold_uint_expression(right)?; - - UExpressionInner::Or(box left, box right) - } - UExpressionInner::LeftShift(box e, by) => { - let e = f.fold_uint_expression(e)?; - - UExpressionInner::LeftShift(box e, by) - } - UExpressionInner::RightShift(box e, by) => { - let e = f.fold_uint_expression(e)?; - - UExpressionInner::RightShift(box e, by) - } - UExpressionInner::Not(box e) => { - let e = f.fold_uint_expression(e)?; - - UExpressionInner::Not(box e) - } - UExpressionInner::Conditional(c) => match f.fold_conditional_expression(&ty, c)? { - ConditionalOrExpression::Conditional(s) => UExpressionInner::Conditional(s), + Add(e) => match f.fold_binary_expression(&ty, e)? { + BinaryOrExpression::Binary(e) => Add(e), + BinaryOrExpression::Expression(u) => u, + }, + Sub(e) => match f.fold_binary_expression(&ty, e)? { + BinaryOrExpression::Binary(e) => Sub(e), + BinaryOrExpression::Expression(u) => u, + }, + Mult(e) => match f.fold_binary_expression(&ty, e)? { + BinaryOrExpression::Binary(e) => Mult(e), + BinaryOrExpression::Expression(u) => u, + }, + Div(e) => match f.fold_binary_expression(&ty, e)? { + BinaryOrExpression::Binary(e) => Div(e), + BinaryOrExpression::Expression(u) => u, + }, + Rem(e) => match f.fold_binary_expression(&ty, e)? { + BinaryOrExpression::Binary(e) => Rem(e), + BinaryOrExpression::Expression(u) => u, + }, + Xor(e) => match f.fold_binary_expression(&ty, e)? { + BinaryOrExpression::Binary(e) => Xor(e), + BinaryOrExpression::Expression(u) => u, + }, + And(e) => match f.fold_binary_expression(&ty, e)? { + BinaryOrExpression::Binary(e) => And(e), + BinaryOrExpression::Expression(u) => u, + }, + Or(e) => match f.fold_binary_expression(&ty, e)? { + BinaryOrExpression::Binary(e) => Or(e), + BinaryOrExpression::Expression(u) => u, + }, + LeftShift(e) => match f.fold_binary_expression(&ty, e)? { + BinaryOrExpression::Binary(e) => LeftShift(e), + BinaryOrExpression::Expression(u) => u, + }, + RightShift(e) => match f.fold_binary_expression(&ty, e)? { + BinaryOrExpression::Binary(e) => RightShift(e), + BinaryOrExpression::Expression(u) => u, + }, + Not(e) => match f.fold_unary_expression(&ty, e)? { + UnaryOrExpression::Unary(e) => Not(e), + UnaryOrExpression::Expression(u) => u, + }, + Conditional(c) => match f.fold_conditional_expression(&ty, c)? { + ConditionalOrExpression::Conditional(s) => Conditional(s), ConditionalOrExpression::Expression(u) => u, }, }) @@ -527,6 +758,7 @@ pub fn fold_program<'ast, T: Field, F: ResultFolder<'ast, T>>( ) -> Result, F::Error> { Ok(ZirProgram { main: f.fold_function(p.main)?, + ..p }) } @@ -539,7 +771,7 @@ pub fn fold_identifier_expression< f: &mut F, _: &E::Ty, e: IdentifierExpression<'ast, E>, -) -> Result, F::Error> { +) -> Result, E, E::Inner>, F::Error> { Ok(IdentifierOrExpression::Identifier( IdentifierExpression::new(f.fold_name(e.id)?), )) @@ -548,7 +780,7 @@ pub fn fold_identifier_expression< pub fn fold_conditional_expression< 'ast, T: Field, - E: Expr<'ast, T> + ResultFold<'ast, T> + Conditional<'ast, T>, + E: Expr<'ast, T> + ResultFold + Conditional<'ast, T>, F: ResultFolder<'ast, T>, >( f: &mut F, @@ -567,7 +799,7 @@ pub fn fold_conditional_expression< pub fn fold_select_expression< 'ast, T: Field, - E: Expr<'ast, T> + ResultFold<'ast, T> + Select<'ast, T>, + E: Expr<'ast, T> + ResultFold + Select<'ast, T>, F: ResultFolder<'ast, T>, >( f: &mut F, @@ -582,3 +814,39 @@ pub fn fold_select_expression< e.index.fold(f)?, ))) } + +#[allow(clippy::type_complexity)] +pub fn fold_binary_expression< + 'ast, + T: Field, + L: Expr<'ast, T> + PartialEq + ResultFold + From>, + R: Expr<'ast, T> + PartialEq + ResultFold + From>, + E: Expr<'ast, T> + PartialEq + ResultFold + From>, + F: ResultFolder<'ast, T>, + Op, +>( + f: &mut F, + _: &E::Ty, + e: BinaryExpression, +) -> Result, F::Error> { + Ok(BinaryOrExpression::Binary( + BinaryExpression::new(e.left.fold(f)?, e.right.fold(f)?).span(e.span), + )) +} + +pub fn fold_unary_expression< + 'ast, + T: Field, + In: Expr<'ast, T> + PartialEq + ResultFold + From>, + E: Expr<'ast, T> + PartialEq + ResultFold + From>, + F: ResultFolder<'ast, T>, + Op, +>( + f: &mut F, + _: &E::Ty, + e: UnaryExpression, +) -> Result, F::Error> { + Ok(UnaryOrExpression::Unary( + UnaryExpression::new(e.inner.fold(f)?).span(e.span), + )) +} diff --git a/zokrates_ast/src/zir/uint.rs b/zokrates_ast/src/zir/uint.rs index 9ae30d40e..3ace2a152 100644 --- a/zokrates_ast/src/zir/uint.rs +++ b/zokrates_ast/src/zir/uint.rs @@ -1,5 +1,7 @@ -use crate::zir::types::UBitwidth; +use crate::common::expressions::{UValueExpression, UnaryExpression, ValueExpression}; use crate::zir::IdentifierExpression; +use crate::{common::expressions::BinaryExpression, common::operators::*, zir::types::UBitwidth}; +use derivative::Derivative; use serde::{Deserialize, Serialize}; use zokrates_field::Field; @@ -10,14 +12,14 @@ impl<'ast, T: Field> UExpression<'ast, T> { pub fn add(self, other: Self) -> UExpression<'ast, T> { let bitwidth = self.bitwidth; assert_eq!(bitwidth, other.bitwidth); - UExpressionInner::Add(box self, box other).annotate(bitwidth) + UExpressionInner::Add(BinaryExpression::new(self, other)).annotate(bitwidth) } #[allow(clippy::should_implement_trait)] pub fn sub(self, other: Self) -> UExpression<'ast, T> { let bitwidth = self.bitwidth; assert_eq!(bitwidth, other.bitwidth); - UExpressionInner::Sub(box self, box other).annotate(bitwidth) + UExpressionInner::Sub(BinaryExpression::new(self, other)).annotate(bitwidth) } pub fn select(values: Vec, index: Self) -> UExpression<'ast, T> { @@ -28,67 +30,67 @@ impl<'ast, T: Field> UExpression<'ast, T> { pub fn mult(self, other: Self) -> UExpression<'ast, T> { let bitwidth = self.bitwidth; assert_eq!(bitwidth, other.bitwidth); - UExpressionInner::Mult(box self, box other).annotate(bitwidth) + UExpressionInner::Mult(BinaryExpression::new(self, other)).annotate(bitwidth) } #[allow(clippy::should_implement_trait)] pub fn div(self, other: Self) -> UExpression<'ast, T> { let bitwidth = self.bitwidth; assert_eq!(bitwidth, other.bitwidth); - UExpressionInner::Div(box self, box other).annotate(bitwidth) + UExpressionInner::Div(BinaryExpression::new(self, other)).annotate(bitwidth) } #[allow(clippy::should_implement_trait)] pub fn rem(self, other: Self) -> UExpression<'ast, T> { let bitwidth = self.bitwidth; assert_eq!(bitwidth, other.bitwidth); - UExpressionInner::Rem(box self, box other).annotate(bitwidth) + UExpressionInner::Rem(BinaryExpression::new(self, other)).annotate(bitwidth) } pub fn xor(self, other: Self) -> UExpression<'ast, T> { let bitwidth = self.bitwidth; assert_eq!(bitwidth, other.bitwidth); - UExpressionInner::Xor(box self, box other).annotate(bitwidth) + UExpressionInner::Xor(BinaryExpression::new(self, other)).annotate(bitwidth) } #[allow(clippy::should_implement_trait)] pub fn not(self) -> UExpression<'ast, T> { let bitwidth = self.bitwidth; - UExpressionInner::Not(box self).annotate(bitwidth) + UExpressionInner::Not(UnaryExpression::new(self)).annotate(bitwidth) } pub fn or(self, other: Self) -> UExpression<'ast, T> { let bitwidth = self.bitwidth; assert_eq!(bitwidth, other.bitwidth); - UExpressionInner::Or(box self, box other).annotate(bitwidth) + UExpressionInner::Or(BinaryExpression::new(self, other)).annotate(bitwidth) } pub fn and(self, other: Self) -> UExpression<'ast, T> { let bitwidth = self.bitwidth; assert_eq!(bitwidth, other.bitwidth); - UExpressionInner::And(box self, box other).annotate(bitwidth) + UExpressionInner::And(BinaryExpression::new(self, other)).annotate(bitwidth) } - pub fn left_shift(self, by: u32) -> UExpression<'ast, T> { + pub fn left_shift(self, by: Self) -> UExpression<'ast, T> { let bitwidth = self.bitwidth; - UExpressionInner::LeftShift(box self, by).annotate(bitwidth) + UExpressionInner::LeftShift(BinaryExpression::new(self, by)).annotate(bitwidth) } - pub fn right_shift(self, by: u32) -> UExpression<'ast, T> { + pub fn right_shift(self, by: Self) -> UExpression<'ast, T> { let bitwidth = self.bitwidth; - UExpressionInner::RightShift(box self, by).annotate(bitwidth) + UExpressionInner::RightShift(BinaryExpression::new(self, by)).annotate(bitwidth) } } -impl<'ast, T: Field> From for UExpressionInner<'ast, T> { +impl<'ast, T> From for UExpressionInner<'ast, T> { fn from(e: u128) -> Self { - UExpressionInner::Value(e) + UExpressionInner::Value(ValueExpression::new(e)) } } impl<'ast, T> From for UExpression<'ast, T> { fn from(u: u32) -> Self { - UExpressionInner::Value(u as u128).annotate(UBitwidth::B32) + UExpressionInner::from(u as u128).annotate(UBitwidth::B32) } } @@ -151,7 +153,7 @@ impl UMetadata { } pub fn bitwidth(&self) -> u32 { - self.max.bits() as u32 + self.max.bits() } // issue the metadata for a parameter of a given bitwidth @@ -163,7 +165,9 @@ impl UMetadata { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Derivative)] +#[derivative(PartialEq, Hash)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct UExpression<'ast, T> { pub bitwidth: UBitwidth, pub metadata: Option>, @@ -171,23 +175,29 @@ pub struct UExpression<'ast, T> { pub inner: UExpressionInner<'ast, T>, } -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Derivative)] +#[derivative(PartialEq, Hash)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub enum UExpressionInner<'ast, T> { - Value(u128), + Value(UValueExpression), #[serde(borrow)] Identifier(IdentifierExpression<'ast, UExpression<'ast, T>>), Select(SelectExpression<'ast, T, UExpression<'ast, T>>), - Add(Box>, Box>), - Sub(Box>, Box>), - Mult(Box>, Box>), - Div(Box>, Box>), - Rem(Box>, Box>), - Xor(Box>, Box>), - And(Box>, Box>), - Or(Box>, Box>), - LeftShift(Box>, u32), - RightShift(Box>, u32), - Not(Box>), + Add(BinaryExpression, UExpression<'ast, T>, UExpression<'ast, T>>), + Sub(BinaryExpression, UExpression<'ast, T>, UExpression<'ast, T>>), + Mult(BinaryExpression, UExpression<'ast, T>, UExpression<'ast, T>>), + Div(BinaryExpression, UExpression<'ast, T>, UExpression<'ast, T>>), + Rem(BinaryExpression, UExpression<'ast, T>, UExpression<'ast, T>>), + Xor(BinaryExpression, UExpression<'ast, T>, UExpression<'ast, T>>), + And(BinaryExpression, UExpression<'ast, T>, UExpression<'ast, T>>), + Or(BinaryExpression, UExpression<'ast, T>, UExpression<'ast, T>>), + LeftShift( + BinaryExpression, UExpression<'ast, T>, UExpression<'ast, T>>, + ), + RightShift( + BinaryExpression, UExpression<'ast, T>, UExpression<'ast, T>>, + ), + Not(UnaryExpression, UExpression<'ast, T>>), Conditional(ConditionalExpression<'ast, T, UExpression<'ast, T>>), } diff --git a/zokrates_ast/src/zir/variable.rs b/zokrates_ast/src/zir/variable.rs index 14d329727..62ee8bb12 100644 --- a/zokrates_ast/src/zir/variable.rs +++ b/zokrates_ast/src/zir/variable.rs @@ -1,14 +1,7 @@ use crate::zir::types::{Type, UBitwidth}; use crate::zir::Identifier; -use serde::{Deserialize, Serialize}; -use std::fmt; -#[derive(Clone, PartialEq, Hash, Eq, Serialize, Deserialize)] -pub struct Variable<'ast> { - #[serde(borrow)] - pub id: Identifier<'ast>, - pub _type: Type, -} +pub type Variable<'ast> = crate::common::Variable, Type>; impl<'ast> Variable<'ast> { pub fn field_element>>(id: I) -> Variable<'ast> { @@ -23,26 +16,11 @@ impl<'ast> Variable<'ast> { Self::with_id_and_type(id, Type::uint(bitwidth)) } - pub fn with_id_and_type>>(id: I, _type: Type) -> Variable<'ast> { - Variable { - id: id.into(), - _type, - } + pub fn with_id_and_type>>(id: I, ty: Type) -> Variable<'ast> { + Variable::new(id.into(), ty) } pub fn get_type(&self) -> Type { - self._type.clone() - } -} - -impl<'ast> fmt::Display for Variable<'ast> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{} {}", self._type, self.id,) - } -} - -impl<'ast> fmt::Debug for Variable<'ast> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Variable(type: {:?}, id: {:?})", self._type, self.id,) + self.ty.clone() } } diff --git a/zokrates_bellman/Cargo.toml b/zokrates_bellman/Cargo.toml index 852b1fbed..84e1be011 100644 --- a/zokrates_bellman/Cargo.toml +++ b/zokrates_bellman/Cargo.toml @@ -1,22 +1,24 @@ [package] name = "zokrates_bellman" -version = "0.1.0" +version = "0.1.3" edition = "2021" [features] +default = [] wasm = ["bellman/nolog", "bellman/wasm"] multicore = ["bellman/multicore", "phase2/multicore"] [dependencies] -zokrates_field = { version = "0.5", path = "../zokrates_field", default-features = false } +zokrates_field = { version = "0.5", path = "../zokrates_field", default-features = false, features = ["bellman_extensions"] } zokrates_ast = { version = "0.1", path = "../zokrates_ast", default-features = false } zokrates_proof_systems = { version = "0.1", path = "../zokrates_proof_systems", default-features = false } bellman = { package = "bellman_ce", version = "^0.3", default-features = false } pairing = { package = "pairing_ce", version = "^0.21" } phase2 = { git = "https://github.com/Zokrates/phase2", default-features = false } -rand_0_4 = { version = "0.4", package = "rand" }# -getrandom = { version = "0.2", features = ["js", "wasm-bindgen"] } +rand_0_4 = { version = "0.4", package = "rand" } +rand_0_8 = { version = "0.8", package = "rand" } +getrandom = { version = "0.2.8" } hex = "0.4.2" [dev-dependencies] diff --git a/zokrates_bellman/src/groth16.rs b/zokrates_bellman/src/groth16.rs index 79d699ee4..03042d46a 100644 --- a/zokrates_bellman/src/groth16.rs +++ b/zokrates_bellman/src/groth16.rs @@ -8,28 +8,31 @@ use zokrates_field::BellmanFieldExtensions; use zokrates_field::Field; use zokrates_proof_systems::{Backend, MpcBackend, NonUniversalBackend, Proof, SetupKeypair}; -use crate::Bellman; use crate::Computation; +use crate::{get_random_seed, Bellman}; use crate::{parse_g1, parse_g2}; use phase2::MPCParameters; -use rand_0_4::Rng; +use rand_0_4::{ChaChaRng, SeedableRng}; +use rand_0_8::{CryptoRng, RngCore}; use std::io::{Read, Write}; use zokrates_ast::ir::{ProgIterator, Statement, Witness}; use zokrates_proof_systems::groth16::{ProofPoints, VerificationKey, G16}; use zokrates_proof_systems::Scheme; -const G16_WARNING: &str = "WARNING: You are using the G16 scheme which is subject to malleability. See zokrates.github.io/toolbox/proving_schemes.html#g16-malleability for implications."; - impl Backend for Bellman { - fn generate_proof<'a, I: IntoIterator>>( + fn generate_proof< + 'a, + I: IntoIterator>, + R: Read, + G: RngCore + CryptoRng, + >( program: ProgIterator<'a, T, I>, witness: Witness, - proving_key: Vec, + proving_key: R, + rng: &mut G, ) -> Proof { - println!("{}", G16_WARNING); - let computation = Computation::with_witness(program, witness); - let params = Parameters::read(proving_key.as_slice(), true).unwrap(); + let params = Parameters::read(proving_key, true).unwrap(); let public_inputs: Vec = computation .public_inputs_values() @@ -37,7 +40,7 @@ impl Backend for Bellman { .map(|e| format!("0x{}", to_hex(e))) .collect(); - let proof = computation.prove(¶ms); + let proof = computation.prove(¶ms, rng); let proof_points = ProofPoints { a: parse_g1::(&proof.a), b: parse_g2::(&proof.b), @@ -84,12 +87,11 @@ impl Backend for Bellman { } impl NonUniversalBackend for Bellman { - fn setup<'a, I: IntoIterator>>( + fn setup<'a, I: IntoIterator>, R: RngCore + CryptoRng>( program: ProgIterator<'a, T, I>, + rng: &mut R, ) -> SetupKeypair { - println!("{}", G16_WARNING); - - let parameters = Computation::without_witness(program).setup(); + let parameters = Computation::without_witness(program).setup(rng); let mut pk: Vec = Vec::new(); parameters.write(&mut pk).unwrap(); @@ -110,22 +112,25 @@ impl MpcBackend for Bellman { Ok(()) } - fn contribute( - params: &mut R, + fn contribute( + params: R, rng: &mut G, output: &mut W, ) -> Result<[u8; 64], String> { let mut params = MPCParameters::::read(params, true).map_err(|e| e.to_string())?; + let seed = get_random_seed(rng); + let rng = &mut ChaChaRng::from_seed(seed.as_ref()); + let hash = params.contribute(rng); params.write(output).map_err(|e| e.to_string())?; Ok(hash) } - fn verify<'a, P: Read, R: Read, I: IntoIterator>>( - params: &mut P, + fn verify<'a, R: Read, I: IntoIterator>>( + params: R, program: ProgIterator<'a, T, I>, phase1_radix: &mut R, ) -> Result, String> { @@ -140,7 +145,7 @@ impl MpcBackend for Bellman { Ok(hashes) } - fn export_keypair(params: &mut R) -> Result, String> { + fn export_keypair(params: R) -> Result, String> { let params = MPCParameters::::read(params, true).map_err(|e| e.to_string())?; @@ -199,30 +204,49 @@ pub mod serialization { #[cfg(test)] mod tests { + use rand_0_8::rngs::StdRng; + use rand_0_8::SeedableRng; use zokrates_field::Bn128Field; use zokrates_interpreter::Interpreter; use super::*; - use zokrates_ast::common::{Parameter, Variable}; - use zokrates_ast::ir::{Prog, Statement}; + use zokrates_ast::common::flat::Parameter; + use zokrates_ast::ir::{Prog, Statement, Variable}; #[test] fn verify() { let program: Prog = Prog { + module_map: Default::default(), arguments: vec![Parameter::public(Variable::new(0))], return_count: 1, - statements: vec![Statement::constraint(Variable::new(0), Variable::public(0))], + statements: vec![Statement::constraint( + Variable::new(0), + Variable::public(0), + None, + )], + solvers: vec![], }; - let keypair = >::setup(program.clone()); + let rng = &mut StdRng::from_entropy(); + let keypair = + >::setup(program.clone(), rng); let interpreter = Interpreter::default(); let witness = interpreter - .execute(program.clone(), &[Bn128Field::from(42)]) + .execute( + &[Bn128Field::from(42)], + program.statements.iter(), + &program.arguments, + &program.solvers, + ) .unwrap(); - let proof = - >::generate_proof(program, witness, keypair.pk); + let proof = >::generate_proof( + program, + witness, + keypair.pk.as_slice(), + rng, + ); let ans = >::verify(keypair.vk, proof); assert!(ans); diff --git a/zokrates_bellman/src/lib.rs b/zokrates_bellman/src/lib.rs index 26bcf392e..4226e2011 100644 --- a/zokrates_bellman/src/lib.rs +++ b/zokrates_bellman/src/lib.rs @@ -10,12 +10,13 @@ use bellman::{ Circuit, ConstraintSystem, LinearCombination, SynthesisError, Variable as BellmanVariable, }; use std::collections::BTreeMap; -use zokrates_ast::common::Variable; -use zokrates_ast::ir::{CanonicalLinComb, ProgIterator, Statement, Witness}; +use zokrates_ast::common::flat::Variable; +use zokrates_ast::ir::{LinComb, ProgIterator, Statement, Witness}; use zokrates_field::BellmanFieldExtensions; use zokrates_field::Field; use rand_0_4::ChaChaRng; +use rand_0_8::{CryptoRng, RngCore}; pub use self::parse::*; @@ -44,12 +45,13 @@ impl<'a, T: Field, I: IntoIterator>> Computation<'a, T, } fn bellman_combination>( - l: CanonicalLinComb, + l: LinComb, cs: &mut CS, symbols: &mut BTreeMap, witness: &mut Witness, ) -> LinearCombination { - l.0.into_iter() + l.value + .into_iter() .map(|(k, v)| { ( v.into_bellman(), @@ -125,20 +127,10 @@ impl<'a, T: BellmanFieldExtensions + Field, I: IntoIterator(rng: &mut R) -> [u32; 8] { + let mut seed = [0u8; 32]; + rng.fill_bytes(&mut seed); + + use std::mem::transmute; + // This is safe because we are just reinterpreting the bytes (u8[32] -> u32[8]), + // byte order or the actual content does not matter here as this is used + // as a random seed for the rng (rand 0.4) + let seed: [u32; 8] = unsafe { transmute(seed) }; + seed +} + impl<'a, T: BellmanFieldExtensions + Field, I: IntoIterator>> Computation<'a, T, I> { - fn get_random_seed(&self) -> Result<[u32; 8], getrandom::Error> { - let mut seed = [0u8; 32]; - getrandom::getrandom(&mut seed)?; - - use std::mem::transmute; - // This is safe because we are just reinterpreting the bytes (u8[32] -> u32[8]), - // byte order or the actual content does not matter here as this is used - // as a random seed for the rng. - let seed: [u32; 8] = unsafe { transmute(seed) }; - Ok(seed) - } - - pub fn prove(self, params: &Parameters) -> Proof { + pub fn prove( + self, + params: &Parameters, + rng: &mut R, + ) -> Proof { use rand_0_4::SeedableRng; - let seed = self.get_random_seed().unwrap(); + let seed = get_random_seed(rng); let rng = &mut ChaChaRng::from_seed(seed.as_ref()); // extract public inputs @@ -184,13 +180,13 @@ impl<'a, T: BellmanFieldExtensions + Field, I: IntoIterator Parameters { + pub fn setup(self, rng: &mut R) -> Parameters { use rand_0_4::SeedableRng; - let seed = self.get_random_seed().unwrap(); + let seed = get_random_seed(rng); let rng = &mut ChaChaRng::from_seed(seed.as_ref()); // run setup phase generate_random_parameters(self, rng).unwrap() @@ -246,77 +242,124 @@ mod tests { mod prove { use super::*; + use rand_0_8::rngs::StdRng; + use rand_0_8::SeedableRng; use zokrates_ast::flat::Parameter; use zokrates_ast::ir::Prog; #[test] fn empty() { let program: Prog = Prog::default(); - let interpreter = Interpreter::default(); - let witness = interpreter.execute(program.clone(), &[]).unwrap(); + let witness = interpreter + .execute( + &[], + program.statements.iter(), + &program.arguments, + &program.solvers, + ) + .unwrap(); let computation = Computation::with_witness(program, witness); - let params = computation.clone().setup(); - let _proof = computation.prove(¶ms); + let rng = &mut StdRng::from_entropy(); + let params = computation.clone().setup(rng); + let _proof = computation.prove(¶ms, rng); } #[test] fn identity() { let program: Prog = Prog { + module_map: Default::default(), arguments: vec![Parameter::private(Variable::new(0))], return_count: 1, - statements: vec![Statement::constraint(Variable::new(0), Variable::public(0))], + statements: vec![Statement::constraint( + Variable::new(0), + Variable::public(0), + None, + )], + solvers: vec![], }; let interpreter = Interpreter::default(); let witness = interpreter - .execute(program.clone(), &[Bn128Field::from(0)]) + .execute( + &[Bn128Field::from(0)], + program.statements.iter(), + &program.arguments, + &program.solvers, + ) .unwrap(); let computation = Computation::with_witness(program, witness); - let params = computation.clone().setup(); - let _proof = computation.prove(¶ms); + let rng = &mut StdRng::from_entropy(); + let params = computation.clone().setup(rng); + let _proof = computation.prove(¶ms, rng); } #[test] fn public_identity() { let program: Prog = Prog { + module_map: Default::default(), arguments: vec![Parameter::public(Variable::new(0))], return_count: 1, - statements: vec![Statement::constraint(Variable::new(0), Variable::public(0))], + statements: vec![Statement::constraint( + Variable::new(0), + Variable::public(0), + None, + )], + solvers: vec![], }; let interpreter = Interpreter::default(); let witness = interpreter - .execute(program.clone(), &[Bn128Field::from(0)]) + .execute( + &[Bn128Field::from(0)], + program.statements.iter(), + &program.arguments, + &program.solvers, + ) .unwrap(); let computation = Computation::with_witness(program, witness); - let params = computation.clone().setup(); - let _proof = computation.prove(¶ms); + let rng = &mut StdRng::from_entropy(); + let params = computation.clone().setup(rng); + let _proof = computation.prove(¶ms, rng); } #[test] fn no_arguments() { let program: Prog = Prog { + module_map: Default::default(), arguments: vec![], return_count: 1, - statements: vec![Statement::constraint(Variable::one(), Variable::public(0))], + statements: vec![Statement::constraint( + Variable::one(), + Variable::public(0), + None, + )], + solvers: vec![], }; let interpreter = Interpreter::default(); - let witness = interpreter.execute(program.clone(), &[]).unwrap(); + let witness = interpreter + .execute( + &[], + program.statements.iter(), + &program.arguments, + &program.solvers, + ) + .unwrap(); let computation = Computation::with_witness(program, witness); - let params = computation.clone().setup(); - let _proof = computation.prove(¶ms); + let rng = &mut StdRng::from_entropy(); + let params = computation.clone().setup(rng); + let _proof = computation.prove(¶ms, rng); } #[test] @@ -324,6 +367,7 @@ mod tests { // public variables must be ordered from 0 // private variables can be unordered let program: Prog = Prog { + module_map: Default::default(), arguments: vec![ Parameter::private(Variable::new(42)), Parameter::public(Variable::new(51)), @@ -333,51 +377,70 @@ mod tests { Statement::constraint( LinComb::from(Variable::new(42)) + LinComb::from(Variable::new(51)), Variable::public(0), + None, ), Statement::constraint( LinComb::from(Variable::one()) + LinComb::from(Variable::new(42)), Variable::public(1), + None, ), ], + solvers: vec![], }; let interpreter = Interpreter::default(); let witness = interpreter - .execute(program.clone(), &[Bn128Field::from(3), Bn128Field::from(4)]) + .execute( + &[Bn128Field::from(3), Bn128Field::from(4)], + program.statements.iter(), + &program.arguments, + &program.solvers, + ) .unwrap(); let computation = Computation::with_witness(program, witness); - let params = computation.clone().setup(); - let _proof = computation.prove(¶ms); + let rng = &mut StdRng::from_entropy(); + let params = computation.clone().setup(rng); + let _proof = computation.prove(¶ms, rng); } #[test] fn one() { let program: Prog = Prog { + module_map: Default::default(), arguments: vec![Parameter::public(Variable::new(42))], return_count: 1, statements: vec![Statement::constraint( LinComb::from(Variable::new(42)) + LinComb::one(), Variable::public(0), + None, )], + solvers: vec![], }; let interpreter = Interpreter::default(); let witness = interpreter - .execute(program.clone(), &[Bn128Field::from(3)]) + .execute( + &[Bn128Field::from(3)], + program.statements.iter(), + &program.arguments, + &program.solvers, + ) .unwrap(); let computation = Computation::with_witness(program, witness); - let params = computation.clone().setup(); - let _proof = computation.prove(¶ms); + let rng = &mut StdRng::from_entropy(); + let params = computation.clone().setup(rng); + let _proof = computation.prove(¶ms, rng); } #[test] fn with_directives() { let program: Prog = Prog { + module_map: Default::default(), arguments: vec![ Parameter::private(Variable::new(42)), Parameter::public(Variable::new(51)), @@ -386,18 +449,26 @@ mod tests { statements: vec![Statement::constraint( LinComb::from(Variable::new(42)) + LinComb::from(Variable::new(51)), Variable::public(0), + None, )], + solvers: vec![], }; let interpreter = Interpreter::default(); let witness = interpreter - .execute(program.clone(), &[Bn128Field::from(3), Bn128Field::from(4)]) + .execute( + &[Bn128Field::from(3), Bn128Field::from(4)], + program.statements.iter(), + &program.arguments, + &program.solvers, + ) .unwrap(); let computation = Computation::with_witness(program, witness); - let params = computation.clone().setup(); - let _proof = computation.prove(¶ms); + let rng = &mut StdRng::from_entropy(); + let params = computation.clone().setup(rng); + let _proof = computation.prove(¶ms, rng); } } } diff --git a/zokrates_bellperson/Cargo.toml b/zokrates_bellperson/Cargo.toml new file mode 100644 index 000000000..b96a2dcf1 --- /dev/null +++ b/zokrates_bellperson/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "zokrates_bellperson" +version = "0.1.0" +edition = "2021" + +[features] + +[dependencies] +zokrates_field = { version = "0.5", path = "../zokrates_field", features = ["bellperson_extensions"] } +zokrates_ast = { version = "0.1", path = "../zokrates_ast", features = ["bellperson"] } +# zokrates_proof_systems = { version = "0.1", path = "../zokrates_proof_systems", default-features = false } +bellperson = { package = "bellperson", version = "^0.25", default-features = false } +rand_0_4 = { version = "0.4", package = "rand" }# +getrandom = { version = "0.2", features = ["js", "wasm-bindgen"] } +hex = "0.4.2" +pairing = "0.22" +ff = { version = "0.13.0", default-features = false } +nova-snark = { version = "0.21.0" } +zokrates_interpreter = { version = "0.1", path = "../zokrates_interpreter" } +serde = { version = "1.0", features = ["derive"] } + + +[dev-dependencies] +typed-arena = "1.4.1" +rand_0_4 = { version = "0.4", package = "rand" } +getrandom = { version = "0.2", features = ["js", "wasm-bindgen"] } +hex = "0.4.2" +pairing = "0.22" +pasta_curves = { version = "0.5", features = ["repr-c", "serde"] } +zokrates_core = { version = "0.7.3", path = "../zokrates_core" } + + + + + diff --git a/zokrates_bellperson/examples/10_cubes.rs b/zokrates_bellperson/examples/10_cubes.rs new file mode 100644 index 000000000..b817dff53 --- /dev/null +++ b/zokrates_bellperson/examples/10_cubes.rs @@ -0,0 +1,126 @@ +use nova_snark::traits::circuit::TrivialTestCircuit; +use nova_snark::CompressedSNARK; +use nova_snark::PublicParams; +use nova_snark::RecursiveSNARK; +use pasta_curves::{Fp, Fq}; +use std::io; +use std::time::Instant; +use typed_arena::Arena; +use zokrates_bellperson::nova::NovaComputation; +use zokrates_bellperson::Computation; +use zokrates_core::compile::{compile, CompileConfig}; +use zokrates_field::PallasField; + +type G1 = pasta_curves::pallas::Point; +type G2 = pasta_curves::vesta::Point; + +fn main() { + // create a circuit for the incremental computation + + let cube = r#" + def main(field x) -> field { + return x**3; + } + "#; + + let arena = Arena::new(); + + let artifacts = compile::( + cube.to_string(), + "main".into(), + None, + CompileConfig::default(), + &arena, + ) + .unwrap(); + + let prog = artifacts.prog().collect(); + + let circuit_primary = NovaComputation::try_from(Computation::without_witness(&prog)).unwrap(); + let circuit_secondary = TrivialTestCircuit::default(); + + type C1<'a> = NovaComputation<'a, PallasField>; + type C2 = TrivialTestCircuit; + + // produce public parameters + println!("Producing public parameters..."); + let pp = + PublicParams::::setup(circuit_primary.clone(), circuit_secondary.clone()); + + // produce a recursive SNARK + println!("Generating a RecursiveSNARK..."); + let mut recursive_snark: Option> = None; + + let num_steps: usize = 10; + + let z0_primary = vec![Fq::one() + Fq::one()]; + let z0_secondary = vec![Fp::one()]; + + for i in 0..num_steps { + let start = Instant::now(); + let res = RecursiveSNARK::prove_step( + &pp, + recursive_snark, + circuit_primary.clone(), + circuit_secondary.clone(), + z0_primary.clone(), + z0_secondary.clone(), + ); + assert!(res.is_ok()); + println!( + "RecursiveSNARK::prove_step {}: {:?}, took {:?} ", + i, + res.is_ok(), + start.elapsed() + ); + recursive_snark = Some(res.unwrap()); + } + + assert!(recursive_snark.is_some()); + let recursive_snark = recursive_snark.unwrap(); + + // verify the recursive SNARK + println!("Verifying a RecursiveSNARK..."); + let start = Instant::now(); + let res = recursive_snark.verify(&pp, num_steps, z0_primary.clone(), z0_secondary.clone()); + + println!("{:#?}", res); + + println!( + "RecursiveSNARK::verify: {:?}, took {:?}", + res.is_ok(), + start.elapsed() + ); + assert!(res.is_ok()); + + // produce a compressed SNARK + println!("Generating a CompressedSNARK using Spartan with IPA-PC..."); + let start = Instant::now(); + type EE1 = nova_snark::provider::ipa_pc::EvaluationEngine; + type EE2 = nova_snark::provider::ipa_pc::EvaluationEngine; + type S1 = nova_snark::spartan::RelaxedR1CSSNARK; + type S2 = nova_snark::spartan::RelaxedR1CSSNARK; + + let (pk, vk) = CompressedSNARK::<_, _, _, _, S1, S2>::setup(&pp).unwrap(); + + let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &pk, &recursive_snark); + println!( + "CompressedSNARK::prove: {:?}, took {:?}", + res.is_ok(), + start.elapsed() + ); + assert!(res.is_ok()); + let compressed_snark = res.unwrap(); + + // verify the compressed SNARK + println!("Verifying a CompressedSNARK..."); + let start = Instant::now(); + let res = compressed_snark.verify(&vk, num_steps, z0_primary, z0_secondary); + println!( + "CompressedSNARK::verify: {:?}, took {:?}", + res.is_ok(), + start.elapsed() + ); + assert!(res.is_ok()); + println!("========================================================="); +} diff --git a/zokrates_bellperson/src/lib.rs b/zokrates_bellperson/src/lib.rs new file mode 100644 index 000000000..3f91838d6 --- /dev/null +++ b/zokrates_bellperson/src/lib.rs @@ -0,0 +1,164 @@ +pub mod nova; + +use bellperson::gadgets::num::AllocatedNum; +use bellperson::{ + Circuit, ConstraintSystem, LinearCombination, SynthesisError, Variable as BellpersonVariable, +}; + +use std::collections::BTreeMap; +use zokrates_ast::common::flat::Variable; +use zokrates_ast::ir::{LinComb, Prog, Statement, Witness}; +use zokrates_field::BellpersonFieldExtensions; +use zokrates_field::Field; + +pub struct Bellperson; + +#[derive(Clone, Debug)] +pub struct Computation<'ast, T> { + pub program: &'ast Prog<'ast, T>, + pub witness: Option>, +} + +impl<'ast, T: Field> Computation<'ast, T> { + pub fn with_witness(program: &'ast Prog<'ast, T>, witness: Witness) -> Self { + Computation { + program, + witness: Some(witness), + } + } + + pub fn without_witness(program: &'ast Prog<'ast, T>) -> Self { + Computation { + program, + witness: None, + } + } +} + +fn bellperson_combination< + T: Field + BellpersonFieldExtensions, + CS: ConstraintSystem, +>( + l: &LinComb, + cs: &mut CS, + symbols: &mut BTreeMap, + witness: &mut Witness, +) -> LinearCombination { + l.value + .iter() + .map(|(k, v)| { + ( + v.into_bellperson(), + *symbols.entry(*k).or_insert_with(|| { + match k.is_output() { + true => { + unreachable!("outputs should already have been allocated, found {}", k) + } + false => AllocatedNum::alloc(cs.namespace(|| format!("{}", k)), || { + Ok(witness + .0 + .remove(k) + .ok_or(SynthesisError::AssignmentMissing)? + .into_bellperson()) + }), + } + .unwrap() + .get_variable() + }), + ) + }) + .fold(LinearCombination::zero(), |acc, e| acc + e) +} + +impl<'ast, T: BellpersonFieldExtensions + Field> Circuit + for Computation<'ast, T> +{ + fn synthesize>( + self, + cs: &mut CS, + ) -> Result<(), SynthesisError> { + let mut symbols = BTreeMap::new(); + + let mut witness = self.witness.clone().unwrap_or_else(Witness::empty); + + assert!(symbols.insert(Variable::one(), CS::one()).is_none()); + + symbols.extend(self.program.arguments.iter().enumerate().map(|(index, p)| { + let wire = match p.private { + true => { + AllocatedNum::alloc(cs.namespace(|| format!("PRIVATE_INPUT_{}", index)), || { + Ok(witness + .0 + .remove(&p.id) + .ok_or(SynthesisError::AssignmentMissing)? + .into_bellperson()) + }) + } + false => AllocatedNum::alloc_input( + cs.namespace(|| format!("PUBLIC_INPUT_{}", index)), + || { + Ok(witness + .0 + .remove(&p.id) + .ok_or(SynthesisError::AssignmentMissing)? + .into_bellperson()) + }, + ), + } + .unwrap(); + (p.id, wire.get_variable()) + })); + + self.program.returns().iter().for_each(|v| { + assert!(v.id < 0); // this should indeed be an output + let wire = AllocatedNum::alloc_input( + cs.namespace(|| format!("PUBLIC_OUTPUT_{}", -v.id - 1)), + || { + Ok(witness + .0 + .remove(v) + .ok_or(SynthesisError::AssignmentMissing)? + .into_bellperson()) + }, + ) + .unwrap(); + symbols.insert(*v, wire.get_variable()); + }); + + self.synthesize_input_to_output(cs, &mut symbols, &mut witness) + } +} + +impl<'ast, T: BellpersonFieldExtensions + Field> Computation<'ast, T> { + pub fn synthesize_input_to_output>( + &self, + cs: &mut CS, + symbols: &mut BTreeMap, + witness: &mut Witness, + ) -> Result<(), SynthesisError> { + for (i, statement) in self.program.statements.iter().enumerate() { + if let Statement::Constraint(constraint) = statement { + let a = &bellperson_combination(&constraint.quad.left, cs, symbols, witness); + let b = &bellperson_combination(&constraint.quad.right, cs, symbols, witness); + let c = &bellperson_combination(&constraint.lin, cs, symbols, witness); + + cs.enforce( + || format!("Constraint {}", i), + |lc| lc + a, + |lc| lc + b, + |lc| lc + c, + ); + } + } + + Ok(()) + } + + pub fn public_inputs_values(&self) -> Vec { + self.program + .public_inputs_values(self.witness.as_ref().unwrap()) + .iter() + .map(|v| v.into_bellperson()) + .collect() + } +} diff --git a/zokrates_bellperson/src/nova.rs b/zokrates_bellperson/src/nova.rs new file mode 100644 index 000000000..ae4b619c3 --- /dev/null +++ b/zokrates_bellperson/src/nova.rs @@ -0,0 +1,501 @@ +use std::collections::BTreeMap; + +use crate::Computation; +use bellperson::gadgets::num::AllocatedNum; +use bellperson::SynthesisError; +use ff::Field as FFField; +use nova_snark::errors::NovaError; +pub use nova_snark::traits::circuit::StepCircuit; +pub use nova_snark::traits::circuit::TrivialTestCircuit; +use nova_snark::traits::Group; +use nova_snark::CompressedSNARK as GCompressedSNARK; +pub use nova_snark::PublicParams as GPublicParams; +pub use nova_snark::RecursiveSNARK as GRecursiveSNARK; +use nova_snark::VerifierKey as GVerifierKey; +use serde::{Deserialize, Serialize}; +use std::fmt; +use zokrates_ast::ir::*; +use zokrates_field::{BellpersonFieldExtensions, Cycle, Field}; +use zokrates_interpreter::Interpreter; + +pub trait NovaField: + Field + + BellpersonFieldExtensions::Point as Group>::Scalar> + + Cycle +{ +} + +impl< + T: Field + + BellpersonFieldExtensions::Point as Group>::Scalar> + + Cycle, + > NovaField for T +{ +} + +#[derive(Clone, Debug)] +pub struct NovaComputation<'ast, T> { + step_private: Option>, + computation: Computation<'ast, T>, +} + +impl<'ast, T> TryFrom> for NovaComputation<'ast, T> { + type Error = Error; + fn try_from(c: Computation<'ast, T>) -> Result { + let return_count = c.program.return_count; + let public_input_count = c.program.public_count() - return_count; + + if public_input_count != return_count { + return Err(Error::User(format!("Number of return values must match number of public input values for Nova circuits, found `{} != {}`", c.program.return_count, public_input_count))); + } + + Ok(NovaComputation { + step_private: None, + computation: c, + }) + } +} + +type G1 = ::Point; +type G2 = <::Other as Cycle>::Point; +type C1<'ast, T> = NovaComputation<'ast, T>; +type C2 = TrivialTestCircuit<<::Point as Group>::Base>; + +type PublicParams<'ast, T> = GPublicParams, G2, C1<'ast, T>, C2>; +pub type RecursiveSNARK<'ast, T> = GRecursiveSNARK, G2, C1<'ast, T>, C2>; + +#[derive(Debug)] +pub enum Error { + Internal(NovaError), + User(String), +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result { + match self { + Error::Internal(e) => write!(f, "Internal error: {:#?}", e), + Error::User(s) => write!(f, "{}", s), + } + } +} + +impl From for Error { + fn from(e: NovaError) -> Self { + Self::Internal(e) + } +} + +pub fn generate_public_parameters< + 'ast, + T: Field + + BellpersonFieldExtensions::Point as Group>::Scalar> + + Cycle, +>( + program: &'ast Prog<'ast, T>, +) -> Result, Error> { + Ok(GPublicParams::setup( + NovaComputation::try_from(Computation::without_witness(program))?, + TrivialTestCircuit::default(), + )) +} + +pub fn verify( + params: &PublicParams, + proof: &RecursiveSNARKWithStepCount, + arguments: Vec, +) -> Result, Error> { + let z0_primary: Vec<_> = arguments.into_iter().map(|a| a.into_bellperson()).collect(); + let z0_secondary = vec![<::Point as Group>::Base::ONE]; + + proof + .proof + .verify(params, proof.steps, z0_primary, z0_secondary) + .map_err(Error::Internal) + .map(|(primary, _)| primary.into_iter().map(T::from_bellperson).collect()) +} + +#[derive(Serialize, Debug, Deserialize)] +pub struct RecursiveSNARKWithStepCount<'ast, T: NovaField> { + #[serde(bound = "T: NovaField")] + pub proof: RecursiveSNARK<'ast, T>, + pub steps: usize, +} + +type EE1 = nova_snark::provider::ipa_pc::EvaluationEngine>; +type EE2 = nova_snark::provider::ipa_pc::EvaluationEngine>; +type S1 = nova_snark::spartan::RelaxedR1CSSNARK, EE1>; +type S2 = nova_snark::spartan::RelaxedR1CSSNARK, EE2>; + +pub type CompressedSNARK<'ast, T> = + GCompressedSNARK, G2, C1<'ast, T>, C2, S1, S2>; +pub type VerifierKey<'ast, T> = GVerifierKey, G2, C1<'ast, T>, C2, S1, S2>; + +pub fn compress<'ast, T: NovaField>( + public_parameters: &PublicParams<'ast, T>, + instance: RecursiveSNARKWithStepCount<'ast, T>, +) -> (CompressedSNARK<'ast, T>, VerifierKey<'ast, T>) { + let (pk, vk) = CompressedSNARK::<'ast, T>::setup(public_parameters).unwrap(); + + ( + CompressedSNARK::prove(public_parameters, &pk, &instance.proof).unwrap(), + vk, + ) +} + +pub fn verify_compressed<'ast, T: NovaField>( + proof: &CompressedSNARK<'ast, T>, + vk: &VerifierKey<'ast, T>, + arguments: Vec, + step_count: usize, +) -> bool { + let z0_primary: Vec<_> = arguments.into_iter().map(|a| a.into_bellperson()).collect(); + let z0_secondary = vec![<::Point as Group>::Base::ONE]; + + proof + .verify(vk, step_count, z0_primary, z0_secondary) + .is_ok() +} + +pub fn prove<'ast, T: NovaField>( + public_parameters: &PublicParams<'ast, T>, + program: &'ast Prog<'ast, T>, + arguments: Vec, + mut proof: Option>, + steps: impl IntoIterator>, +) -> Result>, Error> { + let c_primary = NovaComputation::try_from(Computation::without_witness(program))?; + let c_secondary = TrivialTestCircuit::default(); + let z0_primary: Vec<_> = arguments.into_iter().map(|a| a.into_bellperson()).collect(); + let z0_secondary = vec![<::Point as Group>::Base::ONE]; + + for steps_private in steps { + let mut c_primary = c_primary.clone(); + c_primary.step_private = Some(steps_private); + + let steps = proof.as_ref().map(|proof| proof.steps).unwrap_or_default() + 1; + + proof = Some(RecursiveSNARKWithStepCount { + proof: RecursiveSNARK::prove_step( + public_parameters, + proof.map(|proof| proof.proof), + c_primary, + c_secondary.clone(), + z0_primary.clone(), + z0_secondary.clone(), + )?, + steps, + }); + } + + Ok(proof) +} + +impl<'ast, T: Field + BellpersonFieldExtensions + Cycle> StepCircuit + for NovaComputation<'ast, T> +{ + fn arity(&self) -> usize { + let output_count = self.computation.program.return_count; + let input_count = self.computation.program.public_count() - output_count; + assert_eq!(input_count, output_count); + input_count + } + + fn synthesize>( + &self, + cs: &mut CS, + input: &[bellperson::gadgets::num::AllocatedNum], + ) -> Result< + Vec>, + bellperson::SynthesisError, + > { + let output_count = self.computation.program.return_count; + let input_count = self.computation.program.public_count() - output_count; + assert_eq!(input_count, output_count); + + let mut symbols = BTreeMap::new(); + + let mut witness = Witness::default(); + + let outputs = self.computation.program.returns(); + + // populate the witness if we got some input values + // this is a bit hacky and in particular generates the witness in all cases if there are no inputs + if input + .get(0) + .map(|n| n.get_value().is_some()) + .unwrap_or(true) + { + let interpreter = Interpreter::default(); + let inputs: Vec<_> = input + .iter() + .map(|v| T::from_bellperson(v.get_value().unwrap())) + .chain(self.step_private.clone().into_iter().flatten()) + .collect(); + + let program = self.computation.program; + witness = interpreter + .execute( + &inputs, + program.statements.iter(), + &program.arguments, + &program.solvers, + ) + .unwrap(); + } + + // allocate the inputs + for (p, allocated_num) in self.computation.program.arguments.iter().zip(input) { + symbols.insert(p.id, allocated_num.get_variable()); + } + + // allocate the outputs + + let outputs: Vec<_> = outputs + .iter() + .map(|v| { + assert!(v.id < 0); // this should indeed be an output + let wire = AllocatedNum::alloc( + cs.namespace(|| format!("NOVA_INCREMENTAL_OUTPUT_{}", -v.id - 1)), + || { + Ok(witness + .0 + .remove(v) + .ok_or(SynthesisError::AssignmentMissing)? + .into_bellperson()) + }, + ) + .unwrap(); + symbols.insert(*v, wire.get_variable()); + wire + }) + .collect(); + + self.computation + .synthesize_input_to_output(cs, &mut symbols, &mut witness)?; + + Ok(outputs) + } + + fn output(&self, z: &[T::BellpersonField]) -> Vec { + let interpreter = Interpreter::default(); + let inputs: Vec<_> = z + .iter() + .map(|v| T::from_bellperson(*v)) + .chain(self.step_private.clone().unwrap()) + .collect(); + + let program = self.computation.program; + let output = interpreter + .execute( + &inputs, + program.statements.iter(), + &program.arguments, + &program.solvers, + ) + .unwrap(); + + output + .return_values() + .into_iter() + .map(|v| v.into_bellperson()) + .collect() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use zokrates_ast::ir::LinComb; + + mod prove { + use super::*; + use zokrates_ast::flat::Parameter; + use zokrates_ast::ir::Prog; + use zokrates_field::PallasField; + + fn test( + program: Prog, + initial_state: Vec, + step_privates: Vec>, + expected_final_state: Vec, + ) { + let params = generate_public_parameters(&program).unwrap(); + let proof = prove( + ¶ms, + &program, + initial_state.clone(), + None, + step_privates, + ) + .unwrap() + .unwrap(); + assert_eq!( + verify(¶ms, &proof, initial_state).unwrap(), + expected_final_state + ); + } + + #[test] + fn empty() { + let program: Prog = Prog::default(); + test(program, vec![], vec![vec![]; 3], vec![]); + } + + #[test] + fn identity() { + let program: Prog = Prog { + arguments: vec![Parameter::public(Variable::new(0))], + return_count: 1, + statements: vec![Statement::constraint( + Variable::new(0), + Variable::public(0), + None, + )], + module_map: Default::default(), + solvers: vec![], + }; + + test( + program, + vec![PallasField::from(0)], + vec![vec![]; 3], + vec![PallasField::from(0)], + ); + } + + #[test] + fn plus_one() { + let program = Prog { + arguments: vec![Parameter::public(Variable::new(42))], + return_count: 1, + statements: vec![Statement::constraint( + LinComb::from(Variable::new(42)) + LinComb::one(), + Variable::public(0), + None, + )], + module_map: Default::default(), + solvers: vec![], + }; + + test( + program, + vec![PallasField::from(3)], + vec![vec![]; 3], + vec![PallasField::from(6)], + ); + } + + #[test] + fn private_gaps() { + let program = Prog { + arguments: vec![ + Parameter::public(Variable::new(42)), + Parameter::public(Variable::new(51)), + ], + return_count: 2, + statements: vec![ + Statement::constraint( + LinComb::from(Variable::new(42)) + LinComb::from(Variable::new(51)), + Variable::public(0), + None, + ), + Statement::constraint( + LinComb::from(Variable::new(51)) + LinComb::from(Variable::new(42)), + Variable::public(1), + None, + ), + ], + module_map: Default::default(), + solvers: vec![], + }; + + test( + program, + vec![PallasField::from(0), PallasField::from(1)], + vec![vec![]; 3], + vec![PallasField::from(4), PallasField::from(4)], + ); + } + + #[test] + fn fold() { + // def main(public field acc, field e) -> field { + // return acc + e + // } + + // called with init 2 and round private inputs [1, 2, 3] + // should return (((2 + 1) + 2) + 3) = 8 + + let program = Prog { + arguments: vec![ + Parameter::public(Variable::new(0)), + Parameter::private(Variable::new(1)), + ], + return_count: 1, + statements: vec![Statement::constraint( + LinComb::from(Variable::new(0)) + LinComb::from(Variable::new(1)), + Variable::public(0), + None, + )], + module_map: Default::default(), + solvers: vec![], + }; + + test( + program, + vec![PallasField::from(2)], + vec![ + vec![PallasField::from(1)], + vec![PallasField::from(2)], + vec![PallasField::from(3)], + ], + vec![PallasField::from(8)], + ); + } + + #[test] + fn complex_fold() { + // def main(public field[2] acc, field[2] e) -> field[2] { + // return [acc[0] + e[0], acc[1] + e[1]] + // } + + // called with init [2, 3] and round private inputs [[1, 2], [3, 4], [5, 6]] + // should return [2 + 1 + 3 + 5, 3 + 2 + 4 + 6] = [11, 15] + + let program = Prog { + arguments: vec![ + Parameter::public(Variable::new(0)), + Parameter::public(Variable::new(1)), + Parameter::private(Variable::new(2)), + Parameter::private(Variable::new(3)), + ], + return_count: 2, + statements: vec![ + Statement::constraint( + LinComb::from(Variable::new(0)) + LinComb::from(Variable::new(2)), + Variable::public(0), + None, + ), + Statement::constraint( + LinComb::from(Variable::new(1)) + LinComb::from(Variable::new(3)), + Variable::public(1), + None, + ), + ], + module_map: Default::default(), + solvers: vec![], + }; + + test( + program, + vec![PallasField::from(2), PallasField::from(3)], + vec![ + vec![PallasField::from(1), PallasField::from(2)], + vec![PallasField::from(3), PallasField::from(4)], + vec![PallasField::from(5), PallasField::from(6)], + ], + vec![PallasField::from(11), PallasField::from(15)], + ); + } + } +} diff --git a/zokrates_book/src/SUMMARY.md b/zokrates_book/src/SUMMARY.md index 5d2830cbf..84c8ef697 100644 --- a/zokrates_book/src/SUMMARY.md +++ b/zokrates_book/src/SUMMARY.md @@ -27,6 +27,7 @@ - [ZIR](toolbox/ir.md) - [JSON ABI](toolbox/abi.md) - [zokrates.js](toolbox/zokrates_js.md) + - [Experimental](toolbox/experimental.md) - [Examples](examples/index.md) - [A SNARK Powered RNG](examples/rng_tutorial.md) diff --git a/zokrates_book/src/examples/sha256example.md b/zokrates_book/src/examples/sha256example.md index e970d7dc2..a933b8cb8 100644 --- a/zokrates_book/src/examples/sha256example.md +++ b/zokrates_book/src/examples/sha256example.md @@ -43,20 +43,14 @@ As a next step we can create a witness file using the following command: Using the flag `-a` we pass arguments to the program. Recall that our goal is to compute the hash for the number `5`. Consequently we set `a`, `b` and `c` to `0` and `d` to `5`. -Still here? Great! At this point, we can check the `witness` file for the return values: +Still here? Great! At this point we can check the return values. We should see the following output: ``` -{{#include ../../../zokrates_cli/examples/book/sha256_tutorial/test.sh:13}} +Witness: +["263561599766550617289250058199814760685","65303172752238645975888084098459749904"] ``` -which should lead to the following output: - -```sh -~out_0 263561599766550617289250058199814760685 -~out_1 65303172752238645975888084098459749904 -``` - -Hence, by concatenating the outputs as 128 bit numbers, we arrive at the following value as the hash for our selected pre-image : +By concatenating the outputs as 128 bit numbers, we arrive at the following value as the hash for our selected pre-image : `0xc6481e22c5ff4164af680b8cfaa5e8ed3120eeff89c4f307c4a6faaae059ce10` ## Prove knowledge of pre-image @@ -78,13 +72,13 @@ Note that we now compare the result of `sha256packed` with the hard-coded correc So, having defined the program, Victor is now ready to compile the code: ``` -{{#include ../../../zokrates_cli/examples/book/sha256_tutorial/test.sh:17}} +{{#include ../../../zokrates_cli/examples/book/sha256_tutorial/test.sh:15}} ``` Based on that Victor can run the setup phase and export a verifier smart contract as a Solidity file: ``` -{{#include ../../../zokrates_cli/examples/book/sha256_tutorial/test.sh:18:19}} +{{#include ../../../zokrates_cli/examples/book/sha256_tutorial/test.sh:16:17}} ``` `setup` creates a `verification.key` file and a `proving.key` file. Victor gives the proving key to Peggy. @@ -94,13 +88,13 @@ Based on that Victor can run the setup phase and export a verifier smart contrac Peggy provides the correct pre-image as an argument to the program. ``` -{{#include ../../../zokrates_cli/examples/book/sha256_tutorial/test.sh:20}} +{{#include ../../../zokrates_cli/examples/book/sha256_tutorial/test.sh:18}} ``` Finally, Peggy can run the command to construct the proof: ``` -{{#include ../../../zokrates_cli/examples/book/sha256_tutorial/test.sh:21}} +{{#include ../../../zokrates_cli/examples/book/sha256_tutorial/test.sh:19}} ``` As the inputs were declared as private in the program, they do not appear in the proof thanks to the zero-knowledge property of the protocol. diff --git a/zokrates_book/src/gettingstarted.md b/zokrates_book/src/gettingstarted.md index 93caf96c2..d0aa512f3 100644 --- a/zokrates_book/src/gettingstarted.md +++ b/zokrates_book/src/gettingstarted.md @@ -25,7 +25,7 @@ You can build ZoKrates from [source](https://github.com/ZoKrates/ZoKrates/) with git clone https://github.com/ZoKrates/ZoKrates cd ZoKrates export ZOKRATES_STDLIB=$PWD/zokrates_stdlib/stdlib -cargo +nightly build -p zokrates_cli --release +cargo build -p zokrates_cli --release cd target/release ``` diff --git a/zokrates_book/src/language/assembly.md b/zokrates_book/src/language/assembly.md index aa37ddab7..3fdbcad77 100644 --- a/zokrates_book/src/language/assembly.md +++ b/zokrates_book/src/language/assembly.md @@ -1,6 +1,8 @@ ## Assembly -ZoKrates allows developers to define constraints through assembly blocks. Assembly blocks are considered **unsafe**, as safety and correctness of the resulting arithmetic circuit is in the hands of the developer. Usage of assembly is recommended only in optimization efforts for the experienced developers to minimize constraint count of an arithmetic circuit. +ZoKrates allows developers to define constraints through assembly blocks. Assembly blocks are considered **unsafe**, as safety and correctness of the resulting arithmetic circuit is in the hands of the developer. Usage of assembly is recommended only in optimization efforts for experienced developers to minimize constraint count of an arithmetic circuit. + +>The usage of assembly blocks in ZoKrates is experimental. In particular, while assembly blocks help minimise constraint count in some cases, they currently can at the same time lead to larger compiler output and slower witness generation. ## Writing assembly @@ -15,9 +17,19 @@ Assigning a value, in general, should be combined with adding a constraint: {{#include ../../../zokrates_cli/examples/book/assembly/division.zok}} ``` -> The operator `<--` can be sometimes misused, as this operator does not generate any constraints, resulting in unconstrained variables in the constraint system. +> Note that operator `<--` is used for unconstrained assignment and can be easily misused. This operator does not generate constraints, which could result in unconstrained variables in the constraint system. + +Unconstrained assignment `<--` allows assignment to variables with complex types. The type must consist of field elements only (eg. `field[3]`): + +```zok +field[3] mut c = [0; 3]; +asm { + c <-- [2, 2, 4]; + c[0] * c[1] === c[2]; +} +``` -In some cases we can combine the witness assignment and constraint generation with the `<==` operator: +In some cases we can combine the witness assignment and constraint generation with the `<==` operator (constrained assignment): ```zok asm { @@ -34,6 +46,8 @@ asm { } ``` +In the case of constrained assignment `<==`, both sides of the statement have to be of type `field`. + A constraint can contain arithmetic expressions that are built using multiplication, addition, and other variables or `field` values. Only quadratic expressions are allowed to be included in constraints. Non-quadratic expressions or usage of other arithmetic operators like division or power are not allowed as constraints, but can be used in the witness assignment expression. The following code is not allowed: diff --git a/zokrates_book/src/language/types.md b/zokrates_book/src/language/types.md index 8eee2ce62..8daf8c63a 100644 --- a/zokrates_book/src/language/types.md +++ b/zokrates_book/src/language/types.md @@ -25,7 +25,7 @@ Booleans are available in ZoKrates. When a boolean is used as a parameter of the ### `u8/u16/u32/u64` -Unsigned integers represent positive numbers of the interval `[0, 2 ** bitwidth[`, where `bitwidth` is specified in the type's name, e.g., 32 bits in the case of u32. Their arithmetics are defined modulo `2 ** bitwidth`. +Unsigned integers represent positive numbers of the interval `[0, 2 ** bitwidth)`, where `bitwidth` is specified in the type's name, e.g., 32 bits in the case of u32. Their arithmetics are defined modulo `2 ** bitwidth`. Internally, they use a binary encoding, which makes them particularly efficient for implementing programs that operate on that binary representation, e.g., the SHA256 hash function. diff --git a/zokrates_book/src/toolbox/abi.md b/zokrates_book/src/toolbox/abi.md index caaa0c3be..15fd55030 100644 --- a/zokrates_book/src/toolbox/abi.md +++ b/zokrates_book/src/toolbox/abi.md @@ -1,6 +1,6 @@ # ZoKrates ABI -In order to interact programatically with compiled ZoKrates programs, ZoKrates supports passing arguments using an ABI. +In order to interact programmatically with compiled ZoKrates programs, ZoKrates supports passing arguments using an ABI. To illustrate this, we'll use the following example program: diff --git a/zokrates_book/src/toolbox/experimental.md b/zokrates_book/src/toolbox/experimental.md new file mode 100644 index 000000000..953830ba1 --- /dev/null +++ b/zokrates_book/src/toolbox/experimental.md @@ -0,0 +1,64 @@ +# Experimental features + +ZoKrates supports some experimental features. + +## Nova + +ZoKrates supports the `nova` proof system using the `bellperson` backend. Nova is accessed with the subcommand `nova`. + +### API + +To use Nova, programs must have the following signature, for any types `State` and `StepInput`: + +``` +def main(public State state, private StepInput step_input) -> State +``` + +Then, using Nova lets the user prove many steps of this program, given an initial state. + +For example: + +``` +{{#include ../../../zokrates_cli/examples/book/nova_step.zok}} +``` + +We compile this program using the Pallas curve: + +```bash +zokrates compile -i sum.zok --curve pallas +``` + +Then we can prove three iterations as follows: + +```bash +echo "\"0\"" > init.json +echo "[\"1\", \"7\", \"42\"]" > steps.json +zokrates nova prove +``` + +The proof created at `proof.json` proves the statement `0 + 1 + 7 + 42 == 50`. + +We can extend it by running more steps, for example with the same intermediate inputs: + +``` +zokrates nova prove --continue +``` + +The proof updated at `proof.json` proves the statement `50 + (0 + 1 + 7 + 42) == 100`. + +Once we're done, we compress the proof to a compressed snark: + +``` +zokrates nova compress +``` + +Finally, we can verify this proof + +``` +zokrates nova verify +``` + +### Limitations + +- The step circuit must be compiled with `--curve pallas` +- The resulting recursive proof cannot currently be verified on the EVM \ No newline at end of file diff --git a/zokrates_book/src/toolbox/trusted_setup.md b/zokrates_book/src/toolbox/trusted_setup.md index aa05b4f03..db4b5ad61 100644 --- a/zokrates_book/src/toolbox/trusted_setup.md +++ b/zokrates_book/src/toolbox/trusted_setup.md @@ -1,6 +1,6 @@ # Performing a trusted setup using a multi-party computation protocol (MPC) -The zk-SNARK schemes supported by ZoKrates require a trusted setup. This procedure must be run to generate the proving and verification keys. This procedure generates some data often refered to as "toxic waste" which can be used to create fake proofs which will be accepted by the verifier. The entity running the trusted setup is trusted to delete this toxic waste. +The zk-SNARK schemes supported by ZoKrates require a trusted setup. This procedure must be run to generate the proving and verification keys. This procedure generates some data often referred to as "toxic waste" which can be used to create fake proofs which will be accepted by the verifier. The entity running the trusted setup is trusted to delete this toxic waste. Using an MPC protocol, we can run the trusted setup in a decentralized way, so that this responsibility is shared among all participants of the setup. If at least one participant is honest and deletes their part of the toxic waste, then no fake proofs can be created by anyone. This section of the book describes the steps to perform a trusted setup for the Groth16 scheme. @@ -14,7 +14,7 @@ We will start this tutorial by using ZoKrates to compile a basic program. First, we create a new file named `program.zok` with the following content: ```zokrates -{{#include ../../../zokrates_cli/examples/book/mpc_tutorial/circuit.zok}} +{{#include ../../../zokrates_cli/examples/book/mpc_tutorial/program.zok}} ``` We compile the program using the `compile` command. @@ -35,7 +35,7 @@ Parameters written to `mpc.params` ``` Using the `-r` flag, we pass a path to the file which contains the parameters for our circuit with depth `2^n` (`phase1radix2m{n}`). -The parameters for various circuit depths can be computed using the [phase2-bn254](https://github.com/kobigurk/phase2-bn254) utility +The parameters for various circuit depths can be computed using the [phase2-bn254](https://github.com/kobigurk/phase2-bn254) utility by picking the latest response from the [Perpetual Powers of Tau](https://github.com/weijiekoh/perpetualpowersoftau) and following the instructions in the mentioned repositories. ## Making a contribution @@ -126,9 +126,9 @@ Your contribution has been written to `final.params` ``` The random beacon is the `2^n` iteration of `SHA256` over the hash evaluated on -some high entropy and publicly available data. Possible sources of data could be: +some high entropy and publicly available data. Possible sources of data could be: * The closing value of the stock market on a certain date -* The output of a selected set of national lotteries +* The output of a selected set of national lotteries * The value of a block at a particular height in one or more blockchains * [League of Entropy](https://www.cloudflare.com/leagueofentropy/) (drand) @@ -163,5 +163,5 @@ Once the ceremony is finalized, we can export the keys and use them to generate The secure generation of parameters for zk-SNARKs is a crucial step in the trustworthiness of the resulting proof system. The security of the ceremony relies entirely on the fact that at least one participant needs to securely delete their "toxic waste" for the resulting parameters to be generated honestly. Opening the ceremony to a large number of participants reduces the probability that the resulting parameters are dishonest. -Once the ceremony is finalized, we can generate a verifier smart contract by using the keys we obtained through the trusted setup ceremony. +Once the ceremony is finalized, we can generate a verifier smart contract by using the keys we obtained through the trusted setup ceremony. At this point, we can safely deploy the contract and verify proofs on-chain. diff --git a/zokrates_book/src/toolbox/zokrates_js.md b/zokrates_book/src/toolbox/zokrates_js.md index 953e662e9..c5a0cc0e5 100644 --- a/zokrates_book/src/toolbox/zokrates_js.md +++ b/zokrates_book/src/toolbox/zokrates_js.md @@ -8,118 +8,140 @@ npm install zokrates-js ## Importing -##### Bundlers -**Note:** As this library uses a model where the wasm module itself is natively an ES module, you will need a bundler of some form. -Currently the only known bundler known to be fully compatible with `zokrates-js` is [Webpack](https://webpack.js.org/) (`experiments.syncWebAssembly` must be enabled). -The choice of this default was done to reflect the trends of the JS ecosystem. +#### ES modules + ```js -import { initialize } from 'zokrates-js'; +import { initialize } from "zokrates-js"; ``` -##### Node +#### CommonJS + ```js -const { initialize } = require('zokrates-js') +let { initialize } = await import("zokrates-js"); +``` + +#### CDN + +```html + + ``` ## Example + ```js initialize().then((zokratesProvider) => { - const source = "def main(private field a) -> field { return a * a; }"; + const source = "def main(private field a) -> field { return a * a; }"; + + // compilation + const artifacts = zokratesProvider.compile(source); - // compilation - const artifacts = zokratesProvider.compile(source); + // computation + const { witness, output } = zokratesProvider.computeWitness(artifacts, ["2"]); - // computation - const { witness, output } = zokratesProvider.computeWitness(artifacts, ["2"]); + // run setup + const keypair = zokratesProvider.setup(artifacts.program); - // run setup - const keypair = zokratesProvider.setup(artifacts.program); + // generate proof + const proof = zokratesProvider.generateProof( + artifacts.program, + witness, + keypair.pk + ); - // generate proof - const proof = zokratesProvider.generateProof(artifacts.program, witness, keypair.pk); + // export solidity verifier + const verifier = zokratesProvider.exportSolidityVerifier(keypair.vk); - // export solidity verifier - const verifier = zokratesProvider.exportSolidityVerifier(keypair.vk); - - // or verify off-chain - const isVerified = zokratesProvider.verify(keypair.vk, proof); + // or verify off-chain + const isVerified = zokratesProvider.verify(keypair.vk, proof); }); ``` ## API ##### initialize() + Returns an initialized `ZoKratesProvider` as a promise. ```js -initialize().then((zokratesProvider) => { - // call api functions here +initialize().then((zokratesProvider) => { + // call api functions here }); ``` Returns: `Promise` ##### withOptions(options) + Returns a `ZoKratesProvider` configured with given options. ```js -initialize().then((defaultProvider) => { - let zokratesProvider = defaultProvider.withOptions({ - backend: "ark", - curve: "bls12_381", - scheme: "g16" - }); - // ... +initialize().then((defaultProvider) => { + let zokratesProvider = defaultProvider.withOptions({ + backend: "ark", + curve: "bls12_381", + scheme: "g16", + }); + // ... }); ``` Options: -* `backend` - Backend (options: `ark` | `bellman`, default: `ark`) -* `curve` - Elliptic curve (options: `bn128` | `bls12_381` | `bls12_377` | `bw6_761`, default: `bn128`) -* `scheme` - Proving scheme (options: `g16` | `gm17` | `marlin`, default: `g16`) + +- `backend` - Backend (options: `ark` | `bellman`, default: `ark`) +- `curve` - Elliptic curve (options: `bn128` | `bls12_381` | `bls12_377` | `bw6_761`, default: `bn128`) +- `scheme` - Proving scheme (options: `g16` | `gm17` | `marlin`, default: `g16`) Returns: `ZoKratesProvider` ##### compile(source[, options]) + Compiles source code into ZoKrates internal representation of arithmetic circuits. Parameters: -* `source` - Source code to compile -* `options` - Compilation options + +- `source` - Source code to compile +- `options` - Compilation options Returns: `CompilationArtifacts` **Examples:** Compilation: + ```js const artifacts = zokratesProvider.compile("def main() { return; }"); ``` Compilation with custom options: + ```js const source = "..."; const options = { - location: "main.zok", // location of the root module - resolveCallback: (currentLocation, importLocation) => { - console.log(currentLocation + ' is importing ' + importLocation); - return { - source: "def main() { return; }", - location: importLocation - }; - } + location: "main.zok", // location of the root module + resolveCallback: (currentLocation, importLocation) => { + console.log(currentLocation + " is importing " + importLocation); + return { + source: "def main() { return; }", + location: importLocation, + }; + }, }; const artifacts = zokratesProvider.compile(source, options); ``` -**Note:** The `resolveCallback` function is used to resolve dependencies. -This callback receives the current module location and the import location of the module which is being imported. -The callback must synchronously return either an error, `null` or a valid `ResolverResult` object like shown in the example above. -A simple file system resolver for a node environment can be implemented as follows: +**Note:** The `resolveCallback` function is used to resolve dependencies. +This callback receives the current module location and the import location of the module which is being imported. +The callback must synchronously return either an error, `null` or a valid `ResolverResult` object like shown in the example above. +A simple file system resolver in a node environment can be implemented as follows: ```js -const fs = require("fs"); -const path = require("path"); +import fs from "fs"; +import path from "path"; const fileSystemResolver = (from, to) => { const location = path.resolve(path.dirname(path.resolve(from)), to); @@ -129,19 +151,21 @@ const fileSystemResolver = (from, to) => { ``` ##### computeWitness(artifacts, args[, options]) + Computes a valid assignment of the variables, which include the results of the computation. Parameters: -* `artifacts` - Compilation artifacts -* `args` - Array of arguments (eg. `["1", "2", true]`) -* `options` - Computation options + +- `artifacts` - Compilation artifacts +- `args` - Array of arguments (eg. `["1", "2", true]`) +- `options` - Computation options Returns: `ComputationResult` **Example:** ```js -const code = 'def main(private field a) -> field { return a * a; }'; +const code = "def main(private field a) -> field { return a * a; }"; const artifacts = zokratesProvider.compile(code); const { witness, output } = zokratesProvider.computeWitness(artifacts, ["2"]); @@ -150,54 +174,79 @@ console.log(witness); // Resulting witness which can be used to generate a proof console.log(output); // Computation output: "4" ``` -##### setup(program) +##### setup(program[, entropy]) + Generates a trusted setup for the compiled program. Parameters: -* `program` - Compiled program + +- `program` - Compiled program +- `entropy` - User provided randomness (optional) Returns: `SetupKeypair` -##### universalSetup(size) +##### universalSetup(size[, entropy]) + Performs the universal phase of a trusted setup. Only available for the `marlin` scheme. Parameters: -* `size` - Size of the trusted setup passed as an exponent. For example, `8` for `2**8`. + +- `size` - Size of the trusted setup passed as an exponent. For example, `8` for `2**8`. +- `entropy` - User provided randomness (optional) Returns: `Uint8Array` ##### setupWithSrs(srs, program) + Generates a trusted setup with universal public parameters for the compiled program. Only available for `marlin` scheme. Parameters: -* `srs` - Universal public parameters from the universal setup phase -* `program` - Compiled program + +- `srs` - Universal public parameters from the universal setup phase +- `program` - Compiled program Returns: `SetupKeypair` -##### generateProof(program, witness, provingKey) +##### generateProof(program, witness, provingKey[, entropy]) + Generates a proof for a computation of the compiled program. Parameters: -* `program` - Compiled program -* `witness` - Witness (valid assignment of the variables) from the computation result -* `provingKey` - Proving key from the setup keypair + +- `program` - Compiled program +- `witness` - Witness (valid assignment of the variables) from the computation result +- `provingKey` - Proving key from the setup keypair +- `entropy` - User provided randomness (optional) Returns: `Proof` ##### verify(verificationKey, proof) + Verifies the generated proof. Parameters: -* `verificationKey` - Verification key from the setup keypair -* `proof` - Generated proof + +- `verificationKey` - Verification key from the setup keypair +- `proof` - Generated proof Returns: `boolean` ##### exportSolidityVerifier(verificationKey) + Generates a Solidity contract which contains the generated verification key and a public function to verify proofs of computation of the compiled program. Parameters: -* `verificationKey` - Verification key from the setup keypair + +- `verificationKey` - Verification key from the setup keypair Returns: `string` + +##### utils.formatProof(proof) + +Formats the proof into an array of field elements that are compatible as input to the generated solidity contract + +Parameters: + +- `proof` - Generated proof + +Returns: `array` diff --git a/zokrates_circom/Cargo.toml b/zokrates_circom/Cargo.toml index d4ce79429..7cc84a3a2 100644 --- a/zokrates_circom/Cargo.toml +++ b/zokrates_circom/Cargo.toml @@ -1,12 +1,11 @@ [package] name = "zokrates_circom" -version = "0.1.1" +version = "0.1.4" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -zokrates_core = { version = "0.7", path = "../zokrates_core", default-features = false } zokrates_ast = { version = "0.1", path = "../zokrates_ast", default-features = false } zokrates_field = { version = "0.5.0", path = "../zokrates_field", default-features = false } byteorder = "1.4.3" diff --git a/zokrates_circom/src/lib.rs b/zokrates_circom/src/lib.rs index 9b16742fb..9960fc19c 100644 --- a/zokrates_circom/src/lib.rs +++ b/zokrates_circom/src/lib.rs @@ -24,26 +24,28 @@ mod tests { #[test] fn setup_and_prove() { let prog: Prog = Prog { + module_map: Default::default(), arguments: vec![ Parameter::private(Variable::new(0)), Parameter::public(Variable::new(1)), ], return_count: 1, statements: vec![ - Statement::Constraint( - QuadComb::from_linear_combinations( + Statement::constraint( + QuadComb::new( LinComb::from(Variable::new(0)), LinComb::from(Variable::new(0)), ), LinComb::from(Variable::new(0)), None, ), - Statement::Constraint( - (LinComb::from(Variable::new(0)) + LinComb::from(Variable::new(1))).into(), - Variable::public(0).into(), + Statement::constraint( + LinComb::from(Variable::new(0)) + LinComb::from(Variable::new(1)), + Variable::public(0), None, ), ], + solvers: vec![], }; let mut r1cs = vec![]; diff --git a/zokrates_circom/src/r1cs.rs b/zokrates_circom/src/r1cs.rs index 854bc0eab..00c0d8dea 100644 --- a/zokrates_circom/src/r1cs.rs +++ b/zokrates_circom/src/r1cs.rs @@ -69,19 +69,19 @@ pub fn r1cs_program(prog: Prog) -> (Vec, usize, Vec Some((quad, lin)), + for s in prog.statements.iter().filter_map(|s| match s { + Statement::Constraint(s) => Some(s), Statement::Directive(..) => None, Statement::Block(..) => unreachable!(), Statement::Log(..) => None, }) { - for (k, _) in &quad.left.0 { + for (k, _) in &s.quad.left.value { ordered_variables_set.insert(k); } - for (k, _) in &quad.right.0 { + for (k, _) in &s.quad.right.value { ordered_variables_set.insert(k); } - for (k, _) in &lin.0 { + for (k, _) in &s.lin.value { ordered_variables_set.insert(k); } } @@ -95,23 +95,23 @@ pub fn r1cs_program(prog: Prog) -> (Vec, usize, Vec Some((quad, lin)), Statement::Block(..) => unreachable!(), Statement::Directive(..) => None, Statement::Log(..) => None, + Statement::Constraint(s) => Some((s.quad, s.lin)), }) { constraints.push(( quad.left - .0 + .value .into_iter() .map(|(k, v)| (*variables.get(&k).unwrap(), v)) .collect(), quad.right - .0 + .value .into_iter() .map(|(k, v)| (*variables.get(&k).unwrap(), v)) .collect(), - lin.0 + lin.value .into_iter() .map(|(k, v)| (*variables.get(&k).unwrap(), v)) .collect(), @@ -289,13 +289,15 @@ mod tests { #[test] fn return_one() { let prog: Prog = Prog { + module_map: Default::default(), arguments: vec![], return_count: 1, - statements: vec![Statement::Constraint( - LinComb::one().into(), - Variable::public(0).into(), + statements: vec![Statement::constraint( + LinComb::one(), + Variable::public(0), None, )], + solvers: vec![], }; let mut buf = Vec::new(); @@ -345,26 +347,28 @@ mod tests { #[test] fn with_inputs() { let prog: Prog = Prog { + module_map: Default::default(), arguments: vec![ Parameter::private(Variable::new(0)), Parameter::public(Variable::new(1)), ], return_count: 1, statements: vec![ - Statement::Constraint( - QuadComb::from_linear_combinations( + Statement::constraint( + QuadComb::new( LinComb::from(Variable::new(0)), LinComb::from(Variable::new(0)), ), LinComb::from(Variable::new(0)), None, ), - Statement::Constraint( - (LinComb::from(Variable::new(0)) + LinComb::from(Variable::new(1))).into(), - Variable::public(0).into(), + Statement::constraint( + LinComb::from(Variable::new(0)) + LinComb::from(Variable::new(1)), + Variable::public(0), None, ), ], + solvers: vec![], }; let mut buf = Vec::new(); diff --git a/zokrates_cli/Cargo.toml b/zokrates_cli/Cargo.toml index 0aa946334..31f182443 100644 --- a/zokrates_cli/Cargo.toml +++ b/zokrates_cli/Cargo.toml @@ -1,14 +1,15 @@ [package] name = "zokrates_cli" -version = "0.8.3" +version = "0.8.7" authors = ["Jacob Eberhardt ", "Dennis Kuhnert ", "Thibaut Schaeffer "] repository = "https://github.com/Zokrates/ZoKrates.git" edition = "2018" [features] -default = ["bellman", "ark"] +default = ["bellman", "ark", "bellperson"] bellman = ["zokrates_bellman", "zokrates_core/bellman", "zokrates_common/bellman"] ark = ["zokrates_ark", "zokrates_core/ark", "zokrates_common/ark"] +bellperson = ["zokrates_bellperson", "zokrates_core/bellperson", "zokrates_common/bellperson"] [dependencies] log = "0.4" @@ -17,12 +18,14 @@ cfg-if = "0.1" clap = "2.26.2" serde_cbor = "0.11.2" regex = "0.2" -zokrates_field = { version = "0.5", path = "../zokrates_field", default-features = false } +zokrates_field = { version = "0.5", path = "../zokrates_field", features = ["multicore"] } zokrates_abi = { version = "0.1", path = "../zokrates_abi" } zokrates_core = { version = "0.7", path = "../zokrates_core", default-features = false } zokrates_ast = { version = "0.1", path = "../zokrates_ast", default-features = false } +zokrates_profiler = { version = "0.1", path = "../zokrates_profiler", default-features = false } zokrates_interpreter = { version = "0.1", path = "../zokrates_interpreter", default-features = false } zokrates_circom = { version = "0.1", path = "../zokrates_circom", default-features = false } +zokrates_embed = { version = "0.1", path = "../zokrates_embed", features = ["multicore"] } typed-arena = "1.4.1" zokrates_fs_resolver = { version = "0.5", path = "../zokrates_fs_resolver"} zokrates_common = { version = "0.1", path = "../zokrates_common", default-features = false } @@ -39,14 +42,14 @@ sha2 = "0.10.0" # Backends zokrates_proof_systems = { version = "0.1", path = "../zokrates_proof_systems", default-features = false } -zokrates_ark = { version = "0.1", path = "../zokrates_ark", default-features = false, optional = true } -zokrates_bellman = { version = "0.1", path = "../zokrates_bellman", default-features = false, optional = true } +zokrates_ark = { version = "0.1", path = "../zokrates_ark", features = ["multicore"], optional = true } +zokrates_bellman = { version = "0.1", path = "../zokrates_bellman", features = ["multicore"], optional = true } +zokrates_bellperson = { version = "0.1", path = "../zokrates_bellperson", default-features = false, optional = true } [dev-dependencies] glob = "0.2.11" assert_cli = "0.5" tempdir = "0.3" -zokrates_solidity_test = { version = "0.1", path = "../zokrates_solidity_test", default-features = false } ethabi = "17.0.0" primitive-types = { version = "0.11", features = ["rlp"] } fs_extra = "1.1.0" diff --git a/zokrates_cli/examples/book/mpc_tutorial/circuit.zok b/zokrates_cli/examples/book/mpc_tutorial/program.zok similarity index 100% rename from zokrates_cli/examples/book/mpc_tutorial/circuit.zok rename to zokrates_cli/examples/book/mpc_tutorial/program.zok diff --git a/zokrates_cli/examples/book/mpc_tutorial/test.sh b/zokrates_cli/examples/book/mpc_tutorial/test.sh index 743b881b3..979f1e08b 100755 --- a/zokrates_cli/examples/book/mpc_tutorial/test.sh +++ b/zokrates_cli/examples/book/mpc_tutorial/test.sh @@ -7,8 +7,8 @@ function zokrates() { ZOKRATES_STDLIB=$stdlib $bin "$@" } -# compile the circuit -zokrates compile -i circuit.zok -o circuit +# compile the program +zokrates compile -i program.zok -o circuit # initialize the ceremony # this step requires phase1 files eg. phase1radix2m2 for circuits of 2^2 constraints diff --git a/zokrates_cli/examples/book/nova_step.zok b/zokrates_cli/examples/book/nova_step.zok new file mode 100644 index 000000000..15072a569 --- /dev/null +++ b/zokrates_cli/examples/book/nova_step.zok @@ -0,0 +1,3 @@ +def main(public field sum, private field element) -> field { + return sum + element; +} \ No newline at end of file diff --git a/zokrates_cli/examples/book/numeric_inference.zok b/zokrates_cli/examples/book/numeric_inference.zok index f81064319..b3446b51e 100644 --- a/zokrates_cli/examples/book/numeric_inference.zok +++ b/zokrates_cli/examples/book/numeric_inference.zok @@ -1,8 +1,8 @@ def main() { - // `255` is infered to `255f`, and the addition happens between field elements + // `255` is inferred to `255f`, and the addition happens between field elements assert(255 + 1f == 256); - // `255` is infered to `255u8`, and the addition happens between u8 + // `255` is inferred to `255u8`, and the addition happens between u8 // This causes an overflow assert(255 + 1u8 == 0); diff --git a/zokrates_cli/examples/book/sha256_tutorial/test.sh b/zokrates_cli/examples/book/sha256_tutorial/test.sh index 664749ccf..07756593e 100755 --- a/zokrates_cli/examples/book/sha256_tutorial/test.sh +++ b/zokrates_cli/examples/book/sha256_tutorial/test.sh @@ -8,9 +8,7 @@ function zokrates() { } zokrates compile -i hashexample.zok -zokrates compute-witness -a 0 0 0 5 - -grep '~out' witness +zokrates compute-witness -a 0 0 0 5 --verbose cp -f hashexample_updated.zok hashexample.zok diff --git a/zokrates_cli/examples/compile_errors/assembly/unallowed_type_in_assignment.zok b/zokrates_cli/examples/compile_errors/assembly/unallowed_type_in_assignment.zok new file mode 100644 index 000000000..d3c1c2329 --- /dev/null +++ b/zokrates_cli/examples/compile_errors/assembly/unallowed_type_in_assignment.zok @@ -0,0 +1,6 @@ +def main(bool a) { + bool mut b = false; + asm { + b <-- a; + } +} \ No newline at end of file diff --git a/zokrates_cli/examples/compile_errors/assembly/unallowed_type_in_constrained_assignment.zok b/zokrates_cli/examples/compile_errors/assembly/unallowed_type_in_constrained_assignment.zok new file mode 100644 index 000000000..f17a895f2 --- /dev/null +++ b/zokrates_cli/examples/compile_errors/assembly/unallowed_type_in_constrained_assignment.zok @@ -0,0 +1,6 @@ +def main() { + field[2] mut a = [0; 2]; + asm { + a <== [1, 2]; + } +} \ No newline at end of file diff --git a/zokrates_cli/examples/compile_errors/variable_sized_array.zok b/zokrates_cli/examples/compile_errors/variable_sized_array.zok new file mode 100644 index 000000000..bf15681a2 --- /dev/null +++ b/zokrates_cli/examples/compile_errors/variable_sized_array.zok @@ -0,0 +1,4 @@ +def main(u32 N) { + field[N] a = [0; N]; + return; +} \ No newline at end of file diff --git a/zokrates_cli/examples/sudoku/sudoku_checker.zok b/zokrates_cli/examples/sudoku/sudoku_checker.zok index 795e81ed0..4c01df6ec 100644 --- a/zokrates_cli/examples/sudoku/sudoku_checker.zok +++ b/zokrates_cli/examples/sudoku/sudoku_checker.zok @@ -12,11 +12,11 @@ def countDuplicates(field e11, field e12, field e21, field e22) -> field { field mut duplicates = e11 == e12 ? 1 : 0; - duplicates = duplicates + e11 == e21 ? 1 : 0; - duplicates = duplicates + e11 == e22 ? 1 : 0; - duplicates = duplicates + e12 == e21 ? 1 : 0; - duplicates = duplicates + e12 == e21 ? 1 : 0; - duplicates = duplicates + e21 == e22 ? 1 : 0; + duplicates = duplicates + (e11 == e21 ? 1 : 0); + duplicates = duplicates + (e11 == e22 ? 1 : 0); + duplicates = duplicates + (e12 == e21 ? 1 : 0); + duplicates = duplicates + (e12 == e22 ? 1 : 0); + duplicates = duplicates + (e21 == e22 ? 1 : 0); return duplicates; } diff --git a/zokrates_cli/src/bin.rs b/zokrates_cli/src/bin.rs index a5f8a31f8..d988e8983 100644 --- a/zokrates_cli/src/bin.rs +++ b/zokrates_cli/src/bin.rs @@ -1,5 +1,3 @@ -#![feature(panic_info_message)] -#![feature(backtrace)] // // @file bin.rs // @author Jacob Eberhardt @@ -49,6 +47,8 @@ fn cli() -> Result<(), String> { universal_setup::subcommand(), #[cfg(feature = "bellman")] mpc::subcommand(), + #[cfg(feature = "bellperson")] + nova::subcommand(), #[cfg(any(feature = "bellman", feature = "ark"))] setup::subcommand(), export_verifier::subcommand(), @@ -57,7 +57,9 @@ fn cli() -> Result<(), String> { generate_smtlib2::subcommand(), print_proof::subcommand(), #[cfg(any(feature = "bellman", feature = "ark"))] - verify::subcommand()]) + verify::subcommand(), + profile::subcommand() + ]) .get_matches(); match matches.subcommand() { @@ -69,6 +71,8 @@ fn cli() -> Result<(), String> { ("universal-setup", Some(sub_matches)) => universal_setup::exec(sub_matches), #[cfg(feature = "bellman")] ("mpc", Some(sub_matches)) => mpc::exec(sub_matches), + #[cfg(feature = "bellperson")] + ("nova", Some(sub_matches)) => nova::exec(sub_matches), #[cfg(any(feature = "bellman", feature = "ark"))] ("setup", Some(sub_matches)) => setup::exec(sub_matches), ("export-verifier", Some(sub_matches)) => export_verifier::exec(sub_matches), @@ -78,26 +82,14 @@ fn cli() -> Result<(), String> { ("print-proof", Some(sub_matches)) => print_proof::exec(sub_matches), #[cfg(any(feature = "bellman", feature = "ark"))] ("verify", Some(sub_matches)) => verify::exec(sub_matches), + ("profile", Some(sub_matches)) => profile::exec(sub_matches), _ => unreachable!(), } } fn panic_hook(pi: &std::panic::PanicInfo) { - let location = pi - .location() - .map(|l| format!("({})", l)) - .unwrap_or_default(); - - let message = pi - .message() - .map(|m| format!("{}", m)) - .or_else(|| pi.payload().downcast_ref::<&str>().map(|p| p.to_string())); - - if let Some(s) = message { - println!("{} {}", s, location); - } else { - println!("The compiler unexpectedly panicked {}", location); - } + println!("The compiler unexpectedly panicked"); + println!("{}", pi); #[cfg(debug_assertions)] { @@ -218,9 +210,15 @@ mod tests { .unwrap(); let interpreter = zokrates_interpreter::Interpreter::default(); + let prog = artifacts.prog(); let _ = interpreter - .execute(artifacts.prog(), &[Bn128Field::from(0u32)]) + .execute( + &[Bn128Field::from(0u32)], + prog.statements.into_iter(), + &prog.arguments, + &prog.solvers, + ) .unwrap(); } } @@ -258,8 +256,14 @@ mod tests { .unwrap(); let interpreter = zokrates_interpreter::Interpreter::default(); - - let res = interpreter.execute(artifacts.prog(), &[Bn128Field::from(0)]); + let prog = artifacts.prog(); + + let res = interpreter.execute( + &[Bn128Field::from(0)], + prog.statements.into_iter(), + &prog.arguments, + &prog.solvers, + ); assert!(res.is_err()); } diff --git a/zokrates_cli/src/cli_constants.rs b/zokrates_cli/src/cli_constants.rs index 2f002f8de..8e825c5b1 100644 --- a/zokrates_cli/src/cli_constants.rs +++ b/zokrates_cli/src/cli_constants.rs @@ -1,6 +1,9 @@ use zokrates_common::constants::*; pub const FLATTENED_CODE_DEFAULT_PATH: &str = "out"; +pub const NOVA_STEPS_PRIVATE_INPUTS: &str = "steps.json"; +pub const NOVA_PUBLIC_INIT: &str = "init.json"; +pub const JSON_NOVA_RUNNING_INSTANCE: &str = "running_instance.json"; pub const CIRCOM_R1CS_DEFAULT_PATH: &str = "out.r1cs"; pub const CIRCOM_WITNESS_DEFAULT_PATH: &str = "out.wtns"; pub const ABI_SPEC_DEFAULT_PATH: &str = "abi.json"; @@ -13,6 +16,7 @@ pub const UNIVERSAL_SETUP_DEFAULT_PATH: &str = "universal_setup.dat"; pub const UNIVERSAL_SETUP_DEFAULT_SIZE: &str = "10"; pub const SMTLIB2_DEFAULT_PATH: &str = "out.smt2"; pub const MPC_DEFAULT_PATH: &str = "mpc.params"; +pub const NOVA_PARAMS_DEFAULT_PATH: &str = "nova.params"; lazy_static! { pub static ref DEFAULT_STDLIB_PATH: String = dirs::home_dir() @@ -36,7 +40,7 @@ pub const BACKENDS: &[&str] = if cfg!(feature = "ark") { &[] }; -pub const CURVES: &[&str] = &[BN128, BLS12_381, BLS12_377, BW6_761]; +pub const CURVES: &[&str] = &[BN128, BLS12_381, BLS12_377, BW6_761, PALLAS, VESTA]; pub const SCHEMES: &[&str] = &[G16, GM17, MARLIN]; diff --git a/zokrates_cli/src/ops/check.rs b/zokrates_cli/src/ops/check.rs index 97d697efd..c2cada4d6 100644 --- a/zokrates_cli/src/ops/check.rs +++ b/zokrates_cli/src/ops/check.rs @@ -7,7 +7,9 @@ use std::path::{Path, PathBuf}; use zokrates_common::constants::BN128; use zokrates_common::{helpers::CurveParameter, CompileConfig}; use zokrates_core::compile::{check, CompileError}; -use zokrates_field::{Bls12_377Field, Bls12_381Field, Bn128Field, Bw6_761Field, Field}; +use zokrates_field::{ + Bls12_377Field, Bls12_381Field, Bn128Field, Bw6_761Field, Field, PallasField, VestaField, +}; use zokrates_fs_resolver::FileSystemResolver; pub fn subcommand() -> App<'static, 'static> { @@ -56,6 +58,8 @@ pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> { CurveParameter::Bls12_377 => cli_check::(sub_matches), CurveParameter::Bls12_381 => cli_check::(sub_matches), CurveParameter::Bw6_761 => cli_check::(sub_matches), + CurveParameter::Pallas => cli_check::(sub_matches), + CurveParameter::Vesta => cli_check::(sub_matches), } } diff --git a/zokrates_cli/src/ops/compile.rs b/zokrates_cli/src/ops/compile.rs index 74d26b6f2..5265aed72 100644 --- a/zokrates_cli/src/ops/compile.rs +++ b/zokrates_cli/src/ops/compile.rs @@ -10,7 +10,9 @@ use zokrates_circom::write_r1cs; use zokrates_common::constants::BN128; use zokrates_common::{helpers::CurveParameter, CompileConfig}; use zokrates_core::compile::{compile, CompileError}; -use zokrates_field::{Bls12_377Field, Bls12_381Field, Bn128Field, Bw6_761Field, Field}; +use zokrates_field::{ + Bls12_377Field, Bls12_381Field, Bn128Field, Bw6_761Field, Field, PallasField, VestaField, +}; use zokrates_fs_resolver::FileSystemResolver; pub fn subcommand() -> App<'static, 'static> { @@ -81,6 +83,8 @@ pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> { CurveParameter::Bls12_377 => cli_compile::(sub_matches), CurveParameter::Bls12_381 => cli_compile::(sub_matches), CurveParameter::Bw6_761 => cli_compile::(sub_matches), + CurveParameter::Pallas => cli_compile::(sub_matches), + CurveParameter::Vesta => cli_compile::(sub_matches), } } @@ -130,8 +134,8 @@ fn cli_compile(sub_matches: &ArgMatches) -> Result<(), String> { let arena = Arena::new(); - let artifacts = - compile::(source, path, Some(&resolver), config, &arena).map_err(|e| { + let artifacts = compile::(source, path.clone(), Some(&resolver), config, &arena) + .map_err(|e| { format!( "Compilation failed:\n\n{}", e.0.iter() @@ -145,16 +149,24 @@ fn cli_compile(sub_matches: &ArgMatches) -> Result<(), String> { // serialize flattened program and write to binary file log::debug!("Serialize program"); - let bin_output_file = File::create(&bin_output_path) + let bin_output_file = File::create(bin_output_path) .map_err(|why| format!("Could not create {}: {}", bin_output_path.display(), why))?; - let r1cs_output_file = File::create(&r1cs_output_path) + let r1cs_output_file = File::create(r1cs_output_path) .map_err(|why| format!("Could not create {}: {}", r1cs_output_path.display(), why))?; let mut bin_writer = BufWriter::new(bin_output_file); let mut r1cs_writer = BufWriter::new(r1cs_output_file); - let program_flattened = program_flattened.collect(); + let mut program_flattened = program_flattened.collect(); + + // hide user path + program_flattened.module_map = program_flattened + .module_map + .remap_prefix(path.parent().unwrap(), Path::new("")); + program_flattened.module_map = program_flattened + .module_map + .remap_prefix(Path::new(stdlib_path), Path::new("STDLIB")); write_r1cs(&mut r1cs_writer, program_flattened.clone()).unwrap(); @@ -162,7 +174,7 @@ fn cli_compile(sub_matches: &ArgMatches) -> Result<(), String> { Ok(constraint_count) => { // serialize ABI spec and write to JSON file log::debug!("Serialize ABI"); - let abi_spec_file = File::create(&abi_spec_path) + let abi_spec_file = File::create(abi_spec_path) .map_err(|why| format!("Could not create {}: {}", abi_spec_path.display(), why))?; let mut writer = BufWriter::new(abi_spec_file); diff --git a/zokrates_cli/src/ops/compute_witness.rs b/zokrates_cli/src/ops/compute_witness.rs index ab2a959bd..9b05237a8 100644 --- a/zokrates_cli/src/ops/compute_witness.rs +++ b/zokrates_cli/src/ops/compute_witness.rs @@ -66,6 +66,10 @@ pub fn subcommand() -> App<'static, 'static> { .help("Read arguments from stdin") .conflicts_with("arguments") .required(false) + ).arg(Arg::with_name("json") + .long("json") + .help("Write witness in a json format for debugging purposes") + .required(false) ) } @@ -73,7 +77,7 @@ 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!("Could not open {}: {}", path.display(), why))?; + File::open(path).map_err(|why| format!("Could not open {}: {}", path.display(), why))?; let mut reader = BufReader::new(file); @@ -82,6 +86,8 @@ pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> { 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), + ProgEnum::PallasProgram(p) => cli_compute(p, sub_matches), + ProgEnum::VestaProgram(p) => cli_compute(p, sub_matches), } } @@ -102,7 +108,7 @@ fn cli_compute<'a, T: Field, I: Iterator>>( let signature = match is_abi { true => { let path = Path::new(sub_matches.value_of("abi-spec").unwrap()); - let file = File::open(&path) + let file = File::open(path) .map_err(|why| format!("Could not open {}: {}", path.display(), why))?; let mut reader = BufReader::new(file); @@ -168,11 +174,16 @@ fn cli_compute<'a, T: Field, I: Iterator>>( .map_err(|e| format!("Could not parse argument: {}", e))?; let interpreter = zokrates_interpreter::Interpreter::default(); - let public_inputs = ir_prog.public_inputs(); let witness = interpreter - .execute_with_log_stream(ir_prog, &arguments.encode(), &mut std::io::stdout()) + .execute_with_log_stream( + &arguments.encode(), + ir_prog.statements, + &ir_prog.arguments, + &ir_prog.solvers, + &mut std::io::stdout(), + ) .map_err(|e| format!("Execution failed: {}", e))?; use zokrates_abi::Decode; @@ -186,7 +197,7 @@ fn cli_compute<'a, T: Field, I: Iterator>>( // write witness to file let output_path = Path::new(sub_matches.value_of("output").unwrap()); - let output_file = File::create(&output_path) + let output_file = File::create(output_path) .map_err(|why| format!("Could not create {}: {}", output_path.display(), why))?; let writer = BufWriter::new(output_file); @@ -195,9 +206,22 @@ fn cli_compute<'a, T: Field, I: Iterator>>( .write(writer) .map_err(|why| format!("Could not save witness: {:?}", why))?; + // write witness in the json format + if sub_matches.is_present("json") { + let json_path = Path::new(sub_matches.value_of("output").unwrap()).with_extension("json"); + let json_file = File::create(&json_path) + .map_err(|why| format!("Could not create {}: {}", json_path.display(), why))?; + + let writer = BufWriter::new(json_file); + + witness + .write_json(writer) + .map_err(|why| format!("Could not save {}: {:?}", json_path.display(), why))?; + } + // write circom witness to file let wtns_path = Path::new(sub_matches.value_of("circom-witness").unwrap()); - let wtns_file = File::create(&wtns_path) + let wtns_file = File::create(wtns_path) .map_err(|why| format!("Could not create {}: {}", output_path.display(), why))?; let mut writer = BufWriter::new(wtns_file); diff --git a/zokrates_cli/src/ops/export_verifier.rs b/zokrates_cli/src/ops/export_verifier.rs index 08b35a44a..f343a7374 100644 --- a/zokrates_cli/src/ops/export_verifier.rs +++ b/zokrates_cli/src/ops/export_verifier.rs @@ -35,7 +35,7 @@ pub fn subcommand() -> App<'static, 'static> { pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> { let vk_path = Path::new(sub_matches.value_of("input").unwrap()); - let vk_file = File::open(&vk_path) + let vk_file = File::open(vk_path) .map_err(|why| format!("Could not open {}: {}", vk_path.display(), why))?; // deserialize vk to JSON @@ -84,7 +84,7 @@ fn cli_export_verifier App<'static, 'static> { .possible_values(cli_constants::SCHEMES) .default_value(constants::G16), ) + .arg( + Arg::with_name("entropy") + .short("e") + .long("entropy") + .help("User provided randomness") + .takes_value(true) + .required(false), + ) } 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) + let program_file = File::open(program_path) .map_err(|why| format!("Could not open {}: {}", program_path.display(), why))?; let mut reader = BufReader::new(program_file); @@ -112,6 +123,7 @@ pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> { ProgEnum::Bls12_381Program(p) => cli_generate_proof::<_, _, G16, Ark>(p, sub_matches), ProgEnum::Bls12_377Program(p) => cli_generate_proof::<_, _, G16, Ark>(p, sub_matches), ProgEnum::Bw6_761Program(p) => cli_generate_proof::<_, _, G16, Ark>(p, sub_matches), + _ => unreachable!(), }, #[cfg(feature = "ark")] Parameters(BackendParameter::Ark, _, SchemeParameter::GM17) => match prog { @@ -119,6 +131,7 @@ pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> { ProgEnum::Bls12_381Program(p) => cli_generate_proof::<_, _, GM17, Ark>(p, sub_matches), ProgEnum::Bls12_377Program(p) => cli_generate_proof::<_, _, GM17, Ark>(p, sub_matches), ProgEnum::Bw6_761Program(p) => cli_generate_proof::<_, _, GM17, Ark>(p, sub_matches), + _ => unreachable!(), }, #[cfg(feature = "ark")] Parameters(BackendParameter::Ark, _, SchemeParameter::MARLIN) => match prog { @@ -130,6 +143,7 @@ pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> { cli_generate_proof::<_, _, Marlin, Ark>(p, sub_matches) } ProgEnum::Bw6_761Program(p) => cli_generate_proof::<_, _, Marlin, Ark>(p, sub_matches), + _ => unreachable!(), }, _ => unreachable!(), } @@ -149,25 +163,28 @@ fn cli_generate_proof< // deserialize witness let witness_path = Path::new(sub_matches.value_of("witness").unwrap()); - let witness_file = File::open(&witness_path) + let witness_file = File::open(witness_path) .map_err(|why| format!("Could not open {}: {}", witness_path.display(), why))?; - let witness = ir::Witness::read(witness_file) + let witness_reader = BufReader::new(witness_file); + + let witness = ir::Witness::read(witness_reader) .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) + let pk_file = File::open(pk_path) .map_err(|why| format!("Could not open {}: {}", pk_path.display(), why))?; - let mut pk: Vec = Vec::new(); - let mut pk_reader = BufReader::new(pk_file); - pk_reader - .read_to_end(&mut pk) - .map_err(|why| format!("Could not read {}: {}", pk_path.display(), why))?; + let pk_reader = BufReader::new(pk_file); + + let mut rng = sub_matches + .value_of("entropy") + .map(get_rng_from_entropy) + .unwrap_or_else(StdRng::from_entropy); - let proof = B::generate_proof(program, witness, pk); + let proof = B::generate_proof(program, witness, pk_reader, &mut rng); let mut proof_file = File::create(proof_path).unwrap(); let proof = diff --git a/zokrates_cli/src/ops/generate_smtlib2.rs b/zokrates_cli/src/ops/generate_smtlib2.rs index ac58f8e56..f7daf352e 100644 --- a/zokrates_cli/src/ops/generate_smtlib2.rs +++ b/zokrates_cli/src/ops/generate_smtlib2.rs @@ -35,7 +35,7 @@ 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!("Could not open {}: {}", path.display(), why))?; + File::open(path).map_err(|why| format!("Could not open {}: {}", path.display(), why))?; let mut reader = BufReader::new(file); @@ -44,6 +44,8 @@ pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> { ProgEnum::Bls12_377Program(p) => cli_smtlib2(p, sub_matches), ProgEnum::Bls12_381Program(p) => cli_smtlib2(p, sub_matches), ProgEnum::Bw6_761Program(p) => cli_smtlib2(p, sub_matches), + ProgEnum::PallasProgram(p) => cli_smtlib2(p, sub_matches), + ProgEnum::VestaProgram(p) => cli_smtlib2(p, sub_matches), } } diff --git a/zokrates_cli/src/ops/inspect.rs b/zokrates_cli/src/ops/inspect.rs index b8ca37545..e4bd7f064 100644 --- a/zokrates_cli/src/ops/inspect.rs +++ b/zokrates_cli/src/ops/inspect.rs @@ -31,7 +31,7 @@ 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!("Could not open `{}`: {}", path.display(), why))?; + File::open(path).map_err(|why| format!("Could not open `{}`: {}", path.display(), why))?; let mut reader = BufReader::new(file); @@ -40,6 +40,8 @@ pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> { ProgEnum::Bls12_377Program(p) => cli_inspect(p, sub_matches), ProgEnum::Bls12_381Program(p) => cli_inspect(p, sub_matches), ProgEnum::Bw6_761Program(p) => cli_inspect(p, sub_matches), + ProgEnum::PallasProgram(p) => cli_inspect(p, sub_matches), + ProgEnum::VestaProgram(p) => cli_inspect(p, sub_matches), } } diff --git a/zokrates_cli/src/ops/mod.rs b/zokrates_cli/src/ops/mod.rs index e82dd506a..2479786d8 100644 --- a/zokrates_cli/src/ops/mod.rs +++ b/zokrates_cli/src/ops/mod.rs @@ -8,7 +8,10 @@ pub mod generate_smtlib2; pub mod inspect; #[cfg(feature = "bellman")] pub mod mpc; +#[cfg(feature = "bellperson")] +pub mod nova; pub mod print_proof; +pub mod profile; #[cfg(any(feature = "bellman", feature = "ark"))] pub mod setup; #[cfg(feature = "ark")] diff --git a/zokrates_cli/src/ops/mpc/beacon.rs b/zokrates_cli/src/ops/mpc/beacon.rs index b5af669e7..71412868b 100644 --- a/zokrates_cli/src/ops/mpc/beacon.rs +++ b/zokrates_cli/src/ops/mpc/beacon.rs @@ -1,5 +1,6 @@ use crate::cli_constants::MPC_DEFAULT_PATH; use clap::{App, Arg, ArgMatches, SubCommand}; +use rand_0_8::{rngs::StdRng, SeedableRng}; use std::fs::File; use std::io::{BufReader, BufWriter}; use std::path::Path; @@ -72,7 +73,7 @@ fn cli_mpc_beacon, B: MpcBack ) -> Result<(), String> { let path = Path::new(sub_matches.value_of("input").unwrap()); let file = - File::open(&path).map_err(|why| format!("Could not open `{}`: {}", path.display(), why))?; + File::open(path).map_err(|why| format!("Could not open `{}`: {}", path.display(), why))?; let mut reader = BufReader::new(file); @@ -87,9 +88,7 @@ fn cli_mpc_beacon, B: MpcBack // Create an RNG based on the outcome of the random beacon let mut rng = { - use byteorder::{BigEndian, ReadBytesExt}; - use rand_0_4::chacha::ChaChaRng; - use rand_0_4::SeedableRng; + use byteorder::ReadBytesExt; use sha2::{Digest, Sha256}; // The hash used for the beacon @@ -126,16 +125,16 @@ fn cli_mpc_beacon, B: MpcBack let mut digest = &cur_hash[..]; - let mut seed = [0u32; 8]; + let mut seed = [0u8; 32]; for e in &mut seed { - *e = digest.read_u32::().unwrap(); + *e = digest.read_u8().unwrap(); } - ChaChaRng::from_seed(&seed) + StdRng::from_seed(seed) }; let output_path = Path::new(sub_matches.value_of("output").unwrap()); - let output_file = File::create(&output_path) + let output_file = File::create(output_path) .map_err(|why| format!("Could not create `{}`: {}", output_path.display(), why))?; let mut writer = BufWriter::new(output_file); diff --git a/zokrates_cli/src/ops/mpc/contribute.rs b/zokrates_cli/src/ops/mpc/contribute.rs index 3490f381b..96128768c 100644 --- a/zokrates_cli/src/ops/mpc/contribute.rs +++ b/zokrates_cli/src/ops/mpc/contribute.rs @@ -1,11 +1,13 @@ use crate::cli_constants::MPC_DEFAULT_PATH; use clap::{App, Arg, ArgMatches, SubCommand}; +use rand_0_8::{rngs::StdRng, SeedableRng}; use std::fs::File; use std::io::{BufReader, BufWriter}; use std::path::Path; use zokrates_bellman::Bellman; use zokrates_common::constants::{BLS12_381, BN128}; use zokrates_field::{BellmanFieldExtensions, Bls12_381Field, Bn128Field, Field}; +use zokrates_proof_systems::rng::get_rng_from_entropy; use zokrates_proof_systems::{MpcBackend, MpcScheme, G16}; pub fn subcommand() -> App<'static, 'static> { @@ -68,52 +70,23 @@ pub fn cli_mpc_contribute< ) -> Result<(), String> { let path = Path::new(sub_matches.value_of("input").unwrap()); let file = - File::open(&path).map_err(|why| format!("Could not open `{}`: {}", path.display(), why))?; + File::open(path).map_err(|why| format!("Could not open `{}`: {}", path.display(), why))?; let mut reader = BufReader::new(file); - let entropy = sub_matches.value_of("entropy").unwrap(); - - // Create an RNG based on a mixture of system randomness and user provided randomness - let mut rng = { - use blake2::{Blake2b, Digest}; - use byteorder::{BigEndian, ReadBytesExt}; - use rand_0_4::chacha::ChaChaRng; - use rand_0_4::{OsRng, Rng, SeedableRng}; - - let h = { - let mut system_rng = OsRng::new().unwrap(); - let mut h = Blake2b::default(); - - // Gather 1024 bytes of entropy from the system - for _ in 0..1024 { - let r: u8 = system_rng.gen(); - h.input(&[r]); - } - - // Hash it all up to make a seed - h.input(&entropy.as_bytes()); - h.result() - }; - - let mut digest = &h[..]; - - // Interpret the first 32 bytes of the digest as 8 32-bit words - let mut seed = [0u32; 8]; - for e in &mut seed { - *e = digest.read_u32::().unwrap(); - } - - ChaChaRng::from_seed(&seed) - }; let output_path = Path::new(sub_matches.value_of("output").unwrap()); - let output_file = File::create(&output_path) + let output_file = File::create(output_path) .map_err(|why| format!("Could not create `{}`: {}", output_path.display(), why))?; let mut writer = BufWriter::new(output_file); println!("Contributing to `{}`...", path.display()); + let mut rng = sub_matches + .value_of("entropy") + .map(get_rng_from_entropy) + .unwrap_or_else(StdRng::from_entropy); + let hash = B::contribute(&mut reader, &mut rng, &mut writer) .map_err(|e| format!("Failed to contribute: {}", e))?; println!("The BLAKE2b hash of your contribution is:\n"); diff --git a/zokrates_cli/src/ops/mpc/export.rs b/zokrates_cli/src/ops/mpc/export.rs index cf640fa1c..87c780052 100644 --- a/zokrates_cli/src/ops/mpc/export.rs +++ b/zokrates_cli/src/ops/mpc/export.rs @@ -66,7 +66,7 @@ pub fn cli_mpc_export, B: Mpc ) -> Result<(), String> { let path = Path::new(sub_matches.value_of("input").unwrap()); let file = - File::open(&path).map_err(|why| format!("Could not open `{}`: {}", path.display(), why))?; + File::open(path).map_err(|why| format!("Could not open `{}`: {}", path.display(), why))?; let mut reader = BufReader::new(file); diff --git a/zokrates_cli/src/ops/mpc/init.rs b/zokrates_cli/src/ops/mpc/init.rs index eb7ba16e4..72e2283c6 100644 --- a/zokrates_cli/src/ops/mpc/init.rs +++ b/zokrates_cli/src/ops/mpc/init.rs @@ -24,8 +24,8 @@ pub fn subcommand() -> App<'static, 'static> { .arg( Arg::with_name("radix-path") .short("r") - .long("radix-dir") - .help("Path of the directory containing parameters for various 2^m circuit depths (phase1radix2m{0..=m})") + .long("radix-path") + .help("Path of the phase1radix2m{n} file") .value_name("PATH") .takes_value(true) .required(true), @@ -46,7 +46,7 @@ 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!("Could not open `{}`: {}", path.display(), why))?; + File::open(path).map_err(|why| format!("Could not open `{}`: {}", path.display(), why))?; let mut reader = BufReader::new(file); @@ -76,7 +76,7 @@ fn cli_mpc_init< let mut radix_reader = BufReader::new(radix_file); let output_path = Path::new(sub_matches.value_of("output").unwrap()); - let output_file = File::create(&output_path) + let output_file = File::create(output_path) .map_err(|why| format!("Could not create `{}`: {}", output_path.display(), why))?; let mut writer = BufWriter::new(output_file); diff --git a/zokrates_cli/src/ops/mpc/mod.rs b/zokrates_cli/src/ops/mpc/mod.rs index 000d82023..b01a1ddc9 100644 --- a/zokrates_cli/src/ops/mpc/mod.rs +++ b/zokrates_cli/src/ops/mpc/mod.rs @@ -1,4 +1,4 @@ -use clap::{App, ArgMatches, SubCommand}; +use clap::{App, AppSettings, ArgMatches, SubCommand}; pub mod beacon; pub mod contribute; @@ -9,6 +9,7 @@ pub mod verify; pub fn subcommand() -> App<'static, 'static> { SubCommand::with_name("mpc") .about("Multi-party computation (MPC) protocol") + .setting(AppSettings::SubcommandRequiredElseHelp) .subcommands(vec![ init::subcommand().display_order(1), contribute::subcommand().display_order(2), diff --git a/zokrates_cli/src/ops/mpc/verify.rs b/zokrates_cli/src/ops/mpc/verify.rs index fa014bd06..ef0371127 100644 --- a/zokrates_cli/src/ops/mpc/verify.rs +++ b/zokrates_cli/src/ops/mpc/verify.rs @@ -46,7 +46,7 @@ pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> { // read compiled program let path = Path::new(sub_matches.value_of("circuit").unwrap()); let file = - File::open(&path).map_err(|why| format!("Could not open `{}`: {}", path.display(), why))?; + File::open(path).map_err(|why| format!("Could not open `{}`: {}", path.display(), why))?; let mut reader = BufReader::new(file); @@ -71,9 +71,9 @@ fn cli_mpc_verify< let path = Path::new(sub_matches.value_of("input").unwrap()); let file = - File::open(&path).map_err(|why| format!("Could not open `{}`: {}", path.display(), why))?; + File::open(path).map_err(|why| format!("Could not open `{}`: {}", path.display(), why))?; - let mut reader = BufReader::new(file); + let reader = BufReader::new(file); let radix_path = Path::new(sub_matches.value_of("radix-path").unwrap()); let radix_file = File::open(radix_path) @@ -81,7 +81,7 @@ fn cli_mpc_verify< let mut radix_reader = BufReader::new(radix_file); - let result = B::verify(&mut reader, program, &mut radix_reader) + let result = B::verify(reader, program, &mut radix_reader) .map_err(|e| format!("Verification failed: {}", e))?; let contribution_count = result.len(); diff --git a/zokrates_cli/src/ops/nova/compress.rs b/zokrates_cli/src/ops/nova/compress.rs new file mode 100644 index 000000000..1adc722eb --- /dev/null +++ b/zokrates_cli/src/ops/nova/compress.rs @@ -0,0 +1,120 @@ +use crate::cli_constants::{self, JSON_NOVA_RUNNING_INSTANCE}; +use clap::{App, Arg, ArgMatches, SubCommand}; + +use zokrates_field::PallasField; + +use std::io::BufReader; +use std::path::Path; +use std::{fs::File, io::Write}; + +use zokrates_bellperson::nova::{self, NovaField, RecursiveSNARKWithStepCount}; + +pub fn subcommand() -> App<'static, 'static> { + SubCommand::with_name("compress") + .about("Compresses an instance to a Spartan SNARK") + .arg( + Arg::with_name("input") + .long("i") + .help("Path to the running instance") + .takes_value(true) + .default_value(JSON_NOVA_RUNNING_INSTANCE), + ) + .arg( + Arg::with_name("params-path") + .short("p") + .long("params-path") + .help("Path of the nova public parameters") + .value_name("FILE") + .takes_value(true) + .required(false) + .default_value(cli_constants::NOVA_PARAMS_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(cli_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(cli_constants::VERIFICATION_KEY_DEFAULT_PATH), + ) +} + +pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> { + let path = Path::new(sub_matches.value_of("input").unwrap()); + let file = + File::open(path).map_err(|why| format!("Could not open {}: {}", path.display(), why))?; + + let reader = BufReader::new(file); + let instance: RecursiveSNARKWithStepCount = + serde_json::from_reader(reader).unwrap(); + + cli_nova_compress::(instance, sub_matches) +} + +fn cli_nova_compress( + instance: RecursiveSNARKWithStepCount, + sub_matches: &ArgMatches, +) -> Result<(), String> { + let params_path = Path::new(sub_matches.value_of("params-path").unwrap()); + let params_file = File::open(params_path) + .map_err(|why| format!("Could not open {}: {}", params_path.display(), why))?; + + let params_reader = BufReader::new(params_file); + let params = serde_cbor::from_reader(params_reader) + .map_err(|why| format!("Could not deserialize {}: {}", params_path.display(), why))?; + + let proof_path = Path::new(sub_matches.value_of("proof-path").unwrap()); + let verification_key_path = Path::new(sub_matches.value_of("verification-key-path").unwrap()); + + let (proof, vk) = nova::compress(¶ms, instance); + + let proof_json = serde_json::to_string_pretty(&proof).unwrap(); + + let mut proof_file = File::create(proof_path) + .map_err(|why| format!("Could not create {}: {}", proof_path.display(), why))?; + + proof_file + .write(proof_json.as_bytes()) + .map_err(|why| format!("Could not write to {}: {}", proof_path.display(), why))?; + + println!("Compressed SNARK written to '{}'", proof_path.display()); + + let verification_key_json = serde_json::to_string_pretty(&vk).unwrap(); + + let mut verification_key_file = File::create(verification_key_path).map_err(|why| { + format!( + "Could not create {}: {}", + verification_key_path.display(), + why + ) + })?; + + verification_key_file + .write(verification_key_json.as_bytes()) + .map_err(|why| { + format!( + "Could not write to {}: {}", + verification_key_path.display(), + why + ) + })?; + + println!( + "Verification key written to '{}'", + verification_key_path.display() + ); + + Ok(()) +} diff --git a/zokrates_cli/src/ops/nova/mod.rs b/zokrates_cli/src/ops/nova/mod.rs new file mode 100644 index 000000000..3432fa561 --- /dev/null +++ b/zokrates_cli/src/ops/nova/mod.rs @@ -0,0 +1,28 @@ +use clap::{App, AppSettings, ArgMatches, SubCommand}; + +pub mod compress; +pub mod prove; +pub mod setup; +pub mod verify; + +pub fn subcommand() -> App<'static, 'static> { + SubCommand::with_name("nova") + .about("Nova IVC") + .setting(AppSettings::SubcommandRequiredElseHelp) + .subcommands(vec![ + setup::subcommand().display_order(1), + prove::subcommand().display_order(2), + compress::subcommand().display_order(3), + verify::subcommand().display_order(4), + ]) +} + +pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> { + match sub_matches.subcommand() { + ("setup", Some(sub_matches)) => setup::exec(sub_matches), + ("prove", Some(sub_matches)) => prove::exec(sub_matches), + ("compress", Some(sub_matches)) => compress::exec(sub_matches), + ("verify", Some(sub_matches)) => verify::exec(sub_matches), + _ => unreachable!(), + } +} diff --git a/zokrates_cli/src/ops/nova/prove.rs b/zokrates_cli/src/ops/nova/prove.rs new file mode 100644 index 000000000..2ab33d65a --- /dev/null +++ b/zokrates_cli/src/ops/nova/prove.rs @@ -0,0 +1,204 @@ +use crate::cli_constants::{ + self, FLATTENED_CODE_DEFAULT_PATH, NOVA_PUBLIC_INIT, NOVA_STEPS_PRIVATE_INPUTS, +}; +use clap::{App, Arg, ArgMatches, SubCommand}; +use serde_json::{from_reader, Value}; +use std::fs::File; +use std::io::{BufReader, Write}; +use std::path::Path; +use zokrates_abi::{parse_value, Encode, Values}; +use zokrates_ast::ir::{self, ProgEnum}; +use zokrates_ast::typed::abi::Abi; +use zokrates_bellperson::nova::{self, NovaField}; + +pub fn subcommand() -> App<'static, 'static> { + SubCommand::with_name("prove") + .about("Proves many steps of an incremental computation") + .arg( + Arg::with_name("init") + .long("init") + .help("Path to the initial value of the public input") + .takes_value(true) + .default_value(NOVA_PUBLIC_INIT), + ) + .arg( + Arg::with_name("continue") + .short("c") + .long("continue") + .help("Start from an existing proof") + .takes_value(false) + .required(false), + ) + .arg( + Arg::with_name("steps") + .long("steps") + .help("Path to the value of the private input for each step") + .takes_value(true) + .default_value(NOVA_STEPS_PRIVATE_INPUTS), + ) + .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(cli_constants::ABI_SPEC_DEFAULT_PATH), + ) + .arg( + Arg::with_name("params-path") + .short("p") + .long("params-path") + .help("Path of the nova public parameters") + .value_name("FILE") + .takes_value(true) + .required(false) + .default_value(cli_constants::NOVA_PARAMS_DEFAULT_PATH), + ) + .arg( + Arg::with_name("instance-path") + .short("j") + .long("instance-path") + .help("Path of the JSON running instance file") + .value_name("FILE") + .takes_value(true) + .required(false) + .default_value(cli_constants::JSON_NOVA_RUNNING_INSTANCE), + ) +} + +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!("Could not open {}: {}", path.display(), why))?; + + let mut reader = BufReader::new(file); + + match ProgEnum::deserialize(&mut reader)? { + ProgEnum::PallasProgram(p) => cli_nova_prove_step(p, sub_matches), + ProgEnum::VestaProgram(p) => cli_nova_prove_step(p, sub_matches), + _ => Err("Nova is only supported for the following curves: [\"pallas\", \"vesta\"]".into()), + } +} + +fn cli_nova_prove_step<'ast, T: NovaField, I: Iterator>>( + program: ir::ProgIterator<'ast, T, I>, + sub_matches: &ArgMatches, +) -> Result<(), String> { + let proof_path = Path::new(sub_matches.value_of("instance-path").unwrap()); + + println!("Reading step program..."); + let program = program.collect(); + println!("Done"); + + let path = Path::new(sub_matches.value_of("abi-spec").unwrap()); + let file = + File::open(path).map_err(|why| format!("Could not open {}: {}", path.display(), why))?; + + let mut reader = BufReader::new(file); + + let abi: Abi = from_reader(&mut reader).map_err(|why| why.to_string())?; + let signature = abi.signature(); + + let init_type = signature.inputs[0].clone(); + let step_type = signature.inputs[1].clone(); + + let init = { + let path = Path::new(sub_matches.value_of("init").unwrap()); + let file = File::open(path).unwrap(); + let reader = BufReader::new(file); + + parse_value(serde_json::from_reader(reader).unwrap(), init_type) + .unwrap() + .encode() + }; + + let steps: Vec<_> = { + let path = Path::new(sub_matches.value_of("steps").unwrap()); + let json_str = std::fs::read_to_string(path).unwrap(); + + { + let values: Value = serde_json::from_str(&json_str).map_err(|e| e.to_string())?; + + match values { + Value::Array(values) => Ok(Values( + values + .into_iter() + .map(|v| parse_value(v, step_type.clone())) + .collect::>() + .map_err(|e| e.to_string())?, + )), + _ => Err(format!("Expected an array of values, found `{}`", values)), + } + } + .unwrap() + .0 + .into_iter() + .map(|e| e.encode()) + .collect() + }; + + let from = sub_matches.is_present("continue").then(|| { + let path = Path::new(sub_matches.value_of("instance-path").unwrap()); + serde_json::from_reader(BufReader::new(File::open(path).unwrap())).unwrap() + }); + + println!("Reading parameters..."); + + let params_path = Path::new(sub_matches.value_of("params-path").unwrap()); + let params_file = File::open(params_path) + .map_err(|why| format!("Could not open {}: {}", params_path.display(), why))?; + + let params_reader = BufReader::new(params_file); + let params = serde_cbor::from_reader(params_reader) + .map_err(|why| format!("Could not deserialize {}: {}", params_path.display(), why))?; + + println!("Done"); + + let mut proof_file = File::create(proof_path) + .map_err(|why| format!("Could not create {}: {}", proof_path.display(), why))?; + + println!("Generating proof..."); + let proof = nova::prove(¶ms, &program, init.clone(), from, steps) + .map_err(|e| format!("Error `{:#?}` during proving", e))?; + + println!("Done"); + + let proof_json = serde_json::to_string_pretty(&proof).unwrap(); + + proof_file + .write(proof_json.as_bytes()) + .map_err(|why| format!("Could not write to {}: {}", proof_path.display(), why))?; + + match proof { + None => println!("No proof to verify"), + Some(ref proof) => { + // verify the recursive SNARK + println!("Verifying the final proof..."); + let res = nova::verify(¶ms, proof, init); + + match res { + Ok(_) => { + println!("Final proof verified successfully"); + } + Err(e) => { + println!("Error while verifying the final proof: {}", e); + } + } + } + } + + Ok(()) +} diff --git a/zokrates_cli/src/ops/nova/setup.rs b/zokrates_cli/src/ops/nova/setup.rs new file mode 100644 index 000000000..9381f1bcb --- /dev/null +++ b/zokrates_cli/src/ops/nova/setup.rs @@ -0,0 +1,70 @@ +use crate::cli_constants::{FLATTENED_CODE_DEFAULT_PATH, NOVA_PARAMS_DEFAULT_PATH}; +use clap::{App, Arg, ArgMatches, SubCommand}; +use std::fs::File; +use std::io::BufReader; +use std::path::Path; +use zokrates_ast::ir::{self, ProgEnum}; +use zokrates_bellperson::nova::{self, NovaField}; + +pub fn subcommand() -> App<'static, 'static> { + SubCommand::with_name("setup") + .about("Performs a nova 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(FLATTENED_CODE_DEFAULT_PATH), + ) + .arg( + Arg::with_name("output") + .short("o") + .long("output") + .help("Path of the generated public parameters") + .value_name("FILE") + .takes_value(true) + .required(false) + .default_value(NOVA_PARAMS_DEFAULT_PATH), + ) +} + +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!("Could not open {}: {}", path.display(), why))?; + + let mut reader = BufReader::new(file); + + match ProgEnum::deserialize(&mut reader)? { + ProgEnum::PallasProgram(p) => cli_nova_setup(p, sub_matches), + ProgEnum::VestaProgram(p) => cli_nova_setup(p, sub_matches), + _ => Err("Nova is only supported for the following curves: [\"pallas\", \"vesta\"]".into()), + } +} + +fn cli_nova_setup<'ast, T: NovaField, I: Iterator>>( + program: ir::ProgIterator<'ast, T, I>, + sub_matches: &ArgMatches, +) -> Result<(), String> { + println!("Generating public parameters..."); + + let program = program.collect(); + let params_path = Path::new(sub_matches.value_of("output").unwrap()); + + let params_file = File::create(params_path) + .map_err(|why| format!("Could not create {}: {}", params_path.display(), why))?; + + let params = nova::generate_public_parameters(&program).map_err(|e| e.to_string())?; + + // write public parameters + serde_cbor::to_writer(params_file, ¶ms) + .map_err(|why| format!("Could not write to {}: {}", params_path.display(), why))?; + + println!("Public parameters written to '{}'", params_path.display()); + + Ok(()) +} diff --git a/zokrates_cli/src/ops/nova/verify.rs b/zokrates_cli/src/ops/nova/verify.rs new file mode 100644 index 000000000..9a6452bd0 --- /dev/null +++ b/zokrates_cli/src/ops/nova/verify.rs @@ -0,0 +1,125 @@ +use crate::cli_constants::{self, NOVA_PUBLIC_INIT}; +use clap::{App, Arg, ArgMatches, SubCommand}; +use serde_json::from_reader; +use std::fs::File; +use std::io::BufReader; +use std::path::Path; +use zokrates_abi::{parse_value, Encode}; + +use zokrates_ast::typed::abi::Abi; +use zokrates_bellperson::nova::{ + self, CompressedSNARK, NovaField, RecursiveSNARKWithStepCount, VerifierKey, +}; +use zokrates_field::PallasField; + +pub fn subcommand() -> App<'static, 'static> { + SubCommand::with_name("verify") + .about("Verifies a Nova compressed proof") + .arg( + Arg::with_name("init") + .long("init") + .help("Path to the initial value of the public input") + .takes_value(true) + .default_value(NOVA_PUBLIC_INIT), + ) + .arg( + Arg::with_name("proof-path") + .short("j") + .long("proof-path") + .help("Path of the JSON compressed proof path") + .value_name("FILE") + .takes_value(true) + .required(false) + .default_value(cli_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(cli_constants::VERIFICATION_KEY_DEFAULT_PATH), + ) + .arg( + Arg::with_name("instance-path") + .long("instance-path") + .help("Path of the JSON running instance file") + .value_name("FILE") + .takes_value(true) + .required(false) + .default_value(cli_constants::JSON_NOVA_RUNNING_INSTANCE), + ) + .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(cli_constants::ABI_SPEC_DEFAULT_PATH), + ) +} + +pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> { + let proof_path = sub_matches.value_of("proof-path").unwrap(); + + let proof_file = + File::open(proof_path).map_err(|why| format!("Could not open {}: {}", proof_path, why))?; + + let proof_reader = BufReader::new(proof_file); + + let verification_key_path = sub_matches.value_of("verification-key-path").unwrap(); + + let verification_key_file = File::open(verification_key_path) + .map_err(|why| format!("Could not open {}: {}", verification_key_path, why))?; + + let verification_key_reader = BufReader::new(verification_key_file); + + let proof: CompressedSNARK = serde_json::from_reader(proof_reader).unwrap(); + let vk: VerifierKey = serde_json::from_reader(verification_key_reader).unwrap(); + + cli_nova_verify(proof, vk, sub_matches) +} + +fn cli_nova_verify<'ast, T: NovaField>( + proof: CompressedSNARK<'ast, T>, + vk: VerifierKey<'ast, T>, + sub_matches: &ArgMatches, +) -> Result<(), String> { + let path = Path::new(sub_matches.value_of("abi-spec").unwrap()); + let file = + File::open(path).map_err(|why| format!("Could not open {}: {}", path.display(), why))?; + + let mut reader = BufReader::new(file); + + let abi: Abi = from_reader(&mut reader).map_err(|why| why.to_string())?; + let signature = abi.signature(); + + let init_type = signature.inputs[0].clone(); + + let init = { + let path = Path::new(sub_matches.value_of("init").unwrap()); + let file = File::open(path).unwrap(); + let reader = BufReader::new(file); + + parse_value(serde_json::from_reader(reader).unwrap(), init_type) + .unwrap() + .encode() + }; + + let instance_path = Path::new(sub_matches.value_of("instance-path").unwrap()); + let instance: RecursiveSNARKWithStepCount<'ast, T> = + serde_json::from_reader(BufReader::new(File::open(instance_path).unwrap())).unwrap(); + let steps = instance.steps; + + if nova::verify_compressed(&proof, &vk, init, steps) { + println!("Compressed proof succesfully verified"); + } else { + eprintln!("Compressed proof verification failed"); + } + + Ok(()) +} diff --git a/zokrates_cli/src/ops/print_proof.rs b/zokrates_cli/src/ops/print_proof.rs index a6df505af..cf0d25a7c 100644 --- a/zokrates_cli/src/ops/print_proof.rs +++ b/zokrates_cli/src/ops/print_proof.rs @@ -38,7 +38,7 @@ pub fn subcommand() -> App<'static, 'static> { pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> { let proof_path = Path::new(sub_matches.value_of("proof-path").unwrap()); - let proof_file = File::open(&proof_path) + let proof_file = File::open(proof_path) .map_err(|why| format!("Could not open {}: {}", proof_path.display(), why))?; // deserialize proof to JSON diff --git a/zokrates_cli/src/ops/profile.rs b/zokrates_cli/src/ops/profile.rs new file mode 100644 index 000000000..9f505531f --- /dev/null +++ b/zokrates_cli/src/ops/profile.rs @@ -0,0 +1,54 @@ +use crate::cli_constants::FLATTENED_CODE_DEFAULT_PATH; +use clap::{App, Arg, ArgMatches, SubCommand}; +use std::fs::File; +use std::io::BufReader; +use std::path::Path; +use zokrates_ast::ir::{self, ProgEnum}; +use zokrates_field::Field; +use zokrates_profiler::profile; + +pub fn subcommand() -> App<'static, 'static> { + SubCommand::with_name("profile") + .about("Profiles a compiled program, indicating which parts of the source yield the most constraints") + .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), + ) +} + +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!("Could not open `{}`: {}", path.display(), why))?; + + let mut reader = BufReader::new(file); + + match ProgEnum::deserialize(&mut reader)? { + ProgEnum::Bn128Program(p) => cli_profile(p, sub_matches), + ProgEnum::Bls12_377Program(p) => cli_profile(p, sub_matches), + ProgEnum::Bls12_381Program(p) => cli_profile(p, sub_matches), + ProgEnum::Bw6_761Program(p) => cli_profile(p, sub_matches), + ProgEnum::PallasProgram(p) => cli_profile(p, sub_matches), + ProgEnum::VestaProgram(p) => cli_profile(p, sub_matches), + } +} + +fn cli_profile<'ast, T: Field, I: Iterator>>( + ir_prog: ir::ProgIterator<'ast, T, I>, + _: &ArgMatches, +) -> Result<(), String> { + let module_map = ir_prog.module_map.clone(); + + let heat_map = profile(ir_prog); + + println!("{}", heat_map.display(&module_map)); + + Ok(()) +} diff --git a/zokrates_cli/src/ops/setup.rs b/zokrates_cli/src/ops/setup.rs index 0fc569538..5be6d8650 100644 --- a/zokrates_cli/src/ops/setup.rs +++ b/zokrates_cli/src/ops/setup.rs @@ -1,5 +1,7 @@ use crate::cli_constants; use clap::{App, Arg, ArgMatches, SubCommand}; +use rand_0_8::rngs::StdRng; +use rand_0_8::SeedableRng; use std::convert::TryFrom; use std::fs::File; use std::io::{BufReader, Write}; @@ -12,6 +14,7 @@ use zokrates_bellman::Bellman; use zokrates_common::constants; use zokrates_common::helpers::*; use zokrates_field::Field; +use zokrates_proof_systems::rng::get_rng_from_entropy; #[cfg(any(feature = "bellman", feature = "ark"))] use zokrates_proof_systems::*; @@ -78,13 +81,21 @@ pub fn subcommand() -> App<'static, 'static> { .required(false) .default_value(cli_constants::UNIVERSAL_SETUP_DEFAULT_PATH), ) + .arg( + Arg::with_name("entropy") + .short("e") + .long("entropy") + .help("User provided randomness") + .takes_value(true) + .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))?; + 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)?; @@ -118,6 +129,7 @@ pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> { ProgEnum::Bw6_761Program(p) => { cli_setup_non_universal::<_, _, G16, Ark>(p, sub_matches) } + _ => unreachable!(), }, #[cfg(feature = "ark")] Parameters(BackendParameter::Ark, _, SchemeParameter::GM17) => match prog { @@ -131,11 +143,12 @@ pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> { ProgEnum::Bw6_761Program(p) => { cli_setup_non_universal::<_, _, GM17, Ark>(p, sub_matches) } + _ => unreachable!(), }, #[cfg(feature = "ark")] Parameters(BackendParameter::Ark, _, SchemeParameter::MARLIN) => { let setup_path = Path::new(sub_matches.value_of("universal-setup-path").unwrap()); - let setup_file = File::open(&setup_path) + let setup_file = File::open(setup_path) .map_err(|why| format!("Couldn't open {}: {}\nExpected an universal setup, make sure `zokrates universal-setup` was run`", setup_path.display(), why))?; let mut reader = BufReader::new(setup_file); @@ -160,6 +173,7 @@ pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> { ProgEnum::Bw6_761Program(p) => { cli_setup_universal::<_, _, Marlin, Ark>(p, setup, sub_matches) } + _ => unreachable!(), } } _ => unreachable!(), @@ -182,8 +196,13 @@ fn cli_setup_non_universal< 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()); + let mut rng = sub_matches + .value_of("entropy") + .map(get_rng_from_entropy) + .unwrap_or_else(StdRng::from_entropy); + // run setup phase - let keypair = B::setup(program); + let keypair = B::setup(program, &mut rng); // write verification key let mut vk_file = File::create(vk_path) diff --git a/zokrates_cli/src/ops/universal_setup.rs b/zokrates_cli/src/ops/universal_setup.rs index 98bc88924..b3831b65e 100644 --- a/zokrates_cli/src/ops/universal_setup.rs +++ b/zokrates_cli/src/ops/universal_setup.rs @@ -1,5 +1,7 @@ use crate::cli_constants; use clap::{App, Arg, ArgMatches, SubCommand}; +use rand_0_8::rngs::StdRng; +use rand_0_8::SeedableRng; use std::convert::TryFrom; use std::fs::File; use std::io::Write; @@ -9,6 +11,7 @@ use zokrates_ark::Ark; use zokrates_common::constants; use zokrates_common::helpers::*; use zokrates_field::{Bls12_377Field, Bls12_381Field, Bn128Field, Bw6_761Field, Field}; +use zokrates_proof_systems::rng::get_rng_from_entropy; #[cfg(any(feature = "bellman", feature = "ark"))] use zokrates_proof_systems::*; @@ -54,6 +57,14 @@ pub fn subcommand() -> App<'static, 'static> { .required(false) .default_value(cli_constants::UNIVERSAL_SETUP_DEFAULT_SIZE), ) + .arg( + Arg::with_name("entropy") + .short("e") + .long("entropy") + .help("User provided randomness") + .takes_value(true) + .required(false), + ) } pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> { @@ -98,8 +109,13 @@ fn cli_universal_setup, B: UniversalBackend() .map_err(|_| format!("Universal setup size {} is invalid", size))?; + let mut rng = sub_matches + .value_of("entropy") + .map(get_rng_from_entropy) + .unwrap_or_else(StdRng::from_entropy); + // run universal setup phase - let setup = B::universal_setup(size); + let setup = B::universal_setup(size, &mut rng); // write proving key let mut u_file = File::create(u_path) diff --git a/zokrates_cli/src/ops/verify.rs b/zokrates_cli/src/ops/verify.rs index 24a96c387..568b13383 100644 --- a/zokrates_cli/src/ops/verify.rs +++ b/zokrates_cli/src/ops/verify.rs @@ -51,7 +51,7 @@ pub fn subcommand() -> App<'static, 'static> { pub fn exec(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) + let vk_file = File::open(vk_path) .map_err(|why| format!("Could not open {}: {}", vk_path.display(), why))?; // deserialize vk to JSON @@ -60,7 +60,7 @@ pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> { .map_err(|why| format!("Could not deserialize verification key: {}", why))?; let proof_path = Path::new(sub_matches.value_of("proof-path").unwrap()); - let proof_file = File::open(&proof_path) + let proof_file = File::open(proof_path) .map_err(|why| format!("Could not open {}: {}", proof_path.display(), why))?; // deserialize proof to JSON diff --git a/zokrates_cli/tests/code/arithmetics.expected.witness b/zokrates_cli/tests/code/arithmetics.expected.witness deleted file mode 100644 index caaf539db..000000000 --- a/zokrates_cli/tests/code/arithmetics.expected.witness +++ /dev/null @@ -1 +0,0 @@ -~out_0 12 diff --git a/zokrates_cli/tests/code/arithmetics.expected.witness.json b/zokrates_cli/tests/code/arithmetics.expected.witness.json new file mode 100644 index 000000000..4e1ae3537 --- /dev/null +++ b/zokrates_cli/tests/code/arithmetics.expected.witness.json @@ -0,0 +1,3 @@ +{ + "~out_0": "12" +} diff --git a/zokrates_cli/tests/code/conditional_false.expected.witness b/zokrates_cli/tests/code/conditional_false.expected.witness deleted file mode 100644 index 1b8f13fa2..000000000 --- a/zokrates_cli/tests/code/conditional_false.expected.witness +++ /dev/null @@ -1 +0,0 @@ -~out_0 0 \ No newline at end of file diff --git a/zokrates_cli/tests/code/conditional_false.expected.witness.json b/zokrates_cli/tests/code/conditional_false.expected.witness.json new file mode 100644 index 000000000..50655725f --- /dev/null +++ b/zokrates_cli/tests/code/conditional_false.expected.witness.json @@ -0,0 +1,3 @@ +{ + "~out_0": "0" +} diff --git a/zokrates_cli/tests/code/conditional_true.expected.witness b/zokrates_cli/tests/code/conditional_true.expected.witness deleted file mode 100644 index 1e61044c7..000000000 --- a/zokrates_cli/tests/code/conditional_true.expected.witness +++ /dev/null @@ -1 +0,0 @@ -~out_0 1 \ No newline at end of file diff --git a/zokrates_cli/tests/code/conditional_true.expected.witness.json b/zokrates_cli/tests/code/conditional_true.expected.witness.json new file mode 100644 index 000000000..cd003d107 --- /dev/null +++ b/zokrates_cli/tests/code/conditional_true.expected.witness.json @@ -0,0 +1,3 @@ +{ + "~out_0": "1" +} diff --git a/zokrates_cli/tests/code/multidim_update.expected.witness b/zokrates_cli/tests/code/multidim_update.expected.witness deleted file mode 100644 index 0b054f2fe..000000000 --- a/zokrates_cli/tests/code/multidim_update.expected.witness +++ /dev/null @@ -1,4 +0,0 @@ -~out_0 0 -~out_1 0 -~out_2 0 -~out_3 42 \ No newline at end of file diff --git a/zokrates_cli/tests/code/multidim_update.expected.witness.json b/zokrates_cli/tests/code/multidim_update.expected.witness.json new file mode 100644 index 000000000..98c0fbd76 --- /dev/null +++ b/zokrates_cli/tests/code/multidim_update.expected.witness.json @@ -0,0 +1,6 @@ +{ + "~out_0": "0", + "~out_1": "0", + "~out_2": "0", + "~out_3": "42" +} diff --git a/zokrates_cli/tests/code/n_choose_k.expected.witness b/zokrates_cli/tests/code/n_choose_k.expected.witness deleted file mode 100644 index b51f241b4..000000000 --- a/zokrates_cli/tests/code/n_choose_k.expected.witness +++ /dev/null @@ -1 +0,0 @@ -~out_0 5 \ No newline at end of file diff --git a/zokrates_cli/tests/code/n_choose_k.expected.witness.json b/zokrates_cli/tests/code/n_choose_k.expected.witness.json new file mode 100644 index 000000000..839b53c97 --- /dev/null +++ b/zokrates_cli/tests/code/n_choose_k.expected.witness.json @@ -0,0 +1,3 @@ +{ + "~out_0": "5" +} diff --git a/zokrates_cli/tests/code/no_return.expected.witness b/zokrates_cli/tests/code/no_return.expected.witness deleted file mode 100644 index e69de29bb..000000000 diff --git a/zokrates_cli/tests/code/no_return.expected.witness.json b/zokrates_cli/tests/code/no_return.expected.witness.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/zokrates_cli/tests/code/no_return.expected.witness.json @@ -0,0 +1 @@ +{} diff --git a/zokrates_cli/tests/code/return_array.expected.witness b/zokrates_cli/tests/code/return_array.expected.witness deleted file mode 100644 index f9f9cf798..000000000 --- a/zokrates_cli/tests/code/return_array.expected.witness +++ /dev/null @@ -1,8 +0,0 @@ -~out_0 2 -~out_1 1 -~out_2 1 -~out_3 1 -~out_4 3 -~out_5 3 -~out_6 3 -~out_7 3 \ No newline at end of file diff --git a/zokrates_cli/tests/code/return_array.expected.witness.json b/zokrates_cli/tests/code/return_array.expected.witness.json new file mode 100644 index 000000000..d1b0a1d25 --- /dev/null +++ b/zokrates_cli/tests/code/return_array.expected.witness.json @@ -0,0 +1,10 @@ +{ + "~out_0": "2", + "~out_1": "1", + "~out_2": "1", + "~out_3": "1", + "~out_4": "3", + "~out_5": "3", + "~out_6": "3", + "~out_7": "3" +} diff --git a/zokrates_cli/tests/code/simple_add.expected.witness b/zokrates_cli/tests/code/simple_add.expected.witness deleted file mode 100644 index 23b7f950e..000000000 --- a/zokrates_cli/tests/code/simple_add.expected.witness +++ /dev/null @@ -1 +0,0 @@ -~out_0 3 diff --git a/zokrates_cli/tests/code/simple_add.expected.witness.json b/zokrates_cli/tests/code/simple_add.expected.witness.json new file mode 100644 index 000000000..ca9fd972e --- /dev/null +++ b/zokrates_cli/tests/code/simple_add.expected.witness.json @@ -0,0 +1,3 @@ +{ + "~out_0": "3" +} diff --git a/zokrates_cli/tests/code/simple_mul.expected.witness b/zokrates_cli/tests/code/simple_mul.expected.witness deleted file mode 100644 index 8eb3a8d7a..000000000 --- a/zokrates_cli/tests/code/simple_mul.expected.witness +++ /dev/null @@ -1 +0,0 @@ -~out_0 24 \ No newline at end of file diff --git a/zokrates_cli/tests/code/simple_mul.expected.witness.json b/zokrates_cli/tests/code/simple_mul.expected.witness.json new file mode 100644 index 000000000..7143416e9 --- /dev/null +++ b/zokrates_cli/tests/code/simple_mul.expected.witness.json @@ -0,0 +1,3 @@ +{ + "~out_0": "24" +} diff --git a/zokrates_cli/tests/code/taxation.expected.witness b/zokrates_cli/tests/code/taxation.expected.witness deleted file mode 100644 index 1b8f13fa2..000000000 --- a/zokrates_cli/tests/code/taxation.expected.witness +++ /dev/null @@ -1 +0,0 @@ -~out_0 0 \ No newline at end of file diff --git a/zokrates_cli/tests/code/taxation.expected.witness.json b/zokrates_cli/tests/code/taxation.expected.witness.json new file mode 100644 index 000000000..50655725f --- /dev/null +++ b/zokrates_cli/tests/code/taxation.expected.witness.json @@ -0,0 +1,3 @@ +{ + "~out_0": "0" +} diff --git a/zokrates_cli/tests/integration.rs b/zokrates_cli/tests/integration.rs index 6ee737663..68bc0abf6 100644 --- a/zokrates_cli/tests/integration.rs +++ b/zokrates_cli/tests/integration.rs @@ -4,10 +4,10 @@ extern crate primitive_types; extern crate rand_0_4; extern crate rand_0_8; extern crate serde_json; -extern crate zokrates_solidity_test; #[cfg(test)] mod integration { + use ethabi::Token; use fs_extra::copy_items; use fs_extra::dir::CopyOptions; use pretty_assertions::assert_eq; @@ -15,18 +15,79 @@ mod integration { use serde_json::from_reader; use std::fs; use std::fs::File; - use std::io::{BufReader, Read}; - use std::panic; + use std::io::{BufReader, Read, Write}; use std::path::Path; + use std::process::Command; use tempdir::TempDir; use zokrates_abi::{parse_strict, Encode}; + use zokrates_ast::ir::Witness; use zokrates_ast::typed::abi::Abi; use zokrates_field::Bn128Field; use zokrates_proof_systems::{ to_token::ToToken, Marlin, Proof, SolidityCompatibleScheme, G16, GM17, - SOLIDITY_G2_ADDITION_LIB, }; + mod helpers { + use super::*; + use zokrates_ast::common::flat::Variable; + use zokrates_field::Field; + + pub fn parse_variable(s: &str) -> Result { + if s == "~one" { + return Ok(Variable::one()); + } + + let mut public = s.split("~out_"); + match public.nth(1) { + Some(v) => { + let v = v.parse().map_err(|_| s)?; + Ok(Variable::public(v)) + } + None => { + let mut private = s.split('_'); + match private.nth(1) { + Some(v) => { + let v = v.parse().map_err(|_| s)?; + Ok(Variable::new(v)) + } + None => Err(s), + } + } + } + } + + pub fn parse_witness_json(reader: R) -> std::io::Result> { + use std::io::{Error, ErrorKind}; + + let json: serde_json::Value = serde_json::from_reader(reader)?; + let object = json + .as_object() + .ok_or_else(|| Error::new(ErrorKind::Other, "Witness must be an object"))?; + + let mut witness = Witness::empty(); + for (k, v) in object { + let variable = parse_variable(k).map_err(|why| { + Error::new( + ErrorKind::Other, + format!("Invalid variable in witness: {}", why), + ) + })?; + + let value = v + .as_str() + .ok_or_else(|| Error::new(ErrorKind::Other, "Witness value must be a string")) + .and_then(|v| { + T::try_from_dec_str(v).map_err(|_| { + Error::new(ErrorKind::Other, format!("Invalid value in witness: {}", v)) + }) + })?; + + witness.insert(variable, value); + } + Ok(witness) + } + } + macro_rules! map( { $($key:expr => $value:expr),+ } => { @@ -41,6 +102,7 @@ mod integration { #[test] #[ignore] fn test_compile_and_witness_dir() { + let forge = dirs::home_dir().unwrap().join(".foundry/bin/forge"); let global_dir = TempDir::new("global").unwrap(); let global_base = global_dir.path(); let universal_setup_path = global_base.join("universal_setup.dat"); @@ -59,6 +121,38 @@ mod integration { .succeeds() .unwrap(); + let solidity_test_path = global_base.join("zokrates_verifier"); + std::fs::create_dir(&solidity_test_path).unwrap(); + + Command::new(&forge) + .output() + .expect("Could not run `forge`. Make sure foundry is installed to run this test"); + + let output = Command::new(&forge) + .current_dir(&solidity_test_path) + .arg("init") + .arg("--no-git") + .arg("--no-commit") + .arg(".") + .output() + .unwrap(); + + std::io::stdout().write_all(&output.stdout).unwrap(); + std::io::stderr().write_all(&output.stderr).unwrap(); + + assert!(output.status.success()); + + Command::new("rm") + .current_dir(&solidity_test_path) + .arg("./src/*.sol") + .output() + .unwrap(); + Command::new("rm") + .current_dir(&solidity_test_path) + .arg("./test/*.t.sol") + .output() + .unwrap(); + let dir = Path::new("./tests/code"); assert!(dir.is_dir()); for entry in fs::read_dir(dir).unwrap() { @@ -68,7 +162,9 @@ mod integration { let program_name = Path::new(Path::new(path.file_stem().unwrap()).file_stem().unwrap()); let prog = dir.join(program_name).with_extension("zok"); - let witness = dir.join(program_name).with_extension("expected.witness"); + let witness = dir + .join(program_name) + .with_extension("expected.witness.json"); let json_input = dir.join(program_name).with_extension("arguments.json"); test_compile_and_witness( @@ -80,6 +176,17 @@ mod integration { ); } } + + let output = Command::new(&forge) + .current_dir(&solidity_test_path) + .arg("test") + .output() + .expect("failed to forge test"); + + std::io::stdout().write_all(&output.stdout).unwrap(); + std::io::stderr().write_all(&output.stderr).unwrap(); + + assert!(output.status.success()); } fn test_compile_and_witness( @@ -106,6 +213,7 @@ mod integration { .join(program_name) .join("proving") .with_extension("key"); + let solidity_test_path = global_path.join("zokrates_verifier"); let verification_contract_path = tmp_base .join(program_name) .join("verifier") @@ -205,33 +313,24 @@ mod integration { .unwrap(); // load the expected witness - let mut expected_witness_file = File::open(&expected_witness_path).unwrap(); - let mut expected_witness = String::new(); - expected_witness_file - .read_to_string(&mut expected_witness) - .unwrap(); + let expected_witness_file = File::open(expected_witness_path).unwrap(); + let expected_witness: Witness = + helpers::parse_witness_json(expected_witness_file).unwrap(); // load the actual witness - let mut witness_file = File::open(&witness_path).unwrap(); - let mut witness = String::new(); - witness_file.read_to_string(&mut witness).unwrap(); + let witness_file = File::open(&witness_path).unwrap(); + let witness = Witness::::read(witness_file).unwrap(); // load the actual inline witness - let mut inline_witness_file = File::open(&inline_witness_path).unwrap(); - let mut inline_witness = String::new(); - inline_witness_file - .read_to_string(&mut inline_witness) - .unwrap(); + let inline_witness_file = File::open(&inline_witness_path).unwrap(); + let inline_witness = + Witness::::read(inline_witness_file).unwrap(); assert_eq!(inline_witness, witness); - for line in expected_witness.as_str().split('\n') { - assert!( - witness.contains(line), - "Witness generation failed for {}\n\nLine \"{}\" not found in witness", - program_path.to_str().unwrap(), - line - ); + for (k, v) in expected_witness.0 { + let value = witness.0.get(&k).expect("should contain key"); + assert!(v.eq(value)); } let backends = map! { @@ -241,7 +340,6 @@ mod integration { for (backend, schemes) in backends { for scheme in &schemes { - println!("test with {}, {}", backend, scheme); // SETUP let setup = assert_cli::Assert::main_binary() .with_args(&[ @@ -324,7 +422,14 @@ mod integration { ) .unwrap(); - test_solidity_verifier(contract_str, proof); + test_solidity_verifier( + program_name, + backend, + scheme, + &solidity_test_path, + &contract_str, + proof, + ); } "g16" => { // Get the proof @@ -333,7 +438,14 @@ mod integration { ) .unwrap(); - test_solidity_verifier(contract_str, proof); + test_solidity_verifier( + program_name, + backend, + scheme, + &solidity_test_path, + &contract_str, + proof, + ); } "gm17" => { // Get the proof @@ -342,7 +454,14 @@ mod integration { ) .unwrap(); - test_solidity_verifier(contract_str, proof); + test_solidity_verifier( + program_name, + backend, + scheme, + &solidity_test_path, + &contract_str, + proof, + ); } _ => unreachable!(), } @@ -352,48 +471,13 @@ mod integration { } fn test_solidity_verifier + ToToken>( - src: String, + program_name: &str, + backend: &str, + scheme: &str, + solidity_test_path: &Path, + contract_str: &str, proof: Proof, ) { - use ethabi::Token; - use rand_0_8::{rngs::StdRng, SeedableRng}; - use zokrates_solidity_test::{address::*, contract::*, evm::*, to_be_bytes}; - - // Setup EVM - let mut rng = StdRng::from_seed([0; 32]); - let mut evm = Evm::default(); - let deployer = Address::random(&mut rng); - evm.create_account(&deployer, 0); - - // Compile lib - let g2_lib = - Contract::compile_from_src_string(SOLIDITY_G2_ADDITION_LIB, "BN256G2", true, &[]) - .unwrap(); - - // Deploy lib - let create_result = evm - .deploy(g2_lib.encode_create_contract_bytes(&[]).unwrap(), &deployer) - .unwrap(); - let lib_addr = create_result.addr; - - // Compile contract - let contract = Contract::compile_from_src_string( - &src, - "Verifier", - true, - &[("BN256G2", lib_addr.as_token())], - ) - .unwrap(); - - // Deploy contract - let create_result = evm - .deploy( - contract.encode_create_contract_bytes(&[]).unwrap(), - &deployer, - ) - .unwrap(); - let contract_addr = create_result.addr; - // convert to the solidity proof format let solidity_proof = S::Proof::from(proof.proof); @@ -412,40 +496,95 @@ mod integration { .collect::>(), ); - let inputs = [proof_token, input_token.clone()]; - - // Call verify function on contract - let result = evm - .call( - contract - .encode_call_contract_bytes("verifyTx", &inputs) - .unwrap(), - &contract_addr, - &deployer, - ) - .unwrap(); - - assert_eq!(&result.out, &to_be_bytes(&U256::from(1))); + let inputs = ethabi::encode(&[proof_token, input_token.clone()]); // modify the proof let modified_solidity_proof = S::modify(solidity_proof); let modified_proof_token = S::to_token(modified_solidity_proof); - let inputs = [modified_proof_token, input_token]; - - // Call verify function on contract - let result = evm - .call( - contract - .encode_call_contract_bytes("verifyTx", &inputs) - .unwrap(), - &contract_addr, - &deployer, - ) - .unwrap(); + let modified_inputs = ethabi::encode(&[modified_proof_token, input_token]); + + let verifier_name = format!("Verifier_{}_{}_{}", program_name, scheme, backend); + + let verifier_path = solidity_test_path + .join("src") + .join(&verifier_name) + .with_extension("sol"); + let mut file = File::create(verifier_path).unwrap(); + write!(file, "{}", contract_str).unwrap(); + + let test_path = solidity_test_path + .join("test") + .join(format!( + "Verifier_{}_{}_{}_Test", + program_name, scheme, backend + )) + .with_extension("t.sol"); + let mut file = File::create(test_path).unwrap(); + let test_content = format!( + r#" + + pragma solidity ^0.8.17; + + import "forge-std/Test.sol"; + import "../src/{}.sol"; + + contract VerifierTest is Test {{ + Verifier public verifier; + + constructor() {{ + verifier = new Verifier(); + }} + + function testValidProof() public {{ + bytes4 selector = verifier.verifyTx.selector; + uint8[{}] memory b = [{}]; + bytes memory data = new bytes(b.length + 4); + for(uint i; i < 4; i++) {{ + data[i] = selector[i]; + }} + for(uint i; i < b.length; i++) {{ + data[i + 4] = bytes1(b[i]); + }} + (bool success, bytes memory returnData) = address(verifier).call(data); + assertEq(success, true); + bool res = abi.decode(returnData, (bool)); + assertEq(res, true); + }} + + function testInvalidProof() public {{ + bytes4 selector = verifier.verifyTx.selector; + uint8[{}] memory b = [{}]; + bytes memory data = new bytes(b.length + 4); + for(uint i; i < 4; i++) {{ + data[i] = selector[i]; + }} + for(uint i; i < b.length; i++) {{ + data[i + 4] = bytes1(b[i]); + }} + (bool success, ) = address(verifier).call(data); + assertEq(success, false); + }} + }} + + "#, + verifier_name, + inputs.len(), + inputs + .iter() + .map(|v| format!("{:#04X?}", v)) + .collect::>() + .join(", "), + modified_inputs.len(), + modified_inputs + .iter() + .map(|v| format!("{:#04X?}", v)) + .collect::>() + .join(", "), + ); - assert_eq!(result.op_out, Return::InvalidOpcode); + write!(file, "{}", test_content).unwrap(); } fn test_compile_and_smtlib2( @@ -499,7 +638,7 @@ mod integration { .unwrap(); // load the expected smtlib2 - let mut expected_smtlib2_file = File::open(&expected_smtlib2_path).unwrap(); + let mut expected_smtlib2_file = File::open(expected_smtlib2_path).unwrap(); let mut expected_smtlib2 = String::new(); expected_smtlib2_file .read_to_string(&mut expected_smtlib2) diff --git a/zokrates_codegen/Cargo.toml b/zokrates_codegen/Cargo.toml index 6bb566f4c..42fabe756 100644 --- a/zokrates_codegen/Cargo.toml +++ b/zokrates_codegen/Cargo.toml @@ -1,12 +1,13 @@ [package] name = "zokrates_codegen" -version = "0.1.0" +version = "0.1.3" edition = "2021" [features] default = ["ark", "bellman"] ark = ["zokrates_ast/ark", "zokrates_embed/ark", "zokrates_common/ark", "zokrates_interpreter/ark"] bellman = ["zokrates_ast/bellman", "zokrates_embed/bellman", "zokrates_common/bellman", "zokrates_interpreter/bellman"] +bellperson = ["zokrates_ast/bellperson", "zokrates_common/bellperson"] [dependencies] zokrates_field = { version = "0.5.0", path = "../zokrates_field", default-features = false } diff --git a/zokrates_codegen/src/lib.rs b/zokrates_codegen/src/lib.rs index cf4e8cbb0..46faf587e 100644 --- a/zokrates_codegen/src/lib.rs +++ b/zokrates_codegen/src/lib.rs @@ -1,5 +1,3 @@ -#![feature(box_patterns, box_syntax)] - //! Module containing the `Flattener` to process a program that is R1CS-able. //! //! @file flatten.rs @@ -10,9 +8,12 @@ mod utils; use self::utils::flat_expression_from_bits; -use zokrates_ast::zir::{ - ConditionalExpression, SelectExpression, ShouldReduce, UMetadata, ZirAssemblyStatement, - ZirExpressionList, +use zokrates_ast::{ + common::{expressions::ValueExpression, Span}, + zir::{ + canonicalizer::ZirCanonicalizer, ConditionalExpression, Expr, Folder, SelectExpression, + ShouldReduce, UMetadata, ZirAssemblyStatement, ZirExpressionList, ZirProgram, + }, }; use zokrates_interpreter::Interpreter; @@ -20,32 +21,73 @@ use std::collections::{ hash_map::{Entry, HashMap}, VecDeque, }; +use std::ops::*; use zokrates_ast::common::embed::*; use zokrates_ast::common::FlatEmbed; -use zokrates_ast::common::{RuntimeError, Variable}; +use zokrates_ast::common::WithSpan; +use zokrates_ast::common::{flat::Variable, RuntimeError}; use zokrates_ast::flat::*; use zokrates_ast::ir::Solver; use zokrates_ast::zir::types::{Type, UBitwidth}; use zokrates_ast::zir::{ BooleanExpression, Conditional, FieldElementExpression, Identifier, Parameter as ZirParameter, - UExpression, UExpressionInner, Variable as ZirVariable, ZirExpression, ZirFunction, - ZirStatement, + UExpression, UExpressionInner, Variable as ZirVariable, ZirExpression, ZirStatement, }; use zokrates_common::CompileConfig; use zokrates_field::Field; -type FlatStatements<'ast, T> = VecDeque>; +/// A container for statements produced during code generation +/// New statements are registered with the span set in the container +#[derive(Default)] +pub struct FlatStatements<'ast, T> { + span: Option, + buffer: VecDeque>, +} + +impl<'ast, T> FlatStatements<'ast, T> { + fn push_back(&mut self, s: FlatStatement<'ast, T>) { + self.buffer.push_back(s.span(self.span)) + } + + fn pop_front(&mut self) -> Option> { + self.buffer.pop_front() + } + + fn extend(&mut self, i: impl IntoIterator>) { + self.buffer.extend(i.into_iter().map(|s| s.span(self.span))) + } + + fn set_span(&mut self, span: Option) { + self.span = span; + } + + fn is_empty(&self) -> bool { + self.buffer.is_empty() + } +} + +impl<'ast, T> IntoIterator for FlatStatements<'ast, T> { + type Item = FlatStatement<'ast, T>; + + type IntoIter = std::collections::vec_deque::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.buffer.into_iter() + } +} /// Flattens a function /// /// # Arguments /// * `funct` - `ZirFunction` that will be flattened -pub fn from_function_and_config( - funct: ZirFunction, +pub fn from_program_and_config( + prog: ZirProgram, config: CompileConfig, ) -> FlattenerIterator { + let funct = prog.main; + let mut flattener = Flattener::new(config); - let mut statements_flattened = FlatStatements::new(); + let mut statements_flattened = FlatStatements::default(); // push parameters let arguments_flattened = funct .arguments @@ -61,6 +103,7 @@ pub fn from_function_and_config( flattener, }, return_count: funct.signature.outputs.len(), + module_map: prog.module_map, } } @@ -168,12 +211,28 @@ impl<'ast, T: Field> Flatten<'ast, T> for BooleanExpression<'ast, T> { } #[derive(Clone, Debug)] -struct FlatUExpression { +struct FlatUExpression { field: Option>, bits: Option>>, } -impl FlatUExpression { +impl WithSpan for FlatUExpression { + fn span(self, span: Option) -> Self { + Self { + field: self.field.map(|e| e.span(span)), + bits: self + .bits + .map(|bits| bits.into_iter().map(|b| b.span(span)).collect()), + } + } + + fn get_span(&self) -> Option { + let field_span = self.field.as_ref().map(|f| f.get_span()); + field_span.unwrap_or_else(|| unimplemented!()) + } +} + +impl FlatUExpression { fn default() -> Self { FlatUExpression { field: None, @@ -182,7 +241,7 @@ impl FlatUExpression { } } -impl FlatUExpression { +impl FlatUExpression { fn field>>>(mut self, e: U) -> Self { self.field = e.into(); self @@ -200,7 +259,9 @@ impl FlatUExpression { fn with_bits>>>>(e: U) -> Self { Self::default().bits(e) } +} +impl FlatUExpression { fn get_field_unchecked(self) -> FlatExpression { match self.field { Some(f) => f, @@ -230,10 +291,10 @@ impl<'ast, T: Field> Flattener<'ast, T> { statements_flattened: &mut FlatStatements<'ast, T>, ) -> Variable { match e { - FlatExpression::Identifier(id) => id, + FlatExpression::Identifier(id) => id.id, e => { let res = self.use_sym(); - statements_flattened.push_back(FlatStatement::Definition(res, e)); + statements_flattened.push_back(FlatStatement::definition(res, e)); res } } @@ -259,7 +320,7 @@ impl<'ast, T: Field> Flattener<'ast, T> { /// As long as `sizeUnknown` is `true` we don't yet know if a is <= than b. /// 2. Loop over `b`: /// * b[0] = 1 - /// when `b` is 1 we check wether `a` is 0 in that particular run and update + /// when `b` is 1 we check whether `a` is 0 in that particular run and update /// `sizeUnknown` accordingly: /// `sizeUnknown = sizeUnknown && a[0]` /// * b[1] = 1 @@ -290,9 +351,9 @@ impl<'ast, T: Field> Flattener<'ast, T> { .iter() .map(|e| { let e_id = self.define(e.clone(), statements_flattened); - FlatStatement::Condition( + FlatStatement::condition( e_id.into(), - FlatExpression::Mult(box e_id.into(), box e_id.into()), + FlatExpression::mul(e_id.into(), e_id.into()), RuntimeError::Bitness, ) }) @@ -312,28 +373,25 @@ impl<'ast, T: Field> Flattener<'ast, T> { } // init size_unknown = true - statements_flattened.push_back(FlatStatement::Definition( + statements_flattened.push_back(FlatStatement::definition( size_unknown[0], - FlatExpression::Number(T::from(1)), + FlatExpression::value(T::from(1)), )); let mut res = vec![]; for (i, b) in b.iter().enumerate() { if *b { - statements_flattened.push_back(FlatStatement::Definition( + statements_flattened.push_back(FlatStatement::definition( is_not_smaller_run[i], a[i].clone(), )); // don't need to update size_unknown in the last round if i < len - 1 { - statements_flattened.push_back(FlatStatement::Definition( + statements_flattened.push_back(FlatStatement::definition( size_unknown[i + 1], - FlatExpression::Mult( - box size_unknown[i].into(), - box is_not_smaller_run[i].into(), - ), + FlatExpression::mul(size_unknown[i].into(), is_not_smaller_run[i].into()), )); } } else { @@ -343,24 +401,20 @@ impl<'ast, T: Field> Flattener<'ast, T> { // sizeUnknown is not changing in this case // We sill have to assign the old value to the variable of the current run // This trivial definition will later be removed by the optimiser - FlatStatement::Definition(size_unknown[i + 1], size_unknown[i].into()), + FlatStatement::definition(size_unknown[i + 1], size_unknown[i].into()), ); } - let or_left = FlatExpression::Sub( - box FlatExpression::Number(T::from(1)), - box size_unknown[i].into(), - ); + let or_left = + FlatExpression::sub(FlatExpression::value(T::from(1)), size_unknown[i].into()); let or_right: FlatExpression<_> = - FlatExpression::Sub(box FlatExpression::Number(T::from(1)), box a[i].clone()); + FlatExpression::sub(FlatExpression::value(T::from(1)), a[i].clone()); let and_name = self.use_sym(); - let and = FlatExpression::Mult(box or_left.clone(), box or_right.clone()); - statements_flattened.push_back(FlatStatement::Definition(and_name, and)); - let or = FlatExpression::Sub( - box FlatExpression::Add(box or_left, box or_right), - box and_name.into(), - ); + let and = FlatExpression::mul(or_left.clone(), or_right.clone()); + statements_flattened.push_back(FlatStatement::definition(and_name, and)); + let or = + FlatExpression::sub(FlatExpression::add(or_left, or_right), and_name.into()); res.push(or); } @@ -395,30 +449,30 @@ impl<'ast, T: Field> Flattener<'ast, T> { // Y == X * M // 0 == (1-Y) * X - let x = FlatExpression::Sub(box left.into(), box right.into()); + let x = FlatExpression::sub(left.into(), right.into()); let name_y = self.use_sym(); let name_m = self.use_sym(); - statements_flattened.push_back(FlatStatement::Directive(FlatDirective::new( + statements_flattened.push_back(FlatStatement::directive( vec![name_y, name_m], Solver::ConditionEq, vec![x.clone()], - ))); - statements_flattened.push_back(FlatStatement::Condition( - FlatExpression::Identifier(name_y), - FlatExpression::Mult(box x.clone(), box FlatExpression::Identifier(name_m)), + )); + statements_flattened.push_back(FlatStatement::condition( + FlatExpression::identifier(name_y), + FlatExpression::mul(x.clone(), FlatExpression::identifier(name_m)), RuntimeError::Equal, )); - let res = FlatExpression::Sub( - box FlatExpression::Number(T::one()), - box FlatExpression::Identifier(name_y), + let res = FlatExpression::sub( + FlatExpression::value(T::one()), + FlatExpression::identifier(name_y), ); - statements_flattened.push_back(FlatStatement::Condition( - FlatExpression::Number(T::zero()), - FlatExpression::Mult(box res.clone(), box x), + statements_flattened.push_back(FlatStatement::condition( + FlatExpression::value(T::zero()), + FlatExpression::mul(res.clone(), x), RuntimeError::Equal, )); @@ -446,11 +500,11 @@ impl<'ast, T: Field> Flattener<'ast, T> { let conditions_sum = conditions .into_iter() .fold(FlatExpression::from(T::zero()), |acc, e| { - FlatExpression::Add(box acc, box e) + FlatExpression::add(acc, e) }); - statements_flattened.push_back(FlatStatement::Condition( - FlatExpression::Number(T::from(0)), - FlatExpression::Sub(box conditions_sum, box T::from(conditions_count).into()), + statements_flattened.push_back(FlatStatement::condition( + FlatExpression::value(T::from(0)), + FlatExpression::sub(conditions_sum, T::from(conditions_count).into()), error, )); } @@ -507,7 +561,7 @@ impl<'ast, T: Field> Flattener<'ast, T> { ) { // `e < 0` will always result in false value, so we constrain `0 == 1` if c == T::zero() { - statements_flattened.push_back(FlatStatement::Condition( + statements_flattened.push_back(FlatStatement::condition( T::zero().into(), T::one().into(), error, @@ -525,49 +579,58 @@ impl<'ast, T: Field> Flattener<'ast, T> { statements .into_iter() .flat_map(|s| match s { - FlatStatement::Condition(left, right, message) => { - let mut output = VecDeque::new(); + FlatStatement::Condition(s) => { + let span = s.get_span(); + + let mut output = FlatStatements::default(); + + output.set_span(span); // we transform (a == b) into (c => (a == b)) which is (!c || (a == b)) // let's introduce new variables to make sure everything is linear - let name_left = self.define(left, &mut output); - let name_right = self.define(right, &mut output); + let name_lin = self.define(s.lin, &mut output); + let name_quad = self.define(s.quad, &mut output); // let's introduce an expression which is 1 iff `a == b` - let y = FlatExpression::Add( - box FlatExpression::Sub(box name_left.into(), box name_right.into()), - box T::one().into(), - ); - // let's introduce !c - let x = FlatExpression::Sub(box T::one().into(), box condition.clone()); - + let y = FlatExpression::add( + FlatExpression::sub(name_lin.into(), name_quad.into()), + T::one().into(), + ); // let's introduce !c + let x = FlatExpression::sub(T::one().into(), condition.clone()); assert!(x.is_linear() && y.is_linear()); let name_x_or_y = self.use_sym(); - output.push_back(FlatStatement::Directive(FlatDirective { - solver: Solver::Or, - outputs: vec![name_x_or_y], - inputs: vec![x.clone(), y.clone()], - })); - output.push_back(FlatStatement::Condition( - FlatExpression::Add( - box x.clone(), - box FlatExpression::Sub(box y.clone(), box name_x_or_y.into()), + output.push_back(FlatStatement::directive( + vec![name_x_or_y], + Solver::Or, + vec![x.clone(), y.clone()], + )); + output.push_back(FlatStatement::condition( + FlatExpression::add( + x.clone(), + FlatExpression::sub(y.clone(), name_x_or_y.into()), ), - FlatExpression::Mult(box x.clone(), box y.clone()), + FlatExpression::mul(x, y), RuntimeError::BranchIsolation, )); - output.push_back(FlatStatement::Condition( + output.push_back(FlatStatement::condition( name_x_or_y.into(), T::one().into(), - message, + s.error, )); output } - s => VecDeque::from([s]), + s => { + let mut v = FlatStatements::default(); + v.push_back(s); + v + } + }) + .fold(FlatStatements::default(), |mut acc, s| { + acc.push_back(s); + acc }) - .collect() } /// Flatten an if/else expression @@ -593,14 +656,14 @@ impl<'ast, T: Field> Flattener<'ast, T> { self.flatten_boolean_expression(statements_flattened, condition.clone()); let condition_id = self.use_sym(); - statements_flattened.push_back(FlatStatement::Definition(condition_id, condition_flat)); + statements_flattened.push_back(FlatStatement::definition(condition_id, condition_flat)); let (consequence, alternative) = if self.config.isolate_branches { - let mut consequence_statements = VecDeque::new(); + let mut consequence_statements = FlatStatements::default(); let consequence = consequence.flatten(self, &mut consequence_statements); - let mut alternative_statements = VecDeque::new(); + let mut alternative_statements = FlatStatements::default(); let alternative = alternative.flatten(self, &mut alternative_statements); @@ -608,10 +671,7 @@ impl<'ast, T: Field> Flattener<'ast, T> { self.make_conditional(consequence_statements, condition_id.into()); let alternative_statements = self.make_conditional( alternative_statements, - FlatExpression::Sub( - box FlatExpression::Number(T::one()), - box condition_id.into(), - ), + FlatExpression::sub(FlatExpression::value(T::one()), condition_id.into()), ); statements_flattened.extend(consequence_statements); @@ -629,43 +689,37 @@ impl<'ast, T: Field> Flattener<'ast, T> { let alternative = alternative.flat(); let consequence_id = self.use_sym(); - statements_flattened.push_back(FlatStatement::Definition(consequence_id, consequence)); + statements_flattened.push_back(FlatStatement::definition(consequence_id, consequence)); let alternative_id = self.use_sym(); - statements_flattened.push_back(FlatStatement::Definition(alternative_id, alternative)); + statements_flattened.push_back(FlatStatement::definition(alternative_id, alternative)); let term0_id = self.use_sym(); - statements_flattened.push_back(FlatStatement::Definition( + statements_flattened.push_back(FlatStatement::definition( term0_id, - FlatExpression::Mult( - box condition_id.into(), - box FlatExpression::from(consequence_id), - ), + FlatExpression::mul(condition_id.into(), FlatExpression::from(consequence_id)), )); let term1_id = self.use_sym(); - statements_flattened.push_back(FlatStatement::Definition( + statements_flattened.push_back(FlatStatement::definition( term1_id, - FlatExpression::Mult( - box FlatExpression::Sub( - box FlatExpression::Number(T::one()), - box condition_id.into(), - ), - box FlatExpression::from(alternative_id), + FlatExpression::mul( + FlatExpression::sub(FlatExpression::value(T::one()), condition_id.into()), + FlatExpression::from(alternative_id), ), )); let res = self.use_sym(); - statements_flattened.push_back(FlatStatement::Definition( + statements_flattened.push_back(FlatStatement::definition( res, - FlatExpression::Add( - box FlatExpression::from(term0_id), - box FlatExpression::from(term1_id), + FlatExpression::add( + FlatExpression::from(term0_id), + FlatExpression::from(term1_id), ), )); FlatUExpression { - field: Some(FlatExpression::Identifier(res)), + field: Some(FlatExpression::identifier(res)), bits: None, } } @@ -736,8 +790,8 @@ impl<'ast, T: Field> Flattener<'ast, T> { T::from(conditions.len()).into(), conditions .into_iter() - .fold(FlatExpression::Number(T::zero()), |acc, e| { - FlatExpression::Add(box acc, box e) + .fold(FlatExpression::value(T::zero()), |acc, e| { + FlatExpression::add(acc, e) }), ) } @@ -750,13 +804,13 @@ impl<'ast, T: Field> Flattener<'ast, T> { rhs_flattened: FlatExpression, bit_width: usize, ) -> FlatExpression { - FlatExpression::Add( - box self.eq_check( + FlatExpression::add( + self.eq_check( statements_flattened, lhs_flattened.clone(), rhs_flattened.clone(), ), - box self.lt_check( + self.lt_check( statements_flattened, lhs_flattened, rhs_flattened, @@ -774,25 +828,25 @@ impl<'ast, T: Field> Flattener<'ast, T> { bit_width: usize, ) -> FlatExpression { match (lhs_flattened, rhs_flattened) { - (x, FlatExpression::Number(constant)) => { - self.constant_lt_check(statements_flattened, x, constant) + (x, FlatExpression::Value(constant)) => { + self.constant_lt_check(statements_flattened, x, constant.value) } // (c < x <= p - 1) <=> (0 <= p - 1 - x < p - 1 - c) - (FlatExpression::Number(constant), x) => self.constant_lt_check( + (FlatExpression::Value(constant), x) => self.constant_lt_check( statements_flattened, - FlatExpression::Sub(box T::max_value().into(), box x), - T::max_value() - constant, + FlatExpression::sub(T::max_value().into(), x), + T::max_value() - constant.value, ), (lhs_flattened, rhs_flattened) => { let lhs_id = self.define(lhs_flattened, statements_flattened); let rhs_id = self.define(rhs_flattened, statements_flattened); // shifted_sub := 2**safe_width + lhs - rhs - let shifted_sub = FlatExpression::Add( - box FlatExpression::Number(T::from(2).pow(bit_width)), - box FlatExpression::Sub( - box FlatExpression::Identifier(lhs_id), - box FlatExpression::Identifier(rhs_id), + let shifted_sub = FlatExpression::add( + FlatExpression::value(T::from(2).pow(bit_width)), + FlatExpression::sub( + FlatExpression::identifier(lhs_id), + FlatExpression::identifier(rhs_id), ), ); @@ -806,9 +860,9 @@ impl<'ast, T: Field> Flattener<'ast, T> { RuntimeError::IncompleteDynamicRange, ); - FlatExpression::Sub( - box FlatExpression::Number(T::one()), - box shifted_sub_bits_be[0].clone(), + FlatExpression::sub( + FlatExpression::value(T::one()), + shifted_sub_bits_be[0].clone(), ) } } @@ -830,21 +884,27 @@ impl<'ast, T: Field> Flattener<'ast, T> { statements_flattened: &mut FlatStatements<'ast, T>, expression: BooleanExpression<'ast, T>, ) -> FlatExpression { - match expression { + let span = expression.get_span(); + + let span_backup = statements_flattened.span; + + statements_flattened.set_span(span); + + let res = match expression { BooleanExpression::Identifier(x) => { - FlatExpression::Identifier(*self.layout.get(&x.id).unwrap()) + FlatExpression::identifier(*self.layout.get(&x.id).unwrap()) } BooleanExpression::Select(e) => self .flatten_select_expression(statements_flattened, e) .get_field_unchecked(), - BooleanExpression::FieldLt(box lhs, box rhs) => { + BooleanExpression::FieldLt(e) => { // Get the bit width to know the size of the binary decompositions for this Field let bit_width = T::get_required_bits(); let safe_width = bit_width - 2; // dynamic comparison is not complete, it only applies to field elements whose difference is strictly smaller than 2**(bitwidth - 2) - let lhs_flattened = self.flatten_field_expression(statements_flattened, lhs); - let rhs_flattened = self.flatten_field_expression(statements_flattened, rhs); + let lhs_flattened = self.flatten_field_expression(statements_flattened, *e.left); + let rhs_flattened = self.flatten_field_expression(statements_flattened, *e.right); self.lt_check( statements_flattened, lhs_flattened, @@ -852,10 +912,10 @@ impl<'ast, T: Field> Flattener<'ast, T> { safe_width, ) } - BooleanExpression::BoolEq(box lhs, box rhs) => { + BooleanExpression::BoolEq(e) => { // lhs and rhs are booleans, they flatten to 0 or 1 - let x = self.flatten_boolean_expression(statements_flattened, lhs); - let y = self.flatten_boolean_expression(statements_flattened, rhs); + let x = self.flatten_boolean_expression(statements_flattened, *e.left); + let y = self.flatten_boolean_expression(statements_flattened, *e.right); // Wanted: Not(X - Y)**2 which is an XNOR // We know that X and Y are [0, 1] // (X - Y) can become a negative values, which is why squaring the result is needed @@ -871,27 +931,27 @@ impl<'ast, T: Field> Flattener<'ast, T> { // | 0 | 0 | 0 | 1 | // +---+---+-------+---------------+ - let x_sub_y = FlatExpression::Sub(box x, box y); + let x_sub_y = FlatExpression::sub(x, y); let name_x_mult_x = self.use_sym(); - statements_flattened.push_back(FlatStatement::Definition( + statements_flattened.push_back(FlatStatement::definition( name_x_mult_x, - FlatExpression::Mult(box x_sub_y.clone(), box x_sub_y), + FlatExpression::mul(x_sub_y.clone(), x_sub_y), )); - FlatExpression::Sub( - box FlatExpression::Number(T::one()), - box FlatExpression::Identifier(name_x_mult_x), + FlatExpression::sub( + FlatExpression::value(T::one()), + FlatExpression::identifier(name_x_mult_x), ) } - BooleanExpression::FieldEq(box lhs, box rhs) => { - let lhs = self.flatten_field_expression(statements_flattened, lhs); + BooleanExpression::FieldEq(e) => { + let lhs = self.flatten_field_expression(statements_flattened, *e.left); - let rhs = self.flatten_field_expression(statements_flattened, rhs); + let rhs = self.flatten_field_expression(statements_flattened, *e.right); self.eq_check(statements_flattened, lhs, rhs) } - BooleanExpression::UintEq(box lhs, box rhs) => { + BooleanExpression::UintEq(e) => { // We reduce each side into range and apply the same approach as for field elements // Wanted: (Y = (X != 0) ? 1 : 0) @@ -901,39 +961,41 @@ impl<'ast, T: Field> Flattener<'ast, T> { // Y == X * M // 0 == (1-Y) * X - assert!(lhs.metadata.as_ref().unwrap().should_reduce.to_bool()); - assert!(rhs.metadata.as_ref().unwrap().should_reduce.to_bool()); + assert!(e.left.metadata.as_ref().unwrap().should_reduce.to_bool()); + assert!(e.right.metadata.as_ref().unwrap().should_reduce.to_bool()); let lhs = self - .flatten_uint_expression(statements_flattened, lhs) + .flatten_uint_expression(statements_flattened, *e.left) .get_field_unchecked(); let rhs = self - .flatten_uint_expression(statements_flattened, rhs) + .flatten_uint_expression(statements_flattened, *e.right) .get_field_unchecked(); self.eq_check(statements_flattened, lhs, rhs) } - BooleanExpression::FieldLe(box lhs, box rhs) => { + BooleanExpression::FieldLe(e) => { let lt = self.flatten_boolean_expression( statements_flattened, - BooleanExpression::FieldLt(box lhs.clone(), box rhs.clone()), + BooleanExpression::field_lt(*e.left.clone(), *e.right.clone()).span(span), ); + let eq = self.flatten_boolean_expression( statements_flattened, - BooleanExpression::FieldEq(box lhs, box rhs), + BooleanExpression::field_eq(*e.left, *e.right).span(span), ); - FlatExpression::Add(box eq, box lt) + + FlatExpression::add(eq, lt) } - BooleanExpression::UintLt(box lhs, box rhs) => { - let bit_width = lhs.bitwidth.to_usize(); - assert!(lhs.metadata.as_ref().unwrap().should_reduce.to_bool()); - assert!(rhs.metadata.as_ref().unwrap().should_reduce.to_bool()); + BooleanExpression::UintLt(e) => { + let bit_width = e.left.bitwidth.to_usize(); + assert!(e.left.metadata.as_ref().unwrap().should_reduce.to_bool()); + assert!(e.right.metadata.as_ref().unwrap().should_reduce.to_bool()); let lhs_flattened = self - .flatten_uint_expression(statements_flattened, lhs) + .flatten_uint_expression(statements_flattened, *e.left) .get_field_unchecked(); let rhs_flattened = self - .flatten_uint_expression(statements_flattened, rhs) + .flatten_uint_expression(statements_flattened, *e.right) .get_field_unchecked(); self.lt_check( @@ -943,55 +1005,55 @@ impl<'ast, T: Field> Flattener<'ast, T> { bit_width, ) } - BooleanExpression::UintLe(box lhs, box rhs) => { + BooleanExpression::UintLe(e) => { let lt = self.flatten_boolean_expression( statements_flattened, - BooleanExpression::UintLt(box lhs.clone(), box rhs.clone()), + BooleanExpression::uint_lt(*e.left.clone(), *e.right.clone()).span(span), ); let eq = self.flatten_boolean_expression( statements_flattened, - BooleanExpression::UintEq(box lhs, box rhs), + BooleanExpression::uint_eq(*e.left, *e.right).span(span), ); - FlatExpression::Add(box eq, box lt) + FlatExpression::add(eq, lt) } - BooleanExpression::Or(box lhs, box rhs) => { - let x = self.flatten_boolean_expression(statements_flattened, lhs); - let y = self.flatten_boolean_expression(statements_flattened, rhs); + BooleanExpression::Or(e) => { + let x = self.flatten_boolean_expression(statements_flattened, *e.left); + let y = self.flatten_boolean_expression(statements_flattened, *e.right); assert!(x.is_linear() && y.is_linear()); let name_x_or_y = self.use_sym(); - statements_flattened.push_back(FlatStatement::Directive(FlatDirective { - solver: Solver::Or, - outputs: vec![name_x_or_y], - inputs: vec![x.clone(), y.clone()], - })); - statements_flattened.push_back(FlatStatement::Condition( - FlatExpression::Add( - box x.clone(), - box FlatExpression::Sub(box y.clone(), box name_x_or_y.into()), + statements_flattened.push_back(FlatStatement::directive( + vec![name_x_or_y], + Solver::Or, + vec![x.clone(), y.clone()], + )); + statements_flattened.push_back(FlatStatement::condition( + FlatExpression::add( + x.clone(), + FlatExpression::sub(y.clone(), name_x_or_y.into()), ), - FlatExpression::Mult(box x, box y), + FlatExpression::mul(x, y), RuntimeError::Or, )); name_x_or_y.into() } - BooleanExpression::And(box lhs, box rhs) => { - let x = self.flatten_boolean_expression(statements_flattened, lhs); - let y = self.flatten_boolean_expression(statements_flattened, rhs); + BooleanExpression::And(e) => { + let x = self.flatten_boolean_expression(statements_flattened, *e.left); + let y = self.flatten_boolean_expression(statements_flattened, *e.right); let name_x_and_y = self.use_sym(); assert!(x.is_linear() && y.is_linear()); - statements_flattened.push_back(FlatStatement::Definition( + statements_flattened.push_back(FlatStatement::definition( name_x_and_y, - FlatExpression::Mult(box x, box y), + FlatExpression::mul(x, y), )); - FlatExpression::Identifier(name_x_and_y) + FlatExpression::identifier(name_x_and_y) } - BooleanExpression::Not(box exp) => { - let x = self.flatten_boolean_expression(statements_flattened, exp); - FlatExpression::Sub(box FlatExpression::Number(T::one()), box x) + BooleanExpression::Not(e) => { + let x = self.flatten_boolean_expression(statements_flattened, *e.inner); + FlatExpression::sub(FlatExpression::value(T::one()), x) } - BooleanExpression::Value(b) => FlatExpression::Number(match b { + BooleanExpression::Value(b) => FlatExpression::value(match b.value { true => T::from(1), false => T::from(0), }), @@ -999,6 +1061,11 @@ impl<'ast, T: Field> Flattener<'ast, T> { .flatten_conditional_expression(statements_flattened, e) .get_field_unchecked(), } + .span(span); + + statements_flattened.set_span(span_backup); + + res } fn u_to_bits( @@ -1089,8 +1156,8 @@ impl<'ast, T: Field> Flattener<'ast, T> { let constants: Vec<_> = constants .into_iter() .map(|e| match e.get_field_unchecked() { - FlatExpression::Number(n) if n == T::one() => true, - FlatExpression::Number(n) if n == T::zero() => false, + FlatExpression::Value(n) if n.value == T::one() => true, + FlatExpression::Value(n) if n.value == T::zero() => false, _ => unreachable!(), }) .collect(); @@ -1106,8 +1173,8 @@ impl<'ast, T: Field> Flattener<'ast, T> { T::from(conditions.len()).into(), conditions .into_iter() - .fold(FlatExpression::Number(T::zero()), |acc, e| { - FlatExpression::Add(box acc, box e) + .fold(FlatExpression::value(T::zero()), |acc, e| { + FlatExpression::add(acc, e) }), ), )] @@ -1157,16 +1224,16 @@ impl<'ast, T: Field> Flattener<'ast, T> { let statements = funct.statements.into_iter().map(|stat| match stat { FlatStatement::Block(..) => unreachable!(), - FlatStatement::Definition(var, rhs) => { + FlatStatement::Definition(s) => { let new_var = self.use_sym(); - replacement_map.insert(var, new_var); - let new_rhs = rhs.apply_substitution(&replacement_map); - FlatStatement::Definition(new_var, new_rhs) + replacement_map.insert(s.assignee, new_var); + let new_rhs = s.rhs.apply_substitution(&replacement_map); + FlatStatement::definition(new_var, new_rhs) } - FlatStatement::Condition(lhs, rhs, message) => { - let new_lhs = lhs.apply_substitution(&replacement_map); - let new_rhs = rhs.apply_substitution(&replacement_map); - FlatStatement::Condition(new_lhs, new_rhs, message) + FlatStatement::Condition(s) => { + let new_quad = s.quad.apply_substitution(&replacement_map); + let new_lin = s.lin.apply_substitution(&replacement_map); + FlatStatement::condition(new_lin, new_quad, s.error) } FlatStatement::Directive(d) => { let new_outputs = d @@ -1183,15 +1250,11 @@ impl<'ast, T: Field> Flattener<'ast, T> { .into_iter() .map(|i| i.apply_substitution(&replacement_map)) .collect(); - FlatStatement::Directive(FlatDirective { - outputs: new_outputs, - solver: d.solver, - inputs: new_inputs, - }) + FlatStatement::directive(new_outputs, d.solver, new_inputs) } - FlatStatement::Log(l, expressions) => FlatStatement::Log( - l, - expressions + FlatStatement::Log(s) => FlatStatement::Log(LogStatement::new( + s.format_string, + s.expressions .into_iter() .map(|(t, e)| { ( @@ -1202,7 +1265,7 @@ impl<'ast, T: Field> Flattener<'ast, T> { ) }) .collect(), - ), + )), }); statements_flattened.extend(statements); @@ -1253,12 +1316,12 @@ impl<'ast, T: Field> Flattener<'ast, T> { .into_iter() .zip(right_bits.into_iter()) .map(|(x, y)| match (x, y) { - (FlatExpression::Number(n), e) | (e, FlatExpression::Number(n)) => { - if n == T::from(0) { + (FlatExpression::Value(n), e) | (e, FlatExpression::Value(n)) => { + if n.value == T::from(0) { self.define(e, statements_flattened).into() - } else if n == T::from(1) { + } else if n.value == T::from(1) { self.define( - FlatExpression::Sub(box FlatExpression::Number(T::from(1)), box e), + FlatExpression::sub(FlatExpression::value(T::from(1)), e), statements_flattened, ) .into() @@ -1270,20 +1333,17 @@ impl<'ast, T: Field> Flattener<'ast, T> { let name = self.use_sym(); statements_flattened.extend(vec![ - FlatStatement::Directive(FlatDirective::new( + FlatStatement::directive( vec![name], Solver::Xor, vec![x.clone(), y.clone()], - )), - FlatStatement::Condition( - FlatExpression::Add( - box x.clone(), - box FlatExpression::Sub(box y.clone(), box name.into()), - ), - FlatExpression::Mult( - box FlatExpression::Add(box x.clone(), box x), - box y, + ), + FlatStatement::condition( + FlatExpression::add( + x.clone(), + FlatExpression::sub(y.clone(), name.into()), ), + FlatExpression::mul(FlatExpression::add(x.clone(), x), y), RuntimeError::Xor, ), ]); @@ -1313,26 +1373,26 @@ impl<'ast, T: Field> Flattener<'ast, T> { left_flattened } else { let id = self.use_sym(); - statements_flattened.push_back(FlatStatement::Definition(id, left_flattened)); - FlatExpression::Identifier(id) + statements_flattened.push_back(FlatStatement::definition(id, left_flattened)); + FlatExpression::identifier(id) }; let d = if right_flattened.is_linear() { right_flattened } else { let id = self.use_sym(); - statements_flattened.push_back(FlatStatement::Definition(id, right_flattened)); - FlatExpression::Identifier(id) + statements_flattened.push_back(FlatStatement::definition(id, right_flattened)); + FlatExpression::identifier(id) }; // introduce the quotient and remainder let q = self.use_sym(); let r = self.use_sym(); - statements_flattened.push_back(FlatStatement::Directive(FlatDirective { - inputs: vec![n.clone(), d.clone()], - outputs: vec![q, r], - solver: Solver::EuclideanDiv, - })); + statements_flattened.push_back(FlatStatement::directive( + vec![q, r], + Solver::EuclideanDiv, + vec![n.clone(), d.clone()], + )); let target_bitwidth = target_bitwidth.to_usize(); @@ -1356,9 +1416,9 @@ impl<'ast, T: Field> Flattener<'ast, T> { // r < d <=> r - d + 2**w < 2**w let _ = self.get_bits_unchecked( - &FlatUExpression::with_field(FlatExpression::Add( - box FlatExpression::Sub(box r.into(), box d.clone()), - box FlatExpression::Number(T::from(2_u128.pow(target_bitwidth as u32))), + &FlatUExpression::with_field(FlatExpression::add( + FlatExpression::sub(r.into(), d.clone()), + FlatExpression::value(T::from(2_u128.pow(target_bitwidth as u32))), )), target_bitwidth, target_bitwidth, @@ -1367,9 +1427,9 @@ impl<'ast, T: Field> Flattener<'ast, T> { ); // q*d == n - r - statements_flattened.push_back(FlatStatement::Condition( - FlatExpression::Sub(box n, box r.into()), - FlatExpression::Mult(box q.into(), box d), + statements_flattened.push_back(FlatStatement::condition( + FlatExpression::sub(n, r.into()), + FlatExpression::mul(q.into(), d), RuntimeError::Euclidean, )); @@ -1387,6 +1447,12 @@ impl<'ast, T: Field> Flattener<'ast, T> { statements_flattened: &mut FlatStatements<'ast, T>, expr: UExpression<'ast, T>, ) -> FlatUExpression { + let span = expr.as_inner().get_span(); + + let span_backup = statements_flattened.span; + + statements_flattened.set_span(span); + // the bitwidth for this type of uint (8, 16 or 32) let target_bitwidth = expr.bitwidth; @@ -1402,10 +1468,10 @@ impl<'ast, T: Field> Flattener<'ast, T> { let res = match expr.into_inner() { UExpressionInner::Value(x) => { - FlatUExpression::with_field(FlatExpression::Number(T::from(x))) + FlatUExpression::with_field(FlatExpression::value(T::from(x.value))) } // force to be a field element UExpressionInner::Identifier(x) => { - let field = FlatExpression::Identifier(*self.layout.get(&x.id).unwrap()); + let field = FlatExpression::identifier(*self.layout.get(&x.id).unwrap()); let bits = self.bits_cache.get(&field).map(|bits| { assert_eq!(bits.len(), target_bitwidth.to_usize()); bits.clone() @@ -1413,8 +1479,8 @@ impl<'ast, T: Field> Flattener<'ast, T> { FlatUExpression::with_field(field).bits(bits) } UExpressionInner::Select(e) => self.flatten_select_expression(statements_flattened, e), - UExpressionInner::Not(box e) => { - let e = self.flatten_uint_expression(statements_flattened, e); + UExpressionInner::Not(e) => { + let e = self.flatten_uint_expression(statements_flattened, *e.inner); let e_bits = e.bits.unwrap(); @@ -1424,7 +1490,7 @@ impl<'ast, T: Field> Flattener<'ast, T> { .into_iter() .map(|bit| { self.define( - FlatExpression::Sub(box FlatExpression::Number(T::from(1)), box bit), + FlatExpression::sub(FlatExpression::value(T::from(1)), bit), statements_flattened, ) .into() @@ -1433,66 +1499,73 @@ impl<'ast, T: Field> Flattener<'ast, T> { FlatUExpression::with_bits(name_not) } - UExpressionInner::Add(box left, box right) => { + UExpressionInner::Add(e) => { let left_flattened = self - .flatten_uint_expression(statements_flattened, left) + .flatten_uint_expression(statements_flattened, *e.left) .get_field_unchecked(); let right_flattened = self - .flatten_uint_expression(statements_flattened, right) + .flatten_uint_expression(statements_flattened, *e.right) .get_field_unchecked(); let new_left = if left_flattened.is_linear() { left_flattened } else { let id = self.use_sym(); - statements_flattened.push_back(FlatStatement::Definition(id, left_flattened)); - FlatExpression::Identifier(id) + statements_flattened.push_back(FlatStatement::definition(id, left_flattened)); + FlatExpression::identifier(id) }; let new_right = if right_flattened.is_linear() { right_flattened } else { let id = self.use_sym(); - statements_flattened.push_back(FlatStatement::Definition(id, right_flattened)); - FlatExpression::Identifier(id) + statements_flattened.push_back(FlatStatement::definition(id, right_flattened)); + FlatExpression::identifier(id) }; - FlatUExpression::with_field(FlatExpression::Add(box new_left, box new_right)) + FlatUExpression::with_field(FlatExpression::add(new_left, new_right)) } - UExpressionInner::Sub(box left, box right) => { + UExpressionInner::Sub(e) => { // see uint optimizer for the reasoning here - let offset = FlatExpression::Number(T::from(2).pow(std::cmp::max( - right.metadata.as_ref().unwrap().bitwidth() as usize, + let offset = FlatExpression::value(T::from(2).pow(std::cmp::max( + e.right.metadata.as_ref().unwrap().bitwidth() as usize, target_bitwidth as usize, ))); let left_flattened = self - .flatten_uint_expression(statements_flattened, left) + .flatten_uint_expression(statements_flattened, *e.left) .get_field_unchecked(); let right_flattened = self - .flatten_uint_expression(statements_flattened, right) + .flatten_uint_expression(statements_flattened, *e.right) .get_field_unchecked(); let new_left = if left_flattened.is_linear() { left_flattened } else { let id = self.use_sym(); - statements_flattened.push_back(FlatStatement::Definition(id, left_flattened)); - FlatExpression::Identifier(id) + statements_flattened.push_back(FlatStatement::definition(id, left_flattened)); + FlatExpression::identifier(id) }; let new_right = if right_flattened.is_linear() { right_flattened } else { let id = self.use_sym(); - statements_flattened.push_back(FlatStatement::Definition(id, right_flattened)); - FlatExpression::Identifier(id) + statements_flattened.push_back(FlatStatement::definition(id, right_flattened)); + FlatExpression::identifier(id) }; - FlatUExpression::with_field(FlatExpression::Add( - box offset, - box FlatExpression::Sub(box new_left, box new_right), + FlatUExpression::with_field(FlatExpression::add( + offset, + FlatExpression::sub(new_left, new_right), )) } - UExpressionInner::LeftShift(box e, by) => { + UExpressionInner::LeftShift(e) => { + let by = match e.right.into_inner() { + UExpressionInner::Value(v) => v.value as u32, + _ => unreachable!(), + }; + + let e = *e.left; + let e = self.flatten_uint_expression(statements_flattened, e); let e_bits = e.bits.unwrap(); @@ -1505,12 +1578,19 @@ impl<'ast, T: Field> Flattener<'ast, T> { .skip(by as usize) .chain( (0..std::cmp::min(by as usize, target_bitwidth.to_usize())) - .map(|_| FlatExpression::Number(T::from(0))), + .map(|_| FlatExpression::value(T::from(0))), ) .collect::>(), ) } - UExpressionInner::RightShift(box e, by) => { + UExpressionInner::RightShift(e) => { + let by = match e.right.into_inner() { + UExpressionInner::Value(v) => v.value as u32, + _ => unreachable!(), + }; + + let e = *e.left; + let e = self.flatten_uint_expression(statements_flattened, e); let e_bits = e.bits.unwrap(); @@ -1519,7 +1599,7 @@ impl<'ast, T: Field> Flattener<'ast, T> { FlatUExpression::with_bits( (0..std::cmp::min(by as usize, target_bitwidth.to_usize())) - .map(|_| FlatExpression::Number(T::from(0))) + .map(|_| FlatExpression::value(T::from(0))) .chain(e_bits.into_iter().take( target_bitwidth.to_usize() - std::cmp::min(by as usize, target_bitwidth.to_usize()), @@ -1527,59 +1607,75 @@ impl<'ast, T: Field> Flattener<'ast, T> { .collect::>(), ) } - UExpressionInner::Mult(box left, box right) => { + UExpressionInner::Mult(e) => { let left_flattened = self - .flatten_uint_expression(statements_flattened, left) + .flatten_uint_expression(statements_flattened, *e.left) .get_field_unchecked(); let right_flattened = self - .flatten_uint_expression(statements_flattened, right) + .flatten_uint_expression(statements_flattened, *e.right) .get_field_unchecked(); let new_left = if left_flattened.is_linear() { left_flattened } else { let id = self.use_sym(); - statements_flattened.push_back(FlatStatement::Definition(id, left_flattened)); - FlatExpression::Identifier(id) + statements_flattened.push_back(FlatStatement::definition(id, left_flattened)); + FlatExpression::identifier(id) }; let new_right = if right_flattened.is_linear() { right_flattened } else { let id = self.use_sym(); - statements_flattened.push_back(FlatStatement::Definition(id, right_flattened)); - FlatExpression::Identifier(id) + statements_flattened.push_back(FlatStatement::definition(id, right_flattened)); + FlatExpression::identifier(id) }; let res = self.use_sym(); - statements_flattened.push_back(FlatStatement::Definition( + statements_flattened.push_back(FlatStatement::definition( res, - FlatExpression::Mult(box new_left, box new_right), + FlatExpression::mul(new_left, new_right), )); - FlatUExpression::with_field(FlatExpression::Identifier(res)) + FlatUExpression::with_field(FlatExpression::identifier(res)) } - UExpressionInner::Div(box left, box right) => { - let (q, _) = - self.euclidean_division(statements_flattened, target_bitwidth, left, right); + UExpressionInner::Div(e) => { + let (q, _) = self.euclidean_division( + statements_flattened, + target_bitwidth, + *e.left, + *e.right, + ); FlatUExpression::with_field(q) } - UExpressionInner::Rem(box left, box right) => { - let (_, r) = - self.euclidean_division(statements_flattened, target_bitwidth, left, right); + UExpressionInner::Rem(e) => { + let (_, r) = self.euclidean_division( + statements_flattened, + target_bitwidth, + *e.left, + *e.right, + ); FlatUExpression::with_field(r) } UExpressionInner::Conditional(e) => { self.flatten_conditional_expression(statements_flattened, e) } - UExpressionInner::Xor(box left, box right) => { - let left_metadata = left.metadata.clone().unwrap(); - let right_metadata = right.metadata.clone().unwrap(); + UExpressionInner::Xor(e) => { + let left_metadata = e.left.metadata.clone().unwrap(); + let right_metadata = e.right.metadata.clone().unwrap(); + + let left_span = e.left.get_span(); + let right_span = e.right.get_span(); + + match (e.left.into_inner(), e.right.into_inner()) { + (UExpressionInner::And(e), UExpressionInner::And(ee)) => { + let a = *e.left; + let b = *e.right; + let aa = *ee.left; + let c = *ee.right; - match (left.into_inner(), right.into_inner()) { - (UExpressionInner::And(box a, box b), UExpressionInner::And(box aa, box c)) => { - if aa.clone().into_inner() == UExpressionInner::Not(box a.clone()) { + if aa.as_inner() == UExpression::not(a.clone()).as_inner() { let a_flattened = self.flatten_uint_expression(statements_flattened, a); let b_flattened = self.flatten_uint_expression(statements_flattened, b); let c_flattened = self.flatten_uint_expression(statements_flattened, c); @@ -1598,17 +1694,14 @@ impl<'ast, T: Field> Flattener<'ast, T> { let ch = self.use_sym(); statements_flattened.extend(vec![ - FlatStatement::Directive(FlatDirective::new( + FlatStatement::directive( vec![ch], Solver::ShaCh, vec![a.clone(), b.clone(), c.clone()], - )), - FlatStatement::Condition( - FlatExpression::Sub(box ch.into(), box c.clone()), - FlatExpression::Mult( - box a, - box FlatExpression::Sub(box b, box c), - ), + ), + FlatStatement::condition( + FlatExpression::sub(ch.into(), c.clone()), + a * (b - c), RuntimeError::ShaXor, ), ]); @@ -1620,25 +1713,32 @@ impl<'ast, T: Field> Flattener<'ast, T> { } else { self.default_xor( statements_flattened, - UExpressionInner::And(box a, box b) - .annotate(target_bitwidth) - .metadata(left_metadata), - UExpressionInner::And(box aa, box c) - .annotate(target_bitwidth) - .metadata(right_metadata), + UExpression::and(a, b).metadata(left_metadata), + UExpression::and(aa, c).metadata(right_metadata), ) } } - (UExpressionInner::Xor(box a, box b), c) => { - let a_metadata = a.metadata.clone().unwrap(); - let b_metadata = b.metadata.clone().unwrap(); + (UExpressionInner::Xor(e), c) => { + let a_metadata = e.left.metadata.clone().unwrap(); + let b_metadata = e.right.metadata.clone().unwrap(); + + let a_span = e.left.get_span(); + let b_span = e.right.get_span(); + let c_span = right_span; - match (a.into_inner(), b.into_inner(), c) { + match (e.left.into_inner(), e.right.into_inner(), c) { ( - UExpressionInner::And(box a, box b), - UExpressionInner::And(box aa, box c), - UExpressionInner::And(box bb, box cc), + UExpressionInner::And(e0), + UExpressionInner::And(e1), + UExpressionInner::And(e2), ) => { + let a = *e0.left; + let b = *e0.right; + let aa = *e1.left; + let c = *e1.right; + let bb = *e2.left; + let cc = *e2.right; + if (aa == a) && (bb == b) && (cc == c) { let a_flattened = self.flatten_uint_expression(statements_flattened, a); @@ -1663,33 +1763,27 @@ impl<'ast, T: Field> Flattener<'ast, T> { let bc = self.use_sym(); statements_flattened.extend(vec![ - FlatStatement::Directive(FlatDirective::new( + FlatStatement::directive( vec![maj], Solver::ShaAndXorAndXorAnd, vec![a.clone(), b.clone(), c.clone()], - )), - FlatStatement::Condition( + ), + FlatStatement::condition( bc.into(), - FlatExpression::Mult( - box b.clone(), - box c.clone(), - ), + FlatExpression::mul(b.clone(), c.clone()), RuntimeError::ShaXor, ), - FlatStatement::Condition( - FlatExpression::Sub( - box bc.into(), - box maj.into(), - ), - FlatExpression::Mult( - box FlatExpression::Sub( - box FlatExpression::Add( - box bc.into(), - box bc.into(), + FlatStatement::condition( + FlatExpression::sub(bc.into(), maj.into()), + FlatExpression::mul( + FlatExpression::sub( + FlatExpression::add( + bc.into(), + bc.into(), ), - box FlatExpression::Add(box b, box c), + FlatExpression::add(b, c), ), - box a, + a, ), RuntimeError::ShaXor, ), @@ -1702,45 +1796,57 @@ impl<'ast, T: Field> Flattener<'ast, T> { } else { self.default_xor( statements_flattened, - UExpressionInner::Xor( - box UExpressionInner::And(box a, box b) - .annotate(target_bitwidth) - .metadata(a_metadata), - box UExpressionInner::And(box aa, box c) - .annotate(target_bitwidth) - .metadata(b_metadata), + UExpression::xor( + UExpression::and(a, b) + .metadata(a_metadata) + .span(a_span), + UExpression::and(aa, c) + .metadata(b_metadata) + .span(b_span), ) - .annotate(target_bitwidth) - .metadata(left_metadata), - UExpressionInner::And(box bb, box cc) - .annotate(target_bitwidth) - .metadata(right_metadata), + .metadata(left_metadata) + .span(left_span), + UExpression::and(bb, cc) + .metadata(right_metadata) + .span(c_span), ) } } (a, b, c) => self.default_xor( statements_flattened, - UExpressionInner::Xor( - box a.annotate(target_bitwidth).metadata(a_metadata), - box b.annotate(target_bitwidth).metadata(b_metadata), + UExpression::xor( + a.annotate(target_bitwidth) + .metadata(a_metadata) + .span(a_span), + b.annotate(target_bitwidth) + .metadata(b_metadata) + .span(b_span), ) - .annotate(target_bitwidth) - .metadata(left_metadata), - c.annotate(target_bitwidth).metadata(right_metadata), + .metadata(left_metadata) + .span(left_span), + c.annotate(target_bitwidth) + .metadata(right_metadata) + .span(c_span), ), } } (left_i, right_i) => self.default_xor( statements_flattened, - left_i.annotate(target_bitwidth).metadata(left_metadata), - right_i.annotate(target_bitwidth).metadata(right_metadata), + left_i + .annotate(target_bitwidth) + .metadata(left_metadata) + .span(left_span), + right_i + .annotate(target_bitwidth) + .metadata(right_metadata) + .span(right_span), ), } } - UExpressionInner::And(box left, box right) => { - let left_flattened = self.flatten_uint_expression(statements_flattened, left); + UExpressionInner::And(e) => { + let left_flattened = self.flatten_uint_expression(statements_flattened, *e.left); - let right_flattened = self.flatten_uint_expression(statements_flattened, right); + let right_flattened = self.flatten_uint_expression(statements_flattened, *e.right); let left_bits = left_flattened.bits.unwrap(); let right_bits = right_flattened.bits.unwrap(); @@ -1752,26 +1858,26 @@ impl<'ast, T: Field> Flattener<'ast, T> { .into_iter() .zip(right_bits.into_iter()) .map(|(x, y)| match (x, y) { - (FlatExpression::Number(n), e) | (e, FlatExpression::Number(n)) => { - if n == T::from(0) { - FlatExpression::Number(T::from(0)) - } else if n == T::from(1) { + (FlatExpression::Value(n), e) | (e, FlatExpression::Value(n)) => { + if n.value == T::from(0) { + FlatExpression::value(T::from(0)) + } else if n.value == T::from(1) { e } else { unreachable!(); } } (x, y) => self - .define(FlatExpression::Mult(box x, box y), statements_flattened) + .define(FlatExpression::mul(x, y), statements_flattened) .into(), }) .collect(); FlatUExpression::with_bits(and) } - UExpressionInner::Or(box left, box right) => { - let left_flattened = self.flatten_uint_expression(statements_flattened, left); - let right_flattened = self.flatten_uint_expression(statements_flattened, right); + UExpressionInner::Or(e) => { + let left_flattened = self.flatten_uint_expression(statements_flattened, *e.left); + let right_flattened = self.flatten_uint_expression(statements_flattened, *e.right); let left_bits = left_flattened.bits.unwrap(); let right_bits = right_flattened.bits.unwrap(); @@ -1786,11 +1892,11 @@ impl<'ast, T: Field> Flattener<'ast, T> { .into_iter() .zip(right_bits.into_iter()) .map(|(x, y)| match (x, y) { - (FlatExpression::Number(n), e) | (e, FlatExpression::Number(n)) => { - if n == T::from(0) { + (FlatExpression::Value(n), e) | (e, FlatExpression::Value(n)) => { + if n.value == T::from(0) { self.define(e, statements_flattened).into() - } else if n == T::from(1) { - FlatExpression::Number(T::from(1)) + } else if n.value == T::from(1) { + FlatExpression::value(T::from(1)) } else { unreachable!() } @@ -1799,17 +1905,17 @@ impl<'ast, T: Field> Flattener<'ast, T> { let name = self.use_sym(); statements_flattened.extend(vec![ - FlatStatement::Directive(FlatDirective::new( + FlatStatement::directive( vec![name], Solver::Or, vec![x.clone(), y.clone()], - )), - FlatStatement::Condition( - FlatExpression::Add( - box x.clone(), - box FlatExpression::Sub(box y.clone(), box name.into()), + ), + FlatStatement::condition( + FlatExpression::add( + x.clone(), + FlatExpression::sub(y.clone(), name.into()), ), - FlatExpression::Mult(box x, box y), + FlatExpression::mul(x, y), RuntimeError::Or, ), ]); @@ -1820,7 +1926,8 @@ impl<'ast, T: Field> Flattener<'ast, T> { FlatUExpression::with_bits(or) } - }; + } + .span(span); let res = match should_reduce { true => { @@ -1834,15 +1941,15 @@ impl<'ast, T: Field> Flattener<'ast, T> { let field = if actual_bitwidth > target_bitwidth.to_usize() { bits.iter().enumerate().fold( - FlatExpression::Number(T::from(0)), + FlatExpression::value(T::from(0)), |acc, (index, bit)| { - FlatExpression::Add( - box acc, - box FlatExpression::Mult( - box FlatExpression::Number( + FlatExpression::add( + acc, + FlatExpression::mul( + FlatExpression::value( T::from(2).pow(target_bitwidth.to_usize() - index - 1), ), - box bit.clone(), + bit.clone(), ), ) }, @@ -1856,6 +1963,8 @@ impl<'ast, T: Field> Flattener<'ast, T> { false => res, }; + statements_flattened.set_span(span_backup); + res } @@ -1884,11 +1993,11 @@ impl<'ast, T: Field> Flattener<'ast, T> { assert!(to <= T::get_required_bits()); // constants do not require directives - if let Some(FlatExpression::Number(ref x)) = e.field { - let bits: Vec<_> = Interpreter::execute_solver(&Solver::bits(to), &[x.clone()]) + if let Some(FlatExpression::Value(ref x)) = e.field { + let bits: Vec<_> = Interpreter::execute_solver(&Solver::bits(to), &[x.value], &[]) .unwrap() .into_iter() - .map(FlatExpression::Number) + .map(FlatExpression::value) .collect(); assert_eq!(bits.len(), to); @@ -1915,28 +2024,28 @@ impl<'ast, T: Field> Flattener<'ast, T> { res } else { (0..to - res.len()) - .map(|_| FlatExpression::Number(T::zero())) + .map(|_| FlatExpression::value(T::zero())) .chain(res) .collect() } } Entry::Vacant(_) => { let bits = (0..from).map(|_| self.use_sym()).collect::>(); - statements_flattened.push_back(FlatStatement::Directive(FlatDirective::new( + statements_flattened.push_back(FlatStatement::directive( bits.clone(), Solver::Bits(from), vec![e.field.clone().unwrap()], - ))); + )); - let bits: Vec<_> = bits.into_iter().map(FlatExpression::Identifier).collect(); + let bits: Vec<_> = bits.into_iter().map(FlatExpression::identifier).collect(); // decompose to the actual bitwidth // bit checks statements_flattened.extend(bits.iter().take(from).map(|bit| { - FlatStatement::Condition( + FlatStatement::condition( bit.clone(), - FlatExpression::Mult(box bit.clone(), box bit.clone()), + FlatExpression::mul(bit.clone(), bit.clone()), RuntimeError::Bitness, ) })); @@ -1944,7 +2053,7 @@ impl<'ast, T: Field> Flattener<'ast, T> { let sum = flat_expression_from_bits(bits.clone()); // sum check - statements_flattened.push_back(FlatStatement::Condition( + statements_flattened.push_back(FlatStatement::condition( e.field.clone().unwrap(), sum.clone(), error, @@ -1974,6 +2083,8 @@ impl<'ast, T: Field> Flattener<'ast, T> { statements_flattened: &mut FlatStatements<'ast, T>, e: SelectExpression<'ast, T, U>, ) -> FlatUExpression { + let span = e.get_span(); + let array = e.array; let index = *e.index; @@ -1983,15 +2094,17 @@ impl<'ast, T: Field> Flattener<'ast, T> { .map(|(i, e)| { let condition = self.flatten_boolean_expression( statements_flattened, - BooleanExpression::UintEq( - box UExpressionInner::Value(i as u128) + BooleanExpression::uint_eq( + UExpression::value(i as u128) .annotate(UBitwidth::B32) .metadata(UMetadata { should_reduce: ShouldReduce::True, max: T::from(i), - }), - box index.clone(), - ), + }) + .span(span), + index.clone(), + ) + .span(span), ); let element = e.flatten(self, statements_flattened); @@ -2002,26 +2115,29 @@ impl<'ast, T: Field> Flattener<'ast, T> { .into_iter() .fold( ( - FlatExpression::Number(T::zero()), - FlatExpression::Number(T::zero()), + FlatExpression::value(T::zero()), + FlatExpression::value(T::zero()), ), |(mut range_check, mut result), (condition, element)| { - range_check = FlatExpression::Add(box range_check, box condition.clone()); + range_check = FlatExpression::add(range_check, condition.clone()).span(span); let conditional_element_id = self.use_sym(); - statements_flattened.push_back(FlatStatement::Definition( - conditional_element_id, - FlatExpression::Mult(box condition, box element.flat()), - )); + statements_flattened.push_back( + FlatStatement::definition( + conditional_element_id, + FlatExpression::mul(condition, element.flat()).span(span), + ) + .span(span), + ); - result = FlatExpression::Add(box result, box conditional_element_id.into()); + result = FlatExpression::add(result, conditional_element_id.into()).span(span); (range_check, result) }, ); - statements_flattened.push_back(FlatStatement::Condition( + statements_flattened.push_back(FlatStatement::condition( range_check, - FlatExpression::Number(T::one()), + FlatExpression::value(T::one()), RuntimeError::SelectRangeCheck, )); FlatUExpression::with_field(result) @@ -2038,84 +2154,90 @@ impl<'ast, T: Field> Flattener<'ast, T> { statements_flattened: &mut FlatStatements<'ast, T>, expr: FieldElementExpression<'ast, T>, ) -> FlatExpression { - match expr { - FieldElementExpression::Number(x) => FlatExpression::Number(x), // force to be a field element - FieldElementExpression::Identifier(x) => FlatExpression::Identifier( + let span = expr.get_span(); + + let span_backup = statements_flattened.span; + + statements_flattened.set_span(span); + + let res = match expr { + FieldElementExpression::Value(x) => FlatExpression::Value(x), // force to be a field element + FieldElementExpression::Identifier(x) => FlatExpression::identifier( *self.layout.get(&x.id).unwrap_or_else(|| panic!("{}", x)), ), FieldElementExpression::Select(e) => self .flatten_select_expression(statements_flattened, e) .get_field_unchecked(), - FieldElementExpression::Add(box left, box right) => { - let left_flattened = self.flatten_field_expression(statements_flattened, left); - let right_flattened = self.flatten_field_expression(statements_flattened, right); + FieldElementExpression::Add(e) => { + let left_flattened = self.flatten_field_expression(statements_flattened, *e.left); + let right_flattened = self.flatten_field_expression(statements_flattened, *e.right); let new_left = if left_flattened.is_linear() { left_flattened } else { let id = self.use_sym(); - statements_flattened.push_back(FlatStatement::Definition(id, left_flattened)); - FlatExpression::Identifier(id) + statements_flattened.push_back(FlatStatement::definition(id, left_flattened)); + FlatExpression::identifier(id) }; let new_right = if right_flattened.is_linear() { right_flattened } else { let id = self.use_sym(); - statements_flattened.push_back(FlatStatement::Definition(id, right_flattened)); - FlatExpression::Identifier(id) + statements_flattened.push_back(FlatStatement::definition(id, right_flattened)); + FlatExpression::identifier(id) }; - FlatExpression::Add(box new_left, box new_right) + FlatExpression::add(new_left, new_right) } - FieldElementExpression::Sub(box left, box right) => { - let left_flattened = self.flatten_field_expression(statements_flattened, left); - let right_flattened = self.flatten_field_expression(statements_flattened, right); + FieldElementExpression::Sub(e) => { + let left_flattened = self.flatten_field_expression(statements_flattened, *e.left); + let right_flattened = self.flatten_field_expression(statements_flattened, *e.right); let new_left = if left_flattened.is_linear() { left_flattened } else { let id = self.use_sym(); - statements_flattened.push_back(FlatStatement::Definition(id, left_flattened)); - FlatExpression::Identifier(id) + statements_flattened.push_back(FlatStatement::definition(id, left_flattened)); + FlatExpression::identifier(id) }; let new_right = if right_flattened.is_linear() { right_flattened } else { let id = self.use_sym(); - statements_flattened.push_back(FlatStatement::Definition(id, right_flattened)); - FlatExpression::Identifier(id) + statements_flattened.push_back(FlatStatement::definition(id, right_flattened)); + FlatExpression::identifier(id) }; - FlatExpression::Sub(box new_left, box new_right) + FlatExpression::sub(new_left, new_right) } - FieldElementExpression::Mult(box left, box right) => { - let left_flattened = self.flatten_field_expression(statements_flattened, left); - let right_flattened = self.flatten_field_expression(statements_flattened, right); + FieldElementExpression::Mult(e) => { + let left_flattened = self.flatten_field_expression(statements_flattened, *e.left); + let right_flattened = self.flatten_field_expression(statements_flattened, *e.right); let new_left = if left_flattened.is_linear() { left_flattened } else { let id = self.use_sym(); - statements_flattened.push_back(FlatStatement::Definition(id, left_flattened)); - FlatExpression::Identifier(id) + statements_flattened.push_back(FlatStatement::definition(id, left_flattened)); + FlatExpression::identifier(id) }; let new_right = if right_flattened.is_linear() { right_flattened } else { let id = self.use_sym(); - statements_flattened.push_back(FlatStatement::Definition(id, right_flattened)); - FlatExpression::Identifier(id) + statements_flattened.push_back(FlatStatement::definition(id, right_flattened)); + FlatExpression::identifier(id) }; - FlatExpression::Mult(box new_left, box new_right) + FlatExpression::mul(new_left, new_right) } - FieldElementExpression::Div(box left, box right) => { - let left_flattened = self.flatten_field_expression(statements_flattened, left); - let right_flattened = self.flatten_field_expression(statements_flattened, right); + FieldElementExpression::Div(e) => { + let left_flattened = self.flatten_field_expression(statements_flattened, *e.left); + let right_flattened = self.flatten_field_expression(statements_flattened, *e.right); let new_left: FlatExpression = { let id = self.use_sym(); - statements_flattened.push_back(FlatStatement::Definition(id, left_flattened)); + statements_flattened.push_back(FlatStatement::definition(id, left_flattened)); id.into() }; let new_right: FlatExpression = { let id = self.use_sym(); - statements_flattened.push_back(FlatStatement::Definition(id, right_flattened)); + statements_flattened.push_back(FlatStatement::definition(id, right_flattened)); id.into() }; @@ -2125,34 +2247,34 @@ impl<'ast, T: Field> Flattener<'ast, T> { let inverse = self.use_sym(); // # c = a/b - statements_flattened.push_back(FlatStatement::Directive(FlatDirective::new( + statements_flattened.push_back(FlatStatement::directive( vec![inverse], Solver::Div, vec![new_left.clone(), new_right.clone()], - ))); + )); // assert(c * b == a) - statements_flattened.push_back(FlatStatement::Condition( + statements_flattened.push_back(FlatStatement::condition( new_left, - FlatExpression::Mult(box new_right, box inverse.into()), + FlatExpression::mul(new_right, inverse.into()), RuntimeError::Division, )); inverse.into() } - FieldElementExpression::Pow(box base, box exponent) => { - match exponent.into_inner() { - UExpressionInner::Value(ref e) => { + FieldElementExpression::Pow(e) => { + match e.right.into_inner() { + UExpressionInner::Value(ref exp) => { // flatten the base expression let base_flattened = - self.flatten_field_expression(statements_flattened, base.clone()); + self.flatten_field_expression(statements_flattened, *e.left.clone()); // we require from the base to be linear // TODO change that assert!(base_flattened.is_linear()); // convert the exponent to bytes, big endian - let ebytes_be = e.to_be_bytes(); + let ebytes_be = exp.value.to_be_bytes(); // convert the bytes to bits, remove leading zeroes (we only need powers up to the highest non-zero bit) #[allow(clippy::needless_collect)] @@ -2181,17 +2303,14 @@ impl<'ast, T: Field> Flattener<'ast, T> { // introduce a new variable let id = self.use_sym(); // set it to the square of the previous one, stored in state - statements_flattened.push_back(FlatStatement::Definition( + statements_flattened.push_back(FlatStatement::definition( id, - FlatExpression::Mult( - box previous.clone(), - box previous.clone(), - ), + FlatExpression::mul(previous.clone(), previous.clone()), )); // store it in the state for later squaring - *state = Some(FlatExpression::Identifier(id)); + *state = Some(FlatExpression::identifier(id)); // return it for later use constructing the result - Some(FlatExpression::Identifier(id)) + Some(FlatExpression::identifier(id)) } } }) @@ -2199,16 +2318,16 @@ impl<'ast, T: Field> Flattener<'ast, T> { // construct the result iterating through the bits, multiplying by the associated power iff the bit is true ebits_le.into_iter().zip(powers).fold( - FlatExpression::Number(T::from(1)), // initialise the result at 1. If we have no bits to itegrate through, we're computing x**0 == 1 + FlatExpression::value(T::from(1)), // initialise the result at 1. If we have no bits to iterate through, we're computing x**0 == 1 |acc, (bit, power)| match bit { true => { // update the result by introducing a new variable let id = self.use_sym(); - statements_flattened.push_back(FlatStatement::Definition( + statements_flattened.push_back(FlatStatement::definition( id, - FlatExpression::Mult(box acc.clone(), box power), // set the new result to the current result times the current power + FlatExpression::mul(acc, power), // set the new result to the current result times the current power )); - FlatExpression::Identifier(id) + FlatExpression::identifier(id) } false => acc, // this bit is false, keep the previous result }, @@ -2221,7 +2340,11 @@ impl<'ast, T: Field> Flattener<'ast, T> { .flatten_conditional_expression(statements_flattened, e) .get_field_unchecked(), _ => unreachable!(), - } + }; + + statements_flattened.set_span(span_backup); + + res } fn flatten_assembly_statement( @@ -2229,31 +2352,46 @@ impl<'ast, T: Field> Flattener<'ast, T> { statements_flattened: &mut FlatStatements<'ast, T>, stat: ZirAssemblyStatement<'ast, T>, ) { + let span = stat.get_span(); + + let span_backup = statements_flattened.span; + + statements_flattened.set_span(span); + match stat { - ZirAssemblyStatement::Assignment(assignees, function) => { - let inputs: Vec> = function + ZirAssemblyStatement::Assignment(s) => { + let inputs: Vec> = s + .expression .arguments .iter() .cloned() .map(|p| self.layout.get(&p.id.id).cloned().unwrap().into()) .collect(); - let outputs: Vec = assignees + + let outputs: Vec = s + .assignee .into_iter() .map(|assignee| self.use_variable(&assignee)) .collect(); + + let mut canonicalizer = ZirCanonicalizer::default(); + let function = canonicalizer.fold_function(s.expression); + let directive = FlatDirective::new(outputs, Solver::Zir(function), inputs); statements_flattened.push_back(FlatStatement::Directive(directive)); } - ZirAssemblyStatement::Constraint(lhs, rhs, metadata) => { - let lhs = self.flatten_field_expression(statements_flattened, lhs); - let rhs = self.flatten_field_expression(statements_flattened, rhs); - statements_flattened.push_back(FlatStatement::Condition( + ZirAssemblyStatement::Constraint(s) => { + let lhs = self.flatten_field_expression(statements_flattened, s.left); + let rhs = self.flatten_field_expression(statements_flattened, s.right); + statements_flattened.push_back(FlatStatement::condition( lhs, rhs, - RuntimeError::SourceAssemblyConstraint(metadata), + RuntimeError::SourceAssemblyConstraint(s.metadata), )); } - } + }; + + statements_flattened.set_span(span_backup); } /// Flattens a statement @@ -2265,21 +2403,21 @@ impl<'ast, T: Field> Flattener<'ast, T> { fn flatten_statement( &mut self, statements_flattened: &mut FlatStatements<'ast, T>, - stat: ZirStatement<'ast, T>, + s: ZirStatement<'ast, T>, ) { - match stat { - ZirStatement::Assembly(statements) => { - let mut block_statements = VecDeque::new(); - for s in statements { - self.flatten_assembly_statement(&mut block_statements, s); - } - statements_flattened.push_back(FlatStatement::Block(block_statements.into())); - } - ZirStatement::Return(exprs) => { + let span = s.get_span(); + + let span_backup = statements_flattened.span; + + statements_flattened.set_span(span); + + match s { + ZirStatement::Return(s) => { #[allow(clippy::needless_collect)] // clippy suggests to not collect here, but `statements_flattened` is borrowed in the iterator, // so we cannot borrow again when extending - let flat_expressions: Vec<_> = exprs + let flat_expressions: Vec<_> = s + .inner .into_iter() .map(|expr| self.flatten_expression(statements_flattened, expr)) .map(|x| x.get_field_unchecked()) @@ -2289,25 +2427,35 @@ impl<'ast, T: Field> Flattener<'ast, T> { flat_expressions .into_iter() .enumerate() - .map(|(index, e)| FlatStatement::Definition(Variable::public(index), e)), + .map(|(index, e)| FlatStatement::definition(Variable::public(index), e)), ); } - ZirStatement::IfElse(condition, consequence, alternative) => { + ZirStatement::Assembly(s) => { + let mut block_statements = FlatStatements::default(); + block_statements.set_span(s.get_span()); + + for s in s.inner { + self.flatten_assembly_statement(&mut block_statements, s); + } + statements_flattened + .push_back(FlatStatement::block(block_statements.buffer.into())); + } + ZirStatement::IfElse(s) => { let condition_flat = - self.flatten_boolean_expression(statements_flattened, condition.clone()); + self.flatten_boolean_expression(statements_flattened, s.condition.clone()); let condition_id = self.use_sym(); statements_flattened - .push_back(FlatStatement::Definition(condition_id, condition_flat)); + .push_back(FlatStatement::definition(condition_id, condition_flat)); if self.config.isolate_branches { - let mut consequence_statements = VecDeque::new(); - let mut alternative_statements = VecDeque::new(); + let mut consequence_statements = FlatStatements::default(); + let mut alternative_statements = FlatStatements::default(); - consequence + s.consequence .into_iter() .for_each(|s| self.flatten_statement(&mut consequence_statements, s)); - alternative + s.alternative .into_iter() .for_each(|s| self.flatten_statement(&mut alternative_statements, s)); @@ -2315,41 +2463,41 @@ impl<'ast, T: Field> Flattener<'ast, T> { self.make_conditional(consequence_statements, condition_id.into()); let alternative_statements = self.make_conditional( alternative_statements, - FlatExpression::Sub( - box FlatExpression::Number(T::one()), - box condition_id.into(), - ), + FlatExpression::sub(FlatExpression::value(T::one()), condition_id.into()), ); statements_flattened.extend(consequence_statements); statements_flattened.extend(alternative_statements); } else { - consequence + s.consequence .into_iter() .for_each(|s| self.flatten_statement(statements_flattened, s)); - alternative + s.alternative .into_iter() .for_each(|s| self.flatten_statement(statements_flattened, s)); } } - ZirStatement::Definition(assignee, expr) => { + ZirStatement::Definition(s) => { // define n variables with n the number of primitive types for v_type // assign them to the n primitive types for expr + let assignee = s.assignee; + let expr = s.rhs; + let rhs = self.flatten_expression(statements_flattened, expr); let bits = rhs.bits.clone(); let var = match rhs.get_field_unchecked() { FlatExpression::Identifier(id) => { - self.use_variable_with_existing(&assignee, id); - id + self.use_variable_with_existing(&assignee, id.id); + id.id } e => { let var = self.use_variable(&assignee); // handle return of function call - statements_flattened.push_back(FlatStatement::Definition(var, e)); + statements_flattened.push_back(FlatStatement::definition(var, e)); var } @@ -2358,22 +2506,25 @@ impl<'ast, T: Field> Flattener<'ast, T> { // register bits if let Some(bits) = bits { self.bits_cache - .insert(FlatExpression::Identifier(var), bits); + .insert(FlatExpression::identifier(var), bits); } } - ZirStatement::Assertion(e, error) => { + ZirStatement::Assertion(s) => { + let e = s.expression; + let error = s.error; + match e { BooleanExpression::And(..) => { for boolean in e.into_conjunction_iterator() { self.flatten_statement( statements_flattened, - ZirStatement::Assertion(boolean, error.clone()), + ZirStatement::assertion(boolean, error.clone()).span(span), ) } } - BooleanExpression::FieldEq(box lhs, box rhs) => { - let lhs = self.flatten_field_expression(statements_flattened, lhs); - let rhs = self.flatten_field_expression(statements_flattened, rhs); + BooleanExpression::FieldEq(e) => { + let lhs = self.flatten_field_expression(statements_flattened, *e.left); + let rhs = self.flatten_field_expression(statements_flattened, *e.right); self.flatten_equality_assertion( statements_flattened, @@ -2382,106 +2533,106 @@ impl<'ast, T: Field> Flattener<'ast, T> { error.into(), ) } - BooleanExpression::FieldLt(box lhs, box rhs) => { - let lhs = self.flatten_field_expression(statements_flattened, lhs); - let rhs = self.flatten_field_expression(statements_flattened, rhs); + BooleanExpression::FieldLt(e) => { + let lhs = self.flatten_field_expression(statements_flattened, *e.left); + let rhs = self.flatten_field_expression(statements_flattened, *e.right); match (lhs, rhs) { - (e, FlatExpression::Number(c)) => self.enforce_constant_lt_check( + (e, FlatExpression::Value(c)) => self.enforce_constant_lt_check( statements_flattened, e, - c, + c.value, error.into(), ), // c < e <=> p - 1 - e < p - 1 - c - (FlatExpression::Number(c), e) => self.enforce_constant_lt_check( + (FlatExpression::Value(c), e) => self.enforce_constant_lt_check( statements_flattened, - FlatExpression::Sub(box T::max_value().into(), box e), - T::max_value() - c, + FlatExpression::sub(T::max_value().into(), e), + T::max_value() - c.value, error.into(), ), (lhs, rhs) => { let bit_width = T::get_required_bits(); let safe_width = bit_width - 2; // dynamic comparison is not complete let e = self.lt_check(statements_flattened, lhs, rhs, safe_width); - statements_flattened.push_back(FlatStatement::Condition( + statements_flattened.push_back(FlatStatement::condition( e, - FlatExpression::Number(T::one()), + FlatExpression::value(T::one()), error.into(), )); } } } - BooleanExpression::FieldLe(box lhs, box rhs) => { - let lhs = self.flatten_field_expression(statements_flattened, lhs); - let rhs = self.flatten_field_expression(statements_flattened, rhs); + BooleanExpression::FieldLe(e) => { + let lhs = self.flatten_field_expression(statements_flattened, *e.left); + let rhs = self.flatten_field_expression(statements_flattened, *e.right); match (lhs, rhs) { - (e, FlatExpression::Number(c)) => self.enforce_constant_le_check( + (e, FlatExpression::Value(c)) => self.enforce_constant_le_check( statements_flattened, e, - c, + c.value, error.into(), ), // c <= e <=> p - 1 - e <= p - 1 - c - (FlatExpression::Number(c), e) => self.enforce_constant_le_check( + (FlatExpression::Value(c), e) => self.enforce_constant_le_check( statements_flattened, - FlatExpression::Sub(box T::max_value().into(), box e), - T::max_value() - c, + FlatExpression::sub(T::max_value().into(), e), + T::max_value() - c.value, error.into(), ), (lhs, rhs) => { let bit_width = T::get_required_bits(); let safe_width = bit_width - 2; // dynamic comparison is not complete let e = self.le_check(statements_flattened, lhs, rhs, safe_width); - statements_flattened.push_back(FlatStatement::Condition( + statements_flattened.push_back(FlatStatement::condition( e, - FlatExpression::Number(T::one()), + FlatExpression::value(T::one()), error.into(), )); } } } - BooleanExpression::UintLe(box lhs, box rhs) => { + BooleanExpression::UintLe(e) => { let lhs = self - .flatten_uint_expression(statements_flattened, lhs) + .flatten_uint_expression(statements_flattened, *e.left) .get_field_unchecked(); let rhs = self - .flatten_uint_expression(statements_flattened, rhs) + .flatten_uint_expression(statements_flattened, *e.right) .get_field_unchecked(); match (lhs, rhs) { - (e, FlatExpression::Number(c)) => self.enforce_constant_le_check( + (e, FlatExpression::Value(c)) => self.enforce_constant_le_check( statements_flattened, e, - c, + c.value, error.into(), ), // c <= e <=> p - 1 - e <= p - 1 - c - (FlatExpression::Number(c), e) => self.enforce_constant_le_check( + (FlatExpression::Value(c), e) => self.enforce_constant_le_check( statements_flattened, - FlatExpression::Sub(box T::max_value().into(), box e), - T::max_value() - c, + FlatExpression::sub(T::max_value().into(), e), + T::max_value() - c.value, error.into(), ), (lhs, rhs) => { let bit_width = T::get_required_bits(); let safe_width = bit_width - 2; // dynamic comparison is not complete let e = self.le_check(statements_flattened, lhs, rhs, safe_width); - statements_flattened.push_back(FlatStatement::Condition( + statements_flattened.push_back(FlatStatement::condition( e, - FlatExpression::Number(T::one()), + FlatExpression::value(T::one()), error.into(), )); } } } - BooleanExpression::UintEq(box lhs, box rhs) => { + BooleanExpression::UintEq(e) => { let lhs = self - .flatten_uint_expression(statements_flattened, lhs) + .flatten_uint_expression(statements_flattened, *e.left) .get_field_unchecked(); let rhs = self - .flatten_uint_expression(statements_flattened, rhs) + .flatten_uint_expression(statements_flattened, *e.right) .get_field_unchecked(); self.flatten_equality_assertion( @@ -2491,9 +2642,9 @@ impl<'ast, T: Field> Flattener<'ast, T> { error.into(), ) } - BooleanExpression::BoolEq(box lhs, box rhs) => { - let lhs = self.flatten_boolean_expression(statements_flattened, lhs); - let rhs = self.flatten_boolean_expression(statements_flattened, rhs); + BooleanExpression::BoolEq(e) => { + let lhs = self.flatten_boolean_expression(statements_flattened, *e.left); + let rhs = self.flatten_boolean_expression(statements_flattened, *e.right); self.flatten_equality_assertion( statements_flattened, @@ -2502,106 +2653,78 @@ impl<'ast, T: Field> Flattener<'ast, T> { error.into(), ) } - // `!(x == 0)` can be asserted by giving the inverse of `x` - BooleanExpression::Not(box BooleanExpression::UintEq( - box UExpression { - inner: UExpressionInner::Value(0), - .. - }, - box x, - )) - | BooleanExpression::Not(box BooleanExpression::UintEq( - box x, - box UExpression { - inner: UExpressionInner::Value(0), - .. - }, - )) => { - let x = self - .flatten_uint_expression(statements_flattened, x) - .get_field_unchecked(); - - // introduce intermediate variable - let x_id = self.define(x, statements_flattened); - - // check that `x` is not 0 by giving its inverse - let invx = self.use_sym(); - - // # invx = 1/x - statements_flattened.push_back(FlatStatement::Directive( - FlatDirective::new( - vec![invx], - Solver::Div, - vec![FlatExpression::Number(T::one()), x_id.into()], - ), - )); - - // assert(invx * x == 1) - statements_flattened.push_back(FlatStatement::Condition( - FlatExpression::Number(T::one()), - FlatExpression::Mult(box invx.into(), box x_id.into()), - RuntimeError::Inverse, - )); - } - // `!(x == 0)` can be asserted by giving the inverse of `x` - BooleanExpression::Not(box BooleanExpression::FieldEq( - box FieldElementExpression::Number(zero), - box x, - )) - | BooleanExpression::Not(box BooleanExpression::FieldEq( - box x, - box FieldElementExpression::Number(zero), - )) if zero == T::from(0) => { - let x = self.flatten_field_expression(statements_flattened, x); - - // introduce intermediate variable - let x_id = self.define(x, statements_flattened); - - // check that `x` is not 0 by giving its inverse - let invx = self.use_sym(); - - // # invx = 1/x - statements_flattened.push_back(FlatStatement::Directive( - FlatDirective::new( - vec![invx], - Solver::Div, - vec![FlatExpression::Number(T::one()), x_id.into()], + BooleanExpression::Not(u) => { + let inner_span = u.get_span(); + + match *u.inner { + BooleanExpression::UintEq(b) => { + if let UExpressionInner::Value(ValueExpression { + value: 0, .. + }) = b.left.inner + { + let x = self + .flatten_uint_expression(statements_flattened, *b.right) + .get_field_unchecked(); + self.enforce_not_zero_assertion(statements_flattened, x) + } else if let UExpressionInner::Value(ValueExpression { + value: 0, + .. + }) = b.right.inner + { + let x = self + .flatten_uint_expression(statements_flattened, *b.left) + .get_field_unchecked(); + self.enforce_not_zero_assertion(statements_flattened, x) + } else { + self.enforce_naive_assertion( + statements_flattened, + BooleanExpression::not(BooleanExpression::UintEq(b)), + error, + ); + } + } + BooleanExpression::FieldEq(b) => match (*b.left, *b.right) { + ( + FieldElementExpression::Value(ValueExpression { + value: zero, + .. + }), + x, + ) + | ( + x, + FieldElementExpression::Value(ValueExpression { + value: zero, + .. + }), + ) if zero == T::from(0) => { + let x = self.flatten_field_expression(statements_flattened, x); + self.enforce_not_zero_assertion(statements_flattened, x) + } + (left, right) => self.enforce_naive_assertion( + statements_flattened, + BooleanExpression::not( + BooleanExpression::field_eq(left, right).span(inner_span), + ) + .span(span), + error, + ), + }, + e => self.enforce_naive_assertion( + statements_flattened, + BooleanExpression::not(e.span(inner_span)).span(span), + error, ), - )); - - // assert(invx * x == 1) - statements_flattened.push_back(FlatStatement::Condition( - FlatExpression::Number(T::one()), - FlatExpression::Mult(box invx.into(), box x_id.into()), - RuntimeError::Inverse, - )); - } - e => { - // naive approach: flatten the boolean to a single field element and constrain it to 1 - let e = self.flatten_boolean_expression(statements_flattened, e); - - if e.is_linear() { - statements_flattened.push_back(FlatStatement::Condition( - e, - FlatExpression::Number(T::from(1)), - error.into(), - )); - } else { - // swap so that left side is linear - statements_flattened.push_back(FlatStatement::Condition( - FlatExpression::Number(T::from(1)), - e, - error.into(), - )); } } + e => self.enforce_naive_assertion(statements_flattened, e, error), } } - ZirStatement::MultipleDefinition(vars, rhs) => { + ZirStatement::MultipleDefinition(s) => { // flatten the right side to p = sum(var_i.type.primitive_count) expressions // define p new variables to the right side expressions - match rhs { + match s.rhs { ZirExpressionList::EmbedCall(embed, generics, exprs) => { let rhs_flattened = self.flatten_embed_call( statements_flattened, @@ -2612,20 +2735,21 @@ impl<'ast, T: Field> Flattener<'ast, T> { let rhs = rhs_flattened.into_iter(); - assert_eq!(vars.len(), rhs.len()); + assert_eq!(s.assignees.len(), rhs.len()); - let vars: Vec<_> = vars + let assignees: Vec<_> = s + .assignees .into_iter() .zip(rhs) .map(|(v, r)| match r.get_field_unchecked() { FlatExpression::Identifier(id) => { - self.use_variable_with_existing(&v, id); - id + self.use_variable_with_existing(&v, id.id); + id.id } e => { let id = self.use_variable(&v); statements_flattened - .push_back(FlatStatement::Definition(id, e)); + .push_back(FlatStatement::definition(id, e)); id } }) @@ -2643,15 +2767,16 @@ impl<'ast, T: Field> Flattener<'ast, T> { .get_field_unchecked() }) .collect(); - self.bits_cache.insert(vars[0].into(), bits); + self.bits_cache.insert(assignees[0].into(), bits); } _ => {} } } } } - ZirStatement::Log(l, expressions) => { - let expressions = expressions + ZirStatement::Log(s) => { + let expressions = s + .expressions .into_iter() .map(|(t, e)| { ( @@ -2666,11 +2791,73 @@ impl<'ast, T: Field> Flattener<'ast, T> { }) .collect(); - statements_flattened.push_back(FlatStatement::Log(l, expressions)); + statements_flattened.push_back(FlatStatement::Log(LogStatement::new( + s.format_string, + expressions, + ))); } + }; + + statements_flattened.set_span(span_backup); + } + + fn enforce_naive_assertion( + &mut self, + statements_flattened: &mut FlatStatements<'ast, T>, + e: BooleanExpression<'ast, T>, + error: zokrates_ast::zir::RuntimeError, + ) { + // naive approach: flatten the boolean to a single field element and constrain it to 1 + let e = self.flatten_boolean_expression(statements_flattened, e); + + if e.is_linear() { + statements_flattened.push_back(FlatStatement::condition( + e, + FlatExpression::value(T::from(1)), + error.into(), + )); + } else { + // swap so that left side is linear + statements_flattened.push_back(FlatStatement::condition( + FlatExpression::value(T::from(1)), + e, + error.into(), + )); } } + /// Enforce that x is not zero + /// + /// # Arguments + /// + /// * `statements_flattened` - `FlatStatements<'ast, T>` Vector where new flattened statements can be added. + /// * `x` - `FlatExpression` The expression to be constrained to not be zero. + fn enforce_not_zero_assertion( + &mut self, + statements_flattened: &mut FlatStatements<'ast, T>, + x: FlatExpression, + ) { + // introduce intermediate variable + let x_id = self.define(x, statements_flattened); + + // check that `x` is not 0 by giving its inverse + let invx = self.use_sym(); + + // # invx = 1/x + statements_flattened.push_back(FlatStatement::Directive(FlatDirective::new( + vec![invx], + Solver::Div, + vec![FlatExpression::value(T::one()), x_id.into()], + ))); + + // assert(invx * x == 1) + statements_flattened.push_back(FlatStatement::condition( + FlatExpression::value(T::one()), + FlatExpression::mul(invx.into(), x_id.into()), + RuntimeError::Inverse, + )); + } + /// Flattens an equality assertion, enforcing it in the circuit. /// /// # Arguments @@ -2686,22 +2873,22 @@ impl<'ast, T: Field> Flattener<'ast, T> { error: RuntimeError, ) { let (lhs, rhs) = match (lhs, rhs) { - (FlatExpression::Mult(box x, box y), z) | (z, FlatExpression::Mult(box x, box y)) => ( + (FlatExpression::Mult(e), z) | (z, FlatExpression::Mult(e)) => ( self.identify_expression(z, statements_flattened), - FlatExpression::Mult( - box self.identify_expression(x, statements_flattened), - box self.identify_expression(y, statements_flattened), + FlatExpression::mul( + self.identify_expression(*e.left, statements_flattened), + self.identify_expression(*e.right, statements_flattened), ), ), (x, z) => ( self.identify_expression(z, statements_flattened), - FlatExpression::Mult( - box self.identify_expression(x, statements_flattened), - box FlatExpression::Number(T::from(1)), + FlatExpression::mul( + self.identify_expression(x, statements_flattened), + FlatExpression::value(T::from(1)), ), ), }; - statements_flattened.push_back(FlatStatement::Condition(lhs, rhs, error)); + statements_flattened.push_back(FlatStatement::condition(lhs, rhs, error)); } /// Identifies a non-linear expression by assigning it to a new identifier. @@ -2719,8 +2906,8 @@ impl<'ast, T: Field> Flattener<'ast, T> { true => e, false => { let sym = self.use_sym(); - statements_flattened.push_back(FlatStatement::Definition(sym, e)); - FlatExpression::Identifier(sym) + statements_flattened.push_back(FlatStatement::definition(sym, e)); + FlatExpression::identifier(sym) } } } @@ -2754,6 +2941,12 @@ impl<'ast, T: Field> Flattener<'ast, T> { parameter: &ZirParameter<'ast>, statements_flattened: &mut FlatStatements<'ast, T>, ) -> Parameter { + let span = parameter.get_span(); + + let backup_span = statements_flattened.span; + + statements_flattened.set_span(span); + let variable = self.use_variable(¶meter.id); match parameter.id.get_type() { @@ -2761,7 +2954,7 @@ impl<'ast, T: Field> Flattener<'ast, T> { // to constrain unsigned integer inputs to be in range, we get their bit decomposition. // it will be cached self.get_bits_unchecked( - &FlatUExpression::with_field(FlatExpression::Identifier(variable)), + &FlatUExpression::with_field(FlatExpression::identifier(variable)), bitwidth.to_usize(), bitwidth.to_usize(), statements_flattened, @@ -2769,19 +2962,18 @@ impl<'ast, T: Field> Flattener<'ast, T> { ); } Type::Boolean => { - statements_flattened.push_back(FlatStatement::Condition( + statements_flattened.push_back(FlatStatement::condition( variable.into(), - FlatExpression::Mult(box variable.into(), box variable.into()), + FlatExpression::mul(variable.into(), variable.into()), RuntimeError::ArgumentBitness, )); } Type::FieldElement => {} } - Parameter { - id: variable, - private: parameter.private, - } + statements_flattened.set_span(backup_span); + + Parameter::new(variable, parameter.private).span(span) } fn issue_new_variable(&mut self) -> Variable { @@ -2803,10 +2995,18 @@ mod tests { use zokrates_ast::zir::types::Signature; use zokrates_ast::zir::types::Type; use zokrates_ast::zir::Id; + use zokrates_ast::zir::ZirFunction; use zokrates_field::Bn128Field; fn flatten_function(f: ZirFunction) -> FlatProg { - from_function_and_config(f, CompileConfig::default()).collect() + from_program_and_config( + ZirProgram { + main: f, + module_map: Default::default(), + }, + CompileConfig::default(), + ) + .collect() } #[test] @@ -2826,22 +3026,22 @@ mod tests { let function = ZirFunction:: { arguments: vec![], statements: vec![ - ZirStatement::Definition( + ZirStatement::definition( zir::Variable::boolean("x".into()), - BooleanExpression::Value(true).into(), + BooleanExpression::value(true).into(), ), - ZirStatement::Definition( + ZirStatement::definition( zir::Variable::boolean("y".into()), - BooleanExpression::Value(true).into(), + BooleanExpression::value(true).into(), ), - ZirStatement::Assertion( - BooleanExpression::BoolEq( - box BooleanExpression::identifier("x".into()), - box BooleanExpression::identifier("y".into()), + ZirStatement::assertion( + BooleanExpression::bool_eq( + BooleanExpression::identifier("x".into()), + BooleanExpression::identifier("y".into()), ), zir::RuntimeError::mock(), ), - ZirStatement::Return(vec![]), + ZirStatement::ret(vec![]), ], signature: Signature { inputs: vec![], @@ -2851,22 +3051,23 @@ mod tests { let flat = flatten_function(function); let expected = FlatFunction { + module_map: Default::default(), arguments: vec![], return_count: 0, statements: vec![ - FlatStatement::Definition( + FlatStatement::definition( Variable::new(0), - FlatExpression::Number(Bn128Field::from(1)), + FlatExpression::value(Bn128Field::from(1)), ), - FlatStatement::Definition( + FlatStatement::definition( Variable::new(1), - FlatExpression::Number(Bn128Field::from(1)), + FlatExpression::value(Bn128Field::from(1)), ), - FlatStatement::Condition( - FlatExpression::Identifier(Variable::new(1)), - FlatExpression::Mult( - box FlatExpression::Identifier(Variable::new(0)), - box FlatExpression::Number(Bn128Field::from(1)), + FlatStatement::condition( + FlatExpression::identifier(Variable::new(1)), + FlatExpression::mul( + FlatExpression::identifier(Variable::new(0)), + FlatExpression::value(Bn128Field::from(1)), ), zir::RuntimeError::mock().into(), ), @@ -2893,25 +3094,25 @@ mod tests { let function = ZirFunction { arguments: vec![], statements: vec![ - ZirStatement::Definition( + ZirStatement::definition( zir::Variable::field_element("x"), - FieldElementExpression::Number(Bn128Field::from(1)).into(), + FieldElementExpression::value(Bn128Field::from(1)).into(), ), - ZirStatement::Definition( + ZirStatement::definition( zir::Variable::field_element("y"), - FieldElementExpression::Number(Bn128Field::from(2)).into(), + FieldElementExpression::value(Bn128Field::from(2)).into(), ), - ZirStatement::Assertion( - BooleanExpression::FieldEq( - box FieldElementExpression::Add( - box FieldElementExpression::identifier("x".into()), - box FieldElementExpression::Number(Bn128Field::from(1)), + ZirStatement::assertion( + BooleanExpression::field_eq( + FieldElementExpression::add( + FieldElementExpression::identifier("x".into()), + FieldElementExpression::value(Bn128Field::from(1)), ), - box FieldElementExpression::identifier("y".into()), + FieldElementExpression::identifier("y".into()), ), zir::RuntimeError::mock(), ), - ZirStatement::Return(vec![]), + ZirStatement::ret(vec![]), ], signature: Signature { inputs: vec![], @@ -2922,25 +3123,26 @@ mod tests { let flat = flatten_function(function); let expected = FlatFunction { + module_map: Default::default(), arguments: vec![], return_count: 0, statements: vec![ - FlatStatement::Definition( + FlatStatement::definition( Variable::new(0), - FlatExpression::Number(Bn128Field::from(1)), + FlatExpression::value(Bn128Field::from(1)), ), - FlatStatement::Definition( + FlatStatement::definition( Variable::new(1), - FlatExpression::Number(Bn128Field::from(2)), - ), - FlatStatement::Condition( - FlatExpression::Identifier(Variable::new(1)), - FlatExpression::Mult( - box FlatExpression::Add( - box FlatExpression::Identifier(Variable::new(0)), - box FlatExpression::Number(Bn128Field::from(1)), + FlatExpression::value(Bn128Field::from(2)), + ), + FlatStatement::condition( + FlatExpression::identifier(Variable::new(1)), + FlatExpression::mul( + FlatExpression::add( + FlatExpression::identifier(Variable::new(0)), + FlatExpression::value(Bn128Field::from(1)), ), - box FlatExpression::Number(Bn128Field::from(1)), + FlatExpression::value(Bn128Field::from(1)), ), zir::RuntimeError::mock().into(), ), @@ -2969,24 +3171,24 @@ mod tests { let function = ZirFunction:: { arguments: vec![], statements: vec![ - ZirStatement::Definition( + ZirStatement::definition( zir::Variable::uint("x".into(), 32), ZirExpression::Uint( - UExpressionInner::Value(42) + UExpression::value(42) .annotate(32) .metadata(metadata.clone()), ), ), - ZirStatement::Assertion( - BooleanExpression::UintEq( - box UExpression::identifier("x".into()) + ZirStatement::assertion( + BooleanExpression::uint_eq( + UExpression::identifier("x".into()) .annotate(32) .metadata(metadata.clone()), - box UExpressionInner::Value(42).annotate(32).metadata(metadata), + UExpression::value(42).annotate(32).metadata(metadata), ), zir::RuntimeError::mock(), ), - ZirStatement::Return(vec![]), + ZirStatement::ret(vec![]), ], signature: Signature { inputs: vec![], @@ -2997,18 +3199,19 @@ mod tests { let flat = flatten_function(function); let expected = FlatFunction { + module_map: Default::default(), arguments: vec![], return_count: 0, statements: vec![ - FlatStatement::Definition( + FlatStatement::definition( Variable::new(0), - FlatExpression::Number(Bn128Field::from(42)), + FlatExpression::value(Bn128Field::from(42)), ), - FlatStatement::Condition( - FlatExpression::Number(Bn128Field::from(42)), - FlatExpression::Mult( - box FlatExpression::Identifier(Variable::new(0)), - box FlatExpression::Number(Bn128Field::from(1)), + FlatStatement::condition( + FlatExpression::value(Bn128Field::from(42)), + FlatExpression::mul( + FlatExpression::identifier(Variable::new(0)), + FlatExpression::value(Bn128Field::from(1)), ), zir::RuntimeError::mock().into(), ), @@ -3035,22 +3238,22 @@ mod tests { let function = ZirFunction { arguments: vec![], statements: vec![ - ZirStatement::Definition( + ZirStatement::definition( zir::Variable::field_element("x"), - FieldElementExpression::Number(Bn128Field::from(2)).into(), + FieldElementExpression::value(Bn128Field::from(2)).into(), ), - ZirStatement::Definition( + ZirStatement::definition( zir::Variable::field_element("y"), - FieldElementExpression::Number(Bn128Field::from(2)).into(), + FieldElementExpression::value(Bn128Field::from(2)).into(), ), - ZirStatement::Assertion( - BooleanExpression::FieldEq( - box FieldElementExpression::identifier("x".into()), - box FieldElementExpression::identifier("y".into()), + ZirStatement::assertion( + BooleanExpression::field_eq( + FieldElementExpression::identifier("x".into()), + FieldElementExpression::identifier("y".into()), ), zir::RuntimeError::mock(), ), - ZirStatement::Return(vec![]), + ZirStatement::ret(vec![]), ], signature: Signature { inputs: vec![], @@ -3061,22 +3264,23 @@ mod tests { let flat = flatten_function(function); let expected = FlatFunction { + module_map: Default::default(), arguments: vec![], return_count: 0, statements: vec![ - FlatStatement::Definition( + FlatStatement::definition( Variable::new(0), - FlatExpression::Number(Bn128Field::from(2)), + FlatExpression::value(Bn128Field::from(2)), ), - FlatStatement::Definition( + FlatStatement::definition( Variable::new(1), - FlatExpression::Number(Bn128Field::from(2)), + FlatExpression::value(Bn128Field::from(2)), ), - FlatStatement::Condition( - FlatExpression::Identifier(Variable::new(1)), - FlatExpression::Mult( - box FlatExpression::Identifier(Variable::new(0)), - box FlatExpression::Number(Bn128Field::from(1)), + FlatStatement::condition( + FlatExpression::identifier(Variable::new(1)), + FlatExpression::mul( + FlatExpression::identifier(Variable::new(0)), + FlatExpression::value(Bn128Field::from(1)), ), zir::RuntimeError::mock().into(), ), @@ -3105,29 +3309,29 @@ mod tests { let function = ZirFunction { arguments: vec![], statements: vec![ - ZirStatement::Definition( + ZirStatement::definition( zir::Variable::field_element("x"), - FieldElementExpression::Number(Bn128Field::from(2)).into(), + FieldElementExpression::value(Bn128Field::from(2)).into(), ), - ZirStatement::Definition( + ZirStatement::definition( zir::Variable::field_element("y"), - FieldElementExpression::Number(Bn128Field::from(2)).into(), + FieldElementExpression::value(Bn128Field::from(2)).into(), ), - ZirStatement::Definition( + ZirStatement::definition( zir::Variable::field_element("z"), - FieldElementExpression::Number(Bn128Field::from(4)).into(), + FieldElementExpression::value(Bn128Field::from(4)).into(), ), - ZirStatement::Assertion( - BooleanExpression::FieldEq( - box FieldElementExpression::Mult( - box FieldElementExpression::identifier("x".into()), - box FieldElementExpression::identifier("y".into()), + ZirStatement::assertion( + BooleanExpression::field_eq( + FieldElementExpression::mul( + FieldElementExpression::identifier("x".into()), + FieldElementExpression::identifier("y".into()), ), - box FieldElementExpression::identifier("z".into()), + FieldElementExpression::identifier("z".into()), ), zir::RuntimeError::mock(), ), - ZirStatement::Return(vec![]), + ZirStatement::ret(vec![]), ], signature: Signature { inputs: vec![], @@ -3138,26 +3342,27 @@ mod tests { let flat = flatten_function(function); let expected = FlatFunction { + module_map: Default::default(), arguments: vec![], return_count: 0, statements: vec![ - FlatStatement::Definition( + FlatStatement::definition( Variable::new(0), - FlatExpression::Number(Bn128Field::from(2)), + FlatExpression::value(Bn128Field::from(2)), ), - FlatStatement::Definition( + FlatStatement::definition( Variable::new(1), - FlatExpression::Number(Bn128Field::from(2)), + FlatExpression::value(Bn128Field::from(2)), ), - FlatStatement::Definition( + FlatStatement::definition( Variable::new(2), - FlatExpression::Number(Bn128Field::from(4)), + FlatExpression::value(Bn128Field::from(4)), ), - FlatStatement::Condition( - FlatExpression::Identifier(Variable::new(2)), - FlatExpression::Mult( - box FlatExpression::Identifier(Variable::new(0)), - box FlatExpression::Identifier(Variable::new(1)), + FlatStatement::condition( + FlatExpression::identifier(Variable::new(2)), + FlatExpression::mul( + FlatExpression::identifier(Variable::new(0)), + FlatExpression::identifier(Variable::new(1)), ), zir::RuntimeError::mock().into(), ), @@ -3186,29 +3391,29 @@ mod tests { let function = ZirFunction { arguments: vec![], statements: vec![ - ZirStatement::Definition( + ZirStatement::definition( zir::Variable::field_element("x"), - FieldElementExpression::Number(Bn128Field::from(2)).into(), + FieldElementExpression::value(Bn128Field::from(2)).into(), ), - ZirStatement::Definition( + ZirStatement::definition( zir::Variable::field_element("y"), - FieldElementExpression::Number(Bn128Field::from(2)).into(), + FieldElementExpression::value(Bn128Field::from(2)).into(), ), - ZirStatement::Definition( + ZirStatement::definition( zir::Variable::field_element("z"), - FieldElementExpression::Number(Bn128Field::from(4)).into(), - ), - ZirStatement::Assertion( - BooleanExpression::FieldEq( - box FieldElementExpression::identifier("z".into()), - box FieldElementExpression::Mult( - box FieldElementExpression::identifier("x".into()), - box FieldElementExpression::identifier("y".into()), + FieldElementExpression::value(Bn128Field::from(4)).into(), + ), + ZirStatement::assertion( + BooleanExpression::field_eq( + FieldElementExpression::identifier("z".into()), + FieldElementExpression::mul( + FieldElementExpression::identifier("x".into()), + FieldElementExpression::identifier("y".into()), ), ), zir::RuntimeError::mock(), ), - ZirStatement::Return(vec![]), + ZirStatement::ret(vec![]), ], signature: Signature { inputs: vec![], @@ -3219,26 +3424,27 @@ mod tests { let flat = flatten_function(function); let expected = FlatFunction { + module_map: Default::default(), arguments: vec![], return_count: 0, statements: vec![ - FlatStatement::Definition( + FlatStatement::definition( Variable::new(0), - FlatExpression::Number(Bn128Field::from(2)), + FlatExpression::value(Bn128Field::from(2)), ), - FlatStatement::Definition( + FlatStatement::definition( Variable::new(1), - FlatExpression::Number(Bn128Field::from(2)), + FlatExpression::value(Bn128Field::from(2)), ), - FlatStatement::Definition( + FlatStatement::definition( Variable::new(2), - FlatExpression::Number(Bn128Field::from(4)), + FlatExpression::value(Bn128Field::from(4)), ), - FlatStatement::Condition( - FlatExpression::Identifier(Variable::new(2)), - FlatExpression::Mult( - box FlatExpression::Identifier(Variable::new(0)), - box FlatExpression::Identifier(Variable::new(1)), + FlatStatement::condition( + FlatExpression::identifier(Variable::new(2)), + FlatExpression::mul( + FlatExpression::identifier(Variable::new(0)), + FlatExpression::identifier(Variable::new(1)), ), zir::RuntimeError::mock().into(), ), @@ -3270,31 +3476,31 @@ mod tests { let function = ZirFunction { arguments: vec![], statements: vec![ - ZirStatement::Definition( + ZirStatement::definition( zir::Variable::field_element("x"), - FieldElementExpression::Number(Bn128Field::from(4)).into(), + FieldElementExpression::value(Bn128Field::from(4)).into(), ), - ZirStatement::Definition( + ZirStatement::definition( zir::Variable::field_element("y"), - FieldElementExpression::Number(Bn128Field::from(4)).into(), + FieldElementExpression::value(Bn128Field::from(4)).into(), ), - ZirStatement::Definition( + ZirStatement::definition( zir::Variable::field_element("z"), - FieldElementExpression::Number(Bn128Field::from(8)).into(), + FieldElementExpression::value(Bn128Field::from(8)).into(), ), - ZirStatement::Definition( + ZirStatement::definition( zir::Variable::field_element("t"), - FieldElementExpression::Number(Bn128Field::from(2)).into(), + FieldElementExpression::value(Bn128Field::from(2)).into(), ), - ZirStatement::Assertion( - BooleanExpression::FieldEq( - box FieldElementExpression::Mult( - box FieldElementExpression::identifier("x".into()), - box FieldElementExpression::identifier("y".into()), + ZirStatement::assertion( + BooleanExpression::field_eq( + FieldElementExpression::mul( + FieldElementExpression::identifier("x".into()), + FieldElementExpression::identifier("y".into()), ), - box FieldElementExpression::Mult( - box FieldElementExpression::identifier("z".into()), - box FieldElementExpression::identifier("t".into()), + FieldElementExpression::mul( + FieldElementExpression::identifier("z".into()), + FieldElementExpression::identifier("t".into()), ), ), zir::RuntimeError::mock(), @@ -3309,37 +3515,38 @@ mod tests { let flat = flatten_function(function); let expected = FlatFunction { + module_map: Default::default(), arguments: vec![], return_count: 0, statements: vec![ - FlatStatement::Definition( + FlatStatement::definition( Variable::new(0), - FlatExpression::Number(Bn128Field::from(4)), + FlatExpression::value(Bn128Field::from(4)), ), - FlatStatement::Definition( + FlatStatement::definition( Variable::new(1), - FlatExpression::Number(Bn128Field::from(4)), + FlatExpression::value(Bn128Field::from(4)), ), - FlatStatement::Definition( + FlatStatement::definition( Variable::new(2), - FlatExpression::Number(Bn128Field::from(8)), + FlatExpression::value(Bn128Field::from(8)), ), - FlatStatement::Definition( + FlatStatement::definition( Variable::new(3), - FlatExpression::Number(Bn128Field::from(2)), + FlatExpression::value(Bn128Field::from(2)), ), - FlatStatement::Definition( + FlatStatement::definition( Variable::new(4), - FlatExpression::Mult( - box FlatExpression::Identifier(Variable::new(2)), - box FlatExpression::Identifier(Variable::new(3)), + FlatExpression::mul( + FlatExpression::identifier(Variable::new(2)), + FlatExpression::identifier(Variable::new(3)), ), ), - FlatStatement::Condition( - FlatExpression::Identifier(Variable::new(4)), - FlatExpression::Mult( - box FlatExpression::Identifier(Variable::new(0)), - box FlatExpression::Identifier(Variable::new(1)), + FlatStatement::condition( + FlatExpression::identifier(Variable::new(4)), + FlatExpression::mul( + FlatExpression::identifier(Variable::new(0)), + FlatExpression::identifier(Variable::new(1)), ), zir::RuntimeError::mock().into(), ), @@ -3365,19 +3572,19 @@ mod tests { let function = ZirFunction { arguments: vec![], statements: vec![ - ZirStatement::Definition( + ZirStatement::definition( zir::Variable::field_element("a"), - FieldElementExpression::Number(Bn128Field::from(7)).into(), + FieldElementExpression::value(Bn128Field::from(7)).into(), ), - ZirStatement::Definition( + ZirStatement::definition( zir::Variable::field_element("b"), - FieldElementExpression::Pow( - box FieldElementExpression::identifier("a".into()), - box 0u32.into(), + FieldElementExpression::pow( + FieldElementExpression::identifier("a".into()), + 0u32.into(), ) .into(), ), - ZirStatement::Return(vec![FieldElementExpression::identifier("b".into()).into()]), + ZirStatement::ret(vec![FieldElementExpression::identifier("b".into()).into()]), ], signature: Signature { inputs: vec![], @@ -3386,20 +3593,21 @@ mod tests { }; let expected = FlatFunction { + module_map: Default::default(), arguments: vec![], return_count: 1, statements: vec![ - FlatStatement::Definition( + FlatStatement::definition( Variable::new(0), - FlatExpression::Number(Bn128Field::from(7)), + FlatExpression::value(Bn128Field::from(7)), ), - FlatStatement::Definition( + FlatStatement::definition( Variable::new(1), - FlatExpression::Number(Bn128Field::from(1)), + FlatExpression::value(Bn128Field::from(1)), ), - FlatStatement::Definition( + FlatStatement::definition( Variable::public(0), - FlatExpression::Identifier(Variable::new(1)), + FlatExpression::identifier(Variable::new(1)), ), ], }; @@ -3426,19 +3634,19 @@ mod tests { let function = ZirFunction { arguments: vec![], statements: vec![ - ZirStatement::Definition( + ZirStatement::definition( zir::Variable::field_element("a"), - FieldElementExpression::Number(Bn128Field::from(7)).into(), + FieldElementExpression::value(Bn128Field::from(7)).into(), ), - ZirStatement::Definition( + ZirStatement::definition( zir::Variable::field_element("b"), - FieldElementExpression::Pow( - box FieldElementExpression::identifier("a".into()), - box 1u32.into(), + FieldElementExpression::pow( + FieldElementExpression::identifier("a".into()), + 1u32.into(), ) .into(), ), - ZirStatement::Return(vec![FieldElementExpression::identifier("b".into()).into()]), + ZirStatement::ret(vec![FieldElementExpression::identifier("b".into()).into()]), ], signature: Signature { inputs: vec![], @@ -3447,23 +3655,24 @@ mod tests { }; let expected = FlatFunction { + module_map: Default::default(), arguments: vec![], return_count: 1, statements: vec![ - FlatStatement::Definition( + FlatStatement::definition( Variable::new(0), - FlatExpression::Number(Bn128Field::from(7)), + FlatExpression::value(Bn128Field::from(7)), ), - FlatStatement::Definition( + FlatStatement::definition( Variable::new(1), - FlatExpression::Mult( - box FlatExpression::Number(Bn128Field::from(1)), - box FlatExpression::Identifier(Variable::new(0)), + FlatExpression::mul( + FlatExpression::value(Bn128Field::from(1)), + FlatExpression::identifier(Variable::new(0)), ), ), - FlatStatement::Definition( + FlatStatement::definition( Variable::public(0), - FlatExpression::Identifier(Variable::new(1)), + FlatExpression::identifier(Variable::new(1)), ), ], }; @@ -3507,19 +3716,19 @@ mod tests { let function = ZirFunction { arguments: vec![], statements: vec![ - ZirStatement::Definition( + ZirStatement::definition( zir::Variable::field_element("a"), - FieldElementExpression::Number(Bn128Field::from(7)).into(), + FieldElementExpression::value(Bn128Field::from(7)).into(), ), - ZirStatement::Definition( + ZirStatement::definition( zir::Variable::field_element("b"), - FieldElementExpression::Pow( - box FieldElementExpression::identifier("a".into()), - box 13u32.into(), + FieldElementExpression::pow( + FieldElementExpression::identifier("a".into()), + 13u32.into(), ) .into(), ), - ZirStatement::Return(vec![FieldElementExpression::identifier("b".into()).into()]), + ZirStatement::ret(vec![FieldElementExpression::identifier("b".into()).into()]), ], signature: Signature { inputs: vec![], @@ -3528,58 +3737,59 @@ mod tests { }; let expected = FlatFunction { + module_map: Default::default(), arguments: vec![], return_count: 1, statements: vec![ - FlatStatement::Definition( + FlatStatement::definition( Variable::new(0), - FlatExpression::Number(Bn128Field::from(7)), + FlatExpression::value(Bn128Field::from(7)), ), - FlatStatement::Definition( + FlatStatement::definition( Variable::new(1), - FlatExpression::Mult( - box FlatExpression::Identifier(Variable::new(0)), - box FlatExpression::Identifier(Variable::new(0)), + FlatExpression::mul( + FlatExpression::identifier(Variable::new(0)), + FlatExpression::identifier(Variable::new(0)), ), ), - FlatStatement::Definition( + FlatStatement::definition( Variable::new(2), - FlatExpression::Mult( - box FlatExpression::Identifier(Variable::new(1)), - box FlatExpression::Identifier(Variable::new(1)), + FlatExpression::mul( + FlatExpression::identifier(Variable::new(1)), + FlatExpression::identifier(Variable::new(1)), ), ), - FlatStatement::Definition( + FlatStatement::definition( Variable::new(3), - FlatExpression::Mult( - box FlatExpression::Identifier(Variable::new(2)), - box FlatExpression::Identifier(Variable::new(2)), + FlatExpression::mul( + FlatExpression::identifier(Variable::new(2)), + FlatExpression::identifier(Variable::new(2)), ), ), - FlatStatement::Definition( + FlatStatement::definition( Variable::new(4), - FlatExpression::Mult( - box FlatExpression::Number(Bn128Field::from(1)), - box FlatExpression::Identifier(Variable::new(0)), + FlatExpression::mul( + FlatExpression::value(Bn128Field::from(1)), + FlatExpression::identifier(Variable::new(0)), ), ), - FlatStatement::Definition( + FlatStatement::definition( Variable::new(5), - FlatExpression::Mult( - box FlatExpression::Identifier(Variable::new(4)), - box FlatExpression::Identifier(Variable::new(2)), + FlatExpression::mul( + FlatExpression::identifier(Variable::new(4)), + FlatExpression::identifier(Variable::new(2)), ), ), - FlatStatement::Definition( + FlatStatement::definition( Variable::new(6), - FlatExpression::Mult( - box FlatExpression::Identifier(Variable::new(5)), - box FlatExpression::Identifier(Variable::new(3)), + FlatExpression::mul( + FlatExpression::identifier(Variable::new(5)), + FlatExpression::identifier(Variable::new(3)), ), ), - FlatStatement::Definition( + FlatStatement::definition( Variable::public(0), - FlatExpression::Identifier(Variable::new(6)), + FlatExpression::identifier(Variable::new(6)), ), ], }; @@ -3593,28 +3803,28 @@ mod tests { fn if_else() { let config = CompileConfig::default(); let expression = FieldElementExpression::conditional( - BooleanExpression::FieldEq( - box FieldElementExpression::Number(Bn128Field::from(32)), - box FieldElementExpression::Number(Bn128Field::from(4)), + BooleanExpression::field_eq( + FieldElementExpression::value(Bn128Field::from(32)), + FieldElementExpression::value(Bn128Field::from(4)), ), - FieldElementExpression::Number(Bn128Field::from(12)), - FieldElementExpression::Number(Bn128Field::from(51)), + FieldElementExpression::value(Bn128Field::from(12)), + FieldElementExpression::value(Bn128Field::from(51)), ); let mut flattener = Flattener::new(config); - flattener.flatten_field_expression(&mut FlatStatements::new(), expression); + flattener.flatten_field_expression(&mut FlatStatements::default(), expression); } #[test] fn geq_leq() { let config = CompileConfig::default(); let mut flattener = Flattener::new(config); - let expression_le = BooleanExpression::FieldLe( - box FieldElementExpression::Number(Bn128Field::from(32)), - box FieldElementExpression::Number(Bn128Field::from(4)), + let expression_le = BooleanExpression::field_le( + FieldElementExpression::value(Bn128Field::from(32)), + FieldElementExpression::value(Bn128Field::from(4)), ); - flattener.flatten_boolean_expression(&mut FlatStatements::new(), expression_le); + flattener.flatten_boolean_expression(&mut FlatStatements::default(), expression_le); } #[test] @@ -3623,21 +3833,21 @@ mod tests { let mut flattener = Flattener::new(config); let expression = FieldElementExpression::conditional( - BooleanExpression::And( - box BooleanExpression::FieldEq( - box FieldElementExpression::Number(Bn128Field::from(4)), - box FieldElementExpression::Number(Bn128Field::from(4)), + BooleanExpression::bitand( + BooleanExpression::field_eq( + FieldElementExpression::value(Bn128Field::from(4)), + FieldElementExpression::value(Bn128Field::from(4)), ), - box BooleanExpression::FieldLt( - box FieldElementExpression::Number(Bn128Field::from(4)), - box FieldElementExpression::Number(Bn128Field::from(20)), + BooleanExpression::field_lt( + FieldElementExpression::value(Bn128Field::from(4)), + FieldElementExpression::value(Bn128Field::from(20)), ), ), - FieldElementExpression::Number(Bn128Field::from(12)), - FieldElementExpression::Number(Bn128Field::from(51)), + FieldElementExpression::value(Bn128Field::from(12)), + FieldElementExpression::value(Bn128Field::from(51)), ); - flattener.flatten_field_expression(&mut FlatStatements::new(), expression); + flattener.flatten_field_expression(&mut FlatStatements::default(), expression); } #[test] @@ -3645,21 +3855,21 @@ mod tests { // a = 5 / b / b let config = CompileConfig::default(); let mut flattener = Flattener::new(config); - let mut statements_flattened = FlatStatements::new(); + let mut statements_flattened = FlatStatements::default(); - let definition = ZirStatement::Definition( + let definition = ZirStatement::definition( zir::Variable::field_element("b"), - FieldElementExpression::Number(Bn128Field::from(42)).into(), + FieldElementExpression::value(Bn128Field::from(42)).into(), ); - let statement = ZirStatement::Definition( + let statement = ZirStatement::definition( zir::Variable::field_element("a"), - FieldElementExpression::Div( - box FieldElementExpression::Div( - box FieldElementExpression::Number(Bn128Field::from(5)), - box FieldElementExpression::identifier("b".into()), + FieldElementExpression::div( + FieldElementExpression::div( + FieldElementExpression::value(Bn128Field::from(5)), + FieldElementExpression::identifier("b".into()), ), - box FieldElementExpression::identifier("b".into()), + FieldElementExpression::identifier("b".into()), ) .into(), ); @@ -3683,35 +3893,35 @@ mod tests { let sym_2 = Variable::new(6); assert_eq!( - statements_flattened, + statements_flattened.buffer, vec![ - FlatStatement::Definition(b, FlatExpression::Number(Bn128Field::from(42))), + FlatStatement::definition(b, FlatExpression::value(Bn128Field::from(42))), // inputs to first div (5/b) - FlatStatement::Definition(five, FlatExpression::Number(Bn128Field::from(5))), - FlatStatement::Definition(b0, b.into()), + FlatStatement::definition(five, FlatExpression::value(Bn128Field::from(5))), + FlatStatement::definition(b0, b.into()), // execute div FlatStatement::Directive(FlatDirective::new( vec![sym_0], Solver::Div, - vec![five, b0] + vec![five.into(), b0.into()] )), - FlatStatement::Condition( + FlatStatement::condition( five.into(), - FlatExpression::Mult(box b0.into(), box sym_0.into()), + FlatExpression::mul(b0.into(), sym_0.into()), RuntimeError::Division ), // inputs to second div (res/b) - FlatStatement::Definition(sym_1, sym_0.into()), - FlatStatement::Definition(b1, b.into()), + FlatStatement::definition(sym_1, sym_0.into()), + FlatStatement::definition(b1, b.into()), // execute div FlatStatement::Directive(FlatDirective::new( vec![sym_2], Solver::Div, - vec![sym_1, b1] + vec![sym_1.into(), b1.into()] )), - FlatStatement::Condition( + FlatStatement::condition( sym_1.into(), - FlatExpression::Mult(box b1.into(), box sym_2.into()), + FlatExpression::mul(b1.into(), sym_2.into()), RuntimeError::Division ), ] diff --git a/zokrates_codegen/src/utils.rs b/zokrates_codegen/src/utils.rs index 6fc257921..ab53c4464 100644 --- a/zokrates_codegen/src/utils.rs +++ b/zokrates_codegen/src/utils.rs @@ -1,3 +1,4 @@ +use std::ops::*; use zokrates_ast::flat::*; use zokrates_field::Field; @@ -6,16 +7,16 @@ pub fn flat_expression_from_bits(v: Vec>) -> FlatExp v: Vec<(T, FlatExpression)>, ) -> FlatExpression { match v.len() { - 0 => FlatExpression::Number(T::zero()), + 0 => FlatExpression::value(T::zero()), 1 => { let (coeff, var) = v[0].clone(); - FlatExpression::Mult(box FlatExpression::Number(coeff), box var) + FlatExpression::mul(FlatExpression::value(coeff), var) } n => { let (u, v) = v.split_at(n / 2); - FlatExpression::Add( - box flat_expression_from_bits_aux(u.to_vec()), - box flat_expression_from_bits_aux(v.to_vec()), + FlatExpression::add( + flat_expression_from_bits_aux(u.to_vec()), + flat_expression_from_bits_aux(v.to_vec()), ) } } diff --git a/zokrates_common/Cargo.toml b/zokrates_common/Cargo.toml index 40ee04f0b..1a418c00c 100644 --- a/zokrates_common/Cargo.toml +++ b/zokrates_common/Cargo.toml @@ -1,15 +1,16 @@ [package] name = "zokrates_common" -version = "0.1.1" +version = "0.1.3" authors = ["dark64 "] edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] -default = ["bellman", "ark"] +default = ["bellman", "ark", "bellperson"] bellman = [] ark = [] +bellperson = [] [dependencies] diff --git a/zokrates_common/src/constants.rs b/zokrates_common/src/constants.rs index 18c4cf294..5327c8348 100644 --- a/zokrates_common/src/constants.rs +++ b/zokrates_common/src/constants.rs @@ -1,11 +1,15 @@ pub const BELLMAN: &str = "bellman"; pub const ARK: &str = "ark"; +pub const BELLPERSON: &str = "bellperson"; pub const BN128: &str = "bn128"; pub const BLS12_381: &str = "bls12_381"; pub const BLS12_377: &str = "bls12_377"; pub const BW6_761: &str = "bw6_761"; +pub const PALLAS: &str = "pallas"; +pub const VESTA: &str = "vesta"; pub const G16: &str = "g16"; pub const GM17: &str = "gm17"; pub const MARLIN: &str = "marlin"; +pub const NOVA: &str = "nova"; diff --git a/zokrates_common/src/helpers.rs b/zokrates_common/src/helpers.rs index b36f91c28..a717ec7d9 100644 --- a/zokrates_common/src/helpers.rs +++ b/zokrates_common/src/helpers.rs @@ -7,6 +7,8 @@ pub enum CurveParameter { Bls12_381, Bls12_377, Bw6_761, + Pallas, + Vesta, } impl std::fmt::Display for CurveParameter { @@ -18,6 +20,8 @@ impl std::fmt::Display for CurveParameter { Bls12_381 => write!(f, "bls12_381"), Bls12_377 => write!(f, "bls12_377"), Bw6_761 => write!(f, "bw6_761"), + Pallas => write!(f, "pallas"), + Vesta => write!(f, "vesta"), } } } @@ -28,6 +32,8 @@ pub enum BackendParameter { Bellman, #[cfg(feature = "ark")] Ark, + #[cfg(feature = "bellperson")] + Bellperson, } impl std::fmt::Display for BackendParameter { @@ -39,6 +45,8 @@ impl std::fmt::Display for BackendParameter { Bellman => write!(f, "bellman"), #[cfg(feature = "ark")] Ark => write!(f, "ark"), + #[cfg(feature = "bellperson")] + Bellperson => write!(f, "bellperson"), } } } @@ -49,6 +57,7 @@ pub enum SchemeParameter { G16, GM17, MARLIN, + NOVA, } impl std::fmt::Display for SchemeParameter { @@ -59,6 +68,7 @@ impl std::fmt::Display for SchemeParameter { G16 => write!(f, "g16"), GM17 => write!(f, "gm17"), MARLIN => write!(f, "marlin"), + NOVA => write!(f, "nova"), } } } @@ -72,6 +82,8 @@ impl TryFrom<&str> for CurveParameter { BLS12_381 => Ok(CurveParameter::Bls12_381), BLS12_377 => Ok(CurveParameter::Bls12_377), BW6_761 => Ok(CurveParameter::Bw6_761), + PALLAS => Ok(CurveParameter::Pallas), + VESTA => Ok(CurveParameter::Vesta), _ => Err(format!("Unknown curve {}", s)), } } @@ -86,6 +98,8 @@ impl TryFrom<&str> for BackendParameter { BELLMAN => Ok(BackendParameter::Bellman), #[cfg(feature = "ark")] ARK => Ok(BackendParameter::Ark), + #[cfg(feature = "bellperson")] + BELLPERSON => Ok(BackendParameter::Bellperson), _ => Err(format!("Unknown backend {}", s)), } } @@ -99,6 +113,7 @@ impl TryFrom<&str> for SchemeParameter { G16 => Ok(SchemeParameter::G16), GM17 => Ok(SchemeParameter::GM17), MARLIN => Ok(SchemeParameter::MARLIN), + NOVA => Ok(SchemeParameter::NOVA), _ => Err(format!("Unknown proving scheme {}", s)), } } @@ -148,6 +163,10 @@ impl TryFrom<(&str, &str, &str)> for Parameters { (BackendParameter::Ark, CurveParameter::Bls12_377, SchemeParameter::MARLIN) => Ok(()), #[cfg(feature = "ark")] (BackendParameter::Ark, CurveParameter::Bw6_761, SchemeParameter::MARLIN) => Ok(()), + #[cfg(feature = "bellperson")] + (BackendParameter::Bellperson, CurveParameter::Pallas, SchemeParameter::NOVA) => Ok(()), + #[cfg(feature = "bellperson")] + (BackendParameter::Bellperson, CurveParameter::Vesta, SchemeParameter::NOVA) => Ok(()), #[cfg(feature = "bellman")] _ => Err(format!( "Unsupported combination of parameters (backend: {}, curve: {}, proving scheme: {})", diff --git a/zokrates_core/Cargo.toml b/zokrates_core/Cargo.toml index 44da27eab..919677960 100644 --- a/zokrates_core/Cargo.toml +++ b/zokrates_core/Cargo.toml @@ -1,15 +1,16 @@ [package] name = "zokrates_core" -version = "0.7.2" +version = "0.7.6" edition = "2021" authors = ["Jacob Eberhardt ", "Dennis Kuhnert "] repository = "https://github.com/Zokrates/ZoKrates" readme = "README.md" [features] -default = ["ark", "bellman"] +default = ["ark", "bellman", "bellperson"] ark = ["zokrates_ast/ark", "zokrates_embed/ark", "zokrates_common/ark", "zokrates_interpreter/ark", "zokrates_codegen/ark", "zokrates_analysis/ark"] bellman = ["zokrates_ast/bellman", "zokrates_embed/bellman", "zokrates_common/bellman", "zokrates_interpreter/bellman", "zokrates_codegen/bellman", "zokrates_analysis/bellman"] +bellperson = ["zokrates_ast/bellperson", "zokrates_common/bellperson"] [dependencies] log = "0.4" @@ -29,8 +30,3 @@ zokrates_interpreter = { version = "0.1", path = "../zokrates_interpreter", defa zokrates_codegen = { version = "0.1", path = "../zokrates_codegen", default-features = false } zokrates_analysis = { version = "0.1", path = "../zokrates_analysis", default-features = false } zokrates_ast = { version = "0.1", path = "../zokrates_ast", default-features = false } -csv = "1" - -[dev-dependencies] -pretty_assertions = "0.6.1" -zokrates_fs_resolver = { version = "0.5", path = "../zokrates_fs_resolver"} diff --git a/zokrates_core/src/compile.rs b/zokrates_core/src/compile.rs index 0c7583fa2..468c1b68b 100644 --- a/zokrates_core/src/compile.rs +++ b/zokrates_core/src/compile.rs @@ -18,8 +18,8 @@ use zokrates_ast::ir::{self, from_flat::from_flat}; use zokrates_ast::typed::abi::Abi; use zokrates_ast::untyped::{Module, OwnedModuleId, Program}; use zokrates_ast::zir::ZirProgram; -use zokrates_codegen::from_function_and_config; -use zokrates_common::{CompileConfig, Resolver}; +use zokrates_codegen::from_program_and_config; +pub use zokrates_common::{CompileConfig, Resolver}; use zokrates_field::Field; use zokrates_pest_ast as pest; @@ -153,18 +153,12 @@ impl fmt::Display for CompileErrorInner { CompileErrorInner::ParserError(ref e) => write!(f, "\n\t{}", e), CompileErrorInner::MacroError(ref e) => write!(f, "\n\t{}", e), CompileErrorInner::SemanticError(ref e) => { - let location = e - .pos() - .map(|p| format!("{}", p.0)) - .unwrap_or_else(|| "".to_string()); + let location = e.pos().map(|p| format!("{}", p.from)).unwrap_or_default(); write!(f, "{}\n\t{}", location, e.message()) } CompileErrorInner::ReadError(ref e) => write!(f, "\n\t{}", e), CompileErrorInner::ImportError(ref e) => { - let location = e - .pos() - .map(|p| format!("{}", p.0)) - .unwrap_or_else(|| "".to_string()); + let location = e.span().map(|p| format!("{}", p.from)).unwrap_or_default(); write!(f, "{}\n\t{}", location, e.message()) } CompileErrorInner::AnalysisError(ref e) => write!(f, "\n\t{}", e), @@ -189,7 +183,7 @@ pub fn compile<'ast, T: Field, E: Into>( // flatten input program log::debug!("Flatten"); - let program_flattened = from_function_and_config(typed_ast.main, config); + let program_flattened = from_program_and_config(typed_ast, config); // convert to ir log::debug!("Convert to IR"); @@ -327,7 +321,7 @@ mod test { assert!(e.0[0] .value() .to_string() - .contains(&"Cannot resolve import without a resolver")); + .contains("Cannot resolve import without a resolver")); } #[test] @@ -448,15 +442,15 @@ struct Bar { field a; } vec![], vec![ConcreteStructMember { id: "b".into(), - ty: box ConcreteType::Struct(ConcreteStructType::new( + ty: Box::new(ConcreteType::Struct(ConcreteStructType::new( "bar".into(), "Bar".into(), vec![], - vec![ConcreteStructMember { - id: "a".into(), - ty: box ConcreteType::FieldElement - }] - )) + vec![ConcreteStructMember::new( + "a".into(), + ConcreteType::FieldElement + )] + ))) }] )) }], diff --git a/zokrates_core/src/imports.rs b/zokrates_core/src/imports.rs index f7fa95f13..3bc08c5b8 100644 --- a/zokrates_core/src/imports.rs +++ b/zokrates_core/src/imports.rs @@ -13,43 +13,43 @@ use std::path::{Path, PathBuf}; use zokrates_ast::untyped::*; use typed_arena::Arena; -use zokrates_ast::common::FlatEmbed; +use zokrates_ast::common::{FlatEmbed, SourceSpan}; use zokrates_ast::untyped::types::UnresolvedType; use zokrates_common::Resolver; use zokrates_field::Field; #[derive(PartialEq, Eq, Debug)] pub struct Error { - pos: Option<(Position, Position)>, + span: Option, message: String, } impl Error { pub fn new>(message: T) -> Error { Error { - pos: None, + span: None, message: message.into(), } } - pub fn pos(&self) -> &Option<(Position, Position)> { - &self.pos + pub fn span(&self) -> &Option { + &self.span } pub fn message(&self) -> &str { &self.message } - fn with_pos(self, pos: Option<(Position, Position)>) -> Error { - Error { pos, ..self } + fn with_span(self, span: Option) -> Error { + Error { span, ..self } } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let location = self - .pos - .map(|p| format!("{}", p.0)) + .span + .map(|p| format!("{}", p.from)) .unwrap_or_else(|| "?".to_string()); write!(f, "{}\n\t{}", location, self.message) } @@ -58,7 +58,7 @@ impl fmt::Display for Error { impl From for Error { fn from(error: io::Error) -> Self { Error { - pos: None, + span: None, message: format!("I/O Error: {}", error), } } @@ -95,7 +95,7 @@ impl Importer { modules: &mut HashMap>, arena: &'ast Arena, ) -> Result, CompileErrors> { - let pos = import.pos(); + let span = import.span().in_module(location); let module_id = import.value.source; let symbol = import.value.id; @@ -111,7 +111,7 @@ impl Importer { Bn128Field::name(), T::name() )) - .with_pos(Some(pos)), + .with_span(Some(span)), ) .in_file(location) .into()); @@ -132,7 +132,7 @@ impl Importer { Bw6_761Field::name(), T::name() )) - .with_pos(Some(pos)), + .with_span(Some(span)), ) .in_file(location) .into()); @@ -195,12 +195,12 @@ impl Importer { expression: Expression::U32Constant(T::get_required_bits() as u32) .into(), } - .start_end(pos.0, pos.1), + .start_end(span.from, span.to), )), }, s => { return Err(CompileErrorInner::ImportError( - Error::new(format!("Embed {} not found", s)).with_pos(Some(pos)), + Error::new(format!("Embed {} not found", s)).with_span(Some(span)), ) .in_file(location) .into()); @@ -245,16 +245,16 @@ impl Importer { id: alias, symbol: Symbol::There( SymbolImport::with_id_in_module(symbol.id, new_location) - .start_end(pos.0, pos.1), + .start_end(span.from, span.to), ), } } Err(err) => { - return Err( - CompileErrorInner::ImportError(err.into().with_pos(Some(pos))) - .in_file(location) - .into(), - ); + return Err(CompileErrorInner::ImportError( + err.into().with_span(Some(span)), + ) + .in_file(location) + .into()); } }, None => { @@ -267,6 +267,6 @@ impl Importer { }, }; - Ok(symbol_declaration.start_end(pos.0, pos.1)) + Ok(symbol_declaration.start_end(span.from, span.to)) } } diff --git a/zokrates_core/src/lib.rs b/zokrates_core/src/lib.rs index 51de21db8..874b996ac 100644 --- a/zokrates_core/src/lib.rs +++ b/zokrates_core/src/lib.rs @@ -1,5 +1,3 @@ -#![feature(box_patterns, box_syntax)] - pub mod compile; pub mod imports; mod macros; diff --git a/zokrates_core/src/optimizer/directive.rs b/zokrates_core/src/optimizer/directive.rs index 4d140637a..dd8159013 100644 --- a/zokrates_core/src/optimizer/directive.rs +++ b/zokrates_core/src/optimizer/directive.rs @@ -28,24 +28,34 @@ impl<'ast, T: Field> Folder<'ast, T> for DirectiveOptimizer<'ast, T> { *self.substitution.get(&v).unwrap_or(&v) } - fn fold_statement(&mut self, s: Statement<'ast, T>) -> Vec> { - match s { - Statement::Directive(d) => { - let d = self.fold_directive(d); + fn fold_directive_statement( + &mut self, + d: DirectiveStatement<'ast, T>, + ) -> Vec> { + let d = DirectiveStatement { + inputs: d + .inputs + .into_iter() + .map(|e| self.fold_quadratic_combination(e)) + .collect(), + outputs: d + .outputs + .into_iter() + .map(|o| self.fold_variable(o)) + .collect(), + ..d + }; - match self.calls.entry((d.solver.clone(), d.inputs.clone())) { - Entry::Vacant(e) => { - e.insert(d.outputs.clone()); - vec![Statement::Directive(d)] - } - Entry::Occupied(e) => { - self.substitution - .extend(d.outputs.into_iter().zip(e.get().iter().cloned())); - vec![] - } - } + match self.calls.entry((d.solver.clone(), d.inputs.clone())) { + Entry::Vacant(e) => { + e.insert(d.outputs.clone()); + vec![Statement::Directive(d)] + } + Entry::Occupied(e) => { + self.substitution + .extend(d.outputs.into_iter().zip(e.get().iter().cloned())); + vec![] } - s => fold_statement(self, s), } } } diff --git a/zokrates_core/src/optimizer/duplicate.rs b/zokrates_core/src/optimizer/duplicate.rs index 664cfc2db..9f12e1e04 100644 --- a/zokrates_core/src/optimizer/duplicate.rs +++ b/zokrates_core/src/optimizer/duplicate.rs @@ -39,14 +39,22 @@ impl<'ast, T: Field> Folder<'ast, T> for DuplicateOptimizer { } fn fold_statement(&mut self, s: Statement<'ast, T>) -> Vec> { - let hashed = hash(&s); - let result = match self.seen.get(&hashed) { - Some(_) => vec![], - None => vec![s], - }; - - self.seen.insert(hashed); - result + match s { + Statement::Block(s) => s + .inner + .into_iter() + .flat_map(|s| self.fold_statement(s)) + .collect(), + s => { + let hashed = hash(&s); + let result = match self.seen.get(&hashed) { + Some(_) => vec![], + None => vec![s], + }; + self.seen.insert(hashed); + result + } + } } } @@ -59,24 +67,28 @@ mod tests { #[test] fn identity() { let p: Prog = Prog { + module_map: Default::default(), statements: vec![ Statement::constraint( - QuadComb::from_linear_combinations( + QuadComb::new( LinComb::summand(3, Variable::new(3)), LinComb::summand(3, Variable::new(3)), ), LinComb::one(), + None, ), Statement::constraint( - QuadComb::from_linear_combinations( + QuadComb::new( LinComb::summand(3, Variable::new(42)), LinComb::summand(3, Variable::new(3)), ), LinComb::zero(), + None, ), ], return_count: 0, arguments: vec![], + solvers: vec![], }; let expected = p.clone(); @@ -90,44 +102,51 @@ mod tests { #[test] fn remove_duplicates() { let constraint = Statement::constraint( - QuadComb::from_linear_combinations( + QuadComb::new( LinComb::summand(3, Variable::new(3)), LinComb::summand(3, Variable::new(3)), ), LinComb::one(), + None, ); let p: Prog = Prog { + module_map: Default::default(), statements: vec![ constraint.clone(), constraint.clone(), Statement::constraint( - QuadComb::from_linear_combinations( + QuadComb::new( LinComb::summand(3, Variable::new(42)), LinComb::summand(3, Variable::new(3)), ), LinComb::zero(), + None, ), constraint.clone(), constraint.clone(), ], return_count: 0, arguments: vec![], + solvers: vec![], }; let expected = Prog { + module_map: Default::default(), statements: vec![ constraint, Statement::constraint( - QuadComb::from_linear_combinations( + QuadComb::new( LinComb::summand(3, Variable::new(42)), LinComb::summand(3, Variable::new(3)), ), LinComb::zero(), + None, ), ], return_count: 0, arguments: vec![], + solvers: vec![], }; assert_eq!( diff --git a/zokrates_core/src/optimizer/mod.rs b/zokrates_core/src/optimizer/mod.rs index 1f94740a9..08a6c1b7d 100644 --- a/zokrates_core/src/optimizer/mod.rs +++ b/zokrates_core/src/optimizer/mod.rs @@ -54,6 +54,8 @@ pub fn optimize<'ast, T: Field, I: IntoIterator>>( .flat_map(move |s| directive_optimizer.fold_statement(s)) .flat_map(move |s| duplicate_optimizer.fold_statement(s)), return_count: p.return_count, + module_map: p.module_map, + solvers: p.solvers, }; log::debug!("Done"); diff --git a/zokrates_core/src/optimizer/redefinition.rs b/zokrates_core/src/optimizer/redefinition.rs index b0877fd02..55880465a 100644 --- a/zokrates_core/src/optimizer/redefinition.rs +++ b/zokrates_core/src/optimizer/redefinition.rs @@ -37,8 +37,9 @@ // - otherwise return `c_0` use std::collections::{HashMap, HashSet}; +use zokrates_ast::common::WithSpan; use zokrates_ast::flat::Variable; -use zokrates_ast::ir::folder::{fold_statement, Folder}; +use zokrates_ast::ir::folder::{fold_statement_cases, Folder}; use zokrates_ast::ir::LinComb; use zokrates_ast::ir::*; use zokrates_field::Field; @@ -62,29 +63,28 @@ impl RedefinitionOptimizer { .into_iter() .chain(p.arguments.iter().map(|p| p.id)) .chain(p.returns()) - .into_iter() .collect(), } } - fn fold_statement<'ast>( + fn fold_statement_cases<'ast>( &mut self, s: Statement<'ast, T>, aggressive: bool, ) -> Vec> { match s { - Statement::Constraint(quad, lin, message) => { - let quad = self.fold_quadratic_combination(quad); - let lin = self.fold_linear_combination(lin); + Statement::Constraint(s) => { + let quad = self.fold_quadratic_combination(s.quad); + let lin = self.fold_linear_combination(s.lin); if lin.is_zero() { - return vec![Statement::Constraint(quad, lin, message)]; + return vec![Statement::constraint(quad, lin, s.error)]; } - let (constraint, to_insert, to_ignore) = match self.ignore.contains(&lin.0[0].0) - || self.substitution.contains_key(&lin.0[0].0) + let (constraint, to_insert, to_ignore) = match self.ignore.contains(&lin.value[0].0) + || self.substitution.contains_key(&lin.value[0].0) { - true => (Some(Statement::Constraint(quad, lin, message)), None, None), + true => (Some(Statement::constraint(quad, lin, s.error)), None, None), false => match lin.try_summand() { // if the right side is a single variable Ok((variable, coefficient)) => match quad.try_linear() { @@ -92,16 +92,16 @@ impl RedefinitionOptimizer { Ok(l) => (None, Some((variable, l / &coefficient)), None), // if the left side isn't linear Err(quad) => ( - Some(Statement::Constraint( + Some(Statement::constraint( quad, LinComb::summand(coefficient, variable), - message, + s.error, )), None, Some(variable), ), }, - Err(l) => (Some(Statement::Constraint(quad, l, message)), None, None), + Err(l) => (Some(Statement::constraint(quad, l, s.error)), None, None), }, }; @@ -122,7 +122,19 @@ impl RedefinitionOptimizer { } } Statement::Directive(d) => { - let d = self.fold_directive(d); + let d = DirectiveStatement { + inputs: d + .inputs + .into_iter() + .map(|e| self.fold_quadratic_combination(e)) + .collect(), + outputs: d + .outputs + .into_iter() + .map(|o| self.fold_variable(o)) + .collect(), + ..d + }; // check if the inputs are constants, ie reduce to the form `coeff * ~one` let inputs: Vec<_> = d @@ -146,7 +158,7 @@ impl RedefinitionOptimizer { // unwrap inputs to their constant value let inputs: Vec<_> = inputs.into_iter().map(|i| i.unwrap()).collect(); // run the solver - let outputs = Interpreter::execute_solver(&d.solver, &inputs).unwrap(); + let outputs = Interpreter::execute_solver(&d.solver, &inputs, &[]).unwrap(); assert_eq!(outputs.len(), d.outputs.len()); // insert the results in the substitution @@ -171,24 +183,30 @@ impl RedefinitionOptimizer { self.ignore.insert(o); } } - vec![Statement::Directive(Directive { inputs, ..d })] + vec![Statement::directive(d.outputs, d.solver, inputs)] } } } - s => fold_statement(self, s), + s => fold_statement_cases(self, s), } } } impl<'ast, T: Field> Folder<'ast, T> for RedefinitionOptimizer { - fn fold_statement(&mut self, s: Statement<'ast, T>) -> Vec> { + fn fold_statement_cases(&mut self, s: Statement<'ast, T>) -> Vec> { match s { Statement::Block(statements) => { #[allow(clippy::needless_collect)] // optimize aggressively and clean up in a second pass (we need to collect here) let statements: Vec<_> = statements + .inner .into_iter() - .flat_map(|s| self.fold_statement(s, true)) + .flat_map(|s| { + let span = s.get_span(); + self.fold_statement_cases(s, true) + .into_iter() + .map(move |s| s.span(span)) + }) .collect(); // clean up @@ -203,22 +221,23 @@ impl<'ast, T: Field> Folder<'ast, T> for RedefinitionOptimizer { }) .collect(); - vec![Statement::Block(statements)] + vec![Statement::block(statements)] } - s => self.fold_statement(s, false), + s => self.fold_statement_cases(s, false), } } fn fold_linear_combination(&mut self, lc: LinComb) -> LinComb { match lc - .0 + .value .iter() .any(|(variable, _)| self.substitution.get(variable).is_some()) { true => // for each summand, check if it is equal to a linear term in our substitution, otherwise keep it as is { - lc.0.into_iter() + lc.value + .into_iter() .map(|(variable, coefficient)| { self.substitution .get(&variable) @@ -250,18 +269,22 @@ mod tests { let out = Variable::public(0); let p: Prog = Prog { + module_map: Default::default(), arguments: vec![x], statements: vec![ Statement::definition(y, x.id), Statement::definition(out, y), ], return_count: 1, + solvers: vec![], }; let optimized: Prog = Prog { + module_map: Default::default(), arguments: vec![x], statements: vec![Statement::definition(out, x.id)], return_count: 1, + solvers: vec![], }; let mut optimizer = RedefinitionOptimizer::init(&p); @@ -277,9 +300,11 @@ mod tests { let x = Parameter::public(Variable::new(0)); let p: Prog = Prog { + module_map: Default::default(), arguments: vec![x], statements: vec![Statement::definition(one, x.id)], return_count: 1, + solvers: vec![], }; let optimized = p.clone(); @@ -308,23 +333,27 @@ mod tests { let out = Variable::public(0); let p: Prog = Prog { + module_map: Default::default(), arguments: vec![x], statements: vec![ Statement::definition(y, x.id), Statement::definition(z, y), - Statement::constraint(z, y), + Statement::constraint(z, y, None), Statement::definition(out, z), ], return_count: 1, + solvers: vec![], }; let optimized: Prog = Prog { + module_map: Default::default(), arguments: vec![x], statements: vec![ - Statement::constraint(x.id, x.id), + Statement::constraint(x.id, x.id, None), Statement::definition(out, x.id), ], return_count: 1, + solvers: vec![], }; let mut optimizer = RedefinitionOptimizer::init(&p); @@ -355,6 +384,7 @@ mod tests { let out_0 = Variable::public(1); let p: Prog = Prog { + module_map: Default::default(), arguments: vec![x], statements: vec![ Statement::definition(y, x.id), @@ -365,15 +395,18 @@ mod tests { Statement::definition(out_1, w), ], return_count: 2, + solvers: vec![], }; let optimized: Prog = Prog { + module_map: Default::default(), arguments: vec![x], statements: vec![ Statement::definition(out_0, x.id), Statement::definition(out_1, Bn128Field::from(1)), ], return_count: 2, + solvers: vec![], }; let mut optimizer = RedefinitionOptimizer::init(&p); @@ -404,6 +437,7 @@ mod tests { let r = Variable::public(0); let p: Prog = Prog { + module_map: Default::default(), arguments: vec![x, y], statements: vec![ Statement::definition(a, LinComb::from(x.id) + LinComb::from(y.id)), @@ -418,18 +452,22 @@ mod tests { Statement::constraint( LinComb::summand(2, c), LinComb::summand(6, x.id) + LinComb::summand(6, y.id), + None, ), Statement::definition(r, LinComb::from(a) + LinComb::from(b) + LinComb::from(c)), ], return_count: 1, + solvers: vec![], }; let expected: Prog = Prog { + module_map: Default::default(), arguments: vec![x, y], statements: vec![ Statement::constraint( LinComb::summand(6, x.id) + LinComb::summand(6, y.id), LinComb::summand(6, x.id) + LinComb::summand(6, y.id), + None, ), Statement::definition( r, @@ -442,6 +480,7 @@ mod tests { ), ], return_count: 1, + solvers: vec![], }; let mut optimizer = RedefinitionOptimizer::init(&p); @@ -470,15 +509,14 @@ mod tests { let z = Variable::new(2); let p: Prog = Prog { + module_map: Default::default(), arguments: vec![x, y], statements: vec![ - Statement::definition( - z, - QuadComb::from_linear_combinations(LinComb::from(x.id), LinComb::from(y.id)), - ), + Statement::definition(z, QuadComb::new(LinComb::from(x.id), LinComb::from(y.id))), Statement::definition(z, LinComb::from(x.id)), ], return_count: 0, + solvers: vec![], }; let optimized = p.clone(); @@ -501,12 +539,14 @@ mod tests { let x = Parameter::public(Variable::new(0)); let p: Prog = Prog { + module_map: Default::default(), arguments: vec![x], statements: vec![ - Statement::constraint(x.id, Bn128Field::from(1)), - Statement::constraint(x.id, Bn128Field::from(2)), + Statement::constraint(x.id, Bn128Field::from(1), None), + Statement::constraint(x.id, Bn128Field::from(2), None), ], return_count: 1, + solvers: vec![], }; let optimized = p.clone(); diff --git a/zokrates_core/src/optimizer/tautology.rs b/zokrates_core/src/optimizer/tautology.rs index 855efa11d..d33ddeeda 100644 --- a/zokrates_core/src/optimizer/tautology.rs +++ b/zokrates_core/src/optimizer/tautology.rs @@ -5,7 +5,6 @@ // // This makes the assumption that ~one has value 1, as should be guaranteed by the verifier -use zokrates_ast::ir::folder::fold_statement; use zokrates_ast::ir::folder::Folder; use zokrates_ast::ir::*; use zokrates_field::Field; @@ -14,19 +13,16 @@ use zokrates_field::Field; pub struct TautologyOptimizer; impl<'ast, T: Field> Folder<'ast, T> for TautologyOptimizer { - fn fold_statement(&mut self, s: Statement<'ast, T>) -> Vec> { - match s { - Statement::Constraint(quad, lin, message) => match quad.try_linear() { - Ok(l) => { - if l == lin { - vec![] - } else { - vec![Statement::Constraint(l.into(), lin, message)] - } + fn fold_constraint_statement(&mut self, s: ConstraintStatement) -> Vec> { + match s.quad.try_linear() { + Ok(l) => { + if l == s.lin { + vec![] + } else { + vec![Statement::constraint(l, s.lin, s.error)] } - Err(quad) => vec![Statement::Constraint(quad, lin, message)], - }, - _ => fold_statement(self, s), + } + Err(quad) => vec![Statement::constraint(quad, s.lin, s.error)], } } } diff --git a/zokrates_core/src/semantics.rs b/zokrates_core/src/semantics.rs index ad584e717..df226c3dd 100644 --- a/zokrates_core/src/semantics.rs +++ b/zokrates_core/src/semantics.rs @@ -8,7 +8,8 @@ use num_bigint::BigUint; use std::collections::{btree_map::Entry, BTreeMap, BTreeSet, HashMap, HashSet}; use std::fmt; use std::path::PathBuf; -use zokrates_ast::common::{FormatString, SourceMetadata}; +use zokrates_ast::common::expressions::ValueExpression; +use zokrates_ast::common::{FormatString, ModuleMap, SourceMetadata, SourceSpan, WithSpan}; use zokrates_ast::typed::types::{GGenericsAssignment, GTupleType, GenericsAssignment}; use zokrates_ast::typed::SourceIdentifier; use zokrates_ast::typed::*; @@ -17,6 +18,8 @@ use zokrates_ast::untyped::Identifier; use zokrates_ast::untyped::*; use zokrates_field::Field; +use std::ops::*; + use zokrates_ast::untyped::types::{UnresolvedSignature, UnresolvedType, UserTypeId}; use std::hash::Hash; @@ -29,7 +32,7 @@ use zokrates_ast::typed::types::{ #[derive(PartialEq, Eq, Debug)] pub struct ErrorInner { - pos: Option<(Position, Position)>, + span: Option, message: String, } @@ -40,8 +43,8 @@ pub struct Error { } impl ErrorInner { - pub fn pos(&self) -> &Option<(Position, Position)> { - &self.pos + pub fn pos(&self) -> &Option { + &self.span } pub fn message(&self) -> &str { @@ -369,6 +372,7 @@ impl<'ast, T: Field> Checker<'ast, T> { Ok(TypedProgram { main: program.main, + module_map: ModuleMap::new(state.typed_modules.keys().cloned()), modules: state.typed_modules, }) } @@ -379,7 +383,7 @@ impl<'ast, T: Field> Checker<'ast, T> { module_id: &ModuleId, state: &State<'ast, T>, ) -> Result, Vec> { - let pos = ty.pos(); + let span = ty.span().in_module(module_id); let ty = ty.value; let mut errors = vec![]; @@ -395,7 +399,7 @@ impl<'ast, T: Field> Checker<'ast, T> { .is_some() { errors.push(ErrorInner { - pos: Some(g.pos()), + span: Some(g.span().in_module(module_id)), message: format!( "Generic parameter {p} conflicts with constant symbol {p}", p = g.value @@ -410,7 +414,7 @@ impl<'ast, T: Field> Checker<'ast, T> { } false => { errors.push(ErrorInner { - pos: Some(g.pos()), + span: Some(g.span().in_module(module_id)), message: format!("Generic parameter {} is already declared", g.value), }); } @@ -432,7 +436,7 @@ impl<'ast, T: Field> Checker<'ast, T> { for declared_generic in generics_map.keys() { if !used_generics.contains(declared_generic) { errors.push(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!("Generic parameter {} must be used", declared_generic), }); } @@ -458,7 +462,7 @@ impl<'ast, T: Field> Checker<'ast, T> { module_id: &ModuleId, state: &State<'ast, T>, ) -> Result, ErrorInner> { - let pos = c.pos(); + let span = c.span().in_module(module_id); let ty = self.check_declaration_type( c.value.ty.clone(), @@ -492,7 +496,7 @@ impl<'ast, T: Field> Checker<'ast, T> { DeclarationType::Int => Err(checked_expr), // Integers cannot be assigned } .map_err(|e| ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Expression `{}` of type `{}` cannot be assigned to constant `{}` of type `{}`", e, @@ -511,7 +515,7 @@ impl<'ast, T: Field> Checker<'ast, T> { module_id: &ModuleId, state: &State<'ast, T>, ) -> Result, Vec> { - let pos = s.pos(); + let span = s.span().in_module(module_id); let s = s.value; let mut errors = vec![]; @@ -529,7 +533,7 @@ impl<'ast, T: Field> Checker<'ast, T> { .is_some() { errors.push(ErrorInner { - pos: Some(g.pos()), + span: Some(g.span().in_module(module_id)), message: format!( "Generic parameter {p} conflicts with constant symbol {p}", p = g.value @@ -544,7 +548,7 @@ impl<'ast, T: Field> Checker<'ast, T> { } false => { errors.push(ErrorInner { - pos: Some(g.pos()), + span: Some(g.span().in_module(module_id)), message: format!("Generic parameter {} is already declared", g.value), }); } @@ -569,7 +573,7 @@ impl<'ast, T: Field> Checker<'ast, T> { Ok(f) => match fields_set.insert(f.0.clone()) { true => fields.push(f), false => errors.push(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!("Duplicate key {} in struct definition", f.0,), }), }, @@ -583,7 +587,7 @@ impl<'ast, T: Field> Checker<'ast, T> { for declared_generic in generics_map.keys() { if !used_generics.contains(declared_generic) { errors.push(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!("Generic parameter {} must be used", declared_generic), }); } @@ -614,7 +618,7 @@ impl<'ast, T: Field> Checker<'ast, T> { ) -> Result<(), Vec> { let mut errors: Vec = vec![]; - let pos = declaration.pos(); + let span = declaration.span().in_module(module_id); let declaration = declaration.value; match declaration.symbol.clone() { @@ -629,7 +633,7 @@ impl<'ast, T: Field> Checker<'ast, T> { match symbol_unifier.insert_type(declaration.id) { false => errors.push( ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "{} conflicts with another symbol", declaration.id @@ -671,7 +675,7 @@ impl<'ast, T: Field> Checker<'ast, T> { match symbol_unifier.insert_constant(declaration.id) { false => errors.push( ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "{} conflicts with another symbol", declaration.id @@ -722,7 +726,7 @@ impl<'ast, T: Field> Checker<'ast, T> { match symbol_unifier.insert_type(declaration.id) { false => errors.push( ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "{} conflicts with another symbol", declaration.id, @@ -753,7 +757,7 @@ impl<'ast, T: Field> Checker<'ast, T> { { false => errors.push( ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "{} conflicts with another symbol", declaration.id @@ -789,7 +793,7 @@ impl<'ast, T: Field> Checker<'ast, T> { } } Symbol::There(import) => { - let pos = import.pos(); + let span = import.span().in_module(module_id); let import = import.value; match Checker::default().check_module(&import.module_id, state) { @@ -800,7 +804,6 @@ impl<'ast, T: Field> Checker<'ast, T> { .get(&import.module_id) .unwrap() .functions_iter() - .into_iter() .filter(|d| d.key.id == import.symbol_id) .map(|d| DeclarationFunctionKey { module: import.module_id.to_path_buf(), @@ -850,7 +853,7 @@ impl<'ast, T: Field> Checker<'ast, T> { errors.push(Error { module_id: module_id.to_path_buf(), inner: ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "{} conflicts with another symbol", declaration.id, @@ -871,7 +874,7 @@ impl<'ast, T: Field> Checker<'ast, T> { errors.push(Error { module_id: module_id.to_path_buf(), inner: ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "{} conflicts with another symbol", declaration.id, @@ -909,7 +912,7 @@ impl<'ast, T: Field> Checker<'ast, T> { } (0, None, None) => { errors.push(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Could not find symbol {} in module {}", import.symbol_id, import.module_id.display(), @@ -923,7 +926,7 @@ impl<'ast, T: Field> Checker<'ast, T> { match symbol_unifier.insert_function(declaration.id, candidate.signature.clone()) { false => { errors.push(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "{} conflicts with another symbol", declaration.id, @@ -957,7 +960,7 @@ impl<'ast, T: Field> Checker<'ast, T> { false => { errors.push( ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "{} conflicts with another symbol", declaration.id @@ -988,7 +991,7 @@ impl<'ast, T: Field> Checker<'ast, T> { _ => unreachable!(), }; - // return if any errors occured + // return if any errors occurred if !errors.is_empty() { return Err(errors); } @@ -1035,7 +1038,7 @@ impl<'ast, T: Field> Checker<'ast, T> { // insert into typed_modules if we checked anything if let Some(typed_module) = to_insert { - // there should be no checked module at that key just yet, if there is we have a colision or we checked something twice + // there should be no checked module at that key just yet, if there is we have a collision or we checked something twice assert!(state .typed_modules .insert(module_id.to_path_buf(), typed_module) @@ -1048,17 +1051,16 @@ impl<'ast, T: Field> Checker<'ast, T> { fn check_single_main(module: &TypedModule) -> Result<(), ErrorInner> { match module .functions_iter() - .into_iter() .filter(|d| d.key.id == "main") .count() { 1 => Ok(()), 0 => Err(ErrorInner { - pos: None, + span: None, message: "No main function found".into(), }), n => Err(ErrorInner { - pos: None, + span: None, message: format!("Only one main function allowed, found {}", n), }), } @@ -1070,14 +1072,14 @@ impl<'ast, T: Field> Checker<'ast, T> { module_id: &ModuleId, types: &TypeMap<'ast, T>, ) -> Result, Vec> { - let pos = var.pos(); + let span = var.span().in_module(module_id); let var = self.check_variable(var, module_id, types)?; match var.get_type() { Type::Uint(UBitwidth::B32) => Ok(()), t => Err(vec![ErrorInner { - pos: Some(pos), + span: Some(span), message: format!("Variable in for loop cannot have type {}", t), }]), }?; @@ -1106,7 +1108,7 @@ impl<'ast, T: Field> Checker<'ast, T> { self.enter_scope(); - let pos = funct_node.pos(); + let span = funct_node.span().in_module(module_id); let mut errors = vec![]; let funct = funct_node.value; @@ -1142,14 +1144,14 @@ impl<'ast, T: Field> Checker<'ast, T> { } for (arg, decl_ty) in funct.arguments.into_iter().zip(s.inputs.iter()) { - let pos = arg.pos(); + let span = arg.span().in_module(module_id); let arg = arg.value; // parameters defined on a non-entrypoint function should not have visibility modifiers if (state.main_id != module_id || id != "main") && arg.is_private.is_some() { errors.push(ErrorInner { - pos: Some(pos), + span: Some(span), message: "Visibility modifiers on arguments are only allowed on the entrypoint function" .into(), @@ -1159,18 +1161,17 @@ impl<'ast, T: Field> Checker<'ast, T> { let decl_v = DeclarationVariable::new( self.id_in_this_scope(arg.id.value.id), decl_ty.clone(), - arg.id.value.is_mutable, ); let is_mutable = arg.id.value.is_mutable; - let ty = specialize_declaration_type(decl_v.clone()._type, &generics).unwrap(); + let ty = specialize_declaration_type(decl_v.clone().ty, &generics).unwrap(); assert_eq!(self.scope.level, 1); let id = arg.id.value.id; let info = IdentifierInfo { - id: decl_v.id.id.clone(), + id: decl_v.id.id.id.clone(), ty, is_mutable, }; @@ -1178,27 +1179,27 @@ impl<'ast, T: Field> Checker<'ast, T> { false => {} true => { errors.push(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!("Duplicate name in function definition: `{}` was previously declared as an argument, a generic parameter or a constant", arg.id.value.id) }); } }; - arguments_checked.push(DeclarationParameter { - id: decl_v, - private: arg.is_private.unwrap_or(false), - }); + arguments_checked.push( + DeclarationParameter::new(decl_v, arg.is_private.unwrap_or(false)) + .with_span(span), + ); } let mut found_return = false; for stat in funct.statements.into_iter() { - let pos = Some(stat.pos()); + let span = Some(stat.span().in_module(module_id)); if let Statement::Return(..) = stat.value { if found_return { errors.push(ErrorInner { - pos, + span, message: "Expected a single return statement".to_string(), }); } @@ -1217,12 +1218,13 @@ impl<'ast, T: Field> Checker<'ast, T> { } if !found_return { - match (&*s.output).is_empty_tuple() { - true => statements_checked - .push(TypedStatement::Return(TypedExpression::empty_tuple())), + match (*s.output).is_empty_tuple() { + true => statements_checked.push( + TypedStatement::ret(TypedExpression::empty_tuple()).with_span(span), + ), false => { errors.push(ErrorInner { - pos: Some(pos), + span: Some(span), message: "Expected a return statement".to_string(), }); } @@ -1271,7 +1273,7 @@ impl<'ast, T: Field> Checker<'ast, T> { .is_some() { errors.push(ErrorInner { - pos: Some(g.pos()), + span: Some(g.span().in_module(module_id)), message: format!( "Generic parameter {p} conflicts with constant symbol {p}", p = g.value @@ -1286,7 +1288,7 @@ impl<'ast, T: Field> Checker<'ast, T> { } false => { errors.push(ErrorInner { - pos: Some(g.pos()), + span: Some(g.span().in_module(module_id)), message: format!("Generic parameter {} is already declared", g.value), }); } @@ -1348,7 +1350,7 @@ impl<'ast, T: Field> Checker<'ast, T> { module_id: &ModuleId, types: &TypeMap<'ast, T>, ) -> Result, ErrorInner> { - let pos = ty.pos(); + let span = ty.span().in_module(module_id); let ty = ty.value; match ty { @@ -1364,7 +1366,7 @@ impl<'ast, T: Field> Checker<'ast, T> { TypedExpression::Uint(e) => match e.bitwidth() { UBitwidth::B32 => Ok(e), _ => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Expected array dimension to be a u32 constant, found {} of type {}", e, ty @@ -1374,7 +1376,7 @@ impl<'ast, T: Field> Checker<'ast, T> { TypedExpression::Int(v) => { UExpression::try_from_int(v.clone(), &UBitwidth::B32).map_err(|_| { ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Expected array dimension to be a u32 constant, found {} of type {}", v, ty @@ -1383,7 +1385,7 @@ impl<'ast, T: Field> Checker<'ast, T> { }) } _ => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Expected array dimension to be a u32 constant, found {} of type {}", size, ty @@ -1411,7 +1413,7 @@ impl<'ast, T: Field> Checker<'ast, T> { .get(&id) .cloned() .ok_or_else(|| ErrorInner { - pos: Some(pos), + span: Some(span), message: format!("Undefined type {}", id), })?; @@ -1438,13 +1440,13 @@ impl<'ast, T: Field> Checker<'ast, T> { UExpression::try_from_typed(e, &UBitwidth::B32) .map(|e| (GenericIdentifier::with_name(g).with_index(i), e)) .map_err(|e| ErrorInner { - pos: Some(pos), + span: Some(span), message: format!("Expected u32 expression, but got expression of type {}", e.get_type()), }) }) }, None => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: "Expected u32 constant or identifier, but found `_`. Generic inference is not supported yet." .into(), @@ -1456,7 +1458,7 @@ impl<'ast, T: Field> Checker<'ast, T> { Ok(specialize_declaration_type(declaration_type, &assignment).unwrap()) } false => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Expected {} generic argument{} on type {}, but got {}", generic_identifiers.len(), @@ -1481,7 +1483,7 @@ impl<'ast, T: Field> Checker<'ast, T> { generics_map: &BTreeMap, usize>, used_generics: &mut HashSet>, ) -> Result, ErrorInner> { - let pos = expr.pos(); + let span = expr.span().in_module(module_id); match expr.value { Expression::U32Constant(c) => Ok(DeclarationConstant::from(c)), @@ -1492,7 +1494,7 @@ impl<'ast, T: Field> Checker<'ast, T> { )) } else { Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Expected array dimension to be a u32 constant or an identifier, found {}", Expression::IntConstant(c) @@ -1508,7 +1510,7 @@ impl<'ast, T: Field> Checker<'ast, T> { match ty { DeclarationType::Uint(UBitwidth::B32) => Ok(DeclarationConstant::Constant(CanonicalConstantIdentifier::new(name, module_id.into()))), _ => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Expected array dimension to be a u32 constant or an identifier, found {} of type {}", name, ty @@ -1518,13 +1520,13 @@ impl<'ast, T: Field> Checker<'ast, T> { } (None, Some(index)) => Ok(DeclarationConstant::Generic(GenericIdentifier::with_name(name).with_index(*index))), _ => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!("Undeclared symbol `{}`", name) }) } } e => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Expected array dimension to be a u32 constant or an identifier, found {}", e @@ -1541,7 +1543,7 @@ impl<'ast, T: Field> Checker<'ast, T> { generics_map: &BTreeMap, usize>, used_generics: &mut HashSet>, ) -> Result, ErrorInner> { - let pos = ty.pos(); + let span = ty.span().in_module(module_id); let ty = ty.value; match ty { @@ -1587,7 +1589,7 @@ impl<'ast, T: Field> Checker<'ast, T> { .get(&id) .cloned() .ok_or_else(|| ErrorInner { - pos: Some(pos), + span: Some(span), message: format!("Undefined type {}", id), })?; @@ -1605,7 +1607,7 @@ impl<'ast, T: Field> Checker<'ast, T> { ) .map(Some), None => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: "Expected u32 constant or identifier, but found `_`".into(), }), }) @@ -1639,7 +1641,7 @@ impl<'ast, T: Field> Checker<'ast, T> { Ok(res) } false => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Expected {} generic argument{} on type {}, but got {}", ty.generics.len(), @@ -1660,17 +1662,13 @@ impl<'ast, T: Field> Checker<'ast, T> { types: &TypeMap<'ast, T>, ) -> Result, Vec> { let ty = self - .check_type(v.value._type, module_id, types) + .check_type(v.value.ty, module_id, types) .map_err(|e| vec![e])?; // insert into the scope and ignore whether shadowing happened self.insert_into_scope(v.value.id, ty.clone(), v.value.is_mutable); - Ok(Variable::new( - self.id_in_this_scope(v.value.id), - ty, - v.value.is_mutable, - )) + Ok(Variable::new(self.id_in_this_scope(v.value.id), ty)) } fn check_for_loop( @@ -1678,7 +1676,7 @@ impl<'ast, T: Field> Checker<'ast, T> { var: zokrates_ast::untyped::VariableNode<'ast>, range: (ExpressionNode<'ast>, ExpressionNode<'ast>), statements: Vec>, - pos: (Position, Position), + span: SourceSpan, module_id: &ModuleId, types: &TypeMap<'ast, T>, ) -> Result, Vec> { @@ -1693,7 +1691,7 @@ impl<'ast, T: Field> Checker<'ast, T> { TypedExpression::Uint(from) => match from.bitwidth() { UBitwidth::B32 => Ok(from), bitwidth => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Expected lower loop bound to be of type u32, found {}", Type::::Uint(bitwidth) @@ -1702,7 +1700,7 @@ impl<'ast, T: Field> Checker<'ast, T> { }, TypedExpression::Int(v) => { UExpression::try_from_int(v, &UBitwidth::B32).map_err(|_| ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Expected lower loop bound to be of type u32, found {}", Type::::Int @@ -1710,7 +1708,7 @@ impl<'ast, T: Field> Checker<'ast, T> { }) } from => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Expected lower loop bound to be of type u32, found {}", from.get_type() @@ -1723,7 +1721,7 @@ impl<'ast, T: Field> Checker<'ast, T> { TypedExpression::Uint(to) => match to.bitwidth() { UBitwidth::B32 => Ok(to), bitwidth => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Expected upper loop bound to be of type u32, found {}", Type::::Uint(bitwidth) @@ -1732,7 +1730,7 @@ impl<'ast, T: Field> Checker<'ast, T> { }, TypedExpression::Int(v) => { UExpression::try_from_int(v, &UBitwidth::B32).map_err(|_| ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Expected upper loop bound to be of type u32, found {}", Type::::Int @@ -1740,7 +1738,7 @@ impl<'ast, T: Field> Checker<'ast, T> { }) } to => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Expected upper loop bound to be of type u32, found {}", to.get_type() @@ -1756,7 +1754,7 @@ impl<'ast, T: Field> Checker<'ast, T> { .map(|s| self.check_statement(s, module_id, types)) .collect::, _>>()?; - Ok(TypedStatement::For(var, from, to, checked_statements)) + Ok(TypedStatement::for_(var, from, to, checked_statements).with_span(span)) } // the assignee is already checked to be defined and mutable @@ -1769,9 +1767,9 @@ impl<'ast, T: Field> Checker<'ast, T> { ) -> Result, ErrorInner> { match expr.value { // for function calls, check the rhs with the expected type - Expression::FunctionCall(box fun_id_expression, generics, arguments) => self + Expression::FunctionCall(fun_id_expression, generics, arguments) => self .check_function_call_expression( - fun_id_expression, + *fun_id_expression, generics, arguments, Some(return_type), @@ -1789,45 +1787,71 @@ impl<'ast, T: Field> Checker<'ast, T> { module_id: &ModuleId, types: &TypeMap<'ast, T>, ) -> Result>, ErrorInner> { - let pos = stat.pos(); + let span = stat.span().in_module(module_id); match stat.value { AssemblyStatement::Assignment(assignee, expression, constrained) => { let assignee = self.check_assignee(assignee, module_id, types)?; let e = self.check_expression(expression, module_id, types)?; - - let e = FieldElementExpression::try_from_typed(e).map_err(|e| ErrorInner { - pos: Some(pos), - message: format!( - "Expected right hand side of an assembly assignment to be of type field, found {}", - e.get_type(), - ), + let e = TypedExpression::align_to_type(e, &assignee.get_type()).map_err(|e| { + ErrorInner { + span: Some(span), + message: format!( + "Expected value of type `{}`, found `{}` of type `{}`", + e.1, + e.0, + e.0.get_type() + ), + } })?; match constrained { - true => { - let e = FieldElementExpression::block(vec![], e); - match assignee.get_type() { - Type::FieldElement => Ok(vec![ - TypedAssemblyStatement::Assignment( + true => match assignee.get_type() { + // in case of `lhs <== rhs` we expect lhs and rhs to be of type field + Type::FieldElement => { + let e = FieldElementExpression::try_from_typed(e).map_err(|e| ErrorInner { + span: Some(span), + message: format!( + "Expected right hand side of an assembly constrained assignment to be of type field, found {}", + e.get_type(), + ), + })?; + + let e = FieldElementExpression::block(vec![], e); + Ok(vec![ + TypedAssemblyStatement::assignment( assignee.clone(), e.clone().into(), - ), - TypedAssemblyStatement::Constraint( + ) + .with_span(span), + TypedAssemblyStatement::constraint( assignee.into(), e, - SourceMetadata::new(module_id.display().to_string(), pos.0), - ), - ]), - ty => Err(ErrorInner { - pos: Some(pos), - message: format!("Assignee must be of type field, found {}", ty), - }), + SourceMetadata::new(module_id.display().to_string(), span.from), + ) + .with_span(span), + ]) } - } + ty => Err(ErrorInner { + span: Some(span), + message: format!("Assignee must be of type field, found {}", ty), + }), + }, false => { - let e = FieldElementExpression::block(vec![], e); - Ok(vec![TypedAssemblyStatement::Assignment(assignee, e.into())]) + // we can allow composite types in case of `<--` as no constraints are generated from this type of statement + // a composite type should only consist of field types + match e.get_type().is_composite_of_field() { + true => { + let e = TypedExpression::block(vec![], e); + Ok(vec![ + TypedAssemblyStatement::assignment(assignee, e).with_span(span) + ]) + }, + false => Err(ErrorInner { + span: Some(span), + message: "Assignee must be of type field or a composite type of field elements".to_string(), + }) + } } } } @@ -1836,7 +1860,7 @@ impl<'ast, T: Field> Checker<'ast, T> { let rhs = self.check_expression(rhs, module_id, types)?; let lhs = FieldElementExpression::try_from_typed(lhs).map_err(|e| ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Expected left hand side of a constraint to be of type field, found {}", e.get_type(), @@ -1844,18 +1868,19 @@ impl<'ast, T: Field> Checker<'ast, T> { })?; let rhs = FieldElementExpression::try_from_typed(rhs).map_err(|e| ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Expected right hand side of a constraint to be of type field, found {}", e.get_type(), ), })?; - Ok(vec![TypedAssemblyStatement::Constraint( + Ok(vec![TypedAssemblyStatement::constraint( lhs, rhs, - SourceMetadata::new(module_id.display().to_string(), pos.0), - )]) + SourceMetadata::new(module_id.display().to_string(), span.from), + ) + .with_span(span)]) } } } @@ -1866,7 +1891,7 @@ impl<'ast, T: Field> Checker<'ast, T> { module_id: &ModuleId, types: &TypeMap<'ast, T>, ) -> Result, Vec> { - let pos = stat.pos(); + let span = stat.span().in_module(module_id); match stat.value { Statement::Assembly(statements) => { @@ -1877,7 +1902,9 @@ impl<'ast, T: Field> Checker<'ast, T> { .map_err(|e| vec![e])?, ); } - Ok(TypedStatement::Assembly(checked_statements)) + Ok(TypedStatement::Assembly( + AssemblyBlockStatement::new(checked_statements).with_span(span), + )) } Statement::Log(l, expressions) => { let l = FormatString::from(l); @@ -1893,7 +1920,7 @@ impl<'ast, T: Field> Checker<'ast, T> { for e in &expressions { if let TypedExpression::Int(e) = e { errors.push(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!("Cannot determine type for expression `{}`", e), }); } @@ -1901,7 +1928,7 @@ impl<'ast, T: Field> Checker<'ast, T> { if expressions.len() != l.len() { errors.push(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Wrong argument count in log call: expected {}, got {}", l.len(), @@ -1914,7 +1941,7 @@ impl<'ast, T: Field> Checker<'ast, T> { return Err(errors); } - Ok(TypedStatement::Log(l, expressions)) + Ok(TypedStatement::log(l, expressions).with_span(span)) } Statement::Return(e) => { let mut errors = vec![]; @@ -1925,11 +1952,7 @@ impl<'ast, T: Field> Checker<'ast, T> { let e_checked = e .map(|e| { match e.value { - Expression::FunctionCall( - box fun_id_expression, - generics, - arguments, - ) => { + Expression::FunctionCall(fun_id_expression, generics, arguments) => { let ty = zokrates_ast::typed::types::try_from_g_type( return_type.clone(), ) @@ -1937,7 +1960,7 @@ impl<'ast, T: Field> Checker<'ast, T> { .unwrap(); self.check_function_call_expression( - fun_id_expression, + *fun_id_expression, generics, arguments, ty, @@ -1954,7 +1977,7 @@ impl<'ast, T: Field> Checker<'ast, T> { let res = match TypedExpression::align_to_type(e_checked.clone(), &return_type) .map_err(|e| { vec![ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Expected return value to be of type `{}`, found `{}` of type `{}`", e.1, @@ -1967,7 +1990,7 @@ impl<'ast, T: Field> Checker<'ast, T> { match e.get_type() == return_type { true => {} false => errors.push(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Expected `{}` in return statement, found `{}`", return_type, @@ -1975,11 +1998,11 @@ impl<'ast, T: Field> Checker<'ast, T> { ), }), } - TypedStatement::Return(e) + TypedStatement::ret(e).with_span(span) } Err(err) => { errors.extend(err); - TypedStatement::Return(e_checked) + TypedStatement::ret(e_checked).with_span(span) } }; @@ -1992,7 +2015,7 @@ impl<'ast, T: Field> Checker<'ast, T> { Statement::Definition(var, expr) => { // get the lhs type let var_ty = self - .check_type(var.value._type, module_id, types) + .check_type(var.value.ty, module_id, types) .map_err(|e| vec![e])?; // check the rhs based on the lhs type @@ -2003,11 +2026,7 @@ impl<'ast, T: Field> Checker<'ast, T> { // insert the lhs into the scope and ignore whether shadowing happened self.insert_into_scope(var.value.id, var_ty.clone(), var.value.is_mutable); - let var = Variable::new( - self.id_in_this_scope(var.value.id), - var_ty.clone(), - var.value.is_mutable, - ); + let var = Variable::new(self.id_in_this_scope(var.value.id), var_ty.clone()); match var_ty { Type::FieldElement => FieldElementExpression::try_from_typed(checked_expr) @@ -2032,7 +2051,7 @@ impl<'ast, T: Field> Checker<'ast, T> { Type::Int => Err(checked_expr), // Integers cannot be assigned } .map_err(|e| ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Expression `{}` of type `{}` cannot be assigned to `{}` of type `{}`", e, @@ -2041,7 +2060,7 @@ impl<'ast, T: Field> Checker<'ast, T> { var_ty ), }) - .map(|e| TypedStatement::Definition(var.into(), e.into())) + .map(|e| TypedStatement::definition(var.into(), e).with_span(span)) .map_err(|e| vec![e]) } Statement::Assignment(assignee, expr) => { @@ -2079,7 +2098,7 @@ impl<'ast, T: Field> Checker<'ast, T> { Type::Int => Err(checked_expr), // Integers cannot be assigned } .map_err(|e| ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Expression `{}` of type `{}` cannot be assigned to `{}` of type `{}`", e, @@ -2088,7 +2107,7 @@ impl<'ast, T: Field> Checker<'ast, T> { assignee_ty ), }) - .map(|e| TypedStatement::Definition(assignee, e.into())) + .map(|e| TypedStatement::definition(assignee, e).with_span(span)) .map_err(|e| vec![e]) } Statement::Assertion(e, message) => { @@ -2097,15 +2116,16 @@ impl<'ast, T: Field> Checker<'ast, T> { .map_err(|e| vec![e])?; match e { - TypedExpression::Boolean(e) => Ok(TypedStatement::Assertion( + TypedExpression::Boolean(e) => Ok(TypedStatement::assertion( e, RuntimeError::SourceAssertion( - SourceMetadata::new(module_id.display().to_string(), pos.0) + SourceMetadata::new(module_id.display().to_string(), span.from) .message(message), ), - )), + ) + .with_span(span)), e => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Expected {} to be of type bool, found {}", e, @@ -2118,7 +2138,7 @@ impl<'ast, T: Field> Checker<'ast, T> { Statement::For(var, from, to, statements) => { self.enter_scope(); - let res = self.check_for_loop(var, (from, to), statements, pos, module_id, types); + let res = self.check_for_loop(var, (from, to), statements, span, module_id, types); self.exit_scope(); @@ -2133,33 +2153,32 @@ impl<'ast, T: Field> Checker<'ast, T> { module_id: &ModuleId, types: &TypeMap<'ast, T>, ) -> Result, ErrorInner> { - let pos = assignee.pos(); + let span = assignee.span().in_module(module_id); // check that the assignee is declared match assignee.value { Assignee::Identifier(variable_name) => match self.scope.get(variable_name) { Some(info) => match info.is_mutable { false => Err(ErrorInner { - pos: Some(assignee.pos()), + span: Some(assignee.span().in_module(module_id)), message: format!("Assignment to an immutable variable `{}`", variable_name), }), _ => Ok(TypedAssignee::Identifier(Variable::new( info.id, info.ty.clone(), - info.is_mutable, ))), }, None => Err(ErrorInner { - pos: Some(assignee.pos()), + span: Some(assignee.span().in_module(module_id)), message: format!("Variable `{}` is undeclared", variable_name), }), }, - Assignee::Select(box assignee, box index) => { - let checked_assignee = self.check_assignee(assignee, module_id, types)?; + Assignee::Select(assignee, index) => { + let checked_assignee = self.check_assignee(*assignee, module_id, types)?; let ty = checked_assignee.get_type(); match ty { Type::Array(..) => { - let checked_index = match index { + let checked_index = match *index { RangeOrExpression::Expression(e) => { self.check_expression(e, module_id, types)? } @@ -2172,7 +2191,7 @@ impl<'ast, T: Field> Checker<'ast, T> { let checked_typed_index = UExpression::try_from_typed(checked_index, &UBitwidth::B32).map_err( |e| ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Expected array {} index to have type u32, found {}", checked_assignee, @@ -2181,13 +2200,10 @@ impl<'ast, T: Field> Checker<'ast, T> { }, )?; - Ok(TypedAssignee::Select( - box checked_assignee, - box checked_typed_index, - )) + Ok(TypedAssignee::select(checked_assignee, checked_typed_index)) } ty => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Cannot access element at index {} on {} of type {}", index, checked_assignee, ty, @@ -2195,15 +2211,15 @@ impl<'ast, T: Field> Checker<'ast, T> { }), } } - Assignee::Member(box assignee, box member) => { - let checked_assignee = self.check_assignee(assignee, module_id, types)?; + Assignee::Member(assignee, member) => { + let checked_assignee = self.check_assignee(*assignee, module_id, types)?; let ty = checked_assignee.get_type(); match &ty { - Type::Struct(members) => match members.iter().find(|m| m.id == member) { - Some(_) => Ok(TypedAssignee::Member(box checked_assignee, member.into())), + Type::Struct(members) => match members.iter().find(|m| m.id == *member) { + Some(_) => Ok(TypedAssignee::member(checked_assignee, (*member).into())), None => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "{} {{{}}} doesn't have member {}", ty, @@ -2217,7 +2233,7 @@ impl<'ast, T: Field> Checker<'ast, T> { }), }, ty => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Cannot access field {} on {} of type {}", @@ -2226,15 +2242,15 @@ impl<'ast, T: Field> Checker<'ast, T> { }), } } - Assignee::Element(box assignee, index) => { - let checked_assignee = self.check_assignee(assignee, module_id, types)?; + Assignee::Element(assignee, index) => { + let checked_assignee = self.check_assignee(*assignee, module_id, types)?; let ty = checked_assignee.get_type(); match &ty { Type::Tuple(tuple_ty) => match tuple_ty.elements.get(index as usize) { - Some(_) => Ok(TypedAssignee::Element(box checked_assignee, index)), + Some(_) => Ok(TypedAssignee::element(checked_assignee, index)), None => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Tuple of size {} cannot be accessed at index {}", tuple_ty.elements.len(), @@ -2243,7 +2259,7 @@ impl<'ast, T: Field> Checker<'ast, T> { }), }, ty => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Cannot access element {} on {} of type {}", @@ -2263,7 +2279,7 @@ impl<'ast, T: Field> Checker<'ast, T> { ) -> Result, ErrorInner> { match spread_or_expression { SpreadOrExpression::Spread(s) => { - let pos = s.pos(); + let span = s.span().in_module(module_id); let checked_expression = self.check_expression(s.value.expression, module_id, types)?; @@ -2271,7 +2287,7 @@ impl<'ast, T: Field> Checker<'ast, T> { match checked_expression { TypedExpression::Array(a) => Ok(TypedExpressionOrSpread::Spread(a.into())), e => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Expected spread operator to apply on array, found {}", e.get_type() @@ -2294,11 +2310,11 @@ impl<'ast, T: Field> Checker<'ast, T> { module_id: &ModuleId, types: &TypeMap<'ast, T>, ) -> Result, ErrorInner> { - let pos = function_id.pos(); + let span = function_id.span().in_module(module_id); let fun_id = match function_id.value { Expression::Identifier(id) => Ok(id), e => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Expected function in function call to be an identifier, found `{}`", e @@ -2313,11 +2329,11 @@ impl<'ast, T: Field> Checker<'ast, T> { .into_iter() .map(|g| { g.map(|g| { - let pos = g.pos(); + let span = g.span().in_module(module_id); self.check_expression(g, module_id, types).and_then(|g| { UExpression::try_from_typed(g, &UBitwidth::B32).map_err(|e| { ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Expected {} to be of type u32, found {}", e, @@ -2361,7 +2377,7 @@ impl<'ast, T: Field> Checker<'ast, T> { let signature = f.signature; let arguments_checked = arguments_checked.into_iter().zip(signature.inputs.iter()).map(|(a, t)| TypedExpression::align_to_type(a, t)).collect::, _>>().map_err(|e| ErrorInner { - pos: Some(pos), + span: Some(span), message: format!("Expected function call argument to be of type `{}`, found `{}` of type `{}`", e.1, e.0, e.0.get_type()) })?; @@ -2371,7 +2387,7 @@ impl<'ast, T: Field> Checker<'ast, T> { generics_checked.clone(), arguments_checked.iter().map(|a| a.get_type()).collect() ).map_err(|e| ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Failed to infer value for generic parameter `{}`, try providing an explicit value", e, @@ -2384,7 +2400,7 @@ impl<'ast, T: Field> Checker<'ast, T> { signature: signature.clone(), }; - match output_type { + let res: Result, _> = match output_type { Type::Int => unreachable!(), Type::FieldElement => Ok(FieldElementExpression::function_call( function_key, @@ -2410,23 +2426,25 @@ impl<'ast, T: Field> Checker<'ast, T> { function_key, generics_checked, arguments_checked, - ).annotate(*array_ty.ty, *array_ty.size).into()), + ).annotate(array_ty).into()), Type::Tuple(tuple_ty) => Ok(TupleExpression::function_call( function_key, generics_checked, arguments_checked, ).annotate(tuple_ty).into()), - } + }; + + res.map(|e| e.with_span(span)) } 0 => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Function definition for function {} with signature {} not found.", fun_id, query ), }), n => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!("Ambiguous call to function {}, {} candidates were found. Please be more explicit.", fun_id, n) }), } @@ -2438,11 +2456,11 @@ impl<'ast, T: Field> Checker<'ast, T> { module_id: &ModuleId, types: &TypeMap<'ast, T>, ) -> Result, ErrorInner> { - let pos = expr.pos(); + let span: SourceSpan = expr.span().in_module(module_id); match expr.value { - Expression::IntConstant(v) => Ok(IntExpression::Value(v).into()), - Expression::BooleanConstant(b) => Ok(BooleanExpression::Value(b).into()), + Expression::IntConstant(v) => Ok(IntExpression::value(v).with_span(span).into()), + Expression::BooleanConstant(b) => Ok(BooleanExpression::value(b).with_span(span).into()), Expression::Identifier(name) => { // check that `id` is defined in the scope match self.scope.get(name) { @@ -2457,7 +2475,7 @@ impl<'ast, T: Field> Checker<'ast, T> { Ok(FieldElementExpression::identifier(id.into()).into()) } Type::Array(array_type) => Ok(ArrayExpression::identifier(id.into()) - .annotate(*array_type.ty, *array_type.size) + .annotate(array_type) .into()), Type::Struct(members) => Ok(StructExpression::identifier(id.into()) .annotate(members) @@ -2469,14 +2487,14 @@ impl<'ast, T: Field> Checker<'ast, T> { } } None => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!("Identifier \"{}\" is undefined", name), }), } } - Expression::Add(box e1, box e2) => { - let e1_checked = self.check_expression(e1, module_id, types)?; - let e2_checked = self.check_expression(e2, module_id, types)?; + Expression::Add(e1, e2) => { + let e1_checked = self.check_expression(*e1, module_id, types)?; + let e2_checked = self.check_expression(*e2, module_id, types)?; use self::TypedExpression::*; @@ -2484,14 +2502,15 @@ impl<'ast, T: Field> Checker<'ast, T> { e1_checked, e2_checked, ) .map_err(|(e1, e2)| ErrorInner { - pos: Some(pos), + span: Some(span), message: format!("Cannot apply `+` to {}, {}", e1.get_type(), e2.get_type()), })?; match (e1_checked, e2_checked) { - (Int(e1), Int(e2)) => Ok(IntExpression::Add(box e1, box e2).into()), + (Int(e1), Int(e2)) => Ok(IntExpression::add(e1, e2).into()), (TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => { - Ok(FieldElementExpression::Add(box e1, box e2).into()) + Ok(FieldElementExpression::add(e1, e2) + .into()) } (TypedExpression::Uint(e1), TypedExpression::Uint(e2)) if e1.get_type() == e2.get_type() => @@ -2499,7 +2518,7 @@ impl<'ast, T: Field> Checker<'ast, T> { Ok((e1 + e2).into()) } (t1, t2) => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Cannot apply `+` to {}, {}", @@ -2509,9 +2528,9 @@ impl<'ast, T: Field> Checker<'ast, T> { }), } } - Expression::Sub(box e1, box e2) => { - let e1_checked = self.check_expression(e1, module_id, types)?; - let e2_checked = self.check_expression(e2, module_id, types)?; + Expression::Sub(e1, e2) => { + let e1_checked = self.check_expression(*e1, module_id, types)?; + let e2_checked = self.check_expression(*e2, module_id, types)?; use self::TypedExpression::*; @@ -2519,18 +2538,16 @@ impl<'ast, T: Field> Checker<'ast, T> { e1_checked, e2_checked, ) .map_err(|(e1, e2)| ErrorInner { - pos: Some(pos), + span: Some(span), message: format!("Cannot apply `-` to {}, {}", e1.get_type(), e2.get_type()), })?; match (e1_checked, e2_checked) { - (Int(e1), Int(e2)) => Ok(IntExpression::Sub(box e1, box e2).into()), - (FieldElement(e1), FieldElement(e2)) => { - Ok(FieldElementExpression::Sub(box e1, box e2).into()) - } + (Int(e1), Int(e2)) => Ok(IntExpression::sub(e1, e2).into()), + (FieldElement(e1), FieldElement(e2)) => Ok((e1 - e2).into()), (Uint(e1), Uint(e2)) if e1.get_type() == e2.get_type() => Ok((e1 - e2).into()), (t1, t2) => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Expected only field elements, found {}, {}", @@ -2540,9 +2557,9 @@ impl<'ast, T: Field> Checker<'ast, T> { }), } } - Expression::Mult(box e1, box e2) => { - let e1_checked = self.check_expression(e1, module_id, types)?; - let e2_checked = self.check_expression(e2, module_id, types)?; + Expression::Mult(e1, e2) => { + let e1_checked = self.check_expression(*e1, module_id, types)?; + let e2_checked = self.check_expression(*e2, module_id, types)?; use self::TypedExpression::*; @@ -2550,14 +2567,14 @@ impl<'ast, T: Field> Checker<'ast, T> { e1_checked, e2_checked, ) .map_err(|(e1, e2)| ErrorInner { - pos: Some(pos), + span: Some(span), message: format!("Cannot apply `*` to {}, {}", e1.get_type(), e2.get_type()), })?; match (e1_checked, e2_checked) { - (Int(e1), Int(e2)) => Ok(IntExpression::Mult(box e1, box e2).into()), + (Int(e1), Int(e2)) => Ok(IntExpression::mul(e1, e2).into()), (TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => { - Ok(FieldElementExpression::Mult(box e1, box e2).into()) + Ok((e1 * e2).into()) } (TypedExpression::Uint(e1), TypedExpression::Uint(e2)) if e1.get_type() == e2.get_type() => @@ -2565,7 +2582,7 @@ impl<'ast, T: Field> Checker<'ast, T> { Ok((e1 * e2).into()) } (t1, t2) => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Cannot apply `*` to {}, {}", @@ -2575,9 +2592,9 @@ impl<'ast, T: Field> Checker<'ast, T> { }), } } - Expression::Div(box e1, box e2) => { - let e1_checked = self.check_expression(e1, module_id, types)?; - let e2_checked = self.check_expression(e2, module_id, types)?; + Expression::Div(e1, e2) => { + let e1_checked = self.check_expression(*e1, module_id, types)?; + let e2_checked = self.check_expression(*e2, module_id, types)?; use self::TypedExpression::*; @@ -2585,22 +2602,20 @@ impl<'ast, T: Field> Checker<'ast, T> { e1_checked, e2_checked, ) .map_err(|(e1, e2)| ErrorInner { - pos: Some(pos), + span: Some(span), message: format!("Cannot apply `/` to {}, {}", e1.get_type(), e2.get_type()), })?; match (e1_checked, e2_checked) { - (Int(e1), Int(e2)) => Ok(IntExpression::Div(box e1, box e2).into()), - (FieldElement(e1), FieldElement(e2)) => { - Ok(FieldElementExpression::Div(box e1, box e2).into()) - } + (Int(e1), Int(e2)) => Ok(IntExpression::div(e1, e2).into()), + (FieldElement(e1), FieldElement(e2)) => Ok((e1 / e2).into()), (TypedExpression::Uint(e1), TypedExpression::Uint(e2)) if e1.get_type() == e2.get_type() => { Ok((e1 / e2).into()) } (t1, t2) => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Cannot apply `/` to {}, {}", @@ -2610,15 +2625,15 @@ impl<'ast, T: Field> Checker<'ast, T> { }), } } - Expression::Rem(box e1, box e2) => { - let e1_checked = self.check_expression(e1, module_id, types)?; - let e2_checked = self.check_expression(e2, module_id, types)?; + Expression::Rem(e1, e2) => { + let e1_checked = self.check_expression(*e1, module_id, types)?; + let e2_checked = self.check_expression(*e2, module_id, types)?; let (e1_checked, e2_checked) = TypedExpression::align_without_integers( e1_checked, e2_checked, ) .map_err(|(e1, e2)| ErrorInner { - pos: Some(pos), + span: Some(span), message: format!("Cannot apply `%` to {}, {}", e1.get_type(), e2.get_type()), })?; @@ -2629,7 +2644,7 @@ impl<'ast, T: Field> Checker<'ast, T> { Ok((e1 % e2).into()) } (t1, t2) => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Cannot apply `%` to {}, {}", @@ -2639,9 +2654,9 @@ impl<'ast, T: Field> Checker<'ast, T> { }), } } - Expression::Pow(box e1, box e2) => { - let e1_checked = self.check_expression(e1, module_id, types)?; - let e2_checked = self.check_expression(e2, module_id, types)?; + Expression::Pow(e1, e2) => { + let e1_checked = self.check_expression(*e1, module_id, types)?; + let e2_checked = self.check_expression(*e2, module_id, types)?; let e1_checked = match FieldElementExpression::try_from_typed(e1_checked) { Ok(e) => e.into(), @@ -2654,10 +2669,10 @@ impl<'ast, T: Field> Checker<'ast, T> { match (e1_checked, e2_checked) { (TypedExpression::FieldElement(e1), TypedExpression::Uint(e2)) => Ok( - TypedExpression::FieldElement(FieldElementExpression::Pow(box e1, box e2)), + TypedExpression::FieldElement(FieldElementExpression::pow(e1, e2)), ), (t1, t2) => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Expected `field` and `u32`, found {}, {}", @@ -2667,17 +2682,17 @@ impl<'ast, T: Field> Checker<'ast, T> { }), } } - Expression::Neg(box e) => { - let e = self.check_expression(e, module_id, types)?; + Expression::Neg(e) => { + let e = self.check_expression(*e, module_id, types)?; match e { - TypedExpression::Int(e) => Ok(IntExpression::Neg(box e).into()), + TypedExpression::Int(e) => Ok(IntExpression::neg(e).into()), TypedExpression::FieldElement(e) => { - Ok(FieldElementExpression::Neg(box e).into()) + Ok(FieldElementExpression::neg(e).into()) } TypedExpression::Uint(e) => Ok((-e).into()), e => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Unary operator `-` cannot be applied to {} of type {}", e, @@ -2686,17 +2701,17 @@ impl<'ast, T: Field> Checker<'ast, T> { }), } } - Expression::Pos(box e) => { - let e = self.check_expression(e, module_id, types)?; + Expression::Pos(e) => { + let e = self.check_expression(*e, module_id, types)?; match e { - TypedExpression::Int(e) => Ok(IntExpression::Pos(box e).into()), + TypedExpression::Int(e) => Ok(IntExpression::pos(e).into()), TypedExpression::FieldElement(e) => { - Ok(FieldElementExpression::Pos(box e).into()) + Ok(FieldElementExpression::pos(e).into()) } TypedExpression::Uint(e) => Ok(UExpression::pos(e).into()), e => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Unary operator `+` cannot be applied to {} of type {}", e, @@ -2705,7 +2720,7 @@ impl<'ast, T: Field> Checker<'ast, T> { }), } } - Expression::Conditional(box conditional) => { + Expression::Conditional(conditional) => { let condition_checked = self.check_expression(*conditional.condition, module_id, types)?; @@ -2713,7 +2728,7 @@ impl<'ast, T: Field> Checker<'ast, T> { || !conditional.alternative_statements.is_empty() { return Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: "Statements are not supported in conditional branches".to_string(), }); } @@ -2729,7 +2744,7 @@ impl<'ast, T: Field> Checker<'ast, T> { alternative_checked, ) .map_err(|(e1, e2)| ErrorInner { - pos: Some(pos), + span: Some(span), message: format!("{{consequence}} and {{alternative}} in conditional expression should have the same type, found {}, {}", e1.get_type(), e2.get_type()), })?; @@ -2767,13 +2782,13 @@ impl<'ast, T: Field> Checker<'ast, T> { Ok(IntExpression::conditional(condition, consequence, alternative, kind).into()) }, (c, a) => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!("{{consequence}} and {{alternative}} in conditional expression should have the same type, found {}, {}", c.get_type(), a.get_type()) }) } } c => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "{{condition}} should be a boolean, found {}", c.get_type() @@ -2781,39 +2796,41 @@ impl<'ast, T: Field> Checker<'ast, T> { }), } } - Expression::FieldConstant(n) => Ok(FieldElementExpression::Number( - T::try_from(n).map_err(|_| ErrorInner { - pos: Some(pos), - message: format!( - "Field constant not in the representable range [{}, {}]", - T::min_value(), - T::max_value() - ), - })?, - ) + Expression::FieldConstant(n) => Ok(FieldElementExpression::Value( + T::try_from(n) + .map(ValueExpression::new) + .map_err(|_| ErrorInner { + span: Some(span), + message: format!( + "Field constant not in the representable range [{}, {}]", + T::min_value(), + T::max_value() + ), + })?, + ).with_span(span) .into()), - Expression::U8Constant(n) => Ok(UExpressionInner::Value(n.into()).annotate(8).into()), - Expression::U16Constant(n) => Ok(UExpressionInner::Value(n.into()).annotate(16).into()), - Expression::U32Constant(n) => Ok(UExpressionInner::Value(n.into()).annotate(32).into()), - Expression::U64Constant(n) => Ok(UExpressionInner::Value(n.into()).annotate(64).into()), - Expression::FunctionCall(box fun_id_expression, generics, arguments) => self + Expression::U8Constant(n) => Ok(UExpression::value(n.into()).annotate(8).with_span(span).into()), + Expression::U16Constant(n) => Ok(UExpression::value(n.into()).annotate(16).with_span(span).into()), + Expression::U32Constant(n) => Ok(UExpression::value(n.into()).annotate(32).with_span(span).into()), + Expression::U64Constant(n) => Ok(UExpression::value(n.into()).annotate(64).with_span(span).into()), + Expression::FunctionCall(fun_id_expression, generics, arguments) => self .check_function_call_expression( - fun_id_expression, + *fun_id_expression, generics, arguments, None, module_id, types, ), - Expression::Lt(box e1, box e2) => { - let e1_checked = self.check_expression(e1, module_id, types)?; - let e2_checked = self.check_expression(e2, module_id, types)?; + Expression::Lt(e1, e2) => { + let e1_checked = self.check_expression(*e1, module_id, types)?; + let e2_checked = self.check_expression(*e2, module_id, types)?; let (e1_checked, e2_checked) = TypedExpression::align_without_integers( e1_checked, e2_checked, ) .map_err(|(e1, e2)| ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Cannot compare {} of type {} to {} of type {}", e1, @@ -2825,14 +2842,14 @@ impl<'ast, T: Field> Checker<'ast, T> { match (e1_checked, e2_checked) { (TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => { - Ok(BooleanExpression::FieldLt(box e1, box e2).into()) + Ok(BooleanExpression::field_lt(e1, e2).into()) } (TypedExpression::Uint(e1), TypedExpression::Uint(e2)) => { if e1.get_type() == e2.get_type() { - Ok(BooleanExpression::UintLt(box e1, box e2).into()) + Ok(BooleanExpression::uint_lt(e1, e2).into()) } else { Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Cannot compare {} of type {} to {} of type {}", e1, @@ -2844,7 +2861,7 @@ impl<'ast, T: Field> Checker<'ast, T> { } } (e1, e2) => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Cannot compare {} of type {} to {} of type {}", e1, @@ -2855,15 +2872,15 @@ impl<'ast, T: Field> Checker<'ast, T> { }), } } - Expression::Le(box e1, box e2) => { - let e1_checked = self.check_expression(e1, module_id, types)?; - let e2_checked = self.check_expression(e2, module_id, types)?; + Expression::Le(e1, e2) => { + let e1_checked = self.check_expression(*e1, module_id, types)?; + let e2_checked = self.check_expression(*e2, module_id, types)?; let (e1_checked, e2_checked) = TypedExpression::align_without_integers( e1_checked, e2_checked, ) .map_err(|(e1, e2)| ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Cannot compare {} of type {} to {} of type {}", e1, @@ -2875,14 +2892,14 @@ impl<'ast, T: Field> Checker<'ast, T> { match (e1_checked, e2_checked) { (TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => { - Ok(BooleanExpression::FieldLe(box e1, box e2).into()) + Ok(BooleanExpression::field_le(e1, e2).into()) } (TypedExpression::Uint(e1), TypedExpression::Uint(e2)) => { if e1.get_type() == e2.get_type() { - Ok(BooleanExpression::UintLe(box e1, box e2).into()) + Ok(BooleanExpression::uint_le(e1, e2).into()) } else { Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Cannot compare {} of type {} to {} of type {}", e1, @@ -2894,7 +2911,7 @@ impl<'ast, T: Field> Checker<'ast, T> { } } (e1, e2) => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Cannot compare {} of type {} to {} of type {}", e1, @@ -2905,15 +2922,15 @@ impl<'ast, T: Field> Checker<'ast, T> { }), } } - Expression::Eq(box e1, box e2) => { - let e1_checked = self.check_expression(e1, module_id, types)?; - let e2_checked = self.check_expression(e2, module_id, types)?; + Expression::Eq(e1, e2) => { + let e1_checked = self.check_expression(*e1, module_id, types)?; + let e2_checked = self.check_expression(*e2, module_id, types)?; let (e1_checked, e2_checked) = TypedExpression::align_without_integers( e1_checked, e2_checked, ) .map_err(|(e1, e2)| ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Cannot compare {} of type {} to {} of type {}", e1, @@ -2925,27 +2942,27 @@ impl<'ast, T: Field> Checker<'ast, T> { match (e1_checked, e2_checked) { (TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => { - Ok(BooleanExpression::FieldEq(EqExpression::new(e1, e2)).into()) + Ok(BooleanExpression::field_eq(e1, e2).into()) } (TypedExpression::Boolean(e1), TypedExpression::Boolean(e2)) => { - Ok(BooleanExpression::BoolEq(EqExpression::new(e1, e2)).into()) + Ok(BooleanExpression::bool_eq(e1, e2).into()) } (TypedExpression::Array(e1), TypedExpression::Array(e2)) => { - Ok(BooleanExpression::ArrayEq(EqExpression::new(e1, e2)).into()) + Ok(BooleanExpression::array_eq(e1, e2).into()) } (TypedExpression::Struct(e1), TypedExpression::Struct(e2)) => { - Ok(BooleanExpression::StructEq(EqExpression::new(e1, e2)).into()) + Ok(BooleanExpression::struct_eq(e1, e2).into()) } (TypedExpression::Tuple(e1), TypedExpression::Tuple(e2)) => { - Ok(BooleanExpression::TupleEq(EqExpression::new(e1, e2)).into()) + Ok(BooleanExpression::tuple_eq(e1, e2).into()) } (TypedExpression::Uint(e1), TypedExpression::Uint(e2)) if e1.get_type() == e2.get_type() => { - Ok(BooleanExpression::UintEq(EqExpression::new(e1, e2)).into()) + Ok(BooleanExpression::uint_eq(e1, e2).into()) } (e1, e2) => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Cannot compare {} of type {} to {} of type {}", e1, @@ -2956,15 +2973,15 @@ impl<'ast, T: Field> Checker<'ast, T> { }), } } - Expression::Ge(box e1, box e2) => { - let e1_checked = self.check_expression(e1, module_id, types)?; - let e2_checked = self.check_expression(e2, module_id, types)?; + Expression::Ge(e1, e2) => { + let e1_checked = self.check_expression(*e1, module_id, types)?; + let e2_checked = self.check_expression(*e2, module_id, types)?; let (e1_checked, e2_checked) = TypedExpression::align_without_integers( e1_checked, e2_checked, ) .map_err(|(e1, e2)| ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Cannot compare {} of type {} to {} of type {}", e1, @@ -2976,14 +2993,14 @@ impl<'ast, T: Field> Checker<'ast, T> { match (e1_checked, e2_checked) { (TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => { - Ok(BooleanExpression::FieldGe(box e1, box e2).into()) + Ok(BooleanExpression::field_ge(e1, e2).into()) } (TypedExpression::Uint(e1), TypedExpression::Uint(e2)) => { if e1.get_type() == e2.get_type() { - Ok(BooleanExpression::UintGe(box e1, box e2).into()) + Ok(BooleanExpression::uint_ge(e1, e2).into()) } else { Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Cannot compare {} of type {} to {} of type {}", e1, @@ -2995,7 +3012,7 @@ impl<'ast, T: Field> Checker<'ast, T> { } } (e1, e2) => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Cannot compare {} of type {} to {} of type {}", e1, @@ -3006,15 +3023,15 @@ impl<'ast, T: Field> Checker<'ast, T> { }), } } - Expression::Gt(box e1, box e2) => { - let e1_checked = self.check_expression(e1, module_id, types)?; - let e2_checked = self.check_expression(e2, module_id, types)?; + Expression::Gt(e1, e2) => { + let e1_checked = self.check_expression(*e1, module_id, types)?; + let e2_checked = self.check_expression(*e2, module_id, types)?; let (e1_checked, e2_checked) = TypedExpression::align_without_integers( e1_checked, e2_checked, ) .map_err(|(e1, e2)| ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Cannot compare {} of type {} to {} of type {}", e1, @@ -3026,14 +3043,14 @@ impl<'ast, T: Field> Checker<'ast, T> { match (e1_checked, e2_checked) { (TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => { - Ok(BooleanExpression::FieldGt(box e1, box e2).into()) + Ok(BooleanExpression::field_gt(e1, e2).into()) } (TypedExpression::Uint(e1), TypedExpression::Uint(e2)) => { if e1.get_type() == e2.get_type() { - Ok(BooleanExpression::UintGt(box e1, box e2).into()) + Ok(BooleanExpression::uint_gt(e1, e2).into()) } else { Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Cannot compare {} of type {} to {} of type {}", e1, @@ -3045,7 +3062,7 @@ impl<'ast, T: Field> Checker<'ast, T> { } } (e1, e2) => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Cannot compare {} of type {} to {} of type {}", e1, @@ -3056,10 +3073,10 @@ impl<'ast, T: Field> Checker<'ast, T> { }), } } - Expression::Select(box array, box index) => { - let array = self.check_expression(array, module_id, types)?; + Expression::Select(array, index) => { + let array = self.check_expression(*array, module_id, types)?; - match index { + match *index { RangeOrExpression::Range(r) => { match array { TypedExpression::Array(array) => { @@ -3081,7 +3098,7 @@ impl<'ast, T: Field> Checker<'ast, T> { .unwrap_or_else(|| Ok(array_size.clone().into()))?; let from = UExpression::try_from_typed(from, &UBitwidth::B32).map_err(|e| ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Expected the lower bound of the range to be a u32, found {} of type {}", e, @@ -3090,7 +3107,7 @@ impl<'ast, T: Field> Checker<'ast, T> { })?; let to = UExpression::try_from_typed(to, &UBitwidth::B32).map_err(|e| ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Expected the upper bound of the range to be a u32, found {} of type {}", e, @@ -3099,15 +3116,16 @@ impl<'ast, T: Field> Checker<'ast, T> { })?; Ok(ArrayExpressionInner::Slice( - box array, - box from.clone(), - box to.clone(), - ) - .annotate(inner_type, UExpression::floor_sub(to, from)) + SliceExpression::new( + array, + from.clone(), + to.clone(), + )) + .annotate(ArrayType::new(inner_type, UExpression::floor_sub(to, from))) .into()) } e => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Cannot access slice of expression {} of type {}", e, @@ -3122,7 +3140,7 @@ impl<'ast, T: Field> Checker<'ast, T> { let index = UExpression::try_from_typed(index, &UBitwidth::B32).map_err(|e| { ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Expected index to be of type u32, found {}", e @@ -3145,7 +3163,7 @@ impl<'ast, T: Field> Checker<'ast, T> { } } a => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Cannot access element at index {} of type {} on expression {} of type {}", index, @@ -3158,8 +3176,8 @@ impl<'ast, T: Field> Checker<'ast, T> { } } } - Expression::Element(box e, index) => { - let e = self.check_expression(e, module_id, types)?; + Expression::Element(e, index) => { + let e = self.check_expression(*e, module_id, types)?; match e { TypedExpression::Tuple(t) => { let ty = t.ty().elements.get(index as usize); @@ -3177,7 +3195,7 @@ impl<'ast, T: Field> Checker<'ast, T> { Type::Tuple(..) => Ok(TupleExpression::element(t, index).into()), }, None => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Tuple of size {} cannot be accessed at index {}", t.ty().elements.len(), @@ -3187,7 +3205,7 @@ impl<'ast, T: Field> Checker<'ast, T> { } } e => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Cannot access tuple element {} on expression of type {}", index, @@ -3196,13 +3214,13 @@ impl<'ast, T: Field> Checker<'ast, T> { }), } } - Expression::Member(box e, box id) => { - let e = self.check_expression(e, module_id, types)?; + Expression::Member(e, id) => { + let e = self.check_expression(*e, module_id, types)?; match e { TypedExpression::Struct(s) => { // check that the struct has that field and return the type if it does - let ty = s.ty().iter().find(|m| m.id == id).map(|m| *m.ty.clone()); + let ty = s.ty().iter().find(|m| m.id == *id).map(|m| *m.ty.clone()); match ty { Some(ty) => match ty { @@ -3225,7 +3243,7 @@ impl<'ast, T: Field> Checker<'ast, T> { } }, None => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "{} {{{}}} doesn't have member {}", s.get_type(), @@ -3241,7 +3259,7 @@ impl<'ast, T: Field> Checker<'ast, T> { } } e => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Cannot access member {} on expression of type {}", id, @@ -3260,7 +3278,7 @@ impl<'ast, T: Field> Checker<'ast, T> { if expressions_or_spreads_checked.is_empty() { return Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: "Empty arrays are not allowed".to_string(), }); } @@ -3280,14 +3298,14 @@ impl<'ast, T: Field> Checker<'ast, T> { Type::Int => expressions_or_spreads_checked, t => { let target_array_ty = - ArrayType::new(t, UExpressionInner::Value(0).annotate(UBitwidth::B32)); + ArrayType::new(t, UExpression::value(0).annotate(UBitwidth::B32)); expressions_or_spreads_checked .into_iter() .map(|e| { TypedExpressionOrSpread::align_to_type(e, &target_array_ty).map_err( |(e, ty)| ErrorInner { - pos: Some(pos), + span: Some(span), message: format!("Expected {} to have type {}", e, ty,), }, ) @@ -3308,11 +3326,11 @@ impl<'ast, T: Field> Checker<'ast, T> { .map(|e| e.size()) .fold(None, |acc, e| match acc { Some((c_acc, e_acc)) => match e.as_inner() { - UExpressionInner::Value(e) => Some(((c_acc + *e as u32), e_acc)), + UExpressionInner::Value(e) => Some(((c_acc + e.value as u32), e_acc)), _ => Some((c_acc, e_acc + e)), }, None => match e.as_inner() { - UExpressionInner::Value(e) => Some((*e as u32, 0u32.into())), + UExpressionInner::Value(e) => Some((e.value as u32, 0u32.into())), _ => Some((0u32, e)), }, }) @@ -3320,8 +3338,8 @@ impl<'ast, T: Field> Checker<'ast, T> { .unwrap_or_else(|| 0u32.into()); Ok( - ArrayExpressionInner::Value(unwrapped_expressions_or_spreads.into()) - .annotate(inferred_type, size) + ArrayExpression::value(unwrapped_expressions_or_spreads) + .annotate(ArrayType::new(inferred_type, size)) .into(), ) } @@ -3331,17 +3349,17 @@ impl<'ast, T: Field> Checker<'ast, T> { .map(|e| self.check_expression(e, module_id, types)) .collect::>()?; let ty = TupleType::new(elements.iter().map(|e| e.get_type()).collect()); - Ok(TupleExpressionInner::Value(elements).annotate(ty).into()) + Ok(TupleExpression::value(elements).annotate(ty).into()) } - Expression::ArrayInitializer(box e, box count) => { - let e = self.check_expression(e, module_id, types)?; + Expression::ArrayInitializer(e, count) => { + let e = self.check_expression(*e, module_id, types)?; let ty = e.get_type(); - let count = self.check_expression(count, module_id, types)?; + let count = self.check_expression(*count, module_id, types)?; let count = UExpression::try_from_typed(count, &UBitwidth::B32).map_err(|e| { ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Expected array initializer count to be a u32, found {} of type {}", e, @@ -3350,14 +3368,14 @@ impl<'ast, T: Field> Checker<'ast, T> { } })?; - Ok(ArrayExpressionInner::Repeat(box e, box count.clone()) - .annotate(ty, count) + Ok(ArrayExpressionInner::Repeat(RepeatExpression::new(e, count.clone())) + .annotate(ArrayType::new(ty, count)) .into()) } Expression::InlineStruct(id, inline_members) => { let ty = match types.get(module_id).unwrap().get(&id).cloned() { None => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!("Undefined type `{}`", id), }), Some(ty) => Ok(ty), @@ -3379,7 +3397,7 @@ impl<'ast, T: Field> Checker<'ast, T> { // check that we provided the required number of values if declared_struct_type.members_count() != inline_members.len() { return Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Inline struct {} does not match {} {{{}}}", Expression::InlineStruct(id, inline_members), @@ -3414,7 +3432,7 @@ impl<'ast, T: Field> Checker<'ast, T> { let expression_checked = TypedExpression::align_to_type(expression_checked, &*member.ty) .map_err(|e| ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Member {} of struct {} has type {}, found {} of type {}", member.id, @@ -3428,7 +3446,7 @@ impl<'ast, T: Field> Checker<'ast, T> { Ok(expression_checked) } None => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Member {} of struct {} {{{}}} not found in value {}", member.id, @@ -3454,7 +3472,7 @@ impl<'ast, T: Field> Checker<'ast, T> { .map(|(m, v)| { if !check_type(&m.ty, &v.get_type(), &mut generics_map) { Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Value `{}` doesn't match the expected type `{}` because of conflict in generic values", Expression::InlineStruct(id.clone(), inline_members.clone()), @@ -3462,10 +3480,7 @@ impl<'ast, T: Field> Checker<'ast, T> { ), }) } else { - Ok(StructMember { - id: m.id.clone(), - ty: box v.get_type().clone(), - }) + Ok(StructMember::new(m.id.clone(), v.get_type().clone())) } }) .collect::, _>>()?; @@ -3479,19 +3494,19 @@ impl<'ast, T: Field> Checker<'ast, T> { members, }; - Ok(StructExpressionInner::Value(inferred_values) + Ok(StructExpression::value(inferred_values) .annotate(inferred_struct_type) .into()) } - Expression::And(box e1, box e2) => { - let e1_checked = self.check_expression(e1, module_id, types)?; - let e2_checked = self.check_expression(e2, module_id, types)?; + Expression::And(e1, e2) => { + let e1_checked = self.check_expression(*e1, module_id, types)?; + let e2_checked = self.check_expression(*e2, module_id, types)?; let (e1_checked, e2_checked) = TypedExpression::align_without_integers( e1_checked, e2_checked, ) .map_err(|(e1, e2)| ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Cannot apply boolean operators to {} and {}", e1.get_type(), @@ -3501,13 +3516,13 @@ impl<'ast, T: Field> Checker<'ast, T> { match (e1_checked, e2_checked) { (TypedExpression::Int(e1), TypedExpression::Int(e2)) => { - Ok(IntExpression::And(box e1, box e2).into()) + Ok(IntExpression::and(e1, e2).into()) } (TypedExpression::Boolean(e1), TypedExpression::Boolean(e2)) => { - Ok(BooleanExpression::And(box e1, box e2).into()) + Ok(BooleanExpression::bitand(e1, e2).into()) } (e1, e2) => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Cannot apply boolean operators to {} and {}", @@ -3517,15 +3532,15 @@ impl<'ast, T: Field> Checker<'ast, T> { }), } } - Expression::Or(box e1, box e2) => { - let e1_checked = self.check_expression(e1, module_id, types)?; - let e2_checked = self.check_expression(e2, module_id, types)?; + Expression::Or(e1, e2) => { + let e1_checked = self.check_expression(*e1, module_id, types)?; + let e2_checked = self.check_expression(*e2, module_id, types)?; match (e1_checked, e2_checked) { (TypedExpression::Boolean(e1), TypedExpression::Boolean(e2)) => { - Ok(BooleanExpression::Or(box e1, box e2).into()) + Ok(BooleanExpression::bitor(e1, e2).into()) } (e1, e2) => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Cannot apply `||` to {}, {}", e1.get_type(), @@ -3534,13 +3549,13 @@ impl<'ast, T: Field> Checker<'ast, T> { }), } } - Expression::LeftShift(box e1, box e2) => { - let e1 = self.check_expression(e1, module_id, types)?; - let e2 = self.check_expression(e2, module_id, types)?; + Expression::LeftShift(e1, e2) => { + let e1 = self.check_expression(*e1, module_id, types)?; + let e2 = self.check_expression(*e2, module_id, types)?; let e2 = UExpression::try_from_typed(e2, &UBitwidth::B32).map_err(|e| ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Expected the left shift right operand to have type `u32`, found {}", e @@ -3548,13 +3563,13 @@ impl<'ast, T: Field> Checker<'ast, T> { })?; match e1 { - TypedExpression::Int(e1) => Ok(IntExpression::LeftShift(box e1, box e2).into()), + TypedExpression::Int(e1) => Ok(IntExpression::left_shift(e1, e2).into()), TypedExpression::Uint(e1) => Ok(UExpression::left_shift(e1, e2).into()), TypedExpression::FieldElement(e1) => { - Ok(FieldElementExpression::LeftShift(box e1, box e2).into()) + Ok(FieldElementExpression::left_shift(e1, e2).into()) } e1 => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Cannot left-shift {} by {}", e1.get_type(), @@ -3563,13 +3578,13 @@ impl<'ast, T: Field> Checker<'ast, T> { }), } } - Expression::RightShift(box e1, box e2) => { - let e1 = self.check_expression(e1, module_id, types)?; - let e2 = self.check_expression(e2, module_id, types)?; + Expression::RightShift(e1, e2) => { + let e1 = self.check_expression(*e1, module_id, types)?; + let e2 = self.check_expression(*e2, module_id, types)?; let e2 = UExpression::try_from_typed(e2, &UBitwidth::B32).map_err(|e| ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Expected the right shift right operand to be of type `u32`, found {}", e @@ -3578,14 +3593,14 @@ impl<'ast, T: Field> Checker<'ast, T> { match e1 { TypedExpression::Int(e1) => { - Ok(IntExpression::RightShift(box e1, box e2).into()) + Ok(IntExpression::right_shift(e1, e2).into()) } TypedExpression::Uint(e1) => Ok(UExpression::right_shift(e1, e2).into()), TypedExpression::FieldElement(e1) => { - Ok(FieldElementExpression::RightShift(box e1, box e2).into()) + Ok(FieldElementExpression::right_shift(e1, e2).into()) } e1 => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Cannot right-shift {} by {}", e1.get_type(), @@ -3594,24 +3609,24 @@ impl<'ast, T: Field> Checker<'ast, T> { }), } } - Expression::BitOr(box e1, box e2) => { - let e1_checked = self.check_expression(e1, module_id, types)?; - let e2_checked = self.check_expression(e2, module_id, types)?; + Expression::BitOr(e1, e2) => { + let e1_checked = self.check_expression(*e1, module_id, types)?; + let e2_checked = self.check_expression(*e2, module_id, types)?; let (e1_checked, e2_checked) = TypedExpression::align_without_integers( e1_checked, e2_checked, ) .map_err(|(e1, e2)| ErrorInner { - pos: Some(pos), + span: Some(span), message: format!("Cannot apply `|` to {}, {}", e1.get_type(), e2.get_type()), })?; match (e1_checked, e2_checked) { (TypedExpression::Int(e1), TypedExpression::Int(e2)) => { - Ok(IntExpression::Or(box e1, box e2).into()) + Ok(IntExpression::or(e1, e2).into()) } (TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => { - Ok(FieldElementExpression::Or(box e1, box e2).into()) + Ok(FieldElementExpression::bitor(e1, e2).into()) } (TypedExpression::Uint(e1), TypedExpression::Uint(e2)) if e1.bitwidth() == e2.bitwidth() => @@ -3619,7 +3634,7 @@ impl<'ast, T: Field> Checker<'ast, T> { Ok(UExpression::or(e1, e2).into()) } (e1, e2) => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Cannot apply `|` to {}, {}", e1.get_type(), @@ -3628,24 +3643,24 @@ impl<'ast, T: Field> Checker<'ast, T> { }), } } - Expression::BitAnd(box e1, box e2) => { - let e1_checked = self.check_expression(e1, module_id, types)?; - let e2_checked = self.check_expression(e2, module_id, types)?; + Expression::BitAnd(e1, e2) => { + let e1_checked = self.check_expression(*e1, module_id, types)?; + let e2_checked = self.check_expression(*e2, module_id, types)?; let (e1_checked, e2_checked) = TypedExpression::align_without_integers( e1_checked, e2_checked, ) .map_err(|(e1, e2)| ErrorInner { - pos: Some(pos), + span: Some(span), message: format!("Cannot apply `&` to {}, {}", e1.get_type(), e2.get_type()), })?; match (e1_checked, e2_checked) { (TypedExpression::Int(e1), TypedExpression::Int(e2)) => { - Ok(IntExpression::And(box e1, box e2).into()) + Ok(IntExpression::and(e1, e2).into()) } (TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => { - Ok(FieldElementExpression::And(box e1, box e2).into()) + Ok(FieldElementExpression::bitand(e1, e2).into()) } (TypedExpression::Uint(e1), TypedExpression::Uint(e2)) if e1.bitwidth() == e2.bitwidth() => @@ -3653,7 +3668,7 @@ impl<'ast, T: Field> Checker<'ast, T> { Ok(UExpression::and(e1, e2).into()) } (e1, e2) => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Cannot apply `&` to {}, {}", e1.get_type(), @@ -3662,24 +3677,24 @@ impl<'ast, T: Field> Checker<'ast, T> { }), } } - Expression::BitXor(box e1, box e2) => { - let e1_checked = self.check_expression(e1, module_id, types)?; - let e2_checked = self.check_expression(e2, module_id, types)?; + Expression::BitXor(e1, e2) => { + let e1_checked = self.check_expression(*e1, module_id, types)?; + let e2_checked = self.check_expression(*e2, module_id, types)?; let (e1_checked, e2_checked) = TypedExpression::align_without_integers( e1_checked, e2_checked, ) .map_err(|(e1, e2)| ErrorInner { - pos: Some(pos), + span: Some(span), message: format!("Cannot apply `^` to {}, {}", e1.get_type(), e2.get_type()), })?; match (e1_checked, e2_checked) { (TypedExpression::Int(e1), TypedExpression::Int(e2)) => { - Ok(IntExpression::Xor(box e1, box e2).into()) + Ok(IntExpression::xor(e1, e2).into()) } (TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => { - Ok(FieldElementExpression::Xor(box e1, box e2).into()) + Ok(FieldElementExpression::bitxor(e1, e2).into()) } (TypedExpression::Uint(e1), TypedExpression::Uint(e2)) if e1.bitwidth() == e2.bitwidth() => @@ -3687,7 +3702,7 @@ impl<'ast, T: Field> Checker<'ast, T> { Ok(UExpression::xor(e1, e2).into()) } (e1, e2) => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!( "Cannot apply `^` to {}, {}", e1.get_type(), @@ -3696,19 +3711,19 @@ impl<'ast, T: Field> Checker<'ast, T> { }), } } - Expression::Not(box e) => { - let e_checked = self.check_expression(e, module_id, types)?; + Expression::Not(e) => { + let e_checked = self.check_expression(*e, module_id, types)?; match e_checked { - TypedExpression::Int(e) => Ok(IntExpression::Not(box e).into()), - TypedExpression::Boolean(e) => Ok(BooleanExpression::Not(box e).into()), + TypedExpression::Int(e) => Ok(IntExpression::not(e).into()), + TypedExpression::Boolean(e) => Ok(BooleanExpression::not(e).into()), TypedExpression::Uint(e) => Ok((!e).into()), e => Err(ErrorInner { - pos: Some(pos), + span: Some(span), message: format!("Cannot negate {}", e.get_type()), }), } } - } + }.map(|e| e.with_span(span)) } fn insert_into_scope>>( @@ -3751,19 +3766,17 @@ mod tests { use zokrates_field::Bn128Field; lazy_static! { - static ref MODULE_ID: OwnedModuleId = OwnedModuleId::from(""); + static ref MODULE_ID: OwnedModuleId = OwnedModuleId::default(); } mod constants { use super::*; - use std::ops::Add; - #[test] fn field_in_range() { // The value of `P - 1` is a valid field literal let expr = Expression::FieldConstant(Bn128Field::max_value().to_biguint()).mock(); assert!(Checker::::default() - .check_expression(expr, &*MODULE_ID, &TypeMap::new()) + .check_expression(expr, &MODULE_ID, &TypeMap::new()) .is_ok()); } @@ -3774,7 +3787,7 @@ mod tests { let expr = Expression::FieldConstant(value).mock(); assert!(Checker::::default() - .check_expression(expr, &*MODULE_ID, &TypeMap::new()) + .check_expression(expr, &MODULE_ID, &TypeMap::new()) .is_err()); } } @@ -3797,7 +3810,7 @@ mod tests { ]) .mock(); assert!(Checker::::default() - .check_expression(a, &*MODULE_ID, &types) + .check_expression(a, &MODULE_ID, &types) .is_err()); // [[0f], [0f, 0f]] @@ -3817,7 +3830,7 @@ mod tests { ]) .mock(); assert!(Checker::::default() - .check_expression(a, &*MODULE_ID, &types) + .check_expression(a, &MODULE_ID, &types) .is_ok()); // [[0f], true] @@ -3833,7 +3846,7 @@ mod tests { ]) .mock(); assert!(Checker::::default() - .check_expression(a, &*MODULE_ID, &types) + .check_expression(a, &MODULE_ID, &types) .is_err()); } } @@ -3994,7 +4007,7 @@ mod tests { let mut checker: Checker = Checker::default(); assert_eq!( - checker.check_module(&OwnedTypedModuleId::from("bar"), &mut state), + checker.check_module(&OwnedModuleId::from("bar"), &mut state), Ok(()) ); assert_eq!( @@ -4048,7 +4061,7 @@ mod tests { let mut checker: Checker = Checker::default(); assert_eq!( - checker.check_module(&*MODULE_ID, &mut state).unwrap_err()[0] + checker.check_module(&MODULE_ID, &mut state).unwrap_err()[0] .inner .message, "foo conflicts with another symbol" @@ -4131,7 +4144,7 @@ mod tests { ); let mut checker: Checker = Checker::default(); - assert!(checker.check_module(&*MODULE_ID, &mut state).is_ok()); + assert!(checker.check_module(&MODULE_ID, &mut state).is_ok()); } mod generics { @@ -4173,7 +4186,7 @@ mod tests { ); let mut checker: Checker = Checker::default(); - assert!(checker.check_module(&*MODULE_ID, &mut state).is_ok()); + assert!(checker.check_module(&MODULE_ID, &mut state).is_ok()); } #[test] @@ -4230,7 +4243,7 @@ mod tests { let mut checker: Checker = Checker::default(); assert_eq!( - checker.check_module(&*MODULE_ID, &mut state).unwrap_err()[0] + checker.check_module(&MODULE_ID, &mut state).unwrap_err()[0] .inner .message, "Undeclared symbol `P`" @@ -4270,7 +4283,7 @@ mod tests { ); let mut checker: Checker = Checker::default(); - assert_eq!(checker.check_module(&*MODULE_ID, &mut state), Ok(())); + assert_eq!(checker.check_module(&MODULE_ID, &mut state), Ok(())); assert!(state .typed_modules .get(&*MODULE_ID) @@ -4321,7 +4334,7 @@ mod tests { let mut checker: Checker = Checker::default(); assert_eq!( - checker.check_module(&*MODULE_ID, &mut state).unwrap_err()[0] + checker.check_module(&MODULE_ID, &mut state).unwrap_err()[0] .inner .message, "foo conflicts with another symbol" @@ -4365,7 +4378,7 @@ mod tests { let mut checker: Checker = Checker::default(); assert_eq!( - checker.check_module(&*MODULE_ID, &mut state).unwrap_err()[0] + checker.check_module(&MODULE_ID, &mut state).unwrap_err()[0] .inner .message, "foo conflicts with another symbol" @@ -4417,7 +4430,7 @@ mod tests { let mut checker: Checker = Checker::default(); assert_eq!( - checker.check_module(&*MODULE_ID, &mut state).unwrap_err()[0] + checker.check_module(&MODULE_ID, &mut state).unwrap_err()[0] .inner .message, "foo conflicts with another symbol" @@ -4466,7 +4479,7 @@ mod tests { let mut checker: Checker = Checker::default(); assert_eq!( - checker.check_module(&*MODULE_ID, &mut state).unwrap_err()[0] + checker.check_module(&MODULE_ID, &mut state).unwrap_err()[0] .inner .message, "foo conflicts with another symbol" @@ -4495,14 +4508,14 @@ mod tests { let state = State::new(modules, (*MODULE_ID).clone()); let signature = UnresolvedSignature::new().inputs(vec![UnresolvedType::Array( - box UnresolvedType::FieldElement.mock(), + Box::new(UnresolvedType::FieldElement.mock()), Expression::Identifier("K").mock(), ) .mock()]); assert_eq!( - Checker::::default().check_signature(signature, &*MODULE_ID, &state), + Checker::::default().check_signature(signature, &MODULE_ID, &state), Err(vec![ErrorInner { - pos: Some((Position::mock(), Position::mock())), + span: Some(SourceSpan::mock()), message: "Undeclared symbol `K`".to_string() }]) ); @@ -4517,27 +4530,31 @@ mod tests { let signature = UnresolvedSignature::new() .generics(vec!["K".mock(), "L".mock(), "M".mock()]) .inputs(vec![UnresolvedType::Array( - box UnresolvedType::Array( - box UnresolvedType::FieldElement.mock(), - Expression::Identifier("K").mock(), - ) - .mock(), + Box::new( + UnresolvedType::Array( + Box::new(UnresolvedType::FieldElement.mock()), + Expression::Identifier("K").mock(), + ) + .mock(), + ), Expression::Identifier("L").mock(), ) .mock()]) .output( UnresolvedType::Array( - box UnresolvedType::Array( - box UnresolvedType::FieldElement.mock(), - Expression::Identifier("L").mock(), - ) - .mock(), + Box::new( + UnresolvedType::Array( + Box::new(UnresolvedType::FieldElement.mock()), + Expression::Identifier("L").mock(), + ) + .mock(), + ), Expression::Identifier("K").mock(), ) .mock(), ); assert_eq!( - Checker::::default().check_signature(signature, &*MODULE_ID, &state), + Checker::::default().check_signature(signature, &MODULE_ID, &state), Ok(DeclarationSignature::new() .inputs(vec![DeclarationType::array(( DeclarationType::array(( @@ -4572,9 +4589,9 @@ mod tests { checker.enter_scope(); assert_eq!( - checker.check_statement(statement, &*MODULE_ID, &TypeMap::new()), + checker.check_statement(statement, &MODULE_ID, &TypeMap::new()), Err(vec![ErrorInner { - pos: Some((Position::mock(), Position::mock())), + span: Some(SourceSpan::mock()), message: "Identifier \"b\" is undefined".into() }]) ); @@ -4603,7 +4620,7 @@ mod tests { let mut checker: Checker = new_with_args(scope, HashSet::new()); checker.enter_scope(); assert_eq!( - checker.check_statement(statement, &*MODULE_ID, &TypeMap::new()), + checker.check_statement(statement, &MODULE_ID, &TypeMap::new()), Ok(TypedStatement::definition( typed::Variable::field_element("a").into(), FieldElementExpression::identifier("b".into()).into() @@ -4672,10 +4689,10 @@ mod tests { let mut checker: Checker = Checker::default(); assert_eq!( - checker.check_module(&*MODULE_ID, &mut state), + checker.check_module(&MODULE_ID, &mut state), Err(vec![Error { inner: ErrorInner { - pos: Some((Position::mock(), Position::mock())), + span: Some(SourceSpan::mock()), message: "Identifier \"a\" is undefined".into() }, module_id: (*MODULE_ID).clone() @@ -4768,7 +4785,7 @@ mod tests { ); let mut checker: Checker = Checker::default(); - assert!(checker.check_module(&*MODULE_ID, &mut state).is_ok()); + assert!(checker.check_module(&MODULE_ID, &mut state).is_ok()); } #[test] @@ -4802,9 +4819,9 @@ mod tests { let mut checker: Checker = Checker::default(); assert_eq!( - checker.check_function("foo", foo, &*MODULE_ID, &state), + checker.check_function("foo", foo, &MODULE_ID, &state), Err(vec![ErrorInner { - pos: Some((Position::mock(), Position::mock())), + span: Some(SourceSpan::mock()), message: "Identifier \"i\" is undefined".into() }]) ); @@ -4851,7 +4868,7 @@ mod tests { )]; let foo_statements_checked = vec![ - TypedStatement::For( + TypedStatement::for_( typed::Variable::uint( CoreIdentifier::Source(ShadowedIdentifier::shadow("i".into(), 1)), UBitwidth::B32, @@ -4860,7 +4877,7 @@ mod tests { 10u32.into(), for_statements_checked, ), - TypedStatement::Return(TypedExpression::empty_tuple()), + TypedStatement::ret(TypedExpression::empty_tuple()), ]; let foo = Function { @@ -4881,7 +4898,7 @@ mod tests { let mut checker: Checker = Checker::default(); assert_eq!( - checker.check_function("foo", foo, &*MODULE_ID, &state), + checker.check_function("foo", foo, &MODULE_ID, &state), Ok(foo_checked) ); } @@ -4899,8 +4916,12 @@ mod tests { let bar_statements: Vec = vec![ Statement::Definition( untyped::Variable::immutable("a", UnresolvedType::FieldElement.mock()).mock(), - Expression::FunctionCall(box Expression::Identifier("foo").mock(), None, vec![]) - .mock(), + Expression::FunctionCall( + Box::new(Expression::Identifier("foo").mock()), + None, + vec![], + ) + .mock(), ) .mock(), Statement::Return(None).mock(), @@ -4928,9 +4949,9 @@ mod tests { let mut checker: Checker = new_with_args(Scope::default(), functions); assert_eq!( - checker.check_function("bar", bar, &*MODULE_ID, &state), + checker.check_function("bar", bar, &MODULE_ID, &state), Err(vec![ErrorInner { - pos: Some((Position::mock(), Position::mock())), + span: Some(SourceSpan::mock()), message: "Function definition for function foo with signature () -> field not found." .into() @@ -4948,8 +4969,12 @@ mod tests { let bar_statements: Vec = vec![ Statement::Definition( untyped::Variable::immutable("a", UnresolvedType::FieldElement.mock()).mock(), - Expression::FunctionCall(box Expression::Identifier("foo").mock(), None, vec![]) - .mock(), + Expression::FunctionCall( + Box::new(Expression::Identifier("foo").mock()), + None, + vec![], + ) + .mock(), ) .mock(), Statement::Return(None).mock(), @@ -4967,9 +4992,9 @@ mod tests { let mut checker: Checker = new_with_args(Scope::default(), HashSet::new()); assert_eq!( - checker.check_function("bar", bar, &*MODULE_ID, &state), + checker.check_function("bar", bar, &MODULE_ID, &state), Err(vec![ErrorInner { - pos: Some((Position::mock(), Position::mock())), + span: Some(SourceSpan::mock()), message: "Function definition for function foo with signature () -> field not found." @@ -5004,8 +5029,12 @@ mod tests { let main_statements: Vec = vec![ Statement::Assignment( Assignee::Identifier("a").mock(), - Expression::FunctionCall(box Expression::Identifier("foo").mock(), None, vec![]) - .mock(), + Expression::FunctionCall( + Box::new(Expression::Identifier("foo").mock()), + None, + vec![], + ) + .mock(), ) .mock(), Statement::Return(None).mock(), @@ -5042,10 +5071,10 @@ mod tests { let mut checker: Checker = new_with_args(Scope::default(), HashSet::new()); assert_eq!( - checker.check_module(&*MODULE_ID, &mut state), + checker.check_module(&MODULE_ID, &mut state), Err(vec![Error { inner: ErrorInner { - pos: Some((Position::mock(), Position::mock())), + span: Some(SourceSpan::mock()), message: "Variable `a` is undeclared".into() }, module_id: (*MODULE_ID).clone() @@ -5096,14 +5125,18 @@ mod tests { .mock(), Statement::Assignment( Assignee::Select( - box Assignee::Identifier("a").mock(), - box RangeOrExpression::Expression( + Box::new(Assignee::Identifier("a").mock()), + Box::new(RangeOrExpression::Expression( untyped::Expression::IntConstant(0usize.into()).mock(), - ), + )), + ) + .mock(), + Expression::FunctionCall( + Box::new(Expression::Identifier("foo").mock()), + None, + vec![], ) .mock(), - Expression::FunctionCall(box Expression::Identifier("foo").mock(), None, vec![]) - .mock(), ) .mock(), Statement::Return(None).mock(), @@ -5139,7 +5172,7 @@ mod tests { ); let mut checker: Checker = new_with_args(Scope::default(), HashSet::new()); - assert!(checker.check_module(&*MODULE_ID, &mut state).is_ok()); + assert!(checker.check_module(&MODULE_ID, &mut state).is_ok()); } #[test] @@ -5153,13 +5186,15 @@ mod tests { let bar_statements: Vec = vec![ Statement::Assertion( Expression::Eq( - box Expression::IntConstant(1usize.into()).mock(), - box Expression::FunctionCall( - box Expression::Identifier("foo").mock(), - None, - vec![], - ) - .mock(), + Box::new(Expression::IntConstant(1usize.into()).mock()), + Box::new( + Expression::FunctionCall( + Box::new(Expression::Identifier("foo").mock()), + None, + vec![], + ) + .mock(), + ), ) .mock(), None, @@ -5180,9 +5215,9 @@ mod tests { let mut checker: Checker = new_with_args(Scope::default(), HashSet::new()); assert_eq!( - checker.check_function("bar", bar, &*MODULE_ID, &state), + checker.check_function("bar", bar, &MODULE_ID, &state), Err(vec![ErrorInner { - pos: Some((Position::mock(), Position::mock())), + span: Some(SourceSpan::mock()), message: "Function definition for function foo with signature () -> _ not found." .into() @@ -5213,9 +5248,9 @@ mod tests { let mut checker: Checker = new_with_args(Scope::default(), HashSet::new()); assert_eq!( - checker.check_function("bar", bar, &*MODULE_ID, &state), + checker.check_function("bar", bar, &MODULE_ID, &state), Err(vec![ErrorInner { - pos: Some((Position::mock(), Position::mock())), + span: Some(SourceSpan::mock()), message: "Identifier \"a\" is undefined".into() }]) ); @@ -5251,7 +5286,7 @@ mod tests { let mut checker: Checker = new_with_args(Scope::default(), HashSet::new()); assert_eq!( checker - .check_function("main", f, &*MODULE_ID, &state) + .check_function("main", f, &MODULE_ID, &state) .unwrap_err()[0] .message, "Duplicate name in function definition: `a` was previously declared as an argument, a generic parameter or a constant" @@ -5326,7 +5361,7 @@ mod tests { checker.check_program(program), Err(vec![Error { inner: ErrorInner { - pos: None, + span: None, message: "Only one main function allowed, found 2".into() }, module_id: (*MODULE_ID).clone() @@ -5353,7 +5388,7 @@ mod tests { untyped::Expression::IntConstant(2usize.into()).mock(), ) .mock(), - &*MODULE_ID, + &MODULE_ID, &TypeMap::new(), ); let s2_checked: Result, Vec> = checker @@ -5364,7 +5399,7 @@ mod tests { untyped::Expression::IntConstant(2usize.into()).mock(), ) .mock(), - &*MODULE_ID, + &MODULE_ID, &TypeMap::new(), ); assert!(s2_checked.is_ok()); @@ -5385,7 +5420,7 @@ mod tests { untyped::Expression::IntConstant(2usize.into()).mock(), ) .mock(), - &*MODULE_ID, + &MODULE_ID, &TypeMap::new(), ); let s2_checked: Result, Vec> = checker @@ -5395,7 +5430,7 @@ mod tests { untyped::Expression::BooleanConstant(true).mock(), ) .mock(), - &*MODULE_ID, + &MODULE_ID, &TypeMap::new(), ); assert!(s2_checked.is_ok()); @@ -5459,16 +5494,14 @@ mod tests { typed::Variable::new( CoreIdentifier::from(ShadowedIdentifier::shadow("a".into(), 0)), Type::FieldElement, - true, ) .into(), - FieldElementExpression::Number(2u32.into()).into(), + FieldElementExpression::value(2u32.into()).into(), ), - TypedStatement::For( + TypedStatement::for_( typed::Variable::new( CoreIdentifier::from(ShadowedIdentifier::shadow("i".into(), 1)), Type::Uint(UBitwidth::B32), - false, ), 0u32.into(), 0u32.into(), @@ -5477,19 +5510,17 @@ mod tests { typed::Variable::new( CoreIdentifier::from(ShadowedIdentifier::shadow("a".into(), 0)), Type::FieldElement, - true, ) .into(), - FieldElementExpression::Number(3u32.into()).into(), + FieldElementExpression::value(3u32.into()).into(), ), TypedStatement::definition( typed::Variable::new( CoreIdentifier::from(ShadowedIdentifier::shadow("a".into(), 1)), Type::FieldElement, - false, ) .into(), - FieldElementExpression::Number(4u32.into()).into(), + FieldElementExpression::value(4u32.into()).into(), ), ], ), @@ -5497,10 +5528,9 @@ mod tests { typed::Variable::new( CoreIdentifier::from(ShadowedIdentifier::shadow("a".into(), 0)), Type::FieldElement, - true, ) .into(), - FieldElementExpression::Number(5u32.into()).into(), + FieldElementExpression::value(5u32.into()).into(), ), ]; @@ -5509,7 +5539,7 @@ mod tests { .into_iter() .map(|s| { checker - .check_statement(s, &*MODULE_ID, &TypeMap::default()) + .check_statement(s, &MODULE_ID, &TypeMap::default()) .unwrap() }) .collect(); @@ -5541,7 +5571,7 @@ mod tests { let mut checker: Checker = Checker::default(); - checker.check_module(&*MODULE_ID, &mut state).unwrap(); + checker.check_module(&MODULE_ID, &mut state).unwrap(); (checker, state) } @@ -5569,7 +5599,7 @@ mod tests { Checker::::default().check_struct_type_declaration( "Foo".into(), declaration, - &*MODULE_ID, + &MODULE_ID, &state ), Ok(expected_type) @@ -5613,7 +5643,7 @@ mod tests { Checker::::default().check_struct_type_declaration( "Foo".into(), declaration, - &*MODULE_ID, + &MODULE_ID, &state ), Ok(expected_type) @@ -5648,7 +5678,7 @@ mod tests { .check_struct_type_declaration( "Foo".into(), declaration, - &*MODULE_ID, + &MODULE_ID, &state ) .unwrap_err()[0] @@ -5705,7 +5735,7 @@ mod tests { ); assert!(Checker::default() - .check_module(&*MODULE_ID, &mut state) + .check_module(&MODULE_ID, &mut state) .is_ok()); assert_eq!( state @@ -5765,7 +5795,7 @@ mod tests { ); assert!(Checker::default() - .check_module(&*MODULE_ID, &mut state) + .check_module(&MODULE_ID, &mut state) .is_err()); } @@ -5799,7 +5829,7 @@ mod tests { ); assert!(Checker::default() - .check_module(&*MODULE_ID, &mut state) + .check_module(&MODULE_ID, &mut state) .is_err()); } @@ -5851,7 +5881,7 @@ mod tests { ); assert!(Checker::default() - .check_module(&*MODULE_ID, &mut state) + .check_module(&MODULE_ID, &mut state) .is_err()); } } @@ -5881,7 +5911,7 @@ mod tests { assert_eq!( checker.check_type( UnresolvedType::User("Foo".into(), None).mock(), - &*MODULE_ID, + &MODULE_ID, &state.types ), Ok(Type::Struct(StructType::new( @@ -5896,7 +5926,7 @@ mod tests { checker .check_type( UnresolvedType::User("Bar".into(), None).mock(), - &*MODULE_ID, + &MODULE_ID, &state.types ) .unwrap_err() @@ -5929,19 +5959,21 @@ mod tests { assert_eq!( checker.check_expression( Expression::Member( - box Expression::InlineStruct( - "Foo".into(), - vec![("foo", Expression::IntConstant(42usize.into()).mock())] - ) - .mock(), + Box::new( + Expression::InlineStruct( + "Foo".into(), + vec![("foo", Expression::IntConstant(42usize.into()).mock())] + ) + .mock() + ), "foo".into() ) .mock(), - &*MODULE_ID, + &MODULE_ID, &state.types ), Ok(FieldElementExpression::member( - StructExpressionInner::Value(vec![FieldElementExpression::Number( + StructExpression::value(vec![FieldElementExpression::value( Bn128Field::from(42u32) ) .into()]) @@ -5977,15 +6009,20 @@ mod tests { checker .check_expression( Expression::Member( - box Expression::InlineStruct( - "Foo".into(), - vec![("foo", Expression::IntConstant(42usize.into()).mock())] - ) - .mock(), + Box::new( + Expression::InlineStruct( + "Foo".into(), + vec![( + "foo", + Expression::IntConstant(42usize.into()).mock() + )] + ) + .mock() + ), "bar".into() ) .mock(), - &*MODULE_ID, + &MODULE_ID, &state.types ) .unwrap_err() @@ -6020,7 +6057,7 @@ mod tests { vec![("foo", Expression::IntConstant(42usize.into()).mock())] ) .mock(), - &*MODULE_ID, + &MODULE_ID, &state.types ) .unwrap_err() @@ -6062,12 +6099,12 @@ mod tests { ] ) .mock(), - &*MODULE_ID, + &MODULE_ID, &state.types ), - Ok(StructExpressionInner::Value(vec![ - FieldElementExpression::Number(Bn128Field::from(42u32)).into(), - BooleanExpression::Value(true).into() + Ok(StructExpression::value(vec![ + FieldElementExpression::value(Bn128Field::from(42u32)).into(), + BooleanExpression::value(true).into() ]) .annotate(StructType::new( "".into(), @@ -6115,12 +6152,12 @@ mod tests { ] ) .mock(), - &*MODULE_ID, + &MODULE_ID, &state.types ), - Ok(StructExpressionInner::Value(vec![ - FieldElementExpression::Number(Bn128Field::from(42u32)).into(), - BooleanExpression::Value(true).into() + Ok(StructExpression::value(vec![ + FieldElementExpression::value(Bn128Field::from(42u32)).into(), + BooleanExpression::value(true).into() ]) .annotate(StructType::new( "".into(), @@ -6166,7 +6203,7 @@ mod tests { vec![("foo", Expression::IntConstant(42usize.into()).mock())] ) .mock(), - &*MODULE_ID, + &MODULE_ID, &state.types ) .unwrap_err() @@ -6214,7 +6251,7 @@ mod tests { )] ) .mock(), - &*MODULE_ID, + &MODULE_ID, &state.types ).unwrap_err() .message, @@ -6232,7 +6269,7 @@ mod tests { ] ) .mock(), - &*MODULE_ID, + &MODULE_ID, &state.types ) .unwrap_err() @@ -6292,7 +6329,7 @@ mod tests { main.value.statements = vec![Statement::Return(Some( Expression::FunctionCall( - box Expression::Identifier("foo").mock(), + Box::new(Expression::Identifier("foo").mock()), None, vec![Expression::IntConstant(0usize.into()).mock()], ) @@ -6356,17 +6393,16 @@ mod tests { Expression::FieldConstant(42u32.into()).mock(), ) .mock(), - &*MODULE_ID, + &MODULE_ID, &TypeMap::new(), ) .unwrap(); assert_eq!( - checker.check_assignee(a, &*MODULE_ID, &TypeMap::new()), + checker.check_assignee(a, &MODULE_ID, &TypeMap::new()), Ok(TypedAssignee::Identifier(typed::Variable::new( "a", Type::FieldElement, - true ))) ); } @@ -6376,8 +6412,10 @@ mod tests { // field[3] a = [1, 2, 3] // a[2] = 42 let a = Assignee::Select( - box Assignee::Identifier("a").mock(), - box RangeOrExpression::Expression(Expression::IntConstant(2usize.into()).mock()), + Box::new(Assignee::Identifier("a").mock()), + Box::new(RangeOrExpression::Expression( + Expression::IntConstant(2usize.into()).mock(), + )), ) .mock(); @@ -6408,20 +6446,19 @@ mod tests { .mock(), ) .mock(), - &*MODULE_ID, + &MODULE_ID, &TypeMap::new(), ) .unwrap(); assert_eq!( - checker.check_assignee(a, &*MODULE_ID, &TypeMap::new()), + checker.check_assignee(a, &MODULE_ID, &TypeMap::new()), Ok(TypedAssignee::Select( - box TypedAssignee::Identifier(typed::Variable::new( + Box::new(TypedAssignee::Identifier(typed::Variable::new( "a", Type::array((Type::FieldElement, 3u32)), - true, - )), - box 2u32.into() + ))), + Box::new(2u32.into()) )) ); } @@ -6431,14 +6468,18 @@ mod tests { // field[1][1] a = [[1]] // a[0][0] let a: AssigneeNode = Assignee::Select( - box Assignee::Select( - box Assignee::Identifier("a").mock(), - box RangeOrExpression::Expression( - Expression::IntConstant(0usize.into()).mock(), - ), - ) - .mock(), - box RangeOrExpression::Expression(Expression::IntConstant(0usize.into()).mock()), + Box::new( + Assignee::Select( + Box::new(Assignee::Identifier("a").mock()), + Box::new(RangeOrExpression::Expression( + Expression::IntConstant(0usize.into()).mock(), + )), + ) + .mock(), + ), + Box::new(RangeOrExpression::Expression( + Expression::IntConstant(0usize.into()).mock(), + )), ) .mock(); @@ -6469,23 +6510,22 @@ mod tests { .mock(), ) .mock(), - &*MODULE_ID, + &MODULE_ID, &TypeMap::new(), ) .unwrap(); assert_eq!( - checker.check_assignee(a, &*MODULE_ID, &TypeMap::new()), + checker.check_assignee(a, &MODULE_ID, &TypeMap::new()), Ok(TypedAssignee::Select( - box TypedAssignee::Select( - box TypedAssignee::Identifier(typed::Variable::new( + Box::new(TypedAssignee::Select( + Box::new(TypedAssignee::Identifier(typed::Variable::new( "a", Type::array((Type::array((Type::FieldElement, 1u32)), 1u32)), - true, - )), - box 0u32.into() - ), - box 0u32.into() + ))), + Box::new(0u32.into()) + )), + Box::new(0u32.into()) )) ); } diff --git a/zokrates_core_test/Cargo.toml b/zokrates_core_test/Cargo.toml index 40c31f338..3730edd67 100644 --- a/zokrates_core_test/Cargo.toml +++ b/zokrates_core_test/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zokrates_core_test" -version = "0.2.9" +version = "0.2.11" authors = ["schaeff "] edition = "2018" diff --git a/zokrates_core_test/tests/tests/arrays/fun_spread.zok b/zokrates_core_test/tests/tests/arrays/fun_spread.zok index 7a2ccd905..861c05368 100644 --- a/zokrates_core_test/tests/tests/arrays/fun_spread.zok +++ b/zokrates_core_test/tests/tests/arrays/fun_spread.zok @@ -1,6 +1,6 @@ import "utils/pack/bool/nonStrictUnpack256.zok" as unpack256; def main(field[2] inputs) -> bool[512] { - bool[512] preimage512 = [...unpack256(inputs[0]), ...unpack256(inputs[1])]; + bool[512] preimage512 = [...unpack256(inputs[0], 254), ...unpack256(inputs[1], 254)]; return preimage512; } \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/arrays/propagate_multidim.json b/zokrates_core_test/tests/tests/arrays/propagate_multidim.json new file mode 100644 index 000000000..40a30f3ca --- /dev/null +++ b/zokrates_core_test/tests/tests/arrays/propagate_multidim.json @@ -0,0 +1,5 @@ +{ + "curves": ["Bn128"], + "max_constraint_count": 0, + "tests": [] +} diff --git a/zokrates_core_test/tests/tests/arrays/propagate_multidim.zok b/zokrates_core_test/tests/tests/arrays/propagate_multidim.zok new file mode 100644 index 000000000..886b57300 --- /dev/null +++ b/zokrates_core_test/tests/tests/arrays/propagate_multidim.zok @@ -0,0 +1,6 @@ +def main() { + field[2][2] mut a = [[1; 2], [1; 2]]; + a[0][0] = 0; + field[2][2] mut b = [...[[1; 2]; 2]]; + b[0][0] = 0; +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/assembly/assignment.json b/zokrates_core_test/tests/tests/assembly/assignment.json new file mode 100644 index 000000000..ca8f32f11 --- /dev/null +++ b/zokrates_core_test/tests/tests/assembly/assignment.json @@ -0,0 +1,16 @@ +{ + "curves": ["Bn128"], + "max_constraint_count": 4, + "tests": [ + { + "input": { + "values": ["1", "2"] + }, + "output": { + "Ok": { + "value": ["3", "2"] + } + } + } + ] +} diff --git a/zokrates_core_test/tests/tests/assembly/assignment.zok b/zokrates_core_test/tests/tests/assembly/assignment.zok new file mode 100644 index 000000000..8c9bb6dcb --- /dev/null +++ b/zokrates_core_test/tests/tests/assembly/assignment.zok @@ -0,0 +1,15 @@ +def foo(field a, field b) -> field[2] { + field c = a + b; + field d = a * b; + return [c, d]; +} + +def main(field a, field b) -> field[2] { + field[2] mut c = [0; 2]; + asm { + c <-- foo(a, b); + a + b === c[0]; + a * b === c[1]; + } + return c; +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/assembly/composite_assignment.json b/zokrates_core_test/tests/tests/assembly/composite_assignment.json new file mode 100644 index 000000000..7fce10f1a --- /dev/null +++ b/zokrates_core_test/tests/tests/assembly/composite_assignment.json @@ -0,0 +1,16 @@ +{ + "curves": ["Bn128"], + "max_constraint_count": 1, + "tests": [ + { + "input": { + "values": ["2", "2", "4"] + }, + "output": { + "Ok": { + "value": [] + } + } + } + ] +} diff --git a/zokrates_core_test/tests/tests/assembly/composite_assignment.zok b/zokrates_core_test/tests/tests/assembly/composite_assignment.zok new file mode 100644 index 000000000..9bf3af9f8 --- /dev/null +++ b/zokrates_core_test/tests/tests/assembly/composite_assignment.zok @@ -0,0 +1,7 @@ +def main(field a, field b, field c) { + field[2] mut out = [0; 2]; + asm { + out <-- [a, b]; + out[0] * out[1] === c; + } +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/assembly/propagation/array_propagation.json b/zokrates_core_test/tests/tests/assembly/propagation/array_propagation.json new file mode 100644 index 000000000..02caa4e5b --- /dev/null +++ b/zokrates_core_test/tests/tests/assembly/propagation/array_propagation.json @@ -0,0 +1,16 @@ +{ + "curves": ["Bn128"], + "max_constraint_count": 1, + "tests": [ + { + "input": { + "values": ["2"] + }, + "output": { + "Ok": { + "value": "4" + } + } + } + ] +} diff --git a/zokrates_core_test/tests/tests/assembly/propagation/array_propagation.zok b/zokrates_core_test/tests/tests/assembly/propagation/array_propagation.zok new file mode 100644 index 000000000..12fa26c73 --- /dev/null +++ b/zokrates_core_test/tests/tests/assembly/propagation/array_propagation.zok @@ -0,0 +1,12 @@ +def mul(field a, field b) -> field { + field mut res = 0; + asm { + res <== a * b; + } + return res; +} + +def main(field a) -> field { + field[2] b = [2, a]; // this will get propagated in zir + return mul(b[0], b[1]); +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/call_ssa.json b/zokrates_core_test/tests/tests/call_ssa.json new file mode 100644 index 000000000..ae021f62d --- /dev/null +++ b/zokrates_core_test/tests/tests/call_ssa.json @@ -0,0 +1,15 @@ +{ + "max_constraint_count": 1, + "tests": [ + { + "input": { + "values": ["0"] + }, + "output": { + "Ok": { + "value": "4" + } + } + } + ] +} diff --git a/zokrates_core_test/tests/tests/call_ssa.zok b/zokrates_core_test/tests/tests/call_ssa.zok new file mode 100644 index 000000000..dad61d190 --- /dev/null +++ b/zokrates_core_test/tests/tests/call_ssa.zok @@ -0,0 +1,11 @@ +// main should be x -> x + 4 + +def foo(field mut a) -> field { + a = a + 1; + return a + 1; +} + +def main(field mut a) -> field { + a = foo(a + 1); + return a + 1; +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/constant_condition.json b/zokrates_core_test/tests/tests/constant_condition.json new file mode 100644 index 000000000..08b8a0e94 --- /dev/null +++ b/zokrates_core_test/tests/tests/constant_condition.json @@ -0,0 +1,3 @@ +{ + "tests": [] +} diff --git a/zokrates_core_test/tests/tests/constant_condition.zok b/zokrates_core_test/tests/tests/constant_condition.zok new file mode 100644 index 000000000..b42cd3b2c --- /dev/null +++ b/zokrates_core_test/tests/tests/constant_condition.zok @@ -0,0 +1,6 @@ +def main() { + field[2] a = [0; 2]; + for u32 i in 1..2 { + field b = (i == 1) ? 0 : a[i - 2]; + } +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/constants/propagate_embed.json b/zokrates_core_test/tests/tests/constants/propagate_embed.json new file mode 100644 index 000000000..3e1e26856 --- /dev/null +++ b/zokrates_core_test/tests/tests/constants/propagate_embed.json @@ -0,0 +1,5 @@ +{ + "entry_point": "./tests/tests/constants/propagate_embed.zok", + "max_constraint_count": 2, + "tests": [] +} diff --git a/zokrates_core_test/tests/tests/constants/propagate_embed.zok b/zokrates_core_test/tests/tests/constants/propagate_embed.zok new file mode 100644 index 000000000..6bafc7238 --- /dev/null +++ b/zokrates_core_test/tests/tests/constants/propagate_embed.zok @@ -0,0 +1,16 @@ +import "utils/casts/field_to_u32"; +from "EMBED" import unpack; + +def foo() -> field { + return 1; +} + +def main() -> field { + u32 N = field_to_u32(1); + for u32 i in 0..N { + log("{}", i); + } + bool[1] B = unpack(1); + u32 P = B[0] ? 1 : 0; + return foo::() + foo::

(); +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/native_le.zok b/zokrates_core_test/tests/tests/native_le.zok index 74d51a19c..1a70dbe00 100644 --- a/zokrates_core_test/tests/tests/native_le.zok +++ b/zokrates_core_test/tests/tests/native_le.zok @@ -27,7 +27,7 @@ def le(field a, field c) -> bool { return le(a_bits, c_bits); } -// this instanciates comparison starting from u32 +// this instantiates comparison starting from u32 def le(u32 a, u32 c) -> bool { bool[32] a_bits = u32_to_bits(a); bool[32] c_bits = u32_to_bits(c); diff --git a/zokrates_core_test/tests/tests/uint/ch.json b/zokrates_core_test/tests/tests/uint/ch.json index 0039cf2a6..435893ece 100644 --- a/zokrates_core_test/tests/tests/uint/ch.json +++ b/zokrates_core_test/tests/tests/uint/ch.json @@ -1,14 +1,14 @@ { "entry_point": "./tests/tests/uint/ch.zok", - "max_constraint_count": 200, + "max_constraint_count": 132, "tests": [ { "input": { - "values": ["0x00000000", "0x00000000", "0x00000000"] + "values": ["0x0000000f", "0x0000000f", "0x0000000f"] }, "output": { "Ok": { - "value": "0x00000000" + "value": "0x0000000f" } } } diff --git a/zokrates_embed/Cargo.toml b/zokrates_embed/Cargo.toml index 9249b9073..fcff9510e 100644 --- a/zokrates_embed/Cargo.toml +++ b/zokrates_embed/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zokrates_embed" -version = "0.1.8" +version = "0.1.10" authors = ["schaeff "] edition = "2018" @@ -8,8 +8,17 @@ edition = "2018" default = ["ark", "bellman"] ark = ["ark-bls12-377", "ark-bw6-761", "ark-gm17", "ark-relations", "ark-crypto-primitives", "ark-r1cs-std", "ark-std", "ark-ec", "ark-ff", "sapling-crypto_ce"] bellman = ["bellman_ce"] -wasm = ["bellman_ce/wasm", "sapling-crypto_ce/wasm"] -multicore = ["bellman_ce/multicore", "sapling-crypto_ce/multicore"] +wasm = ["bellman_ce/nolog", "bellman_ce/wasm", "sapling-crypto_ce/wasm"] +multicore = [ + "bellman_ce/multicore", + "sapling-crypto_ce/multicore", + "ark-gm17/parallel", + "ark-crypto-primitives/parallel", + "ark-r1cs-std/parallel", + "ark-std/parallel", + "ark-ec/parallel", + "ark-ff/parallel" +] [dependencies] zokrates_field = { version = "0.5.0", path = "../zokrates_field", default-features = false } diff --git a/zokrates_embed/src/ark.rs b/zokrates_embed/src/ark.rs index 40ce41ddd..fa8544962 100644 --- a/zokrates_embed/src/ark.rs +++ b/zokrates_embed/src/ark.rs @@ -279,8 +279,8 @@ fn var_to_index(var: &FpVar, offset: usize) -> usize { fn new_g1(flat: &[T]) -> G1 { assert_eq!(flat.len(), 2); G1::new( - BLS12Fq::from_str(&*flat[0].to_dec_string()).unwrap(), - BLS12Fq::from_str(&*flat[1].to_dec_string()).unwrap(), + BLS12Fq::from_str(&flat[0].to_dec_string()).unwrap(), + BLS12Fq::from_str(&flat[1].to_dec_string()).unwrap(), false, ) } @@ -290,12 +290,12 @@ fn new_g2(flat: &[T]) -> G2 { assert_eq!(flat.len(), 4); G2::new( BLS12Fq2::new( - BLS12Fq::from_str(&*flat[0].to_dec_string()).unwrap(), - BLS12Fq::from_str(&*flat[1].to_dec_string()).unwrap(), + BLS12Fq::from_str(&flat[0].to_dec_string()).unwrap(), + BLS12Fq::from_str(&flat[1].to_dec_string()).unwrap(), ), BLS12Fq2::new( - BLS12Fq::from_str(&*flat[2].to_dec_string()).unwrap(), - BLS12Fq::from_str(&*flat[3].to_dec_string()).unwrap(), + BLS12Fq::from_str(&flat[2].to_dec_string()).unwrap(), + BLS12Fq::from_str(&flat[3].to_dec_string()).unwrap(), ), false, ) diff --git a/zokrates_field/Cargo.toml b/zokrates_field/Cargo.toml index 87c98f369..e00a8250e 100644 --- a/zokrates_field/Cargo.toml +++ b/zokrates_field/Cargo.toml @@ -1,12 +1,14 @@ [package] name = "zokrates_field" -version = "0.5.2" +version = "0.5.5" authors = ["Thibaut Schaeffer ", "Guillaume Ballet "] -edition = "2018" +edition = "2021" [features] -default = ["bellman"] -bellman = ["bellman_ce"] +default = ["bellman_extensions"] +bellperson_extensions = ["bellperson", "pairing", "ff", "pasta_curves", "nova-snark"] +bellman_extensions = ["bellman_ce"] +multicore = ["ark-ff/parallel", "ark-ec/parallel"] [dependencies] serde = "1.0" @@ -21,6 +23,13 @@ num-integer = { version = "0.1", default-features = false } # bellman bellman_ce = { version = "^0.3", default-features = false, optional = true } +# bellperson +bellperson = { version = "0.25", default-features = false, optional = true } +pairing = { version = "0.22", default-features = false, optional = true } +ff = { version = "0.13.0", default-features = false, optional = true } +pasta_curves = { version = "0.5", features = ["repr-c", "serde"], optional = true } +nova-snark = { version = "0.21.0", optional = true } + # ark ark-ff = { version = "^0.3.0", default-features = false } ark-ec = { version = "^0.3.0", default-features = false } @@ -28,7 +37,9 @@ ark-bn254 = { version = "^0.3.0", features = ["curve"], default-features = false ark-bls12-377 = { version = "^0.3.0", features = ["curve"], default-features = false } ark-bls12-381 = { version = "^0.3.0", features = ["curve"] } ark-bw6-761 = { version = "^0.3.0", default-features = false } -ark-serialize = { version = "^0.3.0", default-features = false } +ark-pallas = { version = "^0.3.0", features = ["curve"] } +ark-vesta = { version = "^0.3.0" } +ark-serialize = { version = "^0.3.0", default-features = false, features = ["std"] } [dev-dependencies] rand = "0.4" diff --git a/zokrates_field/src/bls12_377.rs b/zokrates_field/src/bls12_377.rs index 251e0159a..8e74bf9c0 100644 --- a/zokrates_field/src/bls12_377.rs +++ b/zokrates_field/src/bls12_377.rs @@ -1,7 +1,8 @@ use ark_bls12_377::Bls12_377; +use ark_ec::PairingEngine; use crate::G2Type; -prime_field!("bls12_377", Bls12_377, G2Type::Fq2); +prime_field!("bls12_377", ::Fr, G2Type::Fq2); ark_extensions!(Bls12_377); diff --git a/zokrates_field/src/bls12_381.rs b/zokrates_field/src/bls12_381.rs index 403d0b947..9c954039d 100644 --- a/zokrates_field/src/bls12_381.rs +++ b/zokrates_field/src/bls12_381.rs @@ -1,12 +1,13 @@ use ark_bls12_381::Bls12_381; +use ark_ec::PairingEngine; -prime_field!("bls12_381", Bls12_381, G2Type::Fq2); +prime_field!("bls12_381", ::Fr, G2Type::Fq2); ark_extensions!(Bls12_381); -#[cfg(feature = "bellman")] +#[cfg(feature = "bellman_extensions")] use bellman_ce::pairing::bls12_381::{Bls12, Fq2}; use crate::G2Type; -#[cfg(feature = "bellman")] +#[cfg(feature = "bellman_extensions")] bellman_extensions!(Bls12, Fq2); diff --git a/zokrates_field/src/bn128.rs b/zokrates_field/src/bn128.rs index 4b6c9cbb3..129e08afc 100644 --- a/zokrates_field/src/bn128.rs +++ b/zokrates_field/src/bn128.rs @@ -1,14 +1,15 @@ use ark_bn254::Bn254; +use ark_ec::PairingEngine; -prime_field!("bn128", Bn254, G2Type::Fq2); +prime_field!("bn128", ::Fr, G2Type::Fq2); ark_extensions!(Bn254); -#[cfg(feature = "bellman")] +#[cfg(feature = "bellman_extensions")] use bellman_ce::pairing::bn256::{Bn256, Fq2}; use crate::G2Type; -#[cfg(feature = "bellman")] +#[cfg(feature = "bellman_extensions")] bellman_extensions!(Bn256, Fq2); #[cfg(test)] @@ -48,7 +49,7 @@ mod tests { ); assert_eq!( FieldPrime::from("65484493"), - FieldPrime::from("65416358") + &FieldPrime::from("68135") + FieldPrime::from("65416358") + FieldPrime::from("68135") ); } @@ -60,7 +61,7 @@ mod tests { ); assert_eq!( FieldPrime::from("3"), - FieldPrime::from("5") + &FieldPrime::from(-2) + FieldPrime::from("5") + FieldPrime::from(-2) ); } @@ -72,7 +73,7 @@ mod tests { ); assert_eq!( FieldPrime::from("65348223"), - FieldPrime::from("65416358") + &FieldPrime::from(-68135) + FieldPrime::from("65416358") + FieldPrime::from(-68135) ); } @@ -84,7 +85,7 @@ mod tests { ); assert_eq!( FieldPrime::from("65348223"), - FieldPrime::from("65416358") - &FieldPrime::from("68135") + FieldPrime::from("65416358") - FieldPrime::from("68135") ); } @@ -96,7 +97,7 @@ mod tests { ); assert_eq!( FieldPrime::from("65484493"), - FieldPrime::from("65416358") - &FieldPrime::from(-68135) + FieldPrime::from("65416358") - FieldPrime::from(-68135) ); } @@ -112,7 +113,7 @@ mod tests { FieldPrime::from( "21888242871839275222246405745257275088548364400416034343698204186575743147394" ), - FieldPrime::from("68135") - &FieldPrime::from("65416358") + FieldPrime::from("68135") - FieldPrime::from("65416358") ); } @@ -124,7 +125,7 @@ mod tests { ); assert_eq!( FieldPrime::from("13472"), - FieldPrime::from("32") * &FieldPrime::from("421") + FieldPrime::from("32") * FieldPrime::from("421") ); } @@ -140,7 +141,7 @@ mod tests { FieldPrime::from( "21888242871839275222246405745257275088548364400416034343698204186575808014369" ), - FieldPrime::from("54") * &FieldPrime::from(-8912) + FieldPrime::from("54") * FieldPrime::from(-8912) ); } @@ -152,7 +153,7 @@ mod tests { ); assert_eq!( FieldPrime::from("648"), - FieldPrime::from(-54) * &FieldPrime::from(-12) + FieldPrime::from(-54) * FieldPrime::from(-12) ); } @@ -172,7 +173,7 @@ mod tests { ), FieldPrime::from( "21888242871839225222246405785257275088694311157297823662689037894645225727" - ) * &FieldPrime::from("218882428715392752222464057432572755886923") + ) * FieldPrime::from("218882428715392752222464057432572755886923") ); } @@ -184,7 +185,7 @@ mod tests { ); assert_eq!( FieldPrime::from(4), - FieldPrime::from(48) / &FieldPrime::from(12) + FieldPrime::from(48) / FieldPrime::from(12) ); } @@ -290,7 +291,7 @@ mod tests { } } - #[cfg(feature = "bellman")] + #[cfg(feature = "bellman_extensions")] mod bellman { use super::*; @@ -318,7 +319,7 @@ mod tests { let a: Fr = rng.gen(); // now test idempotence let a = FieldPrime::from_bellman(a); - assert_eq!(FieldPrime::from_bellman(a.clone().into_bellman()), a); + assert_eq!(FieldPrime::from_bellman(a.into_bellman()), a); } } diff --git a/zokrates_field/src/bw6_761.rs b/zokrates_field/src/bw6_761.rs index 224331345..8dd1082d3 100644 --- a/zokrates_field/src/bw6_761.rs +++ b/zokrates_field/src/bw6_761.rs @@ -1,7 +1,8 @@ use ark_bw6_761::BW6_761; +use ark_ec::PairingEngine; use crate::G2Type; -prime_field!("bw6_761", BW6_761, G2Type::Fq); +prime_field!("bw6_761", ::Fr, G2Type::Fq); ark_extensions!(BW6_761); diff --git a/zokrates_field/src/dummy_curve.rs b/zokrates_field/src/dummy_curve.rs index 5d3aed4a3..55460f036 100644 --- a/zokrates_field/src/dummy_curve.rs +++ b/zokrates_field/src/dummy_curve.rs @@ -10,7 +10,9 @@ use std::ops::{Add, Div, Mul, Sub}; const _PRIME: u8 = 7; -#[derive(Default, Debug, Hash, Clone, PartialOrd, Ord, Serialize, Deserialize, PartialEq, Eq)] +#[derive( + Default, Debug, Hash, Clone, Copy, PartialOrd, Ord, Serialize, Deserialize, PartialEq, Eq, +)] pub struct FieldPrime { v: u8, } @@ -250,4 +252,12 @@ impl Field for FieldPrime { fn to_biguint(&self) -> num_bigint::BigUint { unimplemented!() } + + fn read(_: R) -> std::io::Result { + unimplemented!() + } + + fn write(&self, _: W) -> std::io::Result<()> { + unimplemented!() + } } diff --git a/zokrates_field/src/lib.rs b/zokrates_field/src/lib.rs index 38f76905b..3308f86cf 100644 --- a/zokrates_field/src/lib.rs +++ b/zokrates_field/src/lib.rs @@ -4,11 +4,10 @@ // @author Jacob Eberhardt // @date 2017 -extern crate num_bigint; - -#[cfg(feature = "bellman")] +#[cfg(feature = "bellman_extensions")] use bellman_ce::pairing::{ff::ScalarEngine, Engine}; - +#[cfg(feature = "bellperson_extensions")] +use nova_snark::provider::pedersen::CommitmentEngine; use num_bigint::BigUint; use num_traits::{CheckedDiv, One, Zero}; use serde::{Deserialize, Serialize}; @@ -16,14 +15,27 @@ use std::convert::{From, TryFrom}; use std::fmt; use std::fmt::{Debug, Display}; use std::hash::Hash; +use std::io::{Read, Write}; use std::ops::{Add, Div, Mul, Sub}; +#[cfg(feature = "bellperson_extensions")] +use nova_snark::traits::Group; + pub trait Pow { type Output; fn pow(self, _: RHS) -> Self::Output; } -#[cfg(feature = "bellman")] +#[cfg(feature = "bellperson_extensions")] +pub trait Cycle { + type Other: Field + BellpersonFieldExtensions + Cycle; + type Point: Group< + Base = <::Point as Group>::Scalar, + CE = CommitmentEngine, + >; +} + +#[cfg(feature = "bellman_extensions")] pub trait BellmanFieldExtensions { /// An associated type to be able to operate with Bellman ff traits type BellmanEngine: Engine; @@ -33,6 +45,14 @@ pub trait BellmanFieldExtensions { fn new_fq2(c0: &str, c1: &str) -> ::Fqe; } +#[cfg(feature = "bellperson_extensions")] +pub trait BellpersonFieldExtensions { + /// An associated type to be able to operate with Bellperson ff traits + type BellpersonField: ff::PrimeField; + + fn from_bellperson(e: Self::BellpersonField) -> Self; + fn into_bellperson(self) -> Self::BellpersonField; +} pub trait ArkFieldExtensions { /// An associated type to be able to operate with ark ff traits type ArkEngine: ark_ec::PairingEngine; @@ -70,6 +90,7 @@ pub trait Field: + Zero + One + Clone + + Copy + PartialEq + Eq + Hash @@ -95,6 +116,10 @@ pub trait Field: + num_traits::CheckedMul { const G2_TYPE: G2Type = G2Type::Fq2; + // Read field from the reader + fn read(reader: R) -> std::io::Result; + // Write field to the writer + fn write(&self, writer: W) -> std::io::Result<()>; /// Returns this `Field`'s contents as little-endian byte vector fn to_byte_vector(&self) -> Vec; /// Returns an element of this `Field` from a little-endian byte vector @@ -144,11 +169,12 @@ mod prime_field { use std::convert::TryFrom; use std::fmt; use std::fmt::{Debug, Display}; + use std::io::{Read, Write}; use std::ops::{Add, Div, Mul, Sub}; - type Fr = <$v as ark_ec::PairingEngine>::Fr; + type Fr = $v; - #[derive(PartialEq, PartialOrd, Clone, Eq, Ord, Hash)] + #[derive(PartialEq, PartialOrd, Clone, Copy, Eq, Ord, Hash)] pub struct FieldPrime { v: Fr, } @@ -186,9 +212,21 @@ mod prime_field { self.v.into_repr().to_bytes_le() } - fn from_byte_vector(bytes: Vec) -> Self { + fn read(reader: R) -> std::io::Result { use ark_ff::FromBytes; + Ok(FieldPrime { + v: Fr::read(reader)?, + }) + } + + fn write(&self, mut writer: W) -> std::io::Result<()> { + use ark_ff::ToBytes; + self.v.write(&mut writer)?; + Ok(()) + } + fn from_byte_vector(bytes: Vec) -> Self { + use ark_ff::FromBytes; FieldPrime { v: Fr::from(::BigInt::read(&bytes[..]).unwrap()), } @@ -574,7 +612,7 @@ mod prime_field { }; } - #[cfg(feature = "bellman")] + #[cfg(feature = "bellman_extensions")] macro_rules! bellman_extensions { ($bellman_type:ty, $fq2_type:ident) => { use crate::BellmanFieldExtensions; @@ -591,9 +629,12 @@ mod prime_field { } fn into_bellman(self) -> ::Fr { - use bellman_ce::pairing::ff::PrimeField; - let s = self.to_dec_string(); - ::Fr::from_str(&s).unwrap() + use bellman_ce::pairing::ff::{PrimeField, PrimeFieldRepr}; + let bytes = self.to_byte_vector(); + let mut repr = + <::Fr as PrimeField>::Repr::default(); + repr.read_le(bytes.as_slice()).unwrap(); + ::Fr::from_repr(repr).unwrap() } fn new_fq2( @@ -609,6 +650,29 @@ mod prime_field { }; } + #[cfg(feature = "bellperson")] + macro_rules! bellperson_extensions { + ($bellperson_type:ty) => { + use crate::BellpersonFieldExtensions; + + impl BellpersonFieldExtensions for FieldPrime { + type BellpersonField = $bellperson_type; + + fn from_bellperson(e: Self::BellpersonField) -> Self { + use ff::PrimeField; + let res = e.to_repr().to_vec(); + Self::from_byte_vector(res) + } + + fn into_bellperson(self) -> Self::BellpersonField { + use ff::PrimeField; + let bytes = self.to_byte_vector(); + Self::BellpersonField::from_repr_vartime(bytes.try_into().unwrap()).unwrap() + } + } + }; + } + macro_rules! ark_extensions { ($ark_type:ty) => { use crate::ArkFieldExtensions; @@ -633,9 +697,13 @@ pub mod bls12_381; pub mod bn128; pub mod bw6_761; pub mod dummy_curve; +pub mod pallas; +pub mod vesta; pub use bls12_377::FieldPrime as Bls12_377Field; pub use bls12_381::FieldPrime as Bls12_381Field; pub use bn128::FieldPrime as Bn128Field; pub use bw6_761::FieldPrime as Bw6_761Field; pub use dummy_curve::FieldPrime as DummyCurveField; +pub use pallas::FieldPrime as PallasField; +pub use vesta::FieldPrime as VestaField; diff --git a/zokrates_field/src/pallas.rs b/zokrates_field/src/pallas.rs new file mode 100644 index 000000000..251a12c62 --- /dev/null +++ b/zokrates_field/src/pallas.rs @@ -0,0 +1,19 @@ +use ark_pallas::Fr as PallasBaseField; +#[cfg(feature = "bellperson_extensions")] +use pasta_curves::Fq; + +#[cfg(feature = "bellperson_extensions")] +use crate::{Cycle, VestaField}; + +use crate::G2Type; + +#[cfg(feature = "bellperson_extensions")] +impl Cycle for FieldPrime { + type Other = VestaField; + type Point = pasta_curves::pallas::Point; +} + +prime_field!("pallas", PallasBaseField, G2Type::Fq2); + +#[cfg(feature = "bellperson_extensions")] +bellperson_extensions!(Fq); diff --git a/zokrates_field/src/vesta.rs b/zokrates_field/src/vesta.rs new file mode 100644 index 000000000..1cc17553a --- /dev/null +++ b/zokrates_field/src/vesta.rs @@ -0,0 +1,19 @@ +use ark_vesta::Fr as VestaBaseField; +#[cfg(feature = "bellperson_extensions")] +use pasta_curves::Fp; + +#[cfg(feature = "bellperson_extensions")] +use crate::{Cycle, PallasField}; + +use crate::G2Type; + +#[cfg(feature = "bellperson_extensions")] +impl Cycle for FieldPrime { + type Other = PallasField; + type Point = pasta_curves::vesta::Point; +} + +prime_field!("vesta", VestaBaseField, G2Type::Fq2); + +#[cfg(feature = "bellperson_extensions")] +bellperson_extensions!(Fp); diff --git a/zokrates_interpreter/Cargo.toml b/zokrates_interpreter/Cargo.toml index 7e36f1f9f..756ccd6a4 100644 --- a/zokrates_interpreter/Cargo.toml +++ b/zokrates_interpreter/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "zokrates_interpreter" -version = "0.1.1" +version = "0.1.5" edition = "2021" [features] default = ["bellman", "ark"] -bellman = ["zokrates_field/bellman", "pairing_ce", "zokrates_embed/bellman", "zokrates_ast/bellman"] -ark = ["ark-bls12-377", "zokrates_embed/ark", "zokrates_ast/ark"] +bellman = ["zokrates_field/bellman_extensions", "pairing_ce", "zokrates_embed/bellman", "zokrates_ast/bellman", "zokrates_analysis/bellman"] +ark = ["ark-bls12-377", "zokrates_embed/ark", "zokrates_ast/ark", "zokrates_analysis/ark"] [dependencies] zokrates_field = { version = "0.5", path = "../zokrates_field", default-features = false } @@ -14,14 +14,9 @@ zokrates_ast = { version = "0.1", path = "../zokrates_ast", default-features = f zokrates_embed = { version = "0.1.0", path = "../zokrates_embed", default-features = false } zokrates_abi = { version = "0.1", path = "../zokrates_abi", default-features = false } zokrates_analysis = { version = "0.1", path = "../zokrates_analysis", default-features = false } - num = { version = "0.1.36", default-features = false } num-bigint = { version = "0.2", default-features = false } - ark-bls12-377 = { version = "^0.3.0", features = ["curve"], default-features = false, optional = true } - pairing_ce = { version = "^0.21", optional = true } - - serde = { version = "1.0", features = ["derive"] } diff --git a/zokrates_interpreter/src/lib.rs b/zokrates_interpreter/src/lib.rs index f33ab3de4..733b453c2 100644 --- a/zokrates_interpreter/src/lib.rs +++ b/zokrates_interpreter/src/lib.rs @@ -1,11 +1,12 @@ use serde::{Deserialize, Serialize}; +use std::borrow::Borrow; use std::collections::HashMap; use std::fmt; use zokrates_abi::{Decode, Value}; use zokrates_ast::ir::{ - LinComb, ProgIterator, QuadComb, RuntimeError, Solver, Statement, Variable, Witness, + LinComb, Parameter, QuadComb, RuntimeError, Solver, Statement, Variable, Witness, }; -use zokrates_ast::zir; +use zokrates_ast::zir::{self, Expr}; use zokrates_field::Field; pub type ExecutionResult = Result, Error>; @@ -13,7 +14,7 @@ pub type ExecutionResult = Result, Error>; #[derive(Default)] pub struct Interpreter { /// Whether we should try to give out-of-range bit decompositions when the input is not a single summand. - /// Used to do targetted testing of `<` flattening, making sure the bit decomposition we base the result on is unique. + /// Used to do targeted testing of `<` flattening, making sure the bit decomposition we base the result on is unique. should_try_out_of_range: bool, } @@ -26,46 +27,59 @@ impl Interpreter { } impl Interpreter { - pub fn execute<'ast, T: Field, I: IntoIterator>>( + pub fn execute<'ast, T: Field, S: Borrow>>( &self, - program: ProgIterator<'ast, T, I>, inputs: &[T], + statements: impl Iterator, + arguments: &[Parameter], + solvers: &[Solver<'ast, T>], ) -> ExecutionResult { - self.execute_with_log_stream(program, inputs, &mut std::io::sink()) + self.execute_with_log_stream(inputs, statements, arguments, solvers, &mut std::io::sink()) } pub fn execute_with_log_stream< 'ast, + 'a, W: std::io::Write, T: Field, - I: IntoIterator>, + S: Borrow>, >( &self, - program: ProgIterator<'ast, T, I>, inputs: &[T], + statements: impl Iterator, + arguments: &[Parameter], + solvers: &[Solver<'ast, T>], log_stream: &mut W, ) -> ExecutionResult { - self.check_inputs(&program, inputs)?; + if arguments.len() != inputs.len() { + return Err(Error::WrongInputCount { + expected: arguments.len(), + received: inputs.len(), + }); + }; + let mut witness = Witness::default(); witness.insert(Variable::one(), T::one()); - for (arg, value) in program.arguments.iter().zip(inputs.iter()) { - witness.insert(arg.id, value.clone()); + for (arg, value) in arguments.iter().zip(inputs.iter()) { + witness.insert(arg.id, *value); } - for statement in program.statements.into_iter() { - match statement { + for statement in statements { + match statement.borrow() { Statement::Block(..) => unreachable!(), - Statement::Constraint(quad, lin, error) => match lin.is_assignee(&witness) { + Statement::Constraint(s) => match s.lin.is_assignee(&witness) { true => { - let val = evaluate_quad(&witness, &quad).unwrap(); - witness.insert(lin.0.get(0).unwrap().0, val); + let val = evaluate_quad(&witness, &s.quad).unwrap(); + witness.insert(s.lin.value.get(0).unwrap().0, val); } false => { - let lhs_value = evaluate_quad(&witness, &quad).unwrap(); - let rhs_value = evaluate_lin(&witness, &lin).unwrap(); + let lhs_value = evaluate_quad(&witness, &s.quad).unwrap(); + let rhs_value = evaluate_lin(&witness, &s.lin).unwrap(); if lhs_value != rhs_value { - return Err(Error::UnsatisfiedConstraint { error }); + return Err(Error::UnsatisfiedConstraint { + error: s.error.clone(), + }); } } }, @@ -83,28 +97,32 @@ impl Interpreter { inputs.pop().unwrap(), )) } - _ => Self::execute_solver(&d.solver, &inputs), + _ => Self::execute_solver(&d.solver, &inputs, solvers), } .map_err(Error::Solver)?; for (i, o) in d.outputs.iter().enumerate() { - witness.insert(*o, res[i].clone()); + witness.insert(*o, res[i]); } } - Statement::Log(l, expressions) => { - let mut parts = l.parts.into_iter(); + Statement::Log(s) => { + let mut parts = s.format_string.parts.iter(); write!(log_stream, "{}", parts.next().unwrap()) .map_err(|_| Error::LogStream)?; - for ((t, e), part) in expressions.into_iter().zip(parts) { + for ((t, e), part) in s.expressions.iter().zip(parts) { let values: Vec<_> = e .iter() .map(|e| evaluate_lin(&witness, e).unwrap()) .collect(); - write!(log_stream, "{}", Value::decode(values, t).into_serde_json()) - .map_err(|_| Error::LogStream)?; + write!( + log_stream, + "{}", + Value::decode(values, t.clone()).into_serde_json() + ) + .map_err(|_| Error::LogStream)?; write!(log_stream, "{}", part).map_err(|_| Error::LogStream)?; } @@ -146,25 +164,18 @@ impl Interpreter { .collect() } - fn check_inputs<'ast, T: Field, I: IntoIterator>, U>( - &self, - program: &ProgIterator<'ast, T, I>, - inputs: &[U], - ) -> Result<(), Error> { - if program.arguments.len() == inputs.len() { - Ok(()) - } else { - Err(Error::WrongInputCount { - expected: program.arguments.len(), - received: inputs.len(), - }) - } - } - pub fn execute_solver<'ast, T: Field>( solver: &Solver<'ast, T>, inputs: &[T], + solvers: &[Solver<'ast, T>], ) -> Result, String> { + let solver = match solver { + Solver::Ref(call) => solvers + .get(call.index) + .ok_or_else(|| format!("Could not get solver at index {}", call.index))?, + s => s, + }; + let (expected_input_count, expected_output_count) = solver.get_signature(); assert_eq!(inputs.len(), expected_input_count); @@ -177,26 +188,26 @@ impl Interpreter { .arguments .iter() .zip(inputs) - .map(|(a, v)| match &a.id._type { + .map(|(a, v)| match &a.id.ty { zir::Type::FieldElement => Ok(( a.id.id.clone(), - zokrates_ast::zir::FieldElementExpression::Number(v.clone()).into(), + zokrates_ast::zir::FieldElementExpression::value(*v).into(), )), zir::Type::Boolean => match v { v if *v == T::from(0) => Ok(( a.id.id.clone(), - zokrates_ast::zir::BooleanExpression::Value(false).into(), + zokrates_ast::zir::BooleanExpression::value(false).into(), )), v if *v == T::from(1) => Ok(( a.id.id.clone(), - zokrates_ast::zir::BooleanExpression::Value(true).into(), + zokrates_ast::zir::BooleanExpression::value(true).into(), )), v => Err(format!("`{}` has unexpected value `{}`", a.id, v)), }, zir::Type::Uint(bitwidth) => match v.bits() <= bitwidth.to_usize() as u32 { true => Ok(( a.id.id.clone(), - zokrates_ast::zir::UExpressionInner::Value( + zokrates_ast::zir::UExpression::value( v.to_dec_string().parse::().unwrap(), ) .annotate(*bitwidth) @@ -222,11 +233,12 @@ impl Interpreter { if let zokrates_ast::zir::ZirStatement::Return(v) = folded_function.statements[0].clone() { - v.into_iter() + v.inner + .into_iter() .map(|v| match v { zokrates_ast::zir::ZirExpression::FieldElement( - zokrates_ast::zir::FieldElementExpression::Number(n), - ) => n, + zokrates_ast::zir::FieldElementExpression::Value(n), + ) => n.value, _ => unreachable!(), }) .collect() @@ -256,41 +268,38 @@ impl Interpreter { .collect() } Solver::Xor => { - let x = inputs[0].clone(); - let y = inputs[1].clone(); + let x = inputs[0]; + let y = inputs[1]; - vec![x.clone() + y.clone() - T::from(2) * x * y] + vec![x + y - T::from(2) * x * y] } Solver::Or => { - let x = inputs[0].clone(); - let y = inputs[1].clone(); + let x = inputs[0]; + let y = inputs[1]; - vec![x.clone() + y.clone() - x * y] + vec![x + y - 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] + let a = inputs[0]; + let b = inputs[1]; + let c = inputs[2]; + vec![b * c - (T::from(2) * b * c - 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] + let a = inputs[0]; + let b = inputs[1]; + let c = inputs[2]; + vec![a * (b - c) + c] } - Solver::Div => vec![inputs[0] - .clone() - .checked_div(&inputs[1]) - .unwrap_or_else(T::one)], + Solver::Div => vec![inputs[0].checked_div(&inputs[1]).unwrap_or_else(T::one)], Solver::EuclideanDiv => { use num::CheckedDiv; - let n = inputs[0].clone().to_biguint(); - let d = inputs[1].clone().to_biguint(); + let n = inputs[0].to_biguint(); + let d = inputs[1].to_biguint(); let q = n.checked_div(&d).unwrap_or_else(|| 0u32.into()); let r = n - d * &q; @@ -334,6 +343,7 @@ impl Interpreter { &inputs[*n + 8usize..], ) } + _ => unreachable!("unexpected solver"), }; assert_eq!(res.len(), expected_output_count); @@ -354,14 +364,11 @@ pub enum Error { } fn evaluate_lin(w: &Witness, l: &LinComb) -> Result { - l.0.iter() - .map(|(var, mult)| { - w.0.get(var) - .map(|v| v.clone() * mult) - .ok_or(EvaluationError) - }) // get each term - .collect::, _>>() // fail if any term isn't found - .map(|v| v.iter().fold(T::from(0), |acc, t| acc + t)) // return the sum + l.value.iter().try_fold(T::from(0), |acc, (var, mult)| { + w.0.get(var) + .map(|v| acc + (*v * mult)) + .ok_or(EvaluationError) // fail if any term isn't found + }) } pub fn evaluate_quad(w: &Witness, q: &QuadComb) -> Result { @@ -434,6 +441,7 @@ mod tests { .iter() .map(|&i| Bn128Field::from(i)) .collect::>(), + &[], ) .unwrap(); let res: Vec = vec![0, 1].iter().map(|&i| Bn128Field::from(i)).collect(); @@ -450,6 +458,7 @@ mod tests { .iter() .map(|&i| Bn128Field::from(i)) .collect::>(), + &[], ) .unwrap(); let res: Vec = vec![1, 1].iter().map(|&i| Bn128Field::from(i)).collect(); @@ -460,9 +469,12 @@ mod tests { #[test] fn bits_of_one() { let inputs = vec![Bn128Field::from(1)]; - let res = - Interpreter::execute_solver(&Solver::Bits(Bn128Field::get_required_bits()), &inputs) - .unwrap(); + let res = Interpreter::execute_solver( + &Solver::Bits(Bn128Field::get_required_bits()), + &inputs, + &[], + ) + .unwrap(); assert_eq!(res[253], Bn128Field::from(1)); for r in &res[0..253] { assert_eq!(*r, Bn128Field::from(0)); @@ -472,9 +484,12 @@ mod tests { #[test] fn bits_of_42() { let inputs = vec![Bn128Field::from(42)]; - let res = - Interpreter::execute_solver(&Solver::Bits(Bn128Field::get_required_bits()), &inputs) - .unwrap(); + 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)); @@ -487,11 +502,54 @@ mod tests { #[test] fn five_hundred_bits_of_1() { let inputs = vec![Bn128Field::from(1)]; - let res = Interpreter::execute_solver(&Solver::Bits(500), &inputs).unwrap(); + let res = Interpreter::execute_solver(&Solver::Bits(500), &inputs, &[]).unwrap(); let mut expected = vec![Bn128Field::from(0); 500]; expected[499] = Bn128Field::from(1); assert_eq!(res, expected); } + + #[test] + fn solver_ref() { + use std::ops::Mul; + use zir::{ + types::{Signature, Type}, + FieldElementExpression, Identifier, IdentifierExpression, Parameter, Variable, + ZirFunction, ZirStatement, + }; + use zokrates_ast::common::RefCall; + + let id = IdentifierExpression::new(Identifier::internal(0usize)); + + // (field i0) -> i0 * i0 + let solver = Solver::Zir(ZirFunction { + arguments: vec![Parameter::new(Variable::field_element(id.id.clone()), true)], + statements: vec![ZirStatement::ret(vec![FieldElementExpression::mul( + FieldElementExpression::Identifier(id.clone()), + FieldElementExpression::Identifier(id.clone()), + ) + .into()])], + signature: Signature::new() + .inputs(vec![Type::FieldElement]) + .outputs(vec![Type::FieldElement]), + }); + + let signature = solver.get_signature(); + let solvers = vec![solver]; + + let inputs = vec![Bn128Field::from(2)]; + let res = Interpreter::execute_solver( + &Solver::Ref(RefCall { + index: 0, + signature, + }), + &inputs, + &solvers, + ) + .unwrap(); + + let expected = vec![Bn128Field::from(4)]; + assert_eq!(res, expected); + } } diff --git a/zokrates_js/.gitignore b/zokrates_js/.gitignore index cd9aa5f80..07ba096de 100644 --- a/zokrates_js/.gitignore +++ b/zokrates_js/.gitignore @@ -3,6 +3,6 @@ dist target pkg wasm-pack.log -stdlib -stdlib.js -metadata.js \ No newline at end of file +metadata.js +wasm.js +umd.min.js \ No newline at end of file diff --git a/zokrates_js/Cargo.toml b/zokrates_js/Cargo.toml index feb949d17..2ff4f49e0 100644 --- a/zokrates_js/Cargo.toml +++ b/zokrates_js/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zokrates_js" -version = "1.1.4" +version = "1.1.8" authors = ["Darko Macesic"] edition = "2018" @@ -8,25 +8,32 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -js-sys = "0.3.33" +js-sys = "=0.3.58" serde = { version = "^1.0.59", features = ["derive"] } serde_json = { version = "1.0", features = ["preserve_order"] } -wasm-bindgen = { version = "0.2.46", features = ["serde-serialize"] } +wasm-bindgen = { version = "=0.2.81", features = ["serde-serialize"] } typed-arena = "1.4.1" lazy_static = "1.4.0" +zokrates_field = { path = "../zokrates_field" } +rand_0_8 = { version = "0.8", package = "rand" } +getrandom = { version = "0.2.8", features = ["js"] } zokrates_core = { path = "../zokrates_core", default-features = false, features = ["ark", "bellman"] } -zokrates_ark = { path = "../zokrates_ark", default-features = false} -zokrates_bellman = { path = "../zokrates_bellman", default-features = false} +zokrates_ark = { path = "../zokrates_ark", default-features = false } +zokrates_embed = { path = "../zokrates_embed", default-features = false } +zokrates_bellman = { path = "../zokrates_bellman", default-features = false } zokrates_common = { path = "../zokrates_common", default-features = false, features = ["ark", "bellman"] } zokrates_proof_systems = { path = "../zokrates_proof_systems", default-features = false } zokrates_ast = { path = "../zokrates_ast", default-features = false, features = ["ark", "bellman"] } zokrates_interpreter = { path = "../zokrates_interpreter", default-features = false, features = ["ark", "bellman"] } -zokrates_field = { path = "../zokrates_field", default-features = false } zokrates_abi = { path = "../zokrates_abi", default-features = false, features = ["ark", "bellman"] } zokrates_circom = { path = "../zokrates_circom" } console_error_panic_hook = "0.1.6" indexmap = "~1.6.2" # see https://github.com/rustwasm/wasm-bindgen/issues/2770#issuecomment-1041102532 +[target.'cfg(target_arch = "wasm32")'.dependencies] +zokrates_embed = { path = "../zokrates_embed", features = ["wasm"] } +zokrates_bellman = { path = "../zokrates_bellman", features = ["wasm"] } + [build-dependencies] json = "0.12.4" walkdir = "2.3.2" diff --git a/zokrates_js/README.md b/zokrates_js/README.md index 8fbbd0007..21911e6cf 100644 --- a/zokrates_js/README.md +++ b/zokrates_js/README.md @@ -6,4 +6,4 @@ JavaScript bindings for [ZoKrates](https://github.com/Zokrates/ZoKrates) project npm install zokrates-js ``` -Check the offical [ZoKrates documentation](https://zokrates.github.io/toolbox/zokrates_js.html) for more details. +Check the official [ZoKrates documentation](https://zokrates.github.io/toolbox/zokrates_js.html) for more details. diff --git a/zokrates_js/build.rs b/zokrates_js/build.rs index 5eea2bc9d..45d38a383 100644 --- a/zokrates_js/build.rs +++ b/zokrates_js/build.rs @@ -40,9 +40,5 @@ fn export_metadata() { .insert("version", config["package"]["version"].as_str().unwrap()) .unwrap(); - fs::write( - "metadata.js", - format!("module.exports = {}", metadata.dump()), - ) - .unwrap(); + fs::write("metadata.js", format!("export default {}", metadata.dump())).unwrap(); } diff --git a/zokrates_js/index-node.js b/zokrates_js/index-node.js new file mode 100644 index 000000000..566a24632 --- /dev/null +++ b/zokrates_js/index-node.js @@ -0,0 +1,5 @@ +// https://docs.rs/getrandom/0.2.8/getrandom/index.html#nodejs-es-module-support +import { webcrypto } from "node:crypto"; +globalThis.crypto = webcrypto; + +export * from "./index.js"; diff --git a/zokrates_js/index.d.ts b/zokrates_js/index.d.ts index 7c7bc8e05..ff7cba246 100644 --- a/zokrates_js/index.d.ts +++ b/zokrates_js/index.d.ts @@ -42,7 +42,7 @@ declare module "zokrates-js" { } export interface ComputationResult { - witness: string; + witness: Uint8Array; output: string; snarkjs?: { witness: Uint8Array; @@ -85,13 +85,14 @@ declare module "zokrates-js" { args: any[], options?: ComputeOptions ): ComputationResult; - setup(program: Uint8Array): SetupKeypair; - universalSetup(size: number): Uint8Array; + setup(program: Uint8Array, entropy?: string): SetupKeypair; + universalSetup(size: number, entropy?: string): Uint8Array; setupWithSrs(srs: Uint8Array, program: Uint8Array): SetupKeypair; generateProof( program: Uint8Array, - witness: string, - provingKey: Uint8Array + witness: Uint8Array, + provingKey: Uint8Array, + entropy?: string ): Proof; verify(verificationKey: VerificationKey, proof: Proof): boolean; exportSolidityVerifier(verificationKey: VerificationKey): string; diff --git a/zokrates_js/index.js b/zokrates_js/index.js index 2d7b9514c..55a7dbda6 100644 --- a/zokrates_js/index.js +++ b/zokrates_js/index.js @@ -1,9 +1,151 @@ -import lib from "./lib.js"; +import { inflate } from "pako"; import metadata from "./metadata.js"; +import * as wasmExports from "./wasm.js"; const initialize = async () => { - const pkg = await import("./pkg/index.js"); - return lib(pkg); + await wasmExports.init(inflate); + + const defaultProvider = { + compile: (source, compileOptions = {}) => { + var { + curve = "bn128", + location = "main.zok", + resolveCallback = () => null, + config = {}, + snarkjs = false, + } = compileOptions; + + config = { snarkjs, ...config }; + + const ptr = wasmExports.compile( + source, + location, + resolveCallback, + config, + curve + ); + const result = Object.assign( + { + program: ptr.program(), + abi: ptr.abi(), + constraintCount: ptr.constraint_count(), + }, + snarkjs ? { snarkjs: { program: ptr.snarkjs_program() } } : {} + ); + ptr.free(); + return result; + }, + computeWitness: (input, args, computeOptions = {}) => { + const { program, abi } = + input instanceof Uint8Array ? { program: input, abi: null } : input; + + const { snarkjs = false, logCallback = console.log } = computeOptions; + const ptr = wasmExports.compute_witness( + program, + abi, + JSON.stringify(args), + { + snarkjs: snarkjs, + }, + logCallback + ); + + const result = Object.assign( + { + witness: ptr.witness(), + output: ptr.output(), + }, + snarkjs + ? { + snarkjs: { + witness: ptr.snarkjs_witness(), + }, + } + : {} + ); + + ptr.free(); + return result; + }, + setup: (program, entropy, options) => { + const ptr = wasmExports.setup(program, entropy, options); + const result = { + vk: ptr.vk(), + pk: ptr.pk(), + }; + ptr.free(); + return result; + }, + universalSetup: (curve, size, entropy) => { + return wasmExports.universal_setup(curve, size, entropy); + }, + setupWithSrs: (srs, program, options) => { + const ptr = wasmExports.setup_with_srs(srs, program, options); + const result = { + vk: ptr.vk(), + pk: ptr.pk(), + }; + ptr.free(); + return result; + }, + generateProof: (program, witness, provingKey, entropy, options) => { + return wasmExports.generate_proof( + program, + witness, + provingKey, + entropy, + options + ); + }, + verify: (vk, proof, options) => { + return wasmExports.verify(vk, proof, options); + }, + exportSolidityVerifier: (vk) => { + return wasmExports.export_solidity_verifier(vk); + }, + utils: { + formatProof: (proof) => { + return wasmExports.format_proof(proof); + }, + }, + }; + + const withOptions = (options) => { + return { + withOptions, + compile: (source, compileOptions = {}) => + defaultProvider.compile(source, { + ...compileOptions, + curve: options.curve, + }), + computeWitness: (artifacts, args, computeOptions = {}) => + defaultProvider.computeWitness(artifacts, args, computeOptions), + setup: (program, entropy) => + defaultProvider.setup(program, entropy, options), + universalSetup: (size, entropy) => + defaultProvider.universalSetup(options.curve, size, entropy), + setupWithSrs: (srs, program) => + defaultProvider.setupWithSrs(srs, program, options), + generateProof: (program, witness, provingKey, entropy) => + defaultProvider.generateProof( + program, + witness, + provingKey, + entropy, + options + ), + verify: (vk, proof) => defaultProvider.verify(vk, proof, options), + exportSolidityVerifier: (vk) => + defaultProvider.exportSolidityVerifier(vk), + utils: { + formatProof: (proof) => defaultProvider.utils.formatProof(proof), + }, + }; + }; + + return { + ...withOptions({ backend: "ark", scheme: "g16", curve: "bn128" }), + }; }; export { initialize, metadata }; diff --git a/zokrates_js/lib.js b/zokrates_js/lib.js deleted file mode 100644 index b3e1ff4ef..000000000 --- a/zokrates_js/lib.js +++ /dev/null @@ -1,112 +0,0 @@ -module.exports = (pkg) => { - const defaultProvider = { - compile: (source, compileOptions = {}) => { - var { - curve = "bn128", - location = "main.zok", - resolveCallback = () => null, - config = {}, - snarkjs = false, - } = compileOptions; - - config = { snarkjs, ...config }; - - const ptr = pkg.compile(source, location, resolveCallback, config, curve); - const result = Object.assign( - { - program: ptr.program(), - abi: ptr.abi(), - constraintCount: ptr.constraint_count(), - }, - snarkjs ? { snarkjs: { program: ptr.snarkjs_program() } } : {} - ); - ptr.free(); - return result; - }, - computeWitness: (input, args, computeOptions = {}) => { - const { program, abi } = - input instanceof Uint8Array ? { program: input, abi: null } : input; - - const { snarkjs = false, logCallback = console.log } = computeOptions; - const ptr = pkg.compute_witness( - program, - abi, - JSON.stringify(args), - { - snarkjs: snarkjs, - }, - logCallback - ); - - const result = Object.assign( - { - witness: ptr.witness(), - output: ptr.output(), - }, - snarkjs - ? { - snarkjs: { - witness: ptr.snarkjs_witness(), - }, - } - : {} - ); - - ptr.free(); - return result; - }, - setup: (program, options) => { - return pkg.setup(program, options); - }, - universalSetup: (curve, size) => { - return pkg.universal_setup(curve, size); - }, - setupWithSrs: (srs, program, options) => { - return pkg.setup_with_srs(srs, program, options); - }, - generateProof: (program, witness, provingKey, options) => { - return pkg.generate_proof(program, witness, provingKey, options); - }, - verify: (vk, proof, options) => { - return pkg.verify(vk, proof, options); - }, - exportSolidityVerifier: (vk) => { - return pkg.export_solidity_verifier(vk); - }, - utils: { - formatProof: (proof) => { - return pkg.format_proof(proof); - }, - }, - }; - - const withOptions = (options) => { - return { - withOptions, - compile: (source, compileOptions = {}) => - defaultProvider.compile(source, { - ...compileOptions, - curve: options.curve, - }), - computeWitness: (artifacts, args, computeOptions = {}) => - defaultProvider.computeWitness(artifacts, args, computeOptions), - setup: (program) => defaultProvider.setup(program, options), - universalSetup: (size) => - defaultProvider.universalSetup(options.curve, size), - setupWithSrs: (srs, program) => - defaultProvider.setupWithSrs(srs, program, options), - generateProof: (program, witness, provingKey) => - defaultProvider.generateProof(program, witness, provingKey, options), - verify: (vk, proof) => defaultProvider.verify(vk, proof, options), - exportSolidityVerifier: (vk) => - defaultProvider.exportSolidityVerifier(vk), - utils: { - formatProof: (proof) => defaultProvider.utils.formatProof(proof), - }, - }; - }; - - return { - ...withOptions({ backend: "ark", scheme: "g16", curve: "bn128" }), - }; -}; diff --git a/zokrates_js/node/index.js b/zokrates_js/node/index.js deleted file mode 100644 index d6d50f3ba..000000000 --- a/zokrates_js/node/index.js +++ /dev/null @@ -1,8 +0,0 @@ -const lib = require("../lib.js"); -const metadata = require("../metadata.js"); - -const initialize = async () => { - return lib(require("./pkg/index.js")); -}; - -module.exports = { initialize, metadata }; diff --git a/zokrates_js/package-lock.json b/zokrates_js/package-lock.json index b15cb706f..4c3f24745 100644 --- a/zokrates_js/package-lock.json +++ b/zokrates_js/package-lock.json @@ -1,2205 +1,5544 @@ { "name": "zokrates-js", - "version": "1.1.4", - "lockfileVersion": 2, + "version": "1.1.5", + "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "zokrates-js", - "version": "1.1.2", + "version": "1.1.5", "license": "GPLv3", + "dependencies": { + "pako": "^2.1.0" + }, "devDependencies": { - "dree": "^2.6.1", + "@babel/core": "^7.20.12", + "@babel/preset-env": "^7.20.2", + "acorn": "^8.8.1", + "astring": "^1.8.4", + "babelify": "^10.0.0", + "browserify": "^17.0.0", + "dree": "^3.4.3", "mocha": "^9.2.0", + "puppeteer": "^19.6.0", "rimraf": "^3.0.2", "snarkjs": "^0.4.25", + "uglify-js": "^3.17.4", "wasm-pack": "^0.10.2" } }, - "node_modules/@iden3/bigarray": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/@iden3/bigarray/-/bigarray-0.0.2.tgz", - "integrity": "sha512-Xzdyxqm1bOFF6pdIsiHLLl3HkSLjbhqJHVyqaTxXt3RqXBEnmsUmEW47H7VOi/ak7TdkRpNkxjyK5Zbkm+y52g==", - "dev": true - }, - "node_modules/@iden3/binfileutils": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/@iden3/binfileutils/-/binfileutils-0.0.11.tgz", - "integrity": "sha512-LylnJoZ0CTdgErnKY8OxohvW4K+p6UHD3sxt+3P9AmMyBQjYR4IpoqoYZZ+9aMj89cmCQ21UvdhndAx04er3NA==", + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", "dev": true, "dependencies": { - "fastfile": "0.0.20", - "ffjavascript": "^0.2.48" + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" } }, - "node_modules/@ungap/promise-all-settled": { - "version": "1.1.2", + "node_modules/@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", "dev": true, - "license": "ISC" + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/@babel/compat-data": { + "version": "7.20.14", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.14.tgz", + "integrity": "sha512-0YpKHD6ImkWMEINCyDAD0HLLUH/lPCefG8ld9it8DJB2wnApraKuhgYTvTY1z7UFIfBTGy5LwncZ+5HWWGbhFw==", "dev": true, "engines": { - "node": ">=8" + "node": ">=6.9.0" } }, - "node_modules/ansi-styles": { - "version": "4.3.0", + "node_modules/@babel/core": { + "version": "7.20.12", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.12.tgz", + "integrity": "sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==", "dev": true, - "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.7", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helpers": "^7.20.7", + "@babel/parser": "^7.20.7", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.12", + "@babel/types": "^7.20.7", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.2", + "semver": "^6.3.0" }, "engines": { - "node": ">=8" + "node": ">=6.9.0" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/babel" } }, - "node_modules/argparse": { - "version": "2.0.1", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/async": { - "version": "3.2.3", + "node_modules/@babel/generator": { + "version": "7.20.14", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz", + "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==", "dev": true, - "license": "MIT" + "dependencies": { + "@babel/types": "^7.20.7", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } }, - "node_modules/axios": { - "version": "0.21.4", + "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", "dev": true, - "license": "MIT", "dependencies": { - "follow-redirects": "^1.14.0" + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" } }, - "node_modules/b4a": { - "version": "1.5.3", + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", + "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", "dev": true, - "license": "ISC" + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } }, - "node_modules/balanced-match": { - "version": "1.0.0", + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", + "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", "dev": true, - "license": "MIT" + "dependencies": { + "@babel/helper-explode-assignable-expression": "^7.18.6", + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + } }, - "node_modules/bfj": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/bfj/-/bfj-7.0.2.tgz", - "integrity": "sha512-+e/UqUzwmzJamNF50tBV6tZPTORow7gQ96iFow+8b562OdMpEK0BcJEq2OSPEDmAbSMBQ7PKZ87ubFkgxpYWgw==", + "node_modules/@babel/helper-compilation-targets": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", + "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", "dev": true, "dependencies": { - "bluebird": "^3.5.5", - "check-types": "^11.1.1", - "hoopy": "^0.1.4", - "tryer": "^1.0.1" + "@babel/compat-data": "^7.20.5", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.21.3", + "lru-cache": "^5.1.1", + "semver": "^6.3.0" }, "engines": { - "node": ">= 8.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/big-integer": { - "version": "1.6.51", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", - "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.20.12", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.12.tgz", + "integrity": "sha512-9OunRkbT0JQcednL0UFvbfXpAsUXiGjUk0a7sN8fUXX7Mue79cUSMjHGDRRi/Vz9vYlpIhLV5fMD5dKoMhhsNQ==", "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-member-expression-to-functions": "^7.20.7", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-replace-supers": "^7.20.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/helper-split-export-declaration": "^7.18.6" + }, "engines": { - "node": ">=0.6" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/binary-install": { - "version": "0.1.1", + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.20.5.tgz", + "integrity": "sha512-m68B1lkg3XDGX5yCvGO0kPx3v9WIYLnzjKfPcQiwntEQa5ZeRkPmo2X/ISJc8qxWGfwUr+kvZAeEzAwLec2r2w==", "dev": true, - "license": "MIT", "dependencies": { - "axios": "^0.21.1", - "rimraf": "^3.0.2", - "tar": "^6.1.0" + "@babel/helper-annotate-as-pure": "^7.18.6", + "regexpu-core": "^5.2.1" }, "engines": { - "node": ">=10" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/blake2b-wasm": { - "version": "2.4.0", + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", + "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", "dev": true, - "license": "MIT", "dependencies": { - "b4a": "^1.0.1", - "nanoassert": "^2.0.0" + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0-0" } }, - "node_modules/blakejs": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", - "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==", - "dev": true - }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true + "node_modules/@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } }, - "node_modules/brace-expansion": { - "version": "1.1.11", + "node_modules/@babel/helper-explode-assignable-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", + "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", "dev": true, - "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/browser-stdout": { - "version": "1.3.1", + "node_modules/@babel/helper-function-name": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", "dev": true, - "license": "ISC" - }, - "node_modules/check-types": { - "version": "11.1.2", - "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.1.2.tgz", - "integrity": "sha512-tzWzvgePgLORb9/3a0YenggReLKAIb2owL03H2Xdoe5pKcUyWRSEQ8xfCar8t2SIAuEDwtmx2da1YB52YuHQMQ==", - "dev": true + "dependencies": { + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } }, - "node_modules/chownr": { - "version": "2.0.0", + "node_modules/@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", "dev": true, - "license": "ISC", + "dependencies": { + "@babel/types": "^7.18.6" + }, "engines": { - "node": ">=10" + "node": ">=6.9.0" } }, - "node_modules/circom_runtime": { - "version": "0.1.18", - "resolved": "https://registry.npmjs.org/circom_runtime/-/circom_runtime-0.1.18.tgz", - "integrity": "sha512-j6k+Jg1DXCYFVgjDRbJDmkAJ9E17js8h1iR7F1UX0IUr5v8NXeOXkfRh9+/73JqSgXb3Eo166a4JHdA/CeoEeA==", + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.20.7.tgz", + "integrity": "sha512-9J0CxJLq315fEdi4s7xK5TQaNYjZw+nDVpVqr1axNGKzdrdwYBD5b4uKv3n75aABG0rCCTK8Im8Ww7eYfMrZgw==", "dev": true, "dependencies": { - "ffjavascript": "0.2.55" + "@babel/types": "^7.20.7" }, - "bin": { - "calcwit": "calcwit.js" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/cliui": { - "version": "7.0.4", + "node_modules/@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", "dev": true, - "license": "ISC", "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/color-convert": { - "version": "2.0.1", + "node_modules/@babel/helper-module-transforms": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz", + "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==", "dev": true, - "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.20.2", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.10", + "@babel/types": "^7.20.7" }, "engines": { - "node": ">=7.0.0" + "node": ">=6.9.0" } }, - "node_modules/color-name": { - "version": "1.1.4", + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", + "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", "dev": true, - "license": "MIT" + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } }, - "node_modules/concat-map": { - "version": "0.0.1", + "node_modules/@babel/helper-plugin-utils": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", + "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", "dev": true, - "license": "MIT" + "engines": { + "node": ">=6.9.0" + } }, - "node_modules/diff": { - "version": "5.0.0", + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", + "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", "dev": true, - "license": "BSD-3-Clause", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-wrap-function": "^7.18.9", + "@babel/types": "^7.18.9" + }, "engines": { - "node": ">=0.3.1" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/dree": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/dree/-/dree-2.8.4.tgz", - "integrity": "sha512-2mrDEAfvLcSelHhZEiJSI4ESFnih5th6cZoqbCwOw8siJy88uCaQMi6wJy4t0IUKHSRDGPpNas+IT8M2EeEFBg==", + "node_modules/@babel/helper-replace-supers": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.20.7.tgz", + "integrity": "sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A==", "dev": true, "dependencies": { - "yargs": "^17.3.1" + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.20.7", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.7", + "@babel/types": "^7.20.7" }, - "bin": { - "dree": "bundled/bin/index.js" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/dree/node_modules/yargs": { - "version": "17.5.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", - "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "node_modules/@babel/helper-simple-access": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", + "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", "dev": true, "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.0.0" + "@babel/types": "^7.20.2" }, "engines": { - "node": ">=12" + "node": ">=6.9.0" } }, - "node_modules/dree/node_modules/yargs-parser": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", - "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz", + "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==", "dev": true, + "dependencies": { + "@babel/types": "^7.20.0" + }, "engines": { - "node": ">=12" + "node": ">=6.9.0" } }, - "node_modules/ejs": { - "version": "3.1.8", + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", "dev": true, - "license": "Apache-2.0", "dependencies": { - "jake": "^10.8.5" - }, - "bin": { - "ejs": "bin/cli.js" + "@babel/types": "^7.18.6" }, "engines": { - "node": ">=0.10.0" + "node": ">=6.9.0" } }, - "node_modules/emoji-regex": { - "version": "8.0.0", + "node_modules/@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", "dev": true, - "license": "MIT" + "engines": { + "node": ">=6.9.0" + } }, - "node_modules/escalade": { - "version": "3.1.1", + "node_modules/@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", "dev": true, - "license": "MIT", "engines": { - "node": ">=6" + "node": ">=6.9.0" } }, - "node_modules/fastfile": { - "version": "0.0.20", - "resolved": "https://registry.npmjs.org/fastfile/-/fastfile-0.0.20.tgz", - "integrity": "sha512-r5ZDbgImvVWCP0lA/cGNgQcZqR+aYdFx3u+CtJqUE510pBUVGMn4ulL/iRTI4tACTYsNJ736uzFxEBXesPAktA==", - "dev": true - }, - "node_modules/ffjavascript": { - "version": "0.2.55", - "resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.2.55.tgz", - "integrity": "sha512-8X0FCIPOWiK6DTWh3pnE3O6D6nIQsirStAXpWMzRDnoDX7SEnDX4I28aVhwjL7L35XS1vy2AU7zc0UCGYxdLjw==", + "node_modules/@babel/helper-validator-option": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", "dev": true, - "dependencies": { - "big-integer": "^1.6.48", - "wasmbuilder": "^0.0.12", - "wasmcurves": "0.1.0", - "web-worker": "^1.2.0" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/filelist": { - "version": "1.0.4", + "node_modules/@babel/helper-wrap-function": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz", + "integrity": "sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q==", "dev": true, - "license": "Apache-2.0", "dependencies": { - "minimatch": "^5.0.1" + "@babel/helper-function-name": "^7.19.0", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.5", + "@babel/types": "^7.20.5" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/filelist/node_modules/brace-expansion": { - "version": "2.0.1", + "node_modules/@babel/helpers": { + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.13.tgz", + "integrity": "sha512-nzJ0DWCL3gB5RCXbUO3KIMMsBY2Eqbx8mBpKGE/02PgyRQFcPQLbkQ1vyy596mZLaP+dAfD+R4ckASzNVmW3jg==", "dev": true, - "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.13", + "@babel/types": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/filelist/node_modules/minimatch": { - "version": "5.1.0", + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", "dev": true, - "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" }, "engines": { - "node": ">=10" + "node": ">=6.9.0" } }, - "node_modules/flat": { - "version": "5.0.2", + "node_modules/@babel/parser": { + "version": "7.20.15", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz", + "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==", "dev": true, - "license": "BSD-3-Clause", "bin": { - "flat": "cli.js" + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" } }, - "node_modules/follow-redirects": { - "version": "1.14.7", + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz", + "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, "engines": { - "node": ">=4.0" + "node": ">=6.9.0" }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/fs-minipass": { - "version": "2.1.0", + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.20.7.tgz", + "integrity": "sha512-sbr9+wNE5aXMBBFBICk01tt7sBf2Oc9ikRFEcem/ZORup9IMUdNhW7/wVLEbbtlWOsEubJet46mHAL2C8+2jKQ==", "dev": true, - "license": "ISC", "dependencies": { - "minipass": "^3.0.0" + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/plugin-proposal-optional-chaining": "^7.20.7" }, "engines": { - "node": ">= 8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/get-caller-file": { - "version": "2.0.5", + "node_modules/@babel/plugin-proposal-async-generator-functions": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz", + "integrity": "sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==", "dev": true, - "license": "ISC", + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-remap-async-to-generator": "^7.18.9", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, "engines": { - "node": "6.* || 8.* || >= 10.*" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/glob": { - "version": "7.1.6", + "node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", "dev": true, - "license": "ISC", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { - "node": "*" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/growl": { - "version": "1.10.5", + "node_modules/@babel/plugin-proposal-class-static-block": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.20.7.tgz", + "integrity": "sha512-AveGOoi9DAjUYYuUAG//Ig69GlazLnoyzMw68VCDux+c1tsnnH/OkYcpz/5xzMkEFC6UxjR5Gw1c+iY2wOGVeQ==", "dev": true, - "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.20.7", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, "engines": { - "node": ">=4.x" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" } }, - "node_modules/he": { - "version": "1.2.0", + "node_modules/@babel/plugin-proposal-dynamic-import": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", + "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", "dev": true, - "license": "MIT", - "bin": { - "he": "bin/he" + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/hoopy": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", - "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==", + "node_modules/@babel/plugin-proposal-export-namespace-from": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", + "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, "engines": { - "node": ">= 6.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/inflight": { - "version": "1.0.6", + "node_modules/@babel/plugin-proposal-json-strings": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", + "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", "dev": true, - "license": "ISC", "dependencies": { - "once": "^1.3.0", - "wrappy": "1" + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/inherits": { - "version": "2.0.4", - "dev": true, - "license": "ISC" - }, - "node_modules/is-extglob": { - "version": "2.1.1", + "node_modules/@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz", + "integrity": "sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==", "dev": true, - "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, "engines": { - "node": ">=0.10.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", + "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", "dev": true, - "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, "engines": { - "node": ">=8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/is-glob": { - "version": "4.0.1", + "node_modules/@babel/plugin-proposal-numeric-separator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", "dev": true, - "license": "MIT", "dependencies": { - "is-extglob": "^2.1.1" + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" }, "engines": { - "node": ">=0.10.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/is-plain-obj": { - "version": "2.1.0", + "node_modules/@babel/plugin-proposal-object-rest-spread": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz", + "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==", "dev": true, - "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.20.5", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.20.7" + }, "engines": { - "node": ">=8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", + "node_modules/@babel/plugin-proposal-optional-catch-binding": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", + "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", "dev": true, - "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, "engines": { - "node": ">=10" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/isexe": { - "version": "2.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/jake": { - "version": "10.8.5", + "node_modules/@babel/plugin-proposal-optional-chaining": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.20.7.tgz", + "integrity": "sha512-T+A7b1kfjtRM51ssoOfS1+wbyCVqorfyZhT99TvxxLMirPShD8CzKMRepMlCBGM5RpHMbn8s+5MMHnPstJH6mQ==", "dev": true, - "license": "Apache-2.0", "dependencies": { - "async": "^3.2.3", - "chalk": "^4.0.2", - "filelist": "^1.0.1", - "minimatch": "^3.0.4" - }, - "bin": { - "jake": "bin/cli.js" + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" }, "engines": { - "node": ">=10" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/jake/node_modules/chalk": { - "version": "4.1.2", + "node_modules/@babel/plugin-proposal-private-methods": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", "dev": true, - "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { - "node": ">=10" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/jake/node_modules/has-flag": { - "version": "4.0.0", + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.20.5.tgz", + "integrity": "sha512-Vq7b9dUA12ByzB4EjQTPo25sFhY+08pQDBSZRtUAkj7lb7jahaHR5igera16QZ+3my1nYR4dKsNdYj5IjPHilQ==", "dev": true, - "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.20.5", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, "engines": { - "node": ">=8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/jake/node_modules/supports-color": { - "version": "7.2.0", + "node_modules/@babel/plugin-proposal-unicode-property-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", + "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", "dev": true, - "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { - "node": ">=8" + "node": ">=4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/js-sha3": { - "version": "0.8.0", + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", "dev": true, - "license": "MIT" + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/js-yaml": { - "version": "4.1.0", + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", "dev": true, - "license": "MIT", "dependencies": { - "argparse": "^2.0.1" + "@babel/helper-plugin-utils": "^7.12.13" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/locate-path": { - "version": "6.0.0", + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", "dev": true, - "license": "MIT", "dependencies": { - "p-locate": "^5.0.0" + "@babel/helper-plugin-utils": "^7.14.5" }, "engines": { - "node": ">=10" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/log-symbols": { - "version": "4.1.0", + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", "dev": true, - "license": "MIT", "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" + "@babel/helper-plugin-utils": "^7.8.0" }, - "engines": { - "node": ">=10" + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/log-symbols/node_modules/chalk": { - "version": "4.1.2", + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz", + "integrity": "sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==", "dev": true, - "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@babel/helper-plugin-utils": "^7.19.0" }, "engines": { - "node": ">=10" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/log-symbols/node_modules/has-flag": { - "version": "4.0.0", + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/log-symbols/node_modules/supports-color": { - "version": "7.2.0", + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", "dev": true, - "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "@babel/helper-plugin-utils": "^7.10.4" }, - "engines": { - "node": ">=8" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/logplease": { - "version": "1.2.15", + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", "dev": true, - "license": "MIT" + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/minimatch": { - "version": "3.0.4", + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", "dev": true, - "license": "ISC", "dependencies": { - "brace-expansion": "^1.1.7" + "@babel/helper-plugin-utils": "^7.10.4" }, - "engines": { - "node": "*" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/minipass": { - "version": "3.1.6", + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", "dev": true, - "license": "ISC", "dependencies": { - "yallist": "^4.0.0" + "@babel/helper-plugin-utils": "^7.8.0" }, - "engines": { - "node": ">=8" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/minipass/node_modules/yallist": { - "version": "4.0.0", + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", "dev": true, - "license": "ISC" + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/minizlib": { - "version": "2.1.2", + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", "dev": true, - "license": "MIT", "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" }, "engines": { - "node": ">= 8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/minizlib/node_modules/yallist": { - "version": "4.0.0", + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", "dev": true, - "license": "ISC" + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/mocha": { - "version": "9.2.0", + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.20.7.tgz", + "integrity": "sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ==", "dev": true, - "license": "MIT", "dependencies": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.3", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.2.0", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "3.0.4", - "ms": "2.1.3", - "nanoid": "3.2.0", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "which": "2.0.2", - "workerpool": "6.2.0", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha" + "@babel/helper-plugin-utils": "^7.20.2" }, "engines": { - "node": ">= 12.0.0" + "node": ">=6.9.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/mocha/node_modules/ansi-colors": { - "version": "4.1.1", + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.20.7.tgz", + "integrity": "sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q==", "dev": true, - "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-remap-async-to-generator": "^7.18.9" + }, "engines": { - "node": ">=6" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/mocha/node_modules/anymatch": { - "version": "3.1.2", + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", + "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", "dev": true, - "license": "ISC", "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { - "node": ">= 8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/mocha/node_modules/binary-extensions": { - "version": "2.2.0", + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.20.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.15.tgz", + "integrity": "sha512-Vv4DMZ6MiNOhu/LdaZsT/bsLRxgL94d269Mv4R/9sp6+Mp++X/JqypZYypJXLlM4mlL352/Egzbzr98iABH1CA==", "dev": true, - "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2" + }, "engines": { - "node": ">=8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/mocha/node_modules/braces": { - "version": "3.0.2", + "node_modules/@babel/plugin-transform-classes": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.20.7.tgz", + "integrity": "sha512-LWYbsiXTPKl+oBlXUGlwNlJZetXD5Am+CyBdqhPsDVjM9Jc8jwBJFrKhHf900Kfk2eZG1y9MAG3UNajol7A4VQ==", "dev": true, - "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-replace-supers": "^7.20.7", + "@babel/helper-split-export-declaration": "^7.18.6", + "globals": "^11.1.0" }, "engines": { - "node": ">=8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/mocha/node_modules/chokidar": { - "version": "3.5.3", + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.20.7.tgz", + "integrity": "sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "license": "MIT", "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/template": "^7.20.7" }, "engines": { - "node": ">= 8.10.0" + "node": ">=6.9.0" }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/mocha/node_modules/debug": { - "version": "4.3.3", + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.7.tgz", + "integrity": "sha512-Xwg403sRrZb81IVB79ZPqNQME23yhugYVqgTxAhT99h485F4f+GMELFhhOsscDUB7HCswepKeCKLn/GZvUKoBA==", "dev": true, - "license": "MIT", "dependencies": { - "ms": "2.1.2" + "@babel/helper-plugin-utils": "^7.20.2" }, "engines": { - "node": ">=6.0" + "node": ">=6.9.0" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/mocha/node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "dev": true, - "license": "MIT" - }, - "node_modules/mocha/node_modules/escape-string-regexp": { - "version": "4.0.0", + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", + "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", "dev": true, - "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, "engines": { - "node": ">=10" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/mocha/node_modules/fill-range": { - "version": "7.0.1", + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", + "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", "dev": true, - "license": "MIT", "dependencies": { - "to-regex-range": "^5.0.1" + "@babel/helper-plugin-utils": "^7.18.9" }, "engines": { - "node": ">=8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/mocha/node_modules/find-up": { - "version": "5.0.0", + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", + "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", "dev": true, - "license": "MIT", "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { - "node": ">=10" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/mocha/node_modules/fsevents": { - "version": "2.3.2", + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", + "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/mocha/node_modules/glob": { - "version": "7.2.0", + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", + "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", "dev": true, - "license": "ISC", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9" }, "engines": { - "node": "*" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/mocha/node_modules/glob-parent": { - "version": "5.1.2", + "node_modules/@babel/plugin-transform-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", + "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", "dev": true, - "license": "ISC", "dependencies": { - "is-glob": "^4.0.1" + "@babel/helper-plugin-utils": "^7.18.9" }, "engines": { - "node": ">= 6" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/mocha/node_modules/is-binary-path": { - "version": "2.1.0", + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", + "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", "dev": true, - "license": "MIT", "dependencies": { - "binary-extensions": "^2.0.0" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { - "node": ">=8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/mocha/node_modules/is-number": { - "version": "7.0.0", + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.20.11.tgz", + "integrity": "sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g==", "dev": true, - "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helper-plugin-utils": "^7.20.2" + }, "engines": { - "node": ">=0.12.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/mocha/node_modules/ms": { - "version": "2.1.3", + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.20.11.tgz", + "integrity": "sha512-S8e1f7WQ7cimJQ51JkAaDrEtohVEitXjgCGAS2N8S31Y42E+kWwfSz83LYz57QdBm7q9diARVqanIaH2oVgQnw==", "dev": true, - "license": "MIT" + "dependencies": { + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-simple-access": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/mocha/node_modules/normalize-path": { - "version": "3.0.0", + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.20.11.tgz", + "integrity": "sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw==", "dev": true, - "license": "MIT", + "dependencies": { + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-validator-identifier": "^7.19.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/mocha/node_modules/path-exists": { - "version": "4.0.0", + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", + "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", "dev": true, - "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, "engines": { - "node": ">=8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/mocha/node_modules/readdirp": { - "version": "3.6.0", + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.20.5.tgz", + "integrity": "sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA==", "dev": true, - "license": "MIT", "dependencies": { - "picomatch": "^2.2.1" + "@babel/helper-create-regexp-features-plugin": "^7.20.5", + "@babel/helper-plugin-utils": "^7.20.2" }, "engines": { - "node": ">=8.10.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/mocha/node_modules/strip-json-comments": { - "version": "3.1.1", + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", + "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", "dev": true, - "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, "engines": { - "node": ">=8" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/mocha/node_modules/to-regex-range": { - "version": "5.0.1", + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", + "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", "dev": true, - "license": "MIT", "dependencies": { - "is-number": "^7.0.0" + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.6" }, "engines": { - "node": ">=8.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/mocha/node_modules/which": { - "version": "2.0.2", + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.7.tgz", + "integrity": "sha512-WiWBIkeHKVOSYPO0pWkxGPfKeWrCJyD3NJ53+Lrp/QMSZbsVPovrVl2aWZ19D/LTVnaDv5Ap7GJ/B2CTOZdrfA==", "dev": true, - "license": "ISC", "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" + "@babel/helper-plugin-utils": "^7.20.2" }, "engines": { - "node": ">= 8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/mocha/node_modules/yargs-parser": { - "version": "20.2.4", + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", + "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", "dev": true, - "license": "ISC", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, "engines": { - "node": ">=10" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/nanoassert": { - "version": "2.0.0", + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.20.5.tgz", + "integrity": "sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==", "dev": true, - "license": "ISC" + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "regenerator-transform": "^0.15.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/nanoid": { - "version": "3.2.0", + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", + "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", "dev": true, - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/once": { - "version": "1.4.0", + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", + "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", "dev": true, - "license": "ISC", "dependencies": { - "wrappy": "1" + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/p-limit": { - "version": "3.1.0", + "node_modules/@babel/plugin-transform-spread": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.20.7.tgz", + "integrity": "sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw==", "dev": true, - "license": "MIT", "dependencies": { - "yocto-queue": "^0.1.0" + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0" }, "engines": { - "node": ">=10" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/p-locate": { - "version": "5.0.0", + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", + "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", "dev": true, - "license": "MIT", "dependencies": { - "p-limit": "^3.0.2" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { - "node": ">=10" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", + "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", "dev": true, - "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, "engines": { - "node": ">=0.10.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/picomatch": { - "version": "2.3.1", + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", + "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", "dev": true, - "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, "engines": { - "node": ">=8.6" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/r1csfile": { - "version": "0.0.40", - "resolved": "https://registry.npmjs.org/r1csfile/-/r1csfile-0.0.40.tgz", - "integrity": "sha512-3tKaFLncf42ZTRpPMlgyiFBdk6kir4S4O3X+u4UQjgLYoDPHfizazNbK0Jzj++PVIXVUFAqugSbIo4W3UDuHcQ==", + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", + "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", "dev": true, "dependencies": { - "@iden3/bigarray": "0.0.2", - "@iden3/binfileutils": "0.0.11", - "fastfile": "0.0.20", - "ffjavascript": "0.2.55" + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/randombytes": { - "version": "2.1.0", + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", + "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", "dev": true, - "license": "MIT", "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "dev": true, - "license": "MIT", + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, "engines": { - "node": ">=0.10.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/rimraf": { - "version": "3.0.2", + "node_modules/@babel/preset-env": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.20.2.tgz", + "integrity": "sha512-1G0efQEWR1EHkKvKHqbG+IN/QdgwfByUpM5V5QroDzGV2t3S/WXNQd693cHiHTlCFMpr9B6FkPFXDA2lQcKoDg==", "dev": true, - "license": "ISC", "dependencies": { - "glob": "^7.1.3" + "@babel/compat-data": "^7.20.1", + "@babel/helper-compilation-targets": "^7.20.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-async-generator-functions": "^7.20.1", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-class-static-block": "^7.18.6", + "@babel/plugin-proposal-dynamic-import": "^7.18.6", + "@babel/plugin-proposal-export-namespace-from": "^7.18.9", + "@babel/plugin-proposal-json-strings": "^7.18.6", + "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", + "@babel/plugin-proposal-numeric-separator": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.20.2", + "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.18.6", + "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.20.0", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-transform-arrow-functions": "^7.18.6", + "@babel/plugin-transform-async-to-generator": "^7.18.6", + "@babel/plugin-transform-block-scoped-functions": "^7.18.6", + "@babel/plugin-transform-block-scoping": "^7.20.2", + "@babel/plugin-transform-classes": "^7.20.2", + "@babel/plugin-transform-computed-properties": "^7.18.9", + "@babel/plugin-transform-destructuring": "^7.20.2", + "@babel/plugin-transform-dotall-regex": "^7.18.6", + "@babel/plugin-transform-duplicate-keys": "^7.18.9", + "@babel/plugin-transform-exponentiation-operator": "^7.18.6", + "@babel/plugin-transform-for-of": "^7.18.8", + "@babel/plugin-transform-function-name": "^7.18.9", + "@babel/plugin-transform-literals": "^7.18.9", + "@babel/plugin-transform-member-expression-literals": "^7.18.6", + "@babel/plugin-transform-modules-amd": "^7.19.6", + "@babel/plugin-transform-modules-commonjs": "^7.19.6", + "@babel/plugin-transform-modules-systemjs": "^7.19.6", + "@babel/plugin-transform-modules-umd": "^7.18.6", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1", + "@babel/plugin-transform-new-target": "^7.18.6", + "@babel/plugin-transform-object-super": "^7.18.6", + "@babel/plugin-transform-parameters": "^7.20.1", + "@babel/plugin-transform-property-literals": "^7.18.6", + "@babel/plugin-transform-regenerator": "^7.18.6", + "@babel/plugin-transform-reserved-words": "^7.18.6", + "@babel/plugin-transform-shorthand-properties": "^7.18.6", + "@babel/plugin-transform-spread": "^7.19.0", + "@babel/plugin-transform-sticky-regex": "^7.18.6", + "@babel/plugin-transform-template-literals": "^7.18.9", + "@babel/plugin-transform-typeof-symbol": "^7.18.9", + "@babel/plugin-transform-unicode-escapes": "^7.18.10", + "@babel/plugin-transform-unicode-regex": "^7.18.6", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.20.2", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", + "core-js-compat": "^3.25.1", + "semver": "^6.3.0" }, - "bin": { - "rimraf": "bin.js" + "engines": { + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "dev": true, - "license": "MIT" - }, - "node_modules/serialize-javascript": { - "version": "6.0.0", + "node_modules/@babel/preset-modules": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { - "randombytes": "^2.1.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/snarkjs": { - "version": "0.4.25", - "resolved": "https://registry.npmjs.org/snarkjs/-/snarkjs-0.4.25.tgz", - "integrity": "sha512-20manpB7xCd5gkfkioD6GaAR7tgJmN7xQQislJcPV3Xs2Vkf+1Dz6V+LKRwlc/rU/vT/EopUBm5apqvTOKidbQ==", + "node_modules/@babel/runtime": { + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz", + "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==", "dev": true, "dependencies": { - "@iden3/binfileutils": "0.0.11", - "bfj": "^7.0.2", - "blake2b-wasm": "^2.4.0", - "circom_runtime": "0.1.18", - "ejs": "^3.1.6", - "fastfile": "0.0.20", - "ffjavascript": "0.2.55", - "js-sha3": "^0.8.0", - "logplease": "^1.2.15", - "r1csfile": "0.0.40" + "regenerator-runtime": "^0.13.11" }, - "bin": { - "snarkjs": "build/cli.cjs" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/@babel/template": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", + "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", "dev": true, "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7" }, "engines": { - "node": ">=8" + "node": ">=6.9.0" } }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/@babel/traverse": { + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.13.tgz", + "integrity": "sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.1" + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.7", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.20.13", + "@babel/types": "^7.20.7", + "debug": "^4.1.0", + "globals": "^11.1.0" }, "engines": { - "node": ">=8" + "node": ">=6.9.0" } }, - "node_modules/supports-color": { - "version": "8.1.1", + "node_modules/@babel/types": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", "dev": true, - "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "node": ">=6.9.0" } }, - "node_modules/supports-color/node_modules/has-flag": { - "version": "4.0.0", + "node_modules/@iden3/bigarray": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@iden3/bigarray/-/bigarray-0.0.2.tgz", + "integrity": "sha512-Xzdyxqm1bOFF6pdIsiHLLl3HkSLjbhqJHVyqaTxXt3RqXBEnmsUmEW47H7VOi/ak7TdkRpNkxjyK5Zbkm+y52g==", + "dev": true + }, + "node_modules/@iden3/binfileutils": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/@iden3/binfileutils/-/binfileutils-0.0.11.tgz", + "integrity": "sha512-LylnJoZ0CTdgErnKY8OxohvW4K+p6UHD3sxt+3P9AmMyBQjYR4IpoqoYZZ+9aMj89cmCQ21UvdhndAx04er3NA==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "fastfile": "0.0.20", + "ffjavascript": "^0.2.48" } }, - "node_modules/tar": { - "version": "6.1.11", + "node_modules/@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", "dev": true, - "license": "ISC", "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^3.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" }, "engines": { - "node": ">= 10" + "node": ">=6.0.0" } }, - "node_modules/tar/node_modules/mkdirp": { - "version": "1.0.4", + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", "dev": true, - "license": "MIT", - "bin": { - "mkdirp": "bin/cmd.js" - }, "engines": { - "node": ">=10" + "node": ">=6.0.0" } }, - "node_modules/tar/node_modules/yallist": { - "version": "4.0.0", + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", "dev": true, - "license": "ISC" + "engines": { + "node": ">=6.0.0" + } }, - "node_modules/tryer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", - "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==", + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", "dev": true }, - "node_modules/wasm-pack": { - "version": "0.10.2", + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", "dev": true, - "hasInstallScript": true, - "license": "MIT OR Apache-2.0", "dependencies": { - "binary-install": "^0.1.0" - }, - "bin": { - "wasm-pack": "run.js" + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" } }, - "node_modules/wasmbuilder": { - "version": "0.0.12", - "resolved": "https://registry.npmjs.org/wasmbuilder/-/wasmbuilder-0.0.12.tgz", - "integrity": "sha512-dTMpBgrnLOXrN58i2zakn2ScynsBhq9LfyQIsPz4CyxRF9k1GAORniuqn3xmE9NnI1l7g3iiVCkoB2Cl0/oG8w==", + "node_modules/@types/node": { + "version": "18.11.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.19.tgz", + "integrity": "sha512-YUgMWAQBWLObABqrvx8qKO1enAvBUdjZOAWQ5grBAkp5LQv45jBvYKZ3oFS9iKRCQyFjqw6iuEa1vmFqtxYLZw==", "dev": true, - "dependencies": { - "big-integer": "^1.6.48" - } + "optional": true }, - "node_modules/wasmcurves": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/wasmcurves/-/wasmcurves-0.1.0.tgz", - "integrity": "sha512-kIlcgbVUAv2uQ6lGsepGz/m5V40+Z6rvTBkqCYn3Y2+OcXst+UaP4filJYLh/xDxjJl62FFjZZeAnpeli1Y5/Q==", + "node_modules/@types/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", "dev": true, + "optional": true, "dependencies": { - "big-integer": "^1.6.42", - "blakejs": "^1.1.0" + "@types/node": "*" } }, - "node_modules/web-worker": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.2.0.tgz", - "integrity": "sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA==", - "dev": true - }, - "node_modules/workerpool": { - "version": "6.2.0", + "node_modules/@ungap/promise-all-settled": { + "version": "1.1.2", "dev": true, - "license": "Apache-2.0" + "license": "ISC" }, - "node_modules/wrap-ansi": { - "version": "7.0.0", + "node_modules/acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "bin": { + "acorn": "bin/acorn" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "node": ">=0.4.0" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "dev": true, - "license": "ISC" - }, - "node_modules/y18n": { - "version": "5.0.5", + "node_modules/acorn-node": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", + "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" + "dependencies": { + "acorn": "^7.0.0", + "acorn-walk": "^7.0.0", + "xtend": "^4.0.2" } }, - "node_modules/yargs": { - "version": "16.2.0", + "node_modules/acorn-node/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "bin": { + "acorn": "bin/acorn" }, "engines": { - "node": ">=10" + "node": ">=0.4.0" } }, - "node_modules/yargs-parser": { - "version": "20.2.6", + "node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", "dev": true, - "license": "ISC", "engines": { - "node": ">=10" + "node": ">=0.4.0" } }, - "node_modules/yargs-unparser": { - "version": "2.0.0", + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "dev": true, - "license": "MIT", "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" + "debug": "4" }, "engines": { - "node": ">=10" + "node": ">= 6.0.0" } }, - "node_modules/yargs-unparser/node_modules/camelcase": { - "version": "6.3.0", + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, - "license": "MIT", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, - "node_modules/yargs-unparser/node_modules/decamelize": { - "version": "4.0.0", + "node_modules/ansi-styles": { + "version": "4.3.0", "dev": true, "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/yocto-queue": { - "version": "0.1.0", + "node_modules/argparse": { + "version": "2.0.1", "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - }, - "dependencies": { - "@iden3/bigarray": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/@iden3/bigarray/-/bigarray-0.0.2.tgz", - "integrity": "sha512-Xzdyxqm1bOFF6pdIsiHLLl3HkSLjbhqJHVyqaTxXt3RqXBEnmsUmEW47H7VOi/ak7TdkRpNkxjyK5Zbkm+y52g==", - "dev": true + "license": "Python-2.0" }, - "@iden3/binfileutils": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/@iden3/binfileutils/-/binfileutils-0.0.11.tgz", - "integrity": "sha512-LylnJoZ0CTdgErnKY8OxohvW4K+p6UHD3sxt+3P9AmMyBQjYR4IpoqoYZZ+9aMj89cmCQ21UvdhndAx04er3NA==", + "node_modules/asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", "dev": true, - "requires": { - "fastfile": "0.0.20", - "ffjavascript": "^0.2.48" + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" } }, - "@ungap/promise-all-settled": { - "version": "1.1.2", - "dev": true - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/asn1.js/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", "dev": true }, - "ansi-styles": { - "version": "4.3.0", + "node_modules/assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", "dev": true, - "requires": { - "color-convert": "^2.0.1" + "dependencies": { + "object-assign": "^4.1.1", + "util": "0.10.3" } }, - "argparse": { + "node_modules/assert/node_modules/inherits": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha512-8nWq2nLTAwd02jTqJExUYFSD/fKq6VH9Y/oG2accc/kdI0V98Bag8d5a4gi3XHz73rDWa2PvTtvcWYquKqSENA==", "dev": true }, - "async": { + "node_modules/assert/node_modules/util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha512-5KiHfsmkqacuKjkRkdV7SsfDJ2EGiPsK92s2MhNSY0craxjTdKTtqKsJaCWp4LW33ZZ0OPUv1WO/TFvNQRiQxQ==", + "dev": true, + "dependencies": { + "inherits": "2.0.1" + } + }, + "node_modules/astring": { + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/astring/-/astring-1.8.4.tgz", + "integrity": "sha512-97a+l2LBU3Op3bBQEff79i/E4jMD2ZLFD8rHx9B6mXyB2uQwhJQYfiDqUwtfjF4QA1F2qs//N6Cw8LetMbQjcw==", + "dev": true, + "bin": { + "astring": "bin/astring" + } + }, + "node_modules/async": { "version": "3.2.3", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "axios": { + "node_modules/axios": { "version": "0.21.4", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "follow-redirects": "^1.14.0" } }, - "b4a": { + "node_modules/b4a": { "version": "1.5.3", - "dev": true + "dev": true, + "license": "ISC" + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", + "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.3.3", + "semver": "^6.1.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", + "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.3", + "core-js-compat": "^3.25.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", + "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babelify": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/babelify/-/babelify-10.0.0.tgz", + "integrity": "sha512-X40FaxyH7t3X+JFAKvb1H9wooWKLRCi8pg3m8poqtdZaIng+bjzp9RvKQCvRjF9isHiPkXspbbXT/zwXLtwgwg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } }, - "balanced-match": { + "node_modules/balanced-match": { "version": "1.0.0", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, - "bfj": { + "node_modules/bfj": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/bfj/-/bfj-7.0.2.tgz", "integrity": "sha512-+e/UqUzwmzJamNF50tBV6tZPTORow7gQ96iFow+8b562OdMpEK0BcJEq2OSPEDmAbSMBQ7PKZ87ubFkgxpYWgw==", "dev": true, - "requires": { + "dependencies": { "bluebird": "^3.5.5", "check-types": "^11.1.1", "hoopy": "^0.1.4", "tryer": "^1.0.1" + }, + "engines": { + "node": ">= 8.0.0" } }, - "big-integer": { + "node_modules/big-integer": { "version": "1.6.51", "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.6" + } }, - "binary-install": { + "node_modules/binary-install": { "version": "0.1.1", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "axios": "^0.21.1", "rimraf": "^3.0.2", "tar": "^6.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" } }, - "blake2b-wasm": { + "node_modules/blake2b-wasm": { "version": "2.4.0", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "b4a": "^1.0.1", "nanoassert": "^2.0.0" } }, - "blakejs": { + "node_modules/blakejs": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==", "dev": true }, - "bluebird": { + "node_modules/bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", "dev": true }, - "brace-expansion": { + "node_modules/bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "dev": true + }, + "node_modules/brace-expansion": { "version": "1.1.11", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, - "browser-stdout": { - "version": "1.3.1", + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", "dev": true }, - "check-types": { - "version": "11.1.2", - "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.1.2.tgz", - "integrity": "sha512-tzWzvgePgLORb9/3a0YenggReLKAIb2owL03H2Xdoe5pKcUyWRSEQ8xfCar8t2SIAuEDwtmx2da1YB52YuHQMQ==", - "dev": true + "node_modules/browser-pack": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.1.0.tgz", + "integrity": "sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA==", + "dev": true, + "dependencies": { + "combine-source-map": "~0.8.0", + "defined": "^1.0.0", + "JSONStream": "^1.0.3", + "safe-buffer": "^5.1.1", + "through2": "^2.0.0", + "umd": "^3.0.0" + }, + "bin": { + "browser-pack": "bin/cmd.js" + } }, - "chownr": { + "node_modules/browser-resolve": { "version": "2.0.0", - "dev": true + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-2.0.0.tgz", + "integrity": "sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ==", + "dev": true, + "dependencies": { + "resolve": "^1.17.0" + } }, - "circom_runtime": { - "version": "0.1.18", - "resolved": "https://registry.npmjs.org/circom_runtime/-/circom_runtime-0.1.18.tgz", - "integrity": "sha512-j6k+Jg1DXCYFVgjDRbJDmkAJ9E17js8h1iR7F1UX0IUr5v8NXeOXkfRh9+/73JqSgXb3Eo166a4JHdA/CeoEeA==", + "node_modules/browser-stdout": { + "version": "1.3.1", "dev": true, - "requires": { - "ffjavascript": "0.2.55" + "license": "ISC" + }, + "node_modules/browserify": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/browserify/-/browserify-17.0.0.tgz", + "integrity": "sha512-SaHqzhku9v/j6XsQMRxPyBrSP3gnwmE27gLJYZgMT2GeK3J0+0toN+MnuNYDfHwVGQfLiMZ7KSNSIXHemy905w==", + "dev": true, + "dependencies": { + "assert": "^1.4.0", + "browser-pack": "^6.0.1", + "browser-resolve": "^2.0.0", + "browserify-zlib": "~0.2.0", + "buffer": "~5.2.1", + "cached-path-relative": "^1.0.0", + "concat-stream": "^1.6.0", + "console-browserify": "^1.1.0", + "constants-browserify": "~1.0.0", + "crypto-browserify": "^3.0.0", + "defined": "^1.0.0", + "deps-sort": "^2.0.1", + "domain-browser": "^1.2.0", + "duplexer2": "~0.1.2", + "events": "^3.0.0", + "glob": "^7.1.0", + "has": "^1.0.0", + "htmlescape": "^1.1.0", + "https-browserify": "^1.0.0", + "inherits": "~2.0.1", + "insert-module-globals": "^7.2.1", + "JSONStream": "^1.0.3", + "labeled-stream-splicer": "^2.0.0", + "mkdirp-classic": "^0.5.2", + "module-deps": "^6.2.3", + "os-browserify": "~0.3.0", + "parents": "^1.0.1", + "path-browserify": "^1.0.0", + "process": "~0.11.0", + "punycode": "^1.3.2", + "querystring-es3": "~0.2.0", + "read-only-stream": "^2.0.0", + "readable-stream": "^2.0.2", + "resolve": "^1.1.4", + "shasum-object": "^1.0.0", + "shell-quote": "^1.6.1", + "stream-browserify": "^3.0.0", + "stream-http": "^3.0.0", + "string_decoder": "^1.1.1", + "subarg": "^1.0.0", + "syntax-error": "^1.1.1", + "through2": "^2.0.0", + "timers-browserify": "^1.0.1", + "tty-browserify": "0.0.1", + "url": "~0.11.0", + "util": "~0.12.0", + "vm-browserify": "^1.0.0", + "xtend": "^4.0.0" + }, + "bin": { + "browserify": "bin/cmd.js" + }, + "engines": { + "node": ">= 0.8" } }, - "cliui": { - "version": "7.0.4", + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, - "color-convert": { - "version": "2.0.1", + "node_modules/browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", "dev": true, - "requires": { - "color-name": "~1.1.4" + "dependencies": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" } }, - "color-name": { - "version": "1.1.4", - "dev": true + "node_modules/browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "dependencies": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } }, - "concat-map": { - "version": "0.0.1", - "dev": true + "node_modules/browserify-rsa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", + "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", + "dev": true, + "dependencies": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + } }, - "diff": { - "version": "5.0.0", - "dev": true + "node_modules/browserify-sign": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", + "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", + "dev": true, + "dependencies": { + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.3", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + } + }, + "node_modules/browserify-sign/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } }, - "dree": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/dree/-/dree-2.8.4.tgz", - "integrity": "sha512-2mrDEAfvLcSelHhZEiJSI4ESFnih5th6cZoqbCwOw8siJy88uCaQMi6wJy4t0IUKHSRDGPpNas+IT8M2EeEFBg==", - "dev": true, - "requires": { - "yargs": "^17.3.1" - }, - "dependencies": { - "yargs": { - "version": "17.5.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", - "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.0.0" - } + "node_modules/browserify-sign/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" }, - "yargs-parser": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", - "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", - "dev": true + { + "type": "consulting", + "url": "https://feross.org/support" } - } + ] }, - "ejs": { - "version": "3.1.8", + "node_modules/browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", "dev": true, - "requires": { - "jake": "^10.8.5" + "dependencies": { + "pako": "~1.0.5" } }, - "emoji-regex": { - "version": "8.0.0", - "dev": true - }, - "escalade": { - "version": "3.1.1", - "dev": true - }, - "fastfile": { - "version": "0.0.20", - "resolved": "https://registry.npmjs.org/fastfile/-/fastfile-0.0.20.tgz", - "integrity": "sha512-r5ZDbgImvVWCP0lA/cGNgQcZqR+aYdFx3u+CtJqUE510pBUVGMn4ulL/iRTI4tACTYsNJ736uzFxEBXesPAktA==", + "node_modules/browserify-zlib/node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", "dev": true }, - "ffjavascript": { - "version": "0.2.55", - "resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.2.55.tgz", - "integrity": "sha512-8X0FCIPOWiK6DTWh3pnE3O6D6nIQsirStAXpWMzRDnoDX7SEnDX4I28aVhwjL7L35XS1vy2AU7zc0UCGYxdLjw==", + "node_modules/browserslist": { + "version": "4.21.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", + "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", "dev": true, - "requires": { - "big-integer": "^1.6.48", - "wasmbuilder": "^0.0.12", - "wasmcurves": "0.1.0", - "web-worker": "^1.2.0" + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001449", + "electron-to-chromium": "^1.4.284", + "node-releases": "^2.0.8", + "update-browserslist-db": "^1.0.10" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "filelist": { - "version": "1.0.4", + "node_modules/buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", + "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", "dev": true, - "requires": { - "minimatch": "^5.0.1" - }, "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "minimatch": { - "version": "5.1.0", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - } + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" } }, - "flat": { - "version": "5.0.2", - "dev": true + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "engines": { + "node": "*" + } }, - "follow-redirects": { - "version": "1.14.7", + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, - "fs-minipass": { - "version": "2.1.0", - "dev": true, - "requires": { - "minipass": "^3.0.0" - } + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "dev": true }, - "fs.realpath": { - "version": "1.0.0", + "node_modules/builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==", "dev": true }, - "get-caller-file": { - "version": "2.0.5", + "node_modules/cached-path-relative": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.1.0.tgz", + "integrity": "sha512-WF0LihfemtesFcJgO7xfOoOcnWzY/QHR4qeDqV44jPU3HTI54+LnfXK3SA27AVVGCdZFgjjFFaqUA9Jx7dMJZA==", "dev": true }, - "glob": { - "version": "7.1.6", + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "growl": { - "version": "1.10.5", - "dev": true + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } }, - "he": { - "version": "1.2.0", - "dev": true + "node_modules/caniuse-lite": { + "version": "1.0.30001450", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001450.tgz", + "integrity": "sha512-qMBmvmQmFXaSxexkjjfMvD5rnDL0+m+dUMZKoDYsGG8iZN29RuYh9eRoMvKsT6uMAWlyUUGDEQGJJYjzCIO9ew==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] }, - "hoopy": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", - "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==", - "dev": true + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } }, - "inflight": { - "version": "1.0.6", + "node_modules/chalk/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" } }, - "inherits": { - "version": "2.0.4", + "node_modules/chalk/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/chalk/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, - "is-extglob": { - "version": "2.1.1", + "node_modules/chalk/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/check-types": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.1.2.tgz", + "integrity": "sha512-tzWzvgePgLORb9/3a0YenggReLKAIb2owL03H2Xdoe5pKcUyWRSEQ8xfCar8t2SIAuEDwtmx2da1YB52YuHQMQ==", "dev": true }, - "is-fullwidth-code-point": { - "version": "3.0.0", + "node_modules/chownr": { + "version": "2.0.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/circom_runtime": { + "version": "0.1.18", + "resolved": "https://registry.npmjs.org/circom_runtime/-/circom_runtime-0.1.18.tgz", + "integrity": "sha512-j6k+Jg1DXCYFVgjDRbJDmkAJ9E17js8h1iR7F1UX0IUr5v8NXeOXkfRh9+/73JqSgXb3Eo166a4JHdA/CeoEeA==", + "dev": true, + "dependencies": { + "ffjavascript": "0.2.55" + }, + "bin": { + "calcwit": "calcwit.js" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/combine-source-map": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.8.0.tgz", + "integrity": "sha512-UlxQ9Vw0b/Bt/KYwCFqdEwsQ1eL8d1gibiFb7lxQJFdvTgc2hIZi6ugsg+kyhzhPV+QEpUiEIwInIAIrgoEkrg==", + "dev": true, + "dependencies": { + "convert-source-map": "~1.1.0", + "inline-source-map": "~0.6.0", + "lodash.memoize": "~3.0.3", + "source-map": "~0.5.3" + } + }, + "node_modules/combine-source-map/node_modules/convert-source-map": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", + "integrity": "sha512-Y8L5rp6jo+g9VEPgvqNfEopjTR4OTYct8lXlS8iVQdmnjDvbdbzYe9rjtFCB9egC86JoNCU61WRY+ScjkZpnIg==", "dev": true }, - "is-glob": { - "version": "4.0.1", + "node_modules/concat-map": { + "version": "0.0.1", "dev": true, - "requires": { - "is-extglob": "^2.1.1" + "license": "MIT" + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" } }, - "is-plain-obj": { - "version": "2.1.0", + "node_modules/console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", "dev": true }, - "is-unicode-supported": { - "version": "0.1.0", + "node_modules/constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==", "dev": true }, - "isexe": { - "version": "2.0.0", + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", "dev": true }, - "jake": { - "version": "10.8.5", + "node_modules/core-js-compat": { + "version": "3.27.2", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.27.2.tgz", + "integrity": "sha512-welaYuF7ZtbYKGrIy7y3eb40d37rG1FvzEOfe7hSLd2iD6duMDqUhRfSvCGyC46HhR6Y8JXXdZ2lnRUMkPBpvg==", "dev": true, - "requires": { - "async": "^3.2.3", - "chalk": "^4.0.2", - "filelist": "^1.0.1", - "minimatch": "^3.0.4" + "dependencies": { + "browserslist": "^4.21.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/cosmiconfig": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.0.0.tgz", + "integrity": "sha512-da1EafcpH6b/TD8vDRaWV7xFINlHlF6zKsGwS1TsuVJTZRkquaS5HTMq7uq6h31619QjbsYl21gVDOm32KM1vQ==", + "dev": true, + "dependencies": { + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0" }, + "engines": { + "node": ">=14" + } + }, + "node_modules/create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "dev": true, "dependencies": { - "chalk": { - "version": "4.1.2", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "has-flag": { - "version": "4.0.0", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" } }, - "js-sha3": { - "version": "0.8.0", + "node_modules/create-ecdh/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", "dev": true }, - "js-yaml": { - "version": "4.1.0", + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "dev": true, - "requires": { - "argparse": "^2.0.1" + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" } }, - "locate-path": { - "version": "6.0.0", + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "dev": true, - "requires": { - "p-locate": "^5.0.0" + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" } }, - "log-symbols": { - "version": "4.1.0", + "node_modules/cross-fetch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", "dev": true, - "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" + "dependencies": { + "node-fetch": "2.6.7" + } + }, + "node_modules/crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dev": true, + "dependencies": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" }, + "engines": { + "node": "*" + } + }, + "node_modules/dash-ast": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dash-ast/-/dash-ast-1.0.0.tgz", + "integrity": "sha512-Vy4dx7gquTeMcQR/hDkYLGUnwVil6vk4FOOct+djUnHOUWt+zJPJAaRIXaAFkPXtJjvlY7o3rfRu0/3hpnwoUA==", + "dev": true + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, "dependencies": { - "chalk": { - "version": "4.1.2", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "has-flag": { - "version": "4.0.0", - "dev": true - }, + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { "supports-color": { - "version": "7.2.0", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } + "optional": true } } }, - "logplease": { - "version": "1.2.15", - "dev": true - }, - "minimatch": { - "version": "3.0.4", + "node_modules/defined": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", + "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==", "dev": true, - "requires": { - "brace-expansion": "^1.1.7" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "minipass": { - "version": "3.1.6", + "node_modules/deps-sort": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.1.tgz", + "integrity": "sha512-1orqXQr5po+3KI6kQb9A4jnXT1PBwggGl2d7Sq2xsnOeI9GPcE/tGcF9UiSZtZBM7MukY4cAh7MemS6tZYipfw==", "dev": true, - "requires": { - "yallist": "^4.0.0" + "dependencies": { + "JSONStream": "^1.0.3", + "shasum-object": "^1.0.0", + "subarg": "^1.0.0", + "through2": "^2.0.0" }, + "bin": { + "deps-sort": "bin/cmd.js" + } + }, + "node_modules/des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "dev": true, "dependencies": { - "yallist": { - "version": "4.0.0", - "dev": true - } + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" } }, - "minizlib": { - "version": "2.1.2", + "node_modules/detective": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.1.tgz", + "integrity": "sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==", "dev": true, - "requires": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" + "dependencies": { + "acorn-node": "^1.8.2", + "defined": "^1.0.0", + "minimist": "^1.2.6" + }, + "bin": { + "detective": "bin/detective.js" }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/devtools-protocol": { + "version": "0.0.1082910", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1082910.tgz", + "integrity": "sha512-RqoZ2GmqaNxyx+99L/RemY5CkwG9D0WEfOKxekwCRXOGrDCep62ngezEJUVMq6rISYQ+085fJnWDQqGHlxVNww==", + "dev": true + }, + "node_modules/diff": { + "version": "5.0.0", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, "dependencies": { - "yallist": { - "version": "4.0.0", - "dev": true - } + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" } }, - "mocha": { - "version": "9.2.0", + "node_modules/diffie-hellman/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", "dev": true, - "requires": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.3", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.2.0", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "3.0.4", - "ms": "2.1.3", - "nanoid": "3.2.0", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "which": "2.0.2", - "workerpool": "6.2.0", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" + "engines": { + "node": ">=0.4", + "npm": ">=1.2" + } + }, + "node_modules/dree": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/dree/-/dree-3.4.4.tgz", + "integrity": "sha512-ROIFLrbCcgp/KcSp2O9ggl4RzCCeyzV9RtlYDpPU4BWUAGUkYcSbzSosaD855WAita45EOaKHiQIc6Oujkprsw==", + "dev": true, + "dependencies": { + "yargs": "^17.6.2" }, + "bin": { + "dree": "bundled/bin/index.js" + } + }, + "node_modules/dree/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, "dependencies": { - "ansi-colors": { - "version": "4.1.1", - "dev": true - }, - "anymatch": { - "version": "3.1.2", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "binary-extensions": { - "version": "2.2.0", - "dev": true - }, - "braces": { - "version": "3.0.2", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "chokidar": { - "version": "3.5.3", - "dev": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - } - }, + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dree/node_modules/yargs": { + "version": "17.6.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", + "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dree/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "dev": true, + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/ejs": { + "version": "3.1.8", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.286", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.286.tgz", + "integrity": "sha512-Vp3CVhmYpgf4iXNKAucoQUDcCrBQX3XLBtwgFqP9BUXuucgvAV9zWp1kYU7LL9j4++s9O+12cb3wMtN4SJy6UQ==", + "dev": true + }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true + }, + "node_modules/fastfile": { + "version": "0.0.20", + "resolved": "https://registry.npmjs.org/fastfile/-/fastfile-0.0.20.tgz", + "integrity": "sha512-r5ZDbgImvVWCP0lA/cGNgQcZqR+aYdFx3u+CtJqUE510pBUVGMn4ulL/iRTI4tACTYsNJ736uzFxEBXesPAktA==", + "dev": true + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/ffjavascript": { + "version": "0.2.55", + "resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.2.55.tgz", + "integrity": "sha512-8X0FCIPOWiK6DTWh3pnE3O6D6nIQsirStAXpWMzRDnoDX7SEnDX4I28aVhwjL7L35XS1vy2AU7zc0UCGYxdLjw==", + "dev": true, + "dependencies": { + "big-integer": "^1.6.48", + "wasmbuilder": "^0.0.12", + "wasmcurves": "0.1.0", + "web-worker": "^1.2.0" + } + }, + "node_modules/filelist": { + "version": "1.0.4", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.0", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/follow-redirects": { + "version": "1.14.7", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { "debug": { - "version": "4.3.3", - "dev": true, - "requires": { - "ms": "2.1.2" - }, - "dependencies": { - "ms": { - "version": "2.1.2", - "dev": true - } - } - }, - "escape-string-regexp": { - "version": "4.0.0", - "dev": true - }, - "fill-range": { - "version": "7.0.1", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-up": { - "version": "5.0.0", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "fsevents": { - "version": "2.3.2", - "dev": true, "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-assigned-identifiers": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz", + "integrity": "sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ==", + "dev": true + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.1.6", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/growl": { + "version": "1.10.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.x" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash-base/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/hash-base/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/he": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dev": true, + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/hoopy": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", + "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==", + "dev": true, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/htmlescape": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz", + "integrity": "sha512-eVcrzgbR4tim7c7soKQKtxa/kQM4TzjnlU83rcZ9bHU6t31ehfV7SktN6McWgwPWg+JYMA/O3qpGxBvFq1z2Jg==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==", + "dev": true + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "dev": true, + "license": "ISC" + }, + "node_modules/inline-source-map": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz", + "integrity": "sha512-0mVWSSbNDvedDWIN4wxLsdPM4a7cIPcpyMxj3QZ406QRwQ6ePGB1YIHxVPjqpcUGbWQ5C+nHTwGNWAGvt7ggVA==", + "dev": true, + "dependencies": { + "source-map": "~0.5.3" + } + }, + "node_modules/insert-module-globals": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.2.1.tgz", + "integrity": "sha512-ufS5Qq9RZN+Bu899eA9QCAYThY+gGW7oRkmb0vC93Vlyu/CFGcH0OYPEjVkDXA5FEbTt1+VWzdoOD3Ny9N+8tg==", + "dev": true, + "dependencies": { + "acorn-node": "^1.5.2", + "combine-source-map": "^0.8.0", + "concat-stream": "^1.6.1", + "is-buffer": "^1.1.0", + "JSONStream": "^1.0.3", + "path-is-absolute": "^1.0.1", + "process": "~0.11.0", + "through2": "^2.0.0", + "undeclared-identifiers": "^1.1.2", + "xtend": "^4.0.0" + }, + "bin": { + "insert-module-globals": "bin/cmd.js" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/jake": { + "version": "10.8.5", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.1", + "minimatch": "^3.0.4" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jake/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jake/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jake/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/js-sha3": { + "version": "0.8.0", + "dev": true, + "license": "MIT" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ] + }, + "node_modules/JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/labeled-stream-splicer": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.2.tgz", + "integrity": "sha512-Ca4LSXFFZUjPScRaqOcFxneA0VpKZr4MMYCljyQr4LIewTLb3Y0IUTIsnBBsVubIeEfxeSZpSjSsRM8APEQaAw==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "stream-splicer": "^2.0.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/locate-path": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, + "node_modules/lodash.memoize": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz", + "integrity": "sha512-eDn9kqrAmVUC1wmZvlQ6Uhde44n+tXpqPrN8olQJbttgh0oKclk+SF54P47VEGE9CEiMeRwAP8BaM7UHvBkz2A==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/logplease": { + "version": "1.2.15", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "dependencies": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "bin": { + "miller-rabin": "bin/miller-rabin" + } + }, + "node_modules/miller-rabin/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "dev": true + }, + "node_modules/minimatch": { + "version": "3.0.4", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "3.1.6", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass/node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/minizlib": { + "version": "2.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true + }, + "node_modules/mocha": { + "version": "9.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.3", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "3.0.4", + "ms": "2.1.3", + "nanoid": "3.2.0", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "workerpool": "6.2.0", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/ansi-colors": { + "version": "4.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/mocha/node_modules/anymatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/mocha/node_modules/binary-extensions": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/braces": { + "version": "3.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/chokidar": { + "version": "3.5.3", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/mocha/node_modules/debug": { + "version": "4.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/mocha/node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/mocha/node_modules/escape-string-regexp": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/fill-range": { + "version": "7.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/find-up": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/fsevents": { + "version": "2.3.2", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/mocha/node_modules/glob": { + "version": "7.2.0", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/glob-parent": { + "version": "5.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/mocha/node_modules/is-binary-path": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/is-number": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/mocha/node_modules/normalize-path": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mocha/node_modules/path-exists": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/readdirp": { + "version": "3.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/mocha/node_modules/strip-json-comments": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/to-regex-range": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/mocha/node_modules/which": { + "version": "2.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/mocha/node_modules/yargs-parser": { + "version": "20.2.4", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/module-deps": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.2.3.tgz", + "integrity": "sha512-fg7OZaQBcL4/L+AK5f4iVqf9OMbCclXfy/znXRxTVhJSeW5AIlS9AwheYwDaXM3lVW7OBeaeUEY3gbaC6cLlSA==", + "dev": true, + "dependencies": { + "browser-resolve": "^2.0.0", + "cached-path-relative": "^1.0.2", + "concat-stream": "~1.6.0", + "defined": "^1.0.0", + "detective": "^5.2.0", + "duplexer2": "^0.1.2", + "inherits": "^2.0.1", + "JSONStream": "^1.0.3", + "parents": "^1.0.0", + "readable-stream": "^2.0.2", + "resolve": "^1.4.0", + "stream-combiner2": "^1.1.1", + "subarg": "^1.0.0", + "through2": "^2.0.0", + "xtend": "^4.0.0" + }, + "bin": { + "module-deps": "bin/cmd.js" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/nanoassert": { + "version": "2.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/nanoid": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-releases": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", + "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", + "dev": true + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==", + "dev": true + }, + "node_modules/p-limit": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pako": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parents": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz", + "integrity": "sha512-mXKF3xkoUt5td2DoxpLmtOmZvko9VfFpwRwkKDHSNvgmpLAeBo18YDhcPbBzJq+QLCHMbGOfzia2cX4U+0v9Mg==", + "dev": true, + "dependencies": { + "path-platform": "~0.11.15" + } + }, + "node_modules/parse-asn1": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", + "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", + "dev": true, + "dependencies": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-platform": { + "version": "0.11.15", + "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz", + "integrity": "sha512-Y30dB6rab1A/nfEKsZxmr01nUotHX0c/ZiIAsCTatEe1CmS5Pm5He7fZ195bPT7RdquoaL8lLxFCMQi/bS7IJg==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "dev": true, + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, + "node_modules/public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "dependencies": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/public-encrypt/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "dev": true + }, + "node_modules/puppeteer": { + "version": "19.6.3", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-19.6.3.tgz", + "integrity": "sha512-K03xTtGDwS6cBXX/EoqoZxglCUKcX2SLIl92fMnGMRjYpPGXoAV2yKEh3QXmXzKqfZXd8TxjjFww+tEttWv8kw==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "cosmiconfig": "8.0.0", + "https-proxy-agent": "5.0.1", + "progress": "2.0.3", + "proxy-from-env": "1.1.0", + "puppeteer-core": "19.6.3" + }, + "engines": { + "node": ">=14.1.0" + } + }, + "node_modules/puppeteer-core": { + "version": "19.6.3", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-19.6.3.tgz", + "integrity": "sha512-8MbhioSlkDaHkmolpQf9Z7ui7jplFfOFTnN8d5kPsCazRRTNIH6/bVxPskn0v5Gh9oqOBlknw0eHH0/OBQAxpQ==", + "dev": true, + "dependencies": { + "cross-fetch": "3.1.5", + "debug": "4.3.4", + "devtools-protocol": "0.0.1082910", + "extract-zip": "2.0.1", + "https-proxy-agent": "5.0.1", + "proxy-from-env": "1.1.0", + "rimraf": "3.0.2", + "tar-fs": "2.1.1", + "unbzip2-stream": "1.4.3", + "ws": "8.11.0" + }, + "engines": { + "node": ">=14.1.0" + } + }, + "node_modules/querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", + "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", + "dev": true, + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==", + "dev": true, + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/r1csfile": { + "version": "0.0.40", + "resolved": "https://registry.npmjs.org/r1csfile/-/r1csfile-0.0.40.tgz", + "integrity": "sha512-3tKaFLncf42ZTRpPMlgyiFBdk6kir4S4O3X+u4UQjgLYoDPHfizazNbK0Jzj++PVIXVUFAqugSbIo4W3UDuHcQ==", + "dev": true, + "dependencies": { + "@iden3/bigarray": "0.0.2", + "@iden3/binfileutils": "0.0.11", + "fastfile": "0.0.20", + "ffjavascript": "0.2.55" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "dependencies": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "node_modules/read-only-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz", + "integrity": "sha512-3ALe0bjBVZtkdWKIcThYpQCLbBMd/+Tbh2CDSrAIDO3UsZ4Xs+tnyjv2MjCOMMgBG+AsUOeuP1cgtY1INISc8w==", + "dev": true, + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", + "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "dev": true + }, + "node_modules/regenerator-transform": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz", + "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regexpu-core": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.2.tgz", + "integrity": "sha512-T0+1Zp2wjF/juXMrMxHxidqGYn8U4R+zleSJhX9tQ1PUsS8a9UtYfbsF9LdiVgNX3kiX8RNaKM42nfSgvFJjmw==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsgen": "^0.7.1", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz", + "integrity": "sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==", + "dev": true + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/shasum-object": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shasum-object/-/shasum-object-1.0.0.tgz", + "integrity": "sha512-Iqo5rp/3xVi6M4YheapzZhhGPVs0yZwHj7wvwQ1B9z8H6zk+FEnI7y3Teq7qwnekfEhu8WmG2z0z4iWZaxLWVg==", + "dev": true, + "dependencies": { + "fast-safe-stringify": "^2.0.7" + } + }, + "node_modules/shell-quote": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.0.tgz", + "integrity": "sha512-QHsz8GgQIGKlRi24yFc6a6lN69Idnx634w49ay6+jA5yFh7a1UY+4Rp6HPx/L/1zcEDPEij8cIsiqR6bQsE5VQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" }, - "glob": { - "version": "7.2.0", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "5.1.2", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "is-binary-path": { - "version": "2.1.0", - "dev": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-number": { - "version": "7.0.0", - "dev": true - }, - "ms": { - "version": "2.1.3", - "dev": true - }, - "normalize-path": { - "version": "3.0.0", - "dev": true - }, - "path-exists": { - "version": "4.0.0", - "dev": true - }, - "readdirp": { - "version": "3.6.0", - "dev": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "strip-json-comments": { - "version": "3.1.1", - "dev": true + { + "type": "patreon", + "url": "https://www.patreon.com/feross" }, - "to-regex-range": { - "version": "5.0.1", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/snarkjs": { + "version": "0.4.25", + "resolved": "https://registry.npmjs.org/snarkjs/-/snarkjs-0.4.25.tgz", + "integrity": "sha512-20manpB7xCd5gkfkioD6GaAR7tgJmN7xQQislJcPV3Xs2Vkf+1Dz6V+LKRwlc/rU/vT/EopUBm5apqvTOKidbQ==", + "dev": true, + "dependencies": { + "@iden3/binfileutils": "0.0.11", + "bfj": "^7.0.2", + "blake2b-wasm": "^2.4.0", + "circom_runtime": "0.1.18", + "ejs": "^3.1.6", + "fastfile": "0.0.20", + "ffjavascript": "0.2.55", + "js-sha3": "^0.8.0", + "logplease": "^1.2.15", + "r1csfile": "0.0.40" + }, + "bin": { + "snarkjs": "build/cli.cjs" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "dev": true, + "dependencies": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, + "node_modules/stream-browserify/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/stream-combiner2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", + "integrity": "sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw==", + "dev": true, + "dependencies": { + "duplexer2": "~0.1.0", + "readable-stream": "^2.0.2" + } + }, + "node_modules/stream-http": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.2.0.tgz", + "integrity": "sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==", + "dev": true, + "dependencies": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "xtend": "^4.0.2" + } + }, + "node_modules/stream-http/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/stream-splicer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.1.tgz", + "integrity": "sha512-Xizh4/NPuYSyAXyT7g8IvdJ9HJpxIGL9PjyhtywCZvvP0OPIdqyrr4dMikeuvY8xahpdKEBlBTySe583totajg==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.2" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" }, - "which": { - "version": "2.0.2", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } + { + "type": "patreon", + "url": "https://www.patreon.com/feross" }, - "yargs-parser": { - "version": "20.2.4", - "dev": true + { + "type": "consulting", + "url": "https://feross.org/support" } + ] + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/subarg": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", + "integrity": "sha512-RIrIdRY0X1xojthNcVtgT9sjpOGagEUKpZdgBUi054OEPFo282yg+zE+t1Rj3+RqKq2xStL7uUHhY+AjbC4BXg==", + "dev": true, + "dependencies": { + "minimist": "^1.1.0" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-color/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/syntax-error": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz", + "integrity": "sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==", + "dev": true, + "dependencies": { + "acorn-node": "^1.2.0" + } + }, + "node_modules/tar": { + "version": "6.1.11", + "dev": true, + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-fs/node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar-stream/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" } }, - "nanoassert": { - "version": "2.0.0", - "dev": true + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "license": "ISC" }, - "nanoid": { - "version": "3.2.0", + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", "dev": true }, - "once": { - "version": "1.4.0", + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", "dev": true, - "requires": { - "wrappy": "1" + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" } }, - "p-limit": { - "version": "3.1.0", + "node_modules/timers-browserify": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz", + "integrity": "sha512-PIxwAupJZiYU4JmVZYwXp9FKsHMXb5h0ZEFyuXTAn8WLHOlcij+FEcbrvDsom1o5dr1YggEtFbECvGCW2sT53Q==", "dev": true, - "requires": { - "yocto-queue": "^0.1.0" + "dependencies": { + "process": "~0.11.0" + }, + "engines": { + "node": ">=0.6.0" } }, - "p-locate": { - "version": "5.0.0", + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", "dev": true, - "requires": { - "p-limit": "^3.0.2" + "engines": { + "node": ">=4" } }, - "path-is-absolute": { + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "node_modules/tryer": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", + "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==", "dev": true }, - "picomatch": { - "version": "2.3.1", + "node_modules/tty-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", + "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==", "dev": true }, - "r1csfile": { - "version": "0.0.40", - "resolved": "https://registry.npmjs.org/r1csfile/-/r1csfile-0.0.40.tgz", - "integrity": "sha512-3tKaFLncf42ZTRpPMlgyiFBdk6kir4S4O3X+u4UQjgLYoDPHfizazNbK0Jzj++PVIXVUFAqugSbIo4W3UDuHcQ==", + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "dev": true + }, + "node_modules/uglify-js": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", "dev": true, - "requires": { - "@iden3/bigarray": "0.0.2", - "@iden3/binfileutils": "0.0.11", - "fastfile": "0.0.20", - "ffjavascript": "0.2.55" + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" } }, - "randombytes": { - "version": "2.1.0", + "node_modules/umd": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.3.tgz", + "integrity": "sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow==", "dev": true, - "requires": { - "safe-buffer": "^5.1.0" + "bin": { + "umd": "bin/cli.js" } }, - "require-directory": { - "version": "2.1.1", - "dev": true - }, - "rimraf": { - "version": "3.0.2", + "node_modules/unbzip2-stream": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", "dev": true, - "requires": { - "glob": "^7.1.3" + "dependencies": { + "buffer": "^5.2.1", + "through": "^2.3.8" } }, - "safe-buffer": { - "version": "5.1.2", - "dev": true + "node_modules/undeclared-identifiers": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/undeclared-identifiers/-/undeclared-identifiers-1.1.3.tgz", + "integrity": "sha512-pJOW4nxjlmfwKApE4zvxLScM/njmwj/DiUBv7EabwE4O8kRUy+HIwxQtZLBPll/jx1LJyBcqNfB3/cpv9EZwOw==", + "dev": true, + "dependencies": { + "acorn-node": "^1.3.0", + "dash-ast": "^1.0.0", + "get-assigned-identifiers": "^1.2.0", + "simple-concat": "^1.0.0", + "xtend": "^4.0.1" + }, + "bin": { + "undeclared-identifiers": "bin.js" + } }, - "serialize-javascript": { - "version": "6.0.0", + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", "dev": true, - "requires": { - "randombytes": "^2.1.0" + "engines": { + "node": ">=4" } }, - "snarkjs": { - "version": "0.4.25", - "resolved": "https://registry.npmjs.org/snarkjs/-/snarkjs-0.4.25.tgz", - "integrity": "sha512-20manpB7xCd5gkfkioD6GaAR7tgJmN7xQQislJcPV3Xs2Vkf+1Dz6V+LKRwlc/rU/vT/EopUBm5apqvTOKidbQ==", + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", "dev": true, - "requires": { - "@iden3/binfileutils": "0.0.11", - "bfj": "^7.0.2", - "blake2b-wasm": "^2.4.0", - "circom_runtime": "0.1.18", - "ejs": "^3.1.6", - "fastfile": "0.0.20", - "ffjavascript": "0.2.55", - "js-sha3": "^0.8.0", - "logplease": "^1.2.15", - "r1csfile": "0.0.40" + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" } }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "engines": { + "node": ">=4" } }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", "dev": true, - "requires": { - "ansi-regex": "^5.0.1" + "engines": { + "node": ">=4" } }, - "supports-color": { - "version": "8.1.1", + "node_modules/update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", "dev": true, - "requires": { - "has-flag": "^4.0.0" + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist-lint": "cli.js" }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ==", + "dev": true, "dependencies": { - "has-flag": { - "version": "4.0.0", - "dev": true - } + "punycode": "1.3.2", + "querystring": "0.2.0" } }, - "tar": { - "version": "6.1.11", + "node_modules/url/node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==", + "dev": true + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", "dev": true, - "requires": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^3.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, "dependencies": { - "mkdirp": { - "version": "1.0.4", - "dev": true - }, - "yallist": { - "version": "4.0.0", - "dev": true - } + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" } }, - "tryer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", - "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==", + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", "dev": true }, - "wasm-pack": { + "node_modules/wasm-pack": { "version": "0.10.2", "dev": true, - "requires": { + "hasInstallScript": true, + "license": "MIT OR Apache-2.0", + "dependencies": { "binary-install": "^0.1.0" + }, + "bin": { + "wasm-pack": "run.js" } }, - "wasmbuilder": { + "node_modules/wasmbuilder": { "version": "0.0.12", "resolved": "https://registry.npmjs.org/wasmbuilder/-/wasmbuilder-0.0.12.tgz", "integrity": "sha512-dTMpBgrnLOXrN58i2zakn2ScynsBhq9LfyQIsPz4CyxRF9k1GAORniuqn3xmE9NnI1l7g3iiVCkoB2Cl0/oG8w==", "dev": true, - "requires": { + "dependencies": { "big-integer": "^1.6.48" } }, - "wasmcurves": { + "node_modules/wasmcurves": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/wasmcurves/-/wasmcurves-0.1.0.tgz", "integrity": "sha512-kIlcgbVUAv2uQ6lGsepGz/m5V40+Z6rvTBkqCYn3Y2+OcXst+UaP4filJYLh/xDxjJl62FFjZZeAnpeli1Y5/Q==", "dev": true, - "requires": { + "dependencies": { "big-integer": "^1.6.42", "blakejs": "^1.1.0" } }, - "web-worker": { + "node_modules/web-worker": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.2.0.tgz", "integrity": "sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA==", "dev": true }, - "workerpool": { - "version": "6.2.0", + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", "dev": true }, - "wrap-ansi": { + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/workerpool": { + "version": "6.2.0", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/wrap-ansi": { "version": "7.0.0", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "wrappy": { + "node_modules/wrappy": { "version": "1.0.2", - "dev": true + "dev": true, + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "engines": { + "node": ">=0.4" + } }, - "y18n": { + "node_modules/y18n": { "version": "5.0.5", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true }, - "yargs": { + "node_modules/yargs": { "version": "16.2.0", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", @@ -2207,35 +5546,75 @@ "string-width": "^4.2.0", "y18n": "^5.0.5", "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" } }, - "yargs-parser": { + "node_modules/yargs-parser": { "version": "20.2.6", - "dev": true + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } }, - "yargs-unparser": { + "node_modules/yargs-unparser": { "version": "2.0.0", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "camelcase": "^6.0.0", "decamelize": "^4.0.0", "flat": "^5.0.2", "is-plain-obj": "^2.1.0" }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser/node_modules/camelcase": { + "version": "6.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yargs-unparser/node_modules/decamelize": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, "dependencies": { - "camelcase": { - "version": "6.3.0", - "dev": true - }, - "decamelize": { - "version": "4.0.0", - "dev": true - } + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" } }, - "yocto-queue": { + "node_modules/yocto-queue": { "version": "0.1.0", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/zokrates_js/package.json b/zokrates_js/package.json index ce404bacd..ddb900a58 100644 --- a/zokrates_js/package.json +++ b/zokrates_js/package.json @@ -1,8 +1,8 @@ { "name": "zokrates-js", - "version": "1.1.4", + "version": "1.1.8", "module": "index.js", - "main": "node/index.js", + "main": "index-node.js", "description": "JavaScript bindings for ZoKrates", "contributors": [ "Darko Macesic ", @@ -15,38 +15,46 @@ ], "license": "GPLv3", "files": [ - "node", - "pkg", "index.js", + "index-node.js", "index.d.ts", - "lib.js", - "metadata.js" + "wasm.js", + "metadata.js", + "umd.min.js" ], "types": "index.d.ts", + "type": "module", "exports": { - "node": "./node/index.js", + "node": "./index-node.js", "default": "./index.js" }, "scripts": { - "wasm-pack": "wasm-pack build --out-name index", + "wasm-pack": "wasm-pack build --out-name index --target web", "prebuild": "npm install", - "build": "npm run build:bundler && npm run build:node", - "build:dev": "npm run build:bundler:dev && npm run build:node:dev", - "build:bundler": "rimraf pkg && npm run wasm-pack -- --target bundler --release && npm run clean-pkg", - "build:bundler:dev": "rimraf pkg && npm run wasm-pack -- --target bundler --dev && npm run clean-pkg", - "build:node": "rimraf node/pkg && npm run wasm-pack -- --target nodejs -d node/pkg --release && npm run clean-node-pkg", - "build:node:dev": "rimraf node/pkg && npm run wasm-pack -- --target nodejs -d node/pkg --dev && npm run clean-node-pkg", - "clean-pkg": "rimraf pkg/README.md pkg/.gitignore pkg/package.json pkg/*.d.ts", - "clean-node-pkg": "rimraf node/pkg/README.md node/pkg/.gitignore node/pkg/package.json node/pkg/*.d.ts", - "pretest": "npm run build:node:dev", + "build": "npm run wasm-pack -- --release && npm run patch && npm run bundle", + "build:dev": "npm run wasm-pack -- --dev && npm run patch && npm run bundle", + "pretest": "npm run build:dev", "test": "npm run run-tests", - "run-tests": "mocha --timeout 100000 --recursive tests" + "run-tests": "mocha --timeout 100000 --recursive tests", + "patch": "node patch.js", + "bundle": "browserify ./index.js --standalone zokrates -t [ babelify --presets [ @babel/preset-env ] ] | uglifyjs --compress --mangle > umd.min.js" }, "devDependencies": { - "dree": "^2.6.1", + "@babel/core": "^7.20.12", + "@babel/preset-env": "^7.20.2", + "acorn": "^8.8.1", + "astring": "^1.8.4", + "babelify": "^10.0.0", + "browserify": "^17.0.0", + "dree": "^3.4.3", "mocha": "^9.2.0", + "puppeteer": "^19.6.0", "rimraf": "^3.0.2", "snarkjs": "^0.4.25", + "uglify-js": "^3.17.4", "wasm-pack": "^0.10.2" + }, + "dependencies": { + "pako": "^2.1.0" } } diff --git a/zokrates_js/patch.js b/zokrates_js/patch.js new file mode 100644 index 000000000..4f4c19aa7 --- /dev/null +++ b/zokrates_js/patch.js @@ -0,0 +1,75 @@ +import { parse } from "acorn"; +import { generate } from "astring"; +import fs from "fs/promises"; +import pako from "pako"; + +(async function () { + const packageObject = JSON.parse( + await fs.readFile("pkg/package.json", { encoding: "utf-8" }) + ); + const wasmPath = packageObject.files.find((file) => file.endsWith(".wasm")); + const wasm = await fs.readFile(`pkg/${wasmPath}`); + + const deflated = Buffer.from(pako.deflate(wasm)); + const wasmBase64 = deflated.toString("base64"); + + const init = `export async function init(inflate) { + const encoded = '${wasmBase64}'; + + let bytes; + + if (typeof Buffer === "function") { + bytes = Buffer.from(encoded, "base64"); + } else if (typeof atob === "function") { + const binary = atob(encoded); + bytes = new Uint8Array(binary.length); + + for (let i = 0; i < binary.length; i++) { + bytes[i] = binary.charCodeAt(i); + } + } else { + throw new Error("Unsupported platform"); + } + + const imports = getImports(); + initMemory(imports); + + bytes = inflate(bytes); + + const { instance, module } = await WebAssembly.instantiate(bytes, imports); + return finalizeInit(instance, module); +} + +export default init;`; + + const generatedSource = await fs.readFile(`pkg/${packageObject.module}`, { + encoding: "utf-8", + }); + + const ast = parse(generatedSource, { + ecmaVersion: "latest", + sourceType: "module", + }); + + let body = ast.body.filter((v) => { + switch (v.type) { + case "FunctionDeclaration": + // we don't use these functions so we strip them out + return !["load", "init", "initSync"].includes(v.id.name); + case "ExportDefaultDeclaration": + // we will provide our own default export + return false; + default: + return true; + } + }); + + body.pop(); // removes `export { initSync }` + + const source = generate({ + ...ast, + body, + }); + + await fs.writeFile("wasm.js", source + init); +})(); diff --git a/zokrates_js/publish.sh b/zokrates_js/publish.sh index f625a0c0f..681dcd1a8 100755 --- a/zokrates_js/publish.sh +++ b/zokrates_js/publish.sh @@ -24,12 +24,6 @@ if [ $NPM_VERSION = $PACKAGE_VERSION ]; then exit 0 fi -# make sure the pkg folder is present -if [ ! -d "pkg" ]; then - echo "pkg folder is missing" - exit 1 -fi - # publish npm set //registry.npmjs.org/:_authToken=${NPM_TOKEN} npm publish \ No newline at end of file diff --git a/zokrates_js/src/lib.rs b/zokrates_js/src/lib.rs index 07082c3e5..b39d0169c 100644 --- a/zokrates_js/src/lib.rs +++ b/zokrates_js/src/lib.rs @@ -4,6 +4,7 @@ mod util; extern crate lazy_static; use crate::util::normalize_path; +use rand_0_8::{rngs::StdRng, SeedableRng}; use serde::{Deserialize, Serialize}; use serde_json::to_string_pretty; use std::convert::TryFrom; @@ -23,8 +24,11 @@ use zokrates_common::helpers::{BackendParameter, CurveParameter, SchemeParameter use zokrates_common::{CompileConfig, Resolver}; use zokrates_core::compile::{compile as core_compile, CompilationArtifacts, CompileError}; use zokrates_core::imports::Error; -use zokrates_field::{Bls12_377Field, Bls12_381Field, Bn128Field, Bw6_761Field, Field}; +use zokrates_field::{ + Bls12_377Field, Bls12_381Field, Bn128Field, Bw6_761Field, Field, PallasField, VestaField, +}; use zokrates_proof_systems::groth16::G16; +use zokrates_proof_systems::rng::get_rng_from_entropy; use zokrates_proof_systems::{ Backend, Marlin, NonUniversalBackend, NonUniversalScheme, Proof, Scheme, SolidityCompatibleField, SolidityCompatibleScheme, TaggedKeypair, TaggedProof, @@ -51,6 +55,7 @@ impl CompilationResult { arr.copy_from(&self.program); arr } + pub fn abi(&self) -> JsValue { JsValue::from_serde(&self.abi).unwrap() } @@ -76,19 +81,23 @@ pub struct ResolverResult { #[wasm_bindgen] pub struct ComputationResult { - witness: String, + witness: Vec, output: String, snarkjs_witness: Option>, } #[wasm_bindgen] impl ComputationResult { - pub fn witness(&self) -> JsValue { - JsValue::from_str(&self.witness) + pub fn witness(&self) -> js_sys::Uint8Array { + let arr = js_sys::Uint8Array::new_with_length(self.witness.len() as u32); + arr.copy_from(&self.witness); + arr } + pub fn output(&self) -> JsValue { JsValue::from_str(&self.output) } + pub fn snarkjs_witness(&self) -> Option { self.snarkjs_witness.as_ref().map(|w| { let arr = js_sys::Uint8Array::new_with_length(w.len() as u32); @@ -98,6 +107,25 @@ impl ComputationResult { } } +#[wasm_bindgen] +pub struct Keypair { + vk: JsValue, + pk: Vec, +} + +#[wasm_bindgen] +impl Keypair { + pub fn vk(&self) -> JsValue { + self.vk.to_owned() + } + + pub fn pk(&self) -> js_sys::Uint8Array { + let arr = js_sys::Uint8Array::new_with_length(self.pk.len() as u32); + arr.copy_from(&self.pk); + arr + } +} + pub struct JsResolver<'a> { callback: &'a js_sys::Function, } @@ -127,7 +155,7 @@ impl<'a> Resolver for JsResolver<'a> { Some(Component::Normal(_)) => { let path_normalized = normalize_path(path); let source = STDLIB - .get(&path_normalized.to_str().unwrap()) + .get(path_normalized.to_str().unwrap()) .ok_or_else(|| { Error::new(format!( "module `{}` not found in stdlib", @@ -202,6 +230,7 @@ impl<'a> Write for LogWriter<'a> { fn write(&mut self, buf: &[u8]) -> std::io::Result { self.buf.write(buf) } + fn flush(&mut self) -> std::io::Result<()> { self.callback .call1( @@ -220,6 +249,7 @@ impl<'a> Write for LogWriter<'a> { mod internal { use super::*; + use rand_0_8::{CryptoRng, RngCore}; pub fn compile( source: JsValue, @@ -316,12 +346,18 @@ mod internal { }; let interpreter = zokrates_interpreter::Interpreter::default(); - let public_inputs = program.public_inputs(); let mut writer = LogWriter::new(log_callback); + let witness = interpreter - .execute_with_log_stream(program, &inputs.encode(), &mut writer) + .execute_with_log_stream( + &inputs.encode(), + program.statements.into_iter(), + &program.arguments, + &program.solvers, + &mut writer, + ) .map_err(|err| JsValue::from_str(&format!("Execution failed: {}", err)))?; let return_values: serde_json::Value = @@ -334,8 +370,14 @@ mod internal { buffer.into_inner() }); + let witness = { + let mut buffer = Cursor::new(vec![]); + witness.write(&mut buffer).unwrap(); + buffer.into_inner() + }; + Ok(ComputationResult { - witness: format!("{}", witness), + witness, output: to_string_pretty(&return_values).unwrap(), snarkjs_witness, }) @@ -345,12 +387,17 @@ mod internal { T: Field, S: NonUniversalScheme + Serialize, B: NonUniversalBackend, + R: RngCore + CryptoRng, >( program: ir::Prog, - ) -> JsValue { - let keypair = B::setup(program); + rng: &mut R, + ) -> Keypair { + let keypair = B::setup(program, rng); let tagged_keypair = TaggedKeypair::::new(keypair); - JsValue::from_serde(&tagged_keypair).unwrap() + Keypair { + vk: JsValue::from_serde(&tagged_keypair.vk).unwrap(), + pk: tagged_keypair.pk, + } } pub fn setup_universal< @@ -362,27 +409,37 @@ mod internal { >( srs: &[u8], program: ir::ProgIterator<'a, T, I>, - ) -> Result { + ) -> Result { let keypair = B::setup(srs.to_vec(), program).map_err(|e| JsValue::from_str(&e))?; - Ok(JsValue::from_serde(&TaggedKeypair::::new(keypair)).unwrap()) + let tagged_keypair = TaggedKeypair::::new(keypair); + Ok(Keypair { + vk: JsValue::from_serde(&tagged_keypair.vk).unwrap(), + pk: tagged_keypair.pk, + }) } - pub fn universal_setup_of_size, B: UniversalBackend>( + pub fn universal_setup_of_size< + T: Field, + S: UniversalScheme, + B: UniversalBackend, + R: RngCore + CryptoRng, + >( size: u32, + rng: &mut R, ) -> Vec { - B::universal_setup(size) + B::universal_setup(size, rng) } - pub fn generate_proof, B: Backend>( + pub fn generate_proof, B: Backend, R: RngCore + CryptoRng>( prog: ir::Prog, - witness: JsValue, + witness: &[u8], pk: &[u8], + rng: &mut R, ) -> Result { - let str_witness = witness.as_string().unwrap(); - let ir_witness: ir::Witness = ir::Witness::read(str_witness.as_bytes()) + let ir_witness: ir::Witness = ir::Witness::read(witness) .map_err(|err| JsValue::from_str(&format!("Could not read witness: {}", err)))?; - let proof = B::generate_proof(prog, ir_witness, pk.to_vec()); + let proof = B::generate_proof(prog, ir_witness, pk, rng); Ok(JsValue::from_serde(&TaggedProof::::new(proof.proof, proof.inputs)).unwrap()) } @@ -460,6 +517,12 @@ pub fn compile( CurveParameter::Bw6_761 => { internal::compile::(source, location, resolve_callback, config) } + CurveParameter::Pallas => { + internal::compile::(source, location, resolve_callback, config) + } + CurveParameter::Vesta => { + internal::compile::(source, location, resolve_callback, config) + } } } @@ -471,7 +534,8 @@ pub fn compute_witness( config: JsValue, log_callback: &js_sys::Function, ) -> Result { - let prog = ir::ProgEnum::deserialize(program) + let cursor = Cursor::new(program); + let prog = ir::ProgEnum::deserialize(cursor) .map_err(|err| JsValue::from_str(&err))? .collect(); match prog { @@ -479,6 +543,8 @@ pub fn compute_witness( ProgEnum::Bls12_381Program(p) => internal::compute::<_>(p, abi, args, config, log_callback), ProgEnum::Bls12_377Program(p) => internal::compute::<_>(p, abi, args, config, log_callback), ProgEnum::Bw6_761Program(p) => internal::compute::<_>(p, abi, args, config, log_callback), + ProgEnum::PallasProgram(p) => internal::compute::<_>(p, abi, args, config, log_callback), + ProgEnum::VestaProgram(p) => internal::compute::<_>(p, abi, args, config, log_callback), } } @@ -516,7 +582,7 @@ pub fn export_solidity_verifier(vk: JsValue) -> Result { } #[wasm_bindgen] -pub fn setup(program: &[u8], options: JsValue) -> Result { +pub fn setup(program: &[u8], entropy: JsValue, options: JsValue) -> Result { let options: serde_json::Value = options.into_serde().unwrap(); let backend = BackendParameter::try_from( @@ -533,36 +599,62 @@ pub fn setup(program: &[u8], options: JsValue) -> Result { ) .map_err(|e| JsValue::from_str(&e))?; - let prog = ir::ProgEnum::deserialize(program) + let cursor = Cursor::new(program); + let prog = ir::ProgEnum::deserialize(cursor) .map_err(|err| JsValue::from_str(&err))? .collect(); + let mut rng = entropy + .as_string() + .map(|s| get_rng_from_entropy(&s)) + .unwrap_or_else(StdRng::from_entropy); + match (backend, scheme) { (BackendParameter::Bellman, SchemeParameter::G16) => match prog { - ProgEnum::Bn128Program(p) => Ok(internal::setup_non_universal::<_, G16, Bellman>(p)), + ProgEnum::Bn128Program(p) => Ok(internal::setup_non_universal::<_, G16, Bellman, _>( + p, &mut rng, + )), ProgEnum::Bls12_381Program(_) => Err(JsValue::from_str( "Not supported: https://github.com/Zokrates/ZoKrates/issues/1200", )), _ => Err(JsValue::from_str("Not supported")), }, (BackendParameter::Ark, SchemeParameter::G16) => match prog { - ProgEnum::Bn128Program(p) => Ok(internal::setup_non_universal::<_, G16, Ark>(p)), - ProgEnum::Bls12_381Program(p) => Ok(internal::setup_non_universal::<_, G16, Ark>(p)), - ProgEnum::Bls12_377Program(p) => Ok(internal::setup_non_universal::<_, G16, Ark>(p)), - ProgEnum::Bw6_761Program(p) => Ok(internal::setup_non_universal::<_, G16, Ark>(p)), + ProgEnum::Bn128Program(p) => { + Ok(internal::setup_non_universal::<_, G16, Ark, _>(p, &mut rng)) + } + ProgEnum::Bls12_381Program(p) => { + Ok(internal::setup_non_universal::<_, G16, Ark, _>(p, &mut rng)) + } + ProgEnum::Bls12_377Program(p) => { + Ok(internal::setup_non_universal::<_, G16, Ark, _>(p, &mut rng)) + } + ProgEnum::Bw6_761Program(p) => { + Ok(internal::setup_non_universal::<_, G16, Ark, _>(p, &mut rng)) + } + _ => Err(JsValue::from_str("Not supported")), }, (BackendParameter::Ark, SchemeParameter::GM17) => match prog { - ProgEnum::Bn128Program(p) => Ok(internal::setup_non_universal::<_, GM17, Ark>(p)), - ProgEnum::Bls12_381Program(p) => Ok(internal::setup_non_universal::<_, GM17, Ark>(p)), - ProgEnum::Bls12_377Program(p) => Ok(internal::setup_non_universal::<_, GM17, Ark>(p)), - ProgEnum::Bw6_761Program(p) => Ok(internal::setup_non_universal::<_, GM17, Ark>(p)), + ProgEnum::Bn128Program(p) => Ok(internal::setup_non_universal::<_, GM17, Ark, _>( + p, &mut rng, + )), + ProgEnum::Bls12_381Program(p) => Ok(internal::setup_non_universal::<_, GM17, Ark, _>( + p, &mut rng, + )), + ProgEnum::Bls12_377Program(p) => Ok(internal::setup_non_universal::<_, GM17, Ark, _>( + p, &mut rng, + )), + ProgEnum::Bw6_761Program(p) => Ok(internal::setup_non_universal::<_, GM17, Ark, _>( + p, &mut rng, + )), + _ => Err(JsValue::from_str("Not supported")), }, _ => Err(JsValue::from_str("Unsupported options")), } } #[wasm_bindgen] -pub fn setup_with_srs(srs: &[u8], program: &[u8], options: JsValue) -> Result { +pub fn setup_with_srs(srs: &[u8], program: &[u8], options: JsValue) -> Result { let options: serde_json::Value = options.into_serde().unwrap(); let scheme = SchemeParameter::try_from( @@ -572,7 +664,8 @@ pub fn setup_with_srs(srs: &[u8], program: &[u8], options: JsValue) -> Result Result internal::setup_universal::<_, _, Marlin, Ark>(srs, p), ProgEnum::Bls12_377Program(p) => internal::setup_universal::<_, _, Marlin, Ark>(srs, p), ProgEnum::Bw6_761Program(p) => internal::setup_universal::<_, _, Marlin, Ark>(srs, p), + _ => Err(JsValue::from_str("Not supported")), }, _ => Err(JsValue::from_str("Given scheme is not universal")), } } #[wasm_bindgen] -pub fn universal_setup(curve: JsValue, size: u32) -> Result, JsValue> { +pub fn universal_setup(curve: JsValue, size: u32, entropy: JsValue) -> Result, JsValue> { let curve = CurveParameter::try_from(curve.as_string().unwrap().as_str()) .map_err(|e| JsValue::from_str(&e))?; + let mut rng = entropy + .as_string() + .map(|s| get_rng_from_entropy(&s)) + .unwrap_or_else(StdRng::from_entropy); + match curve { - CurveParameter::Bn128 => { - Ok(internal::universal_setup_of_size::(size)) - } + CurveParameter::Bn128 => Ok(internal::universal_setup_of_size::< + Bn128Field, + Marlin, + Ark, + _, + >(size, &mut rng)), CurveParameter::Bls12_381 => Ok(internal::universal_setup_of_size::< Bls12_381Field, Marlin, Ark, - >(size)), + _, + >(size, &mut rng)), CurveParameter::Bls12_377 => Ok(internal::universal_setup_of_size::< Bls12_377Field, Marlin, Ark, - >(size)), - CurveParameter::Bw6_761 => { - Ok(internal::universal_setup_of_size::(size)) - } + _, + >(size, &mut rng)), + CurveParameter::Bw6_761 => Ok(internal::universal_setup_of_size::< + Bw6_761Field, + Marlin, + Ark, + _, + >(size, &mut rng)), + c => Err(JsValue::from(format!( + "Curve `{}` is not supported for universal setups", + c + ))), } } #[wasm_bindgen] pub fn generate_proof( program: &[u8], - witness: JsValue, + witness: &[u8], pk: &[u8], + entropy: JsValue, options: JsValue, ) -> Result { let options: serde_json::Value = options.into_serde().unwrap(); @@ -635,14 +747,20 @@ pub fn generate_proof( ) .map_err(|e| JsValue::from_str(&e))?; - let prog = ir::ProgEnum::deserialize(program) + let cursor = Cursor::new(program); + let prog = ir::ProgEnum::deserialize(cursor) .map_err(|err| JsValue::from_str(&err))? .collect(); + let mut rng = entropy + .as_string() + .map(|s| get_rng_from_entropy(&s)) + .unwrap_or_else(StdRng::from_entropy); + match (backend, scheme) { (BackendParameter::Bellman, SchemeParameter::G16) => match prog { ProgEnum::Bn128Program(p) => { - internal::generate_proof::<_, G16, Bellman>(p, witness, pk) + internal::generate_proof::<_, G16, Bellman, _>(p, witness, pk, &mut rng) } ProgEnum::Bls12_381Program(_) => Err(JsValue::from_str( "Not supported: https://github.com/Zokrates/ZoKrates/issues/1200", @@ -650,36 +768,49 @@ pub fn generate_proof( _ => Err(JsValue::from_str("Not supported")), }, (BackendParameter::Ark, SchemeParameter::G16) => match prog { - ProgEnum::Bn128Program(p) => internal::generate_proof::<_, G16, Ark>(p, witness, pk), + ProgEnum::Bn128Program(p) => { + internal::generate_proof::<_, G16, Ark, _>(p, witness, pk, &mut rng) + } ProgEnum::Bls12_381Program(p) => { - internal::generate_proof::<_, G16, Ark>(p, witness, pk) + internal::generate_proof::<_, G16, Ark, _>(p, witness, pk, &mut rng) } ProgEnum::Bls12_377Program(p) => { - internal::generate_proof::<_, G16, Ark>(p, witness, pk) + internal::generate_proof::<_, G16, Ark, _>(p, witness, pk, &mut rng) } - ProgEnum::Bw6_761Program(p) => internal::generate_proof::<_, G16, Ark>(p, witness, pk), + ProgEnum::Bw6_761Program(p) => { + internal::generate_proof::<_, G16, Ark, _>(p, witness, pk, &mut rng) + } + _ => Err(JsValue::from_str("Not supported")), }, (BackendParameter::Ark, SchemeParameter::GM17) => match prog { - ProgEnum::Bn128Program(p) => internal::generate_proof::<_, GM17, Ark>(p, witness, pk), + ProgEnum::Bn128Program(p) => { + internal::generate_proof::<_, GM17, Ark, _>(p, witness, pk, &mut rng) + } ProgEnum::Bls12_381Program(p) => { - internal::generate_proof::<_, GM17, Ark>(p, witness, pk) + internal::generate_proof::<_, GM17, Ark, _>(p, witness, pk, &mut rng) } ProgEnum::Bls12_377Program(p) => { - internal::generate_proof::<_, GM17, Ark>(p, witness, pk) + internal::generate_proof::<_, GM17, Ark, _>(p, witness, pk, &mut rng) } - ProgEnum::Bw6_761Program(p) => internal::generate_proof::<_, GM17, Ark>(p, witness, pk), + ProgEnum::Bw6_761Program(p) => { + internal::generate_proof::<_, GM17, Ark, _>(p, witness, pk, &mut rng) + } + _ => Err(JsValue::from_str("Not supported")), }, (BackendParameter::Ark, SchemeParameter::MARLIN) => match prog { - ProgEnum::Bn128Program(p) => internal::generate_proof::<_, Marlin, Ark>(p, witness, pk), + ProgEnum::Bn128Program(p) => { + internal::generate_proof::<_, Marlin, Ark, _>(p, witness, pk, &mut rng) + } ProgEnum::Bls12_381Program(p) => { - internal::generate_proof::<_, Marlin, Ark>(p, witness, pk) + internal::generate_proof::<_, Marlin, Ark, _>(p, witness, pk, &mut rng) } ProgEnum::Bls12_377Program(p) => { - internal::generate_proof::<_, Marlin, Ark>(p, witness, pk) + internal::generate_proof::<_, Marlin, Ark, _>(p, witness, pk, &mut rng) } ProgEnum::Bw6_761Program(p) => { - internal::generate_proof::<_, Marlin, Ark>(p, witness, pk) + internal::generate_proof::<_, Marlin, Ark, _>(p, witness, pk, &mut rng) } + _ => Err(JsValue::from_str("Not supported")), }, _ => Err(JsValue::from_str("Unsupported options")), } @@ -752,18 +883,21 @@ pub fn verify(vk: JsValue, proof: JsValue, options: JsValue) -> Result internal::verify::(vk, proof), CurveParameter::Bls12_377 => internal::verify::(vk, proof), CurveParameter::Bw6_761 => internal::verify::(vk, proof), + _ => Err(JsValue::from_str("Not supported")), }, (BackendParameter::Ark, SchemeParameter::GM17) => match curve { CurveParameter::Bn128 => internal::verify::(vk, proof), CurveParameter::Bls12_381 => internal::verify::(vk, proof), CurveParameter::Bls12_377 => internal::verify::(vk, proof), CurveParameter::Bw6_761 => internal::verify::(vk, proof), + _ => Err(JsValue::from_str("Not supported")), }, (BackendParameter::Ark, SchemeParameter::MARLIN) => match curve { CurveParameter::Bn128 => internal::verify::(vk, proof), CurveParameter::Bls12_381 => internal::verify::(vk, proof), CurveParameter::Bls12_377 => internal::verify::(vk, proof), CurveParameter::Bw6_761 => internal::verify::(vk, proof), + _ => Err(JsValue::from_str("Not supported")), }, _ => Err(JsValue::from_str("Unsupported options")), } diff --git a/zokrates_js/tests/tests.js b/zokrates_js/tests/tests.js index 8202baa12..ad43c5dbd 100644 --- a/zokrates_js/tests/tests.js +++ b/zokrates_js/tests/tests.js @@ -1,10 +1,10 @@ -const assert = require("assert"); -const path = require("path"); -const fs = require("fs"); -const os = require("os"); -const dree = require("dree"); -const snarkjs = require("snarkjs"); -const { initialize, metadata } = require("../node/index.js"); +import assert from "assert"; +import path from "path"; +import fs from "fs"; +import os from "os"; +import * as snarkjs from "snarkjs"; +import dree from "dree"; +import { initialize, metadata } from "../index-node.js"; let zokratesProvider; let tmpFolder; @@ -38,25 +38,21 @@ describe("tests", () => { describe("compilation", () => { it("should compile", () => { - assert.doesNotThrow(() => { - const artifacts = zokratesProvider.compile( - "def main() -> field { return 42; }" - ); - assert.ok(artifacts); - assert.ok(artifacts.snarkjs === undefined); - assert.equal(artifacts.constraintCount, 1); - }); + const artifacts = zokratesProvider.compile( + "def main() -> field { return 42; }" + ); + assert.ok(artifacts); + assert.ok(artifacts.snarkjs === undefined); + assert.equal(artifacts.constraintCount, 1); }); it("should compile with snarkjs output", () => { - assert.doesNotThrow(() => { - const artifacts = zokratesProvider.compile( - "def main() -> field { return 42; }", - { snarkjs: true } - ); - assert.ok(artifacts); - assert.ok(artifacts.snarkjs.program !== undefined); - }); + const artifacts = zokratesProvider.compile( + "def main() -> field { return 42; }", + { snarkjs: true } + ); + assert.ok(artifacts); + assert.ok(artifacts.snarkjs.program !== undefined); }); it("should throw on invalid code", () => { @@ -64,26 +60,22 @@ describe("tests", () => { }); it("should resolve stdlib module", () => { - assert.doesNotThrow(() => { - const code = `import "utils/pack/bool/unpack" as unpack;\ndef main() { return; }`; - zokratesProvider.compile(code); - }); + const code = `import "utils/pack/bool/unpack_unchecked";\ndef main() {}`; + zokratesProvider.compile(code); }); it("should resolve user module", () => { - assert.doesNotThrow(() => { - const code = - 'import "./test" as test;\ndef main() -> field { return test(); }'; - const options = { - resolveCallback: (_, path) => { - return { - source: "def main() -> field { return 1; }", - location: path, - }; - }, - }; - zokratesProvider.compile(code, options); - }); + const code = + 'import "./test" as test;\ndef main() -> field { return test(); }'; + const options = { + resolveCallback: (_, path) => { + return { + source: "def main() -> field { return 1; }", + location: path, + }; + }, + }; + zokratesProvider.compile(code, options); }); it("should throw on unresolved module", () => { @@ -97,29 +89,25 @@ describe("tests", () => { describe("computation", () => { it("should compute with valid inputs", () => { - assert.doesNotThrow(() => { - const code = "def main(private field a) -> field { return a * a; }"; - const artifacts = zokratesProvider.compile(code); - const result = zokratesProvider.computeWitness(artifacts, ["2"]); - const output = JSON.parse(result.output); - assert.deepEqual(output, "4"); - assert.ok(result.snarkjs === undefined); - }); + const code = "def main(private field a) -> field { return a * a; }"; + const artifacts = zokratesProvider.compile(code); + const result = zokratesProvider.computeWitness(artifacts, ["2"]); + const output = JSON.parse(result.output); + assert.deepEqual(output, "4"); + assert.ok(result.snarkjs === undefined); }); it("should compute with valid inputs with snarkjs output", () => { - assert.doesNotThrow(() => { - const code = "def main(private field a) -> field { return a * a; }"; - const artifacts = zokratesProvider.compile(code); + const code = "def main(private field a) -> field { return a * a; }"; + const artifacts = zokratesProvider.compile(code); - const result = zokratesProvider.computeWitness(artifacts, ["2"], { - snarkjs: true, - }); - - const output = JSON.parse(result.output); - assert.deepEqual(output, "4"); - assert.ok(result.snarkjs.witness !== undefined); + const result = zokratesProvider.computeWitness(artifacts, ["2"], { + snarkjs: true, }); + + const output = JSON.parse(result.output); + assert.deepEqual(output, "4"); + assert.ok(result.snarkjs.witness !== undefined); }); it("should throw on invalid input count", () => { @@ -139,19 +127,17 @@ describe("tests", () => { }); it("should log in debug", () => { - assert.doesNotThrow(() => { - const code = 'def main() { log("{}", 1f); log("{}", 2f); return; }'; - const artifacts = zokratesProvider.compile(code, { - config: { debug: true }, - }); - let logs = []; - zokratesProvider.computeWitness(artifacts, [], { - logCallback: (l) => { - logs.push(l); - }, - }); - assert.deepEqual(logs, ['"1"', '"2"']); + const code = 'def main() { log("{}", 1f); log("{}", 2f); return; }'; + const artifacts = zokratesProvider.compile(code, { + config: { debug: true }, + }); + let logs = []; + zokratesProvider.computeWitness(artifacts, [], { + logCallback: (l) => { + logs.push(l); + }, }); + assert.deepEqual(logs, ['"1"', '"2"']); }); }); @@ -167,37 +153,53 @@ describe("tests", () => { }); it("compile", () => { - assert.doesNotThrow(() => { - const code = `def main(private field a, field b) -> bool { - bool check = if (a == 0){ true} else {a * a == b}; - assert(check); - return true; - }`; - artifacts = provider.compile(code, { snarkjs: true }); - }); + const code = `def main(private field a, field b) -> bool { + bool check = if (a == 0) { true } else { a * a == b }; + assert(check); + return true; + }`; + artifacts = provider.compile(code, { snarkjs: true }); }); it("compute witness", () => { - assert.doesNotThrow(() => { - computationResult = provider.computeWitness( - artifacts, - ["337", "113569"], - { - snarkjs: true, - } - ); - }); + computationResult = provider.computeWitness( + artifacts, + ["337", "113569"], + { + snarkjs: true, + } + ); }); it("setup", () => { - assert.doesNotThrow(() => { - if (options.scheme === "marlin") { - const srs = provider.universalSetup(4); - keypair = provider.setupWithSrs(srs, artifacts.program); - } else { - keypair = provider.setup(artifacts.program); - } - }); + if (options.scheme === "marlin") { + const srs = provider.universalSetup(4); + const srs2 = provider.universalSetup(4); + // second call should return a new srs + assert.notDeepEqual(srs, srs2); + keypair = provider.setupWithSrs(srs, artifacts.program); + } else { + keypair = provider.setup(artifacts.program); + const keypair2 = provider.setup(artifacts.program); + // second call should return a new keypair + assert.notDeepEqual(keypair, keypair2); + } + }); + + it("setup with user-provided entropy", () => { + let entropy = "f5c51ca46c331965"; + if (options.scheme === "marlin") { + const srs = provider.universalSetup(4, entropy); + const srs2 = provider.universalSetup(4, entropy); + // second call with the same entropy should return the same srs + assert.deepEqual(srs, srs2); + keypair = provider.setupWithSrs(srs, artifacts.program); + } else { + keypair = provider.setup(artifacts.program, entropy); + const keypair2 = provider.setup(artifacts.program, entropy); + // second call with the same entropy should return the same keypair + assert.deepEqual(keypair, keypair2); + } }); if (options.scheme === "g16" && options.curve == "bn128") { @@ -220,23 +222,48 @@ describe("tests", () => { if (options.curve === "bn128" && ["g16", "gm17"].includes(options.scheme)) { it("export verifier", () => { - assert.doesNotThrow(() => { - let verifier = provider.exportSolidityVerifier(keypair.vk); - assert.ok(verifier.includes("contract")); - }); + let verifier = provider.exportSolidityVerifier(keypair.vk); + assert.ok(verifier.includes("contract")); }); } it("generate proof", () => { - assert.doesNotThrow(() => { - proof = provider.generateProof( - artifacts.program, - computationResult.witness, - keypair.pk - ); - assert.ok(proof !== undefined); - assert.equal(proof.inputs.length, 2); - }); + proof = provider.generateProof( + artifacts.program, + computationResult.witness, + keypair.pk + ); + assert.ok(proof !== undefined); + assert.equal(proof.inputs.length, 2); + + // second call should return a new proof + let proof2 = provider.generateProof( + artifacts.program, + computationResult.witness, + keypair.pk + ); + assert.notDeepEqual(proof, proof2); + }); + + it("generate proof with user-provided entropy", () => { + let entropy = "326e2c864f414ffb"; + proof = provider.generateProof( + artifacts.program, + computationResult.witness, + keypair.pk, + entropy + ); + assert.ok(proof !== undefined); + assert.equal(proof.inputs.length, 2); + + // second call with the same entropy should return the same proof + let proof2 = provider.generateProof( + artifacts.program, + computationResult.witness, + keypair.pk, + entropy + ); + assert.deepEqual(proof, proof2); }); if (options.scheme === "g16" && options.curve == "bn128") { @@ -264,9 +291,7 @@ describe("tests", () => { } it("verify", () => { - assert.doesNotThrow(() => { - assert(provider.verify(keypair.vk, proof) === true); - }); + assert(provider.verify(keypair.vk, proof) === true); }); }; @@ -364,8 +389,8 @@ describe("tests", () => { extensions: ["json"], }; - dree.scan(testsPath, options, function (file) { - const test = require(file.path); + dree.scan(testsPath, options, async function (file) { + const test = JSON.parse(await fs.promises.readFile(file.path)); const testName = file.path.substring(testsPath.length + 1); if (!ignoreList.some((v) => testName.startsWith(v))) diff --git a/zokrates_js/tests/umd/index.html b/zokrates_js/tests/umd/index.html new file mode 100644 index 000000000..cfb8fe740 --- /dev/null +++ b/zokrates_js/tests/umd/index.html @@ -0,0 +1,38 @@ + + + + + + + Test Document + + + + + + diff --git a/zokrates_js/tests/umd/tests.js b/zokrates_js/tests/umd/tests.js new file mode 100644 index 000000000..4bda5f8a6 --- /dev/null +++ b/zokrates_js/tests/umd/tests.js @@ -0,0 +1,27 @@ +import puppeteer from "puppeteer"; +import assert from "assert"; +import path from "path"; + +describe("umd web tests", () => { + it("verify", async () => { + const browser = await puppeteer.launch({ + headless: true, + args: ["--no-sandbox", "--disable-setuid-sandbox"], + }); + const page = await browser.newPage(); + + let response = await page.goto( + path.dirname(import.meta.url) + "/index.html" + ); + assert(response.ok()); + + let element = await page.waitForSelector("#result", { + timeout: 30000, + visible: true, + }); + let value = await element.evaluate((el) => el.textContent, element); + assert.equal(value, "true"); + + await browser.close(); + }); +}); diff --git a/zokrates_parser/Cargo.toml b/zokrates_parser/Cargo.toml index d5b222ddc..f781d2959 100644 --- a/zokrates_parser/Cargo.toml +++ b/zokrates_parser/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "zokrates_parser" -version = "0.3.2" +version = "0.3.5" authors = ["JacobEberhardt "] edition = "2018" [dependencies] -pest = "2.0" +pest = "=2.3" pest_derive = "2.0" [dev-dependencies] diff --git a/zokrates_parser/src/lib.rs b/zokrates_parser/src/lib.rs index b4f9cb85c..eb61ce2d8 100644 --- a/zokrates_parser/src/lib.rs +++ b/zokrates_parser/src/lib.rs @@ -12,6 +12,7 @@ use pest::Parser; #[grammar = "zokrates.pest"] struct ZoKratesParser; +#[allow(clippy::result_large_err)] pub fn parse(input: &str) -> Result, Error> { ZoKratesParser::parse(Rule::file, input) } diff --git a/zokrates_pest_ast/Cargo.toml b/zokrates_pest_ast/Cargo.toml index 2f609a34f..08a976b59 100644 --- a/zokrates_pest_ast/Cargo.toml +++ b/zokrates_pest_ast/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "zokrates_pest_ast" -version = "0.3.0" +version = "0.3.3" authors = ["schaeff "] edition = "2018" [dependencies] zokrates_parser = { version = "0.3.0", path = "../zokrates_parser" } -pest = "2.0" +pest = "=2.3" pest-ast = "0.3.3" from-pest = "0.3.1" lazy_static = "1.3.0" diff --git a/zokrates_pest_ast/src/lib.rs b/zokrates_pest_ast/src/lib.rs index 65268b304..2fca23ac2 100644 --- a/zokrates_pest_ast/src/lib.rs +++ b/zokrates_pest_ast/src/lib.rs @@ -1,3 +1,6 @@ +// disable a clippy lint as pest_ast generates improper code +#![allow(clippy::clone_on_copy)] + use from_pest::FromPest; use pest::error::Error as PestError; use pest::iterators::Pairs; @@ -69,8 +72,8 @@ mod ast { rhs: Box>, ) -> Box> { // a + b spans from the start of a to the end of b - let (start, _) = lhs.span().clone().split(); - let (_, end) = rhs.span().clone().split(); + let (start, _) = lhs.span().split(); + let (_, end) = rhs.span().split(); let span = start.span(&end); Box::new(match pair.as_rule() { @@ -1173,6 +1176,7 @@ impl fmt::Display for Error { } } +#[allow(clippy::result_large_err)] pub fn generate_ast(input: &str) -> Result { let parse_tree = parse(input).map_err(Error)?; Ok(Prog::from(parse_tree).0) diff --git a/zokrates_profiler/Cargo.toml b/zokrates_profiler/Cargo.toml new file mode 100644 index 000000000..00c0295f3 --- /dev/null +++ b/zokrates_profiler/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "zokrates_profiler" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +zokrates_ast = { version = "0.1", path = "../zokrates_ast", default-features = false } \ No newline at end of file diff --git a/zokrates_profiler/src/lib.rs b/zokrates_profiler/src/lib.rs new file mode 100644 index 000000000..126178572 --- /dev/null +++ b/zokrates_profiler/src/lib.rs @@ -0,0 +1,52 @@ +use std::collections::HashMap; + +use zokrates_ast::{ + common::{ModuleMap, Span}, + ir::{ProgIterator, Statement}, +}; + +#[derive(Default, Debug)] +pub struct HeatMap { + /// the total number of constraints + count: usize, + /// for each span, how many constraints are linked to it + map: HashMap, usize>, +} + +impl HeatMap { + pub fn display(&self, module_map: &ModuleMap) -> String { + let count = self.count; + + let mut stats: Vec<_> = self.map.iter().collect(); + + stats.sort_by(|a, b| b.1.partial_cmp(a.1).unwrap()); + + stats + .iter() + .map(|(span, c)| { + format!( + "{:>4.2}% : {}", + (**c as f64) / (count as f64) * 100.0, + span.map(|s| s.resolve(module_map).to_string()) + .unwrap_or_else(|| String::from("???")), + ) + }) + .collect::>() + .join("\n") + } +} + +pub fn profile<'ast, T, I: IntoIterator>>( + prog: ProgIterator<'ast, T, I>, +) -> HeatMap { + prog.statements + .into_iter() + .fold(HeatMap::default(), |mut heat_map, s| match s { + Statement::Constraint(s) => { + heat_map.count += 1; + *heat_map.map.entry(s.span).or_default() += 1; + heat_map + } + _ => heat_map, + }) +} diff --git a/zokrates_proof_systems/Cargo.toml b/zokrates_proof_systems/Cargo.toml index 5fc9ee2c3..aef2f9e6e 100644 --- a/zokrates_proof_systems/Cargo.toml +++ b/zokrates_proof_systems/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zokrates_proof_systems" -version = "0.1.0" +version = "0.1.3" edition = "2021" [dependencies] @@ -12,5 +12,6 @@ regex = "0.2" cfg-if = "0.1" ethabi = "17.0.0" primitive-types = { version = "0.11", features = ["rlp"] } -rand_0_4 = { version = "0.4", package = "rand" } -getrandom = { version = "0.2", features = ["js"] } \ No newline at end of file +rand_0_8 = { version = "0.8", package = "rand" } +blake2 = "0.8.1" +byteorder = "1" \ No newline at end of file diff --git a/zokrates_proof_systems/src/lib.rs b/zokrates_proof_systems/src/lib.rs index 7076cde06..da48851c8 100644 --- a/zokrates_proof_systems/src/lib.rs +++ b/zokrates_proof_systems/src/lib.rs @@ -1,3 +1,4 @@ +pub mod rng; pub mod to_token; mod scheme; @@ -10,9 +11,8 @@ pub use tagged::{TaggedKeypair, TaggedProof, TaggedVerificationKey}; use zokrates_ast::ir; +use rand_0_8::{CryptoRng, RngCore}; use serde::{Deserialize, Serialize}; - -use rand_0_4::Rng; use std::io::{Read, Write}; use zokrates_field::Field; @@ -45,7 +45,7 @@ pub type Fr = String; pub type Fq = String; pub type Fq2 = (String, String); -#[derive(Serialize, Deserialize, Clone, Debug)] +#[derive(Serialize, Deserialize, Clone, Debug, Default)] pub struct G1Affine(pub Fq, pub Fq); #[derive(Serialize, Deserialize, Clone)] @@ -96,22 +96,29 @@ impl ToString for G2AffineFq2 { } pub trait Backend> { - fn generate_proof<'a, I: IntoIterator>>( + fn generate_proof< + 'a, + I: IntoIterator>, + R: Read, + G: RngCore + CryptoRng, + >( program: ir::ProgIterator<'a, T, I>, witness: ir::Witness, - proving_key: Vec, + proving_key: R, + rng: &mut G, ) -> Proof; fn verify(vk: S::VerificationKey, proof: Proof) -> bool; } pub trait NonUniversalBackend>: Backend { - fn setup<'a, I: IntoIterator>>( + fn setup<'a, I: IntoIterator>, R: RngCore + CryptoRng>( program: ir::ProgIterator<'a, T, I>, + rng: &mut R, ) -> SetupKeypair; } pub trait UniversalBackend>: Backend { - fn universal_setup(size: u32) -> Vec; + fn universal_setup(size: u32, rng: &mut R) -> Vec; fn setup<'a, I: IntoIterator>>( srs: Vec, @@ -126,17 +133,17 @@ pub trait MpcBackend> { output: &mut W, ) -> Result<(), String>; - fn contribute( - params: &mut R, + fn contribute( + params: R, rng: &mut G, output: &mut W, ) -> Result<[u8; 64], String>; - fn verify<'a, P: Read, R: Read, I: IntoIterator>>( - params: &mut P, + fn verify<'a, R: Read, I: IntoIterator>>( + params: R, program: ir::ProgIterator<'a, T, I>, phase1_radix: &mut R, ) -> Result, String>; - fn export_keypair(params: &mut R) -> Result, String>; + fn export_keypair(params: R) -> Result, String>; } diff --git a/zokrates_proof_systems/src/rng.rs b/zokrates_proof_systems/src/rng.rs new file mode 100644 index 000000000..814217f27 --- /dev/null +++ b/zokrates_proof_systems/src/rng.rs @@ -0,0 +1,20 @@ +use blake2::{Blake2b, Digest}; +use byteorder::ReadBytesExt; +use rand_0_8::{rngs::StdRng, SeedableRng}; + +pub fn get_rng_from_entropy(entropy: &str) -> StdRng { + let h = { + let mut h = Blake2b::default(); + h.input(entropy.as_bytes()); + h.result() + }; + + let mut digest = &h[..]; + let mut seed = [0u8; 32]; + + for e in &mut seed { + *e = digest.read_u8().unwrap(); + } + + StdRng::from_seed(seed) +} diff --git a/zokrates_proof_systems/src/to_token.rs b/zokrates_proof_systems/src/to_token.rs index fbefdc400..a2be8a963 100644 --- a/zokrates_proof_systems/src/to_token.rs +++ b/zokrates_proof_systems/src/to_token.rs @@ -8,8 +8,8 @@ use super::{ /// Helper methods for parsing group structure pub fn encode_g1_element(g: &G1Affine) -> (U256, U256) { ( - U256::from(&hex::decode(&g.0.trim_start_matches("0x")).unwrap()[..]), - U256::from(&hex::decode(&g.1.trim_start_matches("0x")).unwrap()[..]), + U256::from(&hex::decode(g.0.trim_start_matches("0x")).unwrap()[..]), + U256::from(&hex::decode(g.1.trim_start_matches("0x")).unwrap()[..]), ) } @@ -17,12 +17,12 @@ pub fn encode_g2_element(g: &G2Affine) -> ((U256, U256), (U256, U256)) { match g { G2Affine::Fq2(g) => ( ( - U256::from(&hex::decode(&g.0 .0.trim_start_matches("0x")).unwrap()[..]), - U256::from(&hex::decode(&g.0 .1.trim_start_matches("0x")).unwrap()[..]), + U256::from(&hex::decode(g.0 .0.trim_start_matches("0x")).unwrap()[..]), + U256::from(&hex::decode(g.0 .1.trim_start_matches("0x")).unwrap()[..]), ), ( - U256::from(&hex::decode(&g.1 .0.trim_start_matches("0x")).unwrap()[..]), - U256::from(&hex::decode(&g.1 .1.trim_start_matches("0x")).unwrap()[..]), + U256::from(&hex::decode(g.1 .0.trim_start_matches("0x")).unwrap()[..]), + U256::from(&hex::decode(g.1 .1.trim_start_matches("0x")).unwrap()[..]), ), ), _ => unreachable!(), @@ -30,7 +30,7 @@ pub fn encode_g2_element(g: &G2Affine) -> ((U256, U256), (U256, U256)) { } pub fn encode_fr_element(f: &Fr) -> U256 { - U256::from(&hex::decode(&f.trim_start_matches("0x")).unwrap()[..]) + U256::from(&hex::decode(f.trim_start_matches("0x")).unwrap()[..]) } pub trait ToToken: SolidityCompatibleScheme { diff --git a/zokrates_solidity_test/Cargo.toml b/zokrates_solidity_test/Cargo.toml deleted file mode 100644 index 02fb69efa..000000000 --- a/zokrates_solidity_test/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "zokrates_solidity_test" -version = "0.1.1" -authors = ["Nirvan Tyagi "] -edition = "2018" - -# Modeled after the testing pipeline of the Fe project: https://github.com/ethereum/fe/ - -[dependencies] -ethabi = "17.0.0" -primitive-types = { version = "0.11", features = ["rlp"] } -hex = { version = "0.4" } -bytes = { version = "1.1", default-features = false } -serde_json = { version = "1.0" } -rand = { version = "0.8" } - -revm = { version = "1.6.0" } -solc = { git = "https://github.com/g-r-a-n-t/solc-rust", rev = "52d4146" } diff --git a/zokrates_solidity_test/contracts/simple_storage.sol b/zokrates_solidity_test/contracts/simple_storage.sol deleted file mode 100644 index 7b2424aaf..000000000 --- a/zokrates_solidity_test/contracts/simple_storage.sol +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -contract SimpleStorage { - Var myVariable; - - struct Var { - uint v; - } - - function set(Var memory x) public { - myVariable = x; - } - - function get() public view returns (uint) { - return myVariable.v; - } -} \ No newline at end of file diff --git a/zokrates_solidity_test/src/address.rs b/zokrates_solidity_test/src/address.rs deleted file mode 100644 index c3a06d7e6..000000000 --- a/zokrates_solidity_test/src/address.rs +++ /dev/null @@ -1,28 +0,0 @@ -use ethabi::token::Token; -use primitive_types::H160; -use rand::Rng; - -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct Address(pub H160); - -impl Address { - pub fn random(rng: &mut R) -> Self { - Self(H160(rng.gen())) - } - - pub fn as_token(&self) -> Token { - Token::Address(self.0) - } -} - -impl AsRef for Address { - fn as_ref(&self) -> &H160 { - &self.0 - } -} - -impl From for Address { - fn from(hash: H160) -> Self { - Self(hash) - } -} diff --git a/zokrates_solidity_test/src/contract.rs b/zokrates_solidity_test/src/contract.rs deleted file mode 100644 index 93334c4a1..000000000 --- a/zokrates_solidity_test/src/contract.rs +++ /dev/null @@ -1,156 +0,0 @@ -use ethabi::{Contract as ContractAbi, Token}; -use serde_json::{from_str, json}; -use solc::compile; - -use std::{fs::File, io::Read, path::Path}; - -use crate::{Error, EvmTestError}; - -#[derive(Clone)] -pub struct Contract { - pub binary: Vec, - pub abi: ContractAbi, -} - -impl Contract { - pub fn new(binary: Vec, abi: ContractAbi) -> Self { - Self { binary, abi } - } - - pub fn compile_from_solidity_file>( - path: P, - contract_name: &str, - opt: bool, - ) -> Result { - // Load source file - let mut src_file = File::open(path) - .map_err(|_| Box::new(EvmTestError("src file open failed".to_string())))?; - let mut src = String::new(); - src_file - .read_to_string(&mut src) - .map_err(|_| Box::new(EvmTestError("src file read failed".to_string())))?; - - Self::compile_from_src_string(&src, contract_name, opt, &[]) - } - - pub fn compile_from_src_string( - src: &str, - contract_name: &str, - opt: bool, - libraries: &[(&str, Token)], - ) -> Result { - // Compile source file using solc - // Configuration: https://docs.soliditylang.org/en/v0.8.10/using-the-compiler.html - // TODO: Change output selection to only compile 'input' file - let solc_config = format!( - r#" - {{ - "language": "Solidity", - "sources": {{ "input.sol": {{ "content": {} }} }}, - "settings": {{ - "optimizer": {{ "enabled": {} }}, - "libraries": {{ - "input.sol" : {{ {} }} - }}, - "outputSelection": {{ - "*": {{ - "*": [ - "evm.bytecode.object", "abi" - ], - "": [ "*" ] }} - }} - }} - }}"#, - json!(src), - opt, - libraries - .iter() - .map(|(name, address)| format!("\"{}\": \"0x{}\"", name, address)) - .collect::>() - .join(",\n") - ); - - Self::compile_from_config(&solc_config, contract_name) - } - - pub fn compile_from_config(config: &str, contract_name: &str) -> Result { - // Compile source file using solc - // Configuration: https://docs.soliditylang.org/en/v0.8.10/using-the-compiler.html - let out = from_str::(&compile(config)) - .map_err(|_| Box::new(EvmTestError("solc compile failed".to_string())))?; - - if out["errors"].is_array() - && out["errors"] - .as_array() - .unwrap() - .iter() - .any(|e| e["severity"] == "error") - { - return Err(Box::new(EvmTestError(format!( - "solc compiled with errors: {}", - out["errors"] - )))); - } - - let binary = { - let hex_code = out["contracts"]["input.sol"][contract_name]["evm"]["bytecode"] - ["object"] - .to_string() - .replace('\"', ""); - - hex::decode(&hex_code) - .map_err(|_| Box::new(EvmTestError("decode hex binary failed".to_string())))? - }; - let abi = { - if out["contracts"]["input.sol"][contract_name]["abi"] == "null" { - return Err(Box::new(EvmTestError( - "solc compiled with null abi".to_string(), - ))); - } - ContractAbi::load( - out["contracts"]["input.sol"][contract_name]["abi"] - .to_string() - .as_bytes(), - ) - .map_err(|_| Box::new(EvmTestError("ethabi failed loading abi".to_string())))? - }; - - Ok(Contract { binary, abi }) - } - - pub fn encode_create_contract_bytes(&self, init: &[Token]) -> Result, Error> { - match &self.abi.constructor { - Some(constructor) => { - let binary = constructor - .encode_input(self.binary.clone(), init) - .map_err(|_| { - Box::new(EvmTestError( - "abi constructor failed to encode inputs".to_string(), - )) - })?; - Ok(binary.to_vec()) - } - None => Ok(self.binary.clone()), - } - } - - pub fn encode_call_contract_bytes( - &self, - fn_name: &str, - input: &[Token], - ) -> Result, Error> { - match self.abi.functions.get(fn_name) { - Some(f) => { - let call_binary = f[0].encode_input(input).map_err(|_| { - Box::new(EvmTestError( - "abi function failed to encode inputs".to_string(), - )) - })?; - Ok(call_binary.to_vec()) - } - None => Err(Box::new(EvmTestError( - "abi does not include function".to_string(), - ))), - } - } -} diff --git a/zokrates_solidity_test/src/evm.rs b/zokrates_solidity_test/src/evm.rs deleted file mode 100644 index d1e209831..000000000 --- a/zokrates_solidity_test/src/evm.rs +++ /dev/null @@ -1,100 +0,0 @@ -use primitive_types::U256; -pub use revm::Return; -use revm::{AccountInfo, Database, InMemoryDB, Log, TransactOut, TransactTo, EVM}; - -use crate::{address::Address, Error, EvmTestError}; - -#[derive(Debug)] -pub struct CallResult { - pub op_out: Return, - pub out: Vec, - pub gas: u64, - pub log_out: Vec, -} - -#[derive(Debug)] -pub struct CreateContractResult { - pub addr: Address, - pub gas: u64, -} - -pub struct Evm { - vm: EVM, -} - -impl Default for Evm { - fn default() -> Self { - let mut vm = revm::new(); - vm.database(InMemoryDB::default()); - Self { vm } - } -} - -impl Evm { - pub fn call( - &mut self, - input: Vec, - addr: &Address, - caller: &Address, - ) -> Result { - self.vm.env.tx.caller = *caller.as_ref(); - self.vm.env.tx.transact_to = TransactTo::Call(*addr.as_ref()); - self.vm.env.tx.data = input.into(); - let (op_out, tx_out, gas, log_out) = self.vm.transact_commit(); - let out = match tx_out { - TransactOut::Call(out) => Ok(out.to_vec()), - _ => Err(Box::new(EvmTestError( - "call contract function failed".to_string(), - ))), - }?; - Ok(CallResult { - op_out, - out, - gas, - log_out, - }) - } - - pub fn deploy( - &mut self, - contract: Vec, - deployer: &Address, - ) -> Result { - self.vm.env.tx.caller = *deployer.as_ref(); - self.vm.env.tx.transact_to = TransactTo::create(); - self.vm.env.tx.data = contract.into(); - let (_, tx_out, gas, _) = self.vm.transact_commit(); - let contract_address = match tx_out { - TransactOut::Create(_, Some(addr)) => Ok(Address(addr)), - _ => Err(Box::new(EvmTestError("create contract failed".to_string()))), - }?; - Ok(CreateContractResult { - addr: contract_address, - gas, - }) - } - - pub fn create_account(&mut self, address: &Address, balance: impl Into) { - let acc = AccountInfo::from_balance(balance.into()); - self.vm.db().unwrap().insert_cache(*address.as_ref(), acc); - } - - pub fn set_account_balance( - &mut self, - address: &Address, - balance: impl Into, - ) -> Result<(), Error> { - let mut acc = self.vm.db().unwrap().basic(*address.as_ref()); - acc.balance = balance.into(); - self.vm.db().unwrap().insert_cache(*address.as_ref(), acc); - Ok(()) - } - - pub fn balance_of(&mut self, address: &Address) -> U256 { - self.vm.db().unwrap().basic(*address.as_ref()).balance - } - - pub fn get_account(&mut self, address: &Address) -> AccountInfo { - self.vm.db().unwrap().basic(*address.as_ref()) - } -} diff --git a/zokrates_solidity_test/src/lib.rs b/zokrates_solidity_test/src/lib.rs deleted file mode 100644 index d437b4cde..000000000 --- a/zokrates_solidity_test/src/lib.rs +++ /dev/null @@ -1,104 +0,0 @@ -use primitive_types::U256; - -use std::{ - error::Error as ErrorTrait, - fmt::{self, Debug}, -}; - -pub mod address; -pub mod contract; -pub mod evm; - -pub type Error = Box; - -#[derive(Debug)] -pub struct EvmTestError(String); - -impl ErrorTrait for EvmTestError { - fn source(&self) -> Option<&(dyn ErrorTrait + 'static)> { - None - } -} - -impl fmt::Display for EvmTestError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0) - } -} - -pub fn to_be_bytes(n: &U256) -> [u8; 32] { - let mut input_bytes: [u8; 32] = [0; 32]; - n.to_big_endian(&mut input_bytes); - input_bytes -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{address::Address, contract::Contract, evm::Evm}; - use ethabi::Token; - use rand::{rngs::StdRng, SeedableRng}; - - #[test] - fn simple_storage_contract_test() { - let mut rng = StdRng::seed_from_u64(0u64); - - // Compile contract - let contract_path = format!( - "{}/contracts/simple_storage.sol", - env!("CARGO_MANIFEST_DIR") - ); - let contract = - Contract::compile_from_solidity_file(contract_path, "SimpleStorage", false).unwrap(); - - // Setup EVM - let mut evm = Evm::default(); - let deployer = Address::random(&mut rng); - evm.create_account(&deployer, 0); - - // Deploy contract - let create_result = evm - .deploy( - contract.encode_create_contract_bytes(&[]).unwrap(), - &deployer, - ) - .unwrap(); - let contract_addr = create_result.addr.clone(); - println!("Contract deploy gas cost: {}", create_result.gas); - - // Call get function on contract - let get_result = evm - .call( - contract.encode_call_contract_bytes("get", &[]).unwrap(), - &contract_addr, - &deployer, - ) - .unwrap(); - assert_eq!(&get_result.out, &to_be_bytes(&U256::from(0))); - - // Call set function on contract - let _ = evm - .call( - contract - .encode_call_contract_bytes( - "set", - &[Token::Tuple(vec![Token::Uint(U256::from(40))])], - ) - .unwrap(), - &contract_addr, - &deployer, - ) - .unwrap(); - - // Call get function on contract - let get_result = evm - .call( - contract.encode_call_contract_bytes("get", &[]).unwrap(), - &contract_addr, - &deployer, - ) - .unwrap(); - assert_eq!(&get_result.out, &to_be_bytes(&U256::from(40))); - println!("{:?}", get_result); - } -} diff --git a/zokrates_stdlib/stdlib/ecc/babyjubjub.zok b/zokrates_stdlib/stdlib/ecc/babyjubjub.zok new file mode 100644 index 000000000..2df5ec0f8 --- /dev/null +++ b/zokrates_stdlib/stdlib/ecc/babyjubjub.zok @@ -0,0 +1,46 @@ +#pragma curve bn128 + +import "./proofOfOwnership" as edwardsProofOfOwnership; +import "./verifyEddsa" as edwardsSignature; +import "utils/pack/bool/nonStrictUnpack256" as unpack256; + + +// The `a` coefficient of the twisted Edwards curve +const field EDWARDS_A = 168700; + +// The `d` coefficient of the twisted Edwards curve +const field EDWARDS_D = 168696; + +// The generator point +const field[2] G = [ + 16540640123574156134436876038791482806971768689494387082833631921987005038935, // Gx + 20819045374670962167435360035096875258406992893633759881276124905556507972311 // Gy +]; + +const u32 bit_size = 254; + + +def proofOfOwnership(field[2] pk, field sk) -> bool { + + return edwardsProofOfOwnership(pk, sk, G, EDWARDS_A, EDWARDS_D, bit_size); +} + + +def verifyEddsa(field[2] R, field S, field[2] A, u32[8] M0, u32[8] M1) -> bool { + + return edwardsSignature(R, S, A, M0, M1, G, EDWARDS_A, EDWARDS_D, bit_size); +} + + +def compress(field[2] pt) -> bool[256] { + field x = pt[0]; + field y = pt[1]; + + bool[256] xBits = unpack256(x, 254); + bool[256] mut yBits = unpack256(y, 254); + + bool sign = xBits[255]; + yBits[0] = sign; + + return yBits; +} \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/ecc/babyjubjub/compress.zok b/zokrates_stdlib/stdlib/ecc/babyjubjub/compress.zok deleted file mode 100644 index 4351b36ac..000000000 --- a/zokrates_stdlib/stdlib/ecc/babyjubjub/compress.zok +++ /dev/null @@ -1,20 +0,0 @@ -import "utils/pack/bool/nonStrictUnpack256" as unpack256; - -// Compress curve point to a 256-bit boolean array using the big-endian bit order -// Python code reference: -// def compress(self): -// x = self.x.n -// y = self.y.n -// return int.to_bytes(y | ((x & 1) << 255), 32, "big") -def main(field[2] pt) -> bool[256] { - field x = pt[0]; - field y = pt[1]; - - bool[256] xBits = unpack256(x); - bool[256] mut yBits = unpack256(y); - - bool sign = xBits[255]; - yBits[0] = sign; - - return yBits; -} \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/ecc/babyjubjub/params.zok b/zokrates_stdlib/stdlib/ecc/babyjubjub/params.zok deleted file mode 100644 index 6dd695dd1..000000000 --- a/zokrates_stdlib/stdlib/ecc/babyjubjub/params.zok +++ /dev/null @@ -1,13 +0,0 @@ -#pragma curve bn128 - -// The `a` coefficient of the twisted Edwards curve -const field EDWARDS_A = 168700; - -// The `d` coefficient of the twisted Edwards curve -const field EDWARDS_D = 168696; - -// The generator point -const field[2] G = [ - 16540640123574156134436876038791482806971768689494387082833631921987005038935, // Gx - 20819045374670962167435360035096875258406992893633759881276124905556507972311 // Gy -]; \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/ecc/jubjub/params.zok b/zokrates_stdlib/stdlib/ecc/jubjub.zok similarity index 53% rename from zokrates_stdlib/stdlib/ecc/jubjub/params.zok rename to zokrates_stdlib/stdlib/ecc/jubjub.zok index c4273750f..89eb6e9a0 100644 --- a/zokrates_stdlib/stdlib/ecc/jubjub/params.zok +++ b/zokrates_stdlib/stdlib/ecc/jubjub.zok @@ -1,5 +1,9 @@ #pragma curve bls12_381 +import "./proofOfOwnership" as edwardsProofOfOwnership; +import "./verifyEddsa" as edwardsSignature; + + // The `a` coefficient of the twisted Edwards curve const field EDWARDS_A = -1; @@ -10,4 +14,18 @@ const field EDWARDS_D = 19257038036680949359750312669786877991949435402254120286 const field[2] G = [ 11076627216317271660298050606127911965867021807910416450833192264015104452986, // Gx 44412834903739585386157632289020980010620626017712148233229312325549216099227 // Gy -]; \ No newline at end of file +]; + +const u32 bit_size = 255; + + +def proofOfOwnership(field[2] pk, field sk) -> bool { + + return edwardsProofOfOwnership(pk, sk, G, EDWARDS_A, EDWARDS_D, bit_size); +} + + +def verifyEddsa(field[2] R, field S, field[2] A, u32[8] M0, u32[8] M1) -> bool { + + return edwardsSignature(R, S, A, M0, M1, G, EDWARDS_A, EDWARDS_D, bit_size); +} \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/ecc/babyjubjub/proofOfOwnership.zok b/zokrates_stdlib/stdlib/ecc/proofOfOwnership.zok similarity index 80% rename from zokrates_stdlib/stdlib/ecc/babyjubjub/proofOfOwnership.zok rename to zokrates_stdlib/stdlib/ecc/proofOfOwnership.zok index 53f09125c..7642737e2 100644 --- a/zokrates_stdlib/stdlib/ecc/babyjubjub/proofOfOwnership.zok +++ b/zokrates_stdlib/stdlib/ecc/proofOfOwnership.zok @@ -1,5 +1,4 @@ import "utils/pack/bool/nonStrictUnpack256" as unpack256; -from "./params" import EDWARDS_A, EDWARDS_D, G; from "ecc/edwards" import scalarMul; /// Verifies match of a given public/private keypair. @@ -14,8 +13,8 @@ from "ecc/edwards" import scalarMul; /// sk: Private key /// /// Returns true for pk/sk being a valid keypair, false otherwise. -def main(field[2] pk, field sk) -> bool { - bool[256] sk_bits = unpack256(sk); +def main(field[2] pk, field sk, field[2] G, field EDWARDS_A, field EDWARDS_D, u32 bit_size) -> bool { + bool[256] sk_bits = unpack256(sk, bit_size); field[2] res = scalarMul(sk_bits, G, EDWARDS_A, EDWARDS_D); return (res[0] == pk[0] && res[1] == pk[1]); } \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/ecc/babyjubjub/verifyEddsa.zok b/zokrates_stdlib/stdlib/ecc/verifyEddsa.zok similarity index 85% rename from zokrates_stdlib/stdlib/ecc/babyjubjub/verifyEddsa.zok rename to zokrates_stdlib/stdlib/ecc/verifyEddsa.zok index bb8e5c785..51103e745 100644 --- a/zokrates_stdlib/stdlib/ecc/babyjubjub/verifyEddsa.zok +++ b/zokrates_stdlib/stdlib/ecc/verifyEddsa.zok @@ -3,7 +3,6 @@ import "utils/pack/bool/nonStrictUnpack256" as unpack256bool; import "utils/pack/u32/nonStrictUnpack256" as unpack256u; from "utils/casts" import cast; from "ecc/edwards" import add, scalarMul, onCurve, orderCheck; -from "./params" import EDWARDS_A, EDWARDS_D, G; /// Verifies an EdDSA Signature. /// @@ -25,18 +24,18 @@ from "./params" import EDWARDS_A, EDWARDS_D, G; /// /// Returns: /// Return true for S being a valid EdDSA Signature, false otherwise. -def main(field[2] R, field S, field[2] A, u32[8] M0, u32[8] M1) -> bool { +def main(field[2] R, field S, field[2] A, u32[8] M0, u32[8] M1, field[2] G, field EDWARDS_A, field EDWARDS_D, u32 bit_size) -> bool { // Check if R is on curve and if it is not in a small subgroup. A is public input and can be checked offline assert(onCurve(R, EDWARDS_A, EDWARDS_D)); // throws if R is not on curve assert(orderCheck(R, EDWARDS_A, EDWARDS_D)); - u32[8] Rx = unpack256u(R[0]); - u32[8] Ax = unpack256u(A[0]); + u32[8] Rx = unpack256u(R[0], bit_size); + u32[8] Ax = unpack256u(A[0], bit_size); u32[8] h = sha256(Rx, Ax, M0, M1); bool[256] hRAM = cast(h); - bool[256] sBits = unpack256bool(S); + bool[256] sBits = unpack256bool(S, bit_size); field[2] lhs = scalarMul(sBits, G, EDWARDS_A, EDWARDS_D); field[2] AhRAM = scalarMul(hRAM, A, EDWARDS_A, EDWARDS_D); diff --git a/zokrates_stdlib/stdlib/hashes/mimc7/mimc7.zok b/zokrates_stdlib/stdlib/hashes/mimc7/mimc7.zok index dd7cbded7..f9ea58904 100644 --- a/zokrates_stdlib/stdlib/hashes/mimc7/mimc7.zok +++ b/zokrates_stdlib/stdlib/hashes/mimc7/mimc7.zok @@ -89,7 +89,7 @@ const field[91] C = [ 4212716923652881254737947578600828255798948993302968210248673545442808456151, 7594017890037021425366623750593200398174488805473151513558919864633711506220, 18979889247746272055963929241596362599320706910852082477600815822482192194401, - 1360213922981323134938688511315690179366171918090039581890971975815045550053 + 13602139229813231349386885113156901793661719180900395818909719758150455500533 ]; def main(field x_in, field k) -> field { @@ -109,4 +109,4 @@ def main(field x_in, field k) -> field { } return t6[R - 1] * t + k; -} \ No newline at end of file +} diff --git a/zokrates_stdlib/stdlib/hashes/pedersen/512bitBool.zok b/zokrates_stdlib/stdlib/hashes/pedersen/512bitBool.zok index aa9a62afb..0e1786a0b 100644 --- a/zokrates_stdlib/stdlib/hashes/pedersen/512bitBool.zok +++ b/zokrates_stdlib/stdlib/hashes/pedersen/512bitBool.zok @@ -1,8 +1,7 @@ import "utils/multiplexer/lookup3bitSigned" as sel3s; import "utils/multiplexer/lookup2bit" as sel2; -import "ecc/babyjubjub/compress"; from "ecc/edwards" import add; -from "ecc/babyjubjub/params" import EDWARDS_A, EDWARDS_D; +from "ecc/babyjubjub" import EDWARDS_A, EDWARDS_D, compress; // Code to export generators used in this example: // import bitstring diff --git a/zokrates_stdlib/stdlib/utils/pack/bool/nonStrictUnpack256.zok b/zokrates_stdlib/stdlib/utils/pack/bool/nonStrictUnpack256.zok index c0f0b81c7..6ba5a8662 100644 --- a/zokrates_stdlib/stdlib/utils/pack/bool/nonStrictUnpack256.zok +++ b/zokrates_stdlib/stdlib/utils/pack/bool/nonStrictUnpack256.zok @@ -1,11 +1,11 @@ -#pragma curve bn128 - import "./unpack_unchecked"; // Unpack a field element as 256 big-endian bits // Note: uniqueness of the output is not guaranteed // For example, `0` can map to `[0, 0, ..., 0]` or to `bits(p)` -def main(field i) -> bool[256] { - bool[254] b = unpack_unchecked(i); - return [false, false, ...b]; +def main(field i, u32 bit_size) -> bool[256] { + assert(bit_size == 254 || bit_size == 255); + u32 padding_size = 256 - bit_size; + bool[bit_size] b = unpack_unchecked(i); + return [...[false; padding_size], ...b]; } \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/utils/pack/bool/pack256.zok b/zokrates_stdlib/stdlib/utils/pack/bool/pack256.zok index c84ff0c29..c85e4f3e5 100644 --- a/zokrates_stdlib/stdlib/utils/pack/bool/pack256.zok +++ b/zokrates_stdlib/stdlib/utils/pack/bool/pack256.zok @@ -1,4 +1,3 @@ -#pragma curve bn128 import "./pack" as pack; diff --git a/zokrates_stdlib/stdlib/utils/pack/u32/nonStrictUnpack256.zok b/zokrates_stdlib/stdlib/utils/pack/u32/nonStrictUnpack256.zok index 37311a5cf..3a3a70039 100644 --- a/zokrates_stdlib/stdlib/utils/pack/u32/nonStrictUnpack256.zok +++ b/zokrates_stdlib/stdlib/utils/pack/u32/nonStrictUnpack256.zok @@ -1,11 +1,9 @@ -#pragma curve bn128 - import "../bool/nonStrictUnpack256" as unpack; import "../../casts/bool_256_to_u32_8" as from_bits; // Unpack a field element as a u32[8] (big-endian) // Note: uniqueness of the output is not guaranteed // For example, `0` can map to `[0, 0, ..., 0]` or to `bits(p)` -def main(field i) -> u32[8] { - return from_bits(unpack(i)); +def main(field i, u32 bit_size) -> u32[8] { + return from_bits(unpack(i, bit_size)); } \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/ecc/babyjubjub/compress.zok b/zokrates_stdlib/tests/tests/ecc/babyjubjub/compress.zok index b74505d43..2f174fe4c 100644 --- a/zokrates_stdlib/tests/tests/ecc/babyjubjub/compress.zok +++ b/zokrates_stdlib/tests/tests/ecc/babyjubjub/compress.zok @@ -1,5 +1,4 @@ -import "ecc/babyjubjub/compress"; -from "ecc/babyjubjub/params" import G; +from "ecc/babyjubjub" import G, compress; // Code to create test cases: // https://github.com/Zokrates/pycrypto diff --git a/zokrates_stdlib/tests/tests/ecc/babyjubjub/edwardsAdd.zok b/zokrates_stdlib/tests/tests/ecc/babyjubjub/edwardsAdd.zok index d38391e2b..802c63873 100644 --- a/zokrates_stdlib/tests/tests/ecc/babyjubjub/edwardsAdd.zok +++ b/zokrates_stdlib/tests/tests/ecc/babyjubjub/edwardsAdd.zok @@ -1,5 +1,5 @@ from "ecc/edwards" import add, negate; -from "ecc/babyjubjub/params" import G, EDWARDS_A, EDWARDS_D; +from "ecc/babyjubjub" import G, EDWARDS_A, EDWARDS_D; // Code to create test cases: // https://github.com/Zokrates/pycrypto diff --git a/zokrates_stdlib/tests/tests/ecc/babyjubjub/edwardsOnCurve.zok b/zokrates_stdlib/tests/tests/ecc/babyjubjub/edwardsOnCurve.zok index 45b14bf8a..6be0b79d7 100644 --- a/zokrates_stdlib/tests/tests/ecc/babyjubjub/edwardsOnCurve.zok +++ b/zokrates_stdlib/tests/tests/ecc/babyjubjub/edwardsOnCurve.zok @@ -1,5 +1,5 @@ from "ecc/edwards" import onCurve; -from "ecc/babyjubjub/params" import EDWARDS_A, EDWARDS_D; +from "ecc/babyjubjub" import EDWARDS_A, EDWARDS_D; // Code to create test cases: // https://github.com/Zokrates/pycrypto diff --git a/zokrates_stdlib/tests/tests/ecc/babyjubjub/edwardsOrderCheck.zok b/zokrates_stdlib/tests/tests/ecc/babyjubjub/edwardsOrderCheck.zok index 6d44f2db2..bf16f0bf8 100644 --- a/zokrates_stdlib/tests/tests/ecc/babyjubjub/edwardsOrderCheck.zok +++ b/zokrates_stdlib/tests/tests/ecc/babyjubjub/edwardsOrderCheck.zok @@ -1,5 +1,5 @@ from "ecc/edwards" import orderCheck; -from "ecc/babyjubjub/params" import EDWARDS_A, EDWARDS_D; +from "ecc/babyjubjub" import EDWARDS_A, EDWARDS_D; // Code to create test cases: // https://github.com/Zokrates/pycrypto diff --git a/zokrates_stdlib/tests/tests/ecc/babyjubjub/edwardsScalarMult.zok b/zokrates_stdlib/tests/tests/ecc/babyjubjub/edwardsScalarMult.zok index bcf1efdbb..960acddfe 100644 --- a/zokrates_stdlib/tests/tests/ecc/babyjubjub/edwardsScalarMult.zok +++ b/zokrates_stdlib/tests/tests/ecc/babyjubjub/edwardsScalarMult.zok @@ -1,5 +1,5 @@ from "ecc/edwards" import scalarMul as mul; -from "ecc/babyjubjub/params" import G, EDWARDS_A, EDWARDS_D; +from "ecc/babyjubjub" import G, EDWARDS_A, EDWARDS_D; // Code to create test cases: // https://github.com/Zokrates/pycrypto diff --git a/zokrates_stdlib/tests/tests/ecc/babyjubjub/proofOfOwnership.zok b/zokrates_stdlib/tests/tests/ecc/babyjubjub/proofOfOwnership.zok index 98c387bff..bacbdae21 100644 --- a/zokrates_stdlib/tests/tests/ecc/babyjubjub/proofOfOwnership.zok +++ b/zokrates_stdlib/tests/tests/ecc/babyjubjub/proofOfOwnership.zok @@ -1,5 +1,5 @@ -import "ecc/babyjubjub/proofOfOwnership" as proofOfOwnership; -from "ecc/edwards" import scalarMul; +from "ecc/babyjubjub" import proofOfOwnership; + // Code to create test cases: // https://github.com/Zokrates/pycrypto diff --git a/zokrates_stdlib/tests/tests/ecc/babyjubjub/verifyEddsa.zok b/zokrates_stdlib/tests/tests/ecc/babyjubjub/verifyEddsa.zok index e813aa133..ff86dc696 100644 --- a/zokrates_stdlib/tests/tests/ecc/babyjubjub/verifyEddsa.zok +++ b/zokrates_stdlib/tests/tests/ecc/babyjubjub/verifyEddsa.zok @@ -1,4 +1,4 @@ -import "ecc/babyjubjub/verifyEddsa" as verifyEddsa; +from "ecc/babyjubjub" import verifyEddsa; // Code to create test case: // https://github.com/Zokrates/pycrypto diff --git a/zokrates_stdlib/tests/tests/ecc/jubjub/edwardsAdd.zok b/zokrates_stdlib/tests/tests/ecc/jubjub/edwardsAdd.zok index 2d72da6dd..4306cfb55 100644 --- a/zokrates_stdlib/tests/tests/ecc/jubjub/edwardsAdd.zok +++ b/zokrates_stdlib/tests/tests/ecc/jubjub/edwardsAdd.zok @@ -1,5 +1,5 @@ from "ecc/edwards" import add, negate; -from "ecc/jubjub/params" import G, EDWARDS_A, EDWARDS_D; +from "ecc/jubjub" import G, EDWARDS_A, EDWARDS_D; def testDoubleViaAdd() -> bool { field[2] out = add(G, G, EDWARDS_A, EDWARDS_D); diff --git a/zokrates_stdlib/tests/tests/ecc/jubjub/edwardsOnCurve.zok b/zokrates_stdlib/tests/tests/ecc/jubjub/edwardsOnCurve.zok index 68e0b0be6..dda5bd262 100644 --- a/zokrates_stdlib/tests/tests/ecc/jubjub/edwardsOnCurve.zok +++ b/zokrates_stdlib/tests/tests/ecc/jubjub/edwardsOnCurve.zok @@ -1,5 +1,5 @@ from "ecc/edwards" import onCurve; -from "ecc/jubjub/params" import EDWARDS_A, EDWARDS_D; +from "ecc/jubjub" import EDWARDS_A, EDWARDS_D; def main() { field u = 11076627216317271660298050606127911965867021807910416450833192264015104452986; diff --git a/zokrates_stdlib/tests/tests/ecc/jubjub/edwardsOrderCheck.zok b/zokrates_stdlib/tests/tests/ecc/jubjub/edwardsOrderCheck.zok index 93332d861..e6c10e323 100644 --- a/zokrates_stdlib/tests/tests/ecc/jubjub/edwardsOrderCheck.zok +++ b/zokrates_stdlib/tests/tests/ecc/jubjub/edwardsOrderCheck.zok @@ -1,5 +1,5 @@ from "ecc/edwards" import orderCheck; -from "ecc/jubjub/params" import EDWARDS_A, EDWARDS_D; +from "ecc/jubjub" import EDWARDS_A, EDWARDS_D; def testOrderCheckTrue() -> bool { field u = 11076627216317271660298050606127911965867021807910416450833192264015104452986; diff --git a/zokrates_stdlib/tests/tests/ecc/jubjub/edwardsScalarMult.zok b/zokrates_stdlib/tests/tests/ecc/jubjub/edwardsScalarMult.zok index 348b0b977..64590c424 100644 --- a/zokrates_stdlib/tests/tests/ecc/jubjub/edwardsScalarMult.zok +++ b/zokrates_stdlib/tests/tests/ecc/jubjub/edwardsScalarMult.zok @@ -1,5 +1,5 @@ from "ecc/edwards" import scalarMul as mul; -from "ecc/jubjub/params" import G, EDWARDS_A, EDWARDS_D; +from "ecc/jubjub" import G, EDWARDS_A, EDWARDS_D; /* def testCyclic() -> bool { diff --git a/zokrates_stdlib/tests/tests/ecc/jubjub/proofOfOwnership.json b/zokrates_stdlib/tests/tests/ecc/jubjub/proofOfOwnership.json new file mode 100644 index 000000000..f702e1da9 --- /dev/null +++ b/zokrates_stdlib/tests/tests/ecc/jubjub/proofOfOwnership.json @@ -0,0 +1,16 @@ +{ + "entry_point": "./tests/tests/ecc/jubjub/proofOfOwnership.zok", + "curves": ["Bls12_381"], + "tests": [ + { + "input": { + "values": [] + }, + "output": { + "Ok": { + "value": [] + } + } + } + ] +} diff --git a/zokrates_stdlib/tests/tests/ecc/jubjub/proofOfOwnership.zok b/zokrates_stdlib/tests/tests/ecc/jubjub/proofOfOwnership.zok new file mode 100644 index 000000000..ea6b20e6a --- /dev/null +++ b/zokrates_stdlib/tests/tests/ecc/jubjub/proofOfOwnership.zok @@ -0,0 +1,29 @@ +from "ecc/jubjub" import proofOfOwnership; + + +// Code to create test cases: +// https://github.com/Zokrates/pycrypto +def testOwnershipTrue() -> bool { + field[2] pk = [14197449566532409051373899088449039913101429151158365207762164998470111126084, 39815292783067036895376009933490224522172606808755118734518018525613835149403]; + field sk = 24537266074035586913841246471742714563414767347802800698790739697702568093815; + + bool out = proofOfOwnership(pk, sk); + + assert(out); + return true; +} + +def testOwnershipFalse() -> bool { + field[2] pk = [14197449566532409051373899088449039913101429151158365207762164998470111126084, 39815292783067036895376009933490224522172606808755118734518018525613835149403]; + field sk = 47423927973606838312622698773159954626747140530476271492884670927146733875544; + + bool out = proofOfOwnership(pk, sk); + + assert(!out); + return true; +} + +def main() { + assert(testOwnershipTrue()); + assert(testOwnershipFalse()); +} \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/ecc/jubjub/verifyEddsa.json b/zokrates_stdlib/tests/tests/ecc/jubjub/verifyEddsa.json new file mode 100644 index 000000000..98b1e734d --- /dev/null +++ b/zokrates_stdlib/tests/tests/ecc/jubjub/verifyEddsa.json @@ -0,0 +1,16 @@ +{ + "entry_point": "./tests/tests/ecc/jubjub/verifyEddsa.zok", + "curves": ["Bls12_381"], + "tests": [ + { + "input": { + "values": [] + }, + "output": { + "Ok": { + "value": [] + } + } + } + ] +} diff --git a/zokrates_stdlib/tests/tests/ecc/jubjub/verifyEddsa.zok b/zokrates_stdlib/tests/tests/ecc/jubjub/verifyEddsa.zok new file mode 100644 index 000000000..ce07cdc51 --- /dev/null +++ b/zokrates_stdlib/tests/tests/ecc/jubjub/verifyEddsa.zok @@ -0,0 +1,21 @@ +from "ecc/jubjub" import verifyEddsa; + + +// Code to create test case: +// https://github.com/Zokrates/pycrypto +def main() { + + // TODO: Jubjub currently work only for keys <=254 bit long + // With the following keys should also work: + field[2] R = [32866767109220564315580607107081162920517672350707254238793964527466586251974, 31852087390335520207922973662676180854641055992940928475111512263314053365736]; + field S = 43627586196239283173178511316555190744314536456808505435494185841008559853678; + + // Public Key + field[2] A = [26479653887939839327536384197110148123933856719900448942651733342668343953867, 21757919891968253927635241665494706427345455214116275076018069565740804326091]; + + u32[8] M0 = [0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000]; + u32[8] M1 = [0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000005]; + + bool isVerified = verifyEddsa(R, S, A, M0, M1); + assert(isVerified); +} \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/utils/pack/bool/nonStrictUnpack256.json b/zokrates_stdlib/tests/tests/utils/pack/bool/nonStrictUnpack256.json index dc6f88bd7..e7c734581 100644 --- a/zokrates_stdlib/tests/tests/utils/pack/bool/nonStrictUnpack256.json +++ b/zokrates_stdlib/tests/tests/utils/pack/bool/nonStrictUnpack256.json @@ -1,6 +1,6 @@ { "entry_point": "./tests/tests/utils/pack/bool/nonStrictUnpack256.zok", - "curves": ["Bn128"], + "curves": ["Bls12_381"], "tests": [ { "input": { diff --git a/zokrates_stdlib/tests/tests/utils/pack/bool/nonStrictUnpack256.zok b/zokrates_stdlib/tests/tests/utils/pack/bool/nonStrictUnpack256.zok index 9cd9694ad..8e8746b26 100644 --- a/zokrates_stdlib/tests/tests/utils/pack/bool/nonStrictUnpack256.zok +++ b/zokrates_stdlib/tests/tests/utils/pack/bool/nonStrictUnpack256.zok @@ -1,26 +1,44 @@ import "utils/pack/bool/nonStrictUnpack256" as unpack256; def testFive() -> bool { - bool[256] b = unpack256(5); + bool[256] b = unpack256(5, 254); assert(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] b = unpack256(5, 255); + assert(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]); + return true; } def testZero() -> bool { - bool[256] b = unpack256(0); + bool[256] b = unpack256(0, 254); + assert(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] b = unpack256(0, 255); assert(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]); + return true; } def testLarge() -> bool { - bool[256] b = unpack256(14474011154664524427946373126085988481658748083205070504932198000989141204991); + bool[256] b = unpack256(14474011154664524427946373126085988481658748083205070504932198000989141204991, 254); assert(b == [false, false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true]); + + bool[256] b = unpack256(28948022309329048855892746252171976963317496166410141009864396001978282409983, 255); + assert(b == [false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true]); + return true; } def testMax() -> bool { - bool[256] b = unpack256(21888242871839275222246405745257275088548364400416034343698204186575808495616); + // bn128 + bool[256] b = unpack256(21888242871839275222246405745257275088548364400416034343698204186575808495616, 254); assert(b == [false, false, true, true, false, false, false, false, false, true, true, false, false, true, false, false, false, true, false, false, true, true, true, false, false, true, true, true, false, false, true, false, true, true, true, false, false, false, false, true, false, false, true, true, false, false, false, true, true, false, true, false, false, false, false, false, false, false, true, false, true, false, false, true, true, false, true, true, true, false, false, false, false, true, false, true, false, false, false, false, false, true, false, false, false, true, false, true, true, false, true, true, false, true, true, false, true, false, false, false, false, false, false, true, true, false, false, false, false, false, false, true, false, true, false, true, true, false, false, false, false, true, false, true, true, true, false, true, false, false, true, false, true, false, false, false, false, false, true, true, false, false, true, true, true, true, true, false, true, false, false, false, false, true, false, false, true, false, false, false, false, true, true, true, true, false, false, true, true, false, true, true, true, false, false, true, false, true, true, true, false, false, false, false, true, false, false, true, false, false, false, true, false, true, false, false, false, false, true, true, true, true, true, false, false, false, false, true, true, true, true, true, false, true, false, true, true, false, false, true, false, false, true, true, true, true, true, 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]); + + // bls12_381 + bool[256] b = unpack256(52435875175126190479447740508185965837690552500527637822603658699938581184512, 255); + assert(b == [false, true, true, true, false, false, true, true, true, true, true, false, true, true, false, true, true, false, true, false, false, true, true, true, false, true, false, true, false, false, true, true, false, false, true, false, true, false, false, true, true, false, false, true, true, true, false, true, false, true, true, true, true, true, false, true, false, true, false, false, true, false, false, false, false, false, true, true, false, false, true, true, false, false, true, true, true, false, false, true, true, true, false, true, true, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, true, false, false, true, true, false, true, false, false, false, false, true, true, true, false, true, true, false, false, false, false, false, false, false, false, true, false, true, false, true, false, true, false, false, true, true, true, false, true, true, true, true, false, true, true, false, true, false, false, true, false, false, false, false, false, false, false, false, true, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, false, true, false, true, true, false, true, true, true, true, true, true, true, true, true, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, 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]); + return true; } diff --git a/zokrates_stdlib/tests/tests/utils/pack/u32/nonStrictUnpack256.json b/zokrates_stdlib/tests/tests/utils/pack/u32/nonStrictUnpack256.json index 00815fc75..5a8dc41e3 100644 --- a/zokrates_stdlib/tests/tests/utils/pack/u32/nonStrictUnpack256.json +++ b/zokrates_stdlib/tests/tests/utils/pack/u32/nonStrictUnpack256.json @@ -1,6 +1,6 @@ { "entry_point": "./tests/tests/utils/pack/u32/nonStrictUnpack256.zok", - "curves": ["Bn128"], + "curves": ["Bls12_381"], "tests": [ { "input": { diff --git a/zokrates_stdlib/tests/tests/utils/pack/u32/nonStrictUnpack256.zok b/zokrates_stdlib/tests/tests/utils/pack/u32/nonStrictUnpack256.zok index 4a865fb6e..67be9afda 100644 --- a/zokrates_stdlib/tests/tests/utils/pack/u32/nonStrictUnpack256.zok +++ b/zokrates_stdlib/tests/tests/utils/pack/u32/nonStrictUnpack256.zok @@ -1,26 +1,41 @@ import "utils/pack/u32/nonStrictUnpack256" as unpack256; def testFive() -> bool { - u32[8] b = unpack256(5); + u32[8] b = unpack256(5, 254); assert(b == [0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000005]); + + u32[8] b = unpack256(5, 255); + assert(b == [0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000005]); + return true; } def testZero() -> bool { - u32[8] b = unpack256(0); + u32[8] b = unpack256(0, 254); + assert(b == [0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000]); + + u32[8] b = unpack256(0, 255); assert(b == [0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000]); return true; } def testLarge() -> bool { - u32[8] b = unpack256(14474011154664524427946373126085988481658748083205070504932198000989141204991); + u32[8] b = unpack256(14474011154664524427946373126085988481658748083205070504932198000989141204991, 254); assert(b == [0x1fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff]); + + u32[8] b = unpack256(28948022309329048855892746252171976963317496166410141009864396001978282409983, 255); + assert(b == [0x3fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff]); return true; } def testMax() -> bool { - u32[8] b = unpack256(21888242871839275222246405745257275088548364400416034343698204186575808495616); + // bn128 + u32[8] b = unpack256(21888242871839275222246405745257275088548364400416034343698204186575808495616, 254); assert(b == [0x30644e72, 0xe131a029, 0xb85045b6, 0x8181585d, 0x2833e848, 0x79b97091, 0x43e1f593, 0xf0000000]); + + // bls12_381 + u32[8] b = unpack256(52435875175126190479447740508185965837690552500527637822603658699938581184512, 255); + assert(b == [0x73eda753, 0x299d7d48, 0x3339d808, 0x09a1d805, 0x53bda402, 0xfffe5bfe, 0xffffffff, 0x00000000]); return true; } diff --git a/zokrates_test/Cargo.toml b/zokrates_test/Cargo.toml index d1fef01bf..9ea298b67 100644 --- a/zokrates_test/Cargo.toml +++ b/zokrates_test/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zokrates_test" -version = "0.2.0" +version = "0.2.3" authors = ["schaeff "] edition = "2018" @@ -18,9 +18,10 @@ serde_json = { version = "1.0", features = ["preserve_order"] } typed-arena = "1.4.1" [dev-dependencies] -wasm-bindgen-test = "^0.3.0" +wasm-bindgen-test = "=0.3.31" zokrates_ark = { version = "0.1", path = "../zokrates_ark" } zokrates_proof_systems = { version = "0.1", path = "../zokrates_proof_systems" } - +rand_0_8 = { version = "0.8", package = "rand" } +getrandom = { version = "0.2.8", features = ["js"] } [lib] diff --git a/zokrates_test/src/lib.rs b/zokrates_test/src/lib.rs index 0aa85f907..c0cb4b589 100644 --- a/zokrates_test/src/lib.rs +++ b/zokrates_test/src/lib.rs @@ -178,7 +178,8 @@ fn compile_and_run(t: Tests) { .unwrap() }; - let output = interpreter.execute(bin.clone(), &input); + let output = + interpreter.execute(&input, bin.statements.iter(), &bin.arguments, &bin.solvers); use zokrates_abi::Decode; diff --git a/zokrates_test/tests/out_of_range.rs b/zokrates_test/tests/out_of_range.rs index ea2800252..dd8757cb3 100644 --- a/zokrates_test/tests/out_of_range.rs +++ b/zokrates_test/tests/out_of_range.rs @@ -38,11 +38,14 @@ fn lt_field() { .unwrap(); let interpreter = Interpreter::try_out_of_range(); + let prog = res.prog(); assert!(interpreter .execute( - res.prog(), - &[Bn128Field::from(10000), Bn128Field::from(5555)] + &[Bn128Field::from(10000), Bn128Field::from(5555)], + prog.statements.into_iter(), + &prog.arguments, + &prog.solvers ) .is_err()); } @@ -74,11 +77,14 @@ fn lt_uint() { .unwrap(); let interpreter = Interpreter::try_out_of_range(); + let prog = res.prog(); assert!(interpreter .execute( - res.prog(), - &[Bn128Field::from(10000), Bn128Field::from(5555)] + &[Bn128Field::from(10000), Bn128Field::from(5555)], + prog.statements.into_iter(), + &prog.arguments, + &prog.solvers ) .is_err()); } @@ -121,9 +127,15 @@ fn unpack256() { .unwrap(); let interpreter = Interpreter::try_out_of_range(); + let prog = res.prog(); assert!(interpreter - .execute(res.prog(), &[Bn128Field::from(0)]) + .execute( + &[Bn128Field::from(0)], + prog.statements.into_iter(), + &prog.arguments, + &prog.solvers + ) .is_err()); } @@ -133,7 +145,7 @@ fn unpack256_unchecked() { import "utils/pack/bool/nonStrictUnpack256"; def main(private field a) { - bool[256] bits = nonStrictUnpack256(a); + bool[256] bits = nonStrictUnpack256(a, 254); assert(bits[255]); return; } @@ -165,8 +177,14 @@ fn unpack256_unchecked() { .unwrap(); let interpreter = Interpreter::try_out_of_range(); + let prog = res.prog(); assert!(interpreter - .execute(res.prog(), &[Bn128Field::from(0)]) + .execute( + &[Bn128Field::from(0)], + prog.statements.into_iter(), + &prog.arguments, + &prog.solvers + ) .is_ok()); } diff --git a/zokrates_test/tests/wasm.rs b/zokrates_test/tests/wasm.rs index 32efefd3c..b723a3966 100644 --- a/zokrates_test/tests/wasm.rs +++ b/zokrates_test/tests/wasm.rs @@ -10,22 +10,40 @@ use zokrates_field::Bn128Field; use zokrates_interpreter::Interpreter; use zokrates_proof_systems::{Backend, NonUniversalBackend}; +use rand_0_8::{rngs::StdRng, SeedableRng}; use zokrates_ark::Ark; use zokrates_proof_systems::groth16::G16; #[wasm_bindgen_test] fn generate_proof() { let program: Prog = Prog { + module_map: Default::default(), arguments: vec![Parameter::public(Variable::new(0))], return_count: 1, - statements: vec![Statement::constraint(Variable::new(0), Variable::new(0))], + statements: vec![Statement::constraint( + Variable::new(0), + Variable::new(0), + None, + )], + solvers: vec![], }; let interpreter = Interpreter::default(); let witness = interpreter - .execute(program.clone(), &[Bn128Field::from(42)]) + .execute( + &[Bn128Field::from(42)], + program.statements.iter(), + &program.arguments, + &program.solvers, + ) .unwrap(); - let keypair = >::setup(program.clone()); - let _proof = >::generate_proof(program, witness, keypair.pk); + let rng = &mut StdRng::from_entropy(); + let keypair = >::setup(program.clone(), rng); + let _proof = >::generate_proof( + program, + witness, + keypair.pk.as_slice(), + rng, + ); } diff --git a/zokrates_test_derive/Cargo.toml b/zokrates_test_derive/Cargo.toml index 753297675..5d67294b4 100644 --- a/zokrates_test_derive/Cargo.toml +++ b/zokrates_test_derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zokrates_test_derive" -version = "0.0.1" +version = "0.0.2" authors = ["schaeff "] edition = "2018" diff --git a/zokrates_test_derive/src/lib.rs b/zokrates_test_derive/src/lib.rs index 5f7f10f9a..110a02753 100644 --- a/zokrates_test_derive/src/lib.rs +++ b/zokrates_test_derive/src/lib.rs @@ -9,7 +9,7 @@ pub fn write_tests(base: &str) { let base = Path::new(&base); let out_dir = env::var("OUT_DIR").unwrap(); let destination = Path::new(&out_dir).join("tests.rs"); - let test_file = File::create(&destination).unwrap(); + let test_file = File::create(destination).unwrap(); let mut writer = BufWriter::new(test_file); for p in glob(base.join("**/*.json").to_str().unwrap()).unwrap() {