diff --git a/.circleci/config.yml b/.circleci/config.yml index a0570b76b..97a1d2feb 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -4,6 +4,7 @@ jobs: build: docker: - image: zokrates/env:latest + resource_class: large steps: - checkout - run: @@ -28,6 +29,7 @@ jobs: test: docker: - image: zokrates/env:latest + resource_class: large steps: - checkout - run: @@ -42,6 +44,9 @@ jobs: - run: name: Check format command: cargo fmt --all -- --check + - run: + name: Run clippy + command: cargo clippy -- -D warnings - run: name: Build command: WITH_LIBSNARK=1 RUSTFLAGS="-D warnings" ./build.sh @@ -80,6 +85,7 @@ jobs: docker: - image: zokrates/env:latest - image: trufflesuite/ganache-cli:next + resource_class: large steps: - checkout - run: @@ -134,7 +140,7 @@ workflows: filters: branches: only: - - master + - deploy requires: - build - test diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..af03a5b6e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,37 @@ +--- +name: Bug Report +about: Bug reports about the ZoKrates toolbox. +--- + + + +## Description + + + +## Environment + +- Compiler version: +- Operating system: + +## Steps to Reproduce + + \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..a7380a7a6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,43 @@ +--- +name: Feature Request +about: ZoKrates toolbox feature requests. +--- + + + +## Abstract + + + +## Motivation + + + +## Specification + + + +## Backwards Compatibility + + \ No newline at end of file diff --git a/.github/workflows/pr-changelog-check.yml b/.github/workflows/pr-changelog-check.yml new file mode 100644 index 000000000..261471cc2 --- /dev/null +++ b/.github/workflows/pr-changelog-check.yml @@ -0,0 +1,14 @@ +name: Pull request changelog check +on: + pull_request: + types: [opened, labeled, unlabeled, synchronize] +jobs: + build: + if: ${{ !(contains(github.event.pull_request.labels.*.name, 'changelog-not-required')) }} + name: Run changelog check + runs-on: ubuntu-latest + steps: + - name: Check out the code + uses: actions/checkout@v2 + - name: Changelog check + run: ./scripts/changelog-check.sh \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 54333de9f..0d3be6e81 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,7 @@ sudo: required env: global: - CRATE_NAME=zokrates + matrix: include: @@ -67,7 +68,7 @@ branches: only: # release tags - /^\d+\.\d+\.\d+.*$/ - - master + - deploy notifications: email: diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..c82363d9d --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,34 @@ +# Changelog +All notable changes to this project will be documented in this file. + +## [Unreleased] +https://github.com/Zokrates/ZoKrates/compare/latest...develop + +## [0.7.0] - 2021-04-09 + +### Release +- https://github.com/Zokrates/ZoKrates/releases/tag/0.7.0 + +### Changes +- Re-export embed functions as stdlib modules, add field to uint casts to stdlib (#801, @dark64) +- Change left `<<` and right `>>` shifts to take `u32` as a second parameter (#783, @schaeff) +- Introduce u64 type, add keccak{256,384,512} and sha3{256,384,512} hash functions to stdlib (#772, @dark64) +- Add negative `-` and positive `+` unary operators, restricting accepted expressions in some places (exponent) to allow for better parsing (#762, @schaeff) +- Make embed functions generic, enabling unpacking to any width at minimal cost (#754, @schaeff) +- Add global `--verbose` flag to CLI for verbose logging, add `--ztf` flag to `compile` command, deprecate `--light` flag as its behaviour is now a default. (#751, @dark64) +- Introduce constant generics for `u32` values. Introduce literal inference (#695, @schaeff) + +## [0.6.4] - 2021-03-19 +### Release +- https://github.com/Zokrates/ZoKrates/releases/tag/0.6.4 + +### Changes +- re-include embeds for a slightly cheaper sha256 +- remove array ssa +- add flag to allow unconstrained variables +- better flattening of conjunctions +- put backends behind features +- accept any assignee in multidef +- minor performance and stability improvements + +For older releases and changes, visit https://github.com/Zokrates/ZoKrates/releases. \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 784a83ae1..44f43a5ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,18 +4,29 @@ version = 3 [[package]] name = "addr2line" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c0929d69e78dd9bf5408269919fcbcaeb2e35e5d43e5815517cdc6a8e11a423" +checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7" dependencies = [ "gimli", ] [[package]] name = "adler" -version = "0.2.3" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" +checksum = "7f200cbb1e856866d9eade941cf3aa0c5d7dd36f74311c4273b494f4ef036957" +dependencies = [ + "getrandom 0.2.2", + "once_cell", + "version_check", +] [[package]] name = "aho-corasick" @@ -37,8 +48,9 @@ dependencies = [ [[package]] name = "ark-bls12-377" -version = "0.1.0" -source = "git+https://github.com/arkworks-rs/curves#7f1fcd66967328a1c5a3d12f8b148d69f7d86888" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb89b97424403ec9cc22a1df0db748dd7396c9ba5fb5c71a6f0e10ae1d1a7449" dependencies = [ "ark-ec", "ark-ff", @@ -47,8 +59,9 @@ dependencies = [ [[package]] name = "ark-bn254" -version = "0.1.0" -source = "git+https://github.com/arkworks-rs/curves#7f1fcd66967328a1c5a3d12f8b148d69f7d86888" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ead066869de5e8cb2938123204d1572f09496b629e146a6f80fa8ec508446ba" dependencies = [ "ark-ec", "ark-ff", @@ -57,8 +70,9 @@ dependencies = [ [[package]] name = "ark-bw6-761" -version = "0.1.0" -source = "git+https://github.com/arkworks-rs/curves#7f1fcd66967328a1c5a3d12f8b148d69f7d86888" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69ad8d74a8e083a59defc4a226a19759691337006d5c9397dbd793af9e406418" dependencies = [ "ark-bls12-377", "ark-ec", @@ -68,39 +82,39 @@ dependencies = [ [[package]] name = "ark-crypto-primitives" -version = "0.1.0" -source = "git+https://github.com/arkworks-rs/crypto-primitives.git?branch=main#ce5cc89011b394eb006987a24088947d5099d641" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74b83a7e125e5c611e4a997123effb2f02e3fbc66531dd77751d3016ee920741" dependencies = [ "ark-ec", "ark-ff", "ark-relations", "ark-snark", "ark-std", - "bench-utils", "blake2", "derivative", - "digest", - "rand 0.7.3", + "digest 0.9.0", ] [[package]] name = "ark-ec" -version = "0.1.0" -source = "git+https://github.com/arkworks-rs/algebra#eac2dd72fd048ea7eac00dabe2ba8bda84287a64" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56006994f509d76fbce6f6ffe3108f7191b4f3754ecd00bbae7cac20ec05020" dependencies = [ "ark-ff", "ark-serialize", "ark-std", "derivative", "num-traits 0.2.14", - "rand 0.7.3", "zeroize", ] [[package]] name = "ark-ff" -version = "0.1.0" -source = "git+https://github.com/arkworks-rs/algebra#eac2dd72fd048ea7eac00dabe2ba8bda84287a64" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4d8802d40fce9212c5c09be08f75c4b3becc0c488e87f60fff787b01250ce33" dependencies = [ "ark-ff-asm", "ark-ff-macros", @@ -108,35 +122,37 @@ dependencies = [ "ark-std", "derivative", "num-traits 0.2.14", - "rand 0.7.3", "rustc_version", "zeroize", ] [[package]] name = "ark-ff-asm" -version = "0.1.0" -source = "git+https://github.com/arkworks-rs/algebra#eac2dd72fd048ea7eac00dabe2ba8bda84287a64" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e8cb28c2137af1ef058aa59616db3f7df67dbb70bf2be4ee6920008cc30d98c" dependencies = [ - "quote 1.0.7", - "syn 1.0.54", + "quote 1.0.9", + "syn 1.0.67", ] [[package]] name = "ark-ff-macros" -version = "0.1.0" -source = "git+https://github.com/arkworks-rs/algebra#eac2dd72fd048ea7eac00dabe2ba8bda84287a64" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9c256a93a10ed9708c16a517d6dcfaba3d215c0d7fab44d29a9affefb5eeb8" dependencies = [ - "num-bigint 0.3.1", + "num-bigint 0.4.0", "num-traits 0.2.14", - "quote 1.0.7", - "syn 1.0.54", + "quote 1.0.9", + "syn 1.0.67", ] [[package]] name = "ark-gm17" -version = "0.1.0" -source = "git+https://github.com/arkworks-rs/gm17#f74debdb0557af2a873c8261970617e6aad7211d" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c9085a6c89aa65178aa2718b2efb62fd7c4dc23fe25285204e30b56e4cbfcac" dependencies = [ "ark-crypto-primitives", "ark-ec", @@ -145,26 +161,26 @@ dependencies = [ "ark-relations", "ark-serialize", "ark-std", - "bench-utils", - "rand 0.7.3", ] [[package]] name = "ark-poly" -version = "0.1.0" -source = "git+https://github.com/arkworks-rs/algebra#eac2dd72fd048ea7eac00dabe2ba8bda84287a64" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6683d21645a2abb94034f6a14e708405e55d9597687952d54b2269922857a" dependencies = [ "ark-ff", "ark-serialize", "ark-std", "derivative", - "rand 0.7.3", + "hashbrown", ] [[package]] name = "ark-relations" -version = "0.1.0" -source = "git+https://github.com/arkworks-rs/snark#0648c547e4f9fda46a40ad0a4896652b87c2316b" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a42f124f8dfff2b0561143c0c7ea48d7f7dc8d2c4c1e87eca14a27430c653c0b" dependencies = [ "ark-ff", "ark-std", @@ -173,8 +189,9 @@ dependencies = [ [[package]] name = "ark-serialize" -version = "0.1.0" -source = "git+https://github.com/arkworks-rs/algebra#eac2dd72fd048ea7eac00dabe2ba8bda84287a64" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e9b59329dc9b92086b3dc619f31cef4a0c802f10829b575a3666d48a48387d" dependencies = [ "ark-serialize-derive", "ark-std", @@ -182,29 +199,35 @@ dependencies = [ [[package]] name = "ark-serialize-derive" -version = "0.1.1-alpha.0" -source = "git+https://github.com/arkworks-rs/algebra#eac2dd72fd048ea7eac00dabe2ba8bda84287a64" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ac3d78c750b01f5df5b2e76d106ed31487a93b3868f14a7f0eb3a74f45e1d8a" dependencies = [ "proc-macro2 1.0.24", - "quote 1.0.7", - "syn 1.0.54", + "quote 1.0.9", + "syn 1.0.67", ] [[package]] name = "ark-snark" -version = "0.1.0" -source = "git+https://github.com/arkworks-rs/snark#0648c547e4f9fda46a40ad0a4896652b87c2316b" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39da26432fe584b0010741299820145ec69180fe9ea18ddf96946932763624a1" dependencies = [ "ark-ff", "ark-relations", "ark-std", - "rand 0.7.3", ] [[package]] name = "ark-std" -version = "0.1.0" -source = "git+https://github.com/arkworks-rs/utils#f6974ac72f59339b7ab798a728a84c5a7b8bac45" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5b856a29bea7b810858116a596beee3d20fc4c5aeb240e8e5a8bca4845a470" +dependencies = [ + "rand 0.7.3", + "rand_xorshift", +] [[package]] name = "arrayref" @@ -260,9 +283,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "backtrace" -version = "0.3.55" +version = "0.3.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef5140344c85b01f9bbb4d4b7288a8aa4b3287ccef913a14bcc78a1063623598" +checksum = "9d117600f438b1707d4e4ae15d3595657288f8235a0eb593e80ecc98ab34e1bc" dependencies = [ "addr2line", "cfg-if 1.0.0", @@ -295,11 +318,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "bench-utils" -version = "0.1.0" -source = "git+https://github.com/arkworks-rs/utils#f6974ac72f59339b7ab798a728a84c5a7b8bac45" - [[package]] name = "bincode" version = "0.8.0" @@ -325,14 +343,13 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "blake2" -version = "0.8.1" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94cb07b0da6a73955f8fb85d24c466778e70cda767a568229b104f0264089330" +checksum = "10a5720225ef5daecf08657f23791354e1685a8c91a4c60c7f3d3b2892f978f4" dependencies = [ - "byte-tools", "crypto-mac", - "digest", - "opaque-debug", + "digest 0.9.0", + "opaque-debug 0.3.0", ] [[package]] @@ -366,7 +383,7 @@ dependencies = [ "block-padding", "byte-tools", "byteorder", - "generic-array", + "generic-array 0.12.4", ] [[package]] @@ -380,9 +397,9 @@ dependencies = [ [[package]] name = "bstr" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "473fc6b38233f9af7baa94fb5852dca389e3d95b8e21c8e3719301462c5d9faf" +checksum = "a40b47ad93e1a5404e6c18dec46b628214fee441c70f4ab5d6942142cc268a3d" dependencies = [ "lazy_static", "memchr", @@ -392,9 +409,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.4.0" +version = "3.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820" +checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe" [[package]] name = "byte-tools" @@ -410,27 +427,37 @@ checksum = "72feb31ffc86498dacdbd0fcebb56138e7177a8cc5cea4516031d15ae85a742e" [[package]] name = "byteorder" -version = "1.3.4" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cargo-platform" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0226944a63d1bf35a3b5f948dd7c59e263db83695c9e8bffc4037de02e30f1d7" +dependencies = [ + "serde", +] [[package]] name = "cargo_metadata" -version = "0.10.0" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8de60b887edf6d74370fc8eb177040da4847d971d6234c7b13a6da324ef0caf" +checksum = "7714a157da7991e23d90686b9524b9e12e0407a108647f52e9328f4b3d51ac7f" dependencies = [ - "semver 0.9.0", + "cargo-platform", + "semver", + "semver-parser", "serde", - "serde_derive", "serde_json", ] [[package]] name = "cc" -version = "1.0.66" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" +checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" dependencies = [ "jobserver", ] @@ -572,9 +599,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d" +checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49" dependencies = [ "autocfg", "cfg-if 1.0.0", @@ -589,19 +616,19 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-mac" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" dependencies = [ - "generic-array", + "generic-array 0.14.4", "subtle", ] [[package]] name = "csv" -version = "1.1.5" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d58633299b24b515ac72a3f869f8b91306a3cec616a602843a383acd6f9e97" +checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" dependencies = [ "bstr", "csv-core", @@ -621,23 +648,23 @@ dependencies = [ [[package]] name = "ctor" -version = "0.1.16" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fbaabec2c953050352311293be5c6aba8e141ba19d6811862b232d6fd020484" +checksum = "5e98e2ad1a782e33928b96fc3948e7c355e5af34ba4de7670fe8bac2a3b2006d" dependencies = [ - "quote 1.0.7", - "syn 1.0.54", + "quote 1.0.9", + "syn 1.0.67", ] [[package]] name = "derivative" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb582b60359da160a9477ee80f15c8d784c477e69c217ef2cdd4169c24ea380f" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ "proc-macro2 1.0.24", - "quote 1.0.7", - "syn 1.0.54", + "quote 1.0.9", + "syn 1.0.67", ] [[package]] @@ -658,7 +685,16 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" dependencies = [ - "generic-array", + "generic-array 0.12.4", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array 0.14.4", ] [[package]] @@ -728,8 +764,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" dependencies = [ "proc-macro2 1.0.24", - "quote 1.0.7", - "syn 1.0.54", + "quote 1.0.9", + "syn 1.0.67", "synstructure", ] @@ -772,15 +808,15 @@ dependencies = [ "num-integer", "num-traits 0.2.14", "proc-macro2 1.0.24", - "quote 1.0.7", - "syn 1.0.54", + "quote 1.0.9", + "syn 1.0.67", ] [[package]] name = "form_urlencoded" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ece68d15c92e84fa4f19d3780f1294e5ca82a78a6d515f1efaabcc144688be00" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" dependencies = [ "matches", "percent-encoding", @@ -810,9 +846,9 @@ checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" [[package]] name = "futures" -version = "0.3.8" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b3b0c040a1fe6529d30b3c5944b280c7f0dcb2930d2c3062bca967b602583d0" +checksum = "7f55667319111d593ba876406af7c409c0ebb44dc4be6132a783ccf163ea14c1" dependencies = [ "futures-channel", "futures-core", @@ -825,9 +861,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.8" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b7109687aa4e177ef6fe84553af6280ef2778bdb7783ba44c9dc3399110fe64" +checksum = "8c2dd2df839b57db9ab69c2c9d8f3e8c81984781937fe2807dc6dcf3b2ad2939" dependencies = [ "futures-core", "futures-sink", @@ -835,15 +871,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.8" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "847ce131b72ffb13b6109a221da9ad97a64cbe48feb1028356b836b47b8f1748" +checksum = "15496a72fabf0e62bdc3df11a59a3787429221dd0710ba8ef163d6f7a9112c94" [[package]] name = "futures-executor" -version = "0.3.8" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4caa2b2b68b880003057c1dd49f1ed937e38f22fcf6c212188a121f08cf40a65" +checksum = "891a4b7b96d84d5940084b2a37632dd65deeae662c114ceaa2c879629c9c0ad1" dependencies = [ "futures-core", "futures-task", @@ -853,30 +889,27 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.8" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "611834ce18aaa1bd13c4b374f5d653e1027cf99b6b502584ff8c9a64413b30bb" +checksum = "d71c2c65c57704c32f5241c1223167c2c3294fd34ac020c807ddbe6db287ba59" [[package]] name = "futures-sink" -version = "0.3.8" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f878195a49cee50e006b02b93cf7e0a95a38ac7b776b4c4d9cc1207cd20fcb3d" +checksum = "85754d98985841b7d4f5e8e6fbfa4a4ac847916893ec511a2917ccd8525b8bb3" [[package]] name = "futures-task" -version = "0.3.8" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c554eb5bf48b2426c4771ab68c6b14468b6e76cc90996f528c3338d761a4d0d" -dependencies = [ - "once_cell", -] +checksum = "fa189ef211c15ee602667a6fcfe1c1fd9e07d42250d2156382820fba33c9df80" [[package]] name = "futures-util" -version = "0.3.8" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d304cff4a7b99cfb7986f7d43fbe93d175e72e704a8860787cc95e9ffd85cbd2" +checksum = "1812c7ab8aedf8d6f2701a43e1243acdbcc2b36ab26e2ad421eb99ac963d96d1" dependencies = [ "futures-channel", "futures-core", @@ -884,27 +917,37 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project", + "pin-project-lite", "pin-utils", "slab", ] [[package]] name = "generic-array" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" dependencies = [ "typenum", ] +[[package]] +name = "generic-array" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", "libc", "wasi 0.9.0+wasi-snapshot-preview1", ] @@ -930,9 +973,9 @@ checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" [[package]] name = "git2" -version = "0.13.12" +version = "0.13.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6f1a0238d7f8f8fd5ee642f4ebac4dbc03e03d1f78fbe7a3ede35dcf7e2224" +checksum = "1d250f5f82326884bd39c2853577e70a121775db76818ffa452ed1e80de12986" dependencies = [ "bitflags", "libc", @@ -955,26 +998,35 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash", +] + [[package]] name = "hermit-abi" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" +checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" dependencies = [ "libc", ] [[package]] name = "hex" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "idna" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" +checksum = "89829a5d69c23d348314a7ac337fe39173b61149a9864deabd260983aed48c21" dependencies = [ "matches", "unicode-bidi", @@ -992,9 +1044,9 @@ dependencies = [ [[package]] name = "itoa" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" +checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" [[package]] name = "jobserver" @@ -1007,9 +1059,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.46" +version = "0.3.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf3d7383929f7c9c7c2d0fa596f325832df98c3704f2c60553080f7127a58175" +checksum = "2d99f9e3e84b8f67f846ef5b4cbbc3b1c29f6c759fcbce6f01aa0e73d932a24c" dependencies = [ "wasm-bindgen", ] @@ -1022,15 +1074,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.81" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" +checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714" [[package]] name = "libgit2-sys" -version = "0.12.14+1.1.0" +version = "0.12.18+1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f25af58e6495f7caf2919d08f212de550cfa3ed2f5e744988938ea292b9f549" +checksum = "3da6a42da88fc37ee1ecda212ffa254c25713532980005d5f7c0b0fbe7e6e885" dependencies = [ "cc", "libc", @@ -1042,9 +1094,9 @@ dependencies = [ [[package]] name = "libssh2-sys" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df40b13fe7ea1be9b9dffa365a51273816c345fc1811478b57ed7d964fbfc4ce" +checksum = "e0186af0d8f171ae6b9c4c90ec51898bad5d08a2d5e470903a50d9ad8959cbee" dependencies = [ "cc", "libc", @@ -1068,11 +1120,11 @@ dependencies = [ [[package]] name = "log" -version = "0.4.11" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", ] [[package]] @@ -1110,9 +1162,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" dependencies = [ "adler", "autocfg", @@ -1149,9 +1201,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e9a41747ae4633fce5adffb4d2e81ffc5e89593cb19917f8fb2cc5ff76507bf" +checksum = "4e0d047c1062aa51e256408c560894e5251f08925980e53cf1aa5bd00eec6512" dependencies = [ "autocfg", "num-integer", @@ -1209,15 +1261,15 @@ dependencies = [ [[package]] name = "object" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397" +checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4" [[package]] name = "once_cell" -version = "1.5.2" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" +checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" [[package]] name = "opaque-debug" @@ -1225,6 +1277,12 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + [[package]] name = "openssl-probe" version = "0.1.2" @@ -1233,9 +1291,9 @@ checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" [[package]] name = "openssl-sys" -version = "0.9.59" +version = "0.9.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de52d8eabd217311538a39bba130d7dea1f1e118010fee7a033d966845e7d5fe" +checksum = "313752393519e876837e09e1fa183ddef0be7735868dced3196f4472d536277f" dependencies = [ "autocfg", "cc", @@ -1311,8 +1369,8 @@ dependencies = [ "pest", "pest_meta", "proc-macro2 1.0.24", - "quote 1.0.7", - "syn 1.0.54", + "quote 1.0.9", + "syn 1.0.67", ] [[package]] @@ -1326,31 +1384,11 @@ dependencies = [ "sha-1", ] -[[package]] -name = "pin-project" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ccc2237c2c489783abd8c4c80e5450fc0e98644555b1364da68cc29aa151ca7" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8e8d2bf0b23038a4424865103a4df472855692821aab4e4f5c3312d461d9e5f" -dependencies = [ - "proc-macro2 1.0.24", - "quote 1.0.7", - "syn 1.0.54", -] - [[package]] name = "pin-project-lite" -version = "0.2.0" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b063f57ec186e6140e2b8b6921e5f1bd89c7356dda5b33acc5401203ca6131c" +checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905" [[package]] name = "pin-utils" @@ -1402,11 +1440,13 @@ dependencies = [ [[package]] name = "pulldown-cmark" -version = "0.2.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eef52fac62d0ea7b9b4dc7da092aa64ea7ec3d90af6679422d3d7e0e14b6ee15" +checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8" dependencies = [ "bitflags", + "memchr", + "unicase", ] [[package]] @@ -1420,9 +1460,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" dependencies = [ "proc-macro2 1.0.24", ] @@ -1446,11 +1486,23 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom 0.1.15", + "getrandom 0.1.16", "libc", - "rand_chacha", + "rand_chacha 0.2.2", "rand_core 0.5.1", - "rand_hc", + "rand_hc 0.2.0", +] + +[[package]] +name = "rand" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +dependencies = [ + "libc", + "rand_chacha 0.3.0", + "rand_core 0.6.2", + "rand_hc 0.3.0", ] [[package]] @@ -1463,6 +1515,16 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "rand_chacha" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.2", +] + [[package]] name = "rand_core" version = "0.3.1" @@ -1484,7 +1546,16 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom 0.1.15", + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" +dependencies = [ + "getrandom 0.2.2", ] [[package]] @@ -1496,6 +1567,24 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "rand_hc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" +dependencies = [ + "rand_core 0.6.2", +] + +[[package]] +name = "rand_xorshift" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8" +dependencies = [ + "rand_core 0.5.1", +] + [[package]] name = "rdrand" version = "0.4.0" @@ -1511,22 +1600,31 @@ version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" +[[package]] +name = "redox_syscall" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" +dependencies = [ + "bitflags", +] + [[package]] name = "redox_users" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" dependencies = [ - "getrandom 0.1.15", - "redox_syscall", + "getrandom 0.1.16", + "redox_syscall 0.1.57", "rust-argon2", ] [[package]] name = "reduce" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c8549eb79c1fc8c449cb18a2d9b7873a7cb1bf2fcbfe8a3ad8812320544341" +checksum = "16d2dc47b68ac15ea328cd7ebe01d7d512ed29787f7d534ad2a3c341328b35d7" [[package]] name = "regex" @@ -1577,7 +1675,7 @@ dependencies = [ "base64", "blake2b_simd", "constant_time_eq", - "crossbeam-utils 0.8.1", + "crossbeam-utils 0.8.3", ] [[package]] @@ -1588,11 +1686,11 @@ checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232" [[package]] name = "rustc_version" -version = "0.3.0" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65c94201b44764d6d1f7e37c15a8289ed55e546c1762c7f1d57f616966e0c181" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" dependencies = [ - "semver 0.11.0", + "semver", ] [[package]] @@ -1619,7 +1717,7 @@ dependencies = [ "bellman_ce", "blake2-rfc_bellman_edition", "byteorder", - "digest", + "digest 0.8.1", "rand 0.4.6", "serde", "serde_derive", @@ -1639,65 +1737,50 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser 0.7.0", - "serde", -] - [[package]] name = "semver" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" dependencies = [ - "semver-parser 0.10.1", + "semver-parser", + "serde", ] [[package]] name = "semver-parser" -version = "0.7.0" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - -[[package]] -name = "semver-parser" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ef146c2ad5e5f4b037cd6ce2ebb775401729b19a82040c1beac9d36c7d1428" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" dependencies = [ "pest", ] [[package]] name = "serde" -version = "1.0.118" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" +checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.118" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" +checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" dependencies = [ "proc-macro2 1.0.24", - "quote 1.0.7", - "syn 1.0.54", + "quote 1.0.9", + "syn 1.0.67", ] [[package]] name = "serde_json" -version = "1.0.60" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1500e84d27fe482ed1dc791a56eddc2f230046a040fa908c08bda1d9fb615779" +checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" dependencies = [ "itoa", "ryu", @@ -1711,9 +1794,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" dependencies = [ "block-buffer", - "digest", + "digest 0.8.1", "fake-simd", - "opaque-debug", + "opaque-debug 0.2.3", ] [[package]] @@ -1723,9 +1806,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" dependencies = [ "block-buffer", - "digest", + "digest 0.8.1", "fake-simd", - "opaque-debug", + "opaque-debug 0.2.3", ] [[package]] @@ -1739,9 +1822,9 @@ dependencies = [ [[package]] name = "skeptic" -version = "0.13.5" +version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6deb8efaf3ad8fd784139db8bbd51806bfbcee87c7be7578e9c930981fb808" +checksum = "188b810342d98f23f0bb875045299f34187b559370b041eb11520c905370a888" dependencies = [ "bytecount", "cargo_metadata", @@ -1766,9 +1849,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "subtle" -version = "1.0.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" +checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" [[package]] name = "syn" @@ -1783,12 +1866,12 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.54" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2af957a63d6bd42255c359c93d9bfdb97076bd3b820897ce55ffbfbf107f44" +checksum = "6498a9efc342871f91cc2d0d694c674368b4ceb40f62b65a7a08c3792935e702" dependencies = [ "proc-macro2 1.0.24", - "quote 1.0.7", + "quote 1.0.9", "unicode-xid 0.2.1", ] @@ -1799,8 +1882,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" dependencies = [ "proc-macro2 1.0.24", - "quote 1.0.7", - "syn 1.0.54", + "quote 1.0.9", + "syn 1.0.67", "unicode-xid 0.2.1", ] @@ -1816,14 +1899,14 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" +checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", "libc", - "rand 0.7.3", - "redox_syscall", + "rand 0.8.3", + "redox_syscall 0.2.5", "remove_dir_all", "winapi", ] @@ -1857,9 +1940,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf8dbc19eb42fba10e8feaaec282fb50e2c14b2726d6301dbfeed0f73306a6f" +checksum = "317cca572a0e89c3ce0ca1f1bdc9369547fe318a683418e42ac8f59d14701023" dependencies = [ "tinyvec_macros", ] @@ -1872,9 +1955,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tracing" -version = "0.1.22" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f47026cdc4080c07e49b37087de021820269d996f581aac150ef9e5583eefe3" +checksum = "01ebdc2bb4498ab1ab5f5b73c5803825e60199229ccba0698170e3be0e7f959f" dependencies = [ "cfg-if 1.0.0", "pin-project-lite", @@ -1895,9 +1978,9 @@ checksum = "a9b2228007eba4120145f785df0f6c92ea538f5a3635a612ecf4e334c8c1446d" [[package]] name = "typenum" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" +checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" [[package]] name = "ucd-trie" @@ -1911,6 +1994,15 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c85f514e095d348c279b1e5cd76795082cf15bd59b93207832abe0b1d8fed236" +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-bidi" version = "0.3.4" @@ -1922,9 +2014,9 @@ dependencies = [ [[package]] name = "unicode-normalization" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a13e63ab62dbe32aeee58d1c5408d35c36c392bba5d9d3142287219721afe606" +checksum = "07fbfce1c8a97d547e8b5334978438d9d6ec8c20e38f56d4a4374d181493eaef" dependencies = [ "tinyvec", ] @@ -1949,9 +2041,9 @@ checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" [[package]] name = "url" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5909f2b0817350449ed73e8bcd81c8c3c8d9a7a5d8acba4b27db277f1868976e" +checksum = "9ccd964113622c8e9322cfac19eb1004a07e636c545f325da085d5cdde6f1f8b" dependencies = [ "form_urlencoded", "idna", @@ -1979,9 +2071,9 @@ checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "version_check" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" [[package]] name = "void" @@ -1991,9 +2083,9 @@ checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" [[package]] name = "walkdir" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" dependencies = [ "same-file", "winapi", @@ -2014,9 +2106,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "wasm-bindgen" -version = "0.2.69" +version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cd364751395ca0f68cafb17666eee36b63077fb5ecd972bbcd74c90c4bf736e" +checksum = "83240549659d187488f91f33c0f8547cbfef0b2088bc470c116d1d260ef623d9" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -2024,24 +2116,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.69" +version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1114f89ab1f4106e5b55e688b828c0ab0ea593a1ea7c094b141b14cbaaec2d62" +checksum = "ae70622411ca953215ca6d06d3ebeb1e915f0f6613e3b495122878d7ebec7dae" dependencies = [ "bumpalo", "lazy_static", "log", "proc-macro2 1.0.24", - "quote 1.0.7", - "syn 1.0.54", + "quote 1.0.9", + "syn 1.0.67", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.19" +version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fe9756085a84584ee9457a002b7cdfe0bfff169f45d2591d8be1345a6780e35" +checksum = "81b8b767af23de6ac18bf2168b690bed2902743ddf0fb39252e36f9e2bfc63ea" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -2051,38 +2143,38 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.69" +version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6ac8995ead1f084a8dea1e65f194d0973800c7f571f6edd70adf06ecf77084" +checksum = "3e734d91443f177bfdb41969de821e15c516931c3c3db3d318fa1b68975d0f6f" dependencies = [ - "quote 1.0.7", + "quote 1.0.9", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.69" +version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a48c72f299d80557c7c62e37e7225369ecc0c963964059509fbafe917c7549" +checksum = "d53739ff08c8a68b0fdbcd54c372b8ab800b1449ab3c9d706503bc7dd1621b2c" dependencies = [ "proc-macro2 1.0.24", - "quote 1.0.7", - "syn 1.0.54", + "quote 1.0.9", + "syn 1.0.67", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.69" +version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e7811dd7f9398f14cc76efd356f98f03aa30419dea46aa810d71e819fc97158" +checksum = "d9a543ae66aa233d14bb765ed9af4a33e81b8b58d1584cf1b47ff8cd0b9e4489" [[package]] name = "wasm-bindgen-test" -version = "0.3.19" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0355fa0c1f9b792a09b6dcb6a8be24d51e71e6d74972f9eb4a44c4c004d24a25" +checksum = "e972e914de63aa53bd84865e54f5c761bd274d48e5be3a6329a662c0386aa67a" dependencies = [ "console_error_panic_hook", "js-sys", @@ -2094,19 +2186,19 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.19" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27e07b46b98024c2ba2f9e83a10c2ef0515f057f2da299c1762a2017de80438b" +checksum = "ea6153a8f9bf24588e9f25c87223414fff124049f68d3a442a0f0eab4768a8b6" dependencies = [ "proc-macro2 1.0.24", - "quote 1.0.7", + "quote 1.0.9", ] [[package]] name = "web-sys" -version = "0.3.46" +version = "0.3.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222b1ef9334f92a21d3fb53dc3fd80f30836959a90f9274a626d7e06315ba3c3" +checksum = "a905d57e488fec8861446d3393670fb50d27a262344013181c2cdf9fff5481be" dependencies = [ "js-sys", "wasm-bindgen", @@ -2159,14 +2251,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f369ddb18862aba61aa49bf31e74d29f0f162dec753063200e1dc084345d16" dependencies = [ "proc-macro2 1.0.24", - "quote 1.0.7", - "syn 1.0.54", + "quote 1.0.9", + "syn 1.0.67", "synstructure", ] [[package]] name = "zokrates_abi" -version = "0.1.3" +version = "0.1.4" dependencies = [ "serde", "serde_derive", @@ -2177,7 +2269,7 @@ dependencies = [ [[package]] name = "zokrates_cli" -version = "0.6.4" +version = "0.7.0" dependencies = [ "assert_cli", "bincode", @@ -2202,7 +2294,7 @@ version = "0.1.0" [[package]] name = "zokrates_core" -version = "0.5.4" +version = "0.6.0" dependencies = [ "ark-bls12-377", "ark-bn254", @@ -2243,7 +2335,7 @@ dependencies = [ [[package]] name = "zokrates_core_test" -version = "0.1.5" +version = "0.2.0" dependencies = [ "zokrates_test", "zokrates_test_derive", @@ -2251,7 +2343,7 @@ dependencies = [ [[package]] name = "zokrates_embed" -version = "0.1.1" +version = "0.1.2" dependencies = [ "bellman_ce", "sapling-crypto_ce", @@ -2259,7 +2351,7 @@ dependencies = [ [[package]] name = "zokrates_field" -version = "0.3.8" +version = "0.4.0" dependencies = [ "ark-bls12-377", "ark-bn254", @@ -2289,7 +2381,7 @@ dependencies = [ [[package]] name = "zokrates_parser" -version = "0.1.6" +version = "0.2.0" dependencies = [ "glob 0.2.11", "pest", @@ -2298,7 +2390,7 @@ dependencies = [ [[package]] name = "zokrates_pest_ast" -version = "0.1.5" +version = "0.2.0" dependencies = [ "from-pest", "glob 0.2.11", @@ -2310,7 +2402,7 @@ dependencies = [ [[package]] name = "zokrates_stdlib" -version = "0.1.8" +version = "0.2.0" dependencies = [ "fs_extra", "zokrates_test", diff --git a/README.md b/README.md index be04187e2..3434cf83d 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,6 @@ # ZoKrates [![Join the chat at https://gitter.im/ZoKrates/Lobby](https://badges.gitter.im/ZoKrates/Lobby.svg)](https://gitter.im/ZoKrates/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -[![CircleCI master](https://img.shields.io/circleci/project/github/Zokrates/ZoKrates/master.svg?label=master)](https://circleci.com/gh/Zokrates/ZoKrates/tree/master) [![CircleCI develop](https://img.shields.io/circleci/project/github/Zokrates/ZoKrates/develop.svg?label=develop)](https://circleci.com/gh/Zokrates/ZoKrates/tree/develop) ZoKrates is a toolbox for zkSNARKs on Ethereum. diff --git a/changelogs/README.md b/changelogs/README.md new file mode 100644 index 000000000..616fb49b2 --- /dev/null +++ b/changelogs/README.md @@ -0,0 +1,14 @@ +## Adding a changelog + +Pull request authors are expected to include a changelog file explaining the changes introduced by the pull request. +The changelog file should be a new file created in the `changelogs/unreleased` folder. +The file should follow the naming convention of `pr-username` and the contents of the file +should be your text for the changelog. + +### Example +``` +changelogs/unreleased # folder to place changelogs + 101-username # your changelog file (pull request #101 by @username) +``` + +Any user-facing change must have a changelog entry. If a pull request does not warrant a changelog, the CI check for a changelog can be skipped by applying a `changelog-not-required` label. diff --git a/changelogs/unreleased/.gitkeep b/changelogs/unreleased/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/clippy.toml b/clippy.toml new file mode 100644 index 000000000..3f707a567 --- /dev/null +++ b/clippy.toml @@ -0,0 +1 @@ +blacklisted-names = [] \ No newline at end of file diff --git a/scripts/benchmark.sh b/scripts/benchmark.sh new file mode 100755 index 000000000..dde98e91a --- /dev/null +++ b/scripts/benchmark.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +# Usage: benchmark.sh +# For MacOS: install gtime with homebrew `brew install gnu-time` + +cmd=$* +format="mem=%KK rss=%MK elapsed=%E cpu=%P cpu.sys=%S inputs=%I outputs=%O" + +if command -v gtime; then + gtime -f "$format" $cmd +else + /usr/bin/time -f "$format" $cmd +fi diff --git a/scripts/changelog-check.sh b/scripts/changelog-check.sh new file mode 100755 index 000000000..bb370d1de --- /dev/null +++ b/scripts/changelog-check.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +set +x + +if [ -z "$CI" ]; then + echo "This script is intended to be run only on Github Actions." >&2 + exit 1 +fi + +CHANGELOG_PATH='changelogs/unreleased' + +echo $GITHUB_REF +pr_number=$(echo $GITHUB_REF | cut -d / -f 3) +changelog="${CHANGELOG_PATH}/${pr_number}-*" + +if ls ${changelog} 1> /dev/null 2>&1; then + echo "Pull request #${pr_number:-?} contains a changelog." +else + echo "Pull request #${pr_number:-?} is missing a changelog. Please add a changelog to ${CHANGELOG_PATH}." + exit 1 +fi + +cl_diff=$(git diff --exit-code $GITHUB_SHA -- CHANGELOG.md) +if [ -n "$cl_diff" ]; then + echo "Pull requests should not directly modify the main CHANGELOG.md file. For more information, please read changelogs/README.md" + exit 1 +fi \ No newline at end of file diff --git a/scripts/changelog.sh b/scripts/changelog.sh new file mode 100755 index 000000000..b8d87773c --- /dev/null +++ b/scripts/changelog.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +# This script is intended for maintainers only to generate changelog markdown before new releases. +# The generated markdown can be added to the main CHANGELOG.md file located at the root of the repository. + +set -e + +if [ -z "$1" ]; then + echo "Usage: $0 TAG" >&2 + exit 1 +fi + +function join { local IFS="$1"; shift; echo "$*"; } +function qdate +{ + if type -p gdate > /dev/null; then + gdate "$@"; + else + date "$@"; + fi +} + +CHANGELOG_PATH='changelogs/unreleased' + +tag=$1 +unreleased=$(ls -t ${CHANGELOG_PATH}) + +echo -e "Generating CHANGELOG markdown from ${CHANGELOG_PATH}\n" +cat << EOT +## [${tag}] - $(qdate '+%Y-%m-%d') + +### Release +- https://github.com/Zokrates/ZoKrates/releases/tag/${tag} + +### Changes +EOT + +for file in $unreleased +do + IFS=$'-' read -ra entry <<< "$file" + contents=$(cat ${CHANGELOG_PATH}/${file} | tr '\n' ' ') + author=$(join '-' ${entry[@]:1}) + echo "- ${contents} (#${entry[0]}, @${author})" +done + +echo -e "\nCopy and paste the markdown above to the appropriate CHANGELOG file." +echo "Be sure to run: git rm ${CHANGELOG_PATH}/*" \ No newline at end of file diff --git a/zokrates_abi/Cargo.toml b/zokrates_abi/Cargo.toml index f3d9e75e0..0813a144d 100644 --- a/zokrates_abi/Cargo.toml +++ b/zokrates_abi/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "zokrates_abi" -version = "0.1.3" +version = "0.1.4" authors = ["Thibaut Schaeffer "] edition = "2018" [dependencies] -zokrates_field = { version = "0.3", path = "../zokrates_field", default-features = false } -zokrates_core = { version = "0.5", path = "../zokrates_core", default-features = false } +zokrates_field = { version = "0.4", path = "../zokrates_field", default-features = false } +zokrates_core = { version = "0.6", path = "../zokrates_core", default-features = false } serde = "1.0" serde_derive = "1.0" serde_json = "1.0" \ No newline at end of file diff --git a/zokrates_abi/src/lib.rs b/zokrates_abi/src/lib.rs index 62b26a420..e2e4a8a01 100644 --- a/zokrates_abi/src/lib.rs +++ b/zokrates_abi/src/lib.rs @@ -17,7 +17,7 @@ impl> Encode for Inputs { use std::collections::BTreeMap; use std::convert::TryFrom; use std::fmt; -use zokrates_core::typed_absy::{Type, UBitwidth}; +use zokrates_core::typed_absy::types::{ConcreteType, UBitwidth}; use zokrates_field::Field; @@ -45,6 +45,7 @@ enum Value { U8(u8), U16(u16), U32(u32), + U64(u64), Field(T), Boolean(bool), Array(Vec>), @@ -56,6 +57,7 @@ enum CheckedValue { U8(u8), U16(u16), U32(u32), + U64(u64), Field(T), Boolean(bool), Array(Vec>), @@ -72,6 +74,7 @@ impl fmt::Display for Value { Value::U8(v) => write!(f, "{:#04x}", v), Value::U16(v) => write!(f, "{:#06x}", v), Value::U32(v) => write!(f, "{:#010x}", v), + Value::U64(v) => write!(f, "{:#018x}", v), Value::Boolean(v) => write!(f, "{}", v), Value::Array(v) => write!( f, @@ -94,18 +97,21 @@ impl fmt::Display for Value { } impl Value { - fn check(self, ty: Type) -> Result, String> { + fn check(self, ty: ConcreteType) -> Result, String> { match (self, ty) { - (Value::Field(f), Type::FieldElement) => Ok(CheckedValue::Field(f)), - (Value::U8(f), Type::Uint(UBitwidth::B8)) => Ok(CheckedValue::U8(f)), - (Value::U16(f), Type::Uint(UBitwidth::B16)) => Ok(CheckedValue::U16(f)), - (Value::U32(f), Type::Uint(UBitwidth::B32)) => Ok(CheckedValue::U32(f)), - (Value::Boolean(b), Type::Boolean) => Ok(CheckedValue::Boolean(b)), - (Value::Array(a), Type::Array(array_type)) => { - if a.len() != array_type.size { + (Value::Field(f), ConcreteType::FieldElement) => Ok(CheckedValue::Field(f)), + (Value::U8(f), ConcreteType::Uint(UBitwidth::B8)) => Ok(CheckedValue::U8(f)), + (Value::U16(f), ConcreteType::Uint(UBitwidth::B16)) => Ok(CheckedValue::U16(f)), + (Value::U32(f), ConcreteType::Uint(UBitwidth::B32)) => Ok(CheckedValue::U32(f)), + (Value::U64(f), ConcreteType::Uint(UBitwidth::B64)) => Ok(CheckedValue::U64(f)), + (Value::Boolean(b), ConcreteType::Boolean) => Ok(CheckedValue::Boolean(b)), + (Value::Array(a), ConcreteType::Array(array_type)) => { + let size = array_type.size; + + if a.len() != size as usize { Err(format!( "Expected array of size {}, found array of size {}", - array_type.size, + size, a.len() )) } else { @@ -116,15 +122,16 @@ impl Value { Ok(CheckedValue::Array(a)) } } - (Value::Struct(mut s), Type::Struct(members)) => { - if s.len() != members.len() { + (Value::Struct(mut s), ConcreteType::Struct(struc)) => { + if s.len() != struc.members_count() { Err(format!( "Expected {} member(s), found {}", - members.len(), + struc.members_count(), s.len() )) } else { - let s = members + let s = struc + .members .into_iter() .map(|member| { s.remove(&member.id) @@ -159,6 +166,7 @@ impl> Encode for CheckedValue { CheckedValue::U8(t) => vec![T::from(t as usize)], CheckedValue::U16(t) => vec![T::from(t as usize)], CheckedValue::U32(t) => vec![T::from(t as usize)], + CheckedValue::U64(t) => vec![T::from(t as usize)], CheckedValue::Boolean(b) => vec![if b { 1.into() } else { 0.into() }], CheckedValue::Array(a) => a.into_iter().flat_map(|v| v.encode()).collect(), CheckedValue::Struct(s) => s.into_iter().flat_map(|(_, v)| v.encode()).collect(), @@ -167,7 +175,7 @@ impl> Encode for CheckedValue { } impl Decode for CheckedValues { - type Expected = Vec; + type Expected = Vec; fn decode(raw: Vec, expected: Self::Expected) -> Self { CheckedValues( @@ -185,23 +193,27 @@ impl Decode for CheckedValues { } impl Decode for CheckedValue { - type Expected = Type; + type Expected = ConcreteType; fn decode(raw: Vec, expected: Self::Expected) -> Self { let mut raw = raw; match expected { - Type::FieldElement => CheckedValue::Field(raw.pop().unwrap()), - Type::Uint(UBitwidth::B8) => CheckedValue::U8( - u8::from_str_radix(&raw.pop().unwrap().to_dec_string(), 10).unwrap(), - ), - Type::Uint(UBitwidth::B16) => CheckedValue::U16( - u16::from_str_radix(&raw.pop().unwrap().to_dec_string(), 10).unwrap(), - ), - Type::Uint(UBitwidth::B32) => CheckedValue::U32( - u32::from_str_radix(&raw.pop().unwrap().to_dec_string(), 10).unwrap(), - ), - Type::Boolean => { + ConcreteType::Int => unreachable!(), + ConcreteType::FieldElement => CheckedValue::Field(raw.pop().unwrap()), + ConcreteType::Uint(UBitwidth::B8) => { + CheckedValue::U8(raw.pop().unwrap().to_dec_string().parse().unwrap()) + } + ConcreteType::Uint(UBitwidth::B16) => { + CheckedValue::U16(raw.pop().unwrap().to_dec_string().parse().unwrap()) + } + ConcreteType::Uint(UBitwidth::B32) => { + CheckedValue::U32(raw.pop().unwrap().to_dec_string().parse().unwrap()) + } + ConcreteType::Uint(UBitwidth::B64) => { + CheckedValue::U64(raw.pop().unwrap().to_dec_string().parse().unwrap()) + } + ConcreteType::Boolean => { let v = raw.pop().unwrap(); CheckedValue::Boolean(if v == 0.into() { false @@ -211,12 +223,12 @@ impl Decode for CheckedValue { unreachable!() }) } - Type::Array(array_type) => CheckedValue::Array( + ConcreteType::Array(array_type) => CheckedValue::Array( raw.chunks(array_type.ty.get_primitive_count()) .map(|c| CheckedValue::decode(c.to_vec(), *array_type.ty.clone())) .collect(), ), - Type::Struct(members) => CheckedValue::Struct( + ConcreteType::Struct(members) => CheckedValue::Struct( members .into_iter() .scan(0, |state, member| { @@ -247,9 +259,9 @@ impl TryFrom for Values { match v { serde_json::Value::Array(a) => a .into_iter() - .map(|v| Value::try_from(v)) + .map(Value::try_from) .collect::>() - .map(|v| Values(v)), + .map(Values), v => Err(format!("Expected an array of values, found `{}`", v)), } } @@ -259,20 +271,25 @@ impl TryFrom for Value { type Error = String; fn try_from(v: serde_json::Value) -> Result, Self::Error> { match v { - serde_json::Value::String(s) => T::try_from_dec_str(&s) - .map(|v| Value::Field(v)) - .or_else(|_| match s.len() { - 4 => u8::from_str_radix(&s[2..], 16) - .map(|v| Value::U8(v)) - .map_err(|_| format!("Expected u8 value, found {}", s)), - 6 => u16::from_str_radix(&s[2..], 16) - .map(|v| Value::U16(v)) - .map_err(|_| format!("Expected u16 value, found {}", s)), - 10 => u32::from_str_radix(&s[2..], 16) - .map(|v| Value::U32(v)) - .map_err(|_| format!("Expected u32 value, found {}", s)), - _ => Err(format!("Cannot parse {} to any type", s)), - }), + serde_json::Value::String(s) => { + T::try_from_dec_str(&s) + .map(Value::Field) + .or_else(|_| match s.len() { + 4 => u8::from_str_radix(&s[2..], 16) + .map(Value::U8) + .map_err(|_| format!("Expected u8 value, found {}", s)), + 6 => u16::from_str_radix(&s[2..], 16) + .map(Value::U16) + .map_err(|_| format!("Expected u16 value, found {}", s)), + 10 => u32::from_str_radix(&s[2..], 16) + .map(Value::U32) + .map_err(|_| format!("Expected u32 value, found {}", s)), + 18 => u64::from_str_radix(&s[2..], 16) + .map(Value::U64) + .map_err(|_| format!("Expected u64 value, found {}", s)), + _ => Err(format!("Cannot parse {} to any type", s)), + }) + } serde_json::Value::Bool(b) => Ok(Value::Boolean(b)), serde_json::Value::Number(n) => Err(format!( "Value `{}` isn't allowed, did you mean `\"{}\"`?", @@ -280,50 +297,56 @@ impl TryFrom for Value { )), serde_json::Value::Array(a) => a .into_iter() - .map(|v| Value::try_from(v)) + .map(Value::try_from) .collect::>() - .map(|v| Value::Array(v)), + .map(Value::Array), serde_json::Value::Object(o) => o .into_iter() .map(|(k, v)| Value::try_from(v).map(|v| (k, v))) .collect::, _>>() - .map(|v| Value::Struct(v)), + .map(Value::Struct), v => Err(format!("Value `{}` isn't allowed", v)), } } } -impl Into for CheckedValue { - fn into(self) -> serde_json::Value { +impl CheckedValue { + pub fn into_serde_json(self) -> serde_json::Value { match self { CheckedValue::Field(f) => serde_json::Value::String(f.to_dec_string()), CheckedValue::U8(u) => serde_json::Value::String(format!("{:#04x}", u)), CheckedValue::U16(u) => serde_json::Value::String(format!("{:#06x}", u)), CheckedValue::U32(u) => serde_json::Value::String(format!("{:#010x}", u)), + CheckedValue::U64(u) => serde_json::Value::String(format!("{:#018x}", u)), CheckedValue::Boolean(b) => serde_json::Value::Bool(b), CheckedValue::Array(a) => { - serde_json::Value::Array(a.into_iter().map(|e| e.into()).collect()) - } - CheckedValue::Struct(s) => { - serde_json::Value::Object(s.into_iter().map(|(k, v)| (k, v.into())).collect()) + serde_json::Value::Array(a.into_iter().map(|e| e.into_serde_json()).collect()) } + CheckedValue::Struct(s) => serde_json::Value::Object( + s.into_iter() + .map(|(k, v)| (k, v.into_serde_json())) + .collect(), + ), } } } -impl Into for CheckedValues { - fn into(self) -> serde_json::Value { - serde_json::Value::Array(self.0.into_iter().map(|e| e.into()).collect()) +impl CheckedValues { + pub fn into_serde_json(self) -> serde_json::Value { + serde_json::Value::Array(self.0.into_iter().map(|e| e.into_serde_json()).collect()) } } fn parse(s: &str) -> Result, Error> { let json_values: serde_json::Value = serde_json::from_str(s).map_err(|e| Error::Json(e.to_string()))?; - Values::try_from(json_values).map_err(|e| Error::Conversion(e)) + Values::try_from(json_values).map_err(Error::Conversion) } -pub fn parse_strict(s: &str, types: Vec) -> Result, Error> { +pub fn parse_strict( + s: &str, + types: Vec, +) -> Result, Error> { let parsed = parse(s)?; if parsed.0.len() != types.len() { return Err(Error::Type(format!( @@ -338,7 +361,7 @@ pub fn parse_strict(s: &str, types: Vec) -> Result, _>>() - .map_err(|e| Error::Type(e))?; + .map_err(Error::Type)?; Ok(CheckedValues(checked)) } @@ -403,14 +426,19 @@ mod tests { mod strict { use super::*; - use zokrates_core::typed_absy::types::{StructMember, StructType}; + use zokrates_core::typed_absy::types::{ + ConcreteStructMember, ConcreteStructType, ConcreteType, + }; #[test] fn fields() { let s = r#"["1", "2"]"#; assert_eq!( - parse_strict::(s, vec![Type::FieldElement, Type::FieldElement]) - .unwrap(), + parse_strict::( + s, + vec![ConcreteType::FieldElement, ConcreteType::FieldElement] + ) + .unwrap(), CheckedValues(vec![ CheckedValue::Field(1.into()), CheckedValue::Field(2.into()) @@ -422,7 +450,8 @@ mod tests { fn bools() { let s = "[true, false]"; assert_eq!( - parse_strict::(s, vec![Type::Boolean, Type::Boolean]).unwrap(), + parse_strict::(s, vec![ConcreteType::Boolean, ConcreteType::Boolean]) + .unwrap(), CheckedValues(vec![ CheckedValue::Boolean(true), CheckedValue::Boolean(false) @@ -434,7 +463,11 @@ mod tests { fn array() { let s = "[[true, false]]"; assert_eq!( - parse_strict::(s, vec![Type::array(Type::Boolean, 2)]).unwrap(), + parse_strict::( + s, + vec![ConcreteType::array((ConcreteType::Boolean, 2usize))] + ) + .unwrap(), CheckedValues(vec![CheckedValue::Array(vec![ CheckedValue::Boolean(true), CheckedValue::Boolean(false) @@ -448,10 +481,13 @@ mod tests { assert_eq!( parse_strict::( s, - vec![Type::Struct(StructType::new( + vec![ConcreteType::Struct(ConcreteStructType::new( "".into(), "".into(), - vec![StructMember::new("a".into(), Type::FieldElement)] + vec![ConcreteStructMember::new( + "a".into(), + ConcreteType::FieldElement + )] ))] ) .unwrap(), @@ -466,10 +502,13 @@ mod tests { assert_eq!( parse_strict::( s, - vec![Type::Struct(StructType::new( + vec![ConcreteType::Struct(ConcreteStructType::new( "".into(), "".into(), - vec![StructMember::new("a".into(), Type::FieldElement)] + vec![ConcreteStructMember::new( + "a".into(), + ConcreteType::FieldElement + )] ))] ) .unwrap_err(), @@ -480,10 +519,13 @@ mod tests { assert_eq!( parse_strict::( s, - vec![Type::Struct(StructType::new( + vec![ConcreteType::Struct(ConcreteStructType::new( "".into(), "".into(), - vec![StructMember::new("a".into(), Type::FieldElement)] + vec![ConcreteStructMember::new( + "a".into(), + ConcreteType::FieldElement + )] ))] ) .unwrap_err(), @@ -494,10 +536,13 @@ mod tests { assert_eq!( parse_strict::( s, - vec![Type::Struct(StructType::new( + vec![ConcreteType::Struct(ConcreteStructType::new( "".into(), "".into(), - vec![StructMember::new("a".into(), Type::FieldElement)] + vec![ConcreteStructMember::new( + "a".into(), + ConcreteType::FieldElement + )] ))] ) .unwrap_err(), diff --git a/zokrates_book/src/SUMMARY.md b/zokrates_book/src/SUMMARY.md index 2a6406f3e..6ccefb31e 100644 --- a/zokrates_book/src/SUMMARY.md +++ b/zokrates_book/src/SUMMARY.md @@ -12,6 +12,7 @@ - [Control flow](language/control_flow.md) - [Imports](language/imports.md) - [Comments](language/comments.md) + - [Generics](language/generics.md) - [Macros](language/macros.md) - [Toolbox](toolbox/index.md) diff --git a/zokrates_book/src/language/control_flow.md b/zokrates_book/src/language/control_flow.md index c83961bfe..10036b2b7 100644 --- a/zokrates_book/src/language/control_flow.md +++ b/zokrates_book/src/language/control_flow.md @@ -12,6 +12,12 @@ Arguments are passed by value. {{#include ../../../zokrates_cli/examples/book/side_effects.zok}} ``` +Generic paramaters, if any, must be compile-time constants. They are inferred by the compiler if that is possible, but can also be provided explicitly. + +```zokrates +{{#include ../../../zokrates_cli/examples/book/generic_call.zok}} +``` + ### If-expressions An if-expression allows you to branch your code depending on a boolean condition. @@ -28,7 +34,7 @@ For loops are available with the following syntax: {{#include ../../../zokrates_cli/examples/book/for.zok}} ``` -The bounds have to be constant at compile-time, therefore they cannot depend on execution inputs. +The bounds have to be constant at compile-time, therefore they cannot depend on execution inputs. They can depend on generic parameters. ### Assertions diff --git a/zokrates_book/src/language/functions.md b/zokrates_book/src/language/functions.md index 4fe273399..8282b68e9 100644 --- a/zokrates_book/src/language/functions.md +++ b/zokrates_book/src/language/functions.md @@ -7,7 +7,14 @@ A function has to be declared at the top level before it is called. ``` A function's signature has to be explicitly provided. -Functions can return many values by providing them as a comma-separated list. + +A function can be generic over any number of values of type `u32`. + +```zokrates +{{#include ../../../zokrates_cli/examples/book/generic_function_declaration.zok}} +``` + +Functions can return multiple values by providing them as a comma-separated list. ```zokrates {{#include ../../../zokrates_cli/examples/book/multi_return.zok}} diff --git a/zokrates_book/src/language/generics.md b/zokrates_book/src/language/generics.md new file mode 100644 index 000000000..e0e0dfe17 --- /dev/null +++ b/zokrates_book/src/language/generics.md @@ -0,0 +1,7 @@ +## Generics + +ZoKrates supports code that is generic over constants of the `u32` type. No specific keyword is used: the compiler determines if the generic parameters are indeed constant at compile time. Here's an example of generic code in ZoKrates: + +```zokrates +{{#include ../../../zokrates_cli/examples/book/generics.zok}} +``` \ No newline at end of file diff --git a/zokrates_book/src/language/operators.md b/zokrates_book/src/language/operators.md index baf325887..afaffa383 100644 --- a/zokrates_book/src/language/operators.md +++ b/zokrates_book/src/language/operators.md @@ -1,25 +1,25 @@ ## Operators -The following table lists the precedence and associativity of all available operators. Operators are listed top to bottom, in ascending precedence. +The following table lists the precedence and associativity of all operators. Operators are listed top to bottom, in ascending precedence. Operators in the same box group left to right. Operators are binary, unless the syntax is provided. -| Operator | Description | Associativity | Remarks | -|------------------------------|--------------------------------------------------------------|------------------------------------|---------| -| **
| Power | Left | [^1] | -| *
/
%
| Multiplication
Division
Remainder | Left
Left
Left | | -| +
-
| Addition
Subtraction
| Left
Left | | -| <<
>>
| Left shift
Right shift
| Left
Left | [^2] | -| & | Bitwise AND | Left
Left | | -| \| | Bitwise OR | Left
Left | | -| ^ | Bitwise XOR | Left
Left | | -| >=

>
<=
< | Greater or equal
Greater
Lower or equal
Lower | Left
Left
Left
Left | [^3] | -| !=
==
| Not Equal
Equal
| Left
Left | | -| && | Boolean AND | Left | | -| \|\| | Boolean OR | Left | | +| Operator | Description | Remarks | +|---------------------------------|-------------------------------------------------------------------|---------| +| `**`
| Power | [^1] | +| `+x`
`-x`
`!x`
| Positive
Negative
Negation
| | +| `*`
`/`
`%`
| Multiplication
Division
Remainder
| | +| `+`
`-`
| Addition
Subtraction
| | +| `<<`
`>>`
| Left shift
Right shift
| [^2] | +| `&` | Bitwise AND | | +| | | Bitwise OR | | +| `^` | Bitwise XOR | | +| `>=`
`>`
`<=`
`<`| Greater or equal
Greater
Lower or equal
Lower
| [^3] | +| `!=`
`==`
| Not Equal
Equal
| | +| `&&` | Boolean AND | | +| || | Boolean OR | | +| `if c then x else y fi` | Conditional expression | | +[^1]: The exponent must be a compile-time constant of type `u32` - -[^1]: The exponent must be a compile-time constant - -[^2]: The right operand must be a compile time constant +[^2]: The right operand must be a compile time constant of type `u32` [^3]: Both operands are asserted to be strictly lower than the biggest power of 2 lower than `p/2` \ No newline at end of file diff --git a/zokrates_book/src/language/types.md b/zokrates_book/src/language/types.md index 4a978caec..573d5b77d 100644 --- a/zokrates_book/src/language/types.md +++ b/zokrates_book/src/language/types.md @@ -8,7 +8,7 @@ ZoKrates currently exposes two primitive types and two complex types: This is the most basic type in ZoKrates, and it represents a field element with positive integer values in `[0, p - 1]` where `p` is a (large) prime number. Standard arithmetic operations are supported; note that [division in the finite field](https://en.wikipedia.org/wiki/Finite_field_arithmetic) behaves differently than in the case of integers. -As an example, `p` is set to `21888242871839275222246405745257275088548364400416034343698204186575808495617` when working with the [ALT_BN128](/reference/proving_schemes.html#alt_bn128) curve supported by Ethereum. +As an example, `p` is set to `21888242871839275222246405745257275088548364400416034343698204186575808495617` when working with the [ALT_BN128](/toolbox/proving_schemes.html#alt_bn128) curve supported by Ethereum. While `field` values mostly behave like unsigned integers, one should keep in mind that they overflow at `p` and not some power of 2, so that we have: @@ -22,7 +22,7 @@ Note that for field elements, the division operation multiplies the numerator wi Booleans are available in ZoKrates. When a boolean is used as a parameter of the main function, the program is constrained to only accept `0` or `1` for that parameter. A boolean can be asserted to be true using an `assert(bool)` statement. -### `u8/u16/u32` +### `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`. @@ -32,13 +32,23 @@ Similarly to booleans, unsigned integer inputs of the main function only accept The division operation calculates the standard floor division for integers. The `%` operand can be used to obtain the remainder. +### Numeric inference + +In the case of decimal literals like `42`, the compiler tries to find the appropriate type (`field`, `u8`, `u16`, `u32` or `u64`) depending on the context. If it cannot converge to a single option, an error is returned. This means that there is no default type for decimal literals. + +All operations between literals have the semantics of the inferred type. + +```zokrates +{{#include ../../../zokrates_cli/examples/book/numeric_inference.zok}} +``` + ## Complex Types ZoKrates provides two complex types: arrays and structs. ### Arrays -ZoKrates supports static arrays, i.e., whose length needs to be known at compile time. +ZoKrates supports static arrays, i.e., whose length needs to be known at compile time. For more details on generic array sizes, see [constant generics](/language/generics.html) Arrays can contain elements of any type and have arbitrary dimensions. The following example code shows examples of how to use arrays: diff --git a/zokrates_book/src/rng_tutorial.md b/zokrates_book/src/rng_tutorial.md index 318633e32..ad3fd4472 100644 --- a/zokrates_book/src/rng_tutorial.md +++ b/zokrates_book/src/rng_tutorial.md @@ -56,9 +56,9 @@ Witness: Pick your own value and store it somewhere. ### Detailed explanation -This line imports a Zokrates function from the [standard library](https://github.com/Zokrates/ZoKrates/tree/master/zokrates_stdlib/stdlib). +This line imports a Zokrates function from the [standard library](https://github.com/Zokrates/ZoKrates/tree/latest/zokrates_stdlib/stdlib). You can see the specific function we are importing -[here](https://github.com/Zokrates/ZoKrates/blob/master/zokrates_stdlib/stdlib/hashes/sha256/512bit.zok). It will be +[here](https://github.com/Zokrates/ZoKrates/blob/latest/zokrates_stdlib/stdlib/hashes/sha256/512bit.zok). It will be called `sha256`. ```javascript import "hashes/sha256/512bit" as sha256 @@ -80,7 +80,7 @@ def main(u32[16] hashMe) -> u32[8]: This line does several things. First, `u32[8] h` defines a variable called `h`, whose type is an array of eight 32-bit unsigned integers. This variable is initialized using `sha256`, the function we -[imported from the standard library](https://github.com/Zokrates/ZoKrates/blob/master/zokrates_stdlib/stdlib/hashes/sha256/512bit.zok). +[imported from the standard library](https://github.com/Zokrates/ZoKrates/blob/latest/zokrates_stdlib/stdlib/hashes/sha256/512bit.zok). The `sha256` function expects to get two arrays of eight values each, so we use a [slice `..`](https://zokrates.github.io/language/types.html#slices) to divide `hashMe` into two arrays. diff --git a/zokrates_cli/Cargo.toml b/zokrates_cli/Cargo.toml index eba1f77dd..d4344c914 100644 --- a/zokrates_cli/Cargo.toml +++ b/zokrates_cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zokrates_cli" -version = "0.6.4" +version = "0.7.0" authors = ["Jacob Eberhardt ", "Dennis Kuhnert ", "Thibaut Schaeffer "] repository = "https://github.com/JacobEberhardt/ZoKrates.git" edition = "2018" @@ -16,9 +16,9 @@ cfg-if = "0.1" clap = "2.26.2" bincode = "0.8.0" regex = "0.2" -zokrates_field = { version = "0.3", path = "../zokrates_field", default-features = false } +zokrates_field = { version = "0.4", path = "../zokrates_field", default-features = false } zokrates_abi = { version = "0.1", path = "../zokrates_abi" } -zokrates_core = { version = "0.5", path = "../zokrates_core", default-features = false } +zokrates_core = { version = "0.6", path = "../zokrates_core", default-features = false } zokrates_fs_resolver = { version = "0.5", path = "../zokrates_fs_resolver"} serde_json = "1.0" dirs = "3.0.1" diff --git a/zokrates_cli/build.rs b/zokrates_cli/build.rs index add3c6238..bbdc6b489 100644 --- a/zokrates_cli/build.rs +++ b/zokrates_cli/build.rs @@ -11,5 +11,5 @@ fn export_stdlib() { let out_dir = env::var("OUT_DIR").unwrap(); let mut options = CopyOptions::new(); options.overwrite = true; - copy_items(&vec!["tests/contract"], out_dir, &options).unwrap(); + copy_items(&["tests/contract"], out_dir, &options).unwrap(); } diff --git a/zokrates_cli/examples/arrays/array_loop.zok b/zokrates_cli/examples/arrays/array_loop.zok index 024d3777c..73e4fb457 100644 --- a/zokrates_cli/examples/arrays/array_loop.zok +++ b/zokrates_cli/examples/arrays/array_loop.zok @@ -1,7 +1,7 @@ -def main() -> field: - field[3] a = [1, 2, 3] - field c = 0 - for field i in 0..3 do +def main() -> u32: + u32[3] a = [1, 2, 3] + u32 c = 0 + for u32 i in 0..3 do c = c + a[i] endfor return c \ No newline at end of file diff --git a/zokrates_cli/examples/arrays/array_loop_update.zok b/zokrates_cli/examples/arrays/array_loop_update.zok index 815de1c0e..d16cc9da2 100644 --- a/zokrates_cli/examples/arrays/array_loop_update.zok +++ b/zokrates_cli/examples/arrays/array_loop_update.zok @@ -1,7 +1,7 @@ -def main() -> (field[3]): - field[3] a = [1, 2, 3] - field[3] c = [4, 5, 6] - for field i in 0..3 do +def main() -> (u32[3]): + u32[3] a = [1, 2, 3] + u32[3] c = [4, 5, 6] + for u32 i in 0..3 do c[i] = c[i] + a[i] endfor return c \ No newline at end of file diff --git a/zokrates_cli/examples/arrays/boolean_array.zok b/zokrates_cli/examples/arrays/boolean_array.zok index 08633b673..89576f4d8 100644 --- a/zokrates_cli/examples/arrays/boolean_array.zok +++ b/zokrates_cli/examples/arrays/boolean_array.zok @@ -3,7 +3,7 @@ def main(bool[3] a) -> (field[3]): a[1] = true || a[2] a[2] = a[0] field[3] result = [0; 3] - for field i in 0..3 do + for u32 i in 0..3 do result[i] = if a[i] then 33 else 0 fi endfor return result diff --git a/zokrates_cli/examples/arrays/cube.zok b/zokrates_cli/examples/arrays/cube.zok index 1ea112d03..eca27ec6c 100644 --- a/zokrates_cli/examples/arrays/cube.zok +++ b/zokrates_cli/examples/arrays/cube.zok @@ -1,9 +1,9 @@ def main(field[2][2][2] cube) -> field: field res = 0 - for field i in 0..2 do - for field j in 0..2 do - for field k in 0..2 do + for u32 i in 0..2 do + for u32 j in 0..2 do + for u32 k in 0..2 do res = res + cube[i][j][k] endfor endfor diff --git a/zokrates_cli/examples/arrays/lookup.zok b/zokrates_cli/examples/arrays/lookup.zok index 95404692f..6b25d439f 100644 --- a/zokrates_cli/examples/arrays/lookup.zok +++ b/zokrates_cli/examples/arrays/lookup.zok @@ -1,2 +1,2 @@ -def main(field index, field[5] array) -> field: +def main(u32 index, field[5] array) -> field: return array[index] \ No newline at end of file diff --git a/zokrates_cli/examples/arrays/multidim_update.zok b/zokrates_cli/examples/arrays/multidim_update.zok index 89bdb22d4..358c049a6 100644 --- a/zokrates_cli/examples/arrays/multidim_update.zok +++ b/zokrates_cli/examples/arrays/multidim_update.zok @@ -1,4 +1,4 @@ -def main(field[10][10][10] a, field i, field j, field k) -> (field[3]): +def main(field[10][10][10] a, u32 i, u32 j, u32 k) -> (field[3]): a[i][j][k] = 42 field[3][3] b = [[1, 2, 3], [1, 2, 3], [1, 2, 3]] return b[0] \ No newline at end of file diff --git a/zokrates_cli/examples/arrays/repeat.zok b/zokrates_cli/examples/arrays/repeat.zok new file mode 100644 index 000000000..07ca853e2 --- /dev/null +++ b/zokrates_cli/examples/arrays/repeat.zok @@ -0,0 +1,4 @@ +def main(field a) -> field[4]: + u32 SIZE = 4 + field[SIZE] res = [a; SIZE] + return res \ No newline at end of file diff --git a/zokrates_cli/examples/arrays/slicefrom.zok b/zokrates_cli/examples/arrays/slicefrom.zok index a3e09ec75..225d4a6f5 100644 --- a/zokrates_cli/examples/arrays/slicefrom.zok +++ b/zokrates_cli/examples/arrays/slicefrom.zok @@ -1,6 +1,6 @@ -def slice32from(field offset, field[2048] input) -> (field[32]): +def slice32from(u32 offset, field[2048] input) -> (field[32]): field[32] result = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] - for field i in 0..32 do + for u32 i in 0..32 do result[i] = input[offset + i] endfor return result diff --git a/zokrates_cli/examples/arrays/wrap_select.zok b/zokrates_cli/examples/arrays/wrap_select.zok index 162b6e1f4..03c8b5452 100644 --- a/zokrates_cli/examples/arrays/wrap_select.zok +++ b/zokrates_cli/examples/arrays/wrap_select.zok @@ -1,4 +1,4 @@ -def get(field[32] array, field index) -> field: +def get(field[32] array, u32 index) -> field: return array[index] def main() -> field: diff --git a/zokrates_cli/examples/book/array.zok b/zokrates_cli/examples/book/array.zok index 943fb12ab..1e8bcfce9 100644 --- a/zokrates_cli/examples/book/array.zok +++ b/zokrates_cli/examples/book/array.zok @@ -5,4 +5,6 @@ def main() -> field: field[4] c = [...a, 4] // initialize an array copying values from `a`, followed by 4 field[2] d = a[1..3] // initialize an array copying a slice from `a` bool[3] e = [true, true || false, true] // initialize a boolean array + u32 SIZE = 3 + field[SIZE] f = [1, 2, 3] // initialize a field array with a size that's a compile-time constant return a[0] + b[1] + c[2] diff --git a/zokrates_cli/examples/book/assert.zok b/zokrates_cli/examples/book/assert.zok index c4277fed1..75db27631 100644 --- a/zokrates_cli/examples/book/assert.zok +++ b/zokrates_cli/examples/book/assert.zok @@ -1,3 +1,3 @@ def main() -> (): - assert(1 == 2) + assert(1f == 2f) return \ No newline at end of file diff --git a/zokrates_cli/examples/book/for.zok b/zokrates_cli/examples/book/for.zok index 8c61fc29c..b5d8f5020 100644 --- a/zokrates_cli/examples/book/for.zok +++ b/zokrates_cli/examples/book/for.zok @@ -1,7 +1,7 @@ -def main() -> field: - field res = 0 - for field i in 0..4 do - for field j in i..5 do +def main() -> u32: + u32 res = 0 + for u32 i in 0..4 do + for u32 j in i..5 do res = res + i endfor endfor diff --git a/zokrates_cli/examples/book/for_scope.zok b/zokrates_cli/examples/book/for_scope.zok index 340ca6c97..2b92dd1f8 100644 --- a/zokrates_cli/examples/book/for_scope.zok +++ b/zokrates_cli/examples/book/for_scope.zok @@ -1,6 +1,6 @@ -def main() -> field: - field a = 0 - for field i in 0..5 do +def main() -> u32: + u32 a = 0 + for u32 i in 0..5 do a = a + i endfor // return i <- not allowed diff --git a/zokrates_cli/examples/book/function_declaration.zok b/zokrates_cli/examples/book/function_declaration.zok index 89658ac02..2e0f1bb4b 100644 --- a/zokrates_cli/examples/book/function_declaration.zok +++ b/zokrates_cli/examples/book/function_declaration.zok @@ -1,5 +1,5 @@ -def foo() -> field: - return 1 +def foo(field a, field b) -> field: + return a + b def main() -> field: - return foo() \ No newline at end of file + return foo(1, 2) \ No newline at end of file diff --git a/zokrates_cli/examples/book/generic_call.zok b/zokrates_cli/examples/book/generic_call.zok new file mode 100644 index 000000000..a26a9f814 --- /dev/null +++ b/zokrates_cli/examples/book/generic_call.zok @@ -0,0 +1,7 @@ +def foo() -> field[P]: + return [42; P] + +def main() -> field[2]: + // `P` is inferred from the declaration of `res`, while `N` is provided explicitly + field[2] res = foo::<3, _>() + return res \ No newline at end of file diff --git a/zokrates_cli/examples/book/generic_function_declaration.zok b/zokrates_cli/examples/book/generic_function_declaration.zok new file mode 100644 index 000000000..07c77353e --- /dev/null +++ b/zokrates_cli/examples/book/generic_function_declaration.zok @@ -0,0 +1,6 @@ +def foo() -> field[N]: + return [42; N] + +def main() -> field[2]: + field[2] res = foo() + return res \ No newline at end of file diff --git a/zokrates_cli/examples/book/generics.zok b/zokrates_cli/examples/book/generics.zok new file mode 100644 index 000000000..a9f113210 --- /dev/null +++ b/zokrates_cli/examples/book/generics.zok @@ -0,0 +1,9 @@ +def sum(field[N] a) -> field: + field res = 0 + for u32 i in 0..N do + res = res + a[i] + endfor + return res + +def main(field[3] a) -> field: + return sum(a) \ No newline at end of file diff --git a/zokrates_cli/examples/book/no_shadowing.zok b/zokrates_cli/examples/book/no_shadowing.zok index 2708ee0be..be221372c 100644 --- a/zokrates_cli/examples/book/no_shadowing.zok +++ b/zokrates_cli/examples/book/no_shadowing.zok @@ -1,7 +1,7 @@ def main() -> field: field a = 2 // field a = 3 <- not allowed - for field i in 0..5 do + for u32 i in 0..5 do // field a = 7 <- not allowed endfor return a \ No newline at end of file diff --git a/zokrates_cli/examples/book/numeric_inference.zok b/zokrates_cli/examples/book/numeric_inference.zok new file mode 100644 index 000000000..068229e0b --- /dev/null +++ b/zokrates_cli/examples/book/numeric_inference.zok @@ -0,0 +1,9 @@ +def main(): + // `255` is infered to `255f`, and the addition happens between field elements + assert(255 + 1f == 256) + + // `255` is infered to `255u8`, and the addition happens between u8 + // This causes an overflow + assert(255 + 1u8 == 0) + + return \ No newline at end of file diff --git a/zokrates_cli/examples/compile_errors/double_negation.zok b/zokrates_cli/examples/compile_errors/double_negation.zok new file mode 100644 index 000000000..257892a8f --- /dev/null +++ b/zokrates_cli/examples/compile_errors/double_negation.zok @@ -0,0 +1,3 @@ +def main(): + field a = - - 1 + return \ No newline at end of file diff --git a/zokrates_cli/examples/compile_errors/double_power.zok b/zokrates_cli/examples/compile_errors/double_power.zok new file mode 100644 index 000000000..43443699c --- /dev/null +++ b/zokrates_cli/examples/compile_errors/double_power.zok @@ -0,0 +1,3 @@ +def main(): + field a = 1**2**3 // parentheses are required here + return \ No newline at end of file diff --git a/zokrates_cli/examples/compile_errors/embed_type_mismatch.zok b/zokrates_cli/examples/compile_errors/embed_type_mismatch.zok new file mode 100644 index 000000000..047df566d --- /dev/null +++ b/zokrates_cli/examples/compile_errors/embed_type_mismatch.zok @@ -0,0 +1,5 @@ +import "EMBED/u8_to_bits" as u8_to_bits + +def main(u8 x): + bool[32] b = u8_to_bits(x) // note the incorrect array length on the left + return \ No newline at end of file diff --git a/zokrates_cli/examples/compile_errors/generics/assign_size_mismatch.zok b/zokrates_cli/examples/compile_errors/generics/assign_size_mismatch.zok new file mode 100644 index 000000000..727346f6d --- /dev/null +++ b/zokrates_cli/examples/compile_errors/generics/assign_size_mismatch.zok @@ -0,0 +1,8 @@ +def foo(field[N] a) -> bool: + field[3] b = a + return true + + +def main(field[1] a): + assert(foo(a)) + return \ No newline at end of file diff --git a/zokrates_cli/examples/compile_errors/generics/concrete_length_mismatch.zok b/zokrates_cli/examples/compile_errors/generics/concrete_length_mismatch.zok new file mode 100644 index 000000000..906326a43 --- /dev/null +++ b/zokrates_cli/examples/compile_errors/generics/concrete_length_mismatch.zok @@ -0,0 +1,3 @@ +def main(): + assert([1] == [1, 2]) + return \ No newline at end of file diff --git a/zokrates_cli/examples/compile_errors/generics/generics_in_main.zok b/zokrates_cli/examples/compile_errors/generics/generics_in_main.zok new file mode 100644 index 000000000..137f0b610 --- /dev/null +++ b/zokrates_cli/examples/compile_errors/generics/generics_in_main.zok @@ -0,0 +1,2 @@ +def main

(field[P] a): + return \ No newline at end of file diff --git a/zokrates_cli/examples/compile_errors/generics/incompatible.zok b/zokrates_cli/examples/compile_errors/generics/incompatible.zok new file mode 100644 index 000000000..bbf114d73 --- /dev/null +++ b/zokrates_cli/examples/compile_errors/generics/incompatible.zok @@ -0,0 +1,5 @@ +def foo

(field[P] a, field[P] b) -> field: + return 42 + +def main() -> field: + return foo([1, 2], [1]) \ No newline at end of file diff --git a/zokrates_cli/examples/compile_errors/generics/no_weak_eq.zok b/zokrates_cli/examples/compile_errors/generics/no_weak_eq.zok new file mode 100644 index 000000000..5169eb5bc --- /dev/null +++ b/zokrates_cli/examples/compile_errors/generics/no_weak_eq.zok @@ -0,0 +1,3 @@ +def main(): + assert([[1]] == [1, 2]) + return \ No newline at end of file diff --git a/zokrates_cli/examples/compile_errors/generics/unused.zok b/zokrates_cli/examples/compile_errors/generics/unused.zok new file mode 100644 index 000000000..025c74521 --- /dev/null +++ b/zokrates_cli/examples/compile_errors/generics/unused.zok @@ -0,0 +1,2 @@ +def main

(): + return \ No newline at end of file diff --git a/zokrates_cli/examples/compile_errors/out_of_for_scope.zok b/zokrates_cli/examples/compile_errors/out_of_for_scope.zok index 5d701a181..e1c73da12 100644 --- a/zokrates_cli/examples/compile_errors/out_of_for_scope.zok +++ b/zokrates_cli/examples/compile_errors/out_of_for_scope.zok @@ -1,4 +1,4 @@ def main() -> field: - for field i in 0..5 do + for u32 i in 0..5 do endfor return i \ No newline at end of file diff --git a/zokrates_cli/examples/conditions.zok b/zokrates_cli/examples/conditions.zok index fd92d11d4..74cd9b9a1 100644 --- a/zokrates_cli/examples/conditions.zok +++ b/zokrates_cli/examples/conditions.zok @@ -14,6 +14,6 @@ def main(field a) -> field: assert(2 * b == a * 12 + 60) field c = 7 * (b + a) assert(isEqual(c, 7 * b + 7 * a)) - field k = if [1, 2] == [3, 4] then 1 else 3 fi + field k = if [1f, 2] == [3f, 4] then 1 else 3 fi assert([Bar { foo : [Foo { a: 42 }]}] == [Bar { foo : [Foo { a: 42 }]}]) return b + c \ No newline at end of file diff --git a/zokrates_cli/examples/for.zok b/zokrates_cli/examples/for.zok index 6cce51354..7bdf2b8f7 100644 --- a/zokrates_cli/examples/for.zok +++ b/zokrates_cli/examples/for.zok @@ -1,6 +1,10 @@ +def bound(field x) -> u32: + return 41 + 1 + def main(field a) -> field: field x = 7 - for field i in 0..10 do + x = x + 1 + for u32 i in 0..bound(x) do // x = x + a x = x + a endfor diff --git a/zokrates_cli/examples/functions/lt_comparison.zok b/zokrates_cli/examples/functions/lt_comparison.zok index 8e9b37823..c65428405 100644 --- a/zokrates_cli/examples/functions/lt_comparison.zok +++ b/zokrates_cli/examples/functions/lt_comparison.zok @@ -4,14 +4,14 @@ def lt(field a,field b) -> bool: def cutoff() -> field: return 31337 -def getThing(field index) -> field: +def getThing(u32 index) -> field: field[6] a = [13, 23, 43, 53, 73, 83] return a[index] def cubeThing(field thing) -> field: return thing**3 -def main(field index) -> bool: +def main(u32 index) -> bool: field thing = getThing(index) thing = cubeThing(thing) return lt(cutoff(), thing) diff --git a/zokrates_cli/examples/merkleTree/pedersenPathProof3.zok b/zokrates_cli/examples/merkleTree/pedersenPathProof3.zok index d6225098d..9a7114be3 100644 --- a/zokrates_cli/examples/merkleTree/pedersenPathProof3.zok +++ b/zokrates_cli/examples/merkleTree/pedersenPathProof3.zok @@ -4,9 +4,6 @@ import "ecc/babyjubjubParams" as context from "ecc/babyjubjubParams" import BabyJubJubParams import "hashes/utils/256bitsDirectionHelper" as multiplex -def multiplex(bool selector, u32[8] left, u32[8] right) -> (u32[8]): - return if selector then right else left fi - // Merke-Tree inclusion proof for tree depth 3 using SNARK efficient pedersen hashes // directionSelector=> true if current digest is on the rhs of the hash diff --git a/zokrates_cli/examples/n_choose_k.zok b/zokrates_cli/examples/n_choose_k.zok index a7a34d943..b5e820d72 100644 --- a/zokrates_cli/examples/n_choose_k.zok +++ b/zokrates_cli/examples/n_choose_k.zok @@ -1,9 +1,11 @@ +import "utils/casts/u32_to_field" as to_field + // Binomial Coeffizient, n!/(k!*(n-k)!). def fac(field x) -> field: field f = 1 field counter = 0 - for field i in 1..100 do - f = if counter == x then f else f * i fi + for u32 i in 1..100 do + f = if counter == x then f else f * to_field(i) fi counter = if counter == x then counter else counter + 1 fi endfor return f diff --git a/zokrates_cli/examples/propagate.zok b/zokrates_cli/examples/propagate.zok index 9b3176b0e..543ac20c8 100644 --- a/zokrates_cli/examples/propagate.zok +++ b/zokrates_cli/examples/propagate.zok @@ -2,7 +2,7 @@ def main() -> field: field a = 1 + 2 + 3 field b = if 1 < a then 3 else a + 3 fi field c = if b + a == 2 then 1 else b fi - for field e in 0..2 do + for u32 e in 0..2 do field g = 4 c = c + g endfor diff --git a/zokrates_cli/examples/reduceable_exponent.zok b/zokrates_cli/examples/reduceable_exponent.zok index d3c38a74d..b17bb1c09 100644 --- a/zokrates_cli/examples/reduceable_exponent.zok +++ b/zokrates_cli/examples/reduceable_exponent.zok @@ -1,3 +1,3 @@ def main() -> field: - field a = 2 - return 2**(a**2 + 2) \ No newline at end of file + u32 a = 2 + return 2**(a * 2 + 2) \ No newline at end of file diff --git a/zokrates_cli/examples/sudoku/prime_sudoku_checker.zok b/zokrates_cli/examples/sudoku/prime_sudoku_checker.zok index e61db31d5..a5cd37d63 100644 --- a/zokrates_cli/examples/sudoku/prime_sudoku_checker.zok +++ b/zokrates_cli/examples/sudoku/prime_sudoku_checker.zok @@ -32,26 +32,26 @@ def main(field a21, field b11, field b22, field c11, field c22, field d21, priva bool res = true // go through the whole grid and check that all elements are valid - for field i in 0..4 do - for field j in 0..4 do + for u32 i in 0..4 do + for u32 j in 0..4 do res = res && validateInput(a[i][j]) endfor endfor // go through the 4 2x2 boxes and check that they do not contain duplicates - for field i in 0..1 do - for field j in 0..1 do + for u32 i in 0..1 do + for u32 j in 0..1 do res = res && checkNoDuplicates(a[2*i][2*i], a[2*i][2*i + 1], a[2*i + 1][2*i], a[2*i + 1][2*i + 1]) endfor endfor // go through the 4 rows and check that they do not contain duplicates - for field i in 0..4 do + for u32 i in 0..4 do res = res && checkNoDuplicates(a[i][0], a[i][1], a[i][2], a[i][3]) endfor // go through the 4 columns and check that they do not contain duplicates - for field j in 0..4 do + for u32 j in 0..4 do res = res && checkNoDuplicates(a[0][j], a[1][j], a[2][j], a[3][j]) endfor diff --git a/zokrates_cli/examples/waldo.zok b/zokrates_cli/examples/waldo.zok index 1839354f8..436a42b37 100644 --- a/zokrates_cli/examples/waldo.zok +++ b/zokrates_cli/examples/waldo.zok @@ -10,6 +10,6 @@ def isWaldo(field a, field p, field q) -> bool: return a == p * q // define all -def main(field[3] a, private field index, private field p, private field q) -> bool: +def main(field[3] a, private u32 index, private field p, private field q) -> bool: // prover provides the index of Waldo return isWaldo(a[index], p, q) \ No newline at end of file diff --git a/zokrates_cli/src/bin.rs b/zokrates_cli/src/bin.rs index ab847cc06..4da16054f 100644 --- a/zokrates_cli/src/bin.rs +++ b/zokrates_cli/src/bin.rs @@ -11,7 +11,7 @@ mod constants; mod helpers; mod ops; -use clap::{App, AppSettings}; +use clap::{App, AppSettings, Arg}; use ops::*; fn main() { @@ -28,14 +28,23 @@ fn cli() -> Result<(), String> { .version(env!("CARGO_PKG_VERSION")) .author("Jacob Eberhardt, Thibaut Schaeffer, Stefan Deml, Darko Macesic") .about("Supports generation of zkSNARKs from high level language code including Smart Contracts for proof verification on the Ethereum Blockchain.\n'I know that I show nothing!'") + .arg(Arg::with_name("verbose") + .long("verbose") + .help("Verbose mode") + .required(false) + .global(true) + ) .subcommands(vec![ compile::subcommand(), check::subcommand(), compute_witness::subcommand(), + #[cfg(any(feature = "bellman", feature = "ark", feature = "libsnark"))] setup::subcommand(), export_verifier::subcommand(), + #[cfg(any(feature = "bellman", feature = "ark", feature = "libsnark"))] generate_proof::subcommand(), print_proof::subcommand(), + #[cfg(any(feature = "bellman", feature = "ark", feature = "libsnark"))] verify::subcommand()]) .get_matches(); @@ -110,6 +119,8 @@ mod tests { assert_eq!(res.is_err(), should_error); } }) + .unwrap() + .join() .unwrap(); } @@ -138,7 +149,7 @@ mod tests { let interpreter = ir::Interpreter::default(); let _ = interpreter - .execute(&artifacts.prog(), &vec![Bn128Field::from(0)]) + .execute(&artifacts.prog(), &[Bn128Field::from(0)]) .unwrap(); } } @@ -167,7 +178,7 @@ mod tests { let interpreter = ir::Interpreter::default(); - let res = interpreter.execute(&artifacts.prog(), &vec![Bn128Field::from(0)]); + let res = interpreter.execute(&artifacts.prog(), &[Bn128Field::from(0)]); assert!(res.is_err()); } diff --git a/zokrates_cli/src/constants.rs b/zokrates_cli/src/constants.rs index 1af664ab7..2720f85fd 100644 --- a/zokrates_cli/src/constants.rs +++ b/zokrates_cli/src/constants.rs @@ -19,6 +19,7 @@ lazy_static! { .unwrap(); } +#[cfg(any(feature = "bellman", feature = "ark", feature = "libsnark"))] pub const BACKENDS: &[&str] = if cfg!(feature = "libsnark") { if cfg!(feature = "ark") { if cfg!(feature = "bellman") { @@ -26,27 +27,21 @@ pub const BACKENDS: &[&str] = if cfg!(feature = "libsnark") { } else { &[LIBSNARK, ARK] } + } else if cfg!(feature = "bellman") { + &[BELLMAN, LIBSNARK] } else { - if cfg!(feature = "bellman") { - &[BELLMAN, LIBSNARK] - } else { - &[LIBSNARK] - } + &[LIBSNARK] } -} else { - if cfg!(feature = "ark") { - if cfg!(feature = "bellman") { - &[BELLMAN, ARK] - } else { - &[ARK] - } +} else if cfg!(feature = "ark") { + if cfg!(feature = "bellman") { + &[BELLMAN, ARK] } else { - if cfg!(feature = "bellman") { - &[BELLMAN] - } else { - &[] - } + &[ARK] } +} else if cfg!(feature = "bellman") { + &[BELLMAN] +} else { + &[] }; pub const BN128: &str = "bn128"; diff --git a/zokrates_cli/src/helpers.rs b/zokrates_cli/src/helpers.rs index 295b749ba..f68b6d8c6 100644 --- a/zokrates_cli/src/helpers.rs +++ b/zokrates_cli/src/helpers.rs @@ -18,6 +18,7 @@ pub enum BackendParameter { Libsnark, } +#[allow(clippy::upper_case_acronyms)] pub enum SchemeParameter { G16, GM17, diff --git a/zokrates_cli/src/ops/check.rs b/zokrates_cli/src/ops/check.rs index 99186b86d..b5b25b784 100644 --- a/zokrates_cli/src/ops/check.rs +++ b/zokrates_cli/src/ops/check.rs @@ -58,7 +58,7 @@ fn cli_check(sub_matches: &ArgMatches) -> Result<(), String> { let path = PathBuf::from(sub_matches.value_of("input").unwrap()); let file = File::open(path.clone()) - .map_err(|why| format!("Couldn't open input file {}: {}", path.display(), why))?; + .map_err(|why| format!("Could not open {}: {}", path.display(), why))?; let mut reader = BufReader::new(file); let mut source = String::new(); @@ -69,7 +69,7 @@ fn cli_check(sub_matches: &ArgMatches) -> Result<(), String> { format!( "{}:{}", file.strip_prefix(std::env::current_dir().unwrap()) - .unwrap_or(file.as_path()) + .unwrap_or_else(|_| file.as_path()) .display(), e.value() ) diff --git a/zokrates_cli/src/ops/compile.rs b/zokrates_cli/src/ops/compile.rs index aeea574d8..e02067aaa 100644 --- a/zokrates_cli/src/ops/compile.rs +++ b/zokrates_cli/src/ops/compile.rs @@ -56,10 +56,16 @@ pub fn subcommand() -> App<'static, 'static> { .long("allow-unconstrained-variables") .help("Allow unconstrained variables by inserting dummy constraints") .required(false) - ).arg(Arg::with_name("light") + ).arg(Arg::with_name("ztf") + .long("ztf") + .help("Write human readable output (ztf)") + .required(false) + ) + .arg(Arg::with_name("light") // TODO: deprecated, should be removed .long("light") - .help("Skip logs and human readable output") .required(false) + .overrides_with_all(&["ztf", "verbose"]) + .hidden(true) ) } @@ -74,16 +80,23 @@ pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> { } fn cli_compile(sub_matches: &ArgMatches) -> Result<(), String> { - println!("Compiling {}\n", sub_matches.value_of("input").unwrap()); + // TODO: remove the warning once light flag is removed entirely + if sub_matches.is_present("light") { + println!( + "Warning: the --light flag is deprecated and will be removed in a coming release.\n\ + Terminal output is now off by default and can be activated with the --verbose flag.\n\ + Human-readable output file (ztf) is now off by default and can be activated with the --ztf flag.\n" + ) + } + println!("Compiling {}\n", sub_matches.value_of("input").unwrap()); let path = PathBuf::from(sub_matches.value_of("input").unwrap()); - let light = sub_matches.occurrences_of("light") > 0; let bin_output_path = Path::new(sub_matches.value_of("output").unwrap()); let abi_spec_path = Path::new(sub_matches.value_of("abi-spec").unwrap()); let hr_output_path = bin_output_path.to_path_buf().with_extension("ztf"); let file = File::open(path.clone()) - .map_err(|why| format!("Couldn't open input file {}: {}", path.display(), why))?; + .map_err(|why| format!("Could not open {}: {}", path.display(), why))?; let mut reader = BufReader::new(file); let mut source = String::new(); @@ -92,9 +105,9 @@ fn cli_compile(sub_matches: &ArgMatches) -> Result<(), String> { let fmt_error = |e: &CompileError| { let file = e.file().canonicalize().unwrap(); format!( - "{}:{}", + "{}: {}", file.strip_prefix(std::env::current_dir().unwrap()) - .unwrap_or(file.as_path()) + .unwrap_or_else(|_| file.as_path()) .display(), e.value() ) @@ -132,7 +145,7 @@ fn cli_compile(sub_matches: &ArgMatches) -> Result<(), String> { // serialize flattened program and write to binary file let bin_output_file = File::create(&bin_output_path) - .map_err(|why| format!("Couldn't create {}: {}", bin_output_path.display(), why))?; + .map_err(|why| format!("Could not create {}: {}", bin_output_path.display(), why))?; let mut writer = BufWriter::new(bin_output_file); @@ -140,35 +153,32 @@ fn cli_compile(sub_matches: &ArgMatches) -> Result<(), String> { // serialize ABI spec and write to JSON file let abi_spec_file = File::create(&abi_spec_path) - .map_err(|why| format!("Couldn't create {}: {}", abi_spec_path.display(), why))?; + .map_err(|why| format!("Could not create {}: {}", abi_spec_path.display(), why))?; let abi = artifacts.abi(); let mut writer = BufWriter::new(abi_spec_file); - to_writer_pretty(&mut writer, &abi).map_err(|_| "Unable to write data to file.".to_string())?; - if !light { + if sub_matches.is_present("verbose") { + // debugging output + println!("Compiled program:\n{}", program_flattened); + } + + println!("Compiled code written to '{}'", bin_output_path.display()); + + if sub_matches.is_present("ztf") { // write human-readable output file let hr_output_file = File::create(&hr_output_path) - .map_err(|why| format!("Couldn't create {}: {}", hr_output_path.display(), why))?; + .map_err(|why| format!("Could not create {}: {}", hr_output_path.display(), why))?; let mut hrofb = BufWriter::new(hr_output_file); - write!(&mut hrofb, "{}\n", program_flattened) + writeln!(&mut hrofb, "{}", program_flattened) .map_err(|_| "Unable to write data to file".to_string())?; hrofb .flush() .map_err(|_| "Unable to flush buffer".to_string())?; - } - - if !light { - // debugging output - println!("Compiled program:\n{}", program_flattened); - } - - println!("Compiled code written to '{}'", bin_output_path.display()); - if !light { println!("Human readable code to '{}'", hr_output_path.display()); } diff --git a/zokrates_cli/src/ops/compute_witness.rs b/zokrates_cli/src/ops/compute_witness.rs index f1657f2d2..9da9eb383 100644 --- a/zokrates_cli/src/ops/compute_witness.rs +++ b/zokrates_cli/src/ops/compute_witness.rs @@ -8,7 +8,7 @@ use zokrates_abi::Encode; use zokrates_core::ir; use zokrates_core::ir::ProgEnum; use zokrates_core::typed_absy::abi::Abi; -use zokrates_core::typed_absy::{Signature, Type}; +use zokrates_core::typed_absy::types::{ConcreteSignature, ConcreteType}; use zokrates_field::Field; pub fn subcommand() -> App<'static, 'static> { @@ -22,9 +22,9 @@ pub fn subcommand() -> App<'static, 'static> { .takes_value(true) .required(false) .default_value(FLATTENED_CODE_DEFAULT_PATH) - ).arg(Arg::with_name("abi_spec") + ).arg(Arg::with_name("abi-spec") .short("s") - .long("abi_spec") + .long("abi-spec") .help("Path of the ABI specification") .value_name("FILE") .takes_value(true) @@ -57,10 +57,6 @@ pub fn subcommand() -> App<'static, 'static> { .help("Read arguments from stdin") .conflicts_with("arguments") .required(false) - ).arg(Arg::with_name("light") - .long("light") - .help("Skip logging the human-readable program") - .required(false) ) } @@ -68,7 +64,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!("Couldn't open {}: {}", path.display(), why))?; + File::open(&path).map_err(|why| format!("Could not open {}: {}", path.display(), why))?; let mut reader = BufReader::new(file); @@ -83,8 +79,10 @@ pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> { fn cli_compute(ir_prog: ir::Prog, sub_matches: &ArgMatches) -> Result<(), String> { println!("Computing witness..."); - // print deserialized flattened program - if !sub_matches.is_present("light") { + let verbose = sub_matches.is_present("verbose"); + + // print deserialized flattened program if in verbose mode + if verbose { println!("{}", ir_prog); } @@ -97,18 +95,21 @@ fn cli_compute(ir_prog: ir::Prog, sub_matches: &ArgMatches) -> Resu let signature = match is_abi { true => { - let path = Path::new(sub_matches.value_of("abi_spec").unwrap()); + let path = Path::new(sub_matches.value_of("abi-spec").unwrap()); let file = File::open(&path) - .map_err(|why| format!("couldn't open {}: {}", path.display(), why))?; + .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())?; abi.signature() } - false => Signature::new() - .inputs(vec![Type::FieldElement; ir_prog.main.arguments.len()]) - .outputs(vec![Type::FieldElement; ir_prog.main.returns.len()]), + false => ConcreteSignature::new() + .inputs(vec![ + ConcreteType::FieldElement; + ir_prog.main.arguments.len() + ]) + .outputs(vec![ConcreteType::FieldElement; ir_prog.main.returns.len()]), }; use zokrates_abi::Inputs; @@ -123,8 +124,8 @@ fn cli_compute(ir_prog: ir::Prog, sub_matches: &ArgMatches) -> Resu a.map(|x| T::try_from_dec_str(x).map_err(|_| x.to_string())) .collect::, _>>() }) - .unwrap_or(Ok(vec![])) - .map(|v| Inputs::Raw(v)) + .unwrap_or_else(|| Ok(vec![])) + .map(Inputs::Raw) } // take stdin arguments true => { @@ -137,7 +138,7 @@ fn cli_compute(ir_prog: ir::Prog, sub_matches: &ArgMatches) -> Resu use zokrates_abi::parse_strict; parse_strict(&input, signature.inputs) - .map(|parsed| Inputs::Abi(parsed)) + .map(Inputs::Abi) .map_err(|why| why.to_string()) } Err(_) => Err(String::from("???")), @@ -148,10 +149,10 @@ fn cli_compute(ir_prog: ir::Prog, sub_matches: &ArgMatches) -> Resu Ok(_) => { input.retain(|x| x != '\n'); input - .split(" ") + .split(' ') .map(|x| T::try_from_dec_str(x).map_err(|_| x.to_string())) .collect::, _>>() - .map(|v| Inputs::Raw(v)) + .map(Inputs::Raw) } Err(_) => Err(String::from("???")), }, @@ -170,20 +171,24 @@ fn cli_compute(ir_prog: ir::Prog, sub_matches: &ArgMatches) -> Resu use zokrates_abi::Decode; let results_json_value: serde_json::Value = - zokrates_abi::CheckedValues::decode(witness.return_values(), signature.outputs).into(); + zokrates_abi::CheckedValues::decode(witness.return_values(), signature.outputs) + .into_serde_json(); - println!("\nWitness: \n\n{}", results_json_value); + if verbose { + println!("\nWitness: \n{}\n", results_json_value); + } // write witness to file let output_path = Path::new(sub_matches.value_of("output").unwrap()); let output_file = File::create(&output_path) - .map_err(|why| format!("couldn't create {}: {}", output_path.display(), why))?; + .map_err(|why| format!("Could not create {}: {}", output_path.display(), why))?; let writer = BufWriter::new(output_file); witness .write(writer) - .map_err(|why| format!("could not save witness: {:?}", why))?; + .map_err(|why| format!("Could not save witness: {:?}", why))?; + println!("Witness file written to '{}'", output_path.display()); Ok(()) } diff --git a/zokrates_cli/src/ops/export_verifier.rs b/zokrates_cli/src/ops/export_verifier.rs index b4658c626..d19afdec6 100644 --- a/zokrates_cli/src/ops/export_verifier.rs +++ b/zokrates_cli/src/ops/export_verifier.rs @@ -93,11 +93,11 @@ fn cli_export_verifier App<'static, 'static> { pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> { let program_path = Path::new(sub_matches.value_of("input").unwrap()); let program_file = File::open(&program_path) - .map_err(|why| format!("Couldn't open {}: {}", program_path.display(), why))?; + .map_err(|why| format!("Could not open {}: {}", program_path.display(), why))?; let mut reader = BufReader::new(program_file); let prog = ProgEnum::deserialize(&mut reader)?; @@ -148,7 +148,7 @@ fn cli_generate_proof, B: Backend>( let witness_path = Path::new(sub_matches.value_of("witness").unwrap()); let witness_file = match File::open(&witness_path) { Ok(file) => file, - Err(why) => panic!("Couldn't open {}: {}", witness_path.display(), why), + Err(why) => panic!("Could not open {}: {}", witness_path.display(), why), }; let witness = ir::Witness::read(witness_file) @@ -158,13 +158,13 @@ fn cli_generate_proof, B: Backend>( let proof_path = Path::new(sub_matches.value_of("proof-path").unwrap()); let pk_file = File::open(&pk_path) - .map_err(|why| format!("Couldn't open {}: {}", pk_path.display(), why))?; + .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!("Couldn't read {}: {}", pk_path.display(), why))?; + .map_err(|why| format!("Could not read {}: {}", pk_path.display(), why))?; let proof = B::generate_proof(program, witness, pk); let mut proof_file = File::create(proof_path).unwrap(); @@ -172,9 +172,12 @@ fn cli_generate_proof, B: Backend>( let proof = serde_json::to_string_pretty(&proof).unwrap(); proof_file .write(proof.as_bytes()) - .map_err(|why| format!("Couldn't write to {}: {}", proof_path.display(), why))?; + .map_err(|why| format!("Could not write to {}: {}", proof_path.display(), why))?; - println!("Proof:\n{}", format!("{}", proof)); + if sub_matches.is_present("verbose") { + println!("Proof:\n{}", proof); + } + println!("Proof written to '{}'", proof_path.display()); Ok(()) } diff --git a/zokrates_cli/src/ops/mod.rs b/zokrates_cli/src/ops/mod.rs index bb1748c85..22c53a38f 100644 --- a/zokrates_cli/src/ops/mod.rs +++ b/zokrates_cli/src/ops/mod.rs @@ -1,7 +1,6 @@ pub mod check; pub mod compile; pub mod compute_witness; -#[cfg(any(feature = "bellman", feature = "ark", feature = "libsnark"))] pub mod export_verifier; #[cfg(any(feature = "bellman", feature = "ark", feature = "libsnark"))] pub mod generate_proof; diff --git a/zokrates_cli/src/ops/setup.rs b/zokrates_cli/src/ops/setup.rs index d52f514f5..455d8fb18 100644 --- a/zokrates_cli/src/ops/setup.rs +++ b/zokrates_cli/src/ops/setup.rs @@ -70,12 +70,6 @@ pub fn subcommand() -> App<'static, 'static> { .possible_values(constants::SCHEMES) .default_value(constants::G16), ) - .arg( - Arg::with_name("light") - .long("light") - .help("Skip logging the human-readable program and writing it to a file") - .required(false), - ) } pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> { @@ -136,8 +130,8 @@ fn cli_setup, B: Backend>( ) -> Result<(), String> { println!("Performing setup..."); - // print deserialized flattened program - if !sub_matches.is_present("light") { + // print deserialized flattened program if in verbose mode + if sub_matches.is_present("verbose") { println!("{}", program); } @@ -150,23 +144,26 @@ fn cli_setup, B: Backend>( // write verification key let mut vk_file = File::create(vk_path) - .map_err(|why| format!("couldn't create {}: {}", vk_path.display(), why))?; + .map_err(|why| format!("Could not create {}: {}", vk_path.display(), why))?; vk_file .write_all( serde_json::to_string_pretty(&keypair.vk) .unwrap() .as_bytes(), ) - .map_err(|why| format!("couldn't write to {}: {}", vk_path.display(), why))?; + .map_err(|why| format!("Could not write to {}: {}", vk_path.display(), why))?; + + println!("Verification key written to '{}'", vk_path.display()); // write proving key let mut pk_file = File::create(pk_path) - .map_err(|why| format!("couldn't create {}: {}", pk_path.display(), why))?; + .map_err(|why| format!("Could not create {}: {}", pk_path.display(), why))?; pk_file .write_all(keypair.pk.as_ref()) - .map_err(|why| format!("couldn't write to {}: {}", pk_path.display(), why))?; + .map_err(|why| format!("Could not write to {}: {}", pk_path.display(), why))?; - println!("Setup completed."); + println!("Proving key written to '{}'", pk_path.display()); + println!("Setup completed"); Ok(()) } diff --git a/zokrates_cli/src/ops/verify.rs b/zokrates_cli/src/ops/verify.rs index aefd51b9e..febddc6c1 100644 --- a/zokrates_cli/src/ops/verify.rs +++ b/zokrates_cli/src/ops/verify.rs @@ -106,26 +106,26 @@ fn cli_verify, B: Backend>( ) -> Result<(), String> { let vk_path = Path::new(sub_matches.value_of("verification-key-path").unwrap()); let vk_file = File::open(&vk_path) - .map_err(|why| format!("Couldn't open {}: {}", vk_path.display(), why))?; + .map_err(|why| format!("Could not open {}: {}", vk_path.display(), why))?; let vk_reader = BufReader::new(vk_file); let vk = serde_json::from_reader(vk_reader) - .map_err(|why| format!("Couldn't deserialize verification key: {}", why))?; + .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) - .map_err(|why| format!("Couldn't open {}: {}", proof_path.display(), why))?; + .map_err(|why| format!("Could not open {}: {}", proof_path.display(), why))?; let proof_reader = BufReader::new(proof_file); let proof = serde_json::from_reader(proof_reader) - .map_err(|why| format!("Couldn't deserialize proof: {}", why))?; + .map_err(|why| format!("Could not deserialize proof: {}", why))?; println!("Performing verification..."); println!( - "The verification result is: {}", + "{}", match B::verify(vk, proof) { - true => "PASS", - false => "FAIL", + true => "PASSED", + false => "FAILED", } ); diff --git a/zokrates_cli/tests/code/n_choose_k.zok b/zokrates_cli/tests/code/n_choose_k.zok index a7a34d943..b5e820d72 100644 --- a/zokrates_cli/tests/code/n_choose_k.zok +++ b/zokrates_cli/tests/code/n_choose_k.zok @@ -1,9 +1,11 @@ +import "utils/casts/u32_to_field" as to_field + // Binomial Coeffizient, n!/(k!*(n-k)!). def fac(field x) -> field: field f = 1 field counter = 0 - for field i in 1..100 do - f = if counter == x then f else f * i fi + for u32 i in 1..100 do + f = if counter == x then f else f * to_field(i) fi counter = if counter == x then counter else counter + 1 fi endfor return f diff --git a/zokrates_cli/tests/integration.rs b/zokrates_cli/tests/integration.rs index b147d3da9..77cf2d39a 100644 --- a/zokrates_cli/tests/integration.rs +++ b/zokrates_cli/tests/integration.rs @@ -3,7 +3,7 @@ extern crate serde_json; #[cfg(test)] mod integration { - use assert_cli; + use serde_json::from_reader; use std::fs; use std::fs::File; @@ -105,7 +105,6 @@ mod integration { abi_spec_path.to_str().unwrap(), "-o", flattened_path.to_str().unwrap(), - "--light", ]; // compile @@ -138,7 +137,7 @@ mod integration { // First we need to convert our test input into raw field elements. We need to ABI spec for that let file = File::open(&abi_spec_path) - .map_err(|why| format!("couldn't open {}: {}", flattened_path.display(), why)) + .map_err(|why| format!("Could not open {}: {}", flattened_path.display(), why)) .unwrap(); let mut reader = BufReader::new(file); @@ -147,11 +146,11 @@ mod integration { .map_err(|why| why.to_string()) .unwrap(); - let signature = abi.signature().clone(); + let signature = abi.signature(); let inputs_abi: zokrates_abi::Inputs = parse_strict(&json_input_str, signature.inputs) - .map(|parsed| zokrates_abi::Inputs::Abi(parsed)) + .map(zokrates_abi::Inputs::Abi) .map_err(|why| why.to_string()) .unwrap(); let inputs_raw: Vec<_> = inputs_abi @@ -169,7 +168,7 @@ mod integration { inline_witness_path.to_str().unwrap(), ]; - if inputs_raw.len() > 0 { + if !inputs_raw.is_empty() { compute_inline.push("-a"); for arg in &inputs_raw { @@ -202,7 +201,7 @@ mod integration { assert_eq!(inline_witness, witness); - for line in expected_witness.as_str().split("\n") { + for line in expected_witness.as_str().split('\n') { assert!( witness.contains(line), "Witness generation failed for {}\n\nLine \"{}\" not found in witness", diff --git a/zokrates_core/Cargo.toml b/zokrates_core/Cargo.toml index 51dd5aed6..cbff9f5a6 100644 --- a/zokrates_core/Cargo.toml +++ b/zokrates_core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zokrates_core" -version = "0.5.4" +version = "0.6.0" edition = "2018" authors = ["Jacob Eberhardt ", "Dennis Kuhnert "] repository = "https://github.com/JacobEberhardt/ZoKrates" @@ -28,10 +28,10 @@ serde_json = "1.0" bincode = "0.8.0" hex = "0.4.2" regex = "0.2" -zokrates_field = { version = "0.3.0", path = "../zokrates_field", default-features = false } -zokrates_pest_ast = { version = "0.1.0", path = "../zokrates_pest_ast" } +zokrates_field = { version = "0.4.0", path = "../zokrates_field", default-features = false } +zokrates_pest_ast = { version = "0.2.0", path = "../zokrates_pest_ast" } zokrates_common = { path = "../zokrates_common" } -zokrates_embed = { path = "../zokrates_embed" } +zokrates_embed = { version = "0.1.0", path = "../zokrates_embed" } getrandom = { version = "0.2", features = ["js"] } rand_0_4 = { version = "0.4", package = "rand" } rand_0_7 = { version = "0.7", package = "rand" } @@ -43,14 +43,14 @@ pairing_ce = { version = "^0.21", optional = true } ff_ce = { version = "^0.9", optional = true } # ark -ark-ff = { git = "https://github.com/arkworks-rs/algebra", default-features = false, optional = true } -ark-ec = { git = "https://github.com/arkworks-rs/algebra", default-features = false, optional = true } -ark-bn254 = { git = "https://github.com/arkworks-rs/curves", features = ["curve"], default-features = false, optional = true } -ark-bls12-377 = { git = "https://github.com/arkworks-rs/curves", features = ["curve"], default-features = false, optional = true } -ark-bw6-761 = { git = "https://github.com/arkworks-rs/curves", default-features = false, optional = true } -ark-gm17 = { git = "https://github.com/arkworks-rs/gm17", default-features = false, optional = true } -ark-serialize = { git = "https://github.com/arkworks-rs/algebra", default-features = false, optional = true } -ark-relations = { git = "https://github.com/arkworks-rs/snark", default-features = false, optional = true } +ark-ff = { version = "^0.2.0", default-features = false, optional = true } +ark-ec = { version = "^0.2.0", default-features = false, optional = true } +ark-bn254 = { version = "^0.2.0", features = ["curve"], default-features = false, optional = true } +ark-bls12-377 = { version = "^0.2.0", features = ["curve"], default-features = false, optional = true } +ark-bw6-761 = { version = "^0.2.0", default-features = false, optional = true } +ark-gm17 = { version = "^0.2.0", default-features = false, optional = true } +ark-serialize = { version = "^0.2.0", default-features = false, optional = true } +ark-relations = { version = "^0.2.0", default-features = false, optional = true } [dev-dependencies] wasm-bindgen-test = "^0.3.0" diff --git a/zokrates_core/src/absy/from_ast.rs b/zokrates_core/src/absy/from_ast.rs index 5fbed6643..ccf3a55ba 100644 --- a/zokrates_core/src/absy/from_ast.rs +++ b/zokrates_core/src/absy/from_ast.rs @@ -1,7 +1,6 @@ use crate::absy; use crate::imports; -use num::ToPrimitive; use num_bigint::BigUint; use zokrates_pest_ast as pest; @@ -10,14 +9,14 @@ impl<'ast> From> for absy::Module<'ast> { absy::Module::with_symbols( prog.structs .into_iter() - .map(|t| absy::SymbolDeclarationNode::from(t)) + .map(absy::SymbolDeclarationNode::from) .chain( prog.functions .into_iter() - .map(|f| absy::SymbolDeclarationNode::from(f)), + .map(absy::SymbolDeclarationNode::from), ), ) - .imports(prog.imports.into_iter().map(|i| absy::ImportNode::from(i))) + .imports(prog.imports.into_iter().map(absy::ImportNode::from)) } } @@ -31,17 +30,16 @@ impl<'ast> From> for absy::ImportNode<'ast> { .alias(import.alias.map(|a| a.span.as_str())) .span(import.span) } - pest::ImportDirective::From(import) => imports::Import::new( - Some(import.symbol.span.as_str()), - std::path::Path::new(import.source.span.as_str()), - ) - .alias( - import - .alias - .map(|a| a.span.as_str()) - .or(Some(import.symbol.span.as_str())), - ) - .span(import.span), + pest::ImportDirective::From(import) => { + let symbol_str = import.symbol.span.as_str(); + + imports::Import::new( + Some(import.symbol.span.as_str()), + std::path::Path::new(import.source.span.as_str()), + ) + .alias(import.alias.map(|a| a.span.as_str()).or(Some(symbol_str))) + .span(import.span) + } } } } @@ -58,7 +56,7 @@ impl<'ast> From> for absy::SymbolDeclarationNode<'a fields: definition .fields .into_iter() - .map(|f| absy::StructDefinitionFieldNode::from(f)) + .map(absy::StructDefinitionFieldNode::from) .collect(), } .span(span.clone()); @@ -72,7 +70,7 @@ impl<'ast> From> for absy::SymbolDeclarationNode<'a } impl<'ast> From> for absy::StructDefinitionFieldNode<'ast> { - fn from(field: pest::StructField<'ast>) -> absy::StructDefinitionFieldNode { + fn from(field: pest::StructField<'ast>) -> absy::StructDefinitionFieldNode<'ast> { use crate::absy::NodeValue; let span = field.span; @@ -92,6 +90,13 @@ impl<'ast> From> for absy::SymbolDeclarationNode<'ast> { let span = function.span; let signature = absy::UnresolvedSignature::new() + .generics( + function + .generics + .into_iter() + .map(absy::ConstantGenericNode::from) + .collect(), + ) .inputs( function .parameters @@ -105,7 +110,7 @@ impl<'ast> From> for absy::SymbolDeclarationNode<'ast> { .returns .clone() .into_iter() - .map(|r| absy::UnresolvedTypeNode::from(r)) + .map(absy::UnresolvedTypeNode::from) .collect(), ); @@ -115,12 +120,12 @@ impl<'ast> From> for absy::SymbolDeclarationNode<'ast> { arguments: function .parameters .into_iter() - .map(|a| absy::ParameterNode::from(a)) + .map(absy::ParameterNode::from) .collect(), statements: function .statements .into_iter() - .flat_map(|s| statements_from_statement(s)) + .flat_map(statements_from_statement) .collect(), signature, } @@ -134,6 +139,16 @@ impl<'ast> From> for absy::SymbolDeclarationNode<'ast> { } } +impl<'ast> From> for absy::ConstantGenericNode<'ast> { + fn from(g: pest::IdentifierExpression<'ast>) -> absy::ConstantGenericNode<'ast> { + use absy::NodeValue; + + let name = g.span.as_str(); + + name.span(g.span) + } +} + impl<'ast> From> for absy::ParameterNode<'ast> { fn from(param: pest::Parameter<'ast>) -> absy::ParameterNode<'ast> { use crate::absy::NodeValue; @@ -247,7 +262,7 @@ impl<'ast> From> for absy::StatementNode<'ast> { expressions: statement .expressions .into_iter() - .map(|e| absy::ExpressionNode::from(e)) + .map(absy::ExpressionNode::from) .collect(), } .span(statement.span.clone()), @@ -275,7 +290,7 @@ impl<'ast> From> for absy::StatementNode<'ast> { let statements: Vec> = statement .statements .into_iter() - .flat_map(|s| statements_from_statement(s)) + .flat_map(statements_from_statement) .collect(); let var = absy::Variable::new(index, ty).span(statement.index.span); @@ -289,7 +304,7 @@ impl<'ast> From> for absy::ExpressionNode<'ast> { match expression { pest::Expression::Binary(e) => absy::ExpressionNode::from(e), pest::Expression::Ternary(e) => absy::ExpressionNode::from(e), - pest::Expression::Constant(e) => absy::ExpressionNode::from(e), + pest::Expression::Literal(e) => absy::ExpressionNode::from(e), pest::Expression::Identifier(e) => absy::ExpressionNode::from(e), pest::Expression::Postfix(e) => absy::ExpressionNode::from(e), pest::Expression::InlineArray(e) => absy::ExpressionNode::from(e), @@ -458,7 +473,7 @@ impl<'ast> From> for absy::ExpressionNode<'ast array .expressions .into_iter() - .map(|e| absy::SpreadOrExpression::from(e)) + .map(absy::SpreadOrExpression::from) .collect(), ) .span(array.span) @@ -489,13 +504,8 @@ impl<'ast> From> for absy::ExpressionNode use crate::absy::NodeValue; let value = absy::ExpressionNode::from(*initializer.value); - let count: absy::ExpressionNode<'ast> = absy::ExpressionNode::from(initializer.count); - let count = match count.value { - absy::Expression::FieldConstant(v) => v.to_usize().unwrap(), - _ => unreachable!(), - }; - absy::Expression::InlineArray(vec![absy::SpreadOrExpression::Expression(value); count]) - .span(initializer.span) + let count = absy::ExpressionNode::from(*initializer.count); + absy::Expression::ArrayInitializer(box value, box count).span(initializer.span) } } @@ -503,10 +513,12 @@ impl<'ast> From> for absy::ExpressionNode<'ast> { fn from(unary: pest::UnaryExpression<'ast>) -> absy::ExpressionNode<'ast> { use crate::absy::NodeValue; + let expression = Box::new(absy::ExpressionNode::from(*unary.expression)); + match unary.op { - pest::UnaryOperator::Not(_) => { - absy::Expression::Not(Box::new(absy::ExpressionNode::from(*unary.expression))) - } + pest::UnaryOperator::Not(..) => absy::Expression::Not(expression), + pest::UnaryOperator::Neg(..) => absy::Expression::Neg(expression), + pest::UnaryOperator::Pos(..) => absy::Expression::Pos(expression), } .span(unary.span) } @@ -527,9 +539,25 @@ impl<'ast> From> for absy::ExpressionNode<'ast> { pest::Access::Call(a) => match acc.value { absy::Expression::Identifier(_) => absy::Expression::FunctionCall( &id_str, - a.expressions + a.explicit_generics.map(|explicit_generics| { + explicit_generics + .values + .into_iter() + .map(|i| match i { + pest::ConstantGenericValue::Underscore(_) => None, + pest::ConstantGenericValue::Value(v) => { + Some(absy::ExpressionNode::from(v)) + } + pest::ConstantGenericValue::Identifier(i) => { + Some(absy::Expression::Identifier(i.span.as_str()).span(i.span)) + } + }) + .collect() + }), + a.arguments + .expressions .into_iter() - .map(|e| absy::ExpressionNode::from(e)) + .map(absy::ExpressionNode::from) .collect(), ), e => unimplemented!("only identifiers are callable, found \"{}\"", e), @@ -546,29 +574,69 @@ impl<'ast> From> for absy::ExpressionNode<'ast> { } } -impl<'ast> From> for absy::ExpressionNode<'ast> { - fn from(expression: pest::ConstantExpression<'ast>) -> absy::ExpressionNode<'ast> { +impl<'ast> From> for absy::ExpressionNode<'ast> { + fn from(expression: pest::DecimalLiteralExpression<'ast>) -> absy::ExpressionNode<'ast> { + use crate::absy::NodeValue; + + match expression.suffix { + Some(suffix) => match suffix { + pest::DecimalSuffix::Field(_) => absy::Expression::FieldConstant( + BigUint::parse_bytes(&expression.value.span.as_str().as_bytes(), 10).unwrap(), + ), + pest::DecimalSuffix::U64(_) => { + absy::Expression::U64Constant(expression.value.span.as_str().parse().unwrap()) + } + pest::DecimalSuffix::U32(_) => { + absy::Expression::U32Constant(expression.value.span.as_str().parse().unwrap()) + } + pest::DecimalSuffix::U16(_) => { + absy::Expression::U16Constant(expression.value.span.as_str().parse().unwrap()) + } + pest::DecimalSuffix::U8(_) => { + absy::Expression::U8Constant(expression.value.span.as_str().parse().unwrap()) + } + } + .span(expression.span), + None => absy::Expression::IntConstant( + BigUint::parse_bytes(&expression.value.span.as_str().as_bytes(), 10).unwrap(), + ) + .span(expression.span), + } + } +} + +impl<'ast> From> for absy::ExpressionNode<'ast> { + fn from(expression: pest::HexLiteralExpression<'ast>) -> absy::ExpressionNode<'ast> { use crate::absy::NodeValue; + + match expression.value { + pest::HexNumberExpression::U64(e) => { + absy::Expression::U64Constant(u64::from_str_radix(&e.span.as_str(), 16).unwrap()) + } + pest::HexNumberExpression::U32(e) => { + absy::Expression::U32Constant(u32::from_str_radix(&e.span.as_str(), 16).unwrap()) + } + pest::HexNumberExpression::U16(e) => { + absy::Expression::U16Constant(u16::from_str_radix(&e.span.as_str(), 16).unwrap()) + } + pest::HexNumberExpression::U8(e) => { + absy::Expression::U8Constant(u8::from_str_radix(&e.span.as_str(), 16).unwrap()) + } + } + .span(expression.span) + } +} + +impl<'ast> From> for absy::ExpressionNode<'ast> { + fn from(expression: pest::LiteralExpression<'ast>) -> absy::ExpressionNode<'ast> { + use crate::absy::NodeValue; + match expression { - pest::ConstantExpression::BooleanLiteral(c) => { + pest::LiteralExpression::BooleanLiteral(c) => { absy::Expression::BooleanConstant(c.value.parse().unwrap()).span(c.span) } - pest::ConstantExpression::DecimalNumber(n) => absy::Expression::FieldConstant( - BigUint::parse_bytes(&n.value.as_bytes(), 10).unwrap(), - ) - .span(n.span), - pest::ConstantExpression::U8(n) => absy::Expression::U8Constant( - u8::from_str_radix(&n.value.trim_start_matches("0x"), 16).unwrap(), - ) - .span(n.span), - pest::ConstantExpression::U16(n) => absy::Expression::U16Constant( - u16::from_str_radix(&n.value.trim_start_matches("0x"), 16).unwrap(), - ) - .span(n.span), - pest::ConstantExpression::U32(n) => absy::Expression::U32Constant( - u32::from_str_radix(&n.value.trim_start_matches("0x"), 16).unwrap(), - ) - .span(n.span), + pest::LiteralExpression::DecimalLiteral(n) => absy::ExpressionNode::from(n), + pest::LiteralExpression::HexLiteral(n) => absy::ExpressionNode::from(n), } } } @@ -609,8 +677,8 @@ impl<'ast> From> for absy::AssigneeNode<'ast> { } } -impl<'ast> From> for absy::UnresolvedTypeNode { - fn from(t: pest::Type<'ast>) -> absy::UnresolvedTypeNode { +impl<'ast> From> for absy::UnresolvedTypeNode<'ast> { + fn from(t: pest::Type<'ast>) -> absy::UnresolvedTypeNode<'ast> { use crate::absy::types::UnresolvedType; use crate::absy::NodeValue; @@ -621,6 +689,7 @@ impl<'ast> From> for absy::UnresolvedTypeNode { pest::BasicType::U8(t) => UnresolvedType::Uint(8).span(t.span), pest::BasicType::U16(t) => UnresolvedType::Uint(16).span(t.span), pest::BasicType::U32(t) => UnresolvedType::Uint(32).span(t.span), + pest::BasicType::U64(t) => UnresolvedType::Uint(64).span(t.span), }, pest::Type::Array(t) => { let inner_type = match t.ty { @@ -630,6 +699,7 @@ impl<'ast> From> for absy::UnresolvedTypeNode { pest::BasicType::U8(t) => UnresolvedType::Uint(8).span(t.span), pest::BasicType::U16(t) => UnresolvedType::Uint(16).span(t.span), pest::BasicType::U32(t) => UnresolvedType::Uint(32).span(t.span), + pest::BasicType::U64(t) => UnresolvedType::Uint(64).span(t.span), }, pest::BasicOrStructType::Struct(t) => { UnresolvedType::User(t.span.as_str().to_string()).span(t.span) @@ -640,21 +710,7 @@ impl<'ast> From> for absy::UnresolvedTypeNode { t.dimensions .into_iter() - .map(|s| match s { - pest::Expression::Constant(c) => match c { - pest::ConstantExpression::DecimalNumber(n) => { - str::parse::(&n.value).unwrap() - } - _ => unimplemented!( - "Array size should be a decimal number, found {}", - c.span().as_str() - ), - }, - e => unimplemented!( - "Array size should be constant, found {}", - e.span().as_str() - ), - }) + .map(absy::ExpressionNode::from) .rev() .fold(None, |acc, s| match acc { None => Some(UnresolvedType::array(inner_type.clone(), s)), @@ -688,10 +744,9 @@ mod tests { arguments: vec![], statements: vec![absy::Statement::Return( absy::ExpressionList { - expressions: vec![absy::Expression::FieldConstant(BigUint::from( - 42u32, - )) - .into()], + expressions: vec![ + absy::Expression::IntConstant(42usize.into()).into() + ], } .into(), ) @@ -769,10 +824,9 @@ mod tests { ], statements: vec![absy::Statement::Return( absy::ExpressionList { - expressions: vec![absy::Expression::FieldConstant(BigUint::from( - 42u32, - )) - .into()], + expressions: vec![ + absy::Expression::IntConstant(42usize.into()).into() + ], } .into(), ) @@ -798,7 +852,7 @@ mod tests { use super::*; /// Helper method to generate the ast for `def main(private {ty} a): return` which we use to check ty - fn wrap(ty: UnresolvedType) -> absy::Module<'static> { + fn wrap(ty: UnresolvedType<'static>) -> absy::Module<'static> { absy::Module { symbols: vec![absy::SymbolDeclaration { id: "main", @@ -832,21 +886,31 @@ mod tests { ("bool", UnresolvedType::Boolean), ( "field[2]", - UnresolvedType::Array(box UnresolvedType::FieldElement.mock(), 2), + absy::UnresolvedType::Array( + box absy::UnresolvedType::FieldElement.mock(), + absy::Expression::IntConstant(2usize.into()).mock(), + ), ), ( "field[2][3]", - UnresolvedType::Array( - box UnresolvedType::Array(box UnresolvedType::FieldElement.mock(), 3) - .mock(), - 2, + absy::UnresolvedType::Array( + box absy::UnresolvedType::Array( + box absy::UnresolvedType::FieldElement.mock(), + absy::Expression::IntConstant(3usize.into()).mock(), + ) + .mock(), + absy::Expression::IntConstant(2usize.into()).mock(), ), ), ( - "bool[2][3]", - UnresolvedType::Array( - box UnresolvedType::Array(box UnresolvedType::Boolean.mock(), 3).mock(), - 2, + "bool[2][3u32]", + absy::UnresolvedType::Array( + box absy::UnresolvedType::Array( + box absy::UnresolvedType::Boolean.mock(), + absy::Expression::U32Constant(3u32).mock(), + ) + .mock(), + absy::Expression::IntConstant(2usize.into()).mock(), ), ), ]; @@ -891,15 +955,14 @@ mod tests { // we basically accept `()?[]*` : an optional call at first, then only array accesses let vectors = vec![ - ("a", absy::Expression::Identifier("a").into()), + ("a", absy::Expression::Identifier("a")), ( "a[3]", absy::Expression::Select( box absy::Expression::Identifier("a").into(), box absy::RangeOrExpression::Expression( - absy::Expression::FieldConstant(BigUint::from(3u32)).into(), - ) - .into(), + absy::Expression::IntConstant(3usize.into()).into(), + ), ), ), ( @@ -908,15 +971,13 @@ mod tests { box absy::Expression::Select( box absy::Expression::Identifier("a").into(), box absy::RangeOrExpression::Expression( - absy::Expression::FieldConstant(BigUint::from(3u32)).into(), - ) - .into(), + absy::Expression::IntConstant(3usize.into()).into(), + ), ) .into(), box absy::RangeOrExpression::Expression( - absy::Expression::FieldConstant(BigUint::from(4u32)).into(), - ) - .into(), + absy::Expression::IntConstant(4usize.into()).into(), + ), ), ), ( @@ -924,13 +985,13 @@ mod tests { absy::Expression::Select( box absy::Expression::FunctionCall( "a", - vec![absy::Expression::FieldConstant(BigUint::from(3u32)).into()], + None, + vec![absy::Expression::IntConstant(3usize.into()).into()], ) .into(), box absy::RangeOrExpression::Expression( - absy::Expression::FieldConstant(BigUint::from(4u32)).into(), - ) - .into(), + absy::Expression::IntConstant(4usize.into()).into(), + ), ), ), ( @@ -939,19 +1000,18 @@ mod tests { box absy::Expression::Select( box absy::Expression::FunctionCall( "a", - vec![absy::Expression::FieldConstant(BigUint::from(3u32)).into()], + None, + vec![absy::Expression::IntConstant(3usize.into()).into()], ) .into(), box absy::RangeOrExpression::Expression( - absy::Expression::FieldConstant(BigUint::from(4u32)).into(), - ) - .into(), + absy::Expression::IntConstant(4usize.into()).into(), + ), ) .into(), box absy::RangeOrExpression::Expression( - absy::Expression::FieldConstant(BigUint::from(5u32)).into(), - ) - .into(), + absy::Expression::IntConstant(5usize.into()).into(), + ), ), ), ]; @@ -991,7 +1051,7 @@ mod tests { // For different definitions, we generate declarations // Case 1: `id = expr` where `expr` is not a function call // This is a simple assignment, doesn't implicitely declare a variable - // A `Definition` is generatedm and no `Declaration`s + // A `Definition` is generated and no `Declaration`s let definition = pest::DefinitionStatement { lhs: vec![pest::OptionallyTypedAssignee { @@ -1006,9 +1066,12 @@ mod tests { }, span: span.clone(), }], - expression: pest::Expression::Constant(pest::ConstantExpression::DecimalNumber( - pest::DecimalNumberExpression { - value: String::from("42"), + expression: pest::Expression::Literal(pest::LiteralExpression::DecimalLiteral( + pest::DecimalLiteralExpression { + value: pest::DecimalNumber { + span: Span::new(&"1", 0, 1).unwrap(), + }, + suffix: None, span: span.clone(), }, )), @@ -1047,7 +1110,11 @@ mod tests { span: span.clone(), }, accesses: vec![pest::Access::Call(pest::CallAccess { - expressions: vec![], + explicit_generics: None, + arguments: pest::Arguments { + expressions: vec![], + span: span.clone(), + }, span: span.clone(), })], span: span.clone(), @@ -1104,7 +1171,11 @@ mod tests { span: span.clone(), }, accesses: vec![pest::Access::Call(pest::CallAccess { - expressions: vec![], + explicit_generics: None, + arguments: pest::Arguments { + expressions: vec![], + span: span.clone(), + }, span: span.clone(), })], span: span.clone(), diff --git a/zokrates_core/src/absy/mod.rs b/zokrates_core/src/absy/mod.rs index a497c3746..0eccc1345 100644 --- a/zokrates_core/src/absy/mod.rs +++ b/zokrates_core/src/absy/mod.rs @@ -16,7 +16,7 @@ pub use crate::absy::parameter::{Parameter, ParameterNode}; use crate::absy::types::{FunctionIdentifier, UnresolvedSignature, UnresolvedType, UserTypeId}; pub use crate::absy::variable::{Variable, VariableNode}; use crate::embed::FlatEmbed; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use crate::imports::ImportNode; use std::fmt; @@ -28,18 +28,19 @@ use std::collections::HashMap; pub type Identifier<'ast> = &'ast str; /// The identifier of a `Module`, typically a path or uri -pub type ModuleId = PathBuf; +pub type OwnedModuleId = PathBuf; +pub type ModuleId = Path; /// A collection of `Module`s -pub type Modules<'ast> = HashMap>; +pub type Modules<'ast> = HashMap>; /// A collection of `SymbolDeclaration`. Duplicates are allowed here as they are fine syntactically. pub type Declarations<'ast> = Vec>; /// A `Program` is a collection of `Module`s and an id of the main `Module` pub struct Program<'ast> { - pub modules: HashMap>, - pub main: ModuleId, + pub modules: HashMap>, + pub main: OwnedModuleId, } /// A declaration of a `FunctionSymbol`, be it from an import or a function definition @@ -105,7 +106,7 @@ impl<'ast> Module<'ast> { } } -pub type UnresolvedTypeNode = Node; +pub type UnresolvedTypeNode<'ast> = Node>; /// A struct type definition #[derive(Debug, Clone, PartialEq)] @@ -133,7 +134,7 @@ pub type StructDefinitionNode<'ast> = Node>; #[derive(Debug, Clone, PartialEq)] pub struct StructDefinitionField<'ast> { pub id: Identifier<'ast>, - pub ty: UnresolvedTypeNode, + pub ty: UnresolvedTypeNode<'ast>, } impl<'ast> fmt::Display for StructDefinitionField<'ast> { @@ -150,13 +151,13 @@ pub struct SymbolImport<'ast> { /// the id of the symbol in the target module. Note: there may be many candidates as imports statements do not specify the signature. In that case they must all be functions however. pub symbol_id: Identifier<'ast>, /// the id of the module to import from - pub module_id: ModuleId, + pub module_id: OwnedModuleId, } type SymbolImportNode<'ast> = Node>; impl<'ast> SymbolImport<'ast> { - pub fn with_id_in_module>, U: Into>( + pub fn with_id_in_module>, U: Into>( symbol_id: S, module_id: U, ) -> Self { @@ -216,6 +217,8 @@ impl<'ast> fmt::Debug for Module<'ast> { } } +pub type ConstantGenericNode<'ast> = Node>; + /// A function defined locally #[derive(Clone, PartialEq)] pub struct Function<'ast> { @@ -224,13 +227,26 @@ pub struct Function<'ast> { /// Vector of statements that are executed when running the function pub statements: Vec>, /// function signature - pub signature: UnresolvedSignature, + pub signature: UnresolvedSignature<'ast>, } pub type FunctionNode<'ast> = Node>; impl<'ast> fmt::Display for Function<'ast> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if !self.signature.generics.is_empty() { + write!( + f, + "<{}>", + self.signature + .generics + .iter() + .map(|g| g.to_string()) + .collect::>() + .join(", ") + )?; + } + write!( f, "({}):\n{}", @@ -294,6 +310,7 @@ impl<'ast> fmt::Display for Assignee<'ast> { } /// A statement in a `Function` +#[allow(clippy::large_enum_variant)] #[derive(Clone, PartialEq)] pub enum Statement<'ast> { Return(ExpressionListNode<'ast>), @@ -319,9 +336,9 @@ impl<'ast> fmt::Display for Statement<'ast> { Statement::Definition(ref lhs, ref rhs) => write!(f, "{} = {}", lhs, rhs), Statement::Assertion(ref e) => write!(f, "assert({})", e), Statement::For(ref var, ref start, ref stop, ref list) => { - write!(f, "for {} in {}..{} do\n", var, start, stop)?; + writeln!(f, "for {} in {}..{} do", var, start, stop)?; for l in list { - write!(f, "\t\t{}\n", l)?; + writeln!(f, "\t\t{}", l)?; } write!(f, "\tendfor") } @@ -348,9 +365,9 @@ impl<'ast> fmt::Debug for Statement<'ast> { } Statement::Assertion(ref e) => write!(f, "Assertion({:?})", e), Statement::For(ref var, ref start, ref stop, ref list) => { - write!(f, "for {:?} in {:?}..{:?} do\n", var, start, stop)?; + writeln!(f, "for {:?} in {:?}..{:?} do", var, start, stop)?; for l in list { - write!(f, "\t\t{:?}\n", l)?; + writeln!(f, "\t\t{:?}", l)?; } write!(f, "\tendfor") } @@ -454,11 +471,11 @@ impl<'ast> fmt::Display for Range<'ast> { self.from .as_ref() .map(|e| e.to_string()) - .unwrap_or("".to_string()), + .unwrap_or_else(|| "".to_string()), self.to .as_ref() .map(|e| e.to_string()) - .unwrap_or("".to_string()) + .unwrap_or_else(|| "".to_string()) ) } } @@ -472,11 +489,13 @@ impl<'ast> fmt::Debug for Range<'ast> { /// An expression #[derive(Clone, PartialEq)] pub enum Expression<'ast> { + IntConstant(BigUint), FieldConstant(BigUint), BooleanConstant(bool), U8Constant(u8), U16Constant(u16), U32Constant(u32), + U64Constant(u64), Identifier(Identifier<'ast>), Add(Box>, Box>), Sub(Box>, Box>), @@ -484,12 +503,18 @@ pub enum Expression<'ast> { Div(Box>, Box>), Rem(Box>, Box>), Pow(Box>, Box>), + Neg(Box>), + Pos(Box>), IfElse( Box>, Box>, Box>, ), - FunctionCall(FunctionIdentifier<'ast>, Vec>), + FunctionCall( + FunctionIdentifier<'ast>, + Option>>>, + Vec>, + ), Lt(Box>, Box>), Le(Box>, Box>), Eq(Box>, Box>), @@ -498,6 +523,7 @@ pub enum Expression<'ast> { And(Box>, Box>), Not(Box>), InlineArray(Vec>), + ArrayInitializer(Box>, Box>), InlineStruct(UserTypeId, Vec<(Identifier<'ast>, ExpressionNode<'ast>)>), Select(Box>, Box>), Member(Box>, Box>), @@ -518,6 +544,8 @@ impl<'ast> fmt::Display for Expression<'ast> { Expression::U8Constant(ref i) => write!(f, "{}", i), Expression::U16Constant(ref i) => write!(f, "{}", i), Expression::U32Constant(ref i) => write!(f, "{}", i), + Expression::U64Constant(ref i) => write!(f, "{}", i), + Expression::IntConstant(ref i) => write!(f, "{}", i), Expression::Identifier(ref var) => write!(f, "{}", var), Expression::Add(ref lhs, ref rhs) => write!(f, "({} + {})", lhs, rhs), Expression::Sub(ref lhs, ref rhs) => write!(f, "({} - {})", lhs, rhs), @@ -525,14 +553,29 @@ impl<'ast> fmt::Display for Expression<'ast> { Expression::Div(ref lhs, ref rhs) => write!(f, "({} / {})", lhs, rhs), Expression::Rem(ref lhs, ref rhs) => write!(f, "({} % {})", lhs, rhs), Expression::Pow(ref lhs, ref rhs) => write!(f, "({}**{})", lhs, rhs), + Expression::Neg(ref e) => write!(f, "(-{})", e), + Expression::Pos(ref e) => write!(f, "(+{})", e), Expression::BooleanConstant(b) => write!(f, "{}", b), Expression::IfElse(ref condition, ref consequent, ref alternative) => write!( f, "if {} then {} else {} fi", condition, consequent, alternative ), - Expression::FunctionCall(ref i, ref p) => { - write!(f, "{}(", i,)?; + Expression::FunctionCall(ref i, ref g, ref p) => { + if let Some(g) = g { + write!( + f, + "::<{}>", + g.iter() + .map(|g| g + .as_ref() + .map(|g| g.to_string()) + .unwrap_or_else(|| "_".into())) + .collect::>() + .join(", "), + )?; + } + write!(f, "{}(", i)?; for (i, param) in p.iter().enumerate() { write!(f, "{}", param)?; if i < p.len() - 1 { @@ -558,6 +601,7 @@ impl<'ast> fmt::Display for Expression<'ast> { } write!(f, "]") } + Expression::ArrayInitializer(ref e, ref count) => write!(f, "[{}; {}]", e, count), Expression::InlineStruct(ref id, ref members) => { write!(f, "{} {{", id)?; for (i, (member_id, e)) in members.iter().enumerate() { @@ -583,10 +627,12 @@ impl<'ast> fmt::Display for Expression<'ast> { impl<'ast> fmt::Debug for Expression<'ast> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - Expression::U8Constant(ref i) => write!(f, "{:x}", i), - Expression::U16Constant(ref i) => write!(f, "{:x}", i), - Expression::U32Constant(ref i) => write!(f, "{:x}", i), - Expression::FieldConstant(ref i) => write!(f, "Num({:?})", i), + Expression::U8Constant(ref i) => write!(f, "U8({:x})", i), + Expression::U16Constant(ref i) => write!(f, "U16({:x})", i), + Expression::U32Constant(ref i) => write!(f, "U32({:x})", i), + Expression::U64Constant(ref i) => write!(f, "U64({:x})", i), + Expression::FieldConstant(ref i) => write!(f, "Field({:?})", i), + Expression::IntConstant(ref i) => write!(f, "Int({:?})", i), Expression::Identifier(ref var) => write!(f, "Ide({})", var), Expression::Add(ref lhs, ref rhs) => write!(f, "Add({:?}, {:?})", lhs, rhs), Expression::Sub(ref lhs, ref rhs) => write!(f, "Sub({:?}, {:?})", lhs, rhs), @@ -594,14 +640,16 @@ impl<'ast> fmt::Debug for Expression<'ast> { Expression::Div(ref lhs, ref rhs) => write!(f, "Div({:?}, {:?})", lhs, rhs), Expression::Rem(ref lhs, ref rhs) => write!(f, "Rem({:?}, {:?})", lhs, rhs), Expression::Pow(ref lhs, ref rhs) => write!(f, "Pow({:?}, {:?})", lhs, rhs), + Expression::Neg(ref e) => write!(f, "Neg({:?})", e), + Expression::Pos(ref e) => write!(f, "Pos({:?})", e), Expression::BooleanConstant(b) => write!(f, "{}", b), Expression::IfElse(ref condition, ref consequent, ref alternative) => write!( f, "IfElse({:?}, {:?}, {:?})", condition, consequent, alternative ), - Expression::FunctionCall(ref i, ref p) => { - write!(f, "FunctionCall({:?}, (", i)?; + Expression::FunctionCall(ref g, ref i, ref p) => { + write!(f, "FunctionCall({:?}, {:?}, (", g, i)?; f.debug_list().entries(p.iter()).finish()?; write!(f, ")") } @@ -617,6 +665,9 @@ impl<'ast> fmt::Debug for Expression<'ast> { f.debug_list().entries(exprs.iter()).finish()?; write!(f, "]") } + Expression::ArrayInitializer(ref e, ref count) => { + write!(f, "ArrayInitializer({:?}, {:?})", e, count) + } Expression::InlineStruct(ref id, ref members) => { write!(f, "InlineStruct({:?}, [", id)?; f.debug_list().entries(members.iter()).finish()?; @@ -639,21 +690,13 @@ impl<'ast> fmt::Debug for Expression<'ast> { } /// A list of expressions, used in return statements -#[derive(Clone, PartialEq)] +#[derive(Clone, PartialEq, Default)] pub struct ExpressionList<'ast> { pub expressions: Vec>, } pub type ExpressionListNode<'ast> = Node>; -impl<'ast> ExpressionList<'ast> { - pub fn new() -> ExpressionList<'ast> { - ExpressionList { - expressions: vec![], - } - } -} - impl<'ast> fmt::Display for ExpressionList<'ast> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { for (i, param) in self.expressions.iter().enumerate() { diff --git a/zokrates_core/src/absy/node.rs b/zokrates_core/src/absy/node.rs index cf8d3fb4b..745054b48 100644 --- a/zokrates_core/src/absy/node.rs +++ b/zokrates_core/src/absy/node.rs @@ -35,7 +35,7 @@ impl Node { pub trait NodeValue: fmt::Display + fmt::Debug + Sized + PartialEq { fn at(self, line: usize, col: usize, delta: isize) -> Node { - let start = Position { col, line }; + let start = Position { line, col }; Node::new(start, start.col(delta), self) } @@ -81,7 +81,7 @@ impl<'ast> NodeValue for ExpressionList<'ast> {} impl<'ast> NodeValue for Assignee<'ast> {} impl<'ast> NodeValue for Statement<'ast> {} impl<'ast> NodeValue for SymbolDeclaration<'ast> {} -impl NodeValue for UnresolvedType {} +impl<'ast> NodeValue for UnresolvedType<'ast> {} impl<'ast> NodeValue for StructDefinition<'ast> {} impl<'ast> NodeValue for StructDefinitionField<'ast> {} impl<'ast> NodeValue for Function<'ast> {} @@ -92,6 +92,7 @@ impl<'ast> NodeValue for Parameter<'ast> {} impl<'ast> NodeValue for Import<'ast> {} impl<'ast> NodeValue for Spread<'ast> {} impl<'ast> NodeValue for Range<'ast> {} +impl<'ast> NodeValue for Identifier<'ast> {} impl PartialEq for Node { fn eq(&self, other: &Node) -> bool { diff --git a/zokrates_core/src/absy/types.rs b/zokrates_core/src/absy/types.rs index 49658fa29..439f9ca78 100644 --- a/zokrates_core/src/absy/types.rs +++ b/zokrates_core/src/absy/types.rs @@ -1,3 +1,4 @@ +use crate::absy::ExpressionNode; use crate::absy::UnresolvedTypeNode; use std::fmt; @@ -8,15 +9,15 @@ pub type MemberId = String; pub type UserTypeId = String; #[derive(Clone, PartialEq, Debug)] -pub enum UnresolvedType { +pub enum UnresolvedType<'ast> { FieldElement, Boolean, Uint(usize), - Array(Box, usize), + Array(Box>, ExpressionNode<'ast>), User(UserTypeId), } -impl fmt::Display for UnresolvedType { +impl<'ast> fmt::Display for UnresolvedType<'ast> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { UnresolvedType::FieldElement => write!(f, "field"), @@ -28,8 +29,8 @@ impl fmt::Display for UnresolvedType { } } -impl UnresolvedType { - pub fn array(ty: UnresolvedTypeNode, size: usize) -> Self { +impl<'ast> UnresolvedType<'ast> { + pub fn array(ty: UnresolvedTypeNode<'ast>, size: ExpressionNode<'ast>) -> Self { UnresolvedType::Array(box ty, size) } } @@ -39,17 +40,19 @@ pub type FunctionIdentifier<'ast> = &'ast str; pub use self::signature::UnresolvedSignature; mod signature { + use crate::absy::ConstantGenericNode; use std::fmt; use crate::absy::UnresolvedTypeNode; - #[derive(Clone, PartialEq)] - pub struct UnresolvedSignature { - pub inputs: Vec, - pub outputs: Vec, + #[derive(Clone, PartialEq, Default)] + pub struct UnresolvedSignature<'ast> { + pub generics: Vec>, + pub inputs: Vec>, + pub outputs: Vec>, } - impl fmt::Debug for UnresolvedSignature { + impl<'ast> fmt::Debug for UnresolvedSignature<'ast> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, @@ -59,7 +62,7 @@ mod signature { } } - impl fmt::Display for UnresolvedSignature { + impl<'ast> fmt::Display for UnresolvedSignature<'ast> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "(")?; for (i, t) in self.inputs.iter().enumerate() { @@ -79,20 +82,22 @@ mod signature { } } - impl UnresolvedSignature { - pub fn new() -> UnresolvedSignature { - UnresolvedSignature { - inputs: vec![], - outputs: vec![], - } + impl<'ast> UnresolvedSignature<'ast> { + pub fn new() -> UnresolvedSignature<'ast> { + UnresolvedSignature::default() + } + + pub fn generics(mut self, generics: Vec>) -> Self { + self.generics = generics; + self } - pub fn inputs(mut self, inputs: Vec) -> Self { + pub fn inputs(mut self, inputs: Vec>) -> Self { self.inputs = inputs; self } - pub fn outputs(mut self, outputs: Vec) -> Self { + pub fn outputs(mut self, outputs: Vec>) -> Self { self.outputs = outputs; self } diff --git a/zokrates_core/src/absy/variable.rs b/zokrates_core/src/absy/variable.rs index f03b3f0d3..6b8f9b60d 100644 --- a/zokrates_core/src/absy/variable.rs +++ b/zokrates_core/src/absy/variable.rs @@ -7,21 +7,21 @@ use crate::absy::Identifier; #[derive(Clone, PartialEq)] pub struct Variable<'ast> { pub id: Identifier<'ast>, - pub _type: UnresolvedTypeNode, + pub _type: UnresolvedTypeNode<'ast>, } pub type VariableNode<'ast> = Node>; impl<'ast> Variable<'ast> { - pub fn new>(id: S, t: UnresolvedTypeNode) -> Variable<'ast> { + pub fn new>(id: S, t: UnresolvedTypeNode<'ast>) -> Variable<'ast> { Variable { id: id.into(), _type: t, } } - pub fn get_type(&self) -> UnresolvedType { - self._type.value.clone() + pub fn get_type(&self) -> &UnresolvedType<'ast> { + &self._type.value } } diff --git a/zokrates_core/src/compile.rs b/zokrates_core/src/compile.rs index 7711a52af..af5a91848 100644 --- a/zokrates_core/src/compile.rs +++ b/zokrates_core/src/compile.rs @@ -3,12 +3,13 @@ //! @file compile.rs //! @author Thibaut Schaeffer //! @date 2018 -use crate::absy::{Module, ModuleId, Program}; +use crate::absy::{Module, OwnedModuleId, Program}; use crate::flatten::Flattener; use crate::imports::{self, Importer}; use crate::ir; use crate::macros; use crate::semantics::{self, Checker}; +use crate::static_analysis; use crate::static_analysis::Analyse; use crate::typed_absy::abi::Abi; use crate::zir::ZirProgram; @@ -17,7 +18,7 @@ use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::fmt; use std::io; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use typed_arena::Arena; use zokrates_common::Resolver; use zokrates_field::Field; @@ -55,13 +56,14 @@ pub enum CompileErrorInner { MacroError(macros::Error), SemanticError(semantics::ErrorInner), ReadError(io::Error), + AnalysisError(static_analysis::Error), } impl CompileErrorInner { - pub fn in_file(self, context: &PathBuf) -> CompileError { + pub fn in_file(self, context: &Path) -> CompileError { CompileError { value: self, - file: context.clone(), + file: context.to_path_buf(), } } } @@ -129,6 +131,12 @@ impl From for CompileError { } } +impl From for CompileErrorInner { + fn from(error: static_analysis::Error) -> Self { + CompileErrorInner::AnalysisError(error) + } +} + impl fmt::Display for CompileErrorInner { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { @@ -137,6 +145,7 @@ impl fmt::Display for CompileErrorInner { CompileErrorInner::SemanticError(ref e) => write!(f, "{}", e), CompileErrorInner::ReadError(ref e) => write!(f, "{}", e), CompileErrorInner::ImportError(ref e) => write!(f, "{}", e), + CompileErrorInner::AnalysisError(ref e) => write!(f, "{}", e), } } } @@ -179,7 +188,7 @@ pub fn compile>( }) } -pub fn check<'ast, T: Field, E: Into>( +pub fn check>( source: String, location: FilePath, resolver: Option<&dyn Resolver>, @@ -196,19 +205,18 @@ fn check_with_arena<'ast, T: Field, E: Into>( arena: &'ast Arena, ) -> Result<(ZirProgram<'ast, T>, Abi), CompileErrors> { let source = arena.alloc(source); - let compiled = compile_program::(source, location.clone(), resolver, &arena)?; + let compiled = compile_program::(source, location, resolver, &arena)?; // check semantics - let typed_ast = Checker::check(compiled).map_err(|errors| { - CompileErrors(errors.into_iter().map(|e| CompileError::from(e)).collect()) - })?; + let typed_ast = Checker::check(compiled) + .map_err(|errors| CompileErrors(errors.into_iter().map(CompileError::from).collect()))?; - let abi = typed_ast.abi(); + let main_module = typed_ast.main.clone(); // analyse (unroll and constant propagation) - let typed_ast = typed_ast.analyse(); - - Ok((typed_ast, abi)) + typed_ast + .analyse() + .map_err(|e| CompileErrors(vec![CompileErrorInner::from(e).in_file(&main_module)])) } pub fn compile_program<'ast, T: Field, E: Into>( @@ -233,7 +241,7 @@ pub fn compile_module<'ast, T: Field, E: Into>( source: &'ast str, location: FilePath, resolver: Option<&dyn Resolver>, - modules: &mut HashMap>, + modules: &mut HashMap>, arena: &'ast Arena, ) -> Result, CompileErrors> { let ast = pest::generate_ast(&source) @@ -244,7 +252,7 @@ pub fn compile_module<'ast, T: Field, E: Into>( let module_without_imports: Module = Module::from(ast); - Importer::new().apply_imports::( + Importer::apply_imports::( module_without_imports, location.clone(), resolver, @@ -380,17 +388,17 @@ struct Bar { field a } inputs: vec![AbiInput { name: "f".into(), public: true, - ty: Type::Struct(StructType::new( + ty: ConcreteType::Struct(ConcreteStructType::new( "foo".into(), "Foo".into(), - vec![StructMember { + vec![ConcreteStructMember { id: "b".into(), - ty: box Type::Struct(StructType::new( + ty: box ConcreteType::Struct(ConcreteStructType::new( "bar".into(), "Bar".into(), - vec![StructMember { + vec![ConcreteStructMember { id: "a".into(), - ty: box Type::FieldElement + ty: box ConcreteType::FieldElement }] )) }] diff --git a/zokrates_core/src/embed.rs b/zokrates_core/src/embed.rs index 76b1cd93e..e1b0326df 100644 --- a/zokrates_core/src/embed.rs +++ b/zokrates_core/src/embed.rs @@ -3,7 +3,9 @@ use crate::flat_absy::{ FlatVariable, }; use crate::solvers::Solver; -use crate::typed_absy::types::{FunctionKey, Signature, Type}; +use crate::typed_absy::types::{ + ConcreteGenericsAssignment, Constant, DeclarationSignature, DeclarationType, +}; use std::collections::HashMap; use zokrates_field::{Bn128Field, Field}; @@ -18,77 +20,134 @@ cfg_if::cfg_if! { /// A low level function that contains non-deterministic introduction of variables. It is carried out as is until /// the flattening step when it can be inlined. -#[derive(Debug, Clone, PartialEq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)] pub enum FlatEmbed { + U32ToField, #[cfg(feature = "bellman")] Sha256Round, - Unpack(usize), + Unpack, U8ToBits, U16ToBits, U32ToBits, + U64ToBits, U8FromBits, U16FromBits, U32FromBits, + U64FromBits, } impl FlatEmbed { - pub fn signature(&self) -> Signature { + pub fn signature(&self) -> DeclarationSignature<'static> { match self { + FlatEmbed::U32ToField => DeclarationSignature::new() + .inputs(vec![DeclarationType::uint(32)]) + .outputs(vec![DeclarationType::FieldElement]), + FlatEmbed::Unpack => DeclarationSignature::new() + .generics(vec![Some(Constant::Generic("N"))]) + .inputs(vec![DeclarationType::FieldElement]) + .outputs(vec![DeclarationType::array(( + DeclarationType::Boolean, + "N", + ))]), + FlatEmbed::U8ToBits => DeclarationSignature::new() + .inputs(vec![DeclarationType::uint(8)]) + .outputs(vec![DeclarationType::array(( + DeclarationType::Boolean, + 8usize, + ))]), + FlatEmbed::U16ToBits => DeclarationSignature::new() + .inputs(vec![DeclarationType::uint(16)]) + .outputs(vec![DeclarationType::array(( + DeclarationType::Boolean, + 16usize, + ))]), + FlatEmbed::U32ToBits => DeclarationSignature::new() + .inputs(vec![DeclarationType::uint(32)]) + .outputs(vec![DeclarationType::array(( + DeclarationType::Boolean, + 32usize, + ))]), + FlatEmbed::U64ToBits => DeclarationSignature::new() + .inputs(vec![DeclarationType::uint(64)]) + .outputs(vec![DeclarationType::array(( + DeclarationType::Boolean, + 64usize, + ))]), + FlatEmbed::U8FromBits => DeclarationSignature::new() + .outputs(vec![DeclarationType::uint(8)]) + .inputs(vec![DeclarationType::array(( + DeclarationType::Boolean, + 8usize, + ))]), + FlatEmbed::U16FromBits => DeclarationSignature::new() + .outputs(vec![DeclarationType::uint(16)]) + .inputs(vec![DeclarationType::array(( + DeclarationType::Boolean, + 16usize, + ))]), + FlatEmbed::U32FromBits => DeclarationSignature::new() + .outputs(vec![DeclarationType::uint(32)]) + .inputs(vec![DeclarationType::array(( + DeclarationType::Boolean, + 32usize, + ))]), + FlatEmbed::U64FromBits => DeclarationSignature::new() + .outputs(vec![DeclarationType::uint(64)]) + .inputs(vec![DeclarationType::array(( + DeclarationType::Boolean, + 64usize, + ))]), #[cfg(feature = "bellman")] - FlatEmbed::Sha256Round => Signature::new() + FlatEmbed::Sha256Round => DeclarationSignature::new() .inputs(vec![ - Type::array(Type::Boolean, 512), - Type::array(Type::Boolean, 256), + DeclarationType::array((DeclarationType::Boolean, 512usize)), + DeclarationType::array((DeclarationType::Boolean, 256usize)), ]) - .outputs(vec![Type::array(Type::Boolean, 256)]), - FlatEmbed::Unpack(bitwidth) => Signature::new() - .inputs(vec![Type::FieldElement]) - .outputs(vec![Type::array(Type::Boolean, *bitwidth)]), - FlatEmbed::U8ToBits => Signature::new() - .inputs(vec![Type::uint(8)]) - .outputs(vec![Type::array(Type::Boolean, 8)]), - FlatEmbed::U16ToBits => Signature::new() - .inputs(vec![Type::uint(16)]) - .outputs(vec![Type::array(Type::Boolean, 16)]), - FlatEmbed::U32ToBits => Signature::new() - .inputs(vec![Type::uint(32)]) - .outputs(vec![Type::array(Type::Boolean, 32)]), - FlatEmbed::U8FromBits => Signature::new() - .outputs(vec![Type::uint(8)]) - .inputs(vec![Type::array(Type::Boolean, 8)]), - FlatEmbed::U16FromBits => Signature::new() - .outputs(vec![Type::uint(16)]) - .inputs(vec![Type::array(Type::Boolean, 16)]), - FlatEmbed::U32FromBits => Signature::new() - .outputs(vec![Type::uint(32)]) - .inputs(vec![Type::array(Type::Boolean, 32)]), + .outputs(vec![DeclarationType::array(( + DeclarationType::Boolean, + 256usize, + ))]), } } - pub fn key(&self) -> FunctionKey<'static> { - FunctionKey::with_id(self.id()).signature(self.signature()) + pub fn generics<'ast>(&self, assignment: &ConcreteGenericsAssignment<'ast>) -> Vec { + let gen = self + .signature() + .generics + .into_iter() + .map(|c| match c.unwrap() { + Constant::Generic(g) => g, + _ => unreachable!(), + }); + + assert_eq!(gen.len(), assignment.0.len()); + gen.map(|g| *assignment.0.get(&g).clone().unwrap() as u32) + .collect() } pub fn id(&self) -> &'static str { match self { + FlatEmbed::U32ToField => "_U32_TO_FIELD", #[cfg(feature = "bellman")] FlatEmbed::Sha256Round => "_SHA256_ROUND", - FlatEmbed::Unpack(_) => "_UNPACK", + FlatEmbed::Unpack => "_UNPACK", FlatEmbed::U8ToBits => "_U8_TO_BITS", FlatEmbed::U16ToBits => "_U16_TO_BITS", FlatEmbed::U32ToBits => "_U32_TO_BITS", + FlatEmbed::U64ToBits => "_U64_TO_BITS", FlatEmbed::U8FromBits => "_U8_FROM_BITS", FlatEmbed::U16FromBits => "_U16_FROM_BITS", FlatEmbed::U32FromBits => "_U32_FROM_BITS", + FlatEmbed::U64FromBits => "_U64_FROM_BITS", } } /// Actually get the `FlatFunction` that this `FlatEmbed` represents - pub fn synthetize(&self) -> FlatFunction { + pub fn synthetize(&self, generics: &[u32]) -> FlatFunction { match self { #[cfg(feature = "bellman")] FlatEmbed::Sha256Round => sha256_round(), - FlatEmbed::Unpack(bitwidth) => unpack_to_bitwidth(*bitwidth), + FlatEmbed::Unpack => unpack_to_bitwidth(generics[0] as usize), _ => unreachable!(), } } @@ -101,7 +160,7 @@ fn flat_expression_from_vec(v: &[(usize, E::Fr)]) -> FlatEx match v.len() { 0 => FlatExpression::Number(T::zero()), 1 => { - let (key, val) = v[0].clone(); + let (key, val) = v[0]; let mut res: Vec = vec![]; val.into_repr().write_le(&mut res).unwrap(); FlatExpression::Mult( @@ -152,7 +211,7 @@ pub fn sha256_round() -> FlatFunction { let output_indices = output_indices.into_iter(); let variable_count = r1cs.aux_count + 1; // auxiliary and ONE // indices of the sha256round constraint system variables - let cs_indices = (0..variable_count).into_iter(); + 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 = input_indices @@ -180,7 +239,7 @@ pub fn sha256_round() -> FlatFunction { ); let input_binding_statements = // bind input and current_hash to inputs - input_indices.clone().chain(current_hash_indices).zip(input_argument_indices.clone().chain(current_hash_argument_indices.clone())).map(|(cs_index, argument_index)| { + input_indices.chain(current_hash_indices).zip(input_argument_indices.clone().chain(current_hash_argument_indices.clone())).map(|(cs_index, argument_index)| { FlatStatement::Condition( FlatVariable::new(cs_index).into(), FlatVariable::new(argument_index).into(), @@ -194,7 +253,7 @@ pub fn sha256_round() -> FlatFunction { .collect(); // insert a directive to set the witness based on the bellman gadget and inputs let directive_statement = FlatStatement::Directive(FlatDirective { - outputs: cs_indices.map(|i| FlatVariable::new(i)).collect(), + outputs: cs_indices.map(FlatVariable::new).collect(), inputs: input_argument_indices .chain(current_hash_argument_indices) .map(|i| FlatVariable::new(i).into()) @@ -224,7 +283,7 @@ fn use_variable( ) -> FlatVariable { let var = FlatVariable::new(*index); layout.insert(name, var); - *index = *index + 1; + *index += 1; var } @@ -255,7 +314,7 @@ pub fn unpack_to_bitwidth(bit_width: usize) -> FlatFunction { let directive_inputs = vec![FlatExpression::Identifier(use_variable( &mut layout, - format!("i0"), + "i0".into(), &mut counter, ))]; @@ -268,7 +327,7 @@ pub fn unpack_to_bitwidth(bit_width: usize) -> FlatFunction { let outputs = directive_outputs .iter() .enumerate() - .map(|(_, o)| FlatExpression::Identifier(o.clone())) + .map(|(_, o)| FlatExpression::Identifier(*o)) .collect::>(); // o253, o252, ... o{253 - (bit_width - 1)} are bits @@ -308,7 +367,7 @@ pub fn unpack_to_bitwidth(bit_width: usize) -> FlatFunction { FlatStatement::Directive(FlatDirective { inputs: directive_inputs, outputs: directive_outputs, - solver: solver, + solver, }), ); @@ -436,10 +495,10 @@ mod tests { private: vec![true; 768], }; - let input = (0..512) + let input: Vec<_> = (0..512) .map(|_| 0) .chain((0..256).map(|_| 1)) - .map(|i| Bn128Field::from(i)) + .map(Bn128Field::from) .collect(); let interpreter = Interpreter::default(); diff --git a/zokrates_core/src/flat_absy/flat_parameter.rs b/zokrates_core/src/flat_absy/flat_parameter.rs index 788a3ac45..0b9481cb2 100644 --- a/zokrates_core/src/flat_absy/flat_parameter.rs +++ b/zokrates_core/src/flat_absy/flat_parameter.rs @@ -41,7 +41,7 @@ impl FlatParameter { substitution: &HashMap, ) -> FlatParameter { FlatParameter { - id: substitution.get(&self.id).unwrap().clone(), + id: *substitution.get(&self.id).unwrap(), private: self.private, } } diff --git a/zokrates_core/src/flat_absy/flat_variable.rs b/zokrates_core/src/flat_absy/flat_variable.rs index 5fc96c964..2679cd99f 100644 --- a/zokrates_core/src/flat_absy/flat_variable.rs +++ b/zokrates_core/src/flat_absy/flat_variable.rs @@ -45,7 +45,7 @@ impl FlatVariable { Ok(FlatVariable::public(v)) } None => { - let mut private = s.split("_"); + let mut private = s.split('_'); match private.nth(1) { Some(v) => { let v = v.parse().map_err(|_| s)?; diff --git a/zokrates_core/src/flat_absy/mod.rs b/zokrates_core/src/flat_absy/mod.rs index b96c0c228..08232fbe8 100644 --- a/zokrates_core/src/flat_absy/mod.rs +++ b/zokrates_core/src/flat_absy/mod.rs @@ -146,8 +146,8 @@ impl FlatStatement { .collect(); FlatStatement::Directive(FlatDirective { - outputs, inputs, + outputs, ..d }) } @@ -155,23 +155,13 @@ impl FlatStatement { } } -#[derive(Clone, Hash, Debug)] +#[derive(Clone, Hash, Debug, PartialEq, Eq)] pub struct FlatDirective { pub inputs: Vec>, pub outputs: Vec, pub solver: Solver, } -impl PartialEq for FlatDirective { - fn eq(&self, other: &Self) -> bool { - self.inputs.eq(&other.inputs) - && self.outputs.eq(&other.outputs) - && self.solver.eq(&other.solver) - } -} - -impl Eq for FlatDirective {} - impl FlatDirective { pub fn new>>( outputs: Vec, @@ -249,12 +239,18 @@ impl FlatExpression { FlatExpression::Add(ref x, ref y) | FlatExpression::Sub(ref x, ref y) => { x.is_linear() && y.is_linear() } - FlatExpression::Mult(ref x, ref y) => match (x.clone(), y.clone()) { + 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(_)) => true, - _ => false, - }, + | ( + box FlatExpression::Number(_), + box FlatExpression::Identifier(_) + ) + | ( + box FlatExpression::Identifier(_), + box FlatExpression::Number(_) + ) + ), } } } diff --git a/zokrates_core/src/flatten/mod.rs b/zokrates_core/src/flatten/mod.rs index f3a746ffd..61c287aa1 100644 --- a/zokrates_core/src/flatten/mod.rs +++ b/zokrates_core/src/flatten/mod.rs @@ -1,3 +1,5 @@ +#![allow(clippy::needless_collect)] + //! Module containing the `Flattener` to process a program that is R1CS-able. //! //! @file flatten.rs @@ -8,11 +10,13 @@ mod utils; use self::utils::flat_expression_from_bits; +use crate::ir::Interpreter; use crate::compile::CompileConfig; +use crate::embed::FlatEmbed; use crate::flat_absy::*; -use crate::solvers::{Executable, Solver}; -use crate::zir::types::{FunctionIdentifier, FunctionKey, Signature, Type, UBitwidth}; +use crate::solvers::Solver; +use crate::zir::types::{Type, UBitwidth}; use crate::zir::*; use std::collections::hash_map::Entry; use std::collections::HashMap; @@ -29,8 +33,6 @@ pub struct Flattener<'ast, T: Field> { next_var_idx: usize, /// `FlatVariable`s corresponding to each `Identifier` layout: HashMap, FlatVariable>, - /// Cached `FlatFunction`s to avoid re-flattening them - flat_cache: HashMap, FlatFunction>, /// Cached bit decompositions to avoid re-generating them bits_cache: HashMap, Vec>>, } @@ -59,7 +61,6 @@ trait Flatten<'ast, T: Field>: TryFrom, Error = ()> + IfE fn flatten( self, flattener: &mut Flattener<'ast, T>, - symbols: &ZirFunctionSymbols<'ast, T>, statements_flattened: &mut FlatStatements, ) -> Self::Output; } @@ -70,10 +71,9 @@ impl<'ast, T: Field> Flatten<'ast, T> for FieldElementExpression<'ast, T> { fn flatten( self, flattener: &mut Flattener<'ast, T>, - symbols: &ZirFunctionSymbols<'ast, T>, statements_flattened: &mut FlatStatements, ) -> Self::Output { - flattener.flatten_field_expression(symbols, statements_flattened, self) + flattener.flatten_field_expression(statements_flattened, self) } } @@ -83,10 +83,9 @@ impl<'ast, T: Field> Flatten<'ast, T> for UExpression<'ast, T> { fn flatten( self, flattener: &mut Flattener<'ast, T>, - symbols: &ZirFunctionSymbols<'ast, T>, statements_flattened: &mut FlatStatements, ) -> Self::Output { - flattener.flatten_uint_expression(symbols, statements_flattened, self) + flattener.flatten_uint_expression(statements_flattened, self) } } @@ -96,10 +95,9 @@ impl<'ast, T: Field> Flatten<'ast, T> for BooleanExpression<'ast, T> { fn flatten( self, flattener: &mut Flattener<'ast, T>, - symbols: &ZirFunctionSymbols<'ast, T>, statements_flattened: &mut FlatStatements, ) -> Self::Output { - flattener.flatten_boolean_expression(symbols, statements_flattened, self) + flattener.flatten_boolean_expression(statements_flattened, self) } } @@ -160,7 +158,6 @@ impl<'ast, T: Field> Flattener<'ast, T> { config, next_var_idx: 0, layout: HashMap::new(), - flat_cache: HashMap::new(), bits_cache: HashMap::new(), } } @@ -172,7 +169,7 @@ impl<'ast, T: Field> Flattener<'ast, T> { statements_flattened: &mut FlatStatements, ) -> FlatVariable { match e { - FlatExpression::Identifier(id) => id.into(), + FlatExpression::Identifier(id) => id, e => { let res = self.use_sym(); statements_flattened.push(FlatStatement::Definition(res, e)); @@ -251,10 +248,7 @@ 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].into(), - size_unknown[i].into(), - ), + FlatStatement::Definition(size_unknown[i + 1], size_unknown[i].into()), ); } @@ -287,7 +281,6 @@ impl<'ast, T: Field> Flattener<'ast, T> { /// /// # Arguments /// - /// * `symbols` - Available functions in this context /// * `statements_flattened` - Vector where new flattened statements can be added. /// * `condition` - the condition as a `BooleanExpression`. /// * `consequence` - the consequence of type U. @@ -296,17 +289,16 @@ impl<'ast, T: Field> Flattener<'ast, T> { /// * U is the type of the expression fn flatten_if_else_expression>( &mut self, - symbols: &ZirFunctionSymbols<'ast, T>, statements_flattened: &mut FlatStatements, condition: BooleanExpression<'ast, T>, consequence: U, alternative: U, ) -> FlatUExpression { - let condition = self.flatten_boolean_expression(symbols, statements_flattened, condition); + let condition = self.flatten_boolean_expression(statements_flattened, condition); - let consequence = consequence.flatten(self, symbols, statements_flattened); + let consequence = consequence.flatten(self, statements_flattened); - let alternative = alternative.flatten(self, symbols, statements_flattened); + let alternative = alternative.flatten(self, statements_flattened); let condition_id = self.use_sym(); statements_flattened.push(FlatStatement::Definition(condition_id, condition)); @@ -360,7 +352,6 @@ impl<'ast, T: Field> Flattener<'ast, T> { /// /// # Arguments /// - /// * `symbols` - Available functions in this context /// * `statements_flattened` - Vector where new flattened statements can be added. /// * `expression` - `BooleanExpression` that will be flattened. /// @@ -370,16 +361,15 @@ impl<'ast, T: Field> Flattener<'ast, T> { /// * in order to preserve composability. fn flatten_boolean_expression( &mut self, - symbols: &ZirFunctionSymbols<'ast, T>, statements_flattened: &mut FlatStatements, expression: BooleanExpression<'ast, T>, ) -> FlatExpression { // those will be booleans in the future match expression { BooleanExpression::Identifier(x) => { - FlatExpression::Identifier(self.layout.get(&x).unwrap().clone()) + FlatExpression::Identifier(*self.layout.get(&x).unwrap()) } - BooleanExpression::Lt(box lhs, box rhs) => { + BooleanExpression::FieldLt(box lhs, box rhs) => { // 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; // making sure we don't overflow, assert here? @@ -387,10 +377,8 @@ impl<'ast, T: Field> Flattener<'ast, T> { // We know from semantic checking that lhs and rhs have the same type // What the expression will flatten to depends on that type - let lhs_flattened = - self.flatten_field_expression(symbols, statements_flattened, lhs); - let rhs_flattened = - self.flatten_field_expression(symbols, statements_flattened, rhs); + let lhs_flattened = self.flatten_field_expression(statements_flattened, lhs); + let rhs_flattened = self.flatten_field_expression(statements_flattened, rhs); // lhs let lhs_id = self.define(lhs_flattened, statements_flattened); @@ -411,12 +399,12 @@ impl<'ast, T: Field> Flattener<'ast, T> { ))); // bitness checks - for i in 0..safe_width { + for bit in lhs_bits_be.iter().take(safe_width) { statements_flattened.push(FlatStatement::Condition( - FlatExpression::Identifier(lhs_bits_be[i]), + FlatExpression::Identifier(*bit), FlatExpression::Mult( - box FlatExpression::Identifier(lhs_bits_be[i]), - box FlatExpression::Identifier(lhs_bits_be[i]), + box FlatExpression::Identifier(*bit), + box FlatExpression::Identifier(*bit), ), )); } @@ -424,11 +412,11 @@ impl<'ast, T: Field> Flattener<'ast, T> { // bit decomposition check let mut lhs_sum = FlatExpression::Number(T::from(0)); - for i in 0..safe_width { + for (i, bit) in lhs_bits_be.iter().enumerate().take(safe_width) { lhs_sum = FlatExpression::Add( box lhs_sum, box FlatExpression::Mult( - box FlatExpression::Identifier(lhs_bits_be[i]), + box FlatExpression::Identifier(*bit), box FlatExpression::Number(T::from(2).pow(safe_width - i - 1)), ), ); @@ -457,12 +445,12 @@ impl<'ast, T: Field> Flattener<'ast, T> { ))); // bitness checks - for i in 0..safe_width { + for bit in rhs_bits_be.iter().take(safe_width) { statements_flattened.push(FlatStatement::Condition( - FlatExpression::Identifier(rhs_bits_be[i]), + FlatExpression::Identifier(*bit), FlatExpression::Mult( - box FlatExpression::Identifier(rhs_bits_be[i]), - box FlatExpression::Identifier(rhs_bits_be[i]), + box FlatExpression::Identifier(*bit), + box FlatExpression::Identifier(*bit), ), )); } @@ -470,11 +458,11 @@ impl<'ast, T: Field> Flattener<'ast, T> { // bit decomposition check let mut rhs_sum = FlatExpression::Number(T::from(0)); - for i in 0..safe_width { + for (i, bit) in rhs_bits_be.iter().enumerate().take(safe_width) { rhs_sum = FlatExpression::Add( box rhs_sum, box FlatExpression::Mult( - box FlatExpression::Identifier(rhs_bits_be[i]), + box FlatExpression::Identifier(*bit), box FlatExpression::Number(T::from(2).pow(safe_width - i - 1)), ), ); @@ -510,12 +498,12 @@ impl<'ast, T: Field> Flattener<'ast, T> { ))); // bitness checks - for i in 0..bit_width { + for bit in sub_bits_be.iter().take(bit_width) { statements_flattened.push(FlatStatement::Condition( - FlatExpression::Identifier(sub_bits_be[i]), + FlatExpression::Identifier(*bit), FlatExpression::Mult( - box FlatExpression::Identifier(sub_bits_be[i]), - box FlatExpression::Identifier(sub_bits_be[i]), + box FlatExpression::Identifier(*bit), + box FlatExpression::Identifier(*bit), ), )); } @@ -530,11 +518,11 @@ impl<'ast, T: Field> Flattener<'ast, T> { // sum(sym_b{i} * 2**i) let mut expr = FlatExpression::Number(T::from(0)); - for i in 0..bit_width { + for (i, bit) in sub_bits_be.iter().enumerate().take(bit_width) { expr = FlatExpression::Add( box expr, box FlatExpression::Mult( - box FlatExpression::Identifier(sub_bits_be[i]), + box FlatExpression::Identifier(*bit), box FlatExpression::Number(T::from(2).pow(bit_width - i - 1)), ), ); @@ -546,8 +534,8 @@ impl<'ast, T: Field> Flattener<'ast, T> { } BooleanExpression::BoolEq(box lhs, box rhs) => { // lhs and rhs are booleans, they flatten to 0 or 1 - let x = self.flatten_boolean_expression(symbols, statements_flattened, lhs); - let y = self.flatten_boolean_expression(symbols, statements_flattened, rhs); + let x = self.flatten_boolean_expression(statements_flattened, lhs); + let y = self.flatten_boolean_expression(statements_flattened, rhs); // 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 @@ -588,7 +576,6 @@ impl<'ast, T: Field> Flattener<'ast, T> { let name_m = self.use_sym(); let x = self.flatten_field_expression( - symbols, statements_flattened, FieldElementExpression::Sub(box lhs, box rhs), ); @@ -632,10 +619,10 @@ impl<'ast, T: Field> Flattener<'ast, T> { assert!(rhs.metadata.clone().unwrap().should_reduce.to_bool()); let lhs = self - .flatten_uint_expression(symbols, statements_flattened, lhs) + .flatten_uint_expression(statements_flattened, lhs) .get_field_unchecked(); let rhs = self - .flatten_uint_expression(symbols, statements_flattened, rhs) + .flatten_uint_expression(statements_flattened, rhs) .get_field_unchecked(); let x = FlatExpression::Sub(box lhs, box rhs); @@ -662,32 +649,117 @@ impl<'ast, T: Field> Flattener<'ast, T> { res } - BooleanExpression::Le(box lhs, box rhs) => { + BooleanExpression::FieldLe(box lhs, box rhs) => { let lt = self.flatten_boolean_expression( - symbols, statements_flattened, - BooleanExpression::Lt(box lhs.clone(), box rhs.clone()), + BooleanExpression::FieldLt(box lhs.clone(), box rhs.clone()), ); let eq = self.flatten_boolean_expression( - symbols, statements_flattened, BooleanExpression::FieldEq(box lhs.clone(), box rhs.clone()), ); FlatExpression::Add(box eq, box lt) } - BooleanExpression::Gt(lhs, rhs) => self.flatten_boolean_expression( - symbols, + BooleanExpression::FieldGt(lhs, rhs) => self.flatten_boolean_expression( + statements_flattened, + BooleanExpression::FieldLt(rhs, lhs), + ), + BooleanExpression::FieldGe(lhs, rhs) => self.flatten_boolean_expression( + statements_flattened, + BooleanExpression::FieldLe(rhs, lhs), + ), + BooleanExpression::UintLt(box lhs, box rhs) => { + let lhs_flattened = self.flatten_uint_expression(statements_flattened, lhs); + let rhs_flattened = self.flatten_uint_expression(statements_flattened, rhs); + + // Get the bit width to know the size of the binary decompositions for this Field + // This is not this uint bitwidth + let bit_width = T::get_required_bits(); + + // lhs + let lhs_id = self.define(lhs_flattened.get_field_unchecked(), statements_flattened); + let rhs_id = self.define(rhs_flattened.get_field_unchecked(), statements_flattened); + + // sym := (lhs * 2) - (rhs * 2) + let subtraction_result = FlatExpression::Sub( + box FlatExpression::Mult( + box FlatExpression::Number(T::from(2)), + box FlatExpression::Identifier(lhs_id), + ), + box FlatExpression::Mult( + box FlatExpression::Number(T::from(2)), + box FlatExpression::Identifier(rhs_id), + ), + ); + + // define variables for the bits + let sub_bits_be: Vec = + (0..bit_width).map(|_| self.use_sym()).collect(); + + // add a directive to get the bits + statements_flattened.push(FlatStatement::Directive(FlatDirective::new( + sub_bits_be.clone(), + Solver::bits(bit_width), + vec![subtraction_result.clone()], + ))); + + // bitness checks + for bit in sub_bits_be.iter().take(bit_width) { + statements_flattened.push(FlatStatement::Condition( + FlatExpression::Identifier(*bit), + FlatExpression::Mult( + box FlatExpression::Identifier(*bit), + box FlatExpression::Identifier(*bit), + ), + )); + } + + // check that the decomposition is in the field with a strict `< p` checks + self.strict_le_check( + statements_flattened, + &T::max_value_bit_vector_be(), + sub_bits_be.clone(), + ); + + // sum(sym_b{i} * 2**i) + let mut expr = FlatExpression::Number(T::from(0)); + + for (i, bit) in sub_bits_be.iter().enumerate().take(bit_width) { + expr = FlatExpression::Add( + box expr, + box FlatExpression::Mult( + box FlatExpression::Identifier(*bit), + box FlatExpression::Number(T::from(2).pow(bit_width - i - 1)), + ), + ); + } + + statements_flattened.push(FlatStatement::Condition(subtraction_result, expr)); + + FlatExpression::Identifier(sub_bits_be[bit_width - 1]) + } + BooleanExpression::UintLe(box lhs, box rhs) => { + let lt = self.flatten_boolean_expression( + statements_flattened, + BooleanExpression::UintLt(box lhs.clone(), box rhs.clone()), + ); + let eq = self.flatten_boolean_expression( + statements_flattened, + BooleanExpression::UintEq(box lhs.clone(), box rhs.clone()), + ); + FlatExpression::Add(box eq, box lt) + } + BooleanExpression::UintGt(lhs, rhs) => self.flatten_boolean_expression( statements_flattened, - BooleanExpression::Lt(rhs, lhs), + BooleanExpression::UintLt(rhs, lhs), ), - BooleanExpression::Ge(lhs, rhs) => self.flatten_boolean_expression( - symbols, + BooleanExpression::UintGe(lhs, rhs) => self.flatten_boolean_expression( statements_flattened, - BooleanExpression::Le(rhs, lhs), + BooleanExpression::UintLe(rhs, lhs), ), BooleanExpression::Or(box lhs, box rhs) => { - let x = self.flatten_boolean_expression(symbols, statements_flattened, lhs); - let y = self.flatten_boolean_expression(symbols, statements_flattened, rhs); + let x = self.flatten_boolean_expression(statements_flattened, lhs); + let y = self.flatten_boolean_expression(statements_flattened, rhs); assert!(x.is_linear() && y.is_linear()); let name_x_or_y = self.use_sym(); statements_flattened.push(FlatStatement::Directive(FlatDirective { @@ -705,8 +777,8 @@ impl<'ast, T: Field> Flattener<'ast, T> { name_x_or_y.into() } BooleanExpression::And(box lhs, box rhs) => { - let x = self.flatten_boolean_expression(symbols, statements_flattened, lhs); - let y = self.flatten_boolean_expression(symbols, statements_flattened, rhs); + let x = self.flatten_boolean_expression(statements_flattened, lhs); + let y = self.flatten_boolean_expression(statements_flattened, rhs); let name_x_and_y = self.use_sym(); assert!(x.is_linear() && y.is_linear()); @@ -718,7 +790,7 @@ impl<'ast, T: Field> Flattener<'ast, T> { FlatExpression::Identifier(name_x_and_y) } BooleanExpression::Not(box exp) => { - let x = self.flatten_boolean_expression(symbols, statements_flattened, exp); + let x = self.flatten_boolean_expression(statements_flattened, exp); FlatExpression::Sub(box FlatExpression::Number(T::one()), box x) } BooleanExpression::Value(b) => FlatExpression::Number(match b { @@ -727,38 +799,32 @@ impl<'ast, T: Field> Flattener<'ast, T> { }), BooleanExpression::IfElse(box condition, box consequence, box alternative) => self .flatten_if_else_expression( - symbols, statements_flattened, condition, consequence, alternative, ) - .get_field_unchecked() - .clone(), + .get_field_unchecked(), } } fn flatten_u_to_bits( &mut self, - symbols: &ZirFunctionSymbols<'ast, T>, statements_flattened: &mut FlatStatements, expression: ZirExpression<'ast, T>, bitwidth: UBitwidth, ) -> Vec> { let expression = UExpression::try_from(expression).unwrap(); let from = expression.metadata.clone().unwrap().bitwidth(); - let p = self.flatten_uint_expression(symbols, statements_flattened, expression); - let bits = self - .get_bits(p, from as usize, bitwidth, statements_flattened) + let p = self.flatten_uint_expression(statements_flattened, expression); + self.get_bits(p, from as usize, bitwidth, statements_flattened) .into_iter() - .map(|b| FlatUExpression::with_field(b)) - .collect(); - bits + .map(FlatUExpression::with_field) + .collect() } fn flatten_bits_to_u( &mut self, - symbols: &ZirFunctionSymbols<'ast, T>, statements_flattened: &mut FlatStatements, bits: Vec>, bitwidth: UBitwidth, @@ -767,7 +833,7 @@ impl<'ast, T: Field> Flattener<'ast, T> { let bits: Vec<_> = bits .into_iter() .map(|p| { - self.flatten_expression(symbols, statements_flattened, p) + self.flatten_expression(statements_flattened, p) .get_field_unchecked() }) .collect(); @@ -779,76 +845,61 @@ impl<'ast, T: Field> Flattener<'ast, T> { /// /// # Arguments /// - /// * `symbols` - Available functions in this context /// * `statements_flattened` - Vector where new flattened statements can be added. /// * `id` - `Identifier of the function. /// * `return_types` - Types of the return values of the function /// * `param_expressions` - Arguments of this call - fn flatten_function_call( + fn flatten_embed_call( &mut self, - symbols: &ZirFunctionSymbols<'ast, T>, statements_flattened: &mut FlatStatements, - id: FunctionIdentifier<'ast>, - return_types: Vec, + embed: FlatEmbed, + generics: Vec, param_expressions: Vec>, ) -> Vec> { - let passed_signature = Signature::new() - .inputs(param_expressions.iter().map(|e| e.get_type()).collect()) - .outputs(return_types); - - let key = FunctionKey::with_id(id).signature(passed_signature); - - let funct = self.get_embed(&key, &symbols); - - match funct { + match embed { + crate::embed::FlatEmbed::U64ToBits => self.flatten_u_to_bits( + statements_flattened, + param_expressions[0].clone(), + 64.into(), + ), crate::embed::FlatEmbed::U32ToBits => self.flatten_u_to_bits( - symbols, statements_flattened, param_expressions[0].clone(), 32.into(), ), crate::embed::FlatEmbed::U16ToBits => self.flatten_u_to_bits( - symbols, statements_flattened, param_expressions[0].clone(), 16.into(), ), - crate::embed::FlatEmbed::U8ToBits => self.flatten_u_to_bits( - symbols, - statements_flattened, - param_expressions[0].clone(), - 8.into(), - ), - crate::embed::FlatEmbed::U32FromBits => vec![self.flatten_bits_to_u( - symbols, - statements_flattened, - param_expressions, - 32.into(), - )], - crate::embed::FlatEmbed::U16FromBits => vec![self.flatten_bits_to_u( - symbols, - statements_flattened, - param_expressions, - 16.into(), - )], - crate::embed::FlatEmbed::U8FromBits => vec![self.flatten_bits_to_u( - symbols, - statements_flattened, - param_expressions, - 8.into(), - )], + crate::embed::FlatEmbed::U8ToBits => { + self.flatten_u_to_bits(statements_flattened, param_expressions[0].clone(), 8.into()) + } + crate::embed::FlatEmbed::U64FromBits => { + vec![self.flatten_bits_to_u(statements_flattened, param_expressions, 64.into())] + } + crate::embed::FlatEmbed::U32FromBits => { + vec![self.flatten_bits_to_u(statements_flattened, param_expressions, 32.into())] + } + crate::embed::FlatEmbed::U16FromBits => { + vec![self.flatten_bits_to_u(statements_flattened, param_expressions, 16.into())] + } + crate::embed::FlatEmbed::U8FromBits => { + vec![self.flatten_bits_to_u(statements_flattened, param_expressions, 8.into())] + } funct => { - let funct = funct.synthetize(); + let funct = funct.synthetize(&generics); let mut replacement_map = HashMap::new(); // Handle complex parameters and assign values: // Rename Parameters, assign them to values in call. Resolve complex expressions with definitions + // Clippy doesn't like the fact that we're collecting here, however not doing so leads to a borrow issue + // of `self` in the for-loop just after. This is why the `needless_collect` lint is disabled for this file + // (it does not work for this single line) let params_flattened = param_expressions .into_iter() - .map(|param_expr| { - self.flatten_expression(symbols, statements_flattened, param_expr) - }) + .map(|param_expr| self.flatten_expression(statements_flattened, param_expr)) .into_iter() .map(|x| x.get_field_unchecked()) .collect::>(); @@ -863,11 +914,10 @@ impl<'ast, T: Field> Flattener<'ast, T> { // Ensure renaming and correct returns: // add all flattened statements, adapt return statements - let (mut return_statements, statements): (Vec<_>, Vec<_>) = - funct.statements.into_iter().partition(|s| match s { - FlatStatement::Return(..) => true, - _ => false, - }); + let (mut return_statements, statements): (Vec<_>, Vec<_>) = funct + .statements + .into_iter() + .partition(|s| matches!(s, FlatStatement::Return(..))); let statements: Vec<_> = statements .into_iter() @@ -916,7 +966,7 @@ impl<'ast, T: Field> Flattener<'ast, T> { .expressions .into_iter() .map(|x| x.apply_substitution(&replacement_map)) - .map(|x| FlatUExpression::with_field(x)) + .map(FlatUExpression::with_field) .collect(), _ => unreachable!(), } @@ -928,37 +978,32 @@ impl<'ast, T: Field> Flattener<'ast, T> { /// /// # Arguments /// - /// * `symbols` - Available functions in this context /// * `statements_flattened` - Vector where new flattened statements can be added. /// * `expr` - `ZirExpression` that will be flattened. fn flatten_expression( &mut self, - symbols: &ZirFunctionSymbols<'ast, T>, statements_flattened: &mut FlatStatements, expr: ZirExpression<'ast, T>, ) -> FlatUExpression { match expr { - ZirExpression::FieldElement(e) => FlatUExpression::with_field( - self.flatten_field_expression(symbols, statements_flattened, e), - ), + ZirExpression::FieldElement(e) => { + FlatUExpression::with_field(self.flatten_field_expression(statements_flattened, e)) + } ZirExpression::Boolean(e) => FlatUExpression::with_field( - self.flatten_boolean_expression(symbols, statements_flattened, e), + self.flatten_boolean_expression(statements_flattened, e), ), - ZirExpression::Uint(e) => { - self.flatten_uint_expression(symbols, statements_flattened, e) - } + ZirExpression::Uint(e) => self.flatten_uint_expression(statements_flattened, e), } } fn default_xor( &mut self, - symbols: &ZirFunctionSymbols<'ast, T>, statements_flattened: &mut FlatStatements, left: UExpression<'ast, T>, right: UExpression<'ast, T>, ) -> FlatUExpression { - let left_flattened = self.flatten_uint_expression(symbols, statements_flattened, left); - let right_flattened = self.flatten_uint_expression(symbols, statements_flattened, right); + let left_flattened = self.flatten_uint_expression(statements_flattened, left); + let right_flattened = self.flatten_uint_expression(statements_flattened, right); // `left` and `right` were reduced to the target bitwidth, hence their bits are available @@ -990,7 +1035,7 @@ impl<'ast, T: Field> Flattener<'ast, T> { statements_flattened.extend(vec![ FlatStatement::Directive(FlatDirective::new( - vec![name.clone()], + vec![name], Solver::Xor, vec![x.clone(), y.clone()], )), @@ -1016,17 +1061,16 @@ impl<'ast, T: Field> Flattener<'ast, T> { fn euclidean_division( &mut self, - symbols: &ZirFunctionSymbols<'ast, T>, statements_flattened: &mut FlatStatements, target_bitwidth: UBitwidth, left: UExpression<'ast, T>, right: UExpression<'ast, T>, ) -> (FlatExpression, FlatExpression) { let left_flattened = self - .flatten_uint_expression(symbols, statements_flattened, left) + .flatten_uint_expression(statements_flattened, left) .get_field_unchecked(); let right_flattened = self - .flatten_uint_expression(symbols, statements_flattened, right) + .flatten_uint_expression(statements_flattened, right) .get_field_unchecked(); let n = if left_flattened.is_linear() { left_flattened @@ -1056,7 +1100,7 @@ impl<'ast, T: Field> Flattener<'ast, T> { // assert(invd * d == 1) statements_flattened.push(FlatStatement::Condition( FlatExpression::Number(T::one()), - FlatExpression::Mult(box invd.into(), box d.clone().into()), + FlatExpression::Mult(box invd.into(), box d.clone()), )); // now introduce the quotient and remainder @@ -1065,7 +1109,7 @@ impl<'ast, T: Field> Flattener<'ast, T> { statements_flattened.push(FlatStatement::Directive(FlatDirective { inputs: vec![n.clone(), d.clone()], - outputs: vec![q.clone(), r.clone()], + outputs: vec![q, r], solver: Solver::EuclideanDiv, })); @@ -1088,8 +1132,8 @@ impl<'ast, T: Field> Flattener<'ast, T> { // r < d <=> r - d + 2**w < 2**w let _ = self.get_bits( FlatUExpression::with_field(FlatExpression::Add( - box FlatExpression::Sub(box r.into(), box d.clone().into()), - box FlatExpression::Number(T::from(2usize.pow(target_bitwidth.to_usize() as u32))), + box FlatExpression::Sub(box r.into(), box d.clone()), + box FlatExpression::Number(T::from(2_u128.pow(target_bitwidth.to_usize() as u32))), )), target_bitwidth.to_usize(), target_bitwidth, @@ -1109,19 +1153,17 @@ impl<'ast, T: Field> Flattener<'ast, T> { /// /// # Arguments /// - /// * `symbols` - Available functions in this context /// * `statements_flattened` - Vector where new flattened statements can be added. /// * `expr` - `UExpression` that will be flattened. fn flatten_uint_expression( &mut self, - symbols: &ZirFunctionSymbols<'ast, T>, statements_flattened: &mut FlatStatements, expr: UExpression<'ast, T>, ) -> FlatUExpression { // the bitwidth for this type of uint (8, 16 or 32) let target_bitwidth = expr.bitwidth; - let metadata = expr.metadata.clone().unwrap().clone(); + let metadata = expr.metadata.clone().unwrap(); // the bitwidth on which this value is currently represented let actual_bitwidth = metadata.bitwidth() as usize; @@ -1136,7 +1178,7 @@ impl<'ast, T: Field> Flattener<'ast, T> { FlatUExpression::with_field(FlatExpression::Number(T::from(x as usize))) } // force to be a field element UExpressionInner::Identifier(x) => { - let field = FlatExpression::Identifier(self.layout.get(&x).unwrap().clone()); + let field = FlatExpression::Identifier(*self.layout.get(&x).unwrap()); let bits = self.bits_cache.get(&field).map(|bits| { assert_eq!(bits.len(), target_bitwidth.to_usize()); bits.clone() @@ -1144,7 +1186,7 @@ impl<'ast, T: Field> Flattener<'ast, T> { FlatUExpression::with_field(field).bits(bits) } UExpressionInner::Not(box e) => { - let e = self.flatten_uint_expression(symbols, statements_flattened, e); + let e = self.flatten_uint_expression(statements_flattened, e); let e_bits = e.bits.unwrap(); @@ -1165,11 +1207,11 @@ impl<'ast, T: Field> Flattener<'ast, T> { } UExpressionInner::Add(box left, box right) => { let left_flattened = self - .flatten_uint_expression(symbols, statements_flattened, left) + .flatten_uint_expression(statements_flattened, left) .get_field_unchecked(); let right_flattened = self - .flatten_uint_expression(symbols, statements_flattened, right) + .flatten_uint_expression(statements_flattened, right) .get_field_unchecked(); let new_left = if left_flattened.is_linear() { @@ -1196,10 +1238,10 @@ impl<'ast, T: Field> Flattener<'ast, T> { ); let left_flattened = self - .flatten_uint_expression(symbols, statements_flattened, left) + .flatten_uint_expression(statements_flattened, left) .get_field_unchecked(); let right_flattened = self - .flatten_uint_expression(symbols, statements_flattened, right) + .flatten_uint_expression(statements_flattened, right) .get_field_unchecked(); let new_left = if left_flattened.is_linear() { left_flattened @@ -1222,15 +1264,19 @@ impl<'ast, T: Field> Flattener<'ast, T> { )) } UExpressionInner::LeftShift(box e, box by) => { - let e = self.flatten_uint_expression(symbols, statements_flattened, e); - - let by = match by { - FieldElementExpression::Number(n) => { - n.to_dec_string().parse::().unwrap() - } - _ => unreachable!(), + assert_eq!(by.bitwidth(), UBitwidth::B32); + + let by = match by.into_inner() { + UExpressionInner::Value(n) => n, + by => unimplemented!( + "Variable shifts are unimplemented, found {} << {}", + e, + by.annotate(UBitwidth::B32) + ), }; + let e = self.flatten_uint_expression(statements_flattened, e); + let e_bits = e.bits.unwrap(); assert_eq!(e_bits.len(), target_bitwidth.to_usize()); @@ -1238,44 +1284,48 @@ impl<'ast, T: Field> Flattener<'ast, T> { FlatUExpression::with_bits( e_bits .into_iter() - .skip(by) + .skip(by as usize) .chain( - (0..std::cmp::min(by, target_bitwidth.to_usize())) + (0..std::cmp::min(by as usize, target_bitwidth.to_usize())) .map(|_| FlatExpression::Number(T::from(0))), ) .collect::>(), ) } UExpressionInner::RightShift(box e, box by) => { - let e = self.flatten_uint_expression(symbols, statements_flattened, e); - - let by = match by { - FieldElementExpression::Number(n) => { - n.to_dec_string().parse::().unwrap() - } - _ => unreachable!(), + assert_eq!(by.bitwidth(), UBitwidth::B32); + + let by = match by.into_inner() { + UExpressionInner::Value(n) => n, + by => unimplemented!( + "Variable shifts are unimplemented, found {} >> {}", + e, + by.annotate(UBitwidth::B32) + ), }; + let e = self.flatten_uint_expression(statements_flattened, e); + let e_bits = e.bits.unwrap(); assert_eq!(e_bits.len(), target_bitwidth.to_usize()); FlatUExpression::with_bits( - (0..std::cmp::min(by, target_bitwidth.to_usize())) + (0..std::cmp::min(by as usize, target_bitwidth.to_usize())) .map(|_| FlatExpression::Number(T::from(0))) .chain(e_bits.into_iter().take( target_bitwidth.to_usize() - - std::cmp::min(by, target_bitwidth.to_usize()), + - std::cmp::min(by as usize, target_bitwidth.to_usize()), )) .collect::>(), ) } UExpressionInner::Mult(box left, box right) => { let left_flattened = self - .flatten_uint_expression(symbols, statements_flattened, left) + .flatten_uint_expression(statements_flattened, left) .get_field_unchecked(); let right_flattened = self - .flatten_uint_expression(symbols, statements_flattened, right) + .flatten_uint_expression(statements_flattened, right) .get_field_unchecked(); let new_left = if left_flattened.is_linear() { left_flattened @@ -1302,36 +1352,24 @@ impl<'ast, T: Field> Flattener<'ast, T> { FlatUExpression::with_field(FlatExpression::Identifier(res)) } UExpressionInner::Div(box left, box right) => { - let (q, _) = self.euclidean_division( - symbols, - statements_flattened, - target_bitwidth, - left, - right, - ); + let (q, _) = + self.euclidean_division(statements_flattened, target_bitwidth, left, right); FlatUExpression::with_field(q) } UExpressionInner::Rem(box left, box right) => { - let (_, r) = self.euclidean_division( - symbols, - statements_flattened, - target_bitwidth, - left, - right, - ); + let (_, r) = + self.euclidean_division(statements_flattened, target_bitwidth, left, right); FlatUExpression::with_field(r) } UExpressionInner::IfElse(box condition, box consequence, box alternative) => self .flatten_if_else_expression( - symbols, statements_flattened, condition, consequence, alternative, - ) - .clone(), + ), UExpressionInner::Xor(box left, box right) => { let left_metadata = left.metadata.clone().unwrap(); let right_metadata = right.metadata.clone().unwrap(); @@ -1339,12 +1377,9 @@ impl<'ast, T: Field> Flattener<'ast, T> { 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()) { - let a_flattened = - self.flatten_uint_expression(symbols, statements_flattened, a); - let b_flattened = - self.flatten_uint_expression(symbols, statements_flattened, b); - let c_flattened = - self.flatten_uint_expression(symbols, statements_flattened, c); + 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); let a_bits = a_flattened.bits.unwrap(); let b_bits = b_flattened.bits.unwrap(); @@ -1361,7 +1396,7 @@ impl<'ast, T: Field> Flattener<'ast, T> { statements_flattened.extend(vec![ FlatStatement::Directive(FlatDirective::new( - vec![ch.clone()], + vec![ch], Solver::ShaCh, vec![a.clone(), b.clone(), c.clone()], )), @@ -1380,7 +1415,6 @@ impl<'ast, T: Field> Flattener<'ast, T> { FlatUExpression::with_bits(res) } else { self.default_xor( - symbols, statements_flattened, UExpressionInner::And(box a, box b) .annotate(target_bitwidth) @@ -1402,21 +1436,12 @@ impl<'ast, T: Field> Flattener<'ast, T> { UExpressionInner::And(box bb, box cc), ) => { if (aa == a) && (bb == b) && (cc == c) { - let a_flattened = self.flatten_uint_expression( - symbols, - statements_flattened, - a, - ); - let b_flattened = self.flatten_uint_expression( - symbols, - statements_flattened, - b, - ); - let c_flattened = self.flatten_uint_expression( - symbols, - statements_flattened, - c, - ); + 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); let a_bits = a_flattened.bits.unwrap(); let b_bits = b_flattened.bits.unwrap(); @@ -1435,7 +1460,7 @@ impl<'ast, T: Field> Flattener<'ast, T> { statements_flattened.extend(vec![ FlatStatement::Directive(FlatDirective::new( - vec![maj.clone()], + vec![maj], Solver::ShaAndXorAndXorAnd, vec![a.clone(), b.clone(), c.clone()], )), @@ -1470,7 +1495,6 @@ impl<'ast, T: Field> Flattener<'ast, T> { FlatUExpression::with_bits(res) } else { self.default_xor( - symbols, statements_flattened, UExpressionInner::Xor( box UExpressionInner::And(box a, box b) @@ -1489,7 +1513,6 @@ impl<'ast, T: Field> Flattener<'ast, T> { } } (a, b, c) => self.default_xor( - symbols, statements_flattened, UExpressionInner::Xor( box a.annotate(target_bitwidth).metadata(a_metadata), @@ -1502,7 +1525,6 @@ impl<'ast, T: Field> Flattener<'ast, T> { } } (left_i, right_i) => self.default_xor( - symbols, statements_flattened, left_i.annotate(target_bitwidth).metadata(left_metadata), right_i.annotate(target_bitwidth).metadata(right_metadata), @@ -1510,11 +1532,9 @@ impl<'ast, T: Field> Flattener<'ast, T> { } } UExpressionInner::And(box left, box right) => { - let left_flattened = - self.flatten_uint_expression(symbols, statements_flattened, left); + let left_flattened = self.flatten_uint_expression(statements_flattened, left); - let right_flattened = - self.flatten_uint_expression(symbols, statements_flattened, right); + let right_flattened = self.flatten_uint_expression(statements_flattened, right); let left_bits = left_flattened.bits.unwrap(); let right_bits = right_flattened.bits.unwrap(); @@ -1547,10 +1567,8 @@ impl<'ast, T: Field> Flattener<'ast, T> { FlatUExpression::with_bits(and) } UExpressionInner::Or(box left, box right) => { - let left_flattened = - self.flatten_uint_expression(symbols, statements_flattened, left); - let right_flattened = - self.flatten_uint_expression(symbols, statements_flattened, right); + let left_flattened = self.flatten_uint_expression(statements_flattened, left); + let right_flattened = self.flatten_uint_expression(statements_flattened, right); let left_bits = left_flattened.bits.unwrap(); let right_bits = right_flattened.bits.unwrap(); @@ -1579,7 +1597,7 @@ impl<'ast, T: Field> Flattener<'ast, T> { statements_flattened.extend(vec![ FlatStatement::Directive(FlatDirective::new( - vec![name.clone()], + vec![name], Solver::Or, vec![x.clone(), y.clone()], )), @@ -1622,7 +1640,7 @@ impl<'ast, T: Field> Flattener<'ast, T> { box FlatExpression::Number( T::from(2).pow(target_bitwidth.to_usize() - index - 1), ), - box bit.clone().into(), + box bit.clone(), ), ) }, @@ -1652,23 +1670,19 @@ impl<'ast, T: Field> Flattener<'ast, T> { assert!(to < T::get_required_bits()); // constants do not require directives - match e.field { - Some(FlatExpression::Number(ref x)) => { - let solver = Solver::bits(to); - let bits: Vec<_> = solver - .execute(&vec![x.clone()]) - .unwrap() - .into_iter() - .map(|x| FlatExpression::Number(x)) - .collect(); - - assert_eq!(bits.len(), to); - - self.bits_cache - .insert(e.field.clone().unwrap(), bits.clone()); - return bits; - } - _ => {} + if let Some(FlatExpression::Number(ref x)) = e.field { + let bits: Vec<_> = Interpreter::default() + .execute_solver(&Solver::bits(to), &[x.clone()]) + .unwrap() + .into_iter() + .map(FlatExpression::Number) + .collect(); + + assert_eq!(bits.len(), to); + + self.bits_cache + .insert(e.field.clone().unwrap(), bits.clone()); + return bits; }; e.bits.clone().unwrap_or_else(|| { @@ -1679,7 +1693,7 @@ impl<'ast, T: Field> Flattener<'ast, T> { let from = std::cmp::max(from, to); match self.bits_cache.entry(e.field.clone().unwrap()) { Entry::Occupied(entry) => { - let res: Vec<_> = entry.get().clone().into_iter().map(|e| e.into()).collect(); + let res: Vec<_> = entry.get().clone(); // if we already know a decomposition, it has to be of the size of the target bitwidth assert_eq!(res.len(), to); res @@ -1692,21 +1706,15 @@ impl<'ast, T: Field> Flattener<'ast, T> { vec![e.field.clone().unwrap()], ))); - let bits: Vec<_> = bits - .into_iter() - .map(|b| FlatExpression::Identifier(b)) - .collect(); + let bits: Vec<_> = bits.into_iter().map(FlatExpression::Identifier).collect(); // decompose to the actual bitwidth // bit checks - statements_flattened.extend((0..from).map(|i| { + statements_flattened.extend(bits.iter().take(from).map(|bit| { FlatStatement::Condition( - bits[i].clone(), - FlatExpression::Mult( - box bits[i].clone().into(), - box bits[i].clone().into(), - ), + bit.clone(), + FlatExpression::Mult(box bit.clone(), box bit.clone()), ) })); @@ -1726,7 +1734,7 @@ impl<'ast, T: Field> Flattener<'ast, T> { self.bits_cache.insert(e.field.unwrap(), bits.clone()); self.bits_cache.insert(sum, bits.clone()); - bits.into_iter().map(|v| v.into()).collect() + bits } } }) @@ -1736,25 +1744,21 @@ impl<'ast, T: Field> Flattener<'ast, T> { /// /// # Arguments /// - /// * `symbols` - Available functions in this context /// * `statements_flattened` - Vector where new flattened statements can be added. /// * `expr` - `FieldElementExpression` that will be flattened. fn flatten_field_expression( &mut self, - symbols: &ZirFunctionSymbols<'ast, T>, statements_flattened: &mut FlatStatements, expr: FieldElementExpression<'ast, T>, ) -> FlatExpression { match expr { FieldElementExpression::Number(x) => FlatExpression::Number(x), // force to be a field element FieldElementExpression::Identifier(x) => { - FlatExpression::Identifier(self.layout.get(&x).unwrap().clone()) + FlatExpression::Identifier(*self.layout.get(&x).unwrap_or_else(|| panic!("{}", x))) } FieldElementExpression::Add(box left, box right) => { - let left_flattened = - self.flatten_field_expression(symbols, statements_flattened, left); - let right_flattened = - self.flatten_field_expression(symbols, statements_flattened, right); + let left_flattened = self.flatten_field_expression(statements_flattened, left); + let right_flattened = self.flatten_field_expression(statements_flattened, right); let new_left = if left_flattened.is_linear() { left_flattened } else { @@ -1772,10 +1776,8 @@ impl<'ast, T: Field> Flattener<'ast, T> { FlatExpression::Add(box new_left, box new_right) } FieldElementExpression::Sub(box left, box right) => { - let left_flattened = - self.flatten_field_expression(symbols, statements_flattened, left); - let right_flattened = - self.flatten_field_expression(symbols, statements_flattened, right); + let left_flattened = self.flatten_field_expression(statements_flattened, left); + let right_flattened = self.flatten_field_expression(statements_flattened, right); let new_left = if left_flattened.is_linear() { left_flattened @@ -1795,10 +1797,8 @@ impl<'ast, T: Field> Flattener<'ast, T> { FlatExpression::Sub(box new_left, box new_right) } FieldElementExpression::Mult(box left, box right) => { - let left_flattened = - self.flatten_field_expression(symbols, statements_flattened, left); - let right_flattened = - self.flatten_field_expression(symbols, statements_flattened, right); + let left_flattened = self.flatten_field_expression(statements_flattened, left); + let right_flattened = self.flatten_field_expression(statements_flattened, right); let new_left = if left_flattened.is_linear() { left_flattened } else { @@ -1816,10 +1816,8 @@ impl<'ast, T: Field> Flattener<'ast, T> { FlatExpression::Mult(box new_left, box new_right) } FieldElementExpression::Div(box left, box right) => { - let left_flattened = - self.flatten_field_expression(symbols, statements_flattened, left); - let right_flattened = - self.flatten_field_expression(symbols, statements_flattened, right); + let left_flattened = self.flatten_field_expression(statements_flattened, left); + let right_flattened = self.flatten_field_expression(statements_flattened, right); let new_left: FlatExpression = { let id = self.use_sym(); statements_flattened.push(FlatStatement::Definition(id, left_flattened)); @@ -1844,7 +1842,7 @@ impl<'ast, T: Field> Flattener<'ast, T> { // assert(invb * b == 1) statements_flattened.push(FlatStatement::Condition( FlatExpression::Number(T::one()), - FlatExpression::Mult(box invb.into(), box new_right.clone().into()), + FlatExpression::Mult(box invb.into(), box new_right.clone()), )); // # c = a/b @@ -1856,28 +1854,23 @@ impl<'ast, T: Field> Flattener<'ast, T> { // assert(c * b == a) statements_flattened.push(FlatStatement::Condition( - new_left.into(), + new_left, FlatExpression::Mult(box new_right, box inverse.into()), )); inverse.into() } FieldElementExpression::Pow(box base, box exponent) => { - match exponent { - FieldElementExpression::Number(ref e) => { + match exponent.into_inner() { + UExpressionInner::Value(ref e) => { // flatten the base expression - let base_flattened = self.flatten_field_expression( - symbols, - statements_flattened, - base.clone(), - ); + let base_flattened = + self.flatten_field_expression(statements_flattened, base.clone()); // we require from the base to be linear // TODO change that assert!(base_flattened.is_linear()); - let e = e.to_dec_string().parse::().unwrap(); - // convert the exponent to bytes, big endian let ebytes_be = e.to_be_bytes(); // convert the bytes to bits, remove leading zeroes (we only need powers up to the highest non-zero bit) @@ -1906,16 +1899,16 @@ impl<'ast, T: Field> Flattener<'ast, T> { let id = self.use_sym(); // set it to the square of the previous one, stored in state statements_flattened.push(FlatStatement::Definition( - id.clone(), + id, FlatExpression::Mult( box previous.clone(), box previous.clone(), ), )); // store it in the state for later squaring - *state = Some(FlatExpression::Identifier(id.clone())); + *state = Some(FlatExpression::Identifier(id)); // return it for later use constructing the result - Some(FlatExpression::Identifier(id.clone())) + Some(FlatExpression::Identifier(id)) } } }) @@ -1943,14 +1936,12 @@ impl<'ast, T: Field> Flattener<'ast, T> { } FieldElementExpression::IfElse(box condition, box consequence, box alternative) => self .flatten_if_else_expression( - symbols, statements_flattened, condition, consequence, alternative, ) - .get_field_unchecked() - .clone(), + .get_field_unchecked(), } } @@ -1958,12 +1949,10 @@ impl<'ast, T: Field> Flattener<'ast, T> { /// /// # Arguments /// - /// * `symbols` - Available functions in this context /// * `statements_flattened` - Vector where new flattened statements can be added. /// * `stat` - `ZirStatement` that will be flattened. fn flatten_statement( &mut self, - symbols: &ZirFunctionSymbols<'ast, T>, statements_flattened: &mut FlatStatements, stat: ZirStatement<'ast, T>, ) { @@ -1971,7 +1960,7 @@ impl<'ast, T: Field> Flattener<'ast, T> { ZirStatement::Return(exprs) => { let flat_expressions = exprs .into_iter() - .map(|expr| self.flatten_expression(symbols, statements_flattened, expr)) + .map(|expr| self.flatten_expression(statements_flattened, expr)) .map(|x| x.get_field_unchecked()) .collect::>(); @@ -1981,13 +1970,12 @@ impl<'ast, T: Field> Flattener<'ast, T> { } ZirStatement::Declaration(_) => { // declarations have already been checked - () } ZirStatement::Definition(assignee, expr) => { // define n variables with n the number of primitive types for v_type // assign them to the n primitive types for expr - let rhs = self.flatten_expression(symbols, statements_flattened, expr); + let rhs = self.flatten_expression(statements_flattened, expr); let bits = rhs.bits.clone(); @@ -2007,12 +1995,9 @@ impl<'ast, T: Field> Flattener<'ast, T> { }; // register bits - match bits { - Some(bits) => { - self.bits_cache - .insert(FlatExpression::Identifier(var), bits); - } - None => {} + if let Some(bits) = bits { + self.bits_cache + .insert(FlatExpression::Identifier(var), bits); } } ZirStatement::Assertion(e) => { @@ -2020,39 +2005,36 @@ impl<'ast, T: Field> Flattener<'ast, T> { BooleanExpression::And(..) => { for boolean in e.into_conjunction_iterator() { self.flatten_statement( - symbols, statements_flattened, ZirStatement::Assertion(boolean), ) } } BooleanExpression::FieldEq(box lhs, box rhs) => { - let lhs = self.flatten_field_expression(symbols, statements_flattened, lhs); - let rhs = self.flatten_field_expression(symbols, statements_flattened, rhs); + let lhs = self.flatten_field_expression(statements_flattened, lhs); + let rhs = self.flatten_field_expression(statements_flattened, rhs); self.flatten_equality(statements_flattened, lhs, rhs) } BooleanExpression::UintEq(box lhs, box rhs) => { let lhs = self - .flatten_uint_expression(symbols, statements_flattened, lhs) + .flatten_uint_expression(statements_flattened, lhs) .get_field_unchecked(); let rhs = self - .flatten_uint_expression(symbols, statements_flattened, rhs) + .flatten_uint_expression(statements_flattened, rhs) .get_field_unchecked(); self.flatten_equality(statements_flattened, lhs, rhs) } BooleanExpression::BoolEq(box lhs, box rhs) => { - let lhs = - self.flatten_boolean_expression(symbols, statements_flattened, lhs); - let rhs = - self.flatten_boolean_expression(symbols, statements_flattened, rhs); + let lhs = self.flatten_boolean_expression(statements_flattened, lhs); + let rhs = self.flatten_boolean_expression(statements_flattened, rhs); self.flatten_equality(statements_flattened, lhs, rhs) } _ => { // naive approach: flatten the boolean to a single field element and constrain it to 1 - let e = self.flatten_boolean_expression(symbols, statements_flattened, e); + let e = self.flatten_boolean_expression(statements_flattened, e); if e.is_linear() { statements_flattened.push(FlatStatement::Condition( @@ -2073,20 +2055,19 @@ impl<'ast, T: Field> Flattener<'ast, T> { // flatten the right side to p = sum(var_i.type.primitive_count) expressions // define p new variables to the right side expressions - let var_types = vars.iter().map(|v| v.get_type()).collect(); - match rhs { - ZirExpressionList::FunctionCall(key, exprs, _) => { - let rhs_flattened = self.flatten_function_call( - symbols, + ZirExpressionList::EmbedCall(embed, generics, exprs) => { + let rhs_flattened = self.flatten_embed_call( statements_flattened, - &key.id, - var_types, + embed, + generics, exprs.clone(), ); let rhs = rhs_flattened.into_iter(); + assert_eq!(vars.len(), rhs.len()); + let vars: Vec<_> = vars .into_iter() .zip(rhs) @@ -2103,15 +2084,21 @@ impl<'ast, T: Field> Flattener<'ast, T> { }) .collect(); - if ["_U32_FROM_BITS", "_U16_FROM_BITS", "_U8_FROM_BITS"].contains(&key.id) { - let bits = exprs - .into_iter() - .map(|e| { - self.flatten_expression(symbols, statements_flattened, e) - .get_field_unchecked() - }) - .collect(); - self.bits_cache.insert(vars[0].clone().into(), bits); + match embed { + FlatEmbed::U64FromBits + | FlatEmbed::U32FromBits + | FlatEmbed::U16FromBits + | FlatEmbed::U8FromBits => { + let bits = exprs + .into_iter() + .map(|e| { + self.flatten_expression(statements_flattened, e) + .get_field_unchecked() + }) + .collect(); + self.bits_cache.insert(vars[0].clone().into(), bits); + } + _ => {} } } } @@ -2122,13 +2109,8 @@ impl<'ast, T: Field> Flattener<'ast, T> { /// Flattens a function /// /// # Arguments - /// * `symbols` - Available functions in in this context /// * `funct` - `ZirFunction` that will be flattened - fn flatten_function( - &mut self, - symbols: &ZirFunctionSymbols<'ast, T>, - funct: ZirFunction<'ast, T>, - ) -> FlatFunction { + fn flatten_function(&mut self, funct: ZirFunction<'ast, T>) -> FlatFunction { self.layout = HashMap::new(); self.next_var_idx = 0; @@ -2143,7 +2125,7 @@ impl<'ast, T: Field> Flattener<'ast, T> { // flatten statements in functions and apply substitution for stat in funct.statements { - self.flatten_statement(symbols, &mut statements_flattened, stat); + self.flatten_statement(&mut statements_flattened, stat); } FlatFunction { @@ -2158,28 +2140,8 @@ impl<'ast, T: Field> Flattener<'ast, T> { /// /// * `prog` - `ZirProgram` that will be flattened. fn flatten_program(&mut self, prog: ZirProgram<'ast, T>) -> FlatProg { - let mut prog = prog; - - let mut main_module = prog.modules.remove(&prog.main).unwrap(); - - let main_key = main_module - .functions - .keys() - .find(|k| k.id == "main") - .unwrap() - .clone(); - - let main = main_module.functions.remove(&main_key).unwrap(); - - let symbols = &main_module.functions; - - let main_flattened = match main { - ZirFunctionSymbol::Here(f) => self.flatten_function(&symbols, f), - _ => unreachable!("main should be a typed function locally"), - }; - FlatProg { - main: main_flattened, + main: self.flatten_function(prog.main), } } @@ -2243,7 +2205,7 @@ impl<'ast, T: Field> Flattener<'ast, T> { fn use_variable(&mut self, variable: &Variable<'ast>) -> FlatVariable { let var = self.issue_new_variable(); - self.layout.insert(variable.id.clone(), var.clone()); + self.layout.insert(variable.id.clone(), var); var } @@ -2313,19 +2275,6 @@ impl<'ast, T: Field> Flattener<'ast, T> { fn use_sym(&mut self) -> FlatVariable { self.issue_new_variable() } - - fn get_embed<'a>( - &mut self, - key: &'a FunctionKey<'ast>, - symbols: &'a ZirFunctionSymbols<'ast, T>, - ) -> crate::embed::FlatEmbed { - let f = symbols.get(&key).expect(&format!("{}", key.id)).clone(); - let res = match f { - ZirFunctionSymbol::Flat(flat_function) => flat_function, - _ => unreachable!("only local flat symbols can be flattened"), - }; - res - } } #[cfg(test)] @@ -2371,7 +2320,7 @@ mod tests { let config = CompileConfig::default(); let mut flattener = Flattener::new(&config); - let flat = flattener.flatten_function(&HashMap::new(), function); + let flat = flattener.flatten_function(function); let expected = FlatFunction { arguments: vec![], statements: vec![ @@ -2435,7 +2384,7 @@ mod tests { let config = CompileConfig::default(); let mut flattener = Flattener::new(&config); - let flat = flattener.flatten_function(&HashMap::new(), function); + let flat = flattener.flatten_function(function); let expected = FlatFunction { arguments: vec![], statements: vec![ @@ -2503,7 +2452,7 @@ mod tests { let config = CompileConfig::default(); let mut flattener = Flattener::new(&config); - let flat = flattener.flatten_function(&HashMap::new(), function); + let flat = flattener.flatten_function(function); let expected = FlatFunction { arguments: vec![], statements: vec![ @@ -2560,7 +2509,7 @@ mod tests { let config = CompileConfig::default(); let mut flattener = Flattener::new(&config); - let flat = flattener.flatten_function(&HashMap::new(), function); + let flat = flattener.flatten_function(function); let expected = FlatFunction { arguments: vec![], statements: vec![ @@ -2630,7 +2579,7 @@ mod tests { let config = CompileConfig::default(); let mut flattener = Flattener::new(&config); - let flat = flattener.flatten_function(&HashMap::new(), function); + let flat = flattener.flatten_function(function); let expected = FlatFunction { arguments: vec![], statements: vec![ @@ -2704,7 +2653,7 @@ mod tests { let config = CompileConfig::default(); let mut flattener = Flattener::new(&config); - let flat = flattener.flatten_function(&HashMap::new(), function); + let flat = flattener.flatten_function(function); let expected = FlatFunction { arguments: vec![], statements: vec![ @@ -2788,7 +2737,7 @@ mod tests { let config = CompileConfig::default(); let mut flattener = Flattener::new(&config); - let flat = flattener.flatten_function(&HashMap::new(), function); + let flat = flattener.flatten_function(function); let expected = FlatFunction { arguments: vec![], statements: vec![ @@ -2850,7 +2799,7 @@ mod tests { Variable::field_element("b"), FieldElementExpression::Pow( box FieldElementExpression::Identifier("a".into()), - box FieldElementExpression::Number(Bn128Field::from(0)), + box 0u32.into(), ) .into(), ), @@ -2882,7 +2831,7 @@ mod tests { ], }; - let flattened = flattener.flatten_function(&mut HashMap::new(), function); + let flattened = flattener.flatten_function(function); assert_eq!(flattened, expected); } @@ -2910,7 +2859,7 @@ mod tests { Variable::field_element("b"), FieldElementExpression::Pow( box FieldElementExpression::Identifier("a".into()), - box FieldElementExpression::Number(Bn128Field::from(1)), + box 1u32.into(), ) .into(), ), @@ -2945,7 +2894,7 @@ mod tests { ], }; - let flattened = flattener.flatten_function(&mut HashMap::new(), function); + let flattened = flattener.flatten_function(function); assert_eq!(flattened, expected); } @@ -2990,7 +2939,7 @@ mod tests { Variable::field_element("b"), FieldElementExpression::Pow( box FieldElementExpression::Identifier("a".into()), - box FieldElementExpression::Number(Bn128Field::from(13)), + box 13u32.into(), ) .into(), ), @@ -3060,7 +3009,7 @@ mod tests { ], }; - let flattened = flattener.flatten_function(&mut HashMap::new(), function); + let flattened = flattener.flatten_function(function); assert_eq!(flattened, expected); } @@ -3079,33 +3028,25 @@ mod tests { let mut flattener = Flattener::new(&config); - flattener.flatten_field_expression(&HashMap::new(), &mut FlatStatements::new(), expression); + flattener.flatten_field_expression(&mut FlatStatements::new(), expression); } #[test] fn geq_leq() { let config = CompileConfig::default(); let mut flattener = Flattener::new(&config); - let expression_le = BooleanExpression::Le( + let expression_le = BooleanExpression::FieldLe( box FieldElementExpression::Number(Bn128Field::from(32)), box FieldElementExpression::Number(Bn128Field::from(4)), ); - flattener.flatten_boolean_expression( - &HashMap::new(), - &mut FlatStatements::new(), - expression_le, - ); + flattener.flatten_boolean_expression(&mut FlatStatements::new(), expression_le); let mut flattener = Flattener::new(&config); - let expression_ge = BooleanExpression::Ge( + let expression_ge = BooleanExpression::FieldGe( box FieldElementExpression::Number(Bn128Field::from(32)), box FieldElementExpression::Number(Bn128Field::from(4)), ); - flattener.flatten_boolean_expression( - &HashMap::new(), - &mut FlatStatements::new(), - expression_ge, - ); + flattener.flatten_boolean_expression(&mut FlatStatements::new(), expression_ge); } #[test] @@ -3119,7 +3060,7 @@ mod tests { box FieldElementExpression::Number(Bn128Field::from(4)), box FieldElementExpression::Number(Bn128Field::from(4)), ), - box BooleanExpression::Lt( + box BooleanExpression::FieldLt( box FieldElementExpression::Number(Bn128Field::from(4)), box FieldElementExpression::Number(Bn128Field::from(20)), ), @@ -3128,7 +3069,7 @@ mod tests { box FieldElementExpression::Number(Bn128Field::from(51)), ); - flattener.flatten_field_expression(&HashMap::new(), &mut FlatStatements::new(), expression); + flattener.flatten_field_expression(&mut FlatStatements::new(), expression); } #[test] @@ -3155,9 +3096,9 @@ mod tests { .into(), ); - flattener.flatten_statement(&HashMap::new(), &mut statements_flattened, definition); + flattener.flatten_statement(&mut statements_flattened, definition); - flattener.flatten_statement(&HashMap::new(), &mut statements_flattened, statement); + flattener.flatten_statement(&mut statements_flattened, statement); // define b let b = FlatVariable::new(0); diff --git a/zokrates_core/src/imports.rs b/zokrates_core/src/imports.rs index 0f5c622d4..0794645cb 100644 --- a/zokrates_core/src/imports.rs +++ b/zokrates_core/src/imports.rs @@ -42,7 +42,7 @@ impl fmt::Display for Error { let location = self .pos .map(|p| format!("{}", p.0)) - .unwrap_or("?".to_string()); + .unwrap_or_else(|| "?".to_string()); write!(f, "{}\n\t{}", location, self.message) } } @@ -125,19 +125,14 @@ impl<'ast> fmt::Debug for Import<'ast> { } } -pub struct Importer {} +pub struct Importer; impl Importer { - pub fn new() -> Importer { - Importer {} - } - pub fn apply_imports<'ast, T: Field, E: Into>( - &self, destination: Module<'ast>, location: PathBuf, resolver: Option<&dyn Resolver>, - modules: &mut HashMap>, + modules: &mut HashMap>, arena: &'ast Arena, ) -> Result, CompileErrors> { let mut symbols: Vec<_> = vec![]; @@ -179,7 +174,18 @@ impl Importer { symbols.push( SymbolDeclaration { id: &alias, - symbol: Symbol::Flat(FlatEmbed::Unpack(T::get_required_bits())), + symbol: Symbol::Flat(FlatEmbed::Unpack), + } + .start_end(pos.0, pos.1), + ); + } + "EMBED/u64_to_bits" => { + let alias = alias.unwrap_or("u64_to_bits"); + + symbols.push( + SymbolDeclaration { + id: &alias, + symbol: Symbol::Flat(FlatEmbed::U64ToBits), } .start_end(pos.0, pos.1), ); @@ -217,6 +223,17 @@ impl Importer { .start_end(pos.0, pos.1), ); } + "EMBED/u64_from_bits" => { + let alias = alias.unwrap_or("u64_from_bits"); + + symbols.push( + SymbolDeclaration { + id: &alias, + symbol: Symbol::Flat(FlatEmbed::U64FromBits), + } + .start_end(pos.0, pos.1), + ); + } "EMBED/u32_from_bits" => { let alias = alias.unwrap_or("u32_from_bits"); @@ -267,13 +284,15 @@ impl Importer { let alias = import.alias.unwrap_or( std::path::Path::new(import.source) .file_stem() - .ok_or(CompileErrors::from( - CompileErrorInner::ImportError(Error::new(format!( - "Could not determine alias for import {}", - import.source.display() - ))) - .in_file(&location), - ))? + .ok_or_else(|| { + CompileErrors::from( + CompileErrorInner::ImportError(Error::new(format!( + "Could not determine alias for import {}", + import.source.display() + ))) + .in_file(&location), + ) + })? .to_str() .unwrap(), ); @@ -335,7 +354,6 @@ impl Importer { Ok(Module { imports: vec![], symbols, - ..destination }) } } diff --git a/zokrates_core/src/ir/expression.rs b/zokrates_core/src/ir/expression.rs index 3a4261410..57ec27536 100644 --- a/zokrates_core/src/ir/expression.rs +++ b/zokrates_core/src/ir/expression.rs @@ -2,49 +2,36 @@ use crate::flat_absy::FlatVariable; 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)] +#[derive(Debug, Clone, Serialize, Deserialize, Hash, PartialEq, Eq)] pub struct QuadComb { pub left: LinComb, pub right: LinComb, } -impl PartialEq for QuadComb { - fn eq(&self, other: &Self) -> bool { - self.left.eq(&other.left) && self.right.eq(&other.right) - } -} - -impl Eq for QuadComb {} - impl QuadComb { pub fn from_linear_combinations(left: LinComb, right: LinComb) -> Self { QuadComb { left, right } } - pub fn try_linear(&self) -> Option> { - // identify (k * ~ONE) * (lincomb) and return (k * lincomb) - - match self.left.try_summand() { - Some((ref variable, ref coefficient)) if *variable == FlatVariable::one() => { - return Some(self.right.clone() * &coefficient); - } - _ => {} - } - match self.right.try_summand() { - Some((ref variable, ref coefficient)) if *variable == FlatVariable::one() => { - return Some(self.left.clone() * &coefficient); - } - _ => {} - } + 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 if self.left.is_zero() || self.right.is_zero() { - return Some(LinComb::zero()); + return Ok(LinComb::zero()); } - None + match self.left.try_constant() { + 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)), + }, + } } } @@ -66,17 +53,9 @@ impl fmt::Display for QuadComb { } } -#[derive(Clone, Hash, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, Hash, PartialEq, Eq)] pub struct LinComb(pub Vec<(FlatVariable, T)>); -impl PartialEq for LinComb { - fn eq(&self, other: &Self) -> bool { - self.clone().into_canonical() == other.clone().into_canonical() - } -} - -impl Eq for LinComb {} - #[derive(PartialEq, PartialOrd, Clone, Eq, Ord, Hash, Debug, Serialize, Deserialize)] pub struct CanonicalLinComb(pub BTreeMap); @@ -113,36 +92,52 @@ impl LinComb { } pub fn is_zero(&self) -> bool { - self.0.len() == 0 + self.0.is_empty() } } impl LinComb { - pub fn try_summand(&self) -> Option<(FlatVariable, T)> { + pub fn try_constant(self) -> Result { + match self.0.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; + + if first != &FlatVariable::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)) + } else { + Err(self) + } + } + } + } + + pub fn try_summand(self) -> Result<(FlatVariable, T), Self> { match self.0.len() { // if the lincomb is empty, it is not reduceable to a summand - 0 => None, + 0 => Err(self), _ => { // take the first variable in the lincomb let first = &self.0[0].0; - self.0 - .iter() - .map(|element| { + if self.0.iter().all(|element| // all terms must contain the same variable - if element.0 == *first { - // if they do, return the coefficient - Ok(&element.1) - } else { - // otherwise, stop - Err(()) - } - }) - // collect to a Result to short circuit when we hit an error - .collect::>() - // we didn't hit an error, do final processing. It's fine to clone here. - .map(|v: Vec<_>| (first.clone(), v.iter().fold(T::zero(), |acc, e| acc + *e))) - .ok() + element.0 == *first) + { + Ok(( + *first, + self.0.into_iter().fold(T::zero(), |acc, e| acc + e.1), + )) + } else { + Err(self) + } } } } @@ -207,9 +202,7 @@ impl fmt::Display for LinComb { false => write!( f, "{}", - self.clone() - .into_canonical() - .0 + self.0 .iter() .map(|(k, v)| format!("{} * {}", v.to_compact_dec_string(), k)) .collect::>() @@ -251,10 +244,14 @@ impl Mul<&T> for LinComb { type Output = LinComb; fn mul(self, scalar: &T) -> LinComb { + if scalar == &T::one() { + return self; + } + LinComb( self.0 .into_iter() - .map(|(var, coeff)| (var, coeff * scalar)) + .map(|(var, coeff)| (var, coeff * scalar.clone())) .collect(), ) } @@ -262,7 +259,8 @@ impl Mul<&T> for LinComb { impl Div<&T> for LinComb { type Output = LinComb; - + // Clippy warns about multiplication in a method named div. It's okay, here, since we multiply with the inverse. + #[allow(clippy::suspicious_arithmetic_impl)] fn div(self, scalar: &T) -> LinComb { self * &scalar.inverse_mul().unwrap() } @@ -287,7 +285,7 @@ mod tests { fn add() { let a: LinComb = FlatVariable::new(42).into(); let b: LinComb = FlatVariable::new(42).into(); - let c = a + b.clone(); + let c = a + b; let expected_vec = vec![ (FlatVariable::new(42), Bn128Field::from(1)), @@ -300,7 +298,7 @@ mod tests { fn sub() { let a: LinComb = FlatVariable::new(42).into(); let b: LinComb = FlatVariable::new(42).into(); - let c = a - b.clone(); + let c = a - b; let expected_vec = vec![ (FlatVariable::new(42), Bn128Field::from(1)), @@ -314,7 +312,7 @@ mod tests { fn display() { let a: LinComb = LinComb::from(FlatVariable::new(42)) + LinComb::summand(3, FlatVariable::new(21)); - assert_eq!(&a.to_string(), "3 * _21 + 1 * _42"); + assert_eq!(&a.to_string(), "1 * _42 + 3 * _21"); let zero: LinComb = LinComb::zero(); assert_eq!(&zero.to_string(), "0"); } @@ -350,7 +348,7 @@ mod tests { + LinComb::summand(4, FlatVariable::new(33)), right: LinComb::summand(1, FlatVariable::new(21)), }; - assert_eq!(&a.to_string(), "(4 * _33 + 3 * _42) * (1 * _21)"); + assert_eq!(&a.to_string(), "(3 * _42 + 4 * _33) * (1 * _21)"); let a: QuadComb = QuadComb { left: LinComb::zero(), right: LinComb::summand(1, FlatVariable::new(21)), @@ -371,7 +369,7 @@ mod tests { ]); assert_eq!( summand.try_summand(), - Some((FlatVariable::new(42), Bn128Field::from(6))) + Ok((FlatVariable::new(42), Bn128Field::from(6))) ); let not_summand = LinComb(vec![ @@ -379,10 +377,10 @@ mod tests { (FlatVariable::new(42), Bn128Field::from(2)), (FlatVariable::new(42), Bn128Field::from(3)), ]); - assert_eq!(not_summand.try_summand(), None); + assert!(not_summand.try_summand().is_err()); let empty: LinComb = LinComb(vec![]); - assert_eq!(empty.try_summand(), None); + assert!(empty.try_summand().is_err()); } } } diff --git a/zokrates_core/src/ir/from_flat.rs b/zokrates_core/src/ir/from_flat.rs index 90b202da1..ca11d95b7 100644 --- a/zokrates_core/src/ir/from_flat.rs +++ b/zokrates_core/src/ir/from_flat.rs @@ -71,7 +71,7 @@ impl From> for Prog { let main = main.into(); - Prog { private, main } + Prog { main, private } } } @@ -125,7 +125,7 @@ impl From> for Directive { inputs: ds .inputs .into_iter() - .map(|i| QuadComb::from_flat_expression(i)) + .map(QuadComb::from_flat_expression) .collect(), solver: ds.solver, outputs: ds.outputs, diff --git a/zokrates_core/src/ir/interpreter.rs b/zokrates_core/src/ir/interpreter.rs index 183c30d6a..34df954c3 100644 --- a/zokrates_core/src/ir/interpreter.rs +++ b/zokrates_core/src/ir/interpreter.rs @@ -1,10 +1,13 @@ use crate::flat_absy::flat_variable::FlatVariable; use crate::ir::Directive; use crate::ir::{LinComb, Prog, QuadComb, Statement, Witness}; -use crate::solvers::{Executable, Solver}; +use crate::solvers::Solver; +use pairing_ce::bn256::Bn256; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; use std::fmt; +#[cfg(feature = "bellman")] +use zokrates_embed::generate_sha256_round_witness; use zokrates_field::Field; pub type ExecutionResult = Result, Error>; @@ -34,13 +37,13 @@ impl Interpreter { } impl Interpreter { - pub fn execute(&self, program: &Prog, inputs: &Vec) -> ExecutionResult { + pub fn execute(&self, program: &Prog, inputs: &[T]) -> ExecutionResult { let main = &program.main; self.check_inputs(&program, &inputs)?; let mut witness = BTreeMap::new(); witness.insert(FlatVariable::one(), T::one()); for (arg, value) in main.arguments.iter().zip(inputs.iter()) { - witness.insert(arg.clone(), value.clone().into()); + witness.insert(*arg, value.clone()); } for statement in main.statements.iter() { @@ -48,7 +51,7 @@ impl Interpreter { Statement::Constraint(quad, lin) => match lin.is_assignee(&witness) { true => { let val = quad.evaluate(&witness).unwrap(); - witness.insert(lin.0.iter().next().unwrap().0.clone(), val); + witness.insert(lin.0.get(0).unwrap().0, val); } false => { let lhs_value = quad.evaluate(&witness).unwrap(); @@ -76,10 +79,10 @@ impl Interpreter { .iter() .map(|i| i.evaluate(&witness).unwrap()) .collect(); - match d.solver.execute(&inputs) { + match self.execute_solver(&d.solver, &inputs) { Ok(res) => { for (i, o) in d.outputs.iter().enumerate() { - witness.insert(o.clone(), res[i].clone()); + witness.insert(*o, res[i].clone()); } continue; } @@ -107,12 +110,12 @@ impl Interpreter { value.to_biguint() }; - let mut num = input.clone(); + let mut num = input; let mut res = vec![]; let bits = T::get_required_bits(); for i in (0..bits).rev() { if T::from(2).to_biguint().pow(i as usize) <= num { - num = num - T::from(2).to_biguint().pow(i as usize); + num -= T::from(2).to_biguint().pow(i as usize); res.push(T::one()); } else { res.push(T::zero()); @@ -120,11 +123,11 @@ impl Interpreter { } assert_eq!(num, T::zero().to_biguint()); for (i, o) in d.outputs.iter().enumerate() { - witness.insert(o.clone(), res[i].clone()); + witness.insert(*o, res[i].clone()); } } - fn check_inputs(&self, program: &Prog, inputs: &Vec) -> Result<(), Error> { + fn check_inputs(&self, program: &Prog, inputs: &[U]) -> Result<(), Error> { if program.main.arguments.len() == inputs.len() { Ok(()) } else { @@ -134,26 +137,136 @@ impl Interpreter { }) } } + + pub fn execute_solver( + &self, + solver: &Solver, + inputs: &[T], + ) -> Result, String> { + let (expected_input_count, expected_output_count) = solver.get_signature(); + assert!(inputs.len() == expected_input_count); + + let res = match solver { + Solver::ConditionEq => match inputs[0].is_zero() { + true => vec![T::zero(), T::one()], + false => vec![ + T::one(), + T::one().checked_div(&inputs[0]).unwrap_or_else(T::one), + ], + }, + Solver::Bits(bit_width) => { + let mut num = inputs[0].clone(); + let mut res = vec![]; + + for i in (0..*bit_width).rev() { + if T::from(2).pow(i) <= num { + num = num - T::from(2).pow(i); + res.push(T::one()); + } else { + res.push(T::zero()); + } + } + res + } + Solver::Xor => { + let x = inputs[0].clone(); + let y = inputs[1].clone(); + + vec![x.clone() + y.clone() - T::from(2) * x * y] + } + Solver::Or => { + let x = inputs[0].clone(); + let y = inputs[1].clone(); + + vec![x.clone() + y.clone() - x * y] + } + // res = b * c - (2b * c - b - c) * (a) + Solver::ShaAndXorAndXorAnd => { + let a = inputs[0].clone(); + let b = inputs[1].clone(); + let c = inputs[2].clone(); + vec![b.clone() * c.clone() - (T::from(2) * b.clone() * c.clone() - b - c) * a] + } + // res = a(b - c) + c + Solver::ShaCh => { + let a = inputs[0].clone(); + let b = inputs[1].clone(); + let c = inputs[2].clone(); + vec![a * (b - c.clone()) + c] + } + + Solver::Div => vec![inputs[0] + .clone() + .checked_div(&inputs[1]) + .unwrap_or_else(T::one)], + Solver::EuclideanDiv => { + use num::CheckedDiv; + + let n = inputs[0].clone().to_biguint(); + let d = inputs[1].clone().to_biguint(); + + let q = n.checked_div(&d).unwrap_or_else(|| 0u32.into()); + let r = n - d * &q; + vec![T::try_from(q).unwrap(), T::try_from(r).unwrap()] + } + #[cfg(feature = "bellman")] + Solver::Sha256Round => { + use zokrates_field::Bn128Field; + assert_eq!(T::id(), Bn128Field::id()); + let i = &inputs[0..512]; + let h = &inputs[512..]; + let to_fr = |x: &T| { + use pairing_ce::ff::{PrimeField, ScalarEngine}; + let s = x.to_dec_string(); + ::Fr::from_str(&s).unwrap() + }; + let i: Vec<_> = i.iter().map(|x| to_fr(x)).collect(); + let h: Vec<_> = h.iter().map(|x| to_fr(x)).collect(); + assert_eq!(h.len(), 256); + generate_sha256_round_witness::(&i, &h) + .into_iter() + .map(|x| { + use bellman_ce::pairing::ff::{PrimeField, PrimeFieldRepr}; + let mut res: Vec = vec![]; + x.into_repr().write_le(&mut res).unwrap(); + T::from_byte_vector(res) + }) + .collect() + } + }; + + assert_eq!(res.len(), expected_output_count); + + Ok(res) + } } +#[derive(Debug)] +pub struct EvaluationError; + impl LinComb { - fn evaluate(&self, witness: &BTreeMap) -> Result { + fn evaluate(&self, witness: &BTreeMap) -> Result { self.0 .iter() - .map(|(var, mult)| witness.get(var).map(|v| v.clone() * mult).ok_or(())) // get each term + .map(|(var, mult)| { + witness + .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 } fn is_assignee(&self, witness: &BTreeMap) -> bool { self.0.iter().count() == 1 - && self.0.iter().next().unwrap().1 == T::from(1) - && !witness.contains_key(&self.0.iter().next().unwrap().0) + && self.0.get(0).unwrap().1 == T::from(1) + && !witness.contains_key(&self.0.get(0).unwrap().0) } } impl QuadComb { - pub fn evaluate(&self, witness: &BTreeMap) -> Result { + pub fn evaluate(&self, witness: &BTreeMap) -> Result { let left = self.left.evaluate(&witness)?; let right = self.right.evaluate(&witness)?; Ok(left * right) @@ -192,3 +305,83 @@ impl fmt::Debug for Error { write!(f, "{}", self) } } + +#[cfg(test)] +mod tests { + use super::*; + use zokrates_field::Bn128Field; + + mod eq_condition { + + // Wanted: (Y = (X != 0) ? 1 : 0) + // # Y = if X == 0 then 0 else 1 fi + // # M = if X == 0 then 1 else 1/X fi + + use super::*; + + #[test] + fn execute() { + let cond_eq = Solver::ConditionEq; + let inputs = vec![0]; + let interpreter = Interpreter::default(); + let r = interpreter + .execute_solver( + &cond_eq, + &inputs + .iter() + .map(|&i| Bn128Field::from(i)) + .collect::>(), + ) + .unwrap(); + let res: Vec = vec![0, 1].iter().map(|&i| Bn128Field::from(i)).collect(); + assert_eq!(r, &res[..]); + } + + #[test] + fn execute_non_eq() { + let cond_eq = Solver::ConditionEq; + let inputs = vec![1]; + let interpreter = Interpreter::default(); + let r = interpreter + .execute_solver( + &cond_eq, + &inputs + .iter() + .map(|&i| Bn128Field::from(i)) + .collect::>(), + ) + .unwrap(); + let res: Vec = vec![1, 1].iter().map(|&i| Bn128Field::from(i)).collect(); + assert_eq!(r, &res[..]); + } + } + + #[test] + fn bits_of_one() { + let inputs = vec![Bn128Field::from(1)]; + let interpreter = Interpreter::default(); + let res = interpreter + .execute_solver(&Solver::Bits(Bn128Field::get_required_bits()), &inputs) + .unwrap(); + assert_eq!(res[253], Bn128Field::from(1)); + for r in &res[0..253] { + assert_eq!(*r, Bn128Field::from(0)); + } + } + + #[test] + fn bits_of_42() { + let inputs = vec![Bn128Field::from(42)]; + let interpreter = Interpreter::default(); + let res = interpreter + .execute_solver(&Solver::Bits(Bn128Field::get_required_bits()), &inputs) + .unwrap(); + assert_eq!(res[253], Bn128Field::from(0)); + assert_eq!(res[252], Bn128Field::from(1)); + assert_eq!(res[251], Bn128Field::from(0)); + assert_eq!(res[250], Bn128Field::from(1)); + assert_eq!(res[249], Bn128Field::from(0)); + assert_eq!(res[248], Bn128Field::from(1)); + assert_eq!(res[247], Bn128Field::from(0)); + } +} diff --git a/zokrates_core/src/ir/mod.rs b/zokrates_core/src/ir/mod.rs index c120806bb..dfc97f764 100644 --- a/zokrates_core/src/ir/mod.rs +++ b/zokrates_core/src/ir/mod.rs @@ -3,6 +3,7 @@ use crate::flat_absy::FlatVariable; use crate::solvers::Solver; use serde::{Deserialize, Serialize}; use std::fmt; +use std::hash::Hash; use zokrates_field::Field; mod expression; @@ -19,26 +20,12 @@ pub use self::serialize::ProgEnum; pub use self::interpreter::{Error, ExecutionResult, Interpreter}; pub use self::witness::Witness; -#[derive(Debug, Serialize, Deserialize, Clone, Hash)] +#[derive(Debug, Serialize, Deserialize, Clone, Hash, PartialEq, Eq)] pub enum Statement { Constraint(QuadComb, LinComb), Directive(Directive), } -impl PartialEq for Statement { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Statement::Constraint(l1, r1), Statement::Constraint(l2, r2)) => { - l1.eq(l2) && r1.eq(r2) - } - (Statement::Directive(d1), Statement::Directive(d2)) => d1.eq(d2), - _ => false, - } - } -} - -impl Eq for Statement {} - impl Statement { pub fn definition>>(v: FlatVariable, e: U) -> Self { Statement::Constraint(e.into(), v.into()) @@ -49,23 +36,13 @@ impl Statement { } } -#[derive(Clone, Debug, Serialize, Deserialize, Hash)] +#[derive(Clone, Debug, Serialize, Deserialize, Hash, PartialEq, Eq)] pub struct Directive { pub inputs: Vec>, pub outputs: Vec, pub solver: Solver, } -impl PartialEq for Directive { - fn eq(&self, other: &Self) -> bool { - self.inputs.eq(&other.inputs) - && self.outputs.eq(&other.outputs) - && self.solver.eq(&other.solver) - } -} - -impl Eq for Directive {} - impl fmt::Display for Directive { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( @@ -95,7 +72,7 @@ impl fmt::Display for Statement { } } -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone, Hash, PartialEq, Eq)] pub struct Function { pub id: String, pub statements: Vec>, @@ -103,15 +80,6 @@ pub struct Function { pub returns: Vec, } -impl PartialEq for Function { - fn eq(&self, other: &Self) -> bool { - self.id.eq(&other.id) - && self.statements.eq(&other.statements) - && self.arguments.eq(&other.arguments) - && self.returns.eq(&other.returns) - } -} - impl fmt::Display for Function { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( @@ -138,27 +106,18 @@ impl fmt::Display for Function { } } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, Hash, PartialEq, Eq)] pub struct Prog { pub main: Function, pub private: Vec, } -impl PartialEq for Prog { - fn eq(&self, other: &Self) -> bool { - self.main.eq(&other.main) && self.private.eq(&other.private) - } -} - impl Prog { pub fn constraint_count(&self) -> usize { self.main .statements .iter() - .filter(|s| match s { - Statement::Constraint(..) => true, - _ => false, - }) + .filter(|s| matches!(s, Statement::Constraint(..))) .count() } diff --git a/zokrates_core/src/ir/serialize.rs b/zokrates_core/src/ir/serialize.rs index 8b352f326..d97220a4b 100644 --- a/zokrates_core/src/ir/serialize.rs +++ b/zokrates_core/src/ir/serialize.rs @@ -16,9 +16,9 @@ pub enum ProgEnum { impl Prog { pub fn serialize(&self, mut w: W) { - w.write(ZOKRATES_MAGIC).unwrap(); - w.write(ZOKRATES_VERSION_1).unwrap(); - w.write(&T::id()).unwrap(); + w.write_all(ZOKRATES_MAGIC).unwrap(); + w.write_all(ZOKRATES_VERSION_1).unwrap(); + w.write_all(&T::id()).unwrap(); serialize_into(&mut w, self, Infinite).unwrap(); } diff --git a/zokrates_core/src/ir/witness.rs b/zokrates_core/src/ir/witness.rs index 5303bc446..865556b5a 100644 --- a/zokrates_core/src/ir/witness.rs +++ b/zokrates_core/src/ir/witness.rs @@ -138,7 +138,7 @@ mod tests { fn wrong_value() { let mut buff = Cursor::new(vec![]); - buff.write("_1 123bug".as_ref()).unwrap(); + buff.write_all("_1 123bug".as_ref()).unwrap(); buff.set_position(0); assert!(Witness::::read(buff).is_err()); @@ -148,7 +148,7 @@ mod tests { fn wrong_variable() { let mut buff = Cursor::new(vec![]); - buff.write("_1bug 123".as_ref()).unwrap(); + buff.write_all("_1bug 123".as_ref()).unwrap(); buff.set_position(0); assert!(Witness::::read(buff).is_err()); @@ -157,7 +157,7 @@ mod tests { #[test] fn not_csv() { let mut buff = Cursor::new(vec![]); - buff.write("whatwhat".as_ref()).unwrap(); + buff.write_all("whatwhat".as_ref()).unwrap(); buff.set_position(0); assert!(Witness::::read(buff).is_err()); diff --git a/zokrates_core/src/macros.rs b/zokrates_core/src/macros.rs index ff36c1e7d..a6d5b969f 100644 --- a/zokrates_core/src/macros.rs +++ b/zokrates_core/src/macros.rs @@ -19,7 +19,7 @@ impl fmt::Display for Error { } } -pub fn process_macros<'ast, T: Field>(file: File<'ast>) -> Result, Error> { +pub fn process_macros(file: File) -> Result { match &file.pragma { Some(pragma) => { if T::name() != pragma.curve.name { diff --git a/zokrates_core/src/optimizer/canonicalizer.rs b/zokrates_core/src/optimizer/canonicalizer.rs new file mode 100644 index 000000000..69981b05c --- /dev/null +++ b/zokrates_core/src/optimizer/canonicalizer.rs @@ -0,0 +1,10 @@ +use crate::ir::{folder::Folder, LinComb}; +use zokrates_field::Field; + +pub struct Canonicalizer; + +impl Folder for Canonicalizer { + fn fold_linear_combination(&mut self, l: LinComb) -> LinComb { + l.into_canonical().into() + } +} diff --git a/zokrates_core/src/optimizer/directive.rs b/zokrates_core/src/optimizer/directive.rs index b2972046c..d84a72b35 100644 --- a/zokrates_core/src/optimizer/directive.rs +++ b/zokrates_core/src/optimizer/directive.rs @@ -12,10 +12,10 @@ use crate::flat_absy::flat_variable::FlatVariable; use crate::ir::folder::*; use crate::ir::*; +use crate::optimizer::canonicalizer::Canonicalizer; use crate::solvers::Solver; use std::collections::hash_map::{Entry, HashMap}; use zokrates_field::Field; - #[derive(Debug)] pub struct DirectiveOptimizer { calls: HashMap<(Solver, Vec>), Vec>, @@ -37,6 +37,23 @@ impl DirectiveOptimizer { } impl Folder for DirectiveOptimizer { + fn fold_function(&mut self, f: Function) -> Function { + // in order to correcty identify duplicates, we need to first canonicalize the statements + + let mut canonicalizer = Canonicalizer; + + let f = Function { + statements: f + .statements + .into_iter() + .flat_map(|s| canonicalizer.fold_statement(s)) + .collect(), + ..f + }; + + fold_function(self, f) + } + fn fold_statement(&mut self, s: Statement) -> Vec> { match s { Statement::Directive(d) => { @@ -49,7 +66,7 @@ impl Folder for DirectiveOptimizer { } Entry::Occupied(e) => { self.substitution - .extend(d.outputs.into_iter().zip(e.get().into_iter().cloned())); + .extend(d.outputs.into_iter().zip(e.get().iter().cloned())); vec![] } } diff --git a/zokrates_core/src/optimizer/duplicate.rs b/zokrates_core/src/optimizer/duplicate.rs index f72b3a9fc..f5a6aa965 100644 --- a/zokrates_core/src/optimizer/duplicate.rs +++ b/zokrates_core/src/optimizer/duplicate.rs @@ -1,7 +1,8 @@ //! Module containing the `DuplicateOptimizer` to remove duplicate constraints -use crate::ir::folder::Folder; +use crate::ir::folder::*; use crate::ir::*; +use crate::optimizer::canonicalizer::Canonicalizer; use std::collections::{hash_map::DefaultHasher, HashSet}; use zokrates_field::Field; @@ -33,6 +34,22 @@ impl DuplicateOptimizer { } impl Folder for DuplicateOptimizer { + fn fold_function(&mut self, f: Function) -> Function { + // in order to correcty identify duplicates, we need to first canonicalize the statements + let mut canonicalizer = Canonicalizer; + + let f = Function { + statements: f + .statements + .into_iter() + .flat_map(|s| canonicalizer.fold_statement(s)) + .collect(), + ..f + }; + + fold_function(self, f) + } + fn fold_statement(&mut self, s: Statement) -> Vec> { let hashed = hash(&s); let result = match self.seen.get(&hashed) { @@ -120,7 +137,7 @@ mod tests { main: Function { id: "main".to_string(), statements: vec![ - constraint.clone(), + constraint, Statement::Constraint( QuadComb::from_linear_combinations( LinComb::summand(3, FlatVariable::new(42)), diff --git a/zokrates_core/src/optimizer/mod.rs b/zokrates_core/src/optimizer/mod.rs index fb0e34ab1..6fd1088ad 100644 --- a/zokrates_core/src/optimizer/mod.rs +++ b/zokrates_core/src/optimizer/mod.rs @@ -4,6 +4,7 @@ //! @author Thibaut Schaeffer //! @date 2018 +mod canonicalizer; mod directive; mod duplicate; mod redefinition; @@ -26,7 +27,6 @@ impl Prog { // // deduplicate directives which take the same input let r = DirectiveOptimizer::optimize(r); // remove duplicate constraints - let r = DuplicateOptimizer::optimize(r); - r + DuplicateOptimizer::optimize(r) } } diff --git a/zokrates_core/src/optimizer/redefinition.rs b/zokrates_core/src/optimizer/redefinition.rs index c1994eecf..a72f3c07e 100644 --- a/zokrates_core/src/optimizer/redefinition.rs +++ b/zokrates_core/src/optimizer/redefinition.rs @@ -40,7 +40,6 @@ use crate::flat_absy::flat_variable::FlatVariable; use crate::ir::folder::{fold_function, Folder}; use crate::ir::LinComb; use crate::ir::*; -use crate::solvers::Executable; use std::collections::{HashMap, HashSet}; use zokrates_field::Field; @@ -53,7 +52,7 @@ pub struct RedefinitionOptimizer { } impl RedefinitionOptimizer { - fn new() -> RedefinitionOptimizer { + fn new() -> Self { RedefinitionOptimizer { substitution: HashMap::new(), ignore: HashSet::new(), @@ -72,84 +71,77 @@ impl Folder for RedefinitionOptimizer { let quad = self.fold_quadratic_combination(quad); let lin = self.fold_linear_combination(lin); - let (keep_constraint, to_insert, to_ignore) = match lin.try_summand() { - // if the right side is a single variable - Some((variable, coefficient)) => { - match self.ignore.contains(&variable) { - // if the variable isn't tagged as ignored - false => match self.substitution.get(&variable) { - // if the variable is already defined - Some(_) => (true, None, None), - // if the variable is not defined yet - None => match quad.try_linear() { - // if the left side is linear - Some(l) => (false, Some((variable, l / &coefficient)), None), - // if the left side isn't linear - None => (true, None, Some(variable)), - }, - }, - true => (true, None, None), - } - } - None => (true, None, None), + if lin.is_zero() { + return vec![Statement::Constraint(quad, lin)]; + } + + let (constraint, to_insert, to_ignore) = match self.ignore.contains(&lin.0[0].0) + || self.substitution.contains_key(&lin.0[0].0) + { + true => (Some(Statement::Constraint(quad, lin)), None, None), + false => match lin.try_summand() { + // if the right side is a single variable + Ok((variable, coefficient)) => match quad.try_linear() { + // if the left side is linear + Ok(l) => (None, Some((variable, l / &coefficient)), None), + // if the left side isn't linear + Err(quad) => ( + Some(Statement::Constraint( + quad, + LinComb::summand(coefficient, variable), + )), + None, + Some(variable), + ), + }, + Err(l) => (Some(Statement::Constraint(quad, l)), None, None), + }, }; // insert into the ignored set - match to_ignore { - Some(v) => { - self.ignore.insert(v); - } - None => {} + if let Some(v) = to_ignore { + self.ignore.insert(v); } // insert into the substitution map - match to_insert { - Some((k, v)) => { - self.substitution.insert(k, v.into_canonical()); - } - None => {} + if let Some((k, v)) = to_insert { + self.substitution.insert(k, v.into_canonical()); }; // decide whether the constraint should be kept - match keep_constraint { - false => vec![], - true => vec![Statement::Constraint(quad, lin)], + match constraint { + Some(c) => vec![c], + _ => vec![], } } Statement::Directive(d) => { let d = self.fold_directive(d); // check if the inputs are constants, ie reduce to the form `coeff * ~one` - let inputs = d + let inputs: Vec<_> = d .inputs .into_iter() // we need to reduce to the canonical form to interpret `a + 1 - a` as `1` .map(|i| i.reduce()) - .map(|q| match q.try_linear() { - Some(l) => match l.0.len() { - // 0 is constant and can be represented by an empty lincomb - 0 => Ok(T::from(0)), - _ => l - // try to match to a single summand `coeff * v` - .try_summand() - .map(|(variable, coefficient)| match variable { - // v must be ~one - v if v == FlatVariable::one() => Ok(coefficient), - _ => Err(LinComb::summand(coefficient, variable).into()), - }) - .unwrap_or(Err(l.into())), - }, - None => Err(q), + .map(|q| { + match q + .try_linear() + .map(|l| l.try_constant().map_err(|l| l.into())) + { + Ok(r) => r, + Err(e) => Err(e), + } }) .collect::>>>(); - match inputs.iter().all(|r| r.is_ok()) { + match inputs.iter().all(|i| i.is_ok()) { true => { // unwrap inputs to their constant value - let inputs = inputs.into_iter().map(|i| i.unwrap()).collect(); + let inputs: Vec<_> = inputs.into_iter().map(|i| i.unwrap()).collect(); // run the solver - let outputs = d.solver.execute(&inputs).unwrap(); - + let outputs = Interpreter::default() + .execute_solver(&d.solver, &inputs) + .unwrap(); assert_eq!(outputs.len(), d.outputs.len()); // insert the results in the substitution @@ -160,8 +152,8 @@ impl Folder for RedefinitionOptimizer { vec![] } false => { - // reconstruct the input expressions - let inputs = inputs + //reconstruct the input expressions + let inputs: Vec<_> = inputs .into_iter() .map(|i| { i.map(|v| LinComb::summand(v, FlatVariable::one()).into()) @@ -183,8 +175,7 @@ impl Folder for RedefinitionOptimizer { match lc .0 .iter() - .find(|(variable, _)| self.substitution.get(&variable).is_some()) - .is_some() + .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 @@ -194,7 +185,7 @@ impl Folder for RedefinitionOptimizer { self.substitution .get(&variable) .map(|l| LinComb::from(l.clone()) * &coefficient) - .unwrap_or(LinComb::summand(coefficient, variable)) + .unwrap_or_else(|| LinComb::summand(coefficient, variable)) }) .fold(LinComb::zero(), |acc, x| acc + x) } @@ -209,9 +200,6 @@ impl Folder for RedefinitionOptimizer { } fn fold_function(&mut self, fun: Function) -> Function { - self.substitution.drain(); - self.ignore.drain(); - // to prevent the optimiser from replacing outputs, add them to the ignored set self.ignore.extend(fun.returns.iter().cloned()); @@ -242,7 +230,7 @@ mod tests { id: "foo".to_string(), arguments: vec![x], statements: vec![Statement::definition(y, x), Statement::definition(z, y)], - returns: vec![z.into()], + returns: vec![z], }; let optimized: Function = Function { @@ -269,7 +257,7 @@ mod tests { id: "foo".to_string(), arguments: vec![x], statements: vec![Statement::definition(one, x)], - returns: vec![x.into()], + returns: vec![x], }; let optimized = f.clone(); @@ -304,14 +292,14 @@ mod tests { Statement::definition(z, y), Statement::constraint(z, y), ], - returns: vec![z.into()], + returns: vec![z], }; let optimized: Function = Function { id: "foo".to_string(), arguments: vec![x], statements: vec![Statement::definition(z, x), Statement::constraint(z, x)], - returns: vec![z.into()], + returns: vec![z], }; let mut optimizer = RedefinitionOptimizer::new(); @@ -378,7 +366,7 @@ mod tests { // -> // def main(x, y) -> (1): - // 6*x + 6*y == 6*x + 6*y // will be eliminated as a tautology + // 1*x + 1*y + 2*x + 2*y + 3*x + 3*y == 6*x + 6*y // will be eliminated as a tautology // return 6*x + 6*y let x = FlatVariable::new(0); @@ -412,7 +400,15 @@ mod tests { LinComb::summand(6, x) + LinComb::summand(6, y), LinComb::summand(6, x) + LinComb::summand(6, y), ), - Statement::definition(r, LinComb::summand(6, x) + LinComb::summand(6, y)), + Statement::definition( + r, + LinComb::summand(1, x) + + LinComb::summand(1, y) + + LinComb::summand(2, x) + + LinComb::summand(2, y) + + LinComb::summand(3, x) + + LinComb::summand(3, y), + ), ], returns: vec![r], }; @@ -481,7 +477,7 @@ mod tests { Statement::constraint(x, Bn128Field::from(1)), Statement::constraint(x, Bn128Field::from(2)), ], - returns: vec![x.into()], + returns: vec![x], }; let optimized = f.clone(); diff --git a/zokrates_core/src/optimizer/tautology.rs b/zokrates_core/src/optimizer/tautology.rs index d65584124..c8a4df31b 100644 --- a/zokrates_core/src/optimizer/tautology.rs +++ b/zokrates_core/src/optimizer/tautology.rs @@ -25,17 +25,16 @@ impl TautologyOptimizer { impl Folder for TautologyOptimizer { fn fold_statement(&mut self, s: Statement) -> Vec> { match s { - Statement::Constraint(quad, lin) => { - match quad.try_linear() { - Some(l) => { - if l == lin { - return vec![]; - } + Statement::Constraint(quad, lin) => match quad.try_linear() { + Ok(l) => { + if l == lin { + vec![] + } else { + vec![Statement::Constraint(l.into(), lin)] } - None => {} } - vec![Statement::Constraint(quad, lin)] - } + Err(quad) => vec![Statement::Constraint(quad, lin)], + }, _ => fold_statement(self, s), } } diff --git a/zokrates_core/src/proof_system/ark/gm17.rs b/zokrates_core/src/proof_system/ark/gm17.rs index 19888fdf8..4c982a1ba 100644 --- a/zokrates_core/src/proof_system/ark/gm17.rs +++ b/zokrates_core/src/proof_system/ark/gm17.rs @@ -78,7 +78,7 @@ impl Backend for Ark { query: vk .query .into_iter() - .map(|g1| serialization::to_g1::(g1)) + .map(serialization::to_g1::) .collect(), }; @@ -172,7 +172,7 @@ impl Backend for Ark { query: vk .query .into_iter() - .map(|g1| serialization::to_g1::(g1)) + .map(serialization::to_g1::) .collect(), }; @@ -271,7 +271,7 @@ mod tests { let interpreter = Interpreter::default(); let witness = interpreter - .execute(&program, &vec![Bls12_377Field::from(42)]) + .execute(&program, &[Bls12_377Field::from(42)]) .unwrap(); let proof = @@ -300,7 +300,7 @@ mod tests { let interpreter = Interpreter::default(); let witness = interpreter - .execute(&program, &vec![Bw6_761Field::from(42)]) + .execute(&program, &[Bw6_761Field::from(42)]) .unwrap(); let proof = diff --git a/zokrates_core/src/proof_system/ark/mod.rs b/zokrates_core/src/proof_system/ark/mod.rs index a21fc448b..1e413dbb2 100644 --- a/zokrates_core/src/proof_system/ark/mod.rs +++ b/zokrates_core/src/proof_system/ark/mod.rs @@ -49,42 +49,33 @@ fn ark_combination( cs: &mut ConstraintSystem<<::ArkEngine as PairingEngine>::Fr>, symbols: &mut BTreeMap, witness: &mut Witness, -) -> Result< - LinearCombination<<::ArkEngine as PairingEngine>::Fr>, - SynthesisError, -> { - let lc = - l.0.into_iter() - .map(|(k, v)| { - ( - v.into_ark(), - symbols - .entry(k) - .or_insert_with(|| { - match k.is_output() { - true => cs.new_input_variable(|| { - Ok(witness - .0 - .remove(&k) - .ok_or(SynthesisError::AssignmentMissing)? - .into_ark()) - }), - false => cs.new_witness_variable(|| { - Ok(witness - .0 - .remove(&k) - .ok_or(SynthesisError::AssignmentMissing)? - .into_ark()) - }), - } - .unwrap() - }) - .clone(), - ) - }) - .fold(LinearCombination::zero(), |acc, e| acc + e); - - Ok(lc) +) -> LinearCombination<<::ArkEngine as PairingEngine>::Fr> { + l.0.into_iter() + .map(|(k, v)| { + ( + v.into_ark(), + *symbols.entry(k).or_insert_with(|| { + match k.is_output() { + true => cs.new_input_variable(|| { + Ok(witness + .0 + .remove(&k) + .ok_or(SynthesisError::AssignmentMissing)? + .into_ark()) + }), + false => cs.new_witness_variable(|| { + Ok(witness + .0 + .remove(&k) + .ok_or(SynthesisError::AssignmentMissing)? + .into_ark()) + }), + } + .unwrap() + }), + ) + }) + .fold(LinearCombination::zero(), |acc, e| acc + e) } impl Prog { @@ -96,7 +87,7 @@ impl Prog { // mapping from IR variables let mut symbols = BTreeMap::new(); - let mut witness = witness.unwrap_or(Witness::empty()); + let mut witness = witness.unwrap_or_else(Witness::empty); assert!(symbols.insert(FlatVariable::one(), ConstraintSystem::<<::ArkEngine as PairingEngine>::Fr>::one()).is_none()); @@ -127,37 +118,34 @@ impl Prog { }), } .unwrap(); - (var.clone(), wire) + (*var, wire) }), ); let main = self.main; for statement in main.statements { - match statement { - Statement::Constraint(quad, lin) => { - 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, - )?; - - cs.enforce_constraint(a, b, c)?; - } - _ => {} + 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, + ); + + cs.enforce_constraint(a, b, c)?; } } diff --git a/zokrates_core/src/proof_system/bellman/groth16.rs b/zokrates_core/src/proof_system/bellman/groth16.rs index b8aeb8304..bfdfd49ac 100644 --- a/zokrates_core/src/proof_system/bellman/groth16.rs +++ b/zokrates_core/src/proof_system/bellman/groth16.rs @@ -81,7 +81,7 @@ impl Backend for Bellman { ic: vk .gamma_abc .into_iter() - .map(|g1| serialization::to_g1::(g1)) + .map(serialization::to_g1::) .collect(), }; @@ -156,7 +156,7 @@ mod tests { let interpreter = Interpreter::default(); let witness = interpreter - .execute(&program, &vec![Bn128Field::from(42)]) + .execute(&program, &[Bn128Field::from(42)]) .unwrap(); let proof = diff --git a/zokrates_core/src/proof_system/bellman/mod.rs b/zokrates_core/src/proof_system/bellman/mod.rs index 0368fad66..876d94fdf 100644 --- a/zokrates_core/src/proof_system/bellman/mod.rs +++ b/zokrates_core/src/proof_system/bellman/mod.rs @@ -51,34 +51,31 @@ fn bellman_combination cs.alloc_input( - || format!("{}", k), - || { - Ok(witness - .0 - .remove(&k) - .ok_or(SynthesisError::AssignmentMissing)? - .into_bellman()) - }, - ), - false => cs.alloc( - || format!("{}", k), - || { - Ok(witness - .0 - .remove(&k) - .ok_or(SynthesisError::AssignmentMissing)? - .into_bellman()) - }, - ), - } - .unwrap() - }) - .clone(), + *symbols.entry(k).or_insert_with(|| { + match k.is_output() { + true => cs.alloc_input( + || format!("{}", k), + || { + Ok(witness + .0 + .remove(&k) + .ok_or(SynthesisError::AssignmentMissing)? + .into_bellman()) + }, + ), + false => cs.alloc( + || format!("{}", k), + || { + Ok(witness + .0 + .remove(&k) + .ok_or(SynthesisError::AssignmentMissing)? + .into_bellman()) + }, + ), + } + .unwrap() + }), ) }) .fold(LinearCombination::zero(), |acc, e| acc + e) @@ -93,7 +90,7 @@ impl Prog { // mapping from IR variables let mut symbols = BTreeMap::new(); - let mut witness = witness.unwrap_or(Witness::empty()); + let mut witness = witness.unwrap_or_else(Witness::empty); assert!(symbols.insert(FlatVariable::one(), CS::one()).is_none()); @@ -127,33 +124,29 @@ impl Prog { ), } .unwrap(); - (var.clone(), wire) + (*var, wire) }), ); let main = self.main; for statement in main.statements { - match statement { - Statement::Constraint(quad, lin) => { - let a = &bellman_combination( - quad.left.into_canonical(), - cs, - &mut symbols, - &mut witness, - ); - let b = &bellman_combination( - quad.right.into_canonical(), - cs, - &mut symbols, - &mut witness, - ); - let c = - &bellman_combination(lin.into_canonical(), cs, &mut symbols, &mut witness); - - cs.enforce(|| "Constraint", |lc| lc + a, |lc| lc + b, |lc| lc + c); - } - _ => {} + if let Statement::Constraint(quad, lin) = statement { + let a = &bellman_combination( + quad.left.into_canonical(), + cs, + &mut symbols, + &mut witness, + ); + let b = &bellman_combination( + quad.right.into_canonical(), + cs, + &mut symbols, + &mut witness, + ); + let c = &bellman_combination(lin.into_canonical(), cs, &mut symbols, &mut witness); + + cs.enforce(|| "Constraint", |lc| lc + a, |lc| lc + b, |lc| lc + c); } } @@ -297,7 +290,7 @@ mod tests { let interpreter = Interpreter::default(); - let witness = interpreter.execute(&program, &vec![]).unwrap(); + let witness = interpreter.execute(&program, &[]).unwrap(); let computation = Computation::with_witness(program, witness); let params = computation.clone().setup(); @@ -322,7 +315,7 @@ mod tests { let interpreter = Interpreter::default(); let witness = interpreter - .execute(&program, &vec![Bn128Field::from(0)]) + .execute(&program, &[Bn128Field::from(0)]) .unwrap(); let computation = Computation::with_witness(program, witness); @@ -349,7 +342,7 @@ mod tests { let interpreter = Interpreter::default(); let witness = interpreter - .execute(&program, &vec![Bn128Field::from(0)]) + .execute(&program, &[Bn128Field::from(0)]) .unwrap(); let computation = Computation::with_witness(program, witness); @@ -375,7 +368,7 @@ mod tests { let interpreter = Interpreter::default(); - let witness = interpreter.execute(&program, &vec![]).unwrap(); + let witness = interpreter.execute(&program, &[]).unwrap(); let computation = Computation::with_witness(program, witness); let params = computation.clone().setup(); @@ -412,7 +405,7 @@ mod tests { let interpreter = Interpreter::default(); let witness = interpreter - .execute(&program, &vec![Bn128Field::from(3), Bn128Field::from(4)]) + .execute(&program, &[Bn128Field::from(3), Bn128Field::from(4)]) .unwrap(); let computation = Computation::with_witness(program, witness); @@ -438,7 +431,7 @@ mod tests { let interpreter = Interpreter::default(); let witness = interpreter - .execute(&program, &vec![Bn128Field::from(3)]) + .execute(&program, &[Bn128Field::from(3)]) .unwrap(); let computation = Computation::with_witness(program, witness); @@ -467,7 +460,7 @@ mod tests { let interpreter = Interpreter::default(); let witness = interpreter - .execute(&program, &vec![Bn128Field::from(3), Bn128Field::from(4)]) + .execute(&program, &[Bn128Field::from(3), Bn128Field::from(4)]) .unwrap(); let computation = Computation::with_witness(program, witness); diff --git a/zokrates_core/src/proof_system/scheme/gm17.rs b/zokrates_core/src/proof_system/scheme/gm17.rs index da2333c9b..b35889ed1 100644 --- a/zokrates_core/src/proof_system/scheme/gm17.rs +++ b/zokrates_core/src/proof_system/scheme/gm17.rs @@ -14,6 +14,7 @@ impl NotBw6_761Field for Bls12_377Field {} impl NotBw6_761Field for Bls12_381Field {} impl NotBw6_761Field for Bn128Field {} +#[allow(clippy::upper_case_acronyms)] pub struct GM17; #[derive(Serialize, Deserialize)] diff --git a/zokrates_core/src/proof_system/scheme/pghr13.rs b/zokrates_core/src/proof_system/scheme/pghr13.rs index 29ea5f18c..f2ff8f1af 100644 --- a/zokrates_core/src/proof_system/scheme/pghr13.rs +++ b/zokrates_core/src/proof_system/scheme/pghr13.rs @@ -7,6 +7,7 @@ use regex::Regex; use serde::{Deserialize, Serialize}; use zokrates_field::Field; +#[allow(clippy::upper_case_acronyms)] pub struct PGHR13; #[derive(Serialize, Deserialize)] diff --git a/zokrates_core/src/semantics.rs b/zokrates_core/src/semantics.rs index 4e0746452..3bd4f160d 100644 --- a/zokrates_core/src/semantics.rs +++ b/zokrates_core/src/semantics.rs @@ -7,7 +7,8 @@ use crate::absy::Identifier; use crate::absy::*; use crate::typed_absy::*; -use crate::typed_absy::{Parameter, Variable}; +use crate::typed_absy::{DeclarationParameter, DeclarationVariable, Variable}; +use num_bigint::BigUint; use std::collections::{hash_map::Entry, BTreeSet, HashMap, HashSet}; use std::fmt; use std::path::PathBuf; @@ -16,9 +17,11 @@ use zokrates_field::Field; use crate::parser::Position; use crate::absy::types::{UnresolvedSignature, UnresolvedType, UserTypeId}; -use crate::typed_absy::types::{FunctionKey, Signature, StructLocation, Type}; -use crate::typed_absy::types::{ArrayType, StructMember}; +use crate::typed_absy::types::{ + ArrayType, Constant, DeclarationArrayType, DeclarationFunctionKey, DeclarationSignature, + DeclarationStructMember, DeclarationStructType, DeclarationType, StructLocation, +}; use std::hash::{Hash, Hasher}; #[derive(PartialEq, Debug)] @@ -37,38 +40,38 @@ impl ErrorInner { fn in_file(self, id: &ModuleId) -> Error { Error { inner: self, - module_id: id.clone(), + module_id: id.to_path_buf(), } } } -type TypeMap = HashMap>; +type TypeMap<'ast> = HashMap>>; /// The global state of the program during semantic checks #[derive(Debug)] -struct State<'ast, T: Field> { +struct State<'ast, T> { /// The modules yet to be checked, which we consume as we explore the dependency tree modules: Modules<'ast>, /// The already checked modules, which we're returning at the end typed_modules: TypedModules<'ast, T>, /// The user-defined types, which we keep track at this phase only. In later phases, we rely only on basic types and combinations thereof - types: TypeMap, + types: TypeMap<'ast>, } /// A symbol for a given name: either a type or a group of functions. Not both! #[derive(PartialEq, Hash, Eq, Debug)] -enum SymbolType { +enum SymbolType<'ast> { Type, - Functions(BTreeSet), + Functions(BTreeSet>), } /// A data structure to keep track of all symbols in a module #[derive(Default)] -struct SymbolUnifier { - symbols: HashMap, +struct SymbolUnifier<'ast> { + symbols: HashMap>, } -impl SymbolUnifier { +impl<'ast> SymbolUnifier<'ast> { fn insert_type>(&mut self, id: S) -> bool { let s_type = self.symbols.entry(id.into()); match s_type { @@ -82,7 +85,11 @@ impl SymbolUnifier { } } - fn insert_function>(&mut self, id: S, signature: Signature) -> bool { + fn insert_function>( + &mut self, + id: S, + signature: DeclarationSignature<'ast>, + ) -> bool { let s_type = self.symbols.entry(id.into()); match s_type { // if anything is already called `id`, it depends what it is @@ -90,7 +97,7 @@ impl SymbolUnifier { match o.get_mut() { // if it's a Type, then we can't introduce a function SymbolType::Type => false, - // if it's a Function, we can introduce a new function only if it has a different signature + // if it's a Function, we can introduce it only if it has a different signature SymbolType::Functions(signatures) => signatures.insert(signature), } } @@ -118,21 +125,21 @@ impl fmt::Display for ErrorInner { let location = self .pos .map(|p| format!("{}", p.0)) - .unwrap_or("?".to_string()); + .unwrap_or_else(|| "?".to_string()); write!(f, "{}\n\t{}", location, self.message) } } /// A function query in the current module. #[derive(Debug)] -struct FunctionQuery<'ast> { +struct FunctionQuery<'ast, T> { id: Identifier<'ast>, - inputs: Vec, + inputs: Vec>, /// Output types are optional as we try to infer them - outputs: Vec>, + outputs: Vec>>, } -impl<'ast> fmt::Display for FunctionQuery<'ast> { +impl<'ast, T: fmt::Display> fmt::Display for FunctionQuery<'ast, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "(")?; for (i, t) in self.inputs.iter().enumerate() { @@ -150,7 +157,7 @@ impl<'ast> fmt::Display for FunctionQuery<'ast> { " -> {}", match &self.outputs[0] { Some(t) => format!("{}", t), - None => format!("_"), + None => "_".into(), } ), _ => { @@ -170,68 +177,87 @@ impl<'ast> fmt::Display for FunctionQuery<'ast> { } } -impl<'ast> FunctionQuery<'ast> { +impl<'ast, T: Field> FunctionQuery<'ast, T> { /// Create a new query. fn new( id: Identifier<'ast>, - inputs: &Vec, - outputs: &Vec>, - ) -> FunctionQuery<'ast> { + inputs: &[Type<'ast, T>], + outputs: &[Option>], + ) -> Self { FunctionQuery { id, - inputs: inputs.clone(), - outputs: outputs.clone(), + inputs: inputs.to_owned(), + outputs: outputs.to_owned(), } } /// match a `FunctionKey` against this `FunctionQuery` - fn match_func(&self, func: &FunctionKey) -> bool { + fn match_func(&self, func: &DeclarationFunctionKey<'ast>) -> bool { self.id == func.id - && self.inputs == func.signature.inputs + && self + .inputs + .iter() + .zip(func.signature.inputs.iter()) + .all(|(input_ty, sig_ty)| input_ty.can_be_specialized_to(&sig_ty)) && self.outputs.len() == func.signature.outputs.len() - && self.outputs.iter().enumerate().all(|(index, t)| match t { - Some(ref t) => t == &func.signature.outputs[index], - _ => true, - }) + && self + .outputs + .iter() + .zip(func.signature.outputs.iter()) + .all(|(output_ty, sig_ty)| { + output_ty + .as_ref() + .map(|output_ty| output_ty.can_be_specialized_to(&sig_ty)) + .unwrap_or(true) + }) } - fn match_funcs(&self, funcs: &HashSet>) -> Option> { - funcs.iter().find(|func| self.match_func(func)).cloned() + fn match_funcs( + &self, + funcs: &HashSet>, + ) -> Vec> { + funcs + .iter() + .filter(|func| self.match_func(func)) + .cloned() + .collect() } } /// A scoped variable, so that we can delete all variables of a given scope when exiting it #[derive(Clone, Debug)] -pub struct ScopedVariable<'ast> { - id: Variable<'ast>, +pub struct ScopedVariable<'ast, T> { + id: Variable<'ast, T>, level: usize, } /// Identifiers of different `ScopedVariable`s should not conflict, so we define them as equivalent -impl<'ast> PartialEq for ScopedVariable<'ast> { - fn eq(&self, other: &ScopedVariable) -> bool { +impl<'ast, T> PartialEq for ScopedVariable<'ast, T> { + fn eq(&self, other: &Self) -> bool { self.id.id == other.id.id } } -impl<'ast> Hash for ScopedVariable<'ast> { +impl<'ast, T> Hash for ScopedVariable<'ast, T> { fn hash(&self, state: &mut H) { self.id.id.hash(state); } } -impl<'ast> Eq for ScopedVariable<'ast> {} +impl<'ast, T> Eq for ScopedVariable<'ast, T> {} /// Checker checks the semantics of a program, keeping track of functions and variables in scope -pub struct Checker<'ast> { - scope: HashSet>, - functions: HashSet>, +pub struct Checker<'ast, T> { + return_types: Option>>, + scope: HashSet>, + functions: HashSet>, level: usize, } -impl<'ast> Checker<'ast> { - fn new() -> Checker<'ast> { +impl<'ast, T: Field> Checker<'ast, T> { + fn new() -> Self { Checker { + return_types: None, scope: HashSet::new(), functions: HashSet::new(), level: 0, @@ -243,11 +269,11 @@ impl<'ast> Checker<'ast> { /// # Arguments /// /// * `prog` - The `Program` to be checked - pub fn check(prog: Program<'ast>) -> Result, Vec> { + pub fn check(prog: Program<'ast>) -> Result, Vec> { Checker::new().check_program(prog) } - fn check_program( + fn check_program( &mut self, program: Program<'ast>, ) -> Result, Vec> { @@ -261,7 +287,7 @@ impl<'ast> Checker<'ast> { Err(e) => errors.extend(e), }; - if errors.len() > 0 { + if !errors.is_empty() { return Err(errors); } @@ -287,8 +313,8 @@ impl<'ast> Checker<'ast> { id: String, s: StructDefinitionNode<'ast>, module_id: &ModuleId, - types: &TypeMap, - ) -> Result> { + types: &TypeMap<'ast>, + ) -> Result, Vec> { let pos = s.pos(); let s = s.value; @@ -299,7 +325,7 @@ impl<'ast> Checker<'ast> { for field in s.fields { let member_id = field.value.id.to_string(); match self - .check_type(field.value.ty, module_id, &types) + .check_declaration_type(field.value.ty, module_id, &types, &HashSet::new()) .map(|t| (member_id, t)) { Ok(f) => match fields_set.insert(f.0.clone()) { @@ -315,27 +341,27 @@ impl<'ast> Checker<'ast> { } } - if errors.len() > 0 { + if !errors.is_empty() { return Err(errors); } - Ok(Type::Struct(StructType::new( - module_id.into(), + Ok(DeclarationType::Struct(DeclarationStructType::new( + module_id.to_path_buf(), id, fields .iter() - .map(|f| StructMember::new(f.0.clone(), f.1.clone())) + .map(|f| DeclarationStructMember::new(f.0.clone(), f.1.clone())) .collect(), ))) } - fn check_symbol_declaration( + fn check_symbol_declaration( &mut self, declaration: SymbolDeclarationNode<'ast>, module_id: &ModuleId, state: &mut State<'ast, T>, - functions: &mut HashMap, TypedFunctionSymbol<'ast, T>>, - symbol_unifier: &mut SymbolUnifier, + functions: &mut HashMap, TypedFunctionSymbol<'ast, T>>, + symbol_unifier: &mut SymbolUnifier<'ast>, ) -> Result<(), Vec> { let mut errors: Vec = vec![]; @@ -362,17 +388,20 @@ impl<'ast> Checker<'ast> { } .in_file(module_id), ), - true => {} + true => { + // there should be no entry in the map for this type yet + assert!(state + .types + .entry(module_id.to_path_buf()) + .or_default() + .insert(declaration.id.to_string(), ty) + .is_none()); + } }; - state - .types - .entry(module_id.clone()) - .or_default() - .insert(declaration.id.to_string(), ty); } Err(e) => errors.extend(e.into_iter().map(|inner| Error { inner, - module_id: module_id.clone(), + module_id: module_id.to_path_buf(), })), } } @@ -393,12 +422,18 @@ impl<'ast> Checker<'ast> { }; self.functions.insert( - FunctionKey::with_id(declaration.id.clone()) - .signature(funct.signature.clone()), + DeclarationFunctionKey::with_location( + module_id.to_path_buf(), + declaration.id, + ) + .signature(funct.signature.clone()), ); functions.insert( - FunctionKey::with_id(declaration.id.clone()) - .signature(funct.signature.clone()), + DeclarationFunctionKey::with_location( + module_id.to_path_buf(), + declaration.id, + ) + .signature(funct.signature.clone()), TypedFunctionSymbol::Here(funct), ); } @@ -420,8 +455,9 @@ impl<'ast> Checker<'ast> { .functions .iter() .filter(|(k, _)| k.id == import.symbol_id) - .map(|(_, v)| FunctionKey { - id: import.symbol_id.clone(), + .map(|(_, v)| DeclarationFunctionKey { + module: import.module_id.to_path_buf(), + id: import.symbol_id, signature: v.signature(&state.typed_modules).clone(), }) .collect(); @@ -429,7 +465,7 @@ impl<'ast> Checker<'ast> { // find candidates in the types let type_candidate = state .types - .entry(import.module_id.clone()) + .entry(import.module_id.to_path_buf()) .or_default() .get(import.symbol_id) .cloned(); @@ -439,10 +475,10 @@ impl<'ast> Checker<'ast> { // rename the type to the declared symbol let t = match t { - Type::Struct(t) => Type::Struct(StructType { + DeclarationType::Struct(t) => DeclarationType::Struct(DeclarationStructType { location: Some(StructLocation { name: declaration.id.into(), - module: module_id.clone() + module: module_id.to_path_buf() }), ..t }), @@ -453,7 +489,7 @@ impl<'ast> Checker<'ast> { match symbol_unifier.insert_type(declaration.id) { false => { errors.push(Error { - module_id: module_id.clone(), + module_id: module_id.to_path_buf(), inner: ErrorInner { pos: Some(pos), message: format!( @@ -466,9 +502,9 @@ impl<'ast> Checker<'ast> { }; state .types - .entry(module_id.clone()) + .entry(module_id.to_path_buf()) .or_default() - .insert(declaration.id.to_string(), t.clone()); + .insert(declaration.id.to_string(), t); } (0, None) => { errors.push(ErrorInner { @@ -496,12 +532,12 @@ impl<'ast> Checker<'ast> { true => {} }; - self.functions.insert(candidate.clone().id(declaration.id)); + let local_key = candidate.clone().id(declaration.id).module(module_id.to_path_buf()); + + self.functions.insert(local_key.clone()); functions.insert( - candidate.clone().id(declaration.id), - TypedFunctionSymbol::There( - candidate, - import.module_id.clone(), + local_key, + TypedFunctionSymbol::There(candidate, ), ); } @@ -531,31 +567,30 @@ impl<'ast> Checker<'ast> { }; self.functions.insert( - FunctionKey::with_id(declaration.id.clone()) - .signature(funct.signature().clone()), + DeclarationFunctionKey::with_location(module_id.to_path_buf(), declaration.id) + .signature(funct.signature()), ); functions.insert( - FunctionKey::with_id(declaration.id.clone()) - .signature(funct.signature().clone()), + DeclarationFunctionKey::with_location(module_id.to_path_buf(), declaration.id) + .signature(funct.signature()), TypedFunctionSymbol::Flat(funct), ); } }; // return if any errors occured - if errors.len() > 0 { + if !errors.is_empty() { return Err(errors); } Ok(()) } - fn check_module( + fn check_module( &mut self, module_id: &ModuleId, state: &mut State<'ast, T>, ) -> Result<(), Vec> { - let mut errors = vec![]; let mut checked_functions = HashMap::new(); // check if the module was already removed from the untyped ones @@ -567,25 +602,20 @@ impl<'ast> Checker<'ast> { assert_eq!(module.imports.len(), 0); // we need to create an entry in the types map to store types for this module - state.types.entry(module_id.clone()).or_default(); + state.types.entry(module_id.to_path_buf()).or_default(); // we keep track of the introduced symbols to avoid colisions between types and functions let mut symbol_unifier = SymbolUnifier::default(); // we go through symbol declarations and check them for declaration in module.symbols { - match self.check_symbol_declaration( + self.check_symbol_declaration( declaration, module_id, state, &mut checked_functions, &mut symbol_unifier, - ) { - Ok(()) => {} - Err(e) => { - errors.extend(e); - } - } + )? } Some(TypedModule { @@ -594,27 +624,19 @@ impl<'ast> Checker<'ast> { } }; - // return if any errors occured - if errors.len() > 0 { - return Err(errors); - } - // insert into typed_modules if we checked anything - match to_insert { - Some(typed_module) => { - // there should be no checked module at that key just yet, if there is we have a colision or we checked something twice - assert!(state - .typed_modules - .insert(module_id.clone(), typed_module) - .is_none()); - } - None => {} + 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 + assert!(state + .typed_modules + .insert(module_id.to_path_buf(), typed_module) + .is_none()); }; Ok(()) } - fn check_single_main(module: &TypedModule) -> Result<(), ErrorInner> { + fn check_single_main(module: &TypedModule) -> Result<(), ErrorInner> { match module .functions .iter() @@ -624,7 +646,7 @@ impl<'ast> Checker<'ast> { 1 => Ok(()), 0 => Err(ErrorInner { pos: None, - message: format!("No main function found"), + message: "No main function found".into(), }), n => Err(ErrorInner { pos: None, @@ -633,9 +655,9 @@ impl<'ast> Checker<'ast> { } } - fn check_for_var(&self, var: &VariableNode) -> Result<(), ErrorInner> { + fn check_for_var(&self, var: &VariableNode<'ast>) -> Result<(), ErrorInner> { match var.value.get_type() { - UnresolvedType::FieldElement => Ok(()), + UnresolvedType::Uint(32) => Ok(()), t => Err(ErrorInner { pos: Some(var.pos()), message: format!("Variable in for loop cannot have type {}", t), @@ -643,37 +665,69 @@ impl<'ast> Checker<'ast> { } } - fn check_function( + fn check_function( &mut self, funct_node: FunctionNode<'ast>, module_id: &ModuleId, - types: &TypeMap, + types: &TypeMap<'ast>, ) -> Result, Vec> { + assert!(self.scope.is_empty()); + assert!(self.return_types.is_none()); + self.enter_scope(); let pos = funct_node.pos(); let mut errors = vec![]; let funct = funct_node.value; - let mut arguments_checked = vec![]; let mut signature = None; assert_eq!(funct.arguments.len(), funct.signature.inputs.len()); - for arg in funct.arguments { - match self.check_parameter(arg, module_id, types) { - Ok(a) => { - self.insert_into_scope(a.id.clone()); - arguments_checked.push(a); - } - Err(e) => errors.extend(e), - } - } + let mut arguments_checked = vec![]; let mut statements_checked = vec![]; match self.check_signature(funct.signature, module_id, types) { Ok(s) => { + // define variables for the constants + for generic in &s.generics { + let generic = generic.clone().unwrap(); // for declaration signatures, generics cannot be ignored + + let v = Variable::with_id_and_type( + match generic { + Constant::Generic(g) => g, + _ => unreachable!(), + }, + Type::Uint(UBitwidth::B32), + ); + // we don't have to check for conflicts here, because this was done when checking the signature + self.insert_into_scope(v.clone()); + } + + for (arg, decl_ty) in funct.arguments.into_iter().zip(s.inputs.iter()) { + let pos = arg.pos(); + + let arg = arg.value; + + let decl_v = + DeclarationVariable::with_id_and_type(arg.id.value.id, decl_ty.clone()); + + match self.insert_into_scope(decl_v.clone()) { + true => {} + false => { + errors.push(ErrorInner { + pos: Some(pos), + message: format!("Duplicate name in function definition: `{}` was previously declared as an argument or a generic constant", arg.id.value.id) + }); + } + }; + arguments_checked.push(DeclarationParameter { + id: decl_v, + private: arg.private, + }); + } + let mut found_return = false; for stat in funct.statements.into_iter() { @@ -683,7 +737,7 @@ impl<'ast> Checker<'ast> { if found_return { errors.push(ErrorInner { pos, - message: format!("Expected a single return statement",), + message: "Expected a single return statement".to_string(), }); } @@ -692,31 +746,28 @@ impl<'ast> Checker<'ast> { match self.check_statement(stat, module_id, types) { Ok(statement) => { - match &statement { - TypedStatement::Return(e) => { - match e.iter().map(|e| e.get_type()).collect::>() - == s.outputs - { - true => {} - false => errors.push(ErrorInner { - pos, - message: format!( - "Expected ({}) in return statement, found ({})", - s.outputs - .iter() - .map(|t| t.to_string()) - .collect::>() - .join(", "), - e.iter() - .map(|e| e.get_type()) - .map(|t| t.to_string()) - .collect::>() - .join(", ") - ), - }), - } + if let TypedStatement::Return(e) = &statement { + match e.iter().map(|e| e.get_type()).collect::>() + == s.outputs + { + true => {} + false => errors.push(ErrorInner { + pos, + message: format!( + "Expected ({}) in return statement, found ({})", + s.outputs + .iter() + .map(|t| t.to_string()) + .collect::>() + .join(", "), + e.iter() + .map(|e| e.get_type()) + .map(|t| t.to_string()) + .collect::>() + .join(", ") + ), + }), } - _ => {} }; statements_checked.push(statement); } @@ -729,7 +780,7 @@ impl<'ast> Checker<'ast> { if !found_return { errors.push(ErrorInner { pos: Some(pos), - message: format!("Expected a return statement",), + message: "Expected a return statement".to_string(), }); } @@ -740,11 +791,14 @@ impl<'ast> Checker<'ast> { } }; - if errors.len() > 0 { + self.exit_scope(); + + if !errors.is_empty() { return Err(errors); } - self.exit_scope(); + self.return_types = None; + assert!(self.scope.is_empty()); Ok(TypedFunction { arguments: arguments_checked, @@ -753,32 +807,35 @@ impl<'ast> Checker<'ast> { }) } - fn check_parameter( - &self, - p: ParameterNode<'ast>, - module_id: &ModuleId, - types: &TypeMap, - ) -> Result, Vec> { - let var = self.check_variable(p.value.id, module_id, types)?; - - Ok(Parameter { - id: var, - private: p.value.private, - }) - } - fn check_signature( - &self, - signature: UnresolvedSignature, + &mut self, + signature: UnresolvedSignature<'ast>, module_id: &ModuleId, - types: &TypeMap, - ) -> Result> { + types: &TypeMap<'ast>, + ) -> Result, Vec> { let mut errors = vec![]; let mut inputs = vec![]; let mut outputs = vec![]; + let mut generics = vec![]; + + let mut constants = HashSet::new(); + + for g in signature.generics { + match constants.insert(g.value) { + true => { + generics.push(Some(Constant::Generic(g.value))); + } + false => { + errors.push(ErrorInner { + pos: Some(g.pos()), + message: format!("Generic parameter {} is already declared", g.value), + }); + } + } + } for t in signature.inputs { - match self.check_type(t, module_id, types) { + match self.check_declaration_type(t, module_id, types, &constants) { Ok(t) => { inputs.push(t); } @@ -789,7 +846,7 @@ impl<'ast> Checker<'ast> { } for t in signature.outputs { - match self.check_type(t, module_id, types) { + match self.check_declaration_type(t, module_id, types, &constants) { Ok(t) => { outputs.push(t); } @@ -799,19 +856,25 @@ impl<'ast> Checker<'ast> { } } - if errors.len() > 0 { + if !errors.is_empty() { return Err(errors); } - Ok(Signature { inputs, outputs }) + self.return_types = Some(outputs.clone()); + + Ok(DeclarationSignature { + generics, + inputs, + outputs, + }) } fn check_type( - &self, - ty: UnresolvedTypeNode, + &mut self, + ty: UnresolvedTypeNode<'ast>, module_id: &ModuleId, - types: &TypeMap, - ) -> Result { + types: &TypeMap<'ast>, + ) -> Result, ErrorInner> { let pos = ty.pos(); let ty = ty.value; @@ -819,10 +882,122 @@ impl<'ast> Checker<'ast> { UnresolvedType::FieldElement => Ok(Type::FieldElement), UnresolvedType::Boolean => Ok(Type::Boolean), UnresolvedType::Uint(bitwidth) => Ok(Type::uint(bitwidth)), - UnresolvedType::Array(t, size) => Ok(Type::Array(ArrayType::new( - self.check_type(*t, module_id, types)?, - size, - ))), + UnresolvedType::Array(t, size) => { + let size = self.check_expression(size, module_id, types)?; + + let ty = size.get_type(); + + let size = match size { + TypedExpression::Uint(e) => match e.bitwidth() { + UBitwidth::B32 => Ok(e), + _ => Err(ErrorInner { + pos: Some(pos), + message: format!( + "Expected array dimension to be a u32 constant, found {} of type {}", + e, ty + ), + }), + }, + TypedExpression::Int(v) => UExpression::try_from_int(v.clone(), UBitwidth::B32) + .map_err(|_| ErrorInner { + pos: Some(pos), + message: format!( + "Expected array dimension to be a u32 constant, found {} of type {}", + v, ty + ), + }), + _ => Err(ErrorInner { + pos: Some(pos), + message: format!( + "Expected array dimension to be a u32 constant, found {} of type {}", + size, ty + ), + }), + }?; + + Ok(Type::Array(ArrayType::new( + self.check_type(*t, module_id, types)?, + size, + ))) + } + UnresolvedType::User(id) => types + .get(module_id) + .unwrap() + .get(&id) + .cloned() + .ok_or_else(|| ErrorInner { + pos: Some(pos), + message: format!("Undefined type {}", id), + }) + .map(|t| t.into()), + } + } + + fn check_generic_expression( + &mut self, + expr: ExpressionNode<'ast>, + ) -> Result, ErrorInner> { + let pos = expr.pos(); + + match expr.value { + Expression::U32Constant(c) => Ok(Constant::Concrete(c)), + Expression::IntConstant(c) => { + if c <= BigUint::from(2u128.pow(32) - 1) { + Ok(Constant::Concrete( + u32::from_str_radix(&c.to_str_radix(16), 16).unwrap(), + )) + } else { + Err(ErrorInner { + pos: Some(pos), + message: format!( + "Expected array dimension to be a u32 constant or an identifier, found {}", + Expression::IntConstant(c) + ), + }) + } + } + Expression::Identifier(name) => Ok(Constant::Generic(name)), + e => Err(ErrorInner { + pos: Some(pos), + message: format!( + "Expected array dimension to be a u32 constant or an identifier, found {}", + e + ), + }), + } + } + + fn check_declaration_type( + &mut self, + ty: UnresolvedTypeNode<'ast>, + module_id: &ModuleId, + types: &TypeMap<'ast>, + constants: &HashSet>, + ) -> Result, ErrorInner> { + let pos = ty.pos(); + let ty = ty.value; + + match ty { + UnresolvedType::FieldElement => Ok(DeclarationType::FieldElement), + UnresolvedType::Boolean => Ok(DeclarationType::Boolean), + UnresolvedType::Uint(bitwidth) => Ok(DeclarationType::uint(bitwidth)), + UnresolvedType::Array(t, size) => { + let checked_size = self.check_generic_expression(size.clone())?; + + if let Constant::Generic(g) = checked_size { + if !constants.contains(g) { + return Err(ErrorInner { + pos: Some(pos), + message: format!("Undeclared generic parameter in function definition: `{}` isn\'t declared as a generic constant", g) + }); + } + }; + + Ok(DeclarationType::Array(DeclarationArrayType::new( + self.check_declaration_type(*t, module_id, types, constants)?, + checked_size, + ))) + } UnresolvedType::User(id) => { types .get(module_id) @@ -838,11 +1013,11 @@ impl<'ast> Checker<'ast> { } fn check_variable( - &self, + &mut self, v: crate::absy::VariableNode<'ast>, module_id: &ModuleId, - types: &TypeMap, - ) -> Result, Vec> { + types: &TypeMap<'ast>, + ) -> Result, Vec> { Ok(Variable::with_id_and_type( v.value.id, self.check_type(v.value._type, module_id, types) @@ -850,26 +1025,182 @@ impl<'ast> Checker<'ast> { )) } - fn check_statement( + fn check_for_loop( + &mut self, + var: crate::absy::VariableNode<'ast>, + range: (ExpressionNode<'ast>, ExpressionNode<'ast>), + statements: Vec>, + pos: (Position, Position), + module_id: &ModuleId, + types: &TypeMap<'ast>, + ) -> Result, Vec> { + self.check_for_var(&var).map_err(|e| vec![e])?; + + let var = self.check_variable(var, module_id, types).unwrap(); + + let from = self + .check_expression(range.0, module_id, &types) + .map_err(|e| vec![e])?; + let to = self + .check_expression(range.1, module_id, &types) + .map_err(|e| vec![e])?; + + let from = match from { + TypedExpression::Uint(from) => match from.bitwidth() { + UBitwidth::B32 => Ok(from), + bitwidth => Err(ErrorInner { + pos: Some(pos), + message: format!( + "Expected lower loop bound to be of type u32, found {}", + Type::::Uint(bitwidth) + ), + }), + }, + TypedExpression::Int(v) => { + UExpression::try_from_int(v, UBitwidth::B32).map_err(|_| ErrorInner { + pos: Some(pos), + message: format!( + "Expected lower loop bound to be of type u32, found {}", + Type::::Int + ), + }) + } + from => Err(ErrorInner { + pos: Some(pos), + message: format!( + "Expected lower loop bound to be of type u32, found {}", + from.get_type() + ), + }), + } + .map_err(|e| vec![e])?; + + let to = match to { + TypedExpression::Uint(to) => match to.bitwidth() { + UBitwidth::B32 => Ok(to), + bitwidth => Err(ErrorInner { + pos: Some(pos), + message: format!( + "Expected upper loop bound to be of type u32, found {}", + Type::::Uint(bitwidth) + ), + }), + }, + TypedExpression::Int(v) => { + UExpression::try_from_int(v, UBitwidth::B32).map_err(|_| ErrorInner { + pos: Some(pos), + message: format!( + "Expected upper loop bound to be of type u32, found {}", + Type::::Int + ), + }) + } + to => Err(ErrorInner { + pos: Some(pos), + message: format!( + "Expected upper loop bound to be of type u32, found {}", + to.get_type() + ), + }), + } + .map_err(|e| vec![e])?; + + self.insert_into_scope(var.clone()); + + let mut checked_statements = vec![]; + + for stat in statements { + let checked_stat = self.check_statement(stat, module_id, types)?; + checked_statements.push(checked_stat); + } + + Ok(TypedStatement::For(var, from, to, checked_statements)) + } + + fn check_statement( &mut self, stat: StatementNode<'ast>, module_id: &ModuleId, - types: &TypeMap, + types: &TypeMap<'ast>, ) -> Result, Vec> { let pos = stat.pos(); match stat.value { - Statement::Return(list) => { + Statement::Return(e) => { let mut expression_list_checked = vec![]; + let mut errors = vec![]; - for e in list.value.expressions { + // we clone the return types because there might be other return statements + let return_types = self.return_types.clone().unwrap(); + + for e in e.value.expressions.into_iter() { let e_checked = self .check_expression(e, module_id, &types) .map_err(|e| vec![e])?; expression_list_checked.push(e_checked); } - Ok(TypedStatement::Return(expression_list_checked)) + let res = match expression_list_checked.len() == return_types.len() { + true => match expression_list_checked + .iter() + .zip(return_types.clone()) + .map(|(e, t)| TypedExpression::align_to_type(e.clone(), t.into())) + .collect::, _>>() + .map_err(|e| { + vec![ErrorInner { + pos: Some(pos), + message: format!( + "Expected return value to be of type {}, found {}", + e.1, e.0 + ), + }] + }) { + Ok(e) => { + match e.iter().map(|e| e.get_type()).collect::>() == return_types + { + true => {} + false => errors.push(ErrorInner { + pos: Some(pos), + message: format!( + "Expected ({}) in return statement, found ({})", + return_types + .iter() + .map(|t| t.to_string()) + .collect::>() + .join(", "), + e.iter() + .map(|e| e.get_type()) + .map(|t| t.to_string()) + .collect::>() + .join(", ") + ), + }), + }; + TypedStatement::Return(e) + } + Err(err) => { + errors.extend(err); + TypedStatement::Return(expression_list_checked) + } + }, + false => { + errors.push(ErrorInner { + pos: Some(pos), + message: format!( + "Expected {} expressions in return statement, found {}", + return_types.len(), + expression_list_checked.len() + ), + }); + TypedStatement::Return(expression_list_checked) + } + }; + + if !errors.is_empty() { + return Err(errors); + } + + Ok(res) } Statement::Declaration(var) => { let var = self.check_variable(var, module_id, types)?; @@ -885,16 +1216,14 @@ impl<'ast> Checker<'ast> { Statement::Definition(assignee, expr) => { // we create multidef when rhs is a function call to benefit from inference // check rhs is not a function call here - match expr.value { - Expression::FunctionCall(..) => panic!("Parser should not generate Definition where the right hand side is a FunctionCall"), - _ => {} - } + if let Expression::FunctionCall(..) = expr.value { + panic!("Parser should not generate Definition where the right hand side is a FunctionCall") + } // check the expression to be assigned let checked_expr = self .check_expression(expr, module_id, &types) .map_err(|e| vec![e])?; - let expression_type = checked_expr.get_type(); // check that the assignee is declared and is well formed let var = self @@ -904,16 +1233,35 @@ impl<'ast> Checker<'ast> { let var_type = var.get_type(); // make sure the assignee has the same type as the rhs - match var_type == expression_type { - true => Ok(TypedStatement::Definition(var, checked_expr)), - false => Err(ErrorInner { - pos: Some(pos), - message: format!( - "Expression {} of type {} cannot be assigned to {} of type {}", - checked_expr, expression_type, var, var_type - ), - }), + match var_type.clone() { + Type::FieldElement => FieldElementExpression::try_from_typed(checked_expr) + .map(TypedExpression::from), + Type::Boolean => { + BooleanExpression::try_from_typed(checked_expr).map(TypedExpression::from) + } + Type::Uint(bitwidth) => UExpression::try_from_typed(checked_expr, bitwidth) + .map(TypedExpression::from), + Type::Array(array_ty) => { + ArrayExpression::try_from_typed(checked_expr, *array_ty.ty) + .map(TypedExpression::from) + } + Type::Struct(struct_ty) => { + StructExpression::try_from_typed(checked_expr, struct_ty) + .map(TypedExpression::from) + } + Type::Int => Err(checked_expr), // Integers cannot be assigned } + .map_err(|e| ErrorInner { + pos: Some(pos), + message: format!( + "Expression {} of type {} cannot be assigned to {} of type {}", + e, + e.get_type(), + var.clone(), + var_type + ), + }) + .map(|rhs| TypedStatement::Definition(var, rhs)) .map_err(|e| vec![e]) } Statement::Assertion(e) => { @@ -937,68 +1285,50 @@ impl<'ast> Checker<'ast> { Statement::For(var, from, to, statements) => { self.enter_scope(); - self.check_for_var(&var).map_err(|e| vec![e])?; - - let var = self.check_variable(var, module_id, types).unwrap(); - - let from = self - .check_expression(from, module_id, &types) - .map_err(|e| vec![e])?; - let to = self - .check_expression(to, module_id, &types) - .map_err(|e| vec![e])?; - - let from = match from { - TypedExpression::FieldElement(e) => Ok(e), - e => Err(ErrorInner { - pos: Some(pos), - message: format!( - "Expected lower loop bound to be of type field, found {}", - e.get_type() - ), - }), - } - .map_err(|e| vec![e])?; - - let to = match to { - TypedExpression::FieldElement(e) => Ok(e), - e => Err(ErrorInner { - pos: Some(pos), - message: format!( - "Expected higher loop bound to be of type field, found {}", - e.get_type() - ), - }), - } - .map_err(|e| vec![e])?; - - self.insert_into_scope(var.clone()); - - let mut checked_statements = vec![]; - - for stat in statements { - let checked_stat = self.check_statement(stat, module_id, types)?; - checked_statements.push(checked_stat); - } + let res = self.check_for_loop(var, (from, to), statements, pos, module_id, types); self.exit_scope(); - Ok(TypedStatement::For(var, from, to, checked_statements)) + + res } Statement::MultipleDefinition(assignees, rhs) => { match rhs.value { // Right side has to be a function call - Expression::FunctionCall(fun_id, arguments) => { + Expression::FunctionCall(fun_id, generics, arguments) => { + // check the generic arguments, if any + let generics_checked: Option>>> = generics + .map(|generics| + generics.into_iter().map(|g| + g.map(|g| { + let pos = g.pos(); + self.check_expression(g, module_id, &types).and_then(|g| { + UExpression::try_from_typed(g, UBitwidth::B32).map_err( + |e| ErrorInner { + pos: Some(pos), + message: format!( + "Expected {} to be of type u32, found {}", + e, + e.get_type(), + ), + }, + ) + }) + }) + .transpose() + ) + .collect::>() + ).transpose().map_err(|e| vec![e])?; // check lhs assignees are defined - let (assignees, errors): (Vec<_>, Vec<_>) = assignees.into_iter().map(|a| self.check_assignee::(a, module_id, types)).partition(|r| r.is_ok()); + let (assignees, errors): (Vec<_>, Vec<_>) = assignees.into_iter().map(|a| self.check_assignee(a, module_id, types)).partition(|r| r.is_ok()); - if errors.len() > 0 { + if !errors.is_empty() { return Err(errors.into_iter().map(|e| e.unwrap_err()).collect()); } let assignees: Vec<_> = assignees.into_iter().map(|a| a.unwrap()).collect(); - let assignee_types = assignees.iter().map(|a| Some(a.get_type().clone())).collect(); + let assignee_types: Vec<_> = assignees.iter().map(|a| Some(a.get_type().clone())).collect(); // find argument types let mut arguments_checked = vec![]; @@ -1007,23 +1337,35 @@ impl<'ast> Checker<'ast> { arguments_checked.push(arg_checked); } - let arguments_types = + let arguments_types: Vec<_> = arguments_checked.iter().map(|a| a.get_type()).collect(); let query = FunctionQuery::new(&fun_id, &arguments_types, &assignee_types); - let f = self.find_function(&query); + let functions = self.find_functions(&query); - match f { + match functions.len() { // the function has to be defined - Some(f) => { + 1 => { - let call = TypedExpressionList::FunctionCall(f.clone(), arguments_checked, f.signature.outputs.clone()); + let mut functions = functions; + let f = functions.pop().unwrap(); + + let arguments_checked = arguments_checked.into_iter().zip(f.signature.inputs.clone()).map(|(a, t)| TypedExpression::align_to_type(a, t.into())).collect::, _>>().map_err(|e| vec![ErrorInner { + pos: Some(pos), + message: format!("Expected function call argument to be of type {}, found {} of type {}", e.1, e.0, e.0.get_type()) + }])?; + + let call = TypedExpressionList::FunctionCall(f.clone(), generics_checked.unwrap_or_else(|| vec![None; f.signature.generics.len()]), arguments_checked, assignees.iter().map(|a| a.get_type()).collect()); Ok(TypedStatement::MultipleDefinition(assignees, call)) }, - None => Err(ErrorInner { pos: Some(pos), + 0 => Err(ErrorInner { pos: Some(pos), message: format!("Function definition for function {} with signature {} not found.", fun_id, query) }), + n => Err(ErrorInner { + pos: Some(pos), + message: format!("Ambiguous call to function {}, {} candidates were found. Please be more explicit.", fun_id, n) + }) } } _ => Err(ErrorInner { @@ -1035,11 +1377,11 @@ impl<'ast> Checker<'ast> { } } - fn check_assignee( + fn check_assignee( &mut self, assignee: AssigneeNode<'ast>, module_id: &ModuleId, - types: &TypeMap, + types: &TypeMap<'ast>, ) -> Result, ErrorInner> { let pos = assignee.pos(); // check that the assignee is declared @@ -1070,18 +1412,17 @@ impl<'ast> Checker<'ast> { ), }; - let checked_typed_index = match checked_index { - TypedExpression::FieldElement(e) => Ok(e), - e => Err(ErrorInner { - pos: Some(pos), - - message: format!( - "Expected array {} index to have type field, found {}", - checked_assignee, - e.get_type() - ), - }), - }?; + let checked_typed_index = + UExpression::try_from_typed(checked_index, UBitwidth::B32).map_err( + |e| ErrorInner { + pos: Some(pos), + message: format!( + "Expected array {} index to have type u32, found {}", + checked_assignee, + e.get_type() + ), + }, + )?; Ok(TypedAssignee::Select( box checked_assignee, @@ -1090,7 +1431,6 @@ impl<'ast> Checker<'ast> { } ty => Err(ErrorInner { pos: Some(pos), - message: format!( "Cannot access element at index {} on {} of type {}", index, checked_assignee, ty, @@ -1107,7 +1447,16 @@ impl<'ast> Checker<'ast> { Some(_) => Ok(TypedAssignee::Member(box checked_assignee, member.into())), None => Err(ErrorInner { pos: Some(pos), - message: format!("{} doesn't have member {}", ty, member), + message: format!( + "{} {{{}}} doesn't have member {}", + ty, + members + .iter() + .map(|m| format!("{}: {}", m.id, m.ty)) + .collect::>() + .join(", "), + member + ), }), }, ty => Err(ErrorInner { @@ -1123,12 +1472,12 @@ impl<'ast> Checker<'ast> { } } - fn check_spread_or_expression( + fn check_spread_or_expression( &mut self, spread_or_expression: SpreadOrExpression<'ast>, module_id: &ModuleId, - types: &TypeMap, - ) -> Result>, ErrorInner> { + types: &TypeMap<'ast>, + ) -> Result, ErrorInner> { match spread_or_expression { SpreadOrExpression::Spread(s) => { let pos = s.pos(); @@ -1136,80 +1485,33 @@ impl<'ast> Checker<'ast> { let checked_expression = self.check_expression(s.value.expression, module_id, &types)?; - let res = match checked_expression { - TypedExpression::Array(e) => { - let ty = e.inner_type().clone(); - - let size = e.size(); - match e.into_inner() { - // if we're doing a spread over an inline array, we return the inside of the array: ...[x, y, z] == x, y, z - // this is not strictly needed, but it makes spreads memory linear rather than quadratic - ArrayExpressionInner::Value(v) => Ok(v), - // otherwise we return a[0], ..., a[a.size() -1 ] - e => Ok((0..size) - .map(|i| match &ty { - Type::FieldElement => FieldElementExpression::select( - e.clone().annotate(Type::FieldElement, size), - FieldElementExpression::Number(T::from(i)), - ) - .into(), - Type::Uint(bitwidth) => UExpression::select( - e.clone().annotate(Type::Uint(*bitwidth), size), - FieldElementExpression::Number(T::from(i)), - ) - .into(), - Type::Boolean => BooleanExpression::select( - e.clone().annotate(Type::Boolean, size), - FieldElementExpression::Number(T::from(i)), - ) - .into(), - Type::Array(array_type) => ArrayExpressionInner::Select( - box e - .clone() - .annotate(Type::Array(array_type.clone()), size), - box FieldElementExpression::Number(T::from(i)), - ) - .annotate(*array_type.ty.clone(), array_type.size) - .into(), - Type::Struct(members) => StructExpressionInner::Select( - box e.clone().annotate(Type::Struct(members.clone()), size), - box FieldElementExpression::Number(T::from(i)), - ) - .annotate(members.clone()) - .into(), - }) - .collect()), - } - } + match checked_expression { + TypedExpression::Array(a) => Ok(TypedExpressionOrSpread::Spread(a.into())), e => Err(ErrorInner { pos: Some(pos), - message: format!( "Expected spread operator to apply on array, found {}", e.get_type() ), }), - }; - - let res = res.unwrap(); - - Ok(res) - } - SpreadOrExpression::Expression(e) => { - self.check_expression(e, module_id, &types).map(|r| vec![r]) + } } + SpreadOrExpression::Expression(e) => self + .check_expression(e, module_id, &types) + .map(|r| r.into()), } } - fn check_expression( + fn check_expression( &mut self, expr: ExpressionNode<'ast>, module_id: &ModuleId, - types: &TypeMap, + types: &TypeMap<'ast>, ) -> Result, ErrorInner> { let pos = expr.pos(); match expr.value { + Expression::IntConstant(v) => Ok(IntExpression::Value(v).into()), Expression::BooleanConstant(b) => Ok(BooleanExpression::Value(b).into()), Expression::Identifier(name) => { // check that `id` is defined in the scope @@ -1230,6 +1532,7 @@ impl<'ast> Checker<'ast> { Type::Struct(members) => Ok(StructExpressionInner::Identifier(name.into()) .annotate(members) .into()), + Type::Int => unreachable!(), }, None => Err(ErrorInner { pos: Some(pos), @@ -1241,24 +1544,25 @@ impl<'ast> Checker<'ast> { let e1_checked = self.check_expression(e1, module_id, &types)?; let e2_checked = self.check_expression(e2, module_id, &types)?; + use self::TypedExpression::*; + + let (e1_checked, e2_checked) = TypedExpression::align_without_integers( + e1_checked, e2_checked, + ) + .map_err(|(e1, e2)| ErrorInner { + pos: Some(pos), + 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()), (TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => { Ok(FieldElementExpression::Add(box e1, box e2).into()) } - (TypedExpression::Uint(e1), TypedExpression::Uint(e2)) => { - if e1.get_type() == e2.get_type() { - Ok(UExpression::add(e1, e2).into()) - } else { - Err(ErrorInner { - pos: Some(pos), - - message: format!( - "Cannot apply `+` to {}, {}", - e1.get_type(), - e2.get_type() - ), - }) - } + (TypedExpression::Uint(e1), TypedExpression::Uint(e2)) + if e1.get_type() == e2.get_type() => + { + Ok((e1 + e2).into()) } (t1, t2) => Err(ErrorInner { pos: Some(pos), @@ -1275,25 +1579,22 @@ impl<'ast> Checker<'ast> { let e1_checked = self.check_expression(e1, module_id, &types)?; let e2_checked = self.check_expression(e2, module_id, &types)?; + use self::TypedExpression::*; + + let (e1_checked, e2_checked) = TypedExpression::align_without_integers( + e1_checked, e2_checked, + ) + .map_err(|(e1, e2)| ErrorInner { + pos: Some(pos), + message: format!("Cannot apply `-` to {}, {}", e1.get_type(), e2.get_type()), + })?; + match (e1_checked, e2_checked) { - (TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => { + (Int(e1), Int(e2)) => Ok(IntExpression::Sub(box e1, box e2).into()), + (FieldElement(e1), FieldElement(e2)) => { Ok(FieldElementExpression::Sub(box e1, box e2).into()) } - (TypedExpression::Uint(e1), TypedExpression::Uint(e2)) => { - if e1.get_type() == e2.get_type() { - Ok(UExpression::sub(e1, e2).into()) - } else { - Err(ErrorInner { - pos: Some(pos), - - message: format!( - "Cannot apply `+` to {}, {}", - e1.get_type(), - e2.get_type() - ), - }) - } - } + (Uint(e1), Uint(e2)) if e1.get_type() == e2.get_type() => Ok((e1 - e2).into()), (t1, t2) => Err(ErrorInner { pos: Some(pos), @@ -1309,24 +1610,25 @@ impl<'ast> Checker<'ast> { let e1_checked = self.check_expression(e1, module_id, &types)?; let e2_checked = self.check_expression(e2, module_id, &types)?; + use self::TypedExpression::*; + + let (e1_checked, e2_checked) = TypedExpression::align_without_integers( + e1_checked, e2_checked, + ) + .map_err(|(e1, e2)| ErrorInner { + pos: Some(pos), + 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()), (TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => { Ok(FieldElementExpression::Mult(box e1, box e2).into()) } - (TypedExpression::Uint(e1), TypedExpression::Uint(e2)) => { - if e1.get_type() == e2.get_type() { - Ok(UExpression::mult(e1, e2).into()) - } else { - Err(ErrorInner { - pos: Some(pos), - - message: format!( - "Cannot apply `*` to {}, {}", - e1.get_type(), - e2.get_type() - ), - }) - } + (TypedExpression::Uint(e1), TypedExpression::Uint(e2)) + if e1.get_type() == e2.get_type() => + { + Ok((e1 * e2).into()) } (t1, t2) => Err(ErrorInner { pos: Some(pos), @@ -1343,24 +1645,25 @@ impl<'ast> Checker<'ast> { let e1_checked = self.check_expression(e1, module_id, &types)?; let e2_checked = self.check_expression(e2, module_id, &types)?; + use self::TypedExpression::*; + + let (e1_checked, e2_checked) = TypedExpression::align_without_integers( + e1_checked, e2_checked, + ) + .map_err(|(e1, e2)| ErrorInner { + pos: Some(pos), + message: format!("Cannot apply `/` to {}, {}", e1.get_type(), e2.get_type()), + })?; + match (e1_checked, e2_checked) { - (TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => { + (Int(e1), Int(e2)) => Ok(IntExpression::Div(box e1, box e2).into()), + (FieldElement(e1), FieldElement(e2)) => { Ok(FieldElementExpression::Div(box e1, box e2).into()) } - (TypedExpression::Uint(e1), TypedExpression::Uint(e2)) => { - if e1.get_type() == e2.get_type() { - Ok(UExpression::div(e1, e2).into()) - } else { - Err(ErrorInner { - pos: Some(pos), - - message: format!( - "Cannot apply `/` to {}, {}", - e1.get_type(), - e2.get_type() - ), - }) - } + (TypedExpression::Uint(e1), TypedExpression::Uint(e2)) + if e1.get_type() == e2.get_type() => + { + Ok((e1 / e2).into()) } (t1, t2) => Err(ErrorInner { pos: Some(pos), @@ -1377,21 +1680,19 @@ impl<'ast> Checker<'ast> { 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::Uint(e1), TypedExpression::Uint(e2)) => { - if e1.get_type() == e2.get_type() { - Ok(UExpression::rem(e1, e2).into()) - } else { - Err(ErrorInner { - pos: Some(pos), + let (e1_checked, e2_checked) = TypedExpression::align_without_integers( + e1_checked, e2_checked, + ) + .map_err(|(e1, e2)| ErrorInner { + pos: Some(pos), + message: format!("Cannot apply `%` to {}, {}", e1.get_type(), e2.get_type()), + })?; - message: format!( - "Cannot apply `%` to {}, {}", - e1.get_type(), - e2.get_type() - ), - }) - } + match (e1_checked, e2_checked) { + (TypedExpression::Uint(e1), TypedExpression::Uint(e2)) + if e1.get_type() == e2.get_type() => + { + Ok((e1 % e2).into()) } (t1, t2) => Err(ErrorInner { pos: Some(pos), @@ -1408,56 +1709,111 @@ impl<'ast> Checker<'ast> { 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(), + Err(e) => e, + }; + let e2_checked = match UExpression::try_from_typed(e2_checked, UBitwidth::B32) { + Ok(e) => e.into(), + Err(e) => e, + }; + match (e1_checked, e2_checked) { - (TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => Ok( + (TypedExpression::FieldElement(e1), TypedExpression::Uint(e2)) => Ok( TypedExpression::FieldElement(FieldElementExpression::Pow(box e1, box e2)), ), (t1, t2) => Err(ErrorInner { pos: Some(pos), message: format!( - "Expected only field elements, found {}, {}", + "Expected `field` and `u32`, found {}, {}", t1.get_type(), t2.get_type() ), }), } } + Expression::Neg(box e) => { + let e = self.check_expression(e, module_id, &types)?; + + match e { + TypedExpression::Int(e) => Ok(IntExpression::Neg(box e).into()), + TypedExpression::FieldElement(e) => { + Ok(FieldElementExpression::Neg(box e).into()) + } + TypedExpression::Uint(e) => Ok((-e).into()), + e => Err(ErrorInner { + pos: Some(pos), + message: format!( + "Unary operator `-` cannot be applied to {} of type {}", + e, + e.get_type() + ), + }), + } + } + Expression::Pos(box e) => { + let e = self.check_expression(e, module_id, &types)?; + + match e { + TypedExpression::Int(e) => Ok(IntExpression::Pos(box e).into()), + TypedExpression::FieldElement(e) => { + Ok(FieldElementExpression::Pos(box e).into()) + } + TypedExpression::Uint(e) => Ok(UExpression::pos(e).into()), + e => Err(ErrorInner { + pos: Some(pos), + message: format!( + "Unary operator `+` cannot be applied to {} of type {}", + e, + e.get_type() + ), + }), + } + } Expression::IfElse(box condition, box consequence, box alternative) => { let condition_checked = self.check_expression(condition, module_id, &types)?; let consequence_checked = self.check_expression(consequence, module_id, &types)?; let alternative_checked = self.check_expression(alternative, module_id, &types)?; + let (consequence_checked, alternative_checked) = + TypedExpression::align_without_integers( + consequence_checked, + alternative_checked, + ) + .map_err(|(e1, e2)| ErrorInner { + pos: Some(pos), + message: format!("{{consequence}} and {{alternative}} in `if/else` expression should have the same type, found {}, {}", e1.get_type(), e2.get_type()), + })?; + match condition_checked { TypedExpression::Boolean(condition) => { - let consequence_type = consequence_checked.get_type(); - let alternative_type = alternative_checked.get_type(); - match consequence_type == alternative_type { - true => match (consequence_checked, alternative_checked) { - (TypedExpression::FieldElement(consequence), TypedExpression::FieldElement(alternative)) => { - Ok(FieldElementExpression::IfElse(box condition, box consequence, box alternative).into()) - }, - (TypedExpression::Boolean(consequence), TypedExpression::Boolean(alternative)) => { - Ok(BooleanExpression::IfElse(box condition, box consequence, box alternative).into()) - }, - (TypedExpression::Array(consequence), TypedExpression::Array(alternative)) => { - let inner_type = consequence.inner_type().clone(); - let size = consequence.size(); - Ok(ArrayExpressionInner::IfElse(box condition, box consequence, box alternative).annotate(inner_type, size).into()) - }, - (TypedExpression::Struct(consequence), TypedExpression::Struct(alternative)) => { - let ty = consequence.ty().clone(); - Ok(StructExpressionInner::IfElse(box condition, box consequence, box alternative).annotate(ty).into()) - }, - (TypedExpression::Uint(consequence), TypedExpression::Uint(alternative)) => { - let bitwidth = consequence.bitwidth(); - Ok(UExpressionInner::IfElse(box condition, box consequence, box alternative).annotate(bitwidth).into()) - }, - _ => unreachable!("types should match here as we checked them explicitly") - } - false => Err(ErrorInner { + match (consequence_checked, alternative_checked) { + (TypedExpression::FieldElement(consequence), TypedExpression::FieldElement(alternative)) => { + Ok(FieldElementExpression::IfElse(box condition, box consequence, box alternative).into()) + }, + (TypedExpression::Boolean(consequence), TypedExpression::Boolean(alternative)) => { + Ok(BooleanExpression::IfElse(box condition, box consequence, box alternative).into()) + }, + (TypedExpression::Array(consequence), TypedExpression::Array(alternative)) => { + let inner_type = consequence.inner_type().clone(); + let size = consequence.size(); + Ok(ArrayExpressionInner::IfElse(box condition, box consequence, box alternative).annotate(inner_type, size).into()) + }, + (TypedExpression::Struct(consequence), TypedExpression::Struct(alternative)) => { + let ty = consequence.ty().clone(); + Ok(StructExpressionInner::IfElse(box condition, box consequence, box alternative).annotate(ty).into()) + }, + (TypedExpression::Uint(consequence), TypedExpression::Uint(alternative)) => { + let bitwidth = consequence.bitwidth(); + Ok(UExpressionInner::IfElse(box condition, box consequence, box alternative).annotate(bitwidth).into()) + }, + (TypedExpression::Int(consequence), TypedExpression::Int(alternative)) => { + Ok(IntExpression::IfElse(box condition, box consequence, box alternative).into()) + }, + (c, a) => Err(ErrorInner { pos: Some(pos), - message: format!("{{consequence}} and {{alternative}} in `if/else` expression should have the same type, found {}, {}", consequence_type, alternative_type) + message: format!("{{consequence}} and {{alternative}} in `if/else` expression should have the same type, found {}, {}", c.get_type(), a.get_type()) }) } } @@ -1484,7 +1840,35 @@ impl<'ast> Checker<'ast> { 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::FunctionCall(fun_id, arguments) => { + Expression::U64Constant(n) => Ok(UExpressionInner::Value(n.into()).annotate(64).into()), + Expression::FunctionCall(fun_id, generics, arguments) => { + // check the generic arguments, if any + let generics_checked: Option>>> = generics + .map(|generics| { + generics + .into_iter() + .map(|g| { + g.map(|g| { + let pos = g.pos(); + self.check_expression(g, module_id, &types).and_then(|g| { + UExpression::try_from_typed(g, UBitwidth::B32).map_err( + |e| ErrorInner { + pos: Some(pos), + message: format!( + "Expected {} to be of type u32, found {}", + e, + e.get_type(), + ), + }, + ) + }) + }) + .transpose() + }) + .collect::>() + }) + .transpose()?; + // check the arguments let mut arguments_checked = vec![]; for arg in arguments { @@ -1499,55 +1883,87 @@ impl<'ast> Checker<'ast> { // outside of multidef, function calls must have a single return value // we use type inference to determine the type of the return, so we don't specify it - let query = FunctionQuery::new(&fun_id, &arguments_types, &vec![None]); + let query = FunctionQuery::new(&fun_id, &arguments_types, &[None]); - let f = self.find_function(&query); + let functions = self.find_functions(&query); - match f { + match functions.len() { // the function has to be defined - Some(f) => { + 1 => { + let mut functions = functions; + + let f = functions.pop().unwrap(); + + let signature = f.signature; + + let arguments_checked = arguments_checked.into_iter().zip(signature.inputs.clone()).map(|(a, t)| TypedExpression::align_to_type(a, t.into())).collect::, _>>().map_err(|e| ErrorInner { + pos: Some(pos), + message: format!("Expected function call argument to be of type {}, found {}", e.1, e.0) + })?; + + let output_types = signature.get_output_types(arguments_checked.iter().map(|a| a.get_type()).collect()).map_err(|e| ErrorInner { + pos: Some(pos), + message: format!( + "Failed to infer value for generic parameter `{}`, try being more explicit by using an intermediate variable", + e, + ), + })?; + + let generics_checked = generics_checked.unwrap_or_else(|| vec![None; signature.generics.len()]); + // the return count has to be 1 - match f.signature.outputs.len() { - 1 => match &f.signature.outputs[0] { + match output_types.len() { + 1 => match &output_types[0] { + Type::Int => unreachable!(), Type::FieldElement => Ok(FieldElementExpression::FunctionCall( - FunctionKey { - id: f.id.clone(), - signature: f.signature.clone(), + DeclarationFunctionKey { + module: module_id.to_path_buf(), + id: f.id, + signature: signature.clone(), }, + generics_checked, arguments_checked, ) .into()), Type::Boolean => Ok(BooleanExpression::FunctionCall( - FunctionKey { - id: f.id.clone(), - signature: f.signature.clone(), + DeclarationFunctionKey { + module: module_id.to_path_buf(), + id: f.id, + signature: signature.clone(), }, + generics_checked, arguments_checked, ) .into()), Type::Uint(bitwidth) => Ok(UExpressionInner::FunctionCall( - FunctionKey { - id: f.id.clone(), - signature: f.signature.clone(), + DeclarationFunctionKey { + module: module_id.to_path_buf(), + id: f.id, + signature: signature.clone(), }, + generics_checked, arguments_checked, ) .annotate(*bitwidth) .into()), Type::Struct(members) => Ok(StructExpressionInner::FunctionCall( - FunctionKey { - id: f.id.clone(), - signature: f.signature.clone(), + DeclarationFunctionKey { + module: module_id.to_path_buf(), + id: f.id, + signature: signature.clone(), }, + generics_checked, arguments_checked, ) .annotate(members.clone()) .into()), Type::Array(array_type) => Ok(ArrayExpressionInner::FunctionCall( - FunctionKey { - id: f.id.clone(), - signature: f.signature.clone(), + DeclarationFunctionKey { + module: module_id.to_path_buf(), + id: f.id, + signature: signature.clone(), }, + generics_checked, arguments_checked, ) .annotate(*array_type.ty.clone(), array_type.size.clone()) @@ -1563,7 +1979,7 @@ impl<'ast> Checker<'ast> { }), } } - None => Err(ErrorInner { + 0 => Err(ErrorInner { pos: Some(pos), message: format!( @@ -1571,14 +1987,49 @@ impl<'ast> Checker<'ast> { fun_id, query ), }), + n => Err(ErrorInner { + pos: Some(pos), + message: format!("Ambiguous call to function {}, {} candidates were found. Please be more explicit.", fun_id, n) + }), } } 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)?; + + let (e1_checked, e2_checked) = TypedExpression::align_without_integers( + e1_checked, e2_checked, + ) + .map_err(|(e1, e2)| ErrorInner { + pos: Some(pos), + message: format!( + "Cannot compare {} of type {} to {} of type {}", + e1, + e1.get_type(), + e2, + e2.get_type() + ), + })?; + match (e1_checked, e2_checked) { (TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => { - Ok(BooleanExpression::Lt(box e1, box e2).into()) + Ok(BooleanExpression::FieldLt(box e1, box e2).into()) + } + (TypedExpression::Uint(e1), TypedExpression::Uint(e2)) => { + if e1.get_type() == e2.get_type() { + Ok(BooleanExpression::UintLt(box e1, box e2).into()) + } else { + Err(ErrorInner { + pos: Some(pos), + message: format!( + "Cannot compare {} of type {} to {} of type {}", + e1, + e1.get_type(), + e2, + e2.get_type() + ), + }) + } } (e1, e2) => Err(ErrorInner { pos: Some(pos), @@ -1595,9 +2046,40 @@ impl<'ast> Checker<'ast> { 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)?; + + let (e1_checked, e2_checked) = TypedExpression::align_without_integers( + e1_checked, e2_checked, + ) + .map_err(|(e1, e2)| ErrorInner { + pos: Some(pos), + message: format!( + "Cannot compare {} of type {} to {} of type {}", + e1, + e1.get_type(), + e2, + e2.get_type() + ), + })?; + match (e1_checked, e2_checked) { (TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => { - Ok(BooleanExpression::Le(box e1, box e2).into()) + Ok(BooleanExpression::FieldLe(box e1, box e2).into()) + } + (TypedExpression::Uint(e1), TypedExpression::Uint(e2)) => { + if e1.get_type() == e2.get_type() { + Ok(BooleanExpression::UintLe(box e1, box e2).into()) + } else { + Err(ErrorInner { + pos: Some(pos), + message: format!( + "Cannot compare {} of type {} to {} of type {}", + e1, + e1.get_type(), + e2, + e2.get_type() + ), + }) + } } (e1, e2) => Err(ErrorInner { pos: Some(pos), @@ -1614,6 +2096,21 @@ impl<'ast> Checker<'ast> { 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)?; + + let (e1_checked, e2_checked) = TypedExpression::align_without_integers( + e1_checked, e2_checked, + ) + .map_err(|(e1, e2)| ErrorInner { + pos: Some(pos), + message: format!( + "Cannot compare {} of type {} to {} of type {}", + e1, + e1.get_type(), + e2, + e2.get_type() + ), + })?; + match (e1_checked, e2_checked) { (TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => { Ok(BooleanExpression::FieldEq(box e1, box e2).into()) @@ -1622,52 +2119,17 @@ impl<'ast> Checker<'ast> { Ok(BooleanExpression::BoolEq(box e1, box e2).into()) } (TypedExpression::Array(e1), TypedExpression::Array(e2)) => { - if e1.get_type() == e2.get_type() { - Ok(BooleanExpression::ArrayEq(box e1, box e2).into()) - } else { - Err(ErrorInner { - pos: Some(pos), - message: format!( - "Cannot compare {} of type {} to {} of type {}", - e1, - e1.get_type(), - e2, - e2.get_type() - ), - }) - } + Ok(BooleanExpression::ArrayEq(box e1, box e2).into()) } - (TypedExpression::Struct(e1), TypedExpression::Struct(e2)) => { - if e1.get_type() == e2.get_type() { - Ok(BooleanExpression::StructEq(box e1, box e2).into()) - } else { - Err(ErrorInner { - pos: Some(pos), - message: format!( - "Cannot compare {} of type {} to {} of type {}", - e1, - e1.get_type(), - e2, - e2.get_type() - ), - }) - } + (TypedExpression::Struct(e1), TypedExpression::Struct(e2)) + if e1.get_type() == e2.get_type() => + { + Ok(BooleanExpression::StructEq(box e1, box e2).into()) } - (TypedExpression::Uint(e1), TypedExpression::Uint(e2)) => { - if e1.get_type() == e2.get_type() { - Ok(BooleanExpression::UintEq(box e1, box e2).into()) - } else { - Err(ErrorInner { - pos: Some(pos), - message: format!( - "Cannot compare {} of type {} to {} of type {}", - e1, - e1.get_type(), - e2, - e2.get_type() - ), - }) - } + (TypedExpression::Uint(e1), TypedExpression::Uint(e2)) + if e1.get_type() == e2.get_type() => + { + Ok(BooleanExpression::UintEq(box e1, box e2).into()) } (e1, e2) => Err(ErrorInner { pos: Some(pos), @@ -1684,9 +2146,40 @@ impl<'ast> Checker<'ast> { 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)?; + + let (e1_checked, e2_checked) = TypedExpression::align_without_integers( + e1_checked, e2_checked, + ) + .map_err(|(e1, e2)| ErrorInner { + pos: Some(pos), + message: format!( + "Cannot compare {} of type {} to {} of type {}", + e1, + e1.get_type(), + e2, + e2.get_type() + ), + })?; + match (e1_checked, e2_checked) { (TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => { - Ok(BooleanExpression::Ge(box e1, box e2).into()) + Ok(BooleanExpression::FieldGe(box e1, box e2).into()) + } + (TypedExpression::Uint(e1), TypedExpression::Uint(e2)) => { + if e1.get_type() == e2.get_type() { + Ok(BooleanExpression::UintGe(box e1, box e2).into()) + } else { + Err(ErrorInner { + pos: Some(pos), + message: format!( + "Cannot compare {} of type {} to {} of type {}", + e1, + e1.get_type(), + e2, + e2.get_type() + ), + }) + } } (e1, e2) => Err(ErrorInner { pos: Some(pos), @@ -1703,9 +2196,40 @@ impl<'ast> Checker<'ast> { 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)?; + + let (e1_checked, e2_checked) = TypedExpression::align_without_integers( + e1_checked, e2_checked, + ) + .map_err(|(e1, e2)| ErrorInner { + pos: Some(pos), + message: format!( + "Cannot compare {} of type {} to {} of type {}", + e1, + e1.get_type(), + e2, + e2.get_type() + ), + })?; + match (e1_checked, e2_checked) { (TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => { - Ok(BooleanExpression::Gt(box e1, box e2).into()) + Ok(BooleanExpression::FieldGt(box e1, box e2).into()) + } + (TypedExpression::Uint(e1), TypedExpression::Uint(e2)) => { + if e1.get_type() == e2.get_type() { + Ok(BooleanExpression::UintGt(box e1, box e2).into()) + } else { + Err(ErrorInner { + pos: Some(pos), + message: format!( + "Cannot compare {} of type {} to {} of type {}", + e1, + e1.get_type(), + e2, + e2.get_type() + ), + }) + } } (e1, e2) => Err(ErrorInner { pos: Some(pos), @@ -1723,145 +2247,96 @@ impl<'ast> Checker<'ast> { let array = self.check_expression(array, module_id, &types)?; match index { - RangeOrExpression::Range(r) => match array { - TypedExpression::Array(array) => { - let array_size = array.size(); - let inner_type = array.inner_type().clone(); - - // check that the bounds are valid expressions - let from = r - .value - .from - .map(|e| self.check_expression(e, module_id, &types)) - .unwrap_or(Ok(FieldElementExpression::Number(T::from(0)).into()))?; - - let to = r - .value - .to - .map(|e| self.check_expression(e, module_id, &types)) - .unwrap_or(Ok(FieldElementExpression::Number(T::from( - array_size, - )) - .into()))?; - - // check the bounds are field constants - // Note: it would be nice to allow any field expression, and check it's a constant after constant propagation, - // but it's tricky from a type perspective: the size of the slice changes the type of the resulting array, - // which doesn't work well with our static array approach. Enabling arrays to have unknown size introduces a lot - // of complexity in the compiler, as function selection in inlining requires knowledge of the array size, but - // determining array size potentially requires inlining and propagating. This suggests we would need semantic checking - // to happen iteratively with inlining and propagation, which we can't do now as we go from absy to typed_absy - let from = match from { - TypedExpression::FieldElement(FieldElementExpression::Number(n)) => Ok(n.to_dec_string().parse::().unwrap()), - e => Err(ErrorInner { - pos: Some(pos), - message: format!( - "Expected the lower bound of the range to be a constant field, found {}", - e - ), - }) - }?; + RangeOrExpression::Range(r) => { + match array { + TypedExpression::Array(array) => { + let array_size = array.size(); + + let inner_type = array.inner_type().clone(); + + // check that the bounds are valid expressions + let from = r + .value + .from + .map(|e| self.check_expression(e, module_id, &types)) + .unwrap_or_else(|| Ok(UExpression::from(0u32).into()))?; + + let to = r + .value + .to + .map(|e| self.check_expression(e, module_id, &types)) + .unwrap_or_else(|| Ok(array_size.clone().into()))?; + + let from = UExpression::try_from_typed(from, UBitwidth::B32).map_err(|e| ErrorInner { + pos: Some(pos), + message: format!( + "Expected the lower bound of the range to be a u32, found {} of type {}", + e, + e.get_type() + ), + })?; + + let to = UExpression::try_from_typed(to, UBitwidth::B32).map_err(|e| ErrorInner { + pos: Some(pos), + message: format!( + "Expected the upper bound of the range to be a u32, found {} of type {}", + e, + e.get_type() + ), + })?; + + Ok(ArrayExpressionInner::Slice( + box array, + box from.clone(), + box to.clone(), + ) + .annotate(inner_type, UExpression::floor_sub(to, from)) + .into()) + } + e => Err(ErrorInner { + pos: Some(pos), + message: format!( + "Cannot access slice of expression {} of type {}", + e, + e.get_type(), + ), + }), + } + } + RangeOrExpression::Expression(index) => { + let index = self.check_expression(index, module_id, &types)?; - let to = match to { - TypedExpression::FieldElement(FieldElementExpression::Number(n)) => Ok(n.to_dec_string().parse::().unwrap()), - e => Err(ErrorInner { + let index = + UExpression::try_from_typed(index, UBitwidth::B32).map_err(|e| { + ErrorInner { pos: Some(pos), message: format!( - "Expected the higher bound of the range to be a constant field, found {}", + "Expected index to be of type u32, found {}", e ), - }) - }?; + } + })?; - match (from, to, array_size) { - (f, _, s) if f > s => Err(ErrorInner { - pos: Some(pos), - message: format!( - "Lower range bound {} is out of array bounds [0, {}]", - f, s, - ), - }), - (_, t, s) if t > s => Err(ErrorInner { - pos: Some(pos), - message: format!( - "Higher range bound {} is out of array bounds [0, {}]", - t, s, - ), - }), - (f, t, _) if f > t => Err(ErrorInner { - pos: Some(pos), - message: format!( - "Lower range bound {} is larger than higher range bound {}", - f, t, - ), - }), - (f, t, _) => Ok(ArrayExpressionInner::Value( - (f..t) - .map(|i| match inner_type.clone() { - Type::FieldElement => FieldElementExpression::Select( - box array.clone(), - box FieldElementExpression::Number(T::from(i)), - ) - .into(), - Type::Boolean => BooleanExpression::Select( - box array.clone(), - box FieldElementExpression::Number(T::from(i)), - ) - .into(), - Type::Uint(bitwidth) => UExpressionInner::Select( - box array.clone(), - box FieldElementExpression::Number(T::from(i)), - ) - .annotate(bitwidth) - .into(), - Type::Struct(struct_ty) => { - StructExpressionInner::Select( - box array.clone(), - box FieldElementExpression::Number(T::from(i)), - ) - .annotate(struct_ty) - .into() - } - Type::Array(array_ty) => ArrayExpressionInner::Select( - box array.clone(), - box FieldElementExpression::Number(T::from(i)), - ) - .annotate(*array_ty.ty, array_ty.size) - .into(), - }) - .collect(), - ) - .annotate(inner_type, t - f) - .into()), - } - } - e => Err(ErrorInner { - pos: Some(pos), - message: format!( - "Cannot access slice of expression {} of type {}", - e, - e.get_type(), - ), - }), - }, - RangeOrExpression::Expression(e) => { - match (array, self.check_expression(e, module_id, &types)?) { - (TypedExpression::Array(a), TypedExpression::FieldElement(i)) => { + match array { + TypedExpression::Array(a) => { match a.inner_type().clone() { Type::FieldElement => { - Ok(FieldElementExpression::select(a, i).into()) + Ok(FieldElementExpression::select(a, index).into()) } - Type::Uint(..) => Ok(UExpression::select(a, i).into()), - Type::Boolean => Ok(BooleanExpression::select(a, i).into()), - Type::Array(..) => Ok(ArrayExpression::select(a, i).into()), - Type::Struct(..) => Ok(StructExpression::select(a, i).into()), + Type::Uint(..) => Ok(UExpression::select(a, index).into()), + Type::Boolean => Ok(BooleanExpression::select(a, index).into()), + Type::Array(..) => Ok(ArrayExpression::select(a, index).into()), + Type::Struct(..) => Ok(StructExpression::select(a, index).into()), + Type::Int => unreachable!(), } } - (a, e) => Err(ErrorInner { + a => Err(ErrorInner { pos: Some(pos), message: format!( - "Cannot access element {} on expression of type {}", - e, + "Cannot access element as index {} of type {} on expression {} of type {}", + index, + index.get_type(), + a, a.get_type() ), }), @@ -1879,6 +2354,7 @@ impl<'ast> Checker<'ast> { match ty { Some(ty) => match ty { + Type::Int => unreachable!(), Type::FieldElement => { Ok(FieldElementExpression::member(s, id.to_string()).into()) } @@ -1897,7 +2373,17 @@ impl<'ast> Checker<'ast> { }, None => Err(ErrorInner { pos: Some(pos), - message: format!("{} doesn't have member {}", s.get_type(), id,), + message: format!( + "{} {{{}}} doesn't have member {}", + s.get_type(), + s.ty() + .members + .iter() + .map(|m| format!("{}: {}", m.id, m.ty)) + .collect::>() + .join(", "), + id, + ), }), } } @@ -1911,199 +2397,95 @@ impl<'ast> Checker<'ast> { }), } } - Expression::InlineArray(expressions) => { + Expression::InlineArray(expressions_or_spreads) => { // check each expression, getting its type - let mut expressions_checked = vec![]; - for e in expressions { + let mut expressions_or_spreads_checked = vec![]; + for e in expressions_or_spreads { let e_checked = self.check_spread_or_expression(e, module_id, &types)?; - expressions_checked.extend(e_checked); + expressions_or_spreads_checked.push(e_checked); } - // we infer the type to be the type of the first element - let inferred_type = expressions_checked.get(0).unwrap().get_type().clone(); - - match inferred_type { - Type::FieldElement => { - // we check all expressions have that same type - let mut unwrapped_expressions = vec![]; - - for e in expressions_checked { - let unwrapped_e = match e { - TypedExpression::FieldElement(e) => Ok(e), - e => Err(ErrorInner { - pos: Some(pos), - - message: format!( - "Expected {} to have type {}, but type is {}", - e, - inferred_type, - e.get_type() - ), - }), - }?; - unwrapped_expressions.push(unwrapped_e.into()); - } - - let size = unwrapped_expressions.len(); - - Ok(ArrayExpressionInner::Value(unwrapped_expressions) - .annotate(Type::FieldElement, size) - .into()) - } - Type::Boolean => { - // we check all expressions have that same type - let mut unwrapped_expressions = vec![]; - - for e in expressions_checked { - let unwrapped_e = match e { - TypedExpression::Boolean(e) => Ok(e), - e => Err(ErrorInner { - pos: Some(pos), - - message: format!( - "Expected {} to have type {}, but type is {}", - e, - inferred_type, - e.get_type() - ), - }), - }?; - unwrapped_expressions.push(unwrapped_e.into()); - } - - let size = unwrapped_expressions.len(); - - Ok(ArrayExpressionInner::Value(unwrapped_expressions) - .annotate(Type::Boolean, size) - .into()) - } - ty @ Type::Uint(..) => { - // we check all expressions have that same type - let mut unwrapped_expressions = vec![]; - - for e in expressions_checked { - let unwrapped_e = match e { - TypedExpression::Uint(e) => { - if e.get_type() == ty { - Ok(e) - } else { - Err(ErrorInner { - pos: Some(pos), - - message: format!( - "Expected {} to have type {}, but type is {}", - e, - ty, - e.get_type() - ), - }) - } - } - e => Err(ErrorInner { - pos: Some(pos), - - message: format!( - "Expected {} to have type {}, but type is {}", - e, - ty, - e.get_type() - ), - }), - }?; - unwrapped_expressions.push(unwrapped_e.into()); - } - - let size = unwrapped_expressions.len(); - - Ok(ArrayExpressionInner::Value(unwrapped_expressions) - .annotate(ty, size) - .into()) - } - ty @ Type::Array(..) => { - // we check all expressions have that same type - let mut unwrapped_expressions = vec![]; - - for e in expressions_checked { - let unwrapped_e = match e { - TypedExpression::Array(e) => { - if e.get_type() == ty { - Ok(e) - } else { - Err(ErrorInner { - pos: Some(pos), + if expressions_or_spreads_checked.is_empty() { + return Err(ErrorInner { + pos: Some(pos), + message: "Empty arrays are not allowed".to_string(), + }); + } - message: format!( - "Expected {} to have type {}, but type is {}", - e, - ty, - e.get_type() - ), - }) - } - } - e => Err(ErrorInner { + // we infer the inner type to be the type of the first non-integer element + // if there was no such element, then the array only has integers and we use that as the inner type + let inferred_type = expressions_or_spreads_checked + .iter() + .filter_map(|e| match e.get_type() { + (Type::Int, _) => None, + (t, _) => Some(t), + }) + .next() + .unwrap_or(Type::Int); + + let unwrapped_expressions_or_spreads = match &inferred_type { + Type::Int => expressions_or_spreads_checked, + t => expressions_or_spreads_checked + .into_iter() + .map(|e| { + TypedExpressionOrSpread::align_to_type(e, t.clone()).map_err( + |(e, ty)| ErrorInner { pos: Some(pos), + message: format!("Expected {} to have type {}", e, ty,), + }, + ) + }) + .collect::, _>>()?, + }; - message: format!( - "Expected {} to have type {}, but type is {}", - e, - ty, - e.get_type() - ), - }), - }?; - unwrapped_expressions.push(unwrapped_e.into()); - } - - let size = unwrapped_expressions.len(); - - Ok(ArrayExpressionInner::Value(unwrapped_expressions) - .annotate(ty, size) - .into()) - } - ty @ Type::Struct(..) => { - // we check all expressions have that same type - let mut unwrapped_expressions = vec![]; - - for e in expressions_checked { - let unwrapped_e = match e { - TypedExpression::Struct(e) => { - if e.get_type() == ty { - Ok(e) - } else { - Err(ErrorInner { - pos: Some(pos), + // the size of the inline array is the sum of the size of its elements. However expressed as a u32 expression, + // this value can be an tree of height n in the worst case, with n the size of the array (if all elements are + // simple values and not spreads, 1 + 1 + 1 + ... 1) + // To avoid that, we compute 2 sizes: the sum of all constant sizes as an u32 expression, and the + // sum of all non constant sizes as a u32 number. We then return the sum of the two as a u32 expression. + // `1 + 1 + ... + 1` is reduced to a single expression, which prevents this blowup + + let size: UExpression<'ast, T> = unwrapped_expressions_or_spreads + .iter() + .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)), + _ => Some((c_acc, e_acc + e)), + }, + None => match e.as_inner() { + UExpressionInner::Value(e) => Some((*e as u32, 0u32.into())), + _ => Some((0u32, e)), + }, + }) + .map(|(c_size, e_size)| e_size + c_size.into()) + .unwrap_or_else(|| 0u32.into()); - message: format!( - "Expected {} to have type {}, but type is {}", - e, - ty, - e.get_type() - ), - }) - } - } - e => Err(ErrorInner { - pos: Some(pos), + Ok( + ArrayExpressionInner::Value(unwrapped_expressions_or_spreads.into()) + .annotate(inferred_type, size) + .into(), + ) + } + Expression::ArrayInitializer(box e, box count) => { + let e = self.check_expression(e, module_id, &types)?; + let ty = e.get_type(); - message: format!( - "Expected {} to have type {}, but type is {}", - e, - ty, - e.get_type() - ), - }), - }?; - unwrapped_expressions.push(unwrapped_e.into()); - } + let count = self.check_expression(count, module_id, &types)?; - let size = unwrapped_expressions.len(); + let count = + UExpression::try_from_typed(count, UBitwidth::B32).map_err(|e| ErrorInner { + pos: Some(pos), + message: format!( + "Expected array initializer count to be a u32, found {} of type {}", + e, + e.get_type(), + ), + })?; - Ok(ArrayExpressionInner::Value(unwrapped_expressions) - .annotate(ty, size) - .into()) - } - } + Ok(ArrayExpressionInner::Repeat(box e, box count.clone()) + .annotate(ty, count) + .into()) } Expression::InlineStruct(id, inline_members) => { let ty = self.check_type( @@ -2118,13 +2500,19 @@ impl<'ast> Checker<'ast> { // check that we provided the required number of values - if struct_type.len() != inline_members.len() { + if struct_type.members_count() != inline_members.len() { return Err(ErrorInner { pos: Some(pos), message: format!( - "Inline struct {} does not match {}", - Expression::InlineStruct(id.clone(), inline_members), - Type::Struct(struct_type) + "Inline struct {} does not match {} {{{}}}", + Expression::InlineStruct(id, inline_members), + Type::Struct(struct_type.clone()), + struct_type + .members + .iter() + .map(|m| format!("{}: {}", m.id, m.ty)) + .collect::>() + .join(", ") ), }); } @@ -2144,31 +2532,39 @@ impl<'ast> Checker<'ast> { Some(value) => { let expression_checked = self.check_expression(value, module_id, &types)?; - let checked_type = expression_checked.get_type(); - if checked_type != *member.ty { - return Err(ErrorInner { - pos: Some(pos), - message: format!( - "Member {} of struct {} has type {}, found {} of type {}", - member.id, - id.clone(), - member.ty, - expression_checked, - checked_type, - ), - }); - } else { - result.push(expression_checked.into()); - } + + let expression_checked = TypedExpression::align_to_type( + expression_checked, + *member.ty.clone(), + ) + .map_err(|e| ErrorInner { + pos: Some(pos), + message: format!( + "Member {} of struct {} has type {}, found {} of type {}", + member.id, + id.clone(), + e.1, + e.0, + e.0.get_type(), + ), + })?; + + result.push(expression_checked); } None => { return Err(ErrorInner { pos: Some(pos), message: format!( - "Member {} of struct {} not found in value {}", + "Member {} of struct {} {{{}}} not found in value {}", member.id, Type::Struct(struct_type.clone()), - Expression::InlineStruct(id.clone(), inline_members), + struct_type + .members + .iter() + .map(|m| format!("{}: {}", m.id, m.ty)) + .collect::>() + .join(", "), + Expression::InlineStruct(id, inline_members), ), }) } @@ -2182,7 +2578,23 @@ impl<'ast> Checker<'ast> { 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)?; + + let (e1_checked, e2_checked) = TypedExpression::align_without_integers( + e1_checked, e2_checked, + ) + .map_err(|(e1, e2)| ErrorInner { + pos: Some(pos), + message: format!( + "Cannot apply boolean operators to {} and {}", + 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()) + } (TypedExpression::Boolean(e1), TypedExpression::Boolean(e2)) => { Ok(BooleanExpression::And(box e1, box e2).into()) } @@ -2190,7 +2602,7 @@ impl<'ast> Checker<'ast> { pos: Some(pos), message: format!( - "cannot apply boolean operators to {} and {}", + "Cannot apply boolean operators to {} and {}", e1.get_type(), e2.get_type() ), @@ -2206,23 +2618,35 @@ impl<'ast> Checker<'ast> { } (e1, e2) => Err(ErrorInner { pos: Some(pos), - - message: format!("cannot compare {} to {}", e1.get_type(), e2.get_type()), + message: format!( + "Cannot apply `||` to {}, {}", + e1.get_type(), + e2.get_type() + ), }), } } Expression::LeftShift(box e1, box 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::Uint(e1), TypedExpression::FieldElement(e2)) => { - Ok(UExpression::left_shift(e1, e2).into()) - } - (e1, e2) => Err(ErrorInner { + 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), + message: format!( + "Expected the left shift right operand to have type `u32`, found {}", + e + ), + })?; + + match e1 { + TypedExpression::Int(e1) => Ok(IntExpression::LeftShift(box e1, box e2).into()), + TypedExpression::Uint(e1) => Ok(UExpression::left_shift(e1, e2).into()), + e1 => Err(ErrorInner { pos: Some(pos), message: format!( - "cannot left-shift {} by {}", + "Cannot left-shift {} by {}", e1.get_type(), e2.get_type() ), @@ -2230,17 +2654,28 @@ impl<'ast> Checker<'ast> { } } Expression::RightShift(box e1, box 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::Uint(e1), TypedExpression::FieldElement(e2)) => { - Ok(UExpression::right_shift(e1, e2).into()) + 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), + message: format!( + "Expected the right shift right operand to be of type `u32`, found {}", + e + ), + })?; + + match e1 { + TypedExpression::Int(e1) => { + Ok(IntExpression::RightShift(box e1, box e2).into()) } - (e1, e2) => Err(ErrorInner { + TypedExpression::Uint(e1) => Ok(UExpression::right_shift(e1, e2).into()), + e1 => Err(ErrorInner { pos: Some(pos), message: format!( - "cannot right-shift {} by {}", + "Cannot right-shift {} by {}", e1.get_type(), e2.get_type() ), @@ -2250,21 +2685,23 @@ impl<'ast> Checker<'ast> { 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)?; - match (e1_checked, e2_checked) { - (TypedExpression::Uint(e1), TypedExpression::Uint(e2)) => { - if e1.get_type() == e2.get_type() { - Ok(UExpression::or(e1, e2).into()) - } else { - Err(ErrorInner { - pos: Some(pos), - message: format!( - "Cannot apply `|` to {}, {}", - e1.get_type(), - e2.get_type() - ), - }) - } + let (e1_checked, e2_checked) = TypedExpression::align_without_integers( + e1_checked, e2_checked, + ) + .map_err(|(e1, e2)| ErrorInner { + pos: Some(pos), + 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()) + } + (TypedExpression::Uint(e1), TypedExpression::Uint(e2)) + if e1.bitwidth() == e2.bitwidth() => + { + Ok(UExpression::or(e1, e2).into()) } (e1, e2) => Err(ErrorInner { pos: Some(pos), @@ -2280,21 +2717,23 @@ impl<'ast> Checker<'ast> { 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)?; - match (e1_checked, e2_checked) { - (TypedExpression::Uint(e1), TypedExpression::Uint(e2)) => { - if e1.get_type() == e2.get_type() { - Ok(UExpression::and(e1, e2).into()) - } else { - Err(ErrorInner { - pos: Some(pos), - message: format!( - "Cannot apply `&` to {}, {}", - e1.get_type(), - e2.get_type() - ), - }) - } + let (e1_checked, e2_checked) = TypedExpression::align_without_integers( + e1_checked, e2_checked, + ) + .map_err(|(e1, e2)| ErrorInner { + pos: Some(pos), + 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()) + } + (TypedExpression::Uint(e1), TypedExpression::Uint(e2)) + if e1.bitwidth() == e2.bitwidth() => + { + Ok(UExpression::and(e1, e2).into()) } (e1, e2) => Err(ErrorInner { pos: Some(pos), @@ -2310,21 +2749,23 @@ impl<'ast> Checker<'ast> { 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)?; - match (e1_checked, e2_checked) { - (TypedExpression::Uint(e1), TypedExpression::Uint(e2)) => { - if e1.get_type() == e2.get_type() { - Ok(UExpression::xor(e1, e2).into()) - } else { - Err(ErrorInner { - pos: Some(pos), - message: format!( - "Cannot apply `^` to {}, {}", - e1.get_type(), - e2.get_type() - ), - }) - } + let (e1_checked, e2_checked) = TypedExpression::align_without_integers( + e1_checked, e2_checked, + ) + .map_err(|(e1, e2)| ErrorInner { + pos: Some(pos), + 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()) + } + (TypedExpression::Uint(e1), TypedExpression::Uint(e2)) + if e1.bitwidth() == e2.bitwidth() => + { + Ok(UExpression::xor(e1, e2).into()) } (e1, e2) => Err(ErrorInner { pos: Some(pos), @@ -2340,19 +2781,21 @@ impl<'ast> Checker<'ast> { Expression::Not(box 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::Uint(e) => Ok(UExpression::not(e).into()), + TypedExpression::Uint(e) => Ok((!e).into()), e => Err(ErrorInner { pos: Some(pos), - - message: format!("cannot negate {}", e.get_type()), + message: format!("Cannot negate {}", e.get_type()), }), } } } } - fn get_scope(&self, variable_name: &'ast str) -> Option<&'ast ScopedVariable> { + fn get_scope<'a>(&'a self, variable_name: &'ast str) -> Option<&'a ScopedVariable<'ast, T>> { + // we take advantage of the fact that all ScopedVariable of the same identifier hash to the same thing + // and by construction only one can be in the set self.scope.get(&ScopedVariable { id: Variable::with_id_and_type( crate::typed_absy::Identifier::from(variable_name), @@ -2362,14 +2805,14 @@ impl<'ast> Checker<'ast> { }) } - fn insert_into_scope(&mut self, v: Variable<'ast>) -> bool { + fn insert_into_scope>>(&mut self, v: U) -> bool { self.scope.insert(ScopedVariable { - id: v, + id: v.into(), level: self.level, }) } - fn find_function(&self, query: &FunctionQuery<'ast>) -> Option> { + fn find_functions(&self, query: &FunctionQuery<'ast, T>) -> Vec> { query.match_funcs(&self.functions) } @@ -2390,39 +2833,40 @@ mod tests { use super::*; use crate::absy; use crate::typed_absy; - use num_bigint::BigUint; + use lazy_static::lazy_static; use zokrates_field::Bn128Field; - const MODULE_ID: &str = ""; - + lazy_static! { + static ref MODULE_ID: OwnedModuleId = OwnedModuleId::from(""); + } mod constants { use super::*; - use num_bigint::BigUint; + use std::ops::Add; #[test] fn field_in_range() { + // The value of `P - 1` is a valid field literal + let types = HashMap::new(); - let module_id = "".into(); - let expr = - Expression::FieldConstant(BigUint::from(Bn128Field::max_value().to_biguint())) - .mock(); - assert!(Checker::new() - .check_expression::(expr, &module_id, &types) + let expr = Expression::FieldConstant(Bn128Field::max_value().to_biguint()).mock(); + assert!(Checker::::new() + .check_expression(expr, &*MODULE_ID, &types) .is_ok()); } #[test] fn field_overflow() { + // the value of `P` is an invalid field literal + let types = HashMap::new(); - let module_id = "".into(); let value = Bn128Field::max_value().to_biguint().add(1u32); - let expr = Expression::FieldConstant(BigUint::from(value)).mock(); + let expr = Expression::FieldConstant(value).mock(); - assert!(Checker::new() - .check_expression::(expr, &module_id, &types) + assert!(Checker::::new() + .check_expression(expr, &*MODULE_ID, &types) .is_err()); } } @@ -2433,19 +2877,23 @@ mod tests { #[test] fn element_type_mismatch() { + // having different types in an array isn't allowed + // in the case of arrays, lengths do *not* have to match, as at this point they can be + // generic, so we cannot tell yet + let types = HashMap::new(); - let module_id = "".into(); // [3, true] let a = Expression::InlineArray(vec![ - Expression::FieldConstant(BigUint::from(3u32)).mock().into(), + Expression::IntConstant(3usize.into()).mock().into(), Expression::BooleanConstant(true).mock().into(), ]) .mock(); - assert!(Checker::new() - .check_expression::(a, &module_id, &types) + assert!(Checker::::new() + .check_expression(a, &*MODULE_ID, &types) .is_err()); - // [[0], [0, 0]] + // [[0f], [0f, 0f]] + // accepted at this stage, as we do not check array lengths (as they can be variable) let a = Expression::InlineArray(vec![ Expression::InlineArray(vec![Expression::FieldConstant(BigUint::from(0u32)) .mock() @@ -2460,11 +2908,11 @@ mod tests { .into(), ]) .mock(); - assert!(Checker::new() - .check_expression::(a, &module_id, &types) - .is_err()); + assert!(Checker::::new() + .check_expression(a, &*MODULE_ID, &types) + .is_ok()); - // [[0], true] + // [[0f], true] let a = Expression::InlineArray(vec![ Expression::InlineArray(vec![Expression::FieldConstant(BigUint::from(0u32)) .mock() @@ -2476,63 +2924,63 @@ mod tests { .into(), ]) .mock(); - assert!(Checker::new() - .check_expression::(a, &module_id, &types) + assert!(Checker::::new() + .check_expression(a, &*MODULE_ID, &types) .is_err()); } } - mod symbols { - use super::*; - - /// Helper function to create ((): return) - fn function0() -> FunctionNode<'static> { - let statements: Vec = vec![Statement::Return( - ExpressionList { - expressions: vec![], - } - .mock(), - ) - .mock()]; + /// Helper function to create ((): return) + fn function0() -> FunctionNode<'static> { + let statements = vec![Statement::Return( + ExpressionList { + expressions: vec![], + } + .mock(), + ) + .mock()]; - let arguments = vec![]; + let arguments = vec![]; - let signature = UnresolvedSignature::new(); + let signature = UnresolvedSignature::new(); - Function { - arguments, - statements, - signature, - } - .mock() + Function { + arguments, + statements, + signature, } + .mock() + } - /// Helper function to create ((private field a): return) - fn function1() -> FunctionNode<'static> { - let statements: Vec = vec![Statement::Return( - ExpressionList { - expressions: vec![], - } - .mock(), - ) - .mock()]; - - let arguments = vec![absy::Parameter { - id: absy::Variable::new("a", UnresolvedType::FieldElement.mock()).mock(), - private: true, + /// Helper function to create ((private field a): return) + fn function1() -> FunctionNode<'static> { + let statements = vec![Statement::Return( + ExpressionList { + expressions: vec![], } - .mock()]; + .mock(), + ) + .mock()]; + + let arguments = vec![absy::Parameter { + id: absy::Variable::new("a", UnresolvedType::FieldElement.mock()).mock(), + private: true, + } + .mock()]; - let signature = - UnresolvedSignature::new().inputs(vec![UnresolvedType::FieldElement.mock()]); + let signature = + UnresolvedSignature::new().inputs(vec![UnresolvedType::FieldElement.mock()]); - Function { - arguments, - statements, - signature, - } - .mock() + Function { + arguments, + statements, + signature, } + .mock() + } + + mod symbols { + use super::*; fn struct0() -> StructDefinitionNode<'static> { StructDefinition { fields: vec![] }.mock() @@ -2541,7 +2989,7 @@ mod tests { fn struct1() -> StructDefinitionNode<'static> { StructDefinition { fields: vec![StructDefinitionField { - id: "foo".into(), + id: "foo", ty: UnresolvedType::FieldElement.mock(), } .mock()], @@ -2555,14 +3003,47 @@ mod tests { let mut unifier = SymbolUnifier::default(); + // the `foo` type assert!(unifier.insert_type("foo")); + // the `foo` type annot be declared a second time assert!(!unifier.insert_type("foo")); - assert!(!unifier.insert_function("foo", Signature::new())); - assert!(unifier.insert_function("bar", Signature::new())); - assert!(!unifier.insert_function("bar", Signature::new())); - assert!( - unifier.insert_function("bar", Signature::new().inputs(vec![Type::FieldElement])) - ); + // the `foo` function cannot be declared as the name is already taken by a type + assert!(!unifier.insert_function("foo", DeclarationSignature::new())); + // the `bar` type + assert!(unifier.insert_function("bar", DeclarationSignature::new())); + // a second `bar` function of the same signature cannot be declared + assert!(!unifier.insert_function("bar", DeclarationSignature::new())); + // a second `bar` function of a different signature can be declared + assert!(unifier.insert_function( + "bar", + DeclarationSignature::new().inputs(vec![DeclarationType::FieldElement]) + )); + // a second `bar` function with a generic parameter, which *could* conflict with an existing one should not be allowed + assert!(!unifier.insert_function( + "bar", + DeclarationSignature::new() + .generics(vec![Some("K".into())]) + .inputs(vec![DeclarationType::FieldElement]) + )); + // a `bar` function with a different signature + assert!(unifier.insert_function( + "bar", + DeclarationSignature::new() + .generics(vec![Some("K".into())]) + .inputs(vec![DeclarationType::array(( + DeclarationType::FieldElement, + "K" + ))]) + )); + // a `bar` function with a different signature, but which could conflict with the previous one + assert!(!unifier.insert_function( + "bar", + DeclarationSignature::new().inputs(vec![DeclarationType::array(( + DeclarationType::FieldElement, + 42u32 + ))]) + )); + // a `bar` type isn't allowed as the name is already taken by at least one function assert!(!unifier.insert_type("bar")); } @@ -2601,17 +3082,21 @@ mod tests { .collect(), ); - let mut checker = Checker::new(); + let mut checker: Checker = Checker::new(); - assert_eq!(checker.check_module(&"bar".into(), &mut state), Ok(())); + assert_eq!( + checker.check_module(&OwnedTypedModuleId::from("bar"), &mut state), + Ok(()) + ); assert_eq!( state.typed_modules.get(&PathBuf::from("bar")), Some(&TypedModule { functions: vec![( - FunctionKey::with_id("main").signature(Signature::new()), + DeclarationFunctionKey::with_location("bar", "main") + .signature(DeclarationSignature::new()), TypedFunctionSymbol::There( - FunctionKey::with_id("main").signature(Signature::new()), - "foo".into() + DeclarationFunctionKey::with_location("foo", "main") + .signature(DeclarationSignature::new()), ) )] .into_iter() @@ -2646,22 +3131,195 @@ mod tests { }; let mut state = State::::new( - vec![(PathBuf::from(MODULE_ID).into(), module)] - .into_iter() - .collect(), + vec![((*MODULE_ID).clone(), module)].into_iter().collect(), ); - let mut checker = Checker::new(); + let mut checker: Checker = Checker::new(); + assert_eq!( + checker.check_module(&*MODULE_ID, &mut state).unwrap_err()[0] + .inner + .message, + "foo conflicts with another symbol" + ); + } + + #[test] + fn duplicate_function_declaration_generic() { + // def foo

(private field[P] a): + // return + // def foo(private field[3] a): + // return + // + // should fail as P could be equal to 3 + + let mut f0 = function0(); + + f0.value.arguments = vec![absy::Parameter::private( + absy::Variable::new( + "a", + UnresolvedType::array( + UnresolvedType::FieldElement.mock(), + Expression::Identifier("P").mock(), + ) + .mock(), + ) + .mock(), + ) + .mock()]; + f0.value.signature = UnresolvedSignature::new() + .generics(vec!["P".mock()]) + .inputs(vec![UnresolvedType::array( + UnresolvedType::FieldElement.mock(), + Expression::Identifier("P").mock(), + ) + .mock()]); + + let mut f1 = function0(); + f1.value.arguments = vec![absy::Parameter::private( + absy::Variable::new( + "a", + UnresolvedType::array( + UnresolvedType::FieldElement.mock(), + Expression::U32Constant(3).mock(), + ) + .mock(), + ) + .mock(), + ) + .mock()]; + f1.value.signature = UnresolvedSignature::new().inputs(vec![UnresolvedType::array( + UnresolvedType::FieldElement.mock(), + Expression::U32Constant(3).mock(), + ) + .mock()]); + + let module = Module { + symbols: vec![ + SymbolDeclaration { + id: "foo", + symbol: Symbol::HereFunction(f0), + } + .mock(), + SymbolDeclaration { + id: "foo", + symbol: Symbol::HereFunction(f1), + } + .mock(), + ], + imports: vec![], + }; + + let mut state = State::new(vec![((*MODULE_ID).clone(), module)].into_iter().collect()); + + let mut checker: Checker = Checker::new(); assert_eq!( - checker - .check_module(&PathBuf::from(MODULE_ID).into(), &mut state) - .unwrap_err()[0] + checker.check_module(&*MODULE_ID, &mut state).unwrap_err()[0] .inner .message, "foo conflicts with another symbol" ); } + mod generics { + use super::*; + + #[test] + fn unused_generic() { + // def foo

(): + // return + // def main(): + // return + // + // should succeed + + let mut foo = function0(); + + foo.value.signature = UnresolvedSignature::new().generics(vec!["P".mock()]); + + let module = Module { + symbols: vec![ + SymbolDeclaration { + id: "foo", + symbol: Symbol::HereFunction(foo), + } + .mock(), + SymbolDeclaration { + id: "main", + symbol: Symbol::HereFunction(function0()), + } + .mock(), + ], + imports: vec![], + }; + + let mut state = + State::new(vec![((*MODULE_ID).clone(), module)].into_iter().collect()); + + let mut checker: Checker = Checker::new(); + assert!(checker.check_module(&*MODULE_ID, &mut state).is_ok()); + } + + #[test] + fn undeclared_generic() { + // def foo(field[P] a): + // return + // def main(): + // return + // + // should fail + + let mut foo = function0(); + + foo.value.arguments = vec![absy::Parameter::private( + absy::Variable::new( + "a", + UnresolvedType::array( + UnresolvedType::FieldElement.mock(), + Expression::Identifier("P").mock(), + ) + .mock(), + ) + .mock(), + ) + .mock()]; + foo.value.signature = + UnresolvedSignature::new().inputs(vec![UnresolvedType::array( + UnresolvedType::FieldElement.mock(), + Expression::Identifier("P").mock(), + ) + .mock()]); + + let module = Module { + symbols: vec![ + SymbolDeclaration { + id: "foo", + symbol: Symbol::HereFunction(foo), + } + .mock(), + SymbolDeclaration { + id: "main", + symbol: Symbol::HereFunction(function0()), + } + .mock(), + ], + imports: vec![], + }; + + let mut state = + State::new(vec![((*MODULE_ID).clone(), module)].into_iter().collect()); + + let mut checker: Checker = Checker::new(); + assert_eq!( + checker + .check_module(&*MODULE_ID, &mut state) + .unwrap_err()[0] + .inner + .message, + "Undeclared generic parameter in function definition: `P` isn\'t declared as a generic constant" + ); + } + } + #[test] fn overloaded_function_declaration() { // def foo(): @@ -2688,30 +3346,29 @@ mod tests { }; let mut state = State::::new( - vec![(PathBuf::from(MODULE_ID), module)] - .into_iter() - .collect(), + vec![((*MODULE_ID).clone(), module)].into_iter().collect(), ); - let mut checker = Checker::new(); - assert_eq!( - checker.check_module(&PathBuf::from(MODULE_ID), &mut state), - Ok(()) - ); + let mut checker: Checker = Checker::new(); + assert_eq!(checker.check_module(&*MODULE_ID, &mut state), Ok(())); assert!(state .typed_modules - .get(&PathBuf::from(MODULE_ID)) + .get(&*MODULE_ID) .unwrap() .functions - .contains_key(&FunctionKey::with_id("foo").signature(Signature::new()))); + .contains_key( + &DeclarationFunctionKey::with_location((*MODULE_ID).clone(), "foo") + .signature(DeclarationSignature::new()) + )); assert!(state .typed_modules - .get(&PathBuf::from(MODULE_ID)) + .get(&*MODULE_ID) .unwrap() .functions .contains_key( - &FunctionKey::with_id("foo") - .signature(Signature::new().inputs(vec![Type::FieldElement])) + &DeclarationFunctionKey::with_location((*MODULE_ID).clone(), "foo").signature( + DeclarationSignature::new().inputs(vec![DeclarationType::FieldElement]) + ) )) } @@ -2738,14 +3395,13 @@ mod tests { imports: vec![], }; - let mut state = - State::::new(vec![("main".into(), module)].into_iter().collect()); + let mut state = State::::new( + vec![((*MODULE_ID).clone(), module)].into_iter().collect(), + ); - let mut checker = Checker::new(); + let mut checker: Checker = Checker::new(); assert_eq!( - checker - .check_module(&"main".into(), &mut state) - .unwrap_err()[0] + checker.check_module(&*MODULE_ID, &mut state).unwrap_err()[0] .inner .message, "foo conflicts with another symbol" @@ -2776,14 +3432,13 @@ mod tests { imports: vec![], }; - let mut state = - State::::new(vec![("main".into(), module)].into_iter().collect()); + let mut state = State::::new( + vec![((*MODULE_ID).clone(), module)].into_iter().collect(), + ); - let mut checker = Checker::new(); + let mut checker: Checker = Checker::new(); assert_eq!( - checker - .check_module(&"main".into(), &mut state) - .unwrap_err()[0] + checker.check_module(&*MODULE_ID, &mut state).unwrap_err()[0] .inner .message, "foo conflicts with another symbol" @@ -2828,16 +3483,14 @@ mod tests { }; let mut state = State::::new( - vec![(PathBuf::from(MODULE_ID), main), ("bar".into(), bar)] + vec![((*MODULE_ID).clone(), main), ("bar".into(), bar)] .into_iter() .collect(), ); - let mut checker = Checker::new(); + let mut checker: Checker = Checker::new(); assert_eq!( - checker - .check_module(&PathBuf::from(MODULE_ID), &mut state) - .unwrap_err()[0] + checker.check_module(&*MODULE_ID, &mut state).unwrap_err()[0] .inner .message, "foo conflicts with another symbol" @@ -2879,16 +3532,14 @@ mod tests { }; let mut state = State::::new( - vec![(PathBuf::from(MODULE_ID), main), ("bar".into(), bar)] + vec![((*MODULE_ID).clone(), main), ("bar".into(), bar)] .into_iter() .collect(), ); - let mut checker = Checker::new(); + let mut checker: Checker = Checker::new(); assert_eq!( - checker - .check_module(&PathBuf::from(MODULE_ID), &mut state) - .unwrap_err()[0] + checker.check_module(&*MODULE_ID, &mut state).unwrap_err()[0] .inner .message, "foo conflicts with another symbol" @@ -2896,15 +3547,76 @@ mod tests { } } - pub fn new_with_args<'ast>( - scope: HashSet>, + pub fn new_with_args<'ast, T: Field>( + scope: HashSet>, level: usize, - functions: HashSet>, - ) -> Checker<'ast> { + functions: HashSet>, + ) -> Checker<'ast, T> { Checker { scope, functions, level, + return_types: None, + } + } + + // checking function signatures + mod signature { + use super::*; + + #[test] + fn undeclared_generic() { + let signature = UnresolvedSignature::new().inputs(vec![UnresolvedType::Array( + box UnresolvedType::FieldElement.mock(), + Expression::Identifier("K").mock(), + ) + .mock()]); + assert_eq!(Checker::::new().check_signature(signature, &*MODULE_ID, &TypeMap::default()), Err(vec![ErrorInner { + pos: Some((Position::mock(), Position::mock())), + message: "Undeclared generic parameter in function definition: `K` isn\'t declared as a generic constant".to_string() + }])); + } + + #[test] + fn success() { + // (field[L][K]) -> field[L][K] + + 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(), + Expression::Identifier("L").mock(), + ) + .mock()]) + .outputs(vec![UnresolvedType::Array( + box UnresolvedType::Array( + box UnresolvedType::FieldElement.mock(), + Expression::Identifier("L").mock(), + ) + .mock(), + Expression::Identifier("K").mock(), + ) + .mock()]); + assert_eq!( + Checker::::new().check_signature( + signature, + &*MODULE_ID, + &TypeMap::default() + ), + Ok(DeclarationSignature::new() + .inputs(vec![DeclarationType::array(( + DeclarationType::array((DeclarationType::FieldElement, "K")), + "L" + ))]) + .outputs(vec![DeclarationType::array(( + DeclarationType::array((DeclarationType::FieldElement, "L")), + "K" + ))])) + ); } } @@ -2919,11 +3631,10 @@ mod tests { .mock(); let types = HashMap::new(); - let module_id = "".into(); - let mut checker = Checker::new(); + let mut checker: Checker = Checker::new(); assert_eq!( - checker.check_statement::(statement, &module_id, &types), + checker.check_statement(statement, &*MODULE_ID, &types), Err(vec![ErrorInner { pos: Some((Position::mock(), Position::mock())), message: "Identifier \"b\" is undefined".into() @@ -2942,7 +3653,6 @@ mod tests { .mock(); let types = HashMap::new(); - let module_id = "".into(); let mut scope = HashSet::new(); scope.insert(ScopedVariable { @@ -2953,9 +3663,9 @@ mod tests { id: Variable::field_element("b"), level: 0, }); - let mut checker = new_with_args(scope, 1, HashSet::new()); + let mut checker: Checker = new_with_args(scope, 1, HashSet::new()); assert_eq!( - checker.check_statement::(statement, &module_id, &types), + checker.check_statement(statement, &*MODULE_ID, &types), Ok(TypedStatement::Definition( TypedAssignee::Identifier(typed_absy::Variable::field_element("a")), FieldElementExpression::Identifier("b".into()).into() @@ -2979,7 +3689,7 @@ mod tests { .mock(), Statement::Definition( Assignee::Identifier("a").mock(), - Expression::FieldConstant(BigUint::from(1u32)).mock(), + Expression::IntConstant(1usize.into()).mock(), ) .mock(), Statement::Return( @@ -3009,10 +3719,9 @@ mod tests { let bar = Function { arguments: bar_args, statements: bar_statements, - signature: UnresolvedSignature { - inputs: vec![], - outputs: vec![UnresolvedType::FieldElement.mock()], - }, + signature: UnresolvedSignature::new() + .inputs(vec![]) + .outputs(vec![UnresolvedType::FieldElement.mock()]), } .mock(); @@ -3034,17 +3743,17 @@ mod tests { }; let mut state = - State::::new(vec![("main".into(), module)].into_iter().collect()); + State::::new(vec![((*MODULE_ID).clone(), module)].into_iter().collect()); - let mut checker = Checker::new(); + let mut checker: Checker = Checker::new(); assert_eq!( - checker.check_module(&"main".into(), &mut state), + checker.check_module(&*MODULE_ID, &mut state), Err(vec![Error { inner: ErrorInner { pos: Some((Position::mock(), Position::mock())), message: "Identifier \"a\" is undefined".into() }, - module_id: "main".into() + module_id: (*MODULE_ID).clone() }]) ); } @@ -3068,7 +3777,7 @@ mod tests { .mock(), Statement::Definition( Assignee::Identifier("a").mock(), - Expression::FieldConstant(BigUint::from(1u32)).mock(), + Expression::IntConstant(1usize.into()).mock(), ) .mock(), Statement::Return( @@ -3095,7 +3804,7 @@ mod tests { .mock(), Statement::Definition( Assignee::Identifier("a").mock(), - Expression::FieldConstant(BigUint::from(2u32)).mock(), + Expression::IntConstant(2usize.into()).mock(), ) .mock(), Statement::Return( @@ -3116,7 +3825,7 @@ mod tests { let main_args = vec![]; let main_statements = vec![Statement::Return( ExpressionList { - expressions: vec![Expression::FieldConstant(BigUint::from(1u32)).mock()], + expressions: vec![Expression::IntConstant(1usize.into()).mock()], } .mock(), ) @@ -3125,10 +3834,9 @@ mod tests { let main = Function { arguments: main_args, statements: main_statements, - signature: UnresolvedSignature { - inputs: vec![], - outputs: vec![UnresolvedType::FieldElement.mock()], - }, + signature: UnresolvedSignature::new() + .inputs(vec![]) + .outputs(vec![UnresolvedType::FieldElement.mock()]), } .mock(); @@ -3155,10 +3863,10 @@ mod tests { }; let mut state = - State::::new(vec![("main".into(), module)].into_iter().collect()); + State::::new(vec![((*MODULE_ID).clone(), module)].into_iter().collect()); - let mut checker = Checker::new(); - assert!(checker.check_module(&"main".into(), &mut state).is_ok()); + let mut checker: Checker = Checker::new(); + assert!(checker.check_module(&*MODULE_ID, &mut state).is_ok()); } #[test] @@ -3168,11 +3876,11 @@ mod tests { // endfor // return i // should fail - let foo_statements = vec![ + let foo_statements: Vec = vec![ Statement::For( - absy::Variable::new("i", UnresolvedType::FieldElement.mock()).mock(), - Expression::FieldConstant(BigUint::from(0u32)).mock(), - Expression::FieldConstant(BigUint::from(10u32)).mock(), + absy::Variable::new("i", UnresolvedType::Uint(32).mock()).mock(), + Expression::IntConstant(0usize.into()).mock(), + Expression::IntConstant(10usize.into()).mock(), vec![], ) .mock(), @@ -3187,19 +3895,17 @@ mod tests { let foo = Function { arguments: vec![], statements: foo_statements, - signature: UnresolvedSignature { - inputs: vec![], - outputs: vec![UnresolvedType::FieldElement.mock()], - }, + signature: UnresolvedSignature::new() + .inputs(vec![]) + .outputs(vec![UnresolvedType::FieldElement.mock()]), } .mock(); let types = HashMap::new(); - let module_id = "".into(); - let mut checker = Checker::new(); + let mut checker: Checker = Checker::new(); assert_eq!( - checker.check_function::(foo, &module_id, &types), + checker.check_function(foo, &*MODULE_ID, &types), Err(vec![ErrorInner { pos: Some((Position::mock(), Position::mock())), message: "Identifier \"i\" is undefined".into() @@ -3210,7 +3916,7 @@ mod tests { #[test] fn for_index_in_for() { // def foo(): - // for i in 0..10 do + // for field i in 0..10 do // a = i // endfor // return @@ -3218,7 +3924,7 @@ mod tests { let for_statements = vec![ Statement::Declaration( - absy::Variable::new("a", UnresolvedType::FieldElement.mock()).mock(), + absy::Variable::new("a", UnresolvedType::Uint(32).mock()).mock(), ) .mock(), Statement::Definition( @@ -3230,9 +3936,9 @@ mod tests { let foo_statements = vec![ Statement::For( - absy::Variable::new("i", UnresolvedType::FieldElement.mock()).mock(), - Expression::FieldConstant(BigUint::from(0u32)).mock(), - Expression::FieldConstant(BigUint::from(10u32)).mock(), + absy::Variable::new("i", UnresolvedType::Uint(32).mock()).mock(), + Expression::IntConstant(0usize.into()).mock(), + Expression::IntConstant(10usize.into()).mock(), for_statements, ) .mock(), @@ -3246,18 +3952,20 @@ mod tests { ]; let for_statements_checked = vec![ - TypedStatement::Declaration(typed_absy::Variable::field_element("a")), + TypedStatement::Declaration(typed_absy::Variable::uint("a", UBitwidth::B32)), TypedStatement::Definition( - TypedAssignee::Identifier(typed_absy::Variable::field_element("a")), - FieldElementExpression::Identifier("i".into()).into(), + TypedAssignee::Identifier(typed_absy::Variable::uint("a", UBitwidth::B32)), + UExpressionInner::Identifier("i".into()) + .annotate(UBitwidth::B32) + .into(), ), ]; let foo_statements_checked = vec![ TypedStatement::For( - typed_absy::Variable::field_element("i"), - FieldElementExpression::Number(Bn128Field::from(0u32)), - FieldElementExpression::Number(Bn128Field::from(10u32)), + typed_absy::Variable::uint("i", UBitwidth::B32), + 0u32.into(), + 10u32.into(), for_statements_checked, ), TypedStatement::Return(vec![]), @@ -3273,15 +3981,14 @@ mod tests { let foo_checked = TypedFunction { arguments: vec![], statements: foo_statements_checked, - signature: Signature::new(), + signature: DeclarationSignature::default(), }; let types = HashMap::new(); - let module_id = "".into(); - let mut checker = Checker::new(); + let mut checker: Checker = Checker::new(); assert_eq!( - checker.check_function::(foo, &module_id, &types), + checker.check_function(foo, &*MODULE_ID, &types), Ok(foo_checked) ); } @@ -3300,7 +4007,7 @@ mod tests { .mock(), Statement::MultipleDefinition( vec![Assignee::Identifier("a").mock()], - Expression::FunctionCall("foo", vec![]).mock(), + Expression::FunctionCall("foo", None, vec![]).mock(), ) .mock(), Statement::Return( @@ -3312,12 +4019,13 @@ mod tests { .mock(), ]; - let foo = FunctionKey { + let foo = DeclarationFunctionKey { + module: (*MODULE_ID).clone(), id: "foo", - signature: Signature { - inputs: vec![], - outputs: vec![Type::FieldElement, Type::FieldElement], - }, + signature: DeclarationSignature::new().inputs(vec![]).outputs(vec![ + DeclarationType::FieldElement, + DeclarationType::FieldElement, + ]), }; let functions = vec![foo].into_iter().collect(); @@ -3330,11 +4038,10 @@ mod tests { .mock(); let types = HashMap::new(); - let module_id = "".into(); - let mut checker = new_with_args(HashSet::new(), 0, functions); + let mut checker: Checker = new_with_args(HashSet::new(), 0, functions); assert_eq!( - checker.check_function::(bar, &module_id, &types), + checker.check_function(bar, &*MODULE_ID, &types), Err(vec![ErrorInner { pos: Some((Position::mock(), Position::mock())), message: @@ -3355,8 +4062,8 @@ mod tests { let bar_statements: Vec = vec![ Statement::Assertion( Expression::Eq( - box Expression::FieldConstant(BigUint::from(2u32)).mock(), - box Expression::FunctionCall("foo", vec![]).mock(), + box Expression::IntConstant(2usize.into()).mock(), + box Expression::FunctionCall("foo", None, vec![]).mock(), ) .mock(), ) @@ -3370,12 +4077,13 @@ mod tests { .mock(), ]; - let foo = FunctionKey { + let foo = DeclarationFunctionKey { + module: (*MODULE_ID).clone(), id: "foo", - signature: Signature { - inputs: vec![], - outputs: vec![Type::FieldElement, Type::FieldElement], - }, + signature: DeclarationSignature::new().inputs(vec![]).outputs(vec![ + DeclarationType::FieldElement, + DeclarationType::FieldElement, + ]), }; let functions = vec![foo].into_iter().collect(); @@ -3383,19 +4091,15 @@ mod tests { let bar = Function { arguments: vec![], statements: bar_statements, - signature: UnresolvedSignature { - inputs: vec![], - outputs: vec![], - }, + signature: UnresolvedSignature::new(), } .mock(); let types = HashMap::new(); - let module_id = "".into(); - let mut checker = new_with_args(HashSet::new(), 0, functions); + let mut checker: Checker = new_with_args(HashSet::new(), 0, functions); assert_eq!( - checker.check_function::(bar, &module_id, &types), + checker.check_function(bar, &*MODULE_ID, &types), Err(vec![ErrorInner { pos: Some((Position::mock(), Position::mock())), message: "Function definition for function foo with signature () -> _ not found." @@ -3417,7 +4121,7 @@ mod tests { .mock(), Statement::MultipleDefinition( vec![Assignee::Identifier("a").mock()], - Expression::FunctionCall("foo", vec![]).mock(), + Expression::FunctionCall("foo", None, vec![]).mock(), ) .mock(), Statement::Return( @@ -3437,11 +4141,10 @@ mod tests { .mock(); let types = HashMap::new(); - let module_id = "".into(); - let mut checker = new_with_args(HashSet::new(), 0, HashSet::new()); + let mut checker: Checker = new_with_args(HashSet::new(), 0, HashSet::new()); assert_eq!( - checker.check_function::(bar, &module_id, &types), + checker.check_function(bar, &*MODULE_ID, &types), Err(vec![ErrorInner { pos: Some((Position::mock(), Position::mock())), @@ -3464,8 +4167,8 @@ mod tests { let foo_statements: Vec = vec![Statement::Return( ExpressionList { expressions: vec![ - Expression::FieldConstant(BigUint::from(1u32)).mock(), - Expression::FieldConstant(BigUint::from(2u32)).mock(), + Expression::IntConstant(1usize.into()).mock(), + Expression::IntConstant(2usize.into()).mock(), ], } .mock(), @@ -3479,13 +4182,12 @@ mod tests { } .mock()], statements: foo_statements, - signature: UnresolvedSignature { - inputs: vec![UnresolvedType::FieldElement.mock()], - outputs: vec![ + signature: UnresolvedSignature::new() + .inputs(vec![UnresolvedType::FieldElement.mock()]) + .outputs(vec![ UnresolvedType::FieldElement.mock(), UnresolvedType::FieldElement.mock(), - ], - }, + ]), } .mock(); @@ -3503,12 +4205,13 @@ mod tests { Assignee::Identifier("a").mock(), Assignee::Identifier("b").mock(), ], - Expression::FunctionCall("foo", vec![Expression::Identifier("x").mock()]).mock(), + Expression::FunctionCall("foo", None, vec![Expression::Identifier("x").mock()]) + .mock(), ) .mock(), Statement::Return( ExpressionList { - expressions: vec![Expression::FieldConstant(BigUint::from(1u32)).mock()], + expressions: vec![Expression::IntConstant(1usize.into()).mock()], } .mock(), ) @@ -3518,10 +4221,9 @@ mod tests { let main = Function { arguments: vec![], statements: main_statements, - signature: UnresolvedSignature { - inputs: vec![], - outputs: vec![UnresolvedType::FieldElement.mock()], - }, + signature: UnresolvedSignature::new() + .inputs(vec![]) + .outputs(vec![UnresolvedType::FieldElement.mock()]), } .mock(); @@ -3542,17 +4244,17 @@ mod tests { }; let mut state = - State::::new(vec![("main".into(), module)].into_iter().collect()); + State::::new(vec![((*MODULE_ID).clone(), module)].into_iter().collect()); - let mut checker = new_with_args(HashSet::new(), 0, HashSet::new()); + let mut checker: Checker = new_with_args(HashSet::new(), 0, HashSet::new()); assert_eq!( - checker.check_module(&"main".into(), &mut state), + checker.check_module(&*MODULE_ID, &mut state), Err(vec![Error { inner: ErrorInner { pos: Some((Position::mock(), Position::mock())), message: "Identifier \"x\" is undefined".into() }, - module_id: "main".into() + module_id: (*MODULE_ID).clone() }]) ); } @@ -3569,8 +4271,8 @@ mod tests { let foo_statements: Vec = vec![Statement::Return( ExpressionList { expressions: vec![ - Expression::FieldConstant(BigUint::from(1u32)).mock(), - Expression::FieldConstant(BigUint::from(2u32)).mock(), + Expression::IntConstant(1usize.into()).mock(), + Expression::IntConstant(2usize.into()).mock(), ], } .mock(), @@ -3580,13 +4282,10 @@ mod tests { let foo = Function { arguments: vec![], statements: foo_statements, - signature: UnresolvedSignature { - inputs: vec![], - outputs: vec![ - UnresolvedType::FieldElement.mock(), - UnresolvedType::FieldElement.mock(), - ], - }, + signature: UnresolvedSignature::new().inputs(vec![]).outputs(vec![ + UnresolvedType::FieldElement.mock(), + UnresolvedType::FieldElement.mock(), + ]), } .mock(); @@ -3596,7 +4295,7 @@ mod tests { Assignee::Identifier("a").mock(), Assignee::Identifier("b").mock(), ], - Expression::FunctionCall("foo", vec![]).mock(), + Expression::FunctionCall("foo", None, vec![]).mock(), ) .mock(), Statement::Return( @@ -3611,10 +4310,7 @@ mod tests { let main = Function { arguments: vec![], statements: main_statements, - signature: UnresolvedSignature { - inputs: vec![], - outputs: vec![], - }, + signature: UnresolvedSignature::new().inputs(vec![]).outputs(vec![]), } .mock(); @@ -3635,25 +4331,25 @@ mod tests { }; let mut state = - State::::new(vec![("main".into(), module)].into_iter().collect()); + State::::new(vec![((*MODULE_ID).clone(), module)].into_iter().collect()); - let mut checker = new_with_args(HashSet::new(), 0, HashSet::new()); + let mut checker: Checker = new_with_args(HashSet::new(), 0, HashSet::new()); assert_eq!( - checker.check_module(&"main".into(), &mut state), + checker.check_module(&*MODULE_ID, &mut state), Err(vec![ Error { inner: ErrorInner { pos: Some((Position::mock(), Position::mock())), message: "Variable `a` is undeclared".into() }, - module_id: "main".into() + module_id: (*MODULE_ID).clone() }, Error { inner: ErrorInner { pos: Some((Position::mock(), Position::mock())), message: "Variable `b` is undeclared".into() }, - module_id: "main".into() + module_id: (*MODULE_ID).clone() } ]) ); @@ -3671,7 +4367,7 @@ mod tests { let foo_statements: Vec = vec![Statement::Return( ExpressionList { - expressions: vec![Expression::FieldConstant(BigUint::from(1u32)).mock()], + expressions: vec![Expression::IntConstant(1usize.into()).mock()], } .mock(), ) @@ -3680,10 +4376,9 @@ mod tests { let foo = Function { arguments: vec![], statements: foo_statements, - signature: UnresolvedSignature { - inputs: vec![], - outputs: vec![UnresolvedType::FieldElement.mock()], - }, + signature: UnresolvedSignature::new() + .inputs(vec![]) + .outputs(vec![UnresolvedType::FieldElement.mock()]), } .mock(); @@ -3691,15 +4386,19 @@ mod tests { Statement::Declaration( absy::Variable::new( "a", - UnresolvedType::array(UnresolvedType::FieldElement.mock(), 1).mock(), + UnresolvedType::array( + UnresolvedType::FieldElement.mock(), + Expression::IntConstant(1usize.into()).mock(), + ) + .mock(), ) .mock(), ) .mock(), Statement::Definition( - Assignee::Identifier("a".into()).mock(), + Assignee::Identifier("a").mock(), Expression::InlineArray(vec![absy::SpreadOrExpression::Expression( - Expression::FieldConstant(BigUint::from(0u32)).mock(), + Expression::IntConstant(0usize.into()).mock(), )]) .mock(), ) @@ -3708,11 +4407,11 @@ mod tests { vec![Assignee::Select( box Assignee::Identifier("a").mock(), box RangeOrExpression::Expression( - absy::Expression::FieldConstant(BigUint::from(0u32)).mock(), + absy::Expression::IntConstant(0usize.into()).mock(), ), ) .mock()], - Expression::FunctionCall("foo", vec![]).mock(), + Expression::FunctionCall("foo", None, vec![]).mock(), ) .mock(), Statement::Return( @@ -3727,10 +4426,7 @@ mod tests { let main = Function { arguments: vec![], statements: main_statements, - signature: UnresolvedSignature { - inputs: vec![], - outputs: vec![], - }, + signature: UnresolvedSignature::new().inputs(vec![]).outputs(vec![]), } .mock(); @@ -3751,10 +4447,10 @@ mod tests { }; let mut state = - State::::new(vec![("main".into(), module)].into_iter().collect()); + State::::new(vec![((*MODULE_ID).clone(), module)].into_iter().collect()); - let mut checker = new_with_args(HashSet::new(), 0, HashSet::new()); - assert!(checker.check_module(&"main".into(), &mut state).is_ok()); + let mut checker: Checker = new_with_args(HashSet::new(), 0, HashSet::new()); + assert!(checker.check_module(&*MODULE_ID, &mut state).is_ok()); } #[test] @@ -3763,11 +4459,12 @@ mod tests { // 1 == foo() // return // should fail + let bar_statements: Vec = vec![ Statement::Assertion( Expression::Eq( - box Expression::FieldConstant(BigUint::from(1u32)).mock(), - box Expression::FunctionCall("foo", vec![]).mock(), + box Expression::IntConstant(1usize.into()).mock(), + box Expression::FunctionCall("foo", None, vec![]).mock(), ) .mock(), ) @@ -3789,11 +4486,10 @@ mod tests { .mock(); let types = HashMap::new(); - let module_id = "".into(); - let mut checker = new_with_args(HashSet::new(), 0, HashSet::new()); + let mut checker: Checker = new_with_args(HashSet::new(), 0, HashSet::new()); assert_eq!( - checker.check_function::(bar, &module_id, &types), + checker.check_function(bar, &*MODULE_ID, &types), Err(vec![ErrorInner { pos: Some((Position::mock(), Position::mock())), @@ -3822,22 +4518,18 @@ mod tests { let bar = Function { arguments: vec![], statements: bar_statements, - signature: UnresolvedSignature { - inputs: vec![], - outputs: vec![ - UnresolvedType::FieldElement.mock(), - UnresolvedType::FieldElement.mock(), - ], - }, + signature: UnresolvedSignature::new().inputs(vec![]).outputs(vec![ + UnresolvedType::FieldElement.mock(), + UnresolvedType::FieldElement.mock(), + ]), } .mock(); let types = HashMap::new(); - let module_id = "".into(); - let mut checker = new_with_args(HashSet::new(), 0, HashSet::new()); + let mut checker: Checker = new_with_args(HashSet::new(), 0, HashSet::new()); assert_eq!( - checker.check_function::(bar, &module_id, &types), + checker.check_function(bar, &*MODULE_ID, &types), Err(vec![ErrorInner { pos: Some((Position::mock(), Position::mock())), message: "Identifier \"a\" is undefined".into() @@ -3868,7 +4560,7 @@ mod tests { Assignee::Identifier("a").mock(), Assignee::Identifier("b").mock(), ], - Expression::FunctionCall("foo", vec![]).mock(), + Expression::FunctionCall("foo", None, vec![]).mock(), ) .mock(), Statement::Return( @@ -3893,10 +4585,14 @@ mod tests { typed_absy::Variable::field_element("b").into(), ], TypedExpressionList::FunctionCall( - FunctionKey::with_id("foo").signature( - Signature::new().outputs(vec![Type::FieldElement, Type::FieldElement]), + DeclarationFunctionKey::with_location((*MODULE_ID).clone(), "foo").signature( + DeclarationSignature::new().outputs(vec![ + DeclarationType::FieldElement, + DeclarationType::FieldElement, + ]), ), vec![], + vec![], vec![Type::FieldElement, Type::FieldElement], ), ), @@ -3907,12 +4603,13 @@ mod tests { .into()]), ]; - let foo = FunctionKey { + let foo = DeclarationFunctionKey { + module: (*MODULE_ID).clone(), id: "foo", - signature: Signature { - inputs: vec![], - outputs: vec![Type::FieldElement, Type::FieldElement], - }, + signature: DeclarationSignature::new().inputs(vec![]).outputs(vec![ + DeclarationType::FieldElement, + DeclarationType::FieldElement, + ]), }; let mut functions = HashSet::new(); @@ -3921,32 +4618,62 @@ mod tests { let bar = Function { arguments: vec![], statements: bar_statements, - signature: UnresolvedSignature { - inputs: vec![], - outputs: vec![UnresolvedType::FieldElement.mock()], - }, + signature: UnresolvedSignature::new() + .inputs(vec![]) + .outputs(vec![UnresolvedType::FieldElement.mock()]), } .mock(); let bar_checked = TypedFunction { arguments: vec![], statements: bar_statements_checked, - signature: Signature { - inputs: vec![], - outputs: vec![Type::FieldElement], - }, + signature: DeclarationSignature::new() + .inputs(vec![]) + .outputs(vec![DeclarationType::FieldElement]), }; let types = HashMap::new(); - let module_id = "".into(); - let mut checker = new_with_args(HashSet::new(), 0, functions); + let mut checker: Checker = new_with_args(HashSet::new(), 0, functions); assert_eq!( - checker.check_function(bar, &module_id, &types), + checker.check_function(bar, &*MODULE_ID, &types), Ok(bar_checked) ); } + #[test] + fn duplicate_argument_name() { + // def main(field a, bool a): + // return + + // should fail + + let mut f = function0(); + f.value.arguments = vec![ + absy::Parameter::private( + absy::Variable::new("a", UnresolvedType::FieldElement.mock()).mock(), + ) + .mock(), + absy::Parameter::private( + absy::Variable::new("a", UnresolvedType::Boolean.mock()).mock(), + ) + .mock(), + ]; + f.value.signature = UnresolvedSignature::new().inputs(vec![ + UnresolvedType::FieldElement.mock(), + UnresolvedType::Boolean.mock(), + ]); + + let mut checker: Checker = new_with_args(HashSet::new(), 0, HashSet::new()); + assert_eq!( + checker + .check_function(f, &*MODULE_ID, &HashMap::new()) + .unwrap_err()[0] + .message, + "Duplicate name in function definition: `a` was previously declared as an argument or a generic constant" + ); + } + #[test] fn duplicate_main_function() { // def main(a): @@ -3957,7 +4684,7 @@ mod tests { // should fail let main1_statements: Vec = vec![Statement::Return( ExpressionList { - expressions: vec![Expression::FieldConstant(BigUint::from(1u32)).mock()], + expressions: vec![Expression::IntConstant(1usize.into()).mock()], } .mock(), ) @@ -3971,7 +4698,7 @@ mod tests { let main2_statements: Vec = vec![Statement::Return( ExpressionList { - expressions: vec![Expression::FieldConstant(BigUint::from(1u32)).mock()], + expressions: vec![Expression::IntConstant(1usize.into()).mock()], } .mock(), ) @@ -3982,20 +4709,18 @@ mod tests { let main1 = Function { arguments: main1_arguments, statements: main1_statements, - signature: UnresolvedSignature { - inputs: vec![UnresolvedType::FieldElement.mock()], - outputs: vec![UnresolvedType::FieldElement.mock()], - }, + signature: UnresolvedSignature::new() + .inputs(vec![UnresolvedType::FieldElement.mock()]) + .outputs(vec![UnresolvedType::FieldElement.mock()]), } .mock(); let main2 = Function { arguments: main2_arguments, statements: main2_statements, - signature: UnresolvedSignature { - inputs: vec![], - outputs: vec![UnresolvedType::FieldElement.mock()], - }, + signature: UnresolvedSignature::new() + .inputs(vec![]) + .outputs(vec![UnresolvedType::FieldElement.mock()]), } .mock(); @@ -4018,19 +4743,21 @@ mod tests { }; let program = Program { - modules: vec![("main".into(), main_module)].into_iter().collect(), - main: "main".into(), + modules: vec![((*MODULE_ID).clone(), main_module)] + .into_iter() + .collect(), + main: (*MODULE_ID).clone(), }; - let mut checker = Checker::new(); + let mut checker: Checker = Checker::new(); assert_eq!( - checker.check_program::(program), + checker.check_program(program), Err(vec![Error { inner: ErrorInner { pos: None, message: "Only one main function allowed, found 2".into() }, - module_id: "main".into() + module_id: (*MODULE_ID).clone() }]) ); } @@ -4043,14 +4770,13 @@ mod tests { // should fail let types = HashMap::new(); - let module_id = "".into(); - let mut checker = Checker::new(); + let mut checker: Checker = Checker::new(); let _: Result, Vec> = checker.check_statement( Statement::Declaration( absy::Variable::new("a", UnresolvedType::FieldElement.mock()).mock(), ) .mock(), - &module_id, + &*MODULE_ID, &types, ); let s2_checked: Result, Vec> = checker @@ -4059,7 +4785,7 @@ mod tests { absy::Variable::new("a", UnresolvedType::FieldElement.mock()).mock(), ) .mock(), - &module_id, + &*MODULE_ID, &types, ); assert_eq!( @@ -4079,15 +4805,14 @@ mod tests { // should fail let types = HashMap::new(); - let module_id = "".into(); - let mut checker = Checker::new(); + let mut checker: Checker = Checker::new(); let _: Result, Vec> = checker.check_statement( Statement::Declaration( absy::Variable::new("a", UnresolvedType::FieldElement.mock()).mock(), ) .mock(), - &module_id, + &*MODULE_ID, &types, ); let s2_checked: Result, Vec> = checker @@ -4096,7 +4821,7 @@ mod tests { absy::Variable::new("a", UnresolvedType::Boolean.mock()).mock(), ) .mock(), - &module_id, + &*MODULE_ID, &types, ); assert_eq!( @@ -4110,13 +4835,12 @@ mod tests { mod structs { use super::*; + use crate::typed_absy::types::StructMember; /// solver function to create a module at location "" with a single symbol `Foo { foo: field }` fn create_module_with_foo( s: StructDefinition<'static>, - ) -> (Checker<'static>, State<'static, Bn128Field>) { - let module_id: PathBuf = "".into(); - + ) -> (Checker, State) { let module: Module = Module { imports: vec![], symbols: vec![SymbolDeclaration { @@ -4126,12 +4850,13 @@ mod tests { .mock()], }; - let mut state = - State::::new(vec![(module_id.clone(), module)].into_iter().collect()); + let mut state = State::::new( + vec![((*MODULE_ID).clone(), module)].into_iter().collect(), + ); - let mut checker = Checker::new(); + let mut checker: Checker = Checker::new(); - checker.check_module(&module_id, &mut state).unwrap(); + checker.check_module(&*MODULE_ID, &mut state).unwrap(); (checker, state) } @@ -4143,17 +4868,20 @@ mod tests { #[test] fn empty_def() { // an empty struct should be allowed to be defined - let module_id = "".into(); let types = HashMap::new(); - let declaration = StructDefinition { fields: vec![] }.mock(); + let declaration: StructDefinitionNode = StructDefinition { fields: vec![] }.mock(); - let expected_type = Type::Struct(StructType::new("".into(), "Foo".into(), vec![])); + let expected_type = DeclarationType::Struct(DeclarationStructType::new( + "".into(), + "Foo".into(), + vec![], + )); assert_eq!( - Checker::new().check_struct_type_declaration( + Checker::::new().check_struct_type_declaration( "Foo".into(), declaration, - &module_id, + &*MODULE_ID, &types ), Ok(expected_type) @@ -4163,9 +4891,8 @@ mod tests { #[test] fn valid_def() { // a valid struct should be allowed to be defined - let module_id = "".into(); let types = HashMap::new(); - let declaration = StructDefinition { + let declaration: StructDefinitionNode = StructDefinition { fields: vec![ StructDefinitionField { id: "foo", @@ -4181,87 +4908,32 @@ mod tests { } .mock(); - let expected_type = Type::Struct(StructType::new( + let expected_type = DeclarationType::Struct(DeclarationStructType::new( "".into(), "Foo".into(), vec![ - StructMember::new("foo".into(), Type::FieldElement), - StructMember::new("bar".into(), Type::Boolean), + DeclarationStructMember::new("foo".into(), DeclarationType::FieldElement), + DeclarationStructMember::new("bar".into(), DeclarationType::Boolean), ], )); assert_eq!( - Checker::new().check_struct_type_declaration( + Checker::::new().check_struct_type_declaration( "Foo".into(), declaration, - &module_id, + &*MODULE_ID, &types ), Ok(expected_type) ); } - #[test] - fn preserve_order() { - // two structs with inverted members are not equal - let module_id = "".into(); - let types = HashMap::new(); - - let declaration0 = StructDefinition { - fields: vec![ - StructDefinitionField { - id: "foo", - ty: UnresolvedType::FieldElement.mock(), - } - .mock(), - StructDefinitionField { - id: "bar", - ty: UnresolvedType::Boolean.mock(), - } - .mock(), - ], - } - .mock(); - - let declaration1 = StructDefinition { - fields: vec![ - StructDefinitionField { - id: "bar", - ty: UnresolvedType::Boolean.mock(), - } - .mock(), - StructDefinitionField { - id: "foo", - ty: UnresolvedType::FieldElement.mock(), - } - .mock(), - ], - } - .mock(); - - assert_ne!( - Checker::new().check_struct_type_declaration( - "Foo".into(), - declaration0, - &module_id, - &types - ), - Checker::new().check_struct_type_declaration( - "Foo".into(), - declaration1, - &module_id, - &types - ) - ); - } - #[test] fn duplicate_member_def() { // definition of a struct with a duplicate member should be rejected - let module_id = "".into(); let types = HashMap::new(); - let declaration = StructDefinition { + let declaration: StructDefinitionNode = StructDefinition { fields: vec![ StructDefinitionField { id: "foo", @@ -4278,11 +4950,11 @@ mod tests { .mock(); assert_eq!( - Checker::new() + Checker::::new() .check_struct_type_declaration( "Foo".into(), declaration, - &module_id, + &*MODULE_ID, &types ) .unwrap_err()[0] @@ -4298,8 +4970,6 @@ mod tests { // struct Foo = { foo: field } // struct Bar = { foo: Foo } - let module_id: PathBuf = "".into(); - let module: Module = Module { imports: vec![], symbols: vec![ @@ -4335,26 +5005,29 @@ mod tests { }; let mut state = State::::new( - vec![(module_id.clone(), module)].into_iter().collect(), + vec![((*MODULE_ID).clone(), module)].into_iter().collect(), ); - assert!(Checker::new().check_module(&module_id, &mut state).is_ok()); + assert!(Checker::new().check_module(&*MODULE_ID, &mut state).is_ok()); assert_eq!( state .types - .get(&module_id) + .get(&*MODULE_ID) .unwrap() .get(&"Bar".to_string()) .unwrap(), - &Type::Struct(StructType::new( - module_id.clone(), + &DeclarationType::Struct(DeclarationStructType::new( + (*MODULE_ID).clone(), "Bar".into(), - vec![StructMember::new( + vec![DeclarationStructMember::new( "foo".into(), - Type::Struct(StructType::new( - module_id, + DeclarationType::Struct(DeclarationStructType::new( + (*MODULE_ID).clone(), "Foo".into(), - vec![StructMember::new("foo".into(), Type::FieldElement)] + vec![DeclarationStructMember::new( + "foo".into(), + DeclarationType::FieldElement + )] )) )] )) @@ -4367,8 +5040,6 @@ mod tests { // struct Bar = { foo: Foo } - let module_id: PathBuf = "".into(); - let module: Module = Module { imports: vec![], symbols: vec![SymbolDeclaration { @@ -4388,10 +5059,12 @@ mod tests { }; let mut state = State::::new( - vec![(module_id.clone(), module)].into_iter().collect(), + vec![((*MODULE_ID).clone(), module)].into_iter().collect(), ); - assert!(Checker::new().check_module(&module_id, &mut state).is_err()); + assert!(Checker::new() + .check_module(&*MODULE_ID, &mut state) + .is_err()); } #[test] @@ -4400,8 +5073,6 @@ mod tests { // struct Foo = { foo: Foo } - let module_id: PathBuf = "".into(); - let module: Module = Module { imports: vec![], symbols: vec![SymbolDeclaration { @@ -4421,10 +5092,12 @@ mod tests { }; let mut state = State::::new( - vec![(module_id.clone(), module)].into_iter().collect(), + vec![((*MODULE_ID).clone(), module)].into_iter().collect(), ); - assert!(Checker::new().check_module(&module_id, &mut state).is_err()); + assert!(Checker::new() + .check_module(&*MODULE_ID, &mut state) + .is_err()); } #[test] @@ -4434,8 +5107,6 @@ mod tests { // struct Foo = { bar: Bar } // struct Bar = { foo: Foo } - let module_id: PathBuf = "".into(); - let module: Module = Module { imports: vec![], symbols: vec![ @@ -4471,10 +5142,12 @@ mod tests { }; let mut state = State::::new( - vec![(module_id.clone(), module)].into_iter().collect(), + vec![((*MODULE_ID).clone(), module)].into_iter().collect(), ); - assert!(Checker::new().check_module(&module_id, &mut state).is_err()); + assert!(Checker::new() + .check_module(&*MODULE_ID, &mut state) + .is_err()); } } @@ -4491,7 +5164,7 @@ mod tests { // an undefined type cannot be checked // Bar - let (checker, state) = create_module_with_foo(StructDefinition { + let (mut checker, state) = create_module_with_foo(StructDefinition { fields: vec![StructDefinitionField { id: "foo", ty: UnresolvedType::FieldElement.mock(), @@ -4502,7 +5175,7 @@ mod tests { assert_eq!( checker.check_type( UnresolvedType::User("Foo".into()).mock(), - &PathBuf::from(MODULE_ID).into(), + &*MODULE_ID, &state.types ), Ok(Type::Struct(StructType::new( @@ -4516,7 +5189,7 @@ mod tests { checker .check_type( UnresolvedType::User("Bar".into()).mock(), - &PathBuf::from(MODULE_ID).into(), + &*MODULE_ID, &state.types ) .unwrap_err() @@ -4524,121 +5197,6 @@ mod tests { "Undefined type Bar" ); } - - #[test] - fn parameter() { - // a defined type can be used as parameter - - // an undefined type cannot be used as parameter - - let (checker, state) = create_module_with_foo(StructDefinition { - fields: vec![StructDefinitionField { - id: "foo", - ty: UnresolvedType::FieldElement.mock(), - } - .mock()], - }); - - assert_eq!( - checker.check_parameter( - absy::Parameter { - id: - absy::Variable::new("a", UnresolvedType::User("Foo".into()).mock(),) - .mock(), - private: true, - } - .mock(), - &PathBuf::from(MODULE_ID).into(), - &state.types, - ), - Ok(Parameter { - id: Variable::with_id_and_type( - "a", - Type::Struct(StructType::new( - "".into(), - "Foo".into(), - vec![StructMember::new("foo".into(), Type::FieldElement)] - )) - ), - private: true - }) - ); - - assert_eq!( - checker - .check_parameter( - absy::Parameter { - id: absy::Variable::new( - "a", - UnresolvedType::User("Bar".into()).mock(), - ) - .mock(), - private: true, - } - .mock(), - &PathBuf::from(MODULE_ID).into(), - &state.types, - ) - .unwrap_err()[0] - .message, - "Undefined type Bar" - ); - } - - #[test] - fn variable_declaration() { - // a defined type can be used in a variable declaration - - // an undefined type cannot be used in a variable declaration - - let (mut checker, state) = create_module_with_foo(StructDefinition { - fields: vec![StructDefinitionField { - id: "foo", - ty: UnresolvedType::FieldElement.mock(), - } - .mock()], - }); - - assert_eq!( - checker.check_statement::( - Statement::Declaration( - absy::Variable::new("a", UnresolvedType::User("Foo".into()).mock(),) - .mock() - ) - .mock(), - &PathBuf::from(MODULE_ID).into(), - &state.types, - ), - Ok(TypedStatement::Declaration(Variable::with_id_and_type( - "a", - Type::Struct(StructType::new( - "".into(), - "Foo".into(), - vec![StructMember::new("foo".into(), Type::FieldElement)] - )) - ))) - ); - - assert_eq!( - checker - .check_parameter( - absy::Parameter { - id: absy::Variable::new( - "a", - UnresolvedType::User("Bar".into()).mock(), - ) - .mock(), - private: true, - } - .mock(), - &PathBuf::from(MODULE_ID).into(), - &state.types, - ) - .unwrap_err()[0] - .message, - "Undefined type Bar" - ); - } } /// tests about accessing members @@ -4661,20 +5219,17 @@ mod tests { }); assert_eq!( - checker.check_expression::( + checker.check_expression( Expression::Member( box Expression::InlineStruct( "Foo".into(), - vec![( - "foo", - Expression::FieldConstant(BigUint::from(42u32)).mock() - )] + vec![("foo", Expression::IntConstant(42usize.into()).mock())] ) .mock(), "foo".into() ) .mock(), - &PathBuf::from(MODULE_ID).into(), + &*MODULE_ID, &state.types ), Ok(FieldElementExpression::Member( @@ -4710,20 +5265,17 @@ mod tests { assert_eq!( checker - .check_expression::( + .check_expression( Expression::Member( box Expression::InlineStruct( "Foo".into(), - vec![( - "foo", - Expression::FieldConstant(BigUint::from(42u32)).mock() - )] + vec![("foo", Expression::IntConstant(42usize.into()).mock())] ) .mock(), "bar".into() ) .mock(), - &PathBuf::from(MODULE_ID).into(), + &*MODULE_ID, &state.types ) .unwrap_err() @@ -4751,16 +5303,13 @@ mod tests { assert_eq!( checker - .check_expression::( + .check_expression( Expression::InlineStruct( "Bar".into(), - vec![( - "foo", - Expression::FieldConstant(BigUint::from(42u32)).mock() - )] + vec![("foo", Expression::IntConstant(42usize.into()).mock())] ) .mock(), - &PathBuf::from(MODULE_ID).into(), + &*MODULE_ID, &state.types ) .unwrap_err() @@ -4792,19 +5341,16 @@ mod tests { }); assert_eq!( - checker.check_expression::( + checker.check_expression( Expression::InlineStruct( "Foo".into(), vec![ - ( - "foo", - Expression::FieldConstant(BigUint::from(42u32)).mock() - ), + ("foo", Expression::IntConstant(42usize.into()).mock()), ("bar", Expression::BooleanConstant(true).mock()) ] ) .mock(), - &PathBuf::from(MODULE_ID).into(), + &*MODULE_ID, &state.types ), Ok(StructExpressionInner::Value(vec![ @@ -4846,19 +5392,16 @@ mod tests { }); assert_eq!( - checker.check_expression::( + checker.check_expression( Expression::InlineStruct( "Foo".into(), vec![ ("bar", Expression::BooleanConstant(true).mock()), - ( - "foo", - Expression::FieldConstant(BigUint::from(42u32)).mock() - ) + ("foo", Expression::IntConstant(42usize.into()).mock()) ] ) .mock(), - &PathBuf::from(MODULE_ID).into(), + &*MODULE_ID, &state.types ), Ok(StructExpressionInner::Value(vec![ @@ -4901,16 +5444,13 @@ mod tests { assert_eq!( checker - .check_expression::( + .check_expression( Expression::InlineStruct( "Foo".into(), - vec![( - "foo", - Expression::FieldConstant(BigUint::from(42u32)).mock() - )] + vec![("foo", Expression::IntConstant(42usize.into()).mock())] ) .mock(), - &PathBuf::from(MODULE_ID).into(), + &*MODULE_ID, &state.types ) .unwrap_err() @@ -4945,7 +5485,7 @@ mod tests { assert_eq!( checker - .check_expression::( + .check_expression( Expression::InlineStruct( "Foo".into(), vec![( @@ -4953,11 +5493,11 @@ mod tests { Expression::BooleanConstant(true).mock() ),( "foo", - Expression::FieldConstant(BigUint::from(42u32)).mock() + Expression::IntConstant(42usize.into()).mock() )] ) .mock(), - &PathBuf::from(MODULE_ID).into(), + &*MODULE_ID, &state.types ).unwrap_err() .message, @@ -4966,35 +5506,137 @@ mod tests { assert_eq!( checker - .check_expression::( + .check_expression( Expression::InlineStruct( "Foo".into(), vec![ - ( - "bar", - Expression::FieldConstant(BigUint::from(42u32)).mock() - ), - ( - "foo", - Expression::FieldConstant(BigUint::from(42u32)).mock() - ) + ("bar", Expression::IntConstant(42usize.into()).mock()), + ("foo", Expression::IntConstant(42usize.into()).mock()) ] ) .mock(), - &PathBuf::from(MODULE_ID).into(), + &*MODULE_ID, &state.types ) .unwrap_err() .message, - "Member bar of struct Foo has type bool, found 42 of type field" + "Member bar of struct Foo has type bool, found 42 of type {integer}" ); } } } + mod int_inference { + use super::*; + + #[test] + fn two_candidates() { + // def foo(field a) -> field: + // return 0 + + // def foo(u32 a) -> field: + // return 0 + + // def main() -> field: + // return foo(0) + + // should fail + + let mut foo_field = function0(); + + foo_field.value.arguments = vec![absy::Parameter::private( + absy::Variable { + id: "a", + _type: UnresolvedType::FieldElement.mock(), + } + .mock(), + ) + .mock()]; + foo_field.value.statements = vec![Statement::Return( + ExpressionList { + expressions: vec![Expression::IntConstant(0usize.into()).mock()], + } + .mock(), + ) + .mock()]; + foo_field.value.signature = UnresolvedSignature::new() + .inputs(vec![UnresolvedType::FieldElement.mock()]) + .outputs(vec![UnresolvedType::FieldElement.mock()]); + + let mut foo_u32 = function0(); + + foo_u32.value.arguments = vec![absy::Parameter::private( + absy::Variable { + id: "a", + _type: UnresolvedType::Uint(32).mock(), + } + .mock(), + ) + .mock()]; + foo_u32.value.statements = vec![Statement::Return( + ExpressionList { + expressions: vec![Expression::IntConstant(0usize.into()).mock()], + } + .mock(), + ) + .mock()]; + foo_u32.value.signature = UnresolvedSignature::new() + .inputs(vec![UnresolvedType::Uint(32).mock()]) + .outputs(vec![UnresolvedType::FieldElement.mock()]); + + let mut main = function0(); + + main.value.statements = vec![Statement::Return( + ExpressionList { + expressions: vec![Expression::FunctionCall( + "foo", + None, + vec![Expression::IntConstant(0usize.into()).mock()], + ) + .mock()], + } + .mock(), + ) + .mock()]; + main.value.signature = + UnresolvedSignature::new().outputs(vec![UnresolvedType::FieldElement.mock()]); + + let m = Module::with_symbols(vec![ + absy::SymbolDeclaration { + id: "foo", + symbol: Symbol::HereFunction(foo_field), + } + .mock(), + absy::SymbolDeclaration { + id: "foo", + symbol: Symbol::HereFunction(foo_u32), + } + .mock(), + absy::SymbolDeclaration { + id: "main", + symbol: Symbol::HereFunction(main), + } + .mock(), + ]); + + let p = Program { + main: "".into(), + modules: vec![("".into(), m)].into_iter().collect(), + }; + + let errors = Checker::::new().check_program(p).unwrap_err(); + + assert_eq!(errors.len(), 1); + + assert_eq!( + errors[0].inner.message, + "Ambiguous call to function foo, 2 candidates were found. Please be more explicit." + ); + } + } + mod assignee { use super::*; - use num_bigint::BigUint; #[test] fn identifier() { @@ -5002,21 +5644,22 @@ mod tests { let a = Assignee::Identifier("a").mock(); let types = HashMap::new(); - let module_id = "".into(); - let mut checker: Checker = Checker::new(); + + let mut checker: Checker = Checker::new(); + checker - .check_statement::( + .check_statement( Statement::Declaration( absy::Variable::new("a", UnresolvedType::FieldElement.mock()).mock(), ) .mock(), - &module_id, + &*MODULE_ID, &types, ) .unwrap(); assert_eq!( - checker.check_assignee::(a, &module_id, &types), + checker.check_assignee(a, &*MODULE_ID, &types), Ok(TypedAssignee::Identifier( typed_absy::Variable::field_element("a") )) @@ -5029,36 +5672,40 @@ mod tests { // a[2] = 42 let a = Assignee::Select( box Assignee::Identifier("a").mock(), - box RangeOrExpression::Expression( - Expression::FieldConstant(BigUint::from(2u32)).mock(), - ), + box RangeOrExpression::Expression(Expression::IntConstant(2usize.into()).mock()), ) .mock(); let types = HashMap::new(); - let module_id = "".into(); - let mut checker: Checker = Checker::new(); + let mut checker: Checker = Checker::new(); checker - .check_statement::( + .check_statement( Statement::Declaration( absy::Variable::new( "a", - UnresolvedType::array(UnresolvedType::FieldElement.mock(), 33).mock(), + UnresolvedType::array( + UnresolvedType::FieldElement.mock(), + Expression::IntConstant(33usize.into()).mock(), + ) + .mock(), ) .mock(), ) .mock(), - &module_id, + &*MODULE_ID, &types, ) .unwrap(); assert_eq!( - checker.check_assignee::(a, &module_id, &types), + checker.check_assignee(a, &*MODULE_ID, &types), Ok(TypedAssignee::Select( - box TypedAssignee::Identifier(typed_absy::Variable::field_array("a", 33)), - box FieldElementExpression::Number(Bn128Field::from(2u32)).into() + box TypedAssignee::Identifier(typed_absy::Variable::field_array( + "a", + 33u32.into() + )), + box 2u32.into() )) ); } @@ -5067,55 +5714,56 @@ mod tests { fn array_of_array_element() { // field[33][42] a // a[1][2] - let a = Assignee::Select( + let a: AssigneeNode = Assignee::Select( box Assignee::Select( box Assignee::Identifier("a").mock(), box RangeOrExpression::Expression( - Expression::FieldConstant(BigUint::from(1u32)).mock(), + Expression::IntConstant(1usize.into()).mock(), ), ) .mock(), - box RangeOrExpression::Expression( - Expression::FieldConstant(BigUint::from(2u32)).mock(), - ), + box RangeOrExpression::Expression(Expression::IntConstant(2usize.into()).mock()), ) .mock(); let types = HashMap::new(); - let module_id = "".into(); - let mut checker: Checker = Checker::new(); + + let mut checker: Checker = Checker::new(); checker - .check_statement::( + .check_statement( Statement::Declaration( absy::Variable::new( "a", UnresolvedType::array( - UnresolvedType::array(UnresolvedType::FieldElement.mock(), 33) - .mock(), - 42, + UnresolvedType::array( + UnresolvedType::FieldElement.mock(), + Expression::IntConstant(33usize.into()).mock(), + ) + .mock(), + Expression::IntConstant(42usize.into()).mock(), ) .mock(), ) .mock(), ) .mock(), - &module_id, + &*MODULE_ID, &types, ) .unwrap(); assert_eq!( - checker.check_assignee::(a, &module_id, &types), + checker.check_assignee(a, &*MODULE_ID, &types), Ok(TypedAssignee::Select( box TypedAssignee::Select( box TypedAssignee::Identifier(typed_absy::Variable::array( "a", - Type::array(Type::FieldElement, 33), - 42 + Type::array((Type::FieldElement, 33u32)), + 42u32, )), - box FieldElementExpression::Number(Bn128Field::from(1u32)).into() + box 1u32.into() ), - box FieldElementExpression::Number(Bn128Field::from(2u32)).into() + box 2u32.into() )) ); } diff --git a/zokrates_core/src/solvers/mod.rs b/zokrates_core/src/solvers/mod.rs index 7f5b9b2bc..d6bc0c0c6 100644 --- a/zokrates_core/src/solvers/mod.rs +++ b/zokrates_core/src/solvers/mod.rs @@ -1,10 +1,5 @@ -#[cfg(feature = "bellman")] -use pairing_ce::bn256::Bn256; use serde::{Deserialize, Serialize}; use std::fmt; -#[cfg(feature = "bellman")] -use zokrates_embed::generate_sha256_round_witness; -use zokrates_field::{Bn128Field, Field}; #[derive(Clone, PartialEq, Debug, Serialize, Deserialize, Hash, Eq)] pub enum Solver { @@ -48,168 +43,3 @@ impl Solver { Solver::Bits(width) } } - -pub trait Executable { - fn execute(&self, inputs: &Vec) -> Result, String>; -} - -impl Executable for Solver { - fn execute(&self, inputs: &Vec) -> Result, String> { - let (expected_input_count, expected_output_count) = self.get_signature(); - assert_eq!(inputs.len(), expected_input_count); - - let res = match self { - Solver::ConditionEq => match inputs[0].is_zero() { - true => vec![T::zero(), T::one()], - false => vec![ - T::one(), - T::one().checked_div(&inputs[0]).unwrap_or(T::one()), - ], - }, - Solver::Bits(bit_width) => { - let mut num = inputs[0].clone(); - let mut res = vec![]; - - for i in (0..*bit_width).rev() { - if T::from(2).pow(i) <= num { - num = num - T::from(2).pow(i); - res.push(T::one()); - } else { - res.push(T::zero()); - } - } - res - } - Solver::Xor => { - let x = inputs[0].clone(); - let y = inputs[1].clone(); - - vec![x.clone() + y.clone() - T::from(2) * x * y] - } - Solver::Or => { - let x = inputs[0].clone(); - let y = inputs[1].clone(); - - vec![x.clone() + y.clone() - x * y] - } - // res = b * c - (2b * c - b - c) * (a) - Solver::ShaAndXorAndXorAnd => { - let a = inputs[0].clone(); - let b = inputs[1].clone(); - let c = inputs[2].clone(); - vec![b.clone() * c.clone() - (T::from(2) * b.clone() * c.clone() - b - c) * a] - } - // res = a(b - c) + c - Solver::ShaCh => { - let a = inputs[0].clone(); - let b = inputs[1].clone(); - let c = inputs[2].clone(); - vec![a * (b - c.clone()) + c] - } - Solver::Div => vec![inputs[0] - .clone() - .checked_div(&inputs[1]) - .unwrap_or(T::one())], - Solver::EuclideanDiv => { - use num::CheckedDiv; - - let n = inputs[0].clone().to_biguint(); - let d = inputs[1].clone().to_biguint(); - - let q = n.checked_div(&d).unwrap_or(0u32.into()); - let r = n - d * &q; - vec![T::try_from(q).unwrap(), T::try_from(r).unwrap()] - } - #[cfg(feature = "bellman")] - Solver::Sha256Round => { - assert_eq!(T::id(), Bn128Field::id()); - let i = &inputs[0..512]; - let h = &inputs[512..]; - let to_fr = |x: &T| { - use pairing_ce::ff::{PrimeField, ScalarEngine}; - let s = x.to_dec_string(); - ::Fr::from_str(&s).unwrap() - }; - let i: Vec<_> = i.iter().map(|x| to_fr(x)).collect(); - let h: Vec<_> = h.iter().map(|x| to_fr(x)).collect(); - assert_eq!(h.len(), 256); - generate_sha256_round_witness::(&i, &h) - .into_iter() - .map(|x| { - use bellman_ce::pairing::ff::{PrimeField, PrimeFieldRepr}; - let mut res: Vec = vec![]; - x.into_repr().write_le(&mut res).unwrap(); - T::from_byte_vector(res) - }) - .collect() - } - }; - - assert_eq!(res.len(), expected_output_count); - - Ok(res) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use zokrates_field::Bn128Field; - - mod eq_condition { - - // Wanted: (Y = (X != 0) ? 1 : 0) - // # Y = if X == 0 then 0 else 1 fi - // # M = if X == 0 then 1 else 1/X fi - - use super::*; - - #[test] - fn execute() { - let cond_eq = Solver::ConditionEq; - let inputs = vec![0]; - let r = cond_eq - .execute(&inputs.iter().map(|&i| Bn128Field::from(i)).collect()) - .unwrap(); - let res: Vec = vec![0, 1].iter().map(|&i| Bn128Field::from(i)).collect(); - assert_eq!(r, &res[..]); - } - - #[test] - fn execute_non_eq() { - let cond_eq = Solver::ConditionEq; - let inputs = vec![1]; - let r = cond_eq - .execute(&inputs.iter().map(|&i| Bn128Field::from(i)).collect()) - .unwrap(); - let res: Vec = vec![1, 1].iter().map(|&i| Bn128Field::from(i)).collect(); - assert_eq!(r, &res[..]); - } - } - - #[test] - fn bits_of_one() { - let bits = Solver::Bits(Bn128Field::get_required_bits()); - let inputs = vec![Bn128Field::from(1)]; - let res = bits.execute(&inputs).unwrap(); - assert_eq!(res[253], Bn128Field::from(1)); - for i in 0..253 { - assert_eq!(res[i], Bn128Field::from(0)); - } - } - - #[test] - fn bits_of_42() { - let bits = Solver::Bits(Bn128Field::get_required_bits()); - let inputs = vec![Bn128Field::from(42)]; - let res = bits.execute(&inputs).unwrap(); - - assert_eq!(res[253], Bn128Field::from(0)); - assert_eq!(res[252], Bn128Field::from(1)); - assert_eq!(res[251], Bn128Field::from(0)); - assert_eq!(res[250], Bn128Field::from(1)); - assert_eq!(res[249], Bn128Field::from(0)); - assert_eq!(res[248], Bn128Field::from(1)); - assert_eq!(res[247], Bn128Field::from(0)); - } -} diff --git a/zokrates_core/src/static_analysis/bounds_checker.rs b/zokrates_core/src/static_analysis/bounds_checker.rs new file mode 100644 index 000000000..de43d5f0d --- /dev/null +++ b/zokrates_core/src/static_analysis/bounds_checker.rs @@ -0,0 +1,134 @@ +use crate::typed_absy::result_folder::*; +use crate::typed_absy::*; +use zokrates_field::Field; + +pub struct BoundsChecker; + +pub type Error = String; + +impl BoundsChecker { + pub fn check(p: TypedProgram) -> Result, Error> { + BoundsChecker.fold_program(p) + } + + pub fn check_select<'ast, T: Field, U: Select<'ast, T>>( + &mut self, + array: ArrayExpression<'ast, T>, + index: UExpression<'ast, T>, + ) -> Result { + let array = self.fold_array_expression(array)?; + let index = self.fold_uint_expression(index)?; + + match (array.get_array_type().size.as_inner(), index.as_inner()) { + (UExpressionInner::Value(size), UExpressionInner::Value(index)) => { + if index >= size { + return Err(format!( + "Out of bounds access: {}[{}] but {} is of size {}", + array, index, array, size + )); + } + } + _ => unreachable!(), + }; + + Ok(U::select(array, index)) + } +} + +impl<'ast, T: Field> ResultFolder<'ast, T> for BoundsChecker { + type Error = Error; + + fn fold_array_expression_inner( + &mut self, + ty: &ArrayType<'ast, T>, + e: ArrayExpressionInner<'ast, T>, + ) -> Result, Self::Error> { + match e { + ArrayExpressionInner::Select(box array, box index) => self + .check_select::<_, ArrayExpression<_>>(array, index) + .map(|a| a.into_inner()), + 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 ( + array.get_array_type().size.as_inner(), + from.as_inner(), + to.as_inner(), + ) { + ( + UExpressionInner::Value(size), + UExpressionInner::Value(from), + UExpressionInner::Value(to), + ) => { + if from > to { + return Err(format!( + "Slice is created from an invalid range {}..{}", + from, to + )); + } + + if from > size { + return Err(format!("Lower bound {} of slice {}[{}..{}] is out of bounds for array of size {}", from, array, from, to, size)); + } + + if to > size { + return Err(format!("Upper bound {} of slice {}[{}..{}] is out of bounds for array of size {}", to, array, from, to, size)); + } + } + _ => unreachable!(), + }; + + Ok(ArrayExpressionInner::Slice(box array, box from, box to)) + } + e => fold_array_expression_inner(self, ty, e), + } + } + + fn fold_struct_expression_inner( + &mut self, + ty: &StructType<'ast, T>, + e: StructExpressionInner<'ast, T>, + ) -> Result, Self::Error> { + match e { + StructExpressionInner::Select(box array, box index) => self + .check_select::<_, StructExpression<_>>(array, index) + .map(|a| a.into_inner()), + e => fold_struct_expression_inner(self, ty, e), + } + } + + fn fold_field_expression( + &mut self, + e: FieldElementExpression<'ast, T>, + ) -> Result, Self::Error> { + match e { + FieldElementExpression::Select(box array, box index) => self.check_select(array, index), + e => fold_field_expression(self, e), + } + } + + fn fold_boolean_expression( + &mut self, + e: BooleanExpression<'ast, T>, + ) -> Result, Self::Error> { + match e { + BooleanExpression::Select(box array, box index) => self.check_select(array, index), + e => fold_boolean_expression(self, e), + } + } + + fn fold_uint_expression_inner( + &mut self, + bitwidth: UBitwidth, + e: UExpressionInner<'ast, T>, + ) -> Result, Self::Error> { + match e { + UExpressionInner::Select(box array, box index) => self + .check_select::<_, UExpression<_>>(array, index) + .map(|a| a.into_inner()), + e => fold_uint_expression_inner(self, bitwidth, e), + } + } +} diff --git a/zokrates_core/src/static_analysis/flatten_complex_types.rs b/zokrates_core/src/static_analysis/flatten_complex_types.rs index 708bd68d7..ca97b9599 100644 --- a/zokrates_core/src/static_analysis/flatten_complex_types.rs +++ b/zokrates_core/src/static_analysis/flatten_complex_types.rs @@ -1,31 +1,34 @@ use crate::typed_absy; -use crate::typed_absy::types::{StructType, UBitwidth}; +use crate::typed_absy::types::UBitwidth; use crate::zir; use std::marker::PhantomData; use zokrates_field::Field; +use std::convert::{TryFrom, TryInto}; + pub struct Flattener { phantom: PhantomData, } -fn flatten_identifier_rec<'a>( - id: zir::SourceIdentifier<'a>, - ty: &typed_absy::Type, -) -> Vec> { +fn flatten_identifier_rec<'ast>( + id: zir::SourceIdentifier<'ast>, + ty: &typed_absy::types::ConcreteType, +) -> Vec> { match ty { - typed_absy::Type::FieldElement => vec![zir::Variable { + typed_absy::ConcreteType::Int => unreachable!(), + typed_absy::ConcreteType::FieldElement => vec![zir::Variable { id: zir::Identifier::Source(id), _type: zir::Type::FieldElement, }], - typed_absy::Type::Boolean => vec![zir::Variable { + typed_absy::types::ConcreteType::Boolean => vec![zir::Variable { id: zir::Identifier::Source(id), _type: zir::Type::Boolean, }], - typed_absy::Type::Uint(bitwidth) => vec![zir::Variable { + typed_absy::types::ConcreteType::Uint(bitwidth) => vec![zir::Variable { id: zir::Identifier::Source(id), _type: zir::Type::uint(bitwidth.to_usize()), }], - typed_absy::Type::Array(array_type) => (0..array_type.size) + typed_absy::types::ConcreteType::Array(array_type) => (0..array_type.size) .flat_map(|i| { flatten_identifier_rec( zir::SourceIdentifier::Select(box id.clone(), i), @@ -33,7 +36,7 @@ fn flatten_identifier_rec<'a>( ) }) .collect(), - typed_absy::Type::Struct(members) => members + typed_absy::types::ConcreteType::Struct(members) => members .iter() .flat_map(|struct_member| { flatten_identifier_rec( @@ -57,17 +60,6 @@ impl<'ast, T: Field> Flattener { fold_program(self, p) } - fn fold_module(&mut self, p: typed_absy::TypedModule<'ast, T>) -> zir::ZirModule<'ast, T> { - fold_module(self, p) - } - - fn fold_function_symbol( - &mut self, - s: typed_absy::TypedFunctionSymbol<'ast, T>, - ) -> zir::ZirFunctionSymbol<'ast, T> { - fold_function_symbol(self, s) - } - fn fold_function( &mut self, f: typed_absy::TypedFunction<'ast, T>, @@ -75,9 +67,12 @@ impl<'ast, T: Field> Flattener { fold_function(self, f) } - fn fold_parameter(&mut self, p: typed_absy::Parameter<'ast>) -> Vec> { + fn fold_declaration_parameter( + &mut self, + p: typed_absy::DeclarationParameter<'ast>, + ) -> Vec> { let private = p.private; - self.fold_variable(p.id) + self.fold_variable(p.id.try_into().unwrap()) .into_iter() .map(|v| zir::Parameter { id: v, private }) .collect() @@ -87,10 +82,12 @@ impl<'ast, T: Field> Flattener { zir::SourceIdentifier::Basic(n) } - fn fold_variable(&mut self, v: typed_absy::Variable<'ast>) -> Vec> { + fn fold_variable(&mut self, v: typed_absy::Variable<'ast, T>) -> Vec> { let id = self.fold_name(v.id.clone()); let ty = v.get_type(); + let ty = typed_absy::types::ConcreteType::try_from(ty).unwrap(); + flatten_identifier_rec(id, &ty) } @@ -102,36 +99,34 @@ impl<'ast, T: Field> Flattener { typed_absy::TypedAssignee::Identifier(v) => self.fold_variable(v), typed_absy::TypedAssignee::Select(box a, box i) => { use typed_absy::Typed; - let count = match a.get_type() { - typed_absy::Type::Array(array_ty) => array_ty.ty.get_primitive_count(), + let count = match typed_absy::ConcreteType::try_from(a.get_type()).unwrap() { + typed_absy::ConcreteType::Array(array_ty) => array_ty.ty.get_primitive_count(), _ => unreachable!(), }; let a = self.fold_assignee(a); - match i { - typed_absy::FieldElementExpression::Number(n) => { - let index = n.to_dec_string().parse::().unwrap(); - a[index * count..(index + 1) * count].to_vec() + match i.as_inner() { + typed_absy::UExpressionInner::Value(index) => { + a[*index as usize * count..(*index as usize + 1) * count].to_vec() } - i => unreachable!("index {} not allowed, should be a constant", i), + i => unreachable!("index {:?} not allowed, should be a constant", i), } } typed_absy::TypedAssignee::Member(box a, m) => { use typed_absy::Typed; - let (offset, size) = match a.get_type() { - typed_absy::Type::Struct(struct_type) => { - struct_type - .members - .iter() - .fold((0, None), |(offset, size), member| match size { - Some(_) => (offset, size), - None => match m == member.id { - true => (offset, Some(member.ty.get_primitive_count())), - false => (offset + member.ty.get_primitive_count(), None), - }, - }) - } + let (offset, size) = match typed_absy::ConcreteType::try_from(a.get_type()).unwrap() + { + typed_absy::ConcreteType::Struct(struct_type) => struct_type + .members + .iter() + .fold((0, None), |(offset, size), member| match size { + Some(_) => (offset, size), + None => match m == member.id { + true => (offset, Some(member.ty.get_primitive_count())), + false => (offset + member.ty.get_primitive_count(), None), + }, + }), _ => unreachable!(), }; @@ -151,6 +146,16 @@ impl<'ast, T: Field> Flattener { fold_statement(self, s) } + fn fold_expression_or_spread( + &mut self, + e: typed_absy::TypedExpressionOrSpread<'ast, T>, + ) -> Vec> { + match e { + typed_absy::TypedExpressionOrSpread::Expression(e) => self.fold_expression(e), + typed_absy::TypedExpressionOrSpread::Spread(s) => self.fold_array_expression(s.array), + } + } + fn fold_expression( &mut self, e: typed_absy::TypedExpression<'ast, T>, @@ -161,8 +166,9 @@ impl<'ast, T: Field> Flattener { } typed_absy::TypedExpression::Boolean(e) => vec![self.fold_boolean_expression(e).into()], typed_absy::TypedExpression::Uint(e) => vec![self.fold_uint_expression(e).into()], - typed_absy::TypedExpression::Array(e) => self.fold_array_expression(e).into(), - typed_absy::TypedExpression::Struct(e) => self.fold_struct_expression(e).into(), + typed_absy::TypedExpression::Array(e) => self.fold_array_expression(e), + typed_absy::TypedExpression::Struct(e) => self.fold_struct_expression(e), + typed_absy::TypedExpression::Int(_) => unreachable!(), } } @@ -185,26 +191,20 @@ impl<'ast, T: Field> Flattener { es: typed_absy::TypedExpressionList<'ast, T>, ) -> zir::ZirExpressionList<'ast, T> { match es { - typed_absy::TypedExpressionList::FunctionCall(id, arguments, _) => { - zir::ZirExpressionList::FunctionCall( - self.fold_function_key(id), + typed_absy::TypedExpressionList::EmbedCall(embed, generics, arguments, _) => { + zir::ZirExpressionList::EmbedCall( + embed, + generics, arguments .into_iter() .flat_map(|a| self.fold_expression(a)) .collect(), - vec![], ) } + _ => unreachable!("should have been inlined"), } } - fn fold_function_key( - &mut self, - k: typed_absy::types::FunctionKey<'ast>, - ) -> zir::types::FunctionKey<'ast> { - k.into() - } - fn fold_field_expression( &mut self, e: typed_absy::FieldElementExpression<'ast, T>, @@ -234,7 +234,7 @@ impl<'ast, T: Field> Flattener { fn fold_array_expression_inner( &mut self, - ty: &typed_absy::Type, + ty: &typed_absy::types::ConcreteType, size: usize, e: typed_absy::ArrayExpressionInner<'ast, T>, ) -> Vec> { @@ -242,26 +242,13 @@ impl<'ast, T: Field> Flattener { } fn fold_struct_expression_inner( &mut self, - ty: &StructType, + ty: &typed_absy::types::ConcreteStructType, e: typed_absy::StructExpressionInner<'ast, T>, ) -> Vec> { fold_struct_expression_inner(self, ty, e) } } -pub fn fold_module<'ast, T: Field>( - f: &mut Flattener, - p: typed_absy::TypedModule<'ast, T>, -) -> zir::ZirModule<'ast, T> { - zir::ZirModule { - functions: p - .functions - .into_iter() - .map(|(key, fun)| (f.fold_function_key(key), f.fold_function_symbol(fun))) - .collect(), - } -} - pub fn fold_statement<'ast, T: Field>( f: &mut Flattener, s: typed_absy::TypedStatement<'ast, T>, @@ -284,9 +271,7 @@ pub fn fold_statement<'ast, T: Field>( } typed_absy::TypedStatement::Declaration(v) => { let v = f.fold_variable(v); - v.into_iter() - .map(|v| zir::ZirStatement::Declaration(v)) - .collect() + v.into_iter().map(zir::ZirStatement::Declaration).collect() } typed_absy::TypedStatement::Assertion(e) => { let e = f.fold_boolean_expression(e); @@ -302,19 +287,23 @@ pub fn fold_statement<'ast, T: Field>( f.fold_expression_list(elist), )] } + typed_absy::TypedStatement::PushCallLog(..) => vec![], + typed_absy::TypedStatement::PopCallLog => vec![], } } pub fn fold_array_expression_inner<'ast, T: Field>( f: &mut Flattener, - t: &typed_absy::Type, + ty: &typed_absy::types::ConcreteType, size: usize, - e: typed_absy::ArrayExpressionInner<'ast, T>, + array: typed_absy::ArrayExpressionInner<'ast, T>, ) -> Vec> { - match e { + match array { typed_absy::ArrayExpressionInner::Identifier(id) => { - let variables = - flatten_identifier_rec(f.fold_name(id), &typed_absy::Type::array(t.clone(), size)); + let variables = flatten_identifier_rec( + f.fold_name(id), + &typed_absy::types::ConcreteType::array((ty.clone(), size)), + ); variables .into_iter() .map(|v| match v._type { @@ -326,10 +315,16 @@ pub fn fold_array_expression_inner<'ast, T: Field>( }) .collect() } - typed_absy::ArrayExpressionInner::Value(exprs) => exprs - .into_iter() - .flat_map(|e| f.fold_expression(e)) - .collect(), + typed_absy::ArrayExpressionInner::Value(exprs) => { + let exprs: Vec<_> = exprs + .into_iter() + .flat_map(|e| f.fold_expression_or_spread(e)) + .collect(); + + assert_eq!(exprs.len(), size * ty.get_primitive_count()); + + exprs + } typed_absy::ArrayExpressionInner::FunctionCall(..) => unreachable!(), typed_absy::ArrayExpressionInner::IfElse( box condition, @@ -369,40 +364,74 @@ pub fn fold_array_expression_inner<'ast, T: Field>( let offset: usize = members .iter() .take_while(|member| member.id != id) - .map(|member| member.ty.get_primitive_count()) + .map(|member| { + typed_absy::types::ConcreteType::try_from(*member.ty.clone()) + .unwrap() + .get_primitive_count() + }) .sum(); // we also need the size of this member - let size = t.get_primitive_count() * size; + let size = ty.get_primitive_count() * size; s[offset..offset + size].to_vec() } typed_absy::ArrayExpressionInner::Select(box array, box index) => { let array = f.fold_array_expression(array); - let index = f.fold_field_expression(index); + let index = f.fold_uint_expression(index); - match index { - zir::FieldElementExpression::Number(i) => { - let size = t.get_primitive_count() * size; - let start = i.to_dec_string().parse::().unwrap() * size; + match index.into_inner() { + zir::UExpressionInner::Value(i) => { + let size = ty.clone().get_primitive_count() * size; + let start = i as usize * size; let end = start + size; array[start..end].to_vec() } _ => unreachable!(), } } + typed_absy::ArrayExpressionInner::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); + + match (from.into_inner(), to.into_inner()) { + (zir::UExpressionInner::Value(from), zir::UExpressionInner::Value(to)) => { + assert_eq!(size, to.saturating_sub(from) as usize); + + let element_size = ty.get_primitive_count(); + let start = from as usize * element_size; + let end = to as usize * element_size; + array[start..end].to_vec() + } + _ => unreachable!(), + } + } + typed_absy::ArrayExpressionInner::Repeat(box e, box count) => { + let e = f.fold_expression(e); + let count = f.fold_uint_expression(count); + + match count.into_inner() { + zir::UExpressionInner::Value(count) => { + vec![e; count as usize].into_iter().flatten().collect() + } + _ => unreachable!(), + } + } } } pub fn fold_struct_expression_inner<'ast, T: Field>( f: &mut Flattener, - t: &StructType, - e: typed_absy::StructExpressionInner<'ast, T>, + ty: &typed_absy::types::ConcreteStructType, + struc: typed_absy::StructExpressionInner<'ast, T>, ) -> Vec> { - match e { + match struc { typed_absy::StructExpressionInner::Identifier(id) => { - let variables = - flatten_identifier_rec(f.fold_name(id), &typed_absy::Type::struc(t.clone())); + let variables = flatten_identifier_rec( + f.fold_name(id), + &typed_absy::types::ConcreteType::struc(ty.clone()), + ); variables .into_iter() .map(|v| match v._type { @@ -457,13 +486,18 @@ pub fn fold_struct_expression_inner<'ast, T: Field>( let offset: usize = members .iter() .take_while(|member| member.id != id) - .map(|member| member.ty.get_primitive_count()) + .map(|member| { + typed_absy::types::ConcreteType::try_from(*member.ty.clone()) + .unwrap() + .get_primitive_count() + }) .sum(); // we also need the size of this member - let size = t + let size = ty .iter() .find(|member| member.id == id) + .cloned() .unwrap() .ty .get_primitive_count(); @@ -472,15 +506,12 @@ pub fn fold_struct_expression_inner<'ast, T: Field>( } typed_absy::StructExpressionInner::Select(box array, box index) => { let array = f.fold_array_expression(array); - let index = f.fold_field_expression(index); + let index = f.fold_uint_expression(index); - match index { - zir::FieldElementExpression::Number(i) => { - let size = t - .iter() - .map(|m| m.ty.get_primitive_count()) - .fold(0, |acc, current| acc + current); - let start = i.to_dec_string().parse::().unwrap() * size; + match index.into_inner() { + zir::UExpressionInner::Value(i) => { + let size: usize = ty.iter().map(|m| m.ty.get_primitive_count()).sum(); + let start = i as usize * size; let end = start + size; array[start..end].to_vec() } @@ -498,9 +529,12 @@ pub fn fold_field_expression<'ast, T: Field>( typed_absy::FieldElementExpression::Number(n) => zir::FieldElementExpression::Number(n), typed_absy::FieldElementExpression::Identifier(id) => { zir::FieldElementExpression::Identifier( - flatten_identifier_rec(f.fold_name(id), &typed_absy::Type::FieldElement)[0] - .id - .clone(), + flatten_identifier_rec( + f.fold_name(id), + &typed_absy::types::ConcreteType::FieldElement, + )[0] + .id + .clone(), ) } typed_absy::FieldElementExpression::Add(box e1, box e2) => { @@ -525,9 +559,18 @@ pub fn fold_field_expression<'ast, T: Field>( } typed_absy::FieldElementExpression::Pow(box e1, box e2) => { let e1 = f.fold_field_expression(e1); - let e2 = f.fold_field_expression(e2); + let e2 = f.fold_uint_expression(e2); zir::FieldElementExpression::Pow(box e1, box e2) } + typed_absy::FieldElementExpression::Neg(box e) => { + let e = f.fold_field_expression(e); + + zir::FieldElementExpression::Sub( + box zir::FieldElementExpression::Number(T::zero()), + box e, + ) + } + typed_absy::FieldElementExpression::Pos(box e) => f.fold_field_expression(e), typed_absy::FieldElementExpression::IfElse(box cond, box cons, box alt) => { let cond = f.fold_boolean_expression(cond); let cons = f.fold_field_expression(cons); @@ -543,26 +586,22 @@ pub fn fold_field_expression<'ast, T: Field>( let offset: usize = members .iter() .take_while(|member| member.id != id) - .map(|member| member.ty.get_primitive_count()) + .map(|member| { + typed_absy::types::ConcreteType::try_from(*member.ty.clone()) + .unwrap() + .get_primitive_count() + }) .sum(); - use std::convert::TryInto; - s[offset].clone().try_into().unwrap() } typed_absy::FieldElementExpression::Select(box array, box index) => { let array = f.fold_array_expression(array); - let index = f.fold_field_expression(index); - - use std::convert::TryInto; + let index = f.fold_uint_expression(index); - match index { - zir::FieldElementExpression::Number(i) => array - [i.to_dec_string().parse::().unwrap()] - .clone() - .try_into() - .unwrap(), + match index.into_inner() { + zir::UExpressionInner::Value(i) => array[i as usize].clone().try_into().unwrap(), _ => unreachable!(""), } } @@ -576,7 +615,7 @@ pub fn fold_boolean_expression<'ast, T: Field>( match e { typed_absy::BooleanExpression::Value(v) => zir::BooleanExpression::Value(v), typed_absy::BooleanExpression::Identifier(id) => zir::BooleanExpression::Identifier( - flatten_identifier_rec(f.fold_name(id), &typed_absy::Type::Boolean)[0] + flatten_identifier_rec(f.fold_name(id), &typed_absy::types::ConcreteType::Boolean)[0] .id .clone(), ), @@ -652,25 +691,45 @@ pub fn fold_boolean_expression<'ast, T: Field>( zir::BooleanExpression::UintEq(box e1, box e2) } - typed_absy::BooleanExpression::Lt(box e1, box e2) => { + typed_absy::BooleanExpression::FieldLt(box e1, box e2) => { let e1 = f.fold_field_expression(e1); let e2 = f.fold_field_expression(e2); - zir::BooleanExpression::Lt(box e1, box e2) + zir::BooleanExpression::FieldLt(box e1, box e2) } - typed_absy::BooleanExpression::Le(box e1, box e2) => { + typed_absy::BooleanExpression::FieldLe(box e1, box e2) => { let e1 = f.fold_field_expression(e1); let e2 = f.fold_field_expression(e2); - zir::BooleanExpression::Le(box e1, box e2) + zir::BooleanExpression::FieldLe(box e1, box e2) } - typed_absy::BooleanExpression::Gt(box e1, box e2) => { + typed_absy::BooleanExpression::FieldGt(box e1, box e2) => { let e1 = f.fold_field_expression(e1); let e2 = f.fold_field_expression(e2); - zir::BooleanExpression::Gt(box e1, box e2) + zir::BooleanExpression::FieldGt(box e1, box e2) } - typed_absy::BooleanExpression::Ge(box e1, box e2) => { + typed_absy::BooleanExpression::FieldGe(box e1, box e2) => { let e1 = f.fold_field_expression(e1); let e2 = f.fold_field_expression(e2); - zir::BooleanExpression::Ge(box e1, box e2) + zir::BooleanExpression::FieldGe(box e1, box e2) + } + typed_absy::BooleanExpression::UintLt(box e1, box e2) => { + let e1 = f.fold_uint_expression(e1); + let e2 = f.fold_uint_expression(e2); + zir::BooleanExpression::UintLt(box e1, box e2) + } + typed_absy::BooleanExpression::UintLe(box e1, box e2) => { + let e1 = f.fold_uint_expression(e1); + let e2 = f.fold_uint_expression(e2); + zir::BooleanExpression::UintLe(box e1, box e2) + } + typed_absy::BooleanExpression::UintGt(box e1, box e2) => { + let e1 = f.fold_uint_expression(e1); + let e2 = f.fold_uint_expression(e2); + zir::BooleanExpression::UintGt(box e1, box e2) + } + typed_absy::BooleanExpression::UintGe(box e1, box e2) => { + let e1 = f.fold_uint_expression(e1); + let e2 = f.fold_uint_expression(e2); + zir::BooleanExpression::UintGe(box e1, box e2) } typed_absy::BooleanExpression::Or(box e1, box e2) => { let e1 = f.fold_boolean_expression(e1); @@ -701,25 +760,21 @@ pub fn fold_boolean_expression<'ast, T: Field>( let offset: usize = members .iter() .take_while(|member| member.id != id) - .map(|member| member.ty.get_primitive_count()) + .map(|member| { + typed_absy::types::ConcreteType::try_from(*member.ty.clone()) + .unwrap() + .get_primitive_count() + }) .sum(); - use std::convert::TryInto; - s[offset].clone().try_into().unwrap() } typed_absy::BooleanExpression::Select(box array, box index) => { let array = f.fold_array_expression(array); - let index = f.fold_field_expression(index); + let index = f.fold_uint_expression(index); - use std::convert::TryInto; - - match index { - zir::FieldElementExpression::Number(i) => array - [i.to_dec_string().parse::().unwrap()] - .clone() - .try_into() - .unwrap(), + match index.into_inner() { + zir::UExpressionInner::Value(i) => array[i as usize].clone().try_into().unwrap(), _ => unreachable!(), } } @@ -742,9 +797,12 @@ pub fn fold_uint_expression_inner<'ast, T: Field>( match e { typed_absy::UExpressionInner::Value(v) => zir::UExpressionInner::Value(v), typed_absy::UExpressionInner::Identifier(id) => zir::UExpressionInner::Identifier( - flatten_identifier_rec(f.fold_name(id), &typed_absy::Type::Uint(bitwidth))[0] - .id - .clone(), + flatten_identifier_rec( + f.fold_name(id), + &typed_absy::types::ConcreteType::Uint(bitwidth), + )[0] + .id + .clone(), ), typed_absy::UExpressionInner::Add(box left, box right) => { let left = f.fold_uint_expression(left); @@ -758,6 +816,7 @@ pub fn fold_uint_expression_inner<'ast, T: Field>( zir::UExpressionInner::Sub(box left, box right) } + typed_absy::UExpressionInner::FloorSub(..) => unreachable!(), typed_absy::UExpressionInner::Mult(box left, box right) => { let left = f.fold_uint_expression(left); let right = f.fold_uint_expression(right); @@ -796,13 +855,13 @@ pub fn fold_uint_expression_inner<'ast, T: Field>( } typed_absy::UExpressionInner::LeftShift(box e, box by) => { let e = f.fold_uint_expression(e); - let by = f.fold_field_expression(by); + let by = f.fold_uint_expression(by); zir::UExpressionInner::LeftShift(box e, box by) } typed_absy::UExpressionInner::RightShift(box e, box by) => { let e = f.fold_uint_expression(e); - let by = f.fold_field_expression(by); + let by = f.fold_uint_expression(by); zir::UExpressionInner::RightShift(box e, box by) } @@ -811,21 +870,28 @@ pub fn fold_uint_expression_inner<'ast, T: Field>( zir::UExpressionInner::Not(box e) } + typed_absy::UExpressionInner::Neg(box e) => { + let bitwidth = e.bitwidth(); + + f.fold_uint_expression(typed_absy::UExpressionInner::Value(0).annotate(bitwidth) - e) + .into_inner() + } + + typed_absy::UExpressionInner::Pos(box e) => { + let e = f.fold_uint_expression(e); + + e.into_inner() + } typed_absy::UExpressionInner::FunctionCall(..) => { unreachable!("function calls should have been removed") } typed_absy::UExpressionInner::Select(box array, box index) => { let array = f.fold_array_expression(array); - let index = f.fold_field_expression(index); - - use std::convert::TryInto; + let index = f.fold_uint_expression(index); - match index { - zir::FieldElementExpression::Number(i) => { - let e: zir::UExpression<_> = array[i.to_dec_string().parse::().unwrap()] - .clone() - .try_into() - .unwrap(); + match index.into_inner() { + zir::UExpressionInner::Value(i) => { + let e: zir::UExpression<_> = array[i as usize].clone().try_into().unwrap(); e.into_inner() } _ => unreachable!(), @@ -839,11 +905,13 @@ pub fn fold_uint_expression_inner<'ast, T: Field>( let offset: usize = members .iter() .take_while(|member| member.id != id) - .map(|member| member.ty.get_primitive_count()) + .map(|member| { + typed_absy::types::ConcreteType::try_from(*member.ty.clone()) + .unwrap() + .get_primitive_count() + }) .sum(); - use std::convert::TryInto; - let res: zir::UExpression<'ast, T> = s[offset].clone().try_into().unwrap(); res.into_inner() @@ -865,14 +933,18 @@ pub fn fold_function<'ast, T: Field>( arguments: fun .arguments .into_iter() - .flat_map(|a| f.fold_parameter(a)) + .flat_map(|a| f.fold_declaration_parameter(a)) .collect(), statements: fun .statements .into_iter() .flat_map(|s| f.fold_statement(s)) .collect(), - signature: fun.signature.into(), + signature: typed_absy::types::ConcreteSignature::try_from( + typed_absy::types::Signature::::try_from(fun.signature).unwrap(), + ) + .unwrap() + .into(), } } @@ -880,41 +952,46 @@ pub fn fold_array_expression<'ast, T: Field>( f: &mut Flattener, e: typed_absy::ArrayExpression<'ast, T>, ) -> Vec> { - f.fold_array_expression_inner(&e.inner_type().clone(), e.size(), e.into_inner()) + let size = match e.size().into_inner() { + typed_absy::UExpressionInner::Value(v) => v, + _ => unreachable!(), + } as usize; + f.fold_array_expression_inner( + &typed_absy::types::ConcreteType::try_from(e.inner_type().clone()).unwrap(), + size, + e.into_inner(), + ) } pub fn fold_struct_expression<'ast, T: Field>( f: &mut Flattener, e: typed_absy::StructExpression<'ast, T>, ) -> Vec> { - f.fold_struct_expression_inner(&e.ty().clone(), e.into_inner()) -} - -pub fn fold_function_symbol<'ast, T: Field>( - f: &mut Flattener, - s: typed_absy::TypedFunctionSymbol<'ast, T>, -) -> zir::ZirFunctionSymbol<'ast, T> { - match s { - typed_absy::TypedFunctionSymbol::Here(fun) => { - zir::ZirFunctionSymbol::Here(f.fold_function(fun)) - } - typed_absy::TypedFunctionSymbol::There(key, module) => { - zir::ZirFunctionSymbol::There(f.fold_function_key(key), module) - } // by default, do not fold modules recursively - typed_absy::TypedFunctionSymbol::Flat(flat) => zir::ZirFunctionSymbol::Flat(flat), - } + f.fold_struct_expression_inner( + &typed_absy::types::ConcreteStructType::try_from(e.ty().clone()).unwrap(), + e.into_inner(), + ) } pub fn fold_program<'ast, T: Field>( f: &mut Flattener, - p: typed_absy::TypedProgram<'ast, T>, + mut p: typed_absy::TypedProgram<'ast, T>, ) -> zir::ZirProgram<'ast, T> { + let main_module = p.modules.remove(&p.main).unwrap(); + + let main_function = main_module + .functions + .into_iter() + .find(|(key, _)| key.id == "main") + .unwrap() + .1; + + let main_function = match main_function { + typed_absy::TypedFunctionSymbol::Here(f) => f, + _ => unreachable!(), + }; + zir::ZirProgram { - modules: p - .modules - .into_iter() - .map(|(module_id, module)| (module_id, f.fold_module(module))) - .collect(), - main: p.main, + main: f.fold_function(main_function), } } diff --git a/zokrates_core/src/static_analysis/inline.rs b/zokrates_core/src/static_analysis/inline.rs deleted file mode 100644 index 4fad20a6e..000000000 --- a/zokrates_core/src/static_analysis/inline.rs +++ /dev/null @@ -1,1387 +0,0 @@ -//! Module containing inlining for the typed AST -//! -//! @file inline.rs -//! @author Thibaut Schaeffer -//! @date 2019 - -//! Start from the `main` function in the `main` module and inline all calls except those to flat embeds -//! The resulting program has a single module, where we define a function for each flat embed and replace the function calls with the embeds found -//! during inlining by calls to these functions, to be resolved during flattening. - -//! The resulting program has a single module of the form - -//! def main(): -//! def _SHA_256_ROUND(): -//! def _UNPACK(): - -//! where any call in `main` must be to `_SHA_256_ROUND` or `_UNPACK` - -use crate::typed_absy::types::{FunctionKey, FunctionKeyHash, Type, UBitwidth}; -use crate::typed_absy::{folder::*, *}; -use std::collections::HashMap; -use zokrates_field::Field; - -#[derive(Debug, PartialEq, Eq, Hash, Clone)] -struct Location<'ast> { - module: TypedModuleId, - key: FunctionKey<'ast>, -} - -impl<'ast> Location<'ast> { - fn module(&self) -> &TypedModuleId { - &self.module - } -} - -/// An inliner -#[derive(Debug)] -pub struct Inliner<'ast, T: Field> { - /// the modules in which to look for functions when inlining - modules: TypedModules<'ast, T>, - /// the current module we're visiting - location: Location<'ast>, - /// a buffer of statements to be added to the inlined statements - statement_buffer: Vec>, - /// the current call stack - stack: Vec<(TypedModuleId, FunctionKeyHash, usize)>, - /// the call count for each function - call_count: HashMap<(TypedModuleId, FunctionKey<'ast>), usize>, -} - -impl<'ast, T: Field> Inliner<'ast, T> { - fn with_modules_and_module_id_and_key>( - modules: TypedModules<'ast, T>, - module_id: S, - key: FunctionKey<'ast>, - ) -> Self { - Inliner { - modules, - location: Location { - module: module_id.into(), - key, - }, - statement_buffer: vec![], - stack: vec![], - call_count: HashMap::new(), - } - } - - pub fn inline(p: TypedProgram) -> TypedProgram { - let main_module_id = p.main; - - // get the main module - let main_module = p.modules.get(&main_module_id).unwrap().clone(); - - // get the main function in the main module - let (main_key, main) = main_module - .functions - .into_iter() - .find(|(k, _)| k.id == "main") - .unwrap(); - - // initialize an inliner over all modules, starting from the main module - let mut inliner = Inliner::with_modules_and_module_id_and_key( - p.modules, - main_module_id, - main_key.clone(), - ); - - // inline all calls in the main function, recursively - let main = inliner.fold_function_symbol(main); - - cfg_if::cfg_if! { - if #[cfg(feature = "bellman")] { - // define a function in the main module for the `sha256` embed - let sha256_round = crate::embed::FlatEmbed::Sha256Round; - let sha256_round_key = sha256_round.key::(); - } - } - - // define a function in the main module for the `unpack` embed - let unpack = crate::embed::FlatEmbed::Unpack(T::get_required_bits()); - let unpack_key = unpack.key::(); - - // define a function in the main module for the `u32_to_bits` embed - let u32_to_bits = crate::embed::FlatEmbed::U32ToBits; - let u32_to_bits_key = u32_to_bits.key::(); - - // define a function in the main module for the `u16_to_bits` embed - let u16_to_bits = crate::embed::FlatEmbed::U16ToBits; - let u16_to_bits_key = u16_to_bits.key::(); - - // define a function in the main module for the `u8_to_bits` embed - let u8_to_bits = crate::embed::FlatEmbed::U8ToBits; - let u8_to_bits_key = u8_to_bits.key::(); - - // define a function in the main module for the `u32_from_bits` embed - let u32_from_bits = crate::embed::FlatEmbed::U32FromBits; - let u32_from_bits_key = u32_from_bits.key::(); - - // define a function in the main module for the `u16_from_bits` embed - let u16_from_bits = crate::embed::FlatEmbed::U16FromBits; - let u16_from_bits_key = u16_from_bits.key::(); - - // define a function in the main module for the `u8_from_bits` embed - let u8_from_bits = crate::embed::FlatEmbed::U8FromBits; - let u8_from_bits_key = u8_from_bits.key::(); - - // return a program with a single module containing `main`, `_UNPACK`, and `_SHA256_ROUND - TypedProgram { - main: "main".into(), - modules: vec![( - "main".into(), - TypedModule { - functions: vec![ - #[cfg(feature = "bellman")] - (sha256_round_key, TypedFunctionSymbol::Flat(sha256_round)), - (unpack_key, TypedFunctionSymbol::Flat(unpack)), - (u32_from_bits_key, TypedFunctionSymbol::Flat(u32_from_bits)), - (u16_from_bits_key, TypedFunctionSymbol::Flat(u16_from_bits)), - (u8_from_bits_key, TypedFunctionSymbol::Flat(u8_from_bits)), - (u32_to_bits_key, TypedFunctionSymbol::Flat(u32_to_bits)), - (u16_to_bits_key, TypedFunctionSymbol::Flat(u16_to_bits)), - (u8_to_bits_key, TypedFunctionSymbol::Flat(u8_to_bits)), - (main_key, main), - ] - .into_iter() - .collect(), - }, - )] - .into_iter() - .collect(), - } - } - - /// try to inline a call to function with key `key` in the stack of `self` - /// if inlining succeeds, return the expressions returned by the function call - /// if inlining fails (as in the case of flat function symbols), return the arguments to the function call for further processing - fn try_inline_call( - &mut self, - key: &FunctionKey<'ast>, - expressions: Vec>, - ) -> Result>, (FunctionKey<'ast>, Vec>)> - { - // here we clone a function symbol, which is cheap except when it contains the function body, in which case we'd clone anyways - let res = match self.module().functions.get(&key).unwrap().clone() { - // if the function called is in the same module, we can go ahead and inline in this module - TypedFunctionSymbol::Here(function) => { - let (current_module, current_key) = - self.change_context(self.module_id().clone(), key.clone()); - - let module_id = self.module_id().clone(); - - // increase the number of calls for this function by one - let count = self - .call_count - .entry((self.module_id().clone(), key.clone())) - .and_modify(|i| *i += 1) - .or_insert(1); - // push this call to the stack - self.stack.push((module_id, key.hash(), *count)); - // add definitions for the inputs - let inputs_bindings: Vec<_> = function - .arguments - .iter() - .zip(expressions.clone()) - .map(|(a, e)| { - TypedStatement::Definition( - self.fold_assignee(TypedAssignee::Identifier(a.id.clone())), - e, - ) - }) - .collect(); - - self.statement_buffer.extend(inputs_bindings); - - // filter out the return statement and keep it aside - let (statements, mut ret): (Vec<_>, Vec<_>) = function - .statements - .into_iter() - .flat_map(|s| self.fold_statement(s)) - .partition(|s| match s { - TypedStatement::Return(..) => false, - _ => true, - }); - - // add all statements to the buffer - self.statement_buffer.extend(statements); - - // pop this call from the stack - self.stack.pop(); - - self.change_context(current_module, current_key); - - match ret.pop().unwrap() { - TypedStatement::Return(exprs) => Ok(exprs), - _ => unreachable!(""), - } - } - // if the function called is in some other module, we switch focus to that module and call the function locally there - TypedFunctionSymbol::There(function_key, module_id) => { - // switch focus to `module_id` - let (current_module, current_key) = - self.change_context(module_id, function_key.clone()); - // inline the call there - let res = self.try_inline_call(&function_key, expressions.clone())?; - // switch back focus - self.change_context(current_module, current_key); - Ok(res) - } - // if the function is a flat symbol, replace the call with a call to the local function we provide so it can be inlined in flattening - TypedFunctionSymbol::Flat(embed) => Err((embed.key::(), expressions.clone())), - }; - - res - } - - // Focus the inliner on another module with id `module_id` and return the current `module_id` - fn change_context( - &mut self, - module_id: TypedModuleId, - function_key: FunctionKey<'ast>, - ) -> (TypedModuleId, FunctionKey<'ast>) { - let current_module = std::mem::replace(&mut self.location.module, module_id); - let current_key = std::mem::replace(&mut self.location.key, function_key); - (current_module, current_key) - } - - fn module(&self) -> &TypedModule<'ast, T> { - self.modules.get(self.module_id()).unwrap() - } - - fn module_id(&self) -> &TypedModuleId { - self.location.module() - } -} - -impl<'ast, T: Field> Folder<'ast, T> for Inliner<'ast, T> { - // add extra statements before the modified statement - fn fold_statement(&mut self, s: TypedStatement<'ast, T>) -> Vec> { - let folded = match s { - TypedStatement::MultipleDefinition(assignees, elist) => match elist { - TypedExpressionList::FunctionCall(key, exps, types) => { - let assignees: Vec<_> = assignees - .into_iter() - .map(|a| self.fold_assignee(a)) - .collect(); - let exps: Vec<_> = exps.into_iter().map(|e| self.fold_expression(e)).collect(); - - match self.try_inline_call(&key, exps) { - Ok(ret) => assignees - .into_iter() - .zip(ret.into_iter()) - .map(|(a, e)| TypedStatement::Definition(a, e)) - .collect(), - Err((key, expressions)) => vec![TypedStatement::MultipleDefinition( - assignees, - TypedExpressionList::FunctionCall(key, expressions, types), - )], - } - } - }, - s => fold_statement(self, s), - }; - self.statement_buffer.drain(..).chain(folded).collect() - } - - // prefix all names with the stack - fn fold_name(&mut self, n: Identifier<'ast>) -> Identifier<'ast> { - Identifier { - stack: self.stack.clone(), - ..n - } - } - - // inline calls which return a field element - fn fold_field_expression( - &mut self, - e: FieldElementExpression<'ast, T>, - ) -> FieldElementExpression<'ast, T> { - match e { - FieldElementExpression::FunctionCall(key, exps) => { - let exps: Vec<_> = exps.into_iter().map(|e| self.fold_expression(e)).collect(); - - match self.try_inline_call(&key, exps) { - Ok(mut ret) => match ret.pop().unwrap() { - TypedExpression::FieldElement(e) => e, - _ => unreachable!(), - }, - Err((embed_key, expressions)) => { - let tys = key.signature.outputs.clone(); - let id = Identifier { - id: CoreIdentifier::Call( - key.hash(), - *self - .call_count - .entry((self.module_id().clone(), embed_key.clone())) - .and_modify(|i| *i += 1) - .or_insert(1), - ), - version: 0, - stack: self.stack.clone(), - }; - self.statement_buffer - .push(TypedStatement::MultipleDefinition( - vec![Variable::with_id_and_type(id.clone(), tys[0].clone()).into()], - TypedExpressionList::FunctionCall( - key.clone(), - expressions.clone(), - tys, - ), - )); - - FieldElementExpression::Identifier(id) - } - } - } - e => fold_field_expression(self, e), - } - } - - // inline calls which return a boolean element - fn fold_boolean_expression( - &mut self, - e: BooleanExpression<'ast, T>, - ) -> BooleanExpression<'ast, T> { - match e { - BooleanExpression::FunctionCall(key, exps) => { - let exps: Vec<_> = exps.into_iter().map(|e| self.fold_expression(e)).collect(); - - match self.try_inline_call(&key, exps) { - Ok(mut ret) => match ret.pop().unwrap() { - TypedExpression::Boolean(e) => e, - _ => unreachable!(), - }, - Err((embed_key, expressions)) => { - let tys = key.signature.outputs.clone(); - let id = Identifier { - id: CoreIdentifier::Call( - key.hash(), - *self - .call_count - .entry((self.module_id().clone(), embed_key.clone())) - .and_modify(|i| *i += 1) - .or_insert(1), - ), - version: 0, - stack: self.stack.clone(), - }; - self.statement_buffer - .push(TypedStatement::MultipleDefinition( - vec![Variable::with_id_and_type(id.clone(), tys[0].clone()).into()], - TypedExpressionList::FunctionCall( - key.clone(), - expressions.clone(), - tys, - ), - )); - - BooleanExpression::Identifier(id) - } - } - } - e => fold_boolean_expression(self, e), - } - } - - // inline calls which return an array - fn fold_array_expression_inner( - &mut self, - ty: &Type, - size: usize, - e: ArrayExpressionInner<'ast, T>, - ) -> ArrayExpressionInner<'ast, T> { - match e { - ArrayExpressionInner::FunctionCall(key, exps) => { - let exps: Vec<_> = exps.into_iter().map(|e| self.fold_expression(e)).collect(); - - match self.try_inline_call(&key, exps) { - Ok(mut ret) => match ret.pop().unwrap() { - TypedExpression::Array(e) => e.into_inner(), - _ => unreachable!(), - }, - Err((embed_key, expressions)) => { - let tys = key.signature.outputs.clone(); - let id = Identifier { - id: CoreIdentifier::Call( - key.hash(), - *self - .call_count - .entry((self.module_id().clone(), embed_key.clone())) - .and_modify(|i| *i += 1) - .or_insert(1), - ), - version: 0, - stack: self.stack.clone(), - }; - self.statement_buffer - .push(TypedStatement::MultipleDefinition( - vec![Variable::with_id_and_type(id.clone(), tys[0].clone()).into()], - TypedExpressionList::FunctionCall( - embed_key.clone(), - expressions.clone(), - tys, - ), - )); - - ArrayExpressionInner::Identifier(id) - } - } - } - // default - e => fold_array_expression_inner(self, ty, size, e), - } - } - - fn fold_struct_expression_inner( - &mut self, - ty: &StructType, - e: StructExpressionInner<'ast, T>, - ) -> StructExpressionInner<'ast, T> { - match e { - StructExpressionInner::FunctionCall(key, exps) => { - let exps: Vec<_> = exps.into_iter().map(|e| self.fold_expression(e)).collect(); - - match self.try_inline_call(&key, exps) { - Ok(mut ret) => match ret.pop().unwrap() { - TypedExpression::Struct(e) => e.into_inner(), - _ => unreachable!(), - }, - Err((embed_key, expressions)) => { - let tys = key.signature.outputs.clone(); - let id = Identifier { - id: CoreIdentifier::Call( - key.hash(), - *self - .call_count - .entry((self.module_id().clone(), embed_key.clone())) - .and_modify(|i| *i += 1) - .or_insert(1), - ), - version: 0, - stack: self.stack.clone(), - }; - self.statement_buffer - .push(TypedStatement::MultipleDefinition( - vec![Variable::with_id_and_type(id.clone(), tys[0].clone()).into()], - TypedExpressionList::FunctionCall( - key.clone(), - expressions.clone(), - tys, - ), - )); - - StructExpressionInner::Identifier(id) - } - } - } - // default - e => fold_struct_expression_inner(self, ty, e), - } - } - - fn fold_uint_expression_inner( - &mut self, - size: UBitwidth, - e: UExpressionInner<'ast, T>, - ) -> UExpressionInner<'ast, T> { - match e { - UExpressionInner::FunctionCall(key, exps) => { - let exps: Vec<_> = exps.into_iter().map(|e| self.fold_expression(e)).collect(); - - match self.try_inline_call(&key, exps) { - Ok(mut ret) => match ret.pop().unwrap() { - TypedExpression::Uint(e) => e.into_inner(), - _ => unreachable!(), - }, - Err((embed_key, expressions)) => { - let tys = key.signature.outputs.clone(); - let id = Identifier { - id: CoreIdentifier::Call( - key.hash(), - *self - .call_count - .entry((self.module_id().clone(), embed_key.clone())) - .and_modify(|i| *i += 1) - .or_insert(1), - ), - version: 0, - stack: self.stack.clone(), - }; - self.statement_buffer - .push(TypedStatement::MultipleDefinition( - vec![Variable::with_id_and_type(id.clone(), tys[0].clone()).into()], - TypedExpressionList::FunctionCall( - embed_key.clone(), - expressions.clone(), - tys, - ), - )); - - UExpressionInner::Identifier(id) - } - } - } - // default - e => fold_uint_expression_inner(self, size, e), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::typed_absy::types::{FunctionKey, Signature, Type}; - use std::path::PathBuf; - use zokrates_field::Bn128Field; - - #[test] - fn call_other_module_without_variables() { - // // main - // from "foo" import foo - // def main() -> field: - // return foo() - // - // // foo - // def foo() -> field: - // return 42 - // - // - // // inlined - // def main() -> field: - // return 42 - - let main = TypedModule { - functions: vec![ - ( - FunctionKey::with_id("main") - .signature(Signature::new().outputs(vec![Type::FieldElement])), - TypedFunctionSymbol::Here(TypedFunction { - arguments: vec![], - statements: vec![TypedStatement::Return(vec![ - FieldElementExpression::FunctionCall( - FunctionKey::with_id("foo") - .signature(Signature::new().outputs(vec![Type::FieldElement])), - vec![], - ) - .into(), - ])], - signature: Signature::new().outputs(vec![Type::FieldElement]), - }), - ), - ( - FunctionKey::with_id("foo") - .signature(Signature::new().outputs(vec![Type::FieldElement])), - TypedFunctionSymbol::There( - FunctionKey::with_id("foo") - .signature(Signature::new().outputs(vec![Type::FieldElement])), - "foo".into(), - ), - ), - ] - .into_iter() - .collect(), - }; - - let foo = TypedModule { - functions: vec![( - FunctionKey::with_id("foo") - .signature(Signature::new().outputs(vec![Type::FieldElement])), - TypedFunctionSymbol::Here(TypedFunction { - arguments: vec![], - statements: vec![TypedStatement::Return(vec![ - FieldElementExpression::Number(Bn128Field::from(42)).into(), - ])], - signature: Signature::new().outputs(vec![Type::FieldElement]), - }), - )] - .into_iter() - .collect(), - }; - - let modules: HashMap<_, _> = vec![("main".into(), main), ("foo".into(), foo)] - .into_iter() - .collect(); - - let program = TypedProgram { - main: "main".into(), - modules, - }; - - let program = Inliner::inline(program); - - assert_eq!(program.modules.len(), 1); - assert_eq!( - program - .modules - .get(&PathBuf::from("main")) - .unwrap() - .functions - .get( - &FunctionKey::with_id("main") - .signature(Signature::new().outputs(vec![Type::FieldElement])) - ) - .unwrap(), - &TypedFunctionSymbol::Here(TypedFunction { - arguments: vec![], - statements: vec![TypedStatement::Return(vec![ - FieldElementExpression::Number(Bn128Field::from(42)).into(), - ])], - signature: Signature::new().outputs(vec![Type::FieldElement]), - }) - ); - } - - #[test] - fn call_other_module_with_variables() { - // // main - // from "foo" import foo - // def main(field a) -> field: - // return a * foo(a) - // - // // foo - // def foo(field a) -> field: - // return a * a - // - // - // // inlined - // def main(a) -> field: - // field a_0 = a - // return a * a_0 * a_0 - - let main = TypedModule { - functions: vec![ - ( - FunctionKey::with_id("main").signature( - Signature::new() - .inputs(vec![Type::FieldElement]) - .outputs(vec![Type::FieldElement]), - ), - TypedFunctionSymbol::Here(TypedFunction { - arguments: vec![Parameter::private(Variable::field_element("a"))], - statements: vec![TypedStatement::Return(vec![ - FieldElementExpression::Mult( - box FieldElementExpression::Identifier("a".into()), - box FieldElementExpression::FunctionCall( - FunctionKey::with_id("foo").signature( - Signature::new() - .inputs(vec![Type::FieldElement]) - .outputs(vec![Type::FieldElement]), - ), - vec![FieldElementExpression::Identifier("a".into()).into()], - ), - ) - .into(), - ])], - signature: Signature::new() - .inputs(vec![Type::FieldElement]) - .outputs(vec![Type::FieldElement]), - }), - ), - ( - FunctionKey::with_id("foo").signature( - Signature::new() - .inputs(vec![Type::FieldElement]) - .outputs(vec![Type::FieldElement]), - ), - TypedFunctionSymbol::There( - FunctionKey::with_id("foo").signature( - Signature::new() - .inputs(vec![Type::FieldElement]) - .outputs(vec![Type::FieldElement]), - ), - "foo".into(), - ), - ), - ] - .into_iter() - .collect(), - }; - - let foo = TypedModule { - functions: vec![( - FunctionKey::with_id("foo").signature( - Signature::new() - .inputs(vec![Type::FieldElement]) - .outputs(vec![Type::FieldElement]), - ), - TypedFunctionSymbol::Here(TypedFunction { - arguments: vec![Parameter::private(Variable::field_element("a"))], - statements: vec![TypedStatement::Return(vec![FieldElementExpression::Mult( - box FieldElementExpression::Identifier("a".into()), - box FieldElementExpression::Identifier("a".into()), - ) - .into()])], - signature: Signature::new() - .inputs(vec![Type::FieldElement]) - .outputs(vec![Type::FieldElement]), - }), - )] - .into_iter() - .collect(), - }; - - let modules: HashMap<_, _> = vec![("main".into(), main), ("foo".into(), foo)] - .into_iter() - .collect(); - - let program: TypedProgram = TypedProgram { - main: "main".into(), - modules, - }; - - let program = Inliner::inline(program); - - assert_eq!(program.modules.len(), 1); - - let stack = vec![( - "foo".into(), - FunctionKey::with_id("foo") - .signature( - Signature::new() - .inputs(vec![Type::FieldElement]) - .outputs(vec![Type::FieldElement]), - ) - .hash(), - 1, - )]; - - assert_eq!( - program - .modules - .get(&PathBuf::from("main")) - .unwrap() - .functions - .get( - &FunctionKey::with_id("main").signature( - Signature::new() - .inputs(vec![Type::FieldElement]) - .outputs(vec![Type::FieldElement]) - ) - ) - .unwrap(), - &TypedFunctionSymbol::Here(TypedFunction { - arguments: vec![Parameter::private(Variable::field_element("a"))], - statements: vec![ - TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element( - Identifier::from("a").stack(stack.clone()) - )), - FieldElementExpression::Identifier("a".into()).into() - ), - TypedStatement::Return(vec![FieldElementExpression::Mult( - box FieldElementExpression::Identifier("a".into()), - box FieldElementExpression::Mult( - box FieldElementExpression::Identifier( - Identifier::from("a").stack(stack.clone()) - ), - box FieldElementExpression::Identifier( - Identifier::from("a").stack(stack.clone()) - ) - ) - ) - .into(),]) - ], - signature: Signature::new() - .inputs(vec![Type::FieldElement]) - .outputs(vec![Type::FieldElement]), - }) - ); - } - - #[test] - fn only_memoize_in_same_function() { - // // foo - // def foo(field a) -> field: - // return a - - // // main - // def main(field a) -> field: - // field b = foo(a) + bar(a) - // return b - // - // def bar(field a) -> field: - // return foo(a) - - // inlined - // def main(field a) -> field - // field _0 = a + a - // return _0 - - let signature = Signature::new() - .outputs(vec![Type::FieldElement]) - .inputs(vec![Type::FieldElement]); - - let main: TypedModule = TypedModule { - functions: vec![ - ( - FunctionKey::with_id("main").signature( - Signature::new() - .outputs(vec![Type::FieldElement]) - .inputs(vec![Type::FieldElement]), - ), - TypedFunctionSymbol::Here(TypedFunction { - arguments: vec![Parameter { - id: Variable::field_element("a"), - private: true, - }], - statements: vec![ - TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element("b")), - FieldElementExpression::Add( - box FieldElementExpression::FunctionCall( - FunctionKey::with_id("foo").signature(signature.clone()), - vec![FieldElementExpression::Identifier("a".into()).into()], - ), - box FieldElementExpression::FunctionCall( - FunctionKey::with_id("bar").signature(signature.clone()), - vec![FieldElementExpression::Identifier("a".into()).into()], - ), - ) - .into(), - ), - TypedStatement::Return(vec![FieldElementExpression::Identifier( - "b".into(), - ) - .into()]), - ], - signature: signature.clone(), - }), - ), - ( - FunctionKey::with_id("bar").signature(signature.clone()), - TypedFunctionSymbol::Here(TypedFunction { - arguments: vec![Parameter { - id: Variable::field_element("a"), - private: true, - }], - statements: vec![TypedStatement::Return(vec![ - FieldElementExpression::FunctionCall( - FunctionKey::with_id("foo").signature(signature.clone()), - vec![FieldElementExpression::Identifier("a".into()).into()], - ) - .into(), - ])], - signature: signature.clone(), - }), - ), - ( - FunctionKey::with_id("foo").signature(signature.clone()), - TypedFunctionSymbol::There( - FunctionKey::with_id("foo").signature(signature.clone()), - "foo".into(), - ), - ), - ] - .into_iter() - .collect(), - }; - - let foo: TypedModule = TypedModule { - functions: vec![( - FunctionKey::with_id("foo").signature(signature.clone()), - TypedFunctionSymbol::Here(TypedFunction { - arguments: vec![Parameter { - id: Variable::field_element("a"), - private: true, - }], - statements: vec![TypedStatement::Return(vec![ - FieldElementExpression::Identifier("a".into()).into(), - ])], - signature: signature.clone(), - }), - )] - .into_iter() - .collect(), - }; - - let modules: HashMap<_, _> = vec![("main".into(), main), ("foo".into(), foo)] - .into_iter() - .collect(); - - let program = TypedProgram { - main: "main".into(), - modules, - }; - - let program = Inliner::inline(program); - - assert_eq!(program.modules.len(), 1); - assert_eq!( - program - .modules - .get(&PathBuf::from("main")) - .unwrap() - .functions - .get(&FunctionKey::with_id("main").signature(signature.clone())) - .unwrap(), - &TypedFunctionSymbol::Here(TypedFunction { - arguments: vec![Parameter { - id: Variable::field_element("a"), - private: true, - }], - statements: vec![ - TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element( - Identifier::from("a").stack(vec![( - "foo".into(), - FunctionKey::with_id("foo") - .signature(signature.clone()) - .hash(), - 1 - )]) - )), - FieldElementExpression::Identifier("a".into()).into() - ), - TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element( - Identifier::from("a").stack(vec![( - "main".into(), - FunctionKey::with_id("bar") - .signature(signature.clone()) - .hash(), - 1 - )]) - )), - FieldElementExpression::Identifier("a".into()).into() - ), - TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element( - Identifier::from("a").stack(vec![ - ( - "main".into(), - FunctionKey::with_id("bar") - .signature(signature.clone()) - .hash(), - 1 - ), - ( - "foo".into(), - FunctionKey::with_id("foo") - .signature(signature.clone()) - .hash(), - 2 - ) - ]) - )), - FieldElementExpression::Identifier(Identifier::from("a").stack(vec![( - "main".into(), - FunctionKey::with_id("bar").signature(signature.clone()).hash(), - 1 - )])) - .into() - ), - TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element("b")), - FieldElementExpression::Add( - box FieldElementExpression::Identifier(Identifier::from("a").stack( - vec![( - "foo".into(), - FunctionKey::with_id("foo").signature(signature.clone()).hash(), - 1 - )] - )), - box FieldElementExpression::Identifier(Identifier::from("a").stack( - vec![ - ( - "main".into(), - FunctionKey::with_id("bar") - .signature(signature.clone()) - .hash(), - 1 - ), - ( - "foo".into(), - FunctionKey::with_id("foo") - .signature(signature.clone()) - .hash(), - 2 - ) - ] - )) - ) - .into() - ), - TypedStatement::Return(vec![ - FieldElementExpression::Identifier("b".into()).into(), - ]) - ], - signature: signature.clone(), - }) - ); - } - - #[test] - fn multi_def_from_other_module() { - // // foo - // def foo() -> field: - // return 42 - - // // main - // def main() -> field: - // field b = foo() - // return b - - // inlined - // def main() -> field - // field _0 = 42 - // return _0 - - let main = TypedModule { - functions: vec![ - ( - FunctionKey::with_id("main") - .signature(Signature::new().outputs(vec![Type::FieldElement])), - TypedFunctionSymbol::Here(TypedFunction { - arguments: vec![], - statements: vec![ - TypedStatement::MultipleDefinition( - vec![Variable::field_element("a").into()], - TypedExpressionList::FunctionCall( - FunctionKey::with_id("foo").signature( - Signature::new().outputs(vec![Type::FieldElement]), - ), - vec![], - vec![Type::FieldElement], - ), - ), - TypedStatement::Return(vec![FieldElementExpression::Identifier( - "a".into(), - ) - .into()]), - ], - signature: Signature::new().outputs(vec![Type::FieldElement]), - }), - ), - ( - FunctionKey::with_id("foo") - .signature(Signature::new().outputs(vec![Type::FieldElement])), - TypedFunctionSymbol::There( - FunctionKey::with_id("foo") - .signature(Signature::new().outputs(vec![Type::FieldElement])), - "foo".into(), - ), - ), - ] - .into_iter() - .collect(), - }; - - let foo = TypedModule { - functions: vec![( - FunctionKey::with_id("foo") - .signature(Signature::new().outputs(vec![Type::FieldElement])), - TypedFunctionSymbol::Here(TypedFunction { - arguments: vec![], - statements: vec![TypedStatement::Return(vec![ - FieldElementExpression::Number(Bn128Field::from(42)).into(), - ])], - signature: Signature::new().outputs(vec![Type::FieldElement]), - }), - )] - .into_iter() - .collect(), - }; - - let modules: HashMap<_, _> = vec![("main".into(), main), ("foo".into(), foo)] - .into_iter() - .collect(); - - let program = TypedProgram { - main: "main".into(), - modules, - }; - - let program = Inliner::inline(program); - - assert_eq!(program.modules.len(), 1); - assert_eq!( - program - .modules - .get(&PathBuf::from("main")) - .unwrap() - .functions - .get( - &FunctionKey::with_id("main") - .signature(Signature::new().outputs(vec![Type::FieldElement])) - ) - .unwrap(), - &TypedFunctionSymbol::Here(TypedFunction { - arguments: vec![], - statements: vec![ - TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element("a")), - FieldElementExpression::Number(Bn128Field::from(42)).into() - ), - TypedStatement::Return(vec![ - FieldElementExpression::Identifier("a".into()).into(), - ]) - ], - signature: Signature::new().outputs(vec![Type::FieldElement]), - }) - ); - } - - #[test] - fn multi_def_from_same_module() { - // // main - // def foo() -> field: - // return 42 - // def main() -> field: - // field a = foo() - // return a - - // inlined - // def main() -> field - // field _0 = 42 - // return _0 - - let main = TypedModule { - functions: vec![ - ( - FunctionKey::with_id("main") - .signature(Signature::new().outputs(vec![Type::FieldElement])), - TypedFunctionSymbol::Here(TypedFunction { - arguments: vec![], - statements: vec![ - TypedStatement::MultipleDefinition( - vec![Variable::field_element("a").into()], - TypedExpressionList::FunctionCall( - FunctionKey::with_id("foo").signature( - Signature::new().outputs(vec![Type::FieldElement]), - ), - vec![], - vec![Type::FieldElement], - ), - ), - TypedStatement::Return(vec![FieldElementExpression::Identifier( - "a".into(), - ) - .into()]), - ], - signature: Signature::new().outputs(vec![Type::FieldElement]), - }), - ), - ( - FunctionKey::with_id("foo") - .signature(Signature::new().outputs(vec![Type::FieldElement])), - TypedFunctionSymbol::Here(TypedFunction { - arguments: vec![], - statements: vec![TypedStatement::Return(vec![ - FieldElementExpression::Number(Bn128Field::from(42)).into(), - ])], - signature: Signature::new().outputs(vec![Type::FieldElement]), - }), - ), - ] - .into_iter() - .collect(), - }; - - let modules: HashMap<_, _> = vec![("main".into(), main)].into_iter().collect(); - - let program = TypedProgram { - main: "main".into(), - modules, - }; - - let program = Inliner::inline(program); - - assert_eq!(program.modules.len(), 1); - assert_eq!( - program - .modules - .get(&PathBuf::from("main")) - .unwrap() - .functions - .get( - &FunctionKey::with_id("main") - .signature(Signature::new().outputs(vec![Type::FieldElement])) - ) - .unwrap(), - &TypedFunctionSymbol::Here(TypedFunction { - arguments: vec![], - statements: vec![ - TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element("a")), - FieldElementExpression::Number(Bn128Field::from(42)).into() - ), - TypedStatement::Return(vec![ - FieldElementExpression::Identifier("a".into()).into(), - ]) - ], - signature: Signature::new().outputs(vec![Type::FieldElement]), - }) - ); - } - - #[test] - fn recursive_call_in_other_module() { - // // main - // def main(field a) -> field: - // return id(id(a)) - - // // id - // def main(field a) -> field - // return a - - // inlined - // def main(field a) -> field - // id_main_0_a = a - // id_main_1_a = id_main_0_a - // return id_main_1_a - - let main = TypedModule { - functions: vec![ - ( - FunctionKey::with_id("main").signature( - Signature::new() - .inputs(vec![Type::FieldElement]) - .outputs(vec![Type::FieldElement]), - ), - TypedFunctionSymbol::Here(TypedFunction { - arguments: vec![Parameter::private(Variable::field_element("a"))], - statements: vec![TypedStatement::Return(vec![ - FieldElementExpression::FunctionCall( - FunctionKey::with_id("id").signature( - Signature::new() - .inputs(vec![Type::FieldElement]) - .outputs(vec![Type::FieldElement]), - ), - vec![FieldElementExpression::FunctionCall( - FunctionKey::with_id("id").signature( - Signature::new() - .inputs(vec![Type::FieldElement]) - .outputs(vec![Type::FieldElement]), - ), - vec![FieldElementExpression::Identifier("a".into()).into()], - ) - .into()], - ) - .into(), - ])], - signature: Signature::new() - .inputs(vec![Type::FieldElement]) - .outputs(vec![Type::FieldElement]), - }), - ), - ( - FunctionKey::with_id("id").signature( - Signature::new() - .inputs(vec![Type::FieldElement]) - .outputs(vec![Type::FieldElement]), - ), - TypedFunctionSymbol::There( - FunctionKey::with_id("main").signature( - Signature::new() - .inputs(vec![Type::FieldElement]) - .outputs(vec![Type::FieldElement]), - ), - "id".into(), - ), - ), - ] - .into_iter() - .collect(), - }; - - let id = TypedModule { - functions: vec![( - FunctionKey::with_id("main").signature( - Signature::new() - .inputs(vec![Type::FieldElement]) - .outputs(vec![Type::FieldElement]), - ), - TypedFunctionSymbol::Here(TypedFunction { - arguments: vec![Parameter::private(Variable::field_element("a"))], - statements: vec![TypedStatement::Return(vec![ - FieldElementExpression::Identifier("a".into()).into(), - ])], - signature: Signature::new() - .inputs(vec![Type::FieldElement]) - .outputs(vec![Type::FieldElement]), - }), - )] - .into_iter() - .collect(), - }; - - let modules = vec![("main".into(), main), ("id".into(), id)] - .into_iter() - .collect(); - - let program: TypedProgram = TypedProgram { - main: "main".into(), - modules, - }; - - let program = Inliner::inline(program); - - let stack0 = vec![( - "id".into(), - FunctionKey::with_id("main") - .signature( - Signature::new() - .inputs(vec![Type::FieldElement]) - .outputs(vec![Type::FieldElement]), - ) - .hash(), - 1, - )]; - let stack1 = vec![( - "id".into(), - FunctionKey::with_id("main") - .signature( - Signature::new() - .inputs(vec![Type::FieldElement]) - .outputs(vec![Type::FieldElement]), - ) - .hash(), - 2, - )]; - - assert_eq!(program.modules.len(), 1); - assert_eq!( - program - .modules - .get(&PathBuf::from("main")) - .unwrap() - .functions - .get( - &FunctionKey::with_id("main").signature( - Signature::new() - .inputs(vec![Type::FieldElement]) - .outputs(vec![Type::FieldElement]) - ) - ) - .unwrap(), - &TypedFunctionSymbol::Here(TypedFunction { - arguments: vec![Parameter::private(Variable::field_element("a"))], - statements: vec![ - TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element( - Identifier::from("a").stack(stack0.clone()) - )), - FieldElementExpression::Identifier("a".into()).into() - ), - TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element( - Identifier::from("a").stack(stack1.clone()) - )), - FieldElementExpression::Identifier( - Identifier::from("a").stack(stack0.clone()) - ) - .into() - ), - TypedStatement::Return(vec![FieldElementExpression::Identifier( - Identifier::from("a").stack(stack1.clone()) - ) - .into(),]) - ], - signature: Signature::new() - .inputs(vec![Type::FieldElement]) - .outputs(vec![Type::FieldElement]), - }) - ); - } -} diff --git a/zokrates_core/src/static_analysis/mod.rs b/zokrates_core/src/static_analysis/mod.rs index 83fb69cab..7768ba56f 100644 --- a/zokrates_core/src/static_analysis/mod.rs +++ b/zokrates_core/src/static_analysis/mod.rs @@ -4,69 +4,93 @@ //! @author Thibaut Schaeffer //! @date 2018 +mod bounds_checker; mod flat_propagation; mod flatten_complex_types; -mod inline; -mod propagate_unroll; mod propagation; mod redefinition; -mod return_binder; +mod reducer; mod uint_optimizer; mod unconstrained_vars; -mod unroll; mod variable_read_remover; mod variable_write_remover; +use self::bounds_checker::BoundsChecker; use self::flatten_complex_types::Flattener; -use self::inline::Inliner; -use self::propagate_unroll::PropagatedUnroller; use self::propagation::Propagator; use self::redefinition::RedefinitionOptimizer; -use self::return_binder::ReturnBinder; +use self::reducer::reduce_program; use self::uint_optimizer::UintOptimizer; use self::unconstrained_vars::UnconstrainedVariableDetector; use self::variable_read_remover::VariableReadRemover; use self::variable_write_remover::VariableWriteRemover; use crate::flat_absy::FlatProg; use crate::ir::Prog; -use crate::typed_absy::TypedProgram; +use crate::typed_absy::{abi::Abi, TypedProgram}; use crate::zir::ZirProgram; +use std::fmt; use zokrates_field::Field; pub trait Analyse { fn analyse(self) -> Self; } +#[derive(Debug)] +pub enum Error { + Reducer(self::reducer::Error), + OutOfBounds(self::bounds_checker::Error), + Propagation(self::propagation::Error), +} -impl<'ast, T: Field> TypedProgram<'ast, T> { - pub fn analyse(self) -> ZirProgram<'ast, T> { - // propagated unrolling - let r = PropagatedUnroller::unroll(self).unwrap_or_else(|e| panic!("{}", e)); +impl From for Error { + fn from(e: self::reducer::Error) -> Self { + Error::Reducer(e) + } +} - // return binding - let r = ReturnBinder::bind(r); +impl From for Error { + fn from(e: bounds_checker::Error) -> Self { + Error::OutOfBounds(e) + } +} - // inline - let r = Inliner::inline(r); +impl From for Error { + fn from(e: propagation::Error) -> Self { + Error::Propagation(e) + } +} - // propagate - let r = Propagator::propagate(r); +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Error::Reducer(e) => write!(f, "{}", e), + Error::OutOfBounds(e) => write!(f, "{}", e), + Error::Propagation(e) => write!(f, "{}", e), + } + } +} + +impl<'ast, T: Field> TypedProgram<'ast, T> { + pub fn analyse(self) -> Result<(ZirProgram<'ast, T>, Abi), Error> { + let r = reduce_program(self).map_err(Error::from)?; + let abi = r.abi(); + + // propagate + let r = Propagator::propagate(r).map_err(Error::from)?; // optimize redefinitions let r = RedefinitionOptimizer::optimize(r); - // remove assignment to variable index let r = VariableWriteRemover::apply(r); - // remove variable access to complex types let r = VariableReadRemover::apply(r); - + // check array accesses are in bounds + let r = BoundsChecker::check(r).map_err(Error::from)?; // convert to zir, removing complex types let zir = Flattener::flatten(r); - // optimize uint expressions let zir = UintOptimizer::optimize(zir); - zir + Ok((zir, abi)) } } @@ -78,7 +102,6 @@ impl Analyse for FlatProg { impl Analyse for Prog { fn analyse(self) -> Self { - let r = UnconstrainedVariableDetector::detect(self); - r + UnconstrainedVariableDetector::detect(self) } } diff --git a/zokrates_core/src/static_analysis/propagate_unroll.rs b/zokrates_core/src/static_analysis/propagate_unroll.rs deleted file mode 100644 index 67354b537..000000000 --- a/zokrates_core/src/static_analysis/propagate_unroll.rs +++ /dev/null @@ -1,236 +0,0 @@ -//! Module containing iterative unrolling in order to unroll nested loops with variable bounds -//! -//! For example: -//! ```zokrates -//! for field i in 0..5 do -//! for field j in i..5 do -//! // -//! endfor -//! endfor -//! ``` -//! -//! We can unroll the outer loop, but to unroll the inner one we need to propagate the value of `i` to the lower bound of the loop -//! -//! This module does exactly that: -//! - unroll the outter loop, detecting that it cannot unroll the inner one as the lower `i` bound isn't constant -//! - apply constant propagation to the program, *not visiting statements of loops whose bounds are not constant yet* -//! - unroll again, this time the 5 inner loops all have constant bounds -//! -//! In the case that a loop bound cannot be reduced to a constant, we detect it by noticing that the unroll does -//! not make progress anymore. - -use crate::static_analysis::propagation::Propagator; -use crate::static_analysis::unroll::{Output, Unroller}; -use crate::typed_absy::TypedProgram; -use zokrates_field::Field; - -pub struct PropagatedUnroller; - -impl PropagatedUnroller { - pub fn unroll<'ast, T: Field>( - p: TypedProgram<'ast, T>, - ) -> Result, &'static str> { - let mut blocked_at = None; - - // unroll a first time, retrieving whether the unroll is complete - let mut unrolled = Unroller::unroll(p); - - loop { - // conditions to exit the loop - unrolled = match unrolled { - Output::Complete(p) => return Ok(p), - Output::Incomplete(next, index) => { - if Some(index) == blocked_at { - return Err("Loop unrolling failed. This happened because a loop bound is not constant"); - } else { - // update the index where we blocked - blocked_at = Some(index); - - // propagate - let propagated = Propagator::propagate_verbose(next); - - // unroll - Unroller::unroll(propagated) - } - } - }; - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::typed_absy::types::{FunctionKey, Signature}; - use crate::typed_absy::*; - use zokrates_field::Bn128Field; - - #[test] - fn detect_non_constant_bound() { - let loops = vec![TypedStatement::For( - Variable::field_element("i"), - FieldElementExpression::Identifier("i".into()), - FieldElementExpression::Number(Bn128Field::from(2)), - vec![], - )]; - - let statements = loops; - - let p = TypedProgram { - modules: vec![( - "main".into(), - TypedModule { - functions: vec![( - FunctionKey::with_id("main"), - TypedFunctionSymbol::Here(TypedFunction { - arguments: vec![], - signature: Signature::new(), - statements, - }), - )] - .into_iter() - .collect(), - }, - )] - .into_iter() - .collect(), - main: "main".into(), - }; - - assert!(PropagatedUnroller::unroll(p).is_err()); - } - - #[test] - fn for_loop() { - // for field i in 0..2 - // for field j in i..2 - // field foo = i + j - - // should be unrolled to - // i_0 = 0 - // j_0 = 0 - // foo_0 = i_0 + j_0 - // j_1 = 1 - // foo_1 = i_0 + j_1 - // i_1 = 1 - // j_2 = 1 - // foo_2 = i_1 + j_1 - - let s = TypedStatement::For( - Variable::field_element("i"), - FieldElementExpression::Number(Bn128Field::from(0)), - FieldElementExpression::Number(Bn128Field::from(2)), - vec![TypedStatement::For( - Variable::field_element("j"), - FieldElementExpression::Identifier("i".into()), - FieldElementExpression::Number(Bn128Field::from(2)), - vec![ - TypedStatement::Declaration(Variable::field_element("foo")), - TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element("foo")), - FieldElementExpression::Add( - box FieldElementExpression::Identifier("i".into()), - box FieldElementExpression::Identifier("j".into()), - ) - .into(), - ), - ], - )], - ); - - let expected_statements = vec![ - TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element( - Identifier::from("i").version(0), - )), - FieldElementExpression::Number(Bn128Field::from(0)).into(), - ), - TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element( - Identifier::from("j").version(0), - )), - FieldElementExpression::Number(Bn128Field::from(0)).into(), - ), - TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element( - Identifier::from("foo").version(0), - )), - FieldElementExpression::Add( - box FieldElementExpression::Identifier(Identifier::from("i").version(0)), - box FieldElementExpression::Identifier(Identifier::from("j").version(0)), - ) - .into(), - ), - TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element( - Identifier::from("j").version(1), - )), - FieldElementExpression::Number(Bn128Field::from(1)).into(), - ), - TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element( - Identifier::from("foo").version(1), - )), - FieldElementExpression::Add( - box FieldElementExpression::Identifier(Identifier::from("i").version(0)), - box FieldElementExpression::Identifier(Identifier::from("j").version(1)), - ) - .into(), - ), - TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element( - Identifier::from("i").version(1), - )), - FieldElementExpression::Number(Bn128Field::from(1)).into(), - ), - TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element( - Identifier::from("j").version(2), - )), - FieldElementExpression::Number(Bn128Field::from(1)).into(), - ), - TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element( - Identifier::from("foo").version(2), - )), - FieldElementExpression::Add( - box FieldElementExpression::Identifier(Identifier::from("i").version(1)), - box FieldElementExpression::Identifier(Identifier::from("j").version(2)), - ) - .into(), - ), - ]; - - let p = TypedProgram { - modules: vec![( - "main".into(), - TypedModule { - functions: vec![( - FunctionKey::with_id("main"), - TypedFunctionSymbol::Here(TypedFunction { - arguments: vec![], - signature: Signature::new(), - statements: vec![s], - }), - )] - .into_iter() - .collect(), - }, - )] - .into_iter() - .collect(), - main: "main".into(), - }; - - let statements = match PropagatedUnroller::unroll(p).unwrap().modules - [std::path::Path::new("main")] - .functions[&FunctionKey::with_id("main")] - .clone() - { - TypedFunctionSymbol::Here(f) => f.statements, - _ => unreachable!(), - }; - - assert_eq!(statements, expected_statements); - } -} diff --git a/zokrates_core/src/static_analysis/propagation.rs b/zokrates_core/src/static_analysis/propagation.rs index 2f2993cef..fb32bdd7c 100644 --- a/zokrates_core/src/static_analysis/propagation.rs +++ b/zokrates_core/src/static_analysis/propagation.rs @@ -1,60 +1,62 @@ //! Module containing constant propagation for the typed AST //! -//! On top of the usual behavior of removing statements which assign a constant to a variable (as the variable can simply be -//! substituted for the constant whenever used), we provide a `verbose` mode which does not remove such statements. This is done -//! as for partial passes which do not visit the whole program, the variables being defined may be be used in parts of the program -//! that are not visited. Keeping the statements is semantically equivalent and enables rebuilding the set of constants at the -//! next pass. +//! Constant propagation on the SSA program. The constants map can be passed by the caller to allow for many passes to use +//! the same constants. //! //! @file propagation.rs //! @author Thibaut Schaeffer //! @date 2018 -use crate::typed_absy::folder::*; +use crate::embed::FlatEmbed; +use crate::typed_absy::result_folder::*; use crate::typed_absy::types::Type; use crate::typed_absy::*; use std::collections::HashMap; -use std::convert::TryFrom; +use std::convert::{TryFrom, TryInto}; +use std::fmt; use zokrates_field::Field; -pub struct Propagator<'ast, T: Field> { - // constants keeps track of constant expressions - // we currently do not support partially constant expressions: `field [x, 1][1]` is not considered constant, `field [0, 1][1]` is - constants: HashMap, TypedExpression<'ast, T>>, - // the verbose mode doesn't remove statements which assign constants to variables - // it's required when using propagation in combination with unrolling - verbose: bool, +type Constants<'ast, T> = HashMap, TypedExpression<'ast, T>>; + +#[derive(Debug, PartialEq)] +pub enum Error { + Type(String), } -impl<'ast, T: Field> Propagator<'ast, T> { - fn verbose() -> Self { - Propagator { - constants: HashMap::new(), - verbose: true, +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Error::Type(s) => write!(f, "{}", s), } } +} - fn new() -> Self { - Propagator { - constants: HashMap::new(), - verbose: false, - } - } +pub struct Propagator<'ast, 'a, T: Field> { + // constants keeps track of constant expressions + // we currently do not support partially constant expressions: `field [x, 1][1]` is not considered constant, `field [0, 1][1]` is + constants: &'a mut Constants<'ast, T>, +} - pub fn propagate(p: TypedProgram<'ast, T>) -> TypedProgram<'ast, T> { - Propagator::new().fold_program(p) +impl<'ast, 'a, T: Field> Propagator<'ast, 'a, T> { + pub fn with_constants(constants: &'a mut Constants<'ast, T>) -> Self { + Propagator { constants } } - pub fn propagate_verbose(p: TypedProgram<'ast, T>) -> TypedProgram<'ast, T> { - Propagator::verbose().fold_program(p) + pub fn propagate(p: TypedProgram<'ast, T>) -> Result, Error> { + let mut constants = Constants::new(); + + Propagator { + constants: &mut constants, + } + .fold_program(p) } // get a mutable reference to the constant corresponding to a given assignee if any, otherwise // return the identifier at the root of this assignee - fn try_get_constant_mut<'a>( + fn try_get_constant_mut<'b>( &mut self, - assignee: &'a TypedAssignee<'ast, T>, - ) -> Result<(&'a Variable<'ast>, &mut TypedExpression<'ast, T>), &'a Variable<'ast>> { + assignee: &'b TypedAssignee<'ast, T>, + ) -> Result<(&'b Variable<'ast, T>, &mut TypedExpression<'ast, T>), &'b Variable<'ast, T>> { match assignee { TypedAssignee::Identifier(var) => self .constants @@ -63,19 +65,20 @@ impl<'ast, T: Field> Propagator<'ast, T> { .unwrap_or(Err(var)), TypedAssignee::Select(box assignee, box index) => { match self.try_get_constant_mut(&assignee) { - Ok((v, c)) => match index { - FieldElementExpression::Number(n) => { - let n = n.to_dec_string().parse::().unwrap(); - - match c { - TypedExpression::Array(a) => match a.as_inner_mut() { - ArrayExpressionInner::Value(value) => Ok((v, &mut value[n])), + 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[*n as usize] { + TypedExpressionOrSpread::Expression(ref mut e) => { + Ok((variable, e)) + } _ => unreachable!(), }, _ => unreachable!(), - } - } - _ => Err(v), + }, + _ => unreachable!(), + }, + _ => Err(variable), }, e => e, } @@ -107,86 +110,200 @@ impl<'ast, T: Field> Propagator<'ast, T> { } } -fn is_constant<'ast, T: Field>(e: &TypedExpression<'ast, T>) -> bool { +fn is_constant(e: &TypedExpression) -> bool { match e { TypedExpression::FieldElement(FieldElementExpression::Number(..)) => true, TypedExpression::Boolean(BooleanExpression::Value(..)) => true, TypedExpression::Array(a) => match a.as_inner() { - ArrayExpressionInner::Value(v) => v.iter().all(|e| is_constant(e)), + ArrayExpressionInner::Value(v) => v.0.iter().all(|e| match e { + TypedExpressionOrSpread::Expression(e) => is_constant(e), + _ => false, + }), + ArrayExpressionInner::Slice(box a, box from, box to) => { + is_constant(&from.clone().into()) + && is_constant(&to.clone().into()) + && is_constant(&a.clone().into()) + } + ArrayExpressionInner::Repeat(box e, box count) => { + is_constant(&count.clone().into()) && is_constant(&e) + } _ => false, }, TypedExpression::Struct(a) => match a.as_inner() { StructExpressionInner::Value(v) => v.iter().all(|e| is_constant(e)), _ => false, }, - TypedExpression::Uint(a) => match a.as_inner() { - UExpressionInner::Value(..) => true, - _ => false, - }, + TypedExpression::Uint(a) => matches!(a.as_inner(), UExpressionInner::Value(..)), _ => false, } } -impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> { - fn fold_function(&mut self, f: TypedFunction<'ast, T>) -> TypedFunction<'ast, T> { - self.constants = HashMap::new(); +fn remove_spreads(e: TypedExpression) -> TypedExpression { + fn remove_spreads_aux(e: TypedExpressionOrSpread) -> Vec> { + match e { + TypedExpressionOrSpread::Expression(e) => vec![e], + TypedExpressionOrSpread::Spread(s) => match s.array.into_inner() { + ArrayExpressionInner::Value(v) => { + v.into_iter().flat_map(remove_spreads_aux).collect() + } + _ => unimplemented!(), + }, + } + } + + match e { + TypedExpression::Array(a) => { + let array_ty = a.get_array_type(); + + match a.into_inner() { + ArrayExpressionInner::Value(v) => ArrayExpressionInner::Value( + v.into_iter() + .flat_map(remove_spreads_aux) + .map(|e| e.into()) + .collect::>() + .into(), + ) + .annotate(*array_ty.ty, array_ty.size) + .into(), + ArrayExpressionInner::Slice(box a, box from, box to) => { + let from = match from.into_inner() { + UExpressionInner::Value(from) => from as usize, + _ => unreachable!(), + }; + + let to = match to.into_inner() { + UExpressionInner::Value(to) => to as usize, + _ => unreachable!(), + }; + + let v = match a.into_inner() { + ArrayExpressionInner::Value(v) => v, + _ => unreachable!(), + }; + + ArrayExpressionInner::Value( + v.into_iter() + .flat_map(remove_spreads_aux) + .map(|e| e.into()) + .enumerate() + .filter(|(index, _)| index >= &from && index < &to) + .map(|(_, e)| e) + .collect::>() + .into(), + ) + .annotate(*array_ty.ty, array_ty.size) + .into() + } + ArrayExpressionInner::Repeat(box e, box count) => { + let count = match count.into_inner() { + UExpressionInner::Value(from) => from as usize, + _ => unreachable!(), + }; + + let e = remove_spreads(e); + + ArrayExpressionInner::Value( + vec![TypedExpressionOrSpread::Expression(e); count].into(), + ) + .annotate(*array_ty.ty, array_ty.size) + .into() + } + _ => unreachable!(), + } + } + e => e, + } +} + +impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> { + type Error = Error; + + fn fold_program(&mut self, p: TypedProgram<'ast, T>) -> Result, Error> { + let main = p.main.clone(); + + Ok(TypedProgram { + modules: p + .modules + .into_iter() + .map(|(module_id, module)| { + if module_id == main { + self.fold_module(module).map(|m| (module_id, m)) + } else { + Ok((module_id, module)) + } + }) + .collect::>()?, + main: p.main, + }) + } + + fn fold_module(&mut self, m: TypedModule<'ast, T>) -> Result, Error> { + Ok(TypedModule { + functions: m + .functions + .into_iter() + .map(|(key, fun)| { + if key.id == "main" { + self.fold_function_symbol(fun).map(|f| (key, f)) + } else { + Ok((key, fun)) + } + }) + .collect::>()?, + }) + } + + fn fold_function( + &mut self, + f: TypedFunction<'ast, T>, + ) -> Result, Error> { fold_function(self, f) } - fn fold_statement(&mut self, s: TypedStatement<'ast, T>) -> Vec> { - let res = match s { - TypedStatement::Declaration(v) => vec![TypedStatement::Declaration(v)], - TypedStatement::Return(expressions) => vec![TypedStatement::Return( - expressions - .into_iter() - .map(|e| self.fold_expression(e)) - .collect(), - )], + fn fold_statement( + &mut self, + s: TypedStatement<'ast, T>, + ) -> Result>, Error> { + match s { // propagation to the defined variable if rhs is a constant TypedStatement::Definition(assignee, expr) => { - let expr = self.fold_expression(expr); - let assignee = self.fold_assignee(assignee); + let expr = self.fold_expression(expr)?; + let assignee = self.fold_assignee(assignee)?; + + if let (Ok(a), Ok(e)) = ( + ConcreteType::try_from(assignee.get_type()), + ConcreteType::try_from(expr.get_type()), + ) { + if a != e { + return Err(Error::Type(format!( + "Cannot assign {} of type {} to {} of type {}", + expr, e, assignee, a + ))); + } + }; if is_constant(&expr) { - let verbose = self.verbose; - match assignee { - TypedAssignee::Identifier(var) => match verbose { - true => { - assert!(self - .constants - .insert(var.id.clone(), expr.clone()) - .is_none()); - vec![TypedStatement::Definition( - TypedAssignee::Identifier(var), - expr, - )] - } - false => { - assert!(self.constants.insert(var.id, expr).is_none()); + TypedAssignee::Identifier(var) => { + let expr = remove_spreads(expr); - vec![] - } - }, + assert!(self.constants.insert(var.id, expr).is_none()); + + Ok(vec![]) + } assignee => match self.try_get_constant_mut(&assignee) { - Ok((_, c)) => match verbose { - true => { - *c = expr.clone(); - vec![TypedStatement::Definition(assignee, expr)] - } - false => { - *c = expr; - vec![] - } - }, + Ok((_, c)) => { + *c = remove_spreads(expr); + 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) => vec![ + Some(c) => Ok(vec![ TypedStatement::Definition(v.clone().into(), c), TypedStatement::Definition(assignee, expr), - ], - None => vec![TypedStatement::Definition(assignee, expr)], + ]), + None => Ok(vec![TypedStatement::Definition(assignee, expr)]), }, }, } @@ -198,68 +315,66 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> { .unwrap_or_else(|v| v); match self.constants.remove(&v.id) { - Some(c) => vec![ + Some(c) => Ok(vec![ TypedStatement::Definition(v.clone().into(), c), TypedStatement::Definition(assignee, expr), - ], - None => vec![TypedStatement::Definition(assignee, expr)], + ]), + None => Ok(vec![TypedStatement::Definition(assignee, expr)]), } } } - // propagate the boolean - TypedStatement::Assertion(e) => { - // could stop execution here if condition is known to fail - vec![TypedStatement::Assertion(self.fold_boolean_expression(e))] - } - // only loops with variable bounds are expected here - // we stop propagation here as constants maybe be modified inside the loop body - // which we do not visit + // we do not visit the for-loop statements TypedStatement::For(v, from, to, statements) => { - let from = self.fold_field_expression(from); - let to = self.fold_field_expression(to); + let from = self.fold_uint_expression(from)?; + let to = self.fold_uint_expression(to)?; - // invalidate the constants map as any constant could be modified inside the loop body, which we don't visit - self.constants.clear(); - - vec![TypedStatement::For(v, from, to, statements)] + Ok(vec![TypedStatement::For(v, from, to, statements)]) } TypedStatement::MultipleDefinition(assignees, expression_list) => { let assignees: Vec> = assignees .into_iter() .map(|a| self.fold_assignee(a)) - .collect(); - let expression_list = self.fold_expression_list(expression_list); + .collect::>()?; + let expression_list = self.fold_expression_list(expression_list)?; - match expression_list { - TypedExpressionList::FunctionCall(key, arguments, types) => { + let statements = match expression_list { + TypedExpressionList::EmbedCall(embed, generics, arguments, types) => { let arguments: Vec<_> = arguments .into_iter() .map(|a| self.fold_expression(a)) - .collect(); + .collect::>()?; + + let types = types + .into_iter() + .map(|t| self.fold_type(t)) + .collect::>()?; fn process_u_from_bits<'ast, T: Field>( variables: Vec>, - arguments: Vec>, + mut arguments: Vec>, bitwidth: UBitwidth, ) -> TypedExpression<'ast, T> { assert_eq!(variables.len(), 1); assert_eq!(arguments.len(), 1); - use std::convert::TryInto; + let argument = arguments.pop().unwrap(); + + let argument = remove_spreads(argument); - match ArrayExpression::try_from(arguments[0].clone()) + match ArrayExpression::try_from(argument) .unwrap() .into_inner() { - ArrayExpressionInner::Value(v) => { - assert_eq!(v.len(), bitwidth.to_usize()); + ArrayExpressionInner::Value(v) => UExpressionInner::Value( v.into_iter() .map(|v| match v { - TypedExpression::Boolean( - BooleanExpression::Value(v), + TypedExpressionOrSpread::Expression( + TypedExpression::Boolean( + BooleanExpression::Value(v), + ), ) => v, - _ => unreachable!("should be a boolean value"), + _ => unreachable!("Should be a constant boolean expression. Spreads are not expected here, as in their presence the argument isn't constant"), }) .enumerate() .fold(0, |acc, (i, v)| { @@ -275,9 +390,8 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> { }), ) .annotate(bitwidth) - .into() - } - _ => unreachable!("should be an array value"), + .into(), + v => unreachable!("should be an array value, found {}", v), } } @@ -299,7 +413,7 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> { for i in (0..bitwidth as u32).rev() { if 2u128.pow(i) <= num { - num = num - 2u128.pow(i); + num -= 2u128.pow(i); res.push(true); } else { res.push(false); @@ -310,9 +424,10 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> { ArrayExpressionInner::Value( res.into_iter() .map(|v| BooleanExpression::Value(v).into()) - .collect(), + .collect::>() + .into(), ) - .annotate(Type::Boolean, bitwidth.to_usize()) + .annotate(Type::Boolean, bitwidth.to_usize() as u32) .into() } _ => unreachable!("should be a uint value"), @@ -321,40 +436,54 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> { match arguments.iter().all(|a| is_constant(a)) { true => { - let r: Option> = match key.id { - "_U32_FROM_BITS" => Some(process_u_from_bits( + let r: Option> = match embed { + FlatEmbed::U32ToField => None, // todo + FlatEmbed::U64FromBits => Some(process_u_from_bits( + assignees.clone(), + arguments.clone(), + UBitwidth::B64, + )), + FlatEmbed::U32FromBits => Some(process_u_from_bits( assignees.clone(), arguments.clone(), UBitwidth::B32, )), - "_U16_FROM_BITS" => Some(process_u_from_bits( + FlatEmbed::U16FromBits => Some(process_u_from_bits( assignees.clone(), arguments.clone(), UBitwidth::B16, )), - "_U8_FROM_BITS" => Some(process_u_from_bits( + FlatEmbed::U8FromBits => Some(process_u_from_bits( assignees.clone(), arguments.clone(), UBitwidth::B8, )), - "_U32_TO_BITS" => Some(process_u_to_bits( + FlatEmbed::U64ToBits => Some(process_u_to_bits( + assignees.clone(), + arguments.clone(), + UBitwidth::B64, + )), + FlatEmbed::U32ToBits => Some(process_u_to_bits( assignees.clone(), arguments.clone(), UBitwidth::B32, )), - "_U16_TO_BITS" => Some(process_u_to_bits( + FlatEmbed::U16ToBits => Some(process_u_to_bits( assignees.clone(), arguments.clone(), UBitwidth::B16, )), - "_U8_TO_BITS" => Some(process_u_to_bits( + FlatEmbed::U8ToBits => Some(process_u_to_bits( assignees.clone(), arguments.clone(), UBitwidth::B8, )), - "_UNPACK" => { + FlatEmbed::Unpack => { assert_eq!(assignees.len(), 1); assert_eq!(arguments.len(), 1); + assert_eq!(generics.len(), 1); + + let bit_width = generics[0]; match FieldElementExpression::try_from(arguments[0].clone()) .unwrap() @@ -363,7 +492,7 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> { let mut num = num; let mut res = vec![]; - for i in (0..T::get_required_bits()).rev() { + for i in (0..bit_width as usize).rev() { if T::from(2).pow(i) <= num { num = num - T::from(2).pow(i); res.push(true); @@ -379,56 +508,35 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> { .map(|v| { BooleanExpression::Value(v).into() }) - .collect(), + .collect::>() + .into(), ) - .annotate(Type::Boolean, T::get_required_bits()) + .annotate(Type::Boolean, bit_width) .into(), ) } _ => unreachable!("should be a field value"), } } - "_SHA256_ROUND" => None, - _ => None, + FlatEmbed::Sha256Round => None, }; match r { // if the function call returns a constant Some(expr) => { - let verbose = self.verbose; - let mut assignees = assignees; match assignees.pop().unwrap() { - TypedAssignee::Identifier(var) => match verbose { - true => { - self.constants - .insert(var.id.clone(), expr.clone()); - vec![TypedStatement::Definition( - TypedAssignee::Identifier(var), - expr, - )] - } - false => { - self.constants.insert(var.id, expr); - - vec![] - } - }, + TypedAssignee::Identifier(var) => { + self.constants.insert(var.id, expr); + vec![] + } assignee => { match self.try_get_constant_mut(&assignee) { - Ok((_, c)) => match verbose { - true => { - *c = expr.clone(); - vec![TypedStatement::Definition( - assignee, expr, - )] - } - false => { - *c = expr; - vec![] - } - }, + Ok((_, c)) => { + *c = expr; + vec![] + } Err(v) => match self.constants.remove(&v.id) { Some(c) => vec![ TypedStatement::Definition( @@ -464,15 +572,15 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> { TypedStatement::Definition(v.clone().into(), c), TypedStatement::MultipleDefinition( vec![assignee], - TypedExpressionList::FunctionCall( - key, arguments, types, + TypedExpressionList::EmbedCall( + embed, generics, arguments, types, ), ), ], None => vec![TypedStatement::MultipleDefinition( vec![assignee], - TypedExpressionList::FunctionCall( - key, arguments, types, + TypedExpressionList::EmbedCall( + embed, generics, arguments, types, ), )], } @@ -483,49 +591,84 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> { // if the function arguments are not constant, invalidate the cache // for the return assignees - let invalidations = assignees - .iter() - .flat_map(|assignee| { - let v = self - .try_get_constant_mut(&assignee) - .map(|(v, _)| v) - .unwrap_or_else(|v| v); - match self.constants.remove(&v.id) { - Some(c) => vec![TypedStatement::Definition( - v.clone().into(), - c, - )], - None => vec![], + let def = TypedStatement::MultipleDefinition( + assignees.clone(), + TypedExpressionList::EmbedCall( + embed, generics, arguments, types, + ), + ); + + let invalidations = assignees.iter().flat_map(|assignee| { + let v = self + .try_get_constant_mut(&assignee) + .map(|(v, _)| v) + .unwrap_or_else(|v| v); + match self.constants.remove(&v.id) { + Some(c) => { + vec![TypedStatement::Definition(v.clone().into(), c)] } - }) - .collect::>(); - - let l = TypedExpressionList::FunctionCall(key, arguments, types); - invalidations - .into_iter() - .chain(std::iter::once(TypedStatement::MultipleDefinition( - assignees, l, - ))) - .collect() + None => vec![], + } + }); + + invalidations.chain(std::iter::once(def)).collect() } } } - } - } - }; + TypedExpressionList::FunctionCall(key, generics, arguments, types) => { + let generics = generics + .into_iter() + .map(|g| g.map(|g| self.fold_uint_expression(g)).transpose()) + .collect::>()?; + + let arguments: Vec<_> = arguments + .into_iter() + .map(|a| self.fold_expression(a)) + .collect::>()?; - // In verbose mode, we always return at least a statement - assert!(res.len() > 0 || !self.verbose); + let types = types + .into_iter() + .map(|t| self.fold_type(t)) + .collect::>()?; + + // invalidate the cache for the return assignees as this call mutates them + + let def = TypedStatement::MultipleDefinition( + assignees.clone(), + TypedExpressionList::FunctionCall(key, generics, arguments, types), + ); + + let invalidations = assignees.iter().flat_map(|assignee| { + let v = self + .try_get_constant_mut(&assignee) + .map(|(v, _)| v) + .unwrap_or_else(|v| v); + match self.constants.remove(&v.id) { + Some(c) => { + vec![TypedStatement::Definition(v.clone().into(), c)] + } + None => vec![], + } + }); - res + invalidations.chain(std::iter::once(def)).collect() + } + }; + + Ok(statements) + } + s @ TypedStatement::PushCallLog(..) => Ok(vec![s]), + s @ TypedStatement::PopCallLog => Ok(vec![s]), + s => fold_statement(self, s), + } } fn fold_uint_expression_inner( &mut self, bitwidth: UBitwidth, e: UExpressionInner<'ast, T>, - ) -> UExpressionInner<'ast, T> { - match e { + ) -> Result, Error> { + Ok(match e { UExpressionInner::Identifier(id) => match self.constants.get(&id) { Some(e) => match e { TypedExpression::Uint(e) => e.as_inner().clone(), @@ -534,11 +677,10 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> { None => UExpressionInner::Identifier(id), }, UExpressionInner::Add(box e1, box e2) => match ( - self.fold_uint_expression(e1).into_inner(), - self.fold_uint_expression(e2).into_inner(), + self.fold_uint_expression(e1)?.into_inner(), + self.fold_uint_expression(e2)?.into_inner(), ) { (UExpressionInner::Value(v1), UExpressionInner::Value(v2)) => { - use std::convert::TryInto; UExpressionInner::Value( (v1 + v2) % 2_u128.pow(bitwidth.to_usize().try_into().unwrap()), ) @@ -555,16 +697,15 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> { } }, UExpressionInner::Sub(box e1, box e2) => match ( - self.fold_uint_expression(e1).into_inner(), - self.fold_uint_expression(e2).into_inner(), + self.fold_uint_expression(e1)?.into_inner(), + self.fold_uint_expression(e2)?.into_inner(), ) { (UExpressionInner::Value(v1), UExpressionInner::Value(v2)) => { - use std::convert::TryInto; UExpressionInner::Value( (v1.wrapping_sub(v2)) % 2_u128.pow(bitwidth.to_usize().try_into().unwrap()), ) } - (e, UExpressionInner::Value(v)) | (UExpressionInner::Value(v), e) => match v { + (e, UExpressionInner::Value(v)) => match v { 0 => e, _ => UExpressionInner::Sub( box e.annotate(bitwidth), @@ -575,12 +716,31 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> { UExpressionInner::Sub(box e1.annotate(bitwidth), box e2.annotate(bitwidth)) } }, + UExpressionInner::FloorSub(box e1, box e2) => match ( + self.fold_uint_expression(e1)?.into_inner(), + self.fold_uint_expression(e2)?.into_inner(), + ) { + (UExpressionInner::Value(v1), UExpressionInner::Value(v2)) => { + UExpressionInner::Value( + v1.saturating_sub(v2) % 2_u128.pow(bitwidth.to_usize().try_into().unwrap()), + ) + } + (e, UExpressionInner::Value(v)) => match v { + 0 => e, + _ => UExpressionInner::FloorSub( + box e.annotate(bitwidth), + box UExpressionInner::Value(v).annotate(bitwidth), + ), + }, + (e1, e2) => { + UExpressionInner::Sub(box e1.annotate(bitwidth), box e2.annotate(bitwidth)) + } + }, UExpressionInner::Mult(box e1, box e2) => match ( - self.fold_uint_expression(e1).into_inner(), - self.fold_uint_expression(e2).into_inner(), + self.fold_uint_expression(e1)?.into_inner(), + self.fold_uint_expression(e2)?.into_inner(), ) { (UExpressionInner::Value(v1), UExpressionInner::Value(v2)) => { - use std::convert::TryInto; UExpressionInner::Value( (v1 * v2) % 2_u128.pow(bitwidth.to_usize().try_into().unwrap()), ) @@ -598,11 +758,10 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> { } }, UExpressionInner::Div(box e1, box e2) => match ( - self.fold_uint_expression(e1).into_inner(), - self.fold_uint_expression(e2).into_inner(), + self.fold_uint_expression(e1)?.into_inner(), + self.fold_uint_expression(e2)?.into_inner(), ) { (UExpressionInner::Value(v1), UExpressionInner::Value(v2)) => { - use std::convert::TryInto; UExpressionInner::Value( (v1 / v2) % 2_u128.pow(bitwidth.to_usize().try_into().unwrap()), ) @@ -619,11 +778,10 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> { } }, UExpressionInner::Rem(box e1, box e2) => match ( - self.fold_uint_expression(e1).into_inner(), - self.fold_uint_expression(e2).into_inner(), + self.fold_uint_expression(e1)?.into_inner(), + self.fold_uint_expression(e2)?.into_inner(), ) { (UExpressionInner::Value(v1), UExpressionInner::Value(v2)) => { - use std::convert::TryInto; UExpressionInner::Value( (v1 % v2) % 2_u128.pow(bitwidth.to_usize().try_into().unwrap()), ) @@ -640,44 +798,34 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> { } }, UExpressionInner::RightShift(box e, box by) => { - let e = self.fold_uint_expression(e); - let by = self.fold_field_expression(by); - match (e.into_inner(), by) { - (UExpressionInner::Value(v), FieldElementExpression::Number(by)) => { - let by_as_usize = by.to_dec_string().parse::().unwrap(); - UExpressionInner::Value(v >> by_as_usize) + 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)) => { + UExpressionInner::Value(v >> by) } - (e, FieldElementExpression::Number(by)) => UExpressionInner::RightShift( + (e, by) => UExpressionInner::RightShift( box e.annotate(bitwidth), - box FieldElementExpression::Number(by), + box by.annotate(UBitwidth::B32), ), - (_, e2) => unreachable!(format!( - "non-constant shift {} detected during static analysis", - e2 - )), } } UExpressionInner::LeftShift(box e, box by) => { - let e = self.fold_uint_expression(e); - let by = self.fold_field_expression(by); - match (e.into_inner(), by) { - (UExpressionInner::Value(v), FieldElementExpression::Number(by)) => { - let by_as_usize = by.to_dec_string().parse::().unwrap(); - UExpressionInner::Value((v << by_as_usize) & 0xffffffff) + 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)) => { + UExpressionInner::Value((v << by) & (2_u128.pow(bitwidth as u32) - 1)) } - (e, FieldElementExpression::Number(by)) => UExpressionInner::LeftShift( + (e, by) => UExpressionInner::LeftShift( box e.annotate(bitwidth), - box FieldElementExpression::Number(by), + box by.annotate(UBitwidth::B32), ), - (_, e2) => unreachable!(format!( - "non-constant shift {} detected during static analysis", - e2 - )), } } UExpressionInner::Xor(box e1, box e2) => match ( - self.fold_uint_expression(e1).into_inner(), - self.fold_uint_expression(e2).into_inner(), + self.fold_uint_expression(e1)?.into_inner(), + self.fold_uint_expression(e2)?.into_inner(), ) { (UExpressionInner::Value(v1), UExpressionInner::Value(v2)) => { UExpressionInner::Value(v1 ^ v2) @@ -693,8 +841,8 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> { } }, UExpressionInner::And(box e1, box e2) => match ( - self.fold_uint_expression(e1).into_inner(), - self.fold_uint_expression(e2).into_inner(), + self.fold_uint_expression(e1)?.into_inner(), + self.fold_uint_expression(e2)?.into_inner(), ) { (UExpressionInner::Value(v1), UExpressionInner::Value(v2)) => { UExpressionInner::Value(v1 & v2) @@ -707,84 +855,113 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> { } }, UExpressionInner::IfElse(box condition, box consequence, box alternative) => { - let consequence = self.fold_uint_expression(consequence); - let alternative = self.fold_uint_expression(alternative); - match self.fold_boolean_expression(condition) { + let consequence = self.fold_uint_expression(consequence)?; + let alternative = self.fold_uint_expression(alternative)?; + match self.fold_boolean_expression(condition)? { BooleanExpression::Value(true) => consequence.into_inner(), BooleanExpression::Value(false) => alternative.into_inner(), c => UExpressionInner::IfElse(box c, box consequence, box alternative), } } UExpressionInner::Not(box e) => { - let e = self.fold_uint_expression(e).into_inner(); + let e = self.fold_uint_expression(e)?.into_inner(); match e { - UExpressionInner::Value(v) => UExpressionInner::Value((!v) & 0xffffffff), + UExpressionInner::Value(v) => { + UExpressionInner::Value((!v) & (2_u128.pow(bitwidth as u32) - 1)) + } e => UExpressionInner::Not(box e.annotate(bitwidth)), } } + UExpressionInner::Neg(box e) => { + let e = self.fold_uint_expression(e)?.into_inner(); + match e { + UExpressionInner::Value(v) => UExpressionInner::Value( + (0u128.wrapping_sub(v)) + % 2_u128.pow(bitwidth.to_usize().try_into().unwrap()), + ), + e => UExpressionInner::Neg(box e.annotate(bitwidth)), + } + } + UExpressionInner::Pos(box e) => { + let e = self.fold_uint_expression(e)?.into_inner(); + match e { + UExpressionInner::Value(v) => UExpressionInner::Value(v), + e => UExpressionInner::Pos(box e.annotate(bitwidth)), + } + } UExpressionInner::Select(box array, box index) => { - let array = self.fold_array_expression(array); - let index = self.fold_field_expression(index); + let array = self.fold_array_expression(array)?; + let index = self.fold_uint_expression(index)?; let inner_type = array.inner_type().clone(); let size = array.size(); - match (array.into_inner(), index) { - (ArrayExpressionInner::Value(v), FieldElementExpression::Number(n)) => { - let n_as_usize = n.to_dec_string().parse::().unwrap(); - if n_as_usize < size { - UExpression::try_from(v[n_as_usize].clone()) - .unwrap() - .into_inner() - } else { - unreachable!( - "out of bounds index ({} >= {}) found during static analysis", - n_as_usize, size - ); - } - } - (ArrayExpressionInner::Identifier(id), FieldElementExpression::Number(n)) => { - match self.constants.get(&id) { - Some(a) => match a { - TypedExpression::Array(a) => match a.as_inner() { - ArrayExpressionInner::Value(v) => UExpression::try_from( - v[n.to_dec_string().parse::().unwrap()].clone(), + match size.into_inner() { + UExpressionInner::Value(size) => { + match (array.into_inner(), index.into_inner()) { + (ArrayExpressionInner::Value(v), UExpressionInner::Value(n)) => { + if n < size { + UExpression::try_from( + v.expression_at::>(n as usize) + .unwrap() + .clone(), ) .unwrap() - .into_inner(), - _ => unreachable!(), - }, - _ => unreachable!(""), - }, - None => UExpressionInner::Select( - box ArrayExpressionInner::Identifier(id).annotate(inner_type, size), - box FieldElementExpression::Number(n), + .into_inner() + } else { + unreachable!( + "out of bounds index ({} >= {}) found during static analysis", + n, size + ); + } + } + (ArrayExpressionInner::Identifier(id), UExpressionInner::Value(n)) => { + match self.constants.get(&id) { + Some(a) => match a { + TypedExpression::Array(a) => match a.as_inner() { + ArrayExpressionInner::Value(v) => { + UExpression::try_from( + TypedExpression::try_from( + v.0[n as usize].clone(), + ) + .unwrap(), + ) + .unwrap() + .into_inner() + } + _ => unreachable!(), + }, + _ => unreachable!(""), + }, + None => UExpressionInner::Select( + box ArrayExpressionInner::Identifier(id) + .annotate(inner_type, size as u32), + box UExpressionInner::Value(n).annotate(UBitwidth::B32), + ), + } + } + (a, i) => UExpressionInner::Select( + box a.annotate(inner_type, size as u32), + box i.annotate(UBitwidth::B32), ), } } - (a, i) => UExpressionInner::Select(box a.annotate(inner_type, size), box i), + _ => fold_uint_expression_inner( + self, + bitwidth, + UExpressionInner::Select(box array, box index), + )?, } } - UExpressionInner::FunctionCall(key, arguments) => { - assert!( - self.verbose, - "function calls should only exist out of multidef in verbose mode" - ); - fold_uint_expression_inner( - self, - bitwidth, - UExpressionInner::FunctionCall(key, arguments), - ) - } - e => fold_uint_expression_inner(self, bitwidth, e), - } + e => fold_uint_expression_inner(self, bitwidth, e)?, + }) } fn fold_field_expression( &mut self, e: FieldElementExpression<'ast, T>, - ) -> FieldElementExpression<'ast, T> { - match e { + ) -> Result, Error> { + Ok(match e { FieldElementExpression::Identifier(id) => match self.constants.get(&id) { Some(e) => match e { TypedExpression::FieldElement(e) => e.clone(), @@ -795,8 +972,8 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> { None => FieldElementExpression::Identifier(id), }, FieldElementExpression::Add(box e1, box e2) => match ( - self.fold_field_expression(e1), - self.fold_field_expression(e2), + self.fold_field_expression(e1)?, + self.fold_field_expression(e2)?, ) { (FieldElementExpression::Number(n1), FieldElementExpression::Number(n2)) => { FieldElementExpression::Number(n1 + n2) @@ -804,8 +981,8 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> { (e1, e2) => FieldElementExpression::Add(box e1, box e2), }, FieldElementExpression::Sub(box e1, box e2) => match ( - self.fold_field_expression(e1), - self.fold_field_expression(e2), + self.fold_field_expression(e1)?, + self.fold_field_expression(e2)?, ) { (FieldElementExpression::Number(n1), FieldElementExpression::Number(n2)) => { FieldElementExpression::Number(n1 - n2) @@ -813,8 +990,8 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> { (e1, e2) => FieldElementExpression::Sub(box e1, box e2), }, FieldElementExpression::Mult(box e1, box e2) => match ( - self.fold_field_expression(e1), - self.fold_field_expression(e2), + self.fold_field_expression(e1)?, + self.fold_field_expression(e2)?, ) { (FieldElementExpression::Number(n1), FieldElementExpression::Number(n2)) => { FieldElementExpression::Number(n1 * n2) @@ -822,88 +999,116 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> { (e1, e2) => FieldElementExpression::Mult(box e1, box e2), }, FieldElementExpression::Div(box e1, box e2) => match ( - self.fold_field_expression(e1), - self.fold_field_expression(e2), + self.fold_field_expression(e1)?, + self.fold_field_expression(e2)?, ) { (FieldElementExpression::Number(n1), FieldElementExpression::Number(n2)) => { FieldElementExpression::Number(n1 / n2) } (e1, e2) => FieldElementExpression::Div(box e1, box e2), }, + FieldElementExpression::Neg(box e) => match self.fold_field_expression(e)? { + FieldElementExpression::Number(n) => FieldElementExpression::Number(T::zero() - n), + e => FieldElementExpression::Neg(box e), + }, + FieldElementExpression::Pos(box e) => match self.fold_field_expression(e)? { + FieldElementExpression::Number(n) => FieldElementExpression::Number(n), + e => FieldElementExpression::Pos(box e), + }, FieldElementExpression::Pow(box e1, box e2) => { - let e1 = self.fold_field_expression(e1); - let e2 = self.fold_field_expression(e2); - match (e1, e2) { - (_, FieldElementExpression::Number(ref n2)) if *n2 == T::from(0) => { + let e1 = self.fold_field_expression(e1)?; + let e2 = self.fold_uint_expression(e2)?; + match (e1, e2.into_inner()) { + (_, UExpressionInner::Value(ref n2)) if *n2 == 0 => { FieldElementExpression::Number(T::from(1)) } - (FieldElementExpression::Number(n1), FieldElementExpression::Number(n2)) => { - FieldElementExpression::Number(n1.pow(n2)) - } - (e1, FieldElementExpression::Number(n2)) => { - FieldElementExpression::Pow(box e1, box FieldElementExpression::Number(n2)) + (FieldElementExpression::Number(n1), UExpressionInner::Value(n2)) => { + FieldElementExpression::Number(n1.pow(n2 as usize)) } + (e1, UExpressionInner::Value(n2)) => FieldElementExpression::Pow( + box e1, + box UExpressionInner::Value(n2).annotate(UBitwidth::B32), + ), (_, e2) => unreachable!(format!( "non-constant exponent {} detected during static analysis", - e2 + e2.annotate(UBitwidth::B32) )), } } FieldElementExpression::IfElse(box condition, box consequence, box alternative) => { - let consequence = self.fold_field_expression(consequence); - let alternative = self.fold_field_expression(alternative); - match self.fold_boolean_expression(condition) { + let consequence = self.fold_field_expression(consequence)?; + let alternative = self.fold_field_expression(alternative)?; + match self.fold_boolean_expression(condition)? { BooleanExpression::Value(true) => consequence, BooleanExpression::Value(false) => alternative, c => FieldElementExpression::IfElse(box c, box consequence, box alternative), } } FieldElementExpression::Select(box array, box index) => { - let array = self.fold_array_expression(array); - let index = self.fold_field_expression(index); + let array = self.fold_array_expression(array)?; + let index = self.fold_uint_expression(index)?; let inner_type = array.inner_type().clone(); let size = array.size(); - match (array.into_inner(), index) { - (ArrayExpressionInner::Value(v), FieldElementExpression::Number(n)) => { - let n_as_usize = n.to_dec_string().parse::().unwrap(); - if n_as_usize < size { - FieldElementExpression::try_from(v[n_as_usize].clone()).unwrap() - } else { - unreachable!( - "out of bounds index ({} >= {}) found during static analysis", - n_as_usize, size - ); - } - } - (ArrayExpressionInner::Identifier(id), FieldElementExpression::Number(n)) => { - match self.constants.get(&id) { - Some(a) => match a { - TypedExpression::Array(a) => match a.as_inner() { - ArrayExpressionInner::Value(v) => { - FieldElementExpression::try_from( - v[n.to_dec_string().parse::().unwrap()].clone(), + match size.into_inner() { + UExpressionInner::Value(size) => { + match (array.into_inner(), index.into_inner()) { + (ArrayExpressionInner::Value(v), UExpressionInner::Value(n)) => { + if n < size { + FieldElementExpression::try_from( + v.expression_at::>( + n as usize, ) .unwrap() - } - _ => unreachable!(), - }, - _ => unreachable!(""), - }, - None => FieldElementExpression::Select( - box ArrayExpressionInner::Identifier(id).annotate(inner_type, size), - box FieldElementExpression::Number(n), + .clone(), + ) + .unwrap() + } else { + unreachable!( + "out of bounds index ({} >= {}) found during static analysis", + n, size + ); + } + } + (ArrayExpressionInner::Identifier(id), UExpressionInner::Value(n)) => { + match self.constants.get(&id) { + Some(a) => match a { + TypedExpression::Array(a) => match a.as_inner() { + ArrayExpressionInner::Value(v) => { + FieldElementExpression::try_from( + TypedExpression::try_from( + v.0[n as usize].clone(), + ) + .unwrap(), + ) + .unwrap() + } + _ => unreachable!(), + }, + _ => unreachable!(""), + }, + None => FieldElementExpression::Select( + box ArrayExpressionInner::Identifier(id) + .annotate(inner_type, size as u32), + box UExpressionInner::Value(n).annotate(UBitwidth::B32), + ), + } + } + (a, i) => FieldElementExpression::Select( + box a.annotate(inner_type, size as u32), + box i.annotate(UBitwidth::B32), ), } } - (a, i) => { - FieldElementExpression::Select(box a.annotate(inner_type, size), box i) - } + _ => fold_field_expression( + self, + FieldElementExpression::Select(box array, box index), + )?, } } FieldElementExpression::Member(box s, m) => { - let s = self.fold_struct_expression(s); + let s = self.fold_struct_expression(s)?; let members = match s.get_type() { Type::Struct(members) => members, @@ -926,24 +1131,16 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> { inner => FieldElementExpression::Member(box inner.annotate(members), m), } } - FieldElementExpression::FunctionCall(key, inputs) => { - assert!( - self.verbose, - "function calls should only exist out of multidef in verbose mode" - ); - fold_field_expression(self, FieldElementExpression::FunctionCall(key, inputs)) - } - e => fold_field_expression(self, e), - } + e => fold_field_expression(self, e)?, + }) } fn fold_array_expression_inner( &mut self, - ty: &Type, - size: usize, + ty: &ArrayType<'ast, T>, e: ArrayExpressionInner<'ast, T>, - ) -> ArrayExpressionInner<'ast, T> { - match e { + ) -> Result, Error> { + Ok(match e { ArrayExpressionInner::Identifier(id) => match self.constants.get(&id) { Some(e) => match e { TypedExpression::Array(e) => e.as_inner().clone(), @@ -952,71 +1149,92 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> { None => ArrayExpressionInner::Identifier(id), }, ArrayExpressionInner::Select(box array, box index) => { - let array = self.fold_array_expression(array); - let index = self.fold_field_expression(index); + let array = self.fold_array_expression(array)?; + let index = self.fold_uint_expression(index)?; let inner_type = array.inner_type().clone(); let size = array.size(); - match (array.into_inner(), index) { - (ArrayExpressionInner::Value(v), FieldElementExpression::Number(n)) => { - let n_as_usize = n.to_dec_string().parse::().unwrap(); - if n_as_usize < size { - ArrayExpression::try_from(v[n_as_usize].clone()) + match size.into_inner() { + UExpressionInner::Value(size) => match (array.into_inner(), index.into_inner()) + { + (ArrayExpressionInner::Value(v), UExpressionInner::Value(n)) => { + if n < size { + ArrayExpression::try_from( + v.expression_at::>(n as usize) + .unwrap() + .clone(), + ) .unwrap() .into_inner() - } else { - unreachable!( - "out of bounds index ({} >= {}) found during static analysis", - n_as_usize, size - ); + } else { + unreachable!( + "out of bounds index ({} >= {}) found during static analysis", + n, size + ); + } } - } - (ArrayExpressionInner::Identifier(id), FieldElementExpression::Number(n)) => { - match self.constants.get(&id) { - Some(a) => match a { - TypedExpression::Array(a) => match a.as_inner() { - ArrayExpressionInner::Value(v) => ArrayExpression::try_from( - v[n.to_dec_string().parse::().unwrap()].clone(), - ) - .unwrap() - .into_inner(), - _ => unreachable!(), + (ArrayExpressionInner::Identifier(id), UExpressionInner::Value(n)) => { + match self.constants.get(&id) { + Some(a) => match a { + TypedExpression::Array(a) => match a.as_inner() { + ArrayExpressionInner::Value(v) => { + ArrayExpression::try_from( + v.expression_at::>( + n as usize, + ) + .unwrap() + .clone(), + ) + .unwrap() + .into_inner() + } + _ => unreachable!(), + }, + _ => unreachable!(""), }, - _ => unreachable!(""), - }, - None => ArrayExpressionInner::Select( - box ArrayExpressionInner::Identifier(id).annotate(inner_type, size), - box FieldElementExpression::Number(n), - ), + None => ArrayExpressionInner::Select( + box ArrayExpressionInner::Identifier(id) + .annotate(inner_type, size as u32), + box UExpressionInner::Value(n).annotate(UBitwidth::B32), + ), + } } - } - (a, i) => ArrayExpressionInner::Select(box a.annotate(inner_type, size), box i), + (a, i) => ArrayExpressionInner::Select( + box a.annotate(inner_type, size as u32), + box i.annotate(UBitwidth::B32), + ), + }, + _ => fold_array_expression_inner( + self, + ty, + ArrayExpressionInner::Select(box array, box index), + )?, } } ArrayExpressionInner::IfElse(box condition, box consequence, box alternative) => { - let consequence = self.fold_array_expression(consequence); - let alternative = self.fold_array_expression(alternative); - match self.fold_boolean_expression(condition) { + let consequence = self.fold_array_expression(consequence)?; + let alternative = self.fold_array_expression(alternative)?; + match self.fold_boolean_expression(condition)? { BooleanExpression::Value(true) => consequence.into_inner(), BooleanExpression::Value(false) => alternative.into_inner(), c => ArrayExpressionInner::IfElse(box c, box consequence, box alternative), } } - ArrayExpressionInner::Member(box s, m) => { - let s = self.fold_struct_expression(s); + ArrayExpressionInner::Member(box struc, id) => { + let struc = self.fold_struct_expression(struc)?; - let members = match s.get_type() { + let members = match struc.get_type() { Type::Struct(members) => members, _ => unreachable!("should be a struct"), }; - match s.into_inner() { + match struc.into_inner() { StructExpressionInner::Value(v) => { match members .iter() .zip(v) - .find(|(member, _)| member.id == m) + .find(|(member, _)| member.id == id) .unwrap() .1 { @@ -1024,31 +1242,19 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> { _ => unreachable!("should be an array"), } } - inner => ArrayExpressionInner::Member(box inner.annotate(members), m), + inner => ArrayExpressionInner::Member(box inner.annotate(members), id), } } - ArrayExpressionInner::FunctionCall(key, inputs) => { - assert!( - self.verbose, - "function calls should only exist out of multidef in verbose mode" - ); - fold_array_expression_inner( - self, - ty, - size, - ArrayExpressionInner::FunctionCall(key, inputs), - ) - } - e => fold_array_expression_inner(self, ty, size, e), - } + e => fold_array_expression_inner(self, ty, e)?, + }) } fn fold_struct_expression_inner( &mut self, - ty: &StructType, + ty: &StructType<'ast, T>, e: StructExpressionInner<'ast, T>, - ) -> StructExpressionInner<'ast, T> { - match e { + ) -> Result, Error> { + Ok(match e { StructExpressionInner::Identifier(id) => match self.constants.get(&id) { Some(e) => match e { TypedExpression::Struct(e) => e.as_inner().clone(), @@ -1057,61 +1263,80 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> { None => StructExpressionInner::Identifier(id), }, StructExpressionInner::Select(box array, box index) => { - let array = self.fold_array_expression(array); - let index = self.fold_field_expression(index); + let array = self.fold_array_expression(array)?; + let index = self.fold_uint_expression(index)?; let inner_type = array.inner_type().clone(); let size = array.size(); - match (array.into_inner(), index) { - (ArrayExpressionInner::Value(v), FieldElementExpression::Number(n)) => { - let n_as_usize = n.to_dec_string().parse::().unwrap(); - if n_as_usize < size { - StructExpression::try_from(v[n_as_usize].clone()) + match size.into_inner() { + UExpressionInner::Value(size) => match (array.into_inner(), index.into_inner()) + { + (ArrayExpressionInner::Value(v), UExpressionInner::Value(n)) => { + if n < size { + StructExpression::try_from( + v.expression_at::>(n as usize) + .unwrap() + .clone(), + ) .unwrap() .into_inner() - } else { - unreachable!( - "out of bounds index ({} >= {}) found during static analysis", - n_as_usize, size - ); + } else { + unreachable!( + "out of bounds index ({} >= {}) found during static analysis", + n, size + ); + } } - } - (ArrayExpressionInner::Identifier(id), FieldElementExpression::Number(n)) => { - match self.constants.get(&id) { - Some(a) => match a { - TypedExpression::Array(a) => match a.as_inner() { - ArrayExpressionInner::Value(v) => StructExpression::try_from( - v[n.to_dec_string().parse::().unwrap()].clone(), - ) - .unwrap() - .into_inner(), - _ => unreachable!(), + (ArrayExpressionInner::Identifier(id), UExpressionInner::Value(n)) => { + match self.constants.get(&id) { + Some(a) => match a { + TypedExpression::Array(a) => match a.as_inner() { + ArrayExpressionInner::Value(v) => { + StructExpression::try_from( + v.expression_at::>( + n as usize, + ) + .unwrap() + .clone(), + ) + .unwrap() + .into_inner() + } + _ => unreachable!(), + }, + _ => unreachable!(""), }, - _ => unreachable!(""), - }, - None => StructExpressionInner::Select( - box ArrayExpressionInner::Identifier(id).annotate(inner_type, size), - box FieldElementExpression::Number(n), - ), + None => StructExpressionInner::Select( + box ArrayExpressionInner::Identifier(id) + .annotate(inner_type, size as u32), + box UExpressionInner::Value(n).annotate(UBitwidth::B32), + ), + } } - } - (a, i) => { - StructExpressionInner::Select(box a.annotate(inner_type, size), box i) - } + (a, i) => StructExpressionInner::Select( + box a.annotate(inner_type, size as u32), + box i.annotate(UBitwidth::B32), + ), + }, + _ => fold_struct_expression_inner( + self, + ty, + StructExpressionInner::Select(box array, box index), + )?, } } StructExpressionInner::IfElse(box condition, box consequence, box alternative) => { - let consequence = self.fold_struct_expression(consequence); - let alternative = self.fold_struct_expression(alternative); - match self.fold_boolean_expression(condition) { + let consequence = self.fold_struct_expression(consequence)?; + let alternative = self.fold_struct_expression(alternative)?; + match self.fold_boolean_expression(condition)? { BooleanExpression::Value(true) => consequence.into_inner(), BooleanExpression::Value(false) => alternative.into_inner(), c => StructExpressionInner::IfElse(box c, box consequence, box alternative), } } StructExpressionInner::Member(box s, m) => { - let s = self.fold_struct_expression(s); + let s = self.fold_struct_expression(s)?; let members = match s.get_type() { Type::Struct(members) => members, @@ -1134,31 +1359,20 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> { inner => StructExpressionInner::Member(box inner.annotate(members), m), } } - StructExpressionInner::FunctionCall(key, inputs) => { - assert!( - self.verbose, - "function calls should only exist out of multidef in verbose mode" - ); - fold_struct_expression_inner( - self, - ty, - StructExpressionInner::FunctionCall(key, inputs), - ) - } - e => fold_struct_expression_inner(self, ty, e), - } + e => fold_struct_expression_inner(self, ty, e)?, + }) } fn fold_boolean_expression( &mut self, e: BooleanExpression<'ast, T>, - ) -> BooleanExpression<'ast, T> { + ) -> Result, Error> { // Note: we only propagate when we see constants, as comparing of arbitrary expressions would lead to // a lot of false negatives due to expressions not being in a canonical form // For example, `2 * a` is equivalent to `a + a`, but our notion of equality would not detect that here // 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 { + Ok(match e { BooleanExpression::Identifier(id) => match self.constants.get(&id) { Some(e) => match e { TypedExpression::Boolean(e) => e.clone(), @@ -1167,8 +1381,8 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> { None => BooleanExpression::Identifier(id), }, BooleanExpression::FieldEq(box e1, box e2) => { - let e1 = self.fold_field_expression(e1); - let e2 = self.fold_field_expression(e2); + let e1 = self.fold_field_expression(e1)?; + let e2 = self.fold_field_expression(e2)?; match (e1, e2) { (FieldElementExpression::Number(n1), FieldElementExpression::Number(n2)) => { @@ -1177,9 +1391,20 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> { (e1, e2) => BooleanExpression::FieldEq(box e1, box e2), } } + BooleanExpression::UintEq(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)) => { + BooleanExpression::Value(n1 == n2) + } + _ => BooleanExpression::UintEq(box e1, box e2), + } + } BooleanExpression::BoolEq(box e1, box e2) => { - let e1 = self.fold_boolean_expression(e1); - let e2 = self.fold_boolean_expression(e2); + let e1 = self.fold_boolean_expression(e1)?; + let e2 = self.fold_boolean_expression(e2)?; match (e1, e2) { (BooleanExpression::Value(n1), BooleanExpression::Value(n2)) => { @@ -1188,53 +1413,115 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> { (e1, e2) => BooleanExpression::BoolEq(box e1, box e2), } } - BooleanExpression::Lt(box e1, box e2) => { - let e1 = self.fold_field_expression(e1); - let e2 = self.fold_field_expression(e2); + BooleanExpression::ArrayEq(box e1, box e2) => { + let e1 = self.fold_array_expression(e1)?; + let e2 = self.fold_array_expression(e2)?; + + if let (Ok(t1), Ok(t2)) = ( + ConcreteType::try_from(e1.get_type()), + ConcreteType::try_from(e2.get_type()), + ) { + if t1 != t2 { + return Err(Error::Type(format!( + "Cannot compare {} of type {} to {} of type {}", + e1, t1, e2, t2 + ))); + } + }; + + BooleanExpression::ArrayEq(box e1, box e2) + } + 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)) => { BooleanExpression::Value(n1 < n2) } - (e1, e2) => BooleanExpression::Lt(box e1, box e2), + (e1, e2) => BooleanExpression::FieldLt(box e1, box e2), } } - BooleanExpression::Le(box e1, box e2) => { - let e1 = self.fold_field_expression(e1); - let e2 = self.fold_field_expression(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)) => { BooleanExpression::Value(n1 <= n2) } - (e1, e2) => BooleanExpression::Le(box e1, box e2), + (e1, e2) => BooleanExpression::FieldLe(box e1, box e2), } } - BooleanExpression::Gt(box e1, box e2) => { - let e1 = self.fold_field_expression(e1); - let e2 = self.fold_field_expression(e2); + BooleanExpression::FieldGt(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)) => { BooleanExpression::Value(n1 > n2) } - (e1, e2) => BooleanExpression::Gt(box e1, box e2), + (e1, e2) => BooleanExpression::FieldGt(box e1, box e2), } } - BooleanExpression::Ge(box e1, box e2) => { - let e1 = self.fold_field_expression(e1); - let e2 = self.fold_field_expression(e2); + BooleanExpression::FieldGe(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)) => { BooleanExpression::Value(n1 >= n2) } - (e1, e2) => BooleanExpression::Ge(box e1, box e2), + (e1, e2) => 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)) => { + BooleanExpression::Value(n1 < n2) + } + _ => BooleanExpression::UintLt(box e1, box e2), + } + } + BooleanExpression::UintLe(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)) => { + BooleanExpression::Value(n1 <= n2) + } + _ => BooleanExpression::UintLe(box e1, box e2), + } + } + BooleanExpression::UintGt(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)) => { + BooleanExpression::Value(n1 > n2) + } + _ => BooleanExpression::UintGt(box e1, box 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)) => { + BooleanExpression::Value(n1 >= n2) + } + _ => 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); + let e1 = self.fold_boolean_expression(e1)?; + let e2 = self.fold_boolean_expression(e2)?; match (e1, e2) { // reduction of constants @@ -1253,8 +1540,8 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> { } } BooleanExpression::And(box e1, box e2) => { - let e1 = self.fold_boolean_expression(e1); - let e2 = self.fold_boolean_expression(e2); + let e1 = self.fold_boolean_expression(e1)?; + let e2 = self.fold_boolean_expression(e2)?; match (e1, e2) { // reduction of constants @@ -1271,63 +1558,81 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> { } } BooleanExpression::Not(box e) => { - let e = self.fold_boolean_expression(e); + let e = self.fold_boolean_expression(e)?; match e { BooleanExpression::Value(v) => BooleanExpression::Value(!v), e => BooleanExpression::Not(box e), } } BooleanExpression::IfElse(box condition, box consequence, box alternative) => { - let consequence = self.fold_boolean_expression(consequence); - let alternative = self.fold_boolean_expression(alternative); - match self.fold_boolean_expression(condition) { + let consequence = self.fold_boolean_expression(consequence)?; + let alternative = self.fold_boolean_expression(alternative)?; + match self.fold_boolean_expression(condition)? { BooleanExpression::Value(true) => consequence, BooleanExpression::Value(false) => alternative, c => BooleanExpression::IfElse(box c, box consequence, box alternative), } } BooleanExpression::Select(box array, box index) => { - let array = self.fold_array_expression(array); - let index = self.fold_field_expression(index); + let array = self.fold_array_expression(array)?; + let index = self.fold_uint_expression(index)?; let inner_type = array.inner_type().clone(); let size = array.size(); - match (array.into_inner(), index) { - (ArrayExpressionInner::Value(v), FieldElementExpression::Number(n)) => { - let n_as_usize = n.to_dec_string().parse::().unwrap(); - if n_as_usize < size { - BooleanExpression::try_from(v[n_as_usize].clone()).unwrap() - } else { - unreachable!( - "out of bounds index ({} >= {}) found during static analysis", - n_as_usize, size - ); + match size.into_inner() { + UExpressionInner::Value(size) => match (array.into_inner(), index.into_inner()) + { + (ArrayExpressionInner::Value(v), UExpressionInner::Value(n)) => { + if n < size { + BooleanExpression::try_from( + v.expression_at::>(n as usize) + .unwrap() + .clone(), + ) + .unwrap() + } else { + unreachable!( + "out of bounds index ({} >= {}) found during static analysis", + n, size + ); + } } - } - (ArrayExpressionInner::Identifier(id), FieldElementExpression::Number(n)) => { - match self.constants.get(&id) { - Some(a) => match a { - TypedExpression::Array(a) => match a.as_inner() { - ArrayExpressionInner::Value(v) => BooleanExpression::try_from( - v[n.to_dec_string().parse::().unwrap()].clone(), - ) - .unwrap(), - _ => unreachable!(), + (ArrayExpressionInner::Identifier(id), UExpressionInner::Value(n)) => { + match self.constants.get(&id) { + Some(a) => match a { + TypedExpression::Array(a) => match a.as_inner() { + ArrayExpressionInner::Value(v) => { + BooleanExpression::try_from( + TypedExpression::try_from(v.0[n as usize].clone()) + .unwrap(), + ) + .unwrap() + } + _ => unreachable!(), + }, + _ => unreachable!(""), }, - _ => unreachable!(""), - }, - None => BooleanExpression::Select( - box ArrayExpressionInner::Identifier(id).annotate(inner_type, size), - box FieldElementExpression::Number(n), - ), + None => BooleanExpression::Select( + box ArrayExpressionInner::Identifier(id) + .annotate(inner_type, size as u32), + box UExpressionInner::Value(n).annotate(UBitwidth::B32), + ), + } } - } - (a, i) => BooleanExpression::Select(box a.annotate(inner_type, size), box i), + (a, i) => BooleanExpression::Select( + box a.annotate(inner_type, size as u32), + box i.annotate(UBitwidth::B32), + ), + }, + _ => fold_boolean_expression( + self, + BooleanExpression::Select(box array, box index), + )?, } } BooleanExpression::Member(box s, m) => { - let s = self.fold_struct_expression(s); + let s = self.fold_struct_expression(s)?; let members = match s.get_type() { Type::Struct(members) => members, @@ -1350,15 +1655,8 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> { inner => BooleanExpression::Member(box inner.annotate(members), m), } } - BooleanExpression::FunctionCall(key, inputs) => { - assert!( - self.verbose, - "function calls should only exist out of multidef in verbose mode" - ); - fold_boolean_expression(self, BooleanExpression::FunctionCall(key, inputs)) - } - e => fold_boolean_expression(self, e), - } + e => fold_boolean_expression(self, e)?, + }) } } @@ -1383,8 +1681,8 @@ mod tests { ); assert_eq!( - Propagator::new().fold_field_expression(e), - FieldElementExpression::Number(Bn128Field::from(5)) + Propagator::with_constants(&mut Constants::new()).fold_field_expression(e), + Ok(FieldElementExpression::Number(Bn128Field::from(5))) ); } @@ -1396,8 +1694,8 @@ mod tests { ); assert_eq!( - Propagator::new().fold_field_expression(e), - FieldElementExpression::Number(Bn128Field::from(1)) + Propagator::with_constants(&mut Constants::new()).fold_field_expression(e), + Ok(FieldElementExpression::Number(Bn128Field::from(1))) ); } @@ -1409,8 +1707,8 @@ mod tests { ); assert_eq!( - Propagator::new().fold_field_expression(e), - FieldElementExpression::Number(Bn128Field::from(6)) + Propagator::with_constants(&mut Constants::new()).fold_field_expression(e), + Ok(FieldElementExpression::Number(Bn128Field::from(6))) ); } @@ -1422,8 +1720,8 @@ mod tests { ); assert_eq!( - Propagator::new().fold_field_expression(e), - FieldElementExpression::Number(Bn128Field::from(3)) + Propagator::with_constants(&mut Constants::new()).fold_field_expression(e), + Ok(FieldElementExpression::Number(Bn128Field::from(3))) ); } @@ -1431,12 +1729,12 @@ mod tests { fn pow() { let e = FieldElementExpression::Pow( box FieldElementExpression::Number(Bn128Field::from(2)), - box FieldElementExpression::Number(Bn128Field::from(3)), + box 3u32.into(), ); assert_eq!( - Propagator::new().fold_field_expression(e), - FieldElementExpression::Number(Bn128Field::from(8)) + Propagator::with_constants(&mut Constants::new()).fold_field_expression(e), + Ok(FieldElementExpression::Number(Bn128Field::from(8))) ); } @@ -1449,8 +1747,8 @@ mod tests { ); assert_eq!( - Propagator::new().fold_field_expression(e), - FieldElementExpression::Number(Bn128Field::from(2)) + Propagator::with_constants(&mut Constants::new()).fold_field_expression(e), + Ok(FieldElementExpression::Number(Bn128Field::from(2))) ); } @@ -1463,29 +1761,30 @@ mod tests { ); assert_eq!( - Propagator::new().fold_field_expression(e), - FieldElementExpression::Number(Bn128Field::from(3)) + Propagator::with_constants(&mut Constants::new()).fold_field_expression(e), + Ok(FieldElementExpression::Number(Bn128Field::from(3))) ); } #[test] fn select() { let e = FieldElementExpression::Select( - box ArrayExpressionInner::Value(vec![ - FieldElementExpression::Number(Bn128Field::from(1)).into(), - FieldElementExpression::Number(Bn128Field::from(2)).into(), - FieldElementExpression::Number(Bn128Field::from(3)).into(), - ]) - .annotate(Type::FieldElement, 3), - box FieldElementExpression::Add( - box FieldElementExpression::Number(Bn128Field::from(1)), - box FieldElementExpression::Number(Bn128Field::from(1)), - ), + box 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, 3usize), + box UExpressionInner::Add(box 1u32.into(), box 1u32.into()) + .annotate(UBitwidth::B32), ); assert_eq!( - Propagator::new().fold_field_expression(e), - FieldElementExpression::Number(Bn128Field::from(3)) + Propagator::with_constants(&mut Constants::new()).fold_field_expression(e), + Ok(FieldElementExpression::Number(Bn128Field::from(3))) ); } } @@ -1506,16 +1805,19 @@ mod tests { BooleanExpression::Not(box BooleanExpression::Identifier("a".into())); assert_eq!( - Propagator::new().fold_boolean_expression(e_true), - BooleanExpression::Value(true) + Propagator::with_constants(&mut Constants::new()) + .fold_boolean_expression(e_true), + Ok(BooleanExpression::Value(true)) ); assert_eq!( - Propagator::new().fold_boolean_expression(e_false), - BooleanExpression::Value(false) + Propagator::with_constants(&mut Constants::new()) + .fold_boolean_expression(e_false), + Ok(BooleanExpression::Value(false)) ); assert_eq!( - Propagator::new().fold_boolean_expression(e_default.clone()), - e_default + Propagator::with_constants(&mut Constants::new()) + .fold_boolean_expression(e_default.clone()), + Ok(e_default) ); } @@ -1532,143 +1834,149 @@ mod tests { ); assert_eq!( - Propagator::new().fold_boolean_expression(e_true), - BooleanExpression::Value(true) + Propagator::with_constants(&mut Constants::new()) + .fold_boolean_expression(e_true), + Ok(BooleanExpression::Value(true)) ); assert_eq!( - Propagator::new().fold_boolean_expression(e_false), - BooleanExpression::Value(false) + Propagator::with_constants(&mut Constants::new()) + .fold_boolean_expression(e_false), + Ok(BooleanExpression::Value(false)) ); } #[test] fn bool_eq() { assert_eq!( - Propagator::::new().fold_boolean_expression( - BooleanExpression::BoolEq( + Propagator::::with_constants(&mut Constants::new()) + .fold_boolean_expression(BooleanExpression::BoolEq( box BooleanExpression::Value(false), box BooleanExpression::Value(false) - ) - ), - BooleanExpression::Value(true) + )), + Ok(BooleanExpression::Value(true)) ); assert_eq!( - Propagator::::new().fold_boolean_expression( - BooleanExpression::BoolEq( + Propagator::::with_constants(&mut Constants::new()) + .fold_boolean_expression(BooleanExpression::BoolEq( box BooleanExpression::Value(true), box BooleanExpression::Value(true) - ) - ), - BooleanExpression::Value(true) + )), + Ok(BooleanExpression::Value(true)) ); assert_eq!( - Propagator::::new().fold_boolean_expression( - BooleanExpression::BoolEq( + Propagator::::with_constants(&mut Constants::new()) + .fold_boolean_expression(BooleanExpression::BoolEq( box BooleanExpression::Value(true), box BooleanExpression::Value(false) - ) - ), - BooleanExpression::Value(false) + )), + Ok(BooleanExpression::Value(false)) ); assert_eq!( - Propagator::::new().fold_boolean_expression( - BooleanExpression::BoolEq( + Propagator::::with_constants(&mut Constants::new()) + .fold_boolean_expression(BooleanExpression::BoolEq( box BooleanExpression::Value(false), box BooleanExpression::Value(true) - ) - ), - BooleanExpression::Value(false) + )), + Ok(BooleanExpression::Value(false)) ); } #[test] fn lt() { - let e_true = BooleanExpression::Lt( + let e_true = BooleanExpression::FieldLt( box FieldElementExpression::Number(Bn128Field::from(2)), box FieldElementExpression::Number(Bn128Field::from(4)), ); - let e_false = BooleanExpression::Lt( + let e_false = BooleanExpression::FieldLt( box FieldElementExpression::Number(Bn128Field::from(4)), box FieldElementExpression::Number(Bn128Field::from(2)), ); assert_eq!( - Propagator::new().fold_boolean_expression(e_true), - BooleanExpression::Value(true) + Propagator::with_constants(&mut Constants::new()) + .fold_boolean_expression(e_true), + Ok(BooleanExpression::Value(true)) ); assert_eq!( - Propagator::new().fold_boolean_expression(e_false), - BooleanExpression::Value(false) + Propagator::with_constants(&mut Constants::new()) + .fold_boolean_expression(e_false), + Ok(BooleanExpression::Value(false)) ); } #[test] fn le() { - let e_true = BooleanExpression::Le( + let e_true = BooleanExpression::FieldLe( box FieldElementExpression::Number(Bn128Field::from(2)), box FieldElementExpression::Number(Bn128Field::from(2)), ); - let e_false = BooleanExpression::Le( + let e_false = BooleanExpression::FieldLe( box FieldElementExpression::Number(Bn128Field::from(4)), box FieldElementExpression::Number(Bn128Field::from(2)), ); assert_eq!( - Propagator::new().fold_boolean_expression(e_true), - BooleanExpression::Value(true) + Propagator::with_constants(&mut Constants::new()) + .fold_boolean_expression(e_true), + Ok(BooleanExpression::Value(true)) ); assert_eq!( - Propagator::new().fold_boolean_expression(e_false), - BooleanExpression::Value(false) + Propagator::with_constants(&mut Constants::new()) + .fold_boolean_expression(e_false), + Ok(BooleanExpression::Value(false)) ); } #[test] fn gt() { - let e_true = BooleanExpression::Gt( + let e_true = BooleanExpression::FieldGt( box FieldElementExpression::Number(Bn128Field::from(5)), box FieldElementExpression::Number(Bn128Field::from(4)), ); - let e_false = BooleanExpression::Gt( + let e_false = BooleanExpression::FieldGt( box FieldElementExpression::Number(Bn128Field::from(4)), box FieldElementExpression::Number(Bn128Field::from(5)), ); assert_eq!( - Propagator::new().fold_boolean_expression(e_true), - BooleanExpression::Value(true) + Propagator::with_constants(&mut Constants::new()) + .fold_boolean_expression(e_true), + Ok(BooleanExpression::Value(true)) ); assert_eq!( - Propagator::new().fold_boolean_expression(e_false), - BooleanExpression::Value(false) + Propagator::with_constants(&mut Constants::new()) + .fold_boolean_expression(e_false), + Ok(BooleanExpression::Value(false)) ); } #[test] fn ge() { - let e_true = BooleanExpression::Ge( + let e_true = BooleanExpression::FieldGe( box FieldElementExpression::Number(Bn128Field::from(5)), box FieldElementExpression::Number(Bn128Field::from(5)), ); - let e_false = BooleanExpression::Ge( + let e_false = BooleanExpression::FieldGe( box FieldElementExpression::Number(Bn128Field::from(4)), box FieldElementExpression::Number(Bn128Field::from(5)), ); assert_eq!( - Propagator::new().fold_boolean_expression(e_true), - BooleanExpression::Value(true) + Propagator::with_constants(&mut Constants::new()) + .fold_boolean_expression(e_true), + Ok(BooleanExpression::Value(true)) ); assert_eq!( - Propagator::new().fold_boolean_expression(e_false), - BooleanExpression::Value(false) + Propagator::with_constants(&mut Constants::new()) + .fold_boolean_expression(e_false), + Ok(BooleanExpression::Value(false)) ); } @@ -1677,76 +1985,68 @@ mod tests { let a_bool: Identifier = "a".into(); assert_eq!( - Propagator::::new().fold_boolean_expression( - BooleanExpression::And( + Propagator::::with_constants(&mut Constants::new()) + .fold_boolean_expression(BooleanExpression::And( box BooleanExpression::Value(true), box BooleanExpression::Identifier(a_bool.clone()) - ) - ), - BooleanExpression::Identifier(a_bool.clone()) + )), + Ok(BooleanExpression::Identifier(a_bool.clone())) ); assert_eq!( - Propagator::::new().fold_boolean_expression( - BooleanExpression::And( + Propagator::::with_constants(&mut Constants::new()) + .fold_boolean_expression(BooleanExpression::And( box BooleanExpression::Identifier(a_bool.clone()), box BooleanExpression::Value(true), - ) - ), - BooleanExpression::Identifier(a_bool.clone()) + )), + Ok(BooleanExpression::Identifier(a_bool.clone())) ); assert_eq!( - Propagator::::new().fold_boolean_expression( - BooleanExpression::And( + Propagator::::with_constants(&mut Constants::new()) + .fold_boolean_expression(BooleanExpression::And( box BooleanExpression::Value(false), box BooleanExpression::Identifier(a_bool.clone()) - ) - ), - BooleanExpression::Value(false) + )), + Ok(BooleanExpression::Value(false)) ); assert_eq!( - Propagator::::new().fold_boolean_expression( - BooleanExpression::And( + Propagator::::with_constants(&mut Constants::new()) + .fold_boolean_expression(BooleanExpression::And( box BooleanExpression::Identifier(a_bool.clone()), box BooleanExpression::Value(false), - ) - ), - BooleanExpression::Value(false) + )), + Ok(BooleanExpression::Value(false)) ); assert_eq!( - Propagator::::new().fold_boolean_expression( - BooleanExpression::And( + Propagator::::with_constants(&mut Constants::new()) + .fold_boolean_expression(BooleanExpression::And( box BooleanExpression::Value(true), box BooleanExpression::Value(false), - ) - ), - BooleanExpression::Value(false) + )), + Ok(BooleanExpression::Value(false)) ); assert_eq!( - Propagator::::new().fold_boolean_expression( - BooleanExpression::And( + Propagator::::with_constants(&mut Constants::new()) + .fold_boolean_expression(BooleanExpression::And( box BooleanExpression::Value(false), box BooleanExpression::Value(true), - ) - ), - BooleanExpression::Value(false) + )), + Ok(BooleanExpression::Value(false)) ); assert_eq!( - Propagator::::new().fold_boolean_expression( - BooleanExpression::And( + Propagator::::with_constants(&mut Constants::new()) + .fold_boolean_expression(BooleanExpression::And( box BooleanExpression::Value(true), box BooleanExpression::Value(true), - ) - ), - BooleanExpression::Value(true) + )), + Ok(BooleanExpression::Value(true)) ); assert_eq!( - Propagator::::new().fold_boolean_expression( - BooleanExpression::And( + Propagator::::with_constants(&mut Constants::new()) + .fold_boolean_expression(BooleanExpression::And( box BooleanExpression::Value(false), box BooleanExpression::Value(false), - ) - ), - BooleanExpression::Value(false) + )), + Ok(BooleanExpression::Value(false)) ); } @@ -1755,60 +2055,68 @@ mod tests { let a_bool: Identifier = "a".into(); assert_eq!( - Propagator::::new().fold_boolean_expression(BooleanExpression::Or( - box BooleanExpression::Value(true), - box BooleanExpression::Identifier(a_bool.clone()) - )), - BooleanExpression::Value(true) + 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)) ); assert_eq!( - Propagator::::new().fold_boolean_expression(BooleanExpression::Or( - box BooleanExpression::Identifier(a_bool.clone()), - box BooleanExpression::Value(true), - )), - BooleanExpression::Value(true) + 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)) ); assert_eq!( - Propagator::::new().fold_boolean_expression(BooleanExpression::Or( - box BooleanExpression::Value(false), - box BooleanExpression::Identifier(a_bool.clone()) - )), - BooleanExpression::Identifier(a_bool.clone()) + Propagator::::with_constants(&mut Constants::new()) + .fold_boolean_expression(BooleanExpression::Or( + box BooleanExpression::Value(false), + box BooleanExpression::Identifier(a_bool.clone()) + )), + Ok(BooleanExpression::Identifier(a_bool.clone())) ); assert_eq!( - Propagator::::new().fold_boolean_expression(BooleanExpression::Or( - box BooleanExpression::Identifier(a_bool.clone()), - box BooleanExpression::Value(false), - )), - BooleanExpression::Identifier(a_bool.clone()) + Propagator::::with_constants(&mut Constants::new()) + .fold_boolean_expression(BooleanExpression::Or( + box BooleanExpression::Identifier(a_bool.clone()), + box BooleanExpression::Value(false), + )), + Ok(BooleanExpression::Identifier(a_bool.clone())) ); assert_eq!( - Propagator::::new().fold_boolean_expression(BooleanExpression::Or( - box BooleanExpression::Value(true), - box BooleanExpression::Value(false), - )), - BooleanExpression::Value(true) + Propagator::::with_constants(&mut Constants::new()) + .fold_boolean_expression(BooleanExpression::Or( + box BooleanExpression::Value(true), + box BooleanExpression::Value(false), + )), + Ok(BooleanExpression::Value(true)) ); assert_eq!( - Propagator::::new().fold_boolean_expression(BooleanExpression::Or( - box BooleanExpression::Value(false), - box BooleanExpression::Value(true), - )), - BooleanExpression::Value(true) + Propagator::::with_constants(&mut Constants::new()) + .fold_boolean_expression(BooleanExpression::Or( + box BooleanExpression::Value(false), + box BooleanExpression::Value(true), + )), + Ok(BooleanExpression::Value(true)) ); assert_eq!( - Propagator::::new().fold_boolean_expression(BooleanExpression::Or( - box BooleanExpression::Value(true), - box BooleanExpression::Value(true), - )), - BooleanExpression::Value(true) + Propagator::::with_constants(&mut Constants::new()) + .fold_boolean_expression(BooleanExpression::Or( + box BooleanExpression::Value(true), + box BooleanExpression::Value(true), + )), + Ok(BooleanExpression::Value(true)) ); assert_eq!( - Propagator::::new().fold_boolean_expression(BooleanExpression::Or( - box BooleanExpression::Value(false), - box BooleanExpression::Value(false), - )), - BooleanExpression::Value(false) + Propagator::::with_constants(&mut Constants::new()) + .fold_boolean_expression(BooleanExpression::Or( + box BooleanExpression::Value(false), + box BooleanExpression::Value(false), + )), + Ok(BooleanExpression::Value(false)) ); } } diff --git a/zokrates_core/src/static_analysis/redefinition.rs b/zokrates_core/src/static_analysis/redefinition.rs index dbcd8602e..f44a84503 100644 --- a/zokrates_core/src/static_analysis/redefinition.rs +++ b/zokrates_core/src/static_analysis/redefinition.rs @@ -68,6 +68,6 @@ impl<'ast, T: Field> Folder<'ast, T> for RedefinitionOptimizer<'ast> { } fn fold_name(&mut self, s: Identifier<'ast>) -> Identifier<'ast> { - self.identifiers.get(&s).map(|r| r.clone()).unwrap_or(s) + self.identifiers.get(&s).cloned().unwrap_or(s) } } diff --git a/zokrates_core/src/static_analysis/reducer/inline.rs b/zokrates_core/src/static_analysis/reducer/inline.rs new file mode 100644 index 000000000..01aff4db1 --- /dev/null +++ b/zokrates_core/src/static_analysis/reducer/inline.rs @@ -0,0 +1,235 @@ +// The inlining phase takes a call site (fun::(args)) and inlines it: + +// Given: +// ``` +// def foo(field a) -> field: +// a = a +// n = n +// return a +// ``` +// +// The call site +// ``` +// foo::<42>(x) +// ``` +// +// 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 + +// Notes: +// - The body of the function is in SSA form +// - The return value(s) are assigned to internal variables + +use crate::embed::FlatEmbed; +use crate::static_analysis::reducer::Output; +use crate::static_analysis::reducer::ShallowTransformer; +use crate::static_analysis::reducer::Versions; +use crate::typed_absy::types::ConcreteGenericsAssignment; +use crate::typed_absy::CoreIdentifier; +use crate::typed_absy::Identifier; +use crate::typed_absy::TypedAssignee; +use crate::typed_absy::{ + ConcreteFunctionKey, ConcreteSignature, ConcreteVariable, DeclarationFunctionKey, Signature, + Type, TypedExpression, TypedFunctionSymbol, TypedProgram, TypedStatement, UExpression, + UExpressionInner, Variable, +}; +use zokrates_field::Field; + +pub enum InlineError<'ast, T> { + Generic(DeclarationFunctionKey<'ast>, ConcreteFunctionKey<'ast>), + Flat( + FlatEmbed, + Vec, + Vec>, + Vec>, + ), + NonConstant( + DeclarationFunctionKey<'ast>, + Vec>>, + Vec>, + Vec>, + ), +} + +fn get_canonical_function<'ast, T: Field>( + function_key: DeclarationFunctionKey<'ast>, + program: &TypedProgram<'ast, T>, +) -> (DeclarationFunctionKey<'ast>, TypedFunctionSymbol<'ast, T>) { + match program + .modules + .get(&function_key.module) + .unwrap() + .functions + .iter() + .find(|(key, _)| function_key == **key) + .unwrap() + { + (_, TypedFunctionSymbol::There(key)) => get_canonical_function(key.clone(), &program), + (key, s) => (key.clone(), s.clone()), + } +} + +type InlineResult<'ast, T> = Result< + Output<(Vec>, Vec>), Vec>>, + InlineError<'ast, T>, +>; + +pub fn inline_call<'a, 'ast, T: Field>( + k: DeclarationFunctionKey<'ast>, + generics: Vec>>, + arguments: Vec>, + output_types: Vec>, + program: &TypedProgram<'ast, T>, + versions: &'a mut Versions<'ast>, +) -> InlineResult<'ast, T> { + use std::convert::TryFrom; + + use crate::typed_absy::Typed; + + // we try to get concrete values for explicit generics + let generics_values: Vec> = generics + .iter() + .map(|g| { + g.as_ref() + .map(|g| match g.as_inner() { + UExpressionInner::Value(v) => Ok(*v as u32), + _ => Err(()), + }) + .transpose() + }) + .collect::>() + .map_err(|_| { + InlineError::NonConstant( + k.clone(), + generics.clone(), + arguments.clone(), + output_types.clone(), + ) + })?; + + // 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()) + .inputs(arguments.iter().map(|a| a.get_type()).collect()) + .outputs(output_types.clone()); + + // we try to get concrete values for the whole signature. if this fails we should propagate again + let inferred_signature = match ConcreteSignature::try_from(inferred_signature) { + Ok(s) => s, + Err(_) => { + return Err(InlineError::NonConstant( + k, + generics, + arguments, + output_types, + )); + } + }; + + let (decl_key, symbol) = get_canonical_function(k.clone(), program); + + // get an assignment of generics for this call site + let assignment: ConcreteGenericsAssignment<'ast> = k + .signature + .specialize(generics_values, &inferred_signature) + .map_err(|_| { + InlineError::Generic( + k.clone(), + ConcreteFunctionKey { + module: decl_key.module.clone(), + id: decl_key.id, + signature: inferred_signature.clone(), + }, + ) + })?; + + let f = match symbol { + TypedFunctionSymbol::Here(f) => Ok(f), + TypedFunctionSymbol::Flat(e) => Err(InlineError::Flat( + e, + e.generics(&assignment), + arguments.clone(), + output_types, + )), + _ => unreachable!(), + }?; + + 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 + .arguments + .into_iter() + .zip(inferred_signature.inputs.clone()) + .map(|(p, t)| ConcreteVariable::with_id_and_type(p.id.id, t)) + .zip(arguments.clone()) + .map(|(v, a)| TypedStatement::Definition(TypedAssignee::Identifier(v.into()), a)) + .collect(); + + let (statements, mut returns): (Vec<_>, Vec<_>) = ssa_f + .statements + .into_iter() + .partition(|s| !matches!(s, TypedStatement::Return(..))); + + assert_eq!(returns.len(), 1); + + let returns = match returns.pop().unwrap() { + TypedStatement::Return(e) => e, + _ => unreachable!(), + }; + + let res: Vec> = inferred_signature + .outputs + .iter() + .enumerate() + .map(|(i, t)| { + ConcreteVariable::with_id_and_type( + Identifier::from(CoreIdentifier::Call(i)).version( + *versions + .entry(CoreIdentifier::Call(i).clone()) + .and_modify(|e| *e += 1) // if it was already declared, we increment + .or_insert(0), + ), + t.clone(), + ) + }) + .collect(); + + let expressions: Vec> = res + .iter() + .map(|v| TypedExpression::from(Variable::from(v.clone()))) + .collect(); + + assert_eq!(res.len(), returns.len()); + + let output_bindings: Vec> = res + .into_iter() + .zip(returns) + .map(|(v, a)| TypedStatement::Definition(TypedAssignee::Identifier(v.into()), a)) + .collect(); + + let pop_log = TypedStatement::PopCallLog; + + let statements: Vec<_> = std::iter::once(call_log) + .chain(input_bindings) + .chain(statements) + .chain(output_bindings) + .chain(std::iter::once(pop_log)) + .collect(); + + Ok(incomplete_data + .map(|d| Output::Incomplete((statements.clone(), expressions.clone()), d)) + .unwrap_or_else(|| Output::Complete((statements, expressions)))) +} diff --git a/zokrates_core/src/static_analysis/reducer/mod.rs b/zokrates_core/src/static_analysis/reducer/mod.rs new file mode 100644 index 000000000..db5704dc6 --- /dev/null +++ b/zokrates_core/src/static_analysis/reducer/mod.rs @@ -0,0 +1,1636 @@ +// The reducer reduces the program to a single function which is: +// - in SSA form +// - 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 + +mod inline; +mod shallow_ssa; + +use self::inline::{inline_call, InlineError}; +use crate::typed_absy::result_folder::*; +use crate::typed_absy::types::ConcreteGenericsAssignment; +use crate::typed_absy::types::GGenericsAssignment; +use crate::typed_absy::Folder; +use std::collections::HashMap; + +use crate::typed_absy::{ + ArrayExpression, ArrayExpressionInner, ArrayType, BooleanExpression, CoreIdentifier, + DeclarationFunctionKey, FieldElementExpression, FunctionCall, Identifier, StructExpression, + StructExpressionInner, Type, Typed, TypedExpression, TypedExpressionList, TypedFunction, + TypedFunctionSymbol, TypedModule, TypedProgram, TypedStatement, UExpression, UExpressionInner, + Variable, +}; + +use std::convert::{TryFrom, TryInto}; + +use zokrates_field::Field; + +use self::shallow_ssa::ShallowTransformer; + +use crate::static_analysis::Propagator; + +use std::fmt; + +// 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)] +pub enum Output { + Complete(U), + Incomplete(U, V), +} + +#[derive(Debug, Clone, PartialEq)] +pub enum Error { + Incompatible(String), + GenericsInMain, + // TODO: give more details about what's blocking the progress + NoProgress, +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Error::Incompatible(s) => write!( + f, + "{}", + 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") + } + } +} + +#[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 + } + }, + } + } + + 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).clone().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)); + } +} + +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, +} + +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(); + + Reducer { + statement_buffer: vec![], + for_loop_versions_after: vec![], + for_loop_versions, + substitutions, + program, + versions, + complete: true, + } + } + + fn fold_function_call( + &mut self, + key: DeclarationFunctionKey<'ast>, + generics: Vec>>, + arguments: Vec>, + output_types: Vec>, + ) -> Result + where + E: FunctionCall<'ast, T> + TryFrom, Error = ()> + std::fmt::Debug, + { + let generics = generics + .into_iter() + .map(|g| g.map(|g| self.fold_uint_expression(g)).transpose()) + .collect::>()?; + + let arguments = arguments + .into_iter() + .map(|e| self.fold_expression(e)) + .collect::>()?; + + let res = inline_call( + key.clone(), + generics, + arguments, + output_types, + &self.program, + &mut self.versions, + ); + + match res { + Ok(Output::Complete((statements, expressions))) => { + self.complete &= true; + self.statement_buffer.extend(statements); + Ok(expressions[0].clone().try_into().unwrap()) + } + Ok(Output::Incomplete((statements, expressions), delta_for_loop_versions)) => { + self.complete = false; + self.statement_buffer.extend(statements); + self.for_loop_versions_after.extend(delta_for_loop_versions); + Ok(expressions[0].clone().try_into().unwrap()) + } + Err(InlineError::Generic(decl, conc)) => Err(Error::Incompatible(format!( + "Call site `{}` incompatible with declaration `{}`", + conc.to_string(), + decl.to_string() + ))), + Err(InlineError::NonConstant(key, generics, arguments, mut output_types)) => { + self.complete = false; + + Ok(E::function_call( + key, + generics, + arguments, + output_types.pop().unwrap(), + )) + } + Err(InlineError::Flat(embed, generics, arguments, output_types)) => { + let identifier = Identifier::from(CoreIdentifier::Call(0)).version( + *self + .versions + .entry(CoreIdentifier::Call(0).clone()) + .and_modify(|e| *e += 1) // if it was already declared, we increment + .or_insert(0), + ); + let var = Variable::with_id_and_type(identifier, output_types[0].clone()); + + let v = vec![var.clone().into()]; + + self.statement_buffer + .push(TypedStatement::MultipleDefinition( + v, + TypedExpressionList::EmbedCall(embed, generics, arguments, output_types), + )); + Ok(TypedExpression::from(var).try_into().unwrap()) + } + } + } +} + +impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Reducer<'ast, 'a, T> { + type Error = Error; + + fn fold_statement( + &mut self, + s: TypedStatement<'ast, T>, + ) -> Result>, Self::Error> { + let res = match s { + TypedStatement::MultipleDefinition( + v, + TypedExpressionList::FunctionCall(key, generics, arguments, output_types), + ) => { + let generics = generics + .into_iter() + .map(|g| g.map(|g| self.fold_uint_expression(g)).transpose()) + .collect::>()?; + + let arguments = arguments + .into_iter() + .map(|a| self.fold_expression(a)) + .collect::>()?; + + match inline_call( + key, + generics, + arguments, + output_types, + &self.program, + &mut self.versions, + ) { + Ok(Output::Complete((statements, expressions))) => { + assert_eq!(v.len(), expressions.len()); + + self.complete &= true; + + Ok(statements + .into_iter() + .chain( + v.into_iter() + .zip(expressions) + .map(|(v, e)| TypedStatement::Definition(v, e)), + ) + .collect()) + } + Ok(Output::Incomplete((statements, expressions), delta_for_loop_versions)) => { + assert_eq!(v.len(), expressions.len()); + + self.complete = false; + self.for_loop_versions_after.extend(delta_for_loop_versions); + + Ok(statements + .into_iter() + .chain( + v.into_iter() + .zip(expressions) + .map(|(v, e)| TypedStatement::Definition(v, e)), + ) + .collect()) + } + Err(InlineError::Generic(decl, conc)) => Err(Error::Incompatible(format!( + "Call site `{}` incompatible with declaration `{}`", + conc.to_string(), + decl.to_string() + ))), + Err(InlineError::NonConstant(key, generics, arguments, output_types)) => { + self.complete = false; + + Ok(vec![TypedStatement::MultipleDefinition( + v, + TypedExpressionList::FunctionCall( + key, + generics, + arguments, + output_types, + ), + )]) + } + Err(InlineError::Flat(embed, generics, arguments, output_types)) => { + Ok(vec![TypedStatement::MultipleDefinition( + v, + TypedExpressionList::EmbedCall( + embed, + generics, + arguments, + output_types, + ), + )]) + } + } + } + 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(&mut self.substitutions, &self.versions, &versions_before); + + // the versions after the loop are found by applying an offset of 2 to the versions before the loop + let versions_after = versions_before + .clone() + .into_iter() + .map(|(k, v)| (k, v + 2)) + .collect(); + + let mut transformer = ShallowTransformer::with_versions(&mut self.versions); + + 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()) + .map(|s| transformer.fold_statement(s)) + .flatten() + .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(&mut 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); + + // if the ssa transform got blocked, the reduction is not complete + self.complete &= !blocked; + + 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)]) + } + } + } + s => fold_statement(self, s), + }; + + res.map(|res| self.statement_buffer.drain(..).chain(res).collect()) + } + + fn fold_boolean_expression( + &mut self, + e: BooleanExpression<'ast, T>, + ) -> Result, Self::Error> { + match e { + BooleanExpression::FunctionCall(key, generics, arguments) => { + self.fold_function_call(key, generics, arguments, vec![Type::Boolean]) + } + e => fold_boolean_expression(self, e), + } + } + + fn fold_uint_expression( + &mut self, + e: UExpression<'ast, T>, + ) -> Result, Self::Error> { + match e.as_inner() { + UExpressionInner::FunctionCall(key, generics, arguments) => self.fold_function_call( + key.clone(), + generics.clone(), + arguments.clone(), + vec![e.get_type()], + ), + _ => fold_uint_expression(self, e), + } + } + + fn fold_field_expression( + &mut self, + e: FieldElementExpression<'ast, T>, + ) -> Result, Self::Error> { + match e { + FieldElementExpression::FunctionCall(key, generic, arguments) => { + self.fold_function_call(key, generic, arguments, vec![Type::FieldElement]) + } + e => fold_field_expression(self, e), + } + } + + fn fold_array_expression_inner( + &mut self, + ty: &ArrayType<'ast, T>, + e: ArrayExpressionInner<'ast, T>, + ) -> Result, Self::Error> { + match e { + ArrayExpressionInner::FunctionCall(key, generics, arguments) => self + .fold_function_call::>( + key.clone(), + generics, + arguments.clone(), + vec![Type::array(ty.clone())], + ) + .map(|e| e.into_inner()), + 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, &ty, e), + } + } + + fn fold_struct_expression( + &mut self, + e: StructExpression<'ast, T>, + ) -> Result, Self::Error> { + match e.as_inner() { + StructExpressionInner::FunctionCall(key, generics, arguments) => self + .fold_function_call( + key.clone(), + generics.clone(), + arguments.clone(), + vec![e.get_type()], + ), + _ => fold_struct_expression(self, e), + } + } +} + +pub fn reduce_program(p: TypedProgram) -> Result, Error> { + let main_module = p.modules.get(&p.main).unwrap().clone(); + + let (main_key, main_function) = main_module + .functions + .iter() + .find(|(k, _)| k.id == "main") + .unwrap(); + + let main_function = match main_function { + TypedFunctionSymbol::Here(f) => f.clone(), + _ => unreachable!(), + }; + + match main_function.signature.generics.len() { + 0 => { + let main_function = reduce_function(main_function, GGenericsAssignment::default(), &p)?; + + Ok(TypedProgram { + main: p.main.clone(), + modules: vec![( + p.main.clone(), + TypedModule { + functions: vec![( + main_key.clone(), + TypedFunctionSymbol::Here(main_function), + )] + .into_iter() + .collect(), + }, + )] + .into_iter() + .collect(), + }) + } + _ => Err(Error::GenericsInMain), + } +} + +fn reduce_function<'ast, T: Field>( + f: TypedFunction<'ast, T>, + generics: ConcreteGenericsAssignment<'ast>, + program: &TypedProgram<'ast, T>, +) -> Result, Error> { + let mut versions = Versions::default(); + + 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 constants: HashMap, TypedExpression<'ast, T>> = HashMap::new(); + + 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); + + let new_f = Propagator::with_constants(&mut constants) + .fold_function(new_f) + .map_err(|e| match e { + crate::static_analysis::propagation::Error::Type(e) => { + Error::Incompatible(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| match e { + crate::static_analysis::propagation::Error::Type(e) => { + Error::Incompatible(e) + } + })?; + + let new_hash = Some(compute_hash(&f)); + + if new_hash == hash { + break Err(Error::NoProgress); + } else { + hash = new_hash + } + } + } + } + } + } +} + +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() +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::typed_absy::types::Constant; + use crate::typed_absy::types::DeclarationSignature; + use crate::typed_absy::{ + ArrayExpressionInner, DeclarationFunctionKey, DeclarationType, DeclarationVariable, + FieldElementExpression, Identifier, OwnedTypedModuleId, Select, Type, TypedExpression, + TypedExpressionList, TypedExpressionOrSpread, UBitwidth, UExpressionInner, Variable, + }; + use zokrates_field::Bn128Field; + + use lazy_static::lazy_static; + + lazy_static! { + static ref MAIN_MODULE_ID: OwnedTypedModuleId = OwnedTypedModuleId::from("main"); + } + + #[test] + fn no_generics() { + // def foo(field a) -> field: + // return a + // def main(field a) -> field: + // u32 n = 42 + // n = n + // a = a + // a = foo(a) + // n = n + // return a + + // 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 + + let foo: TypedFunction = TypedFunction { + arguments: vec![DeclarationVariable::field_element("a").into()], + statements: vec![TypedStatement::Return(vec![ + FieldElementExpression::Identifier("a".into()).into(), + ])], + signature: DeclarationSignature::new() + .inputs(vec![DeclarationType::FieldElement]) + .outputs(vec![DeclarationType::FieldElement]), + }; + + let main: TypedFunction = TypedFunction { + arguments: vec![DeclarationVariable::field_element("a").into()], + statements: vec![ + TypedStatement::Definition( + Variable::uint("n", UBitwidth::B32).into(), + TypedExpression::Uint(42u32.into()), + ), + TypedStatement::Definition( + Variable::uint("n", UBitwidth::B32).into(), + UExpressionInner::Identifier("n".into()) + .annotate(UBitwidth::B32) + .into(), + ), + TypedStatement::Definition( + Variable::field_element("a").into(), + FieldElementExpression::Identifier("a".into()).into(), + ), + TypedStatement::MultipleDefinition( + vec![Variable::field_element("a").into()], + TypedExpressionList::FunctionCall( + DeclarationFunctionKey::with_location("main", "foo").signature( + DeclarationSignature::new() + .inputs(vec![DeclarationType::FieldElement]) + .outputs(vec![DeclarationType::FieldElement]), + ), + vec![], + vec![FieldElementExpression::Identifier("a".into()).into()], + vec![Type::FieldElement], + ), + ), + TypedStatement::Definition( + Variable::uint("n", UBitwidth::B32).into(), + UExpressionInner::Identifier("n".into()) + .annotate(UBitwidth::B32) + .into(), + ), + TypedStatement::Return(vec![FieldElementExpression::Identifier("a".into()).into()]), + ], + signature: DeclarationSignature::new() + .inputs(vec![DeclarationType::FieldElement]) + .outputs(vec![DeclarationType::FieldElement]), + }; + + let p = TypedProgram { + main: "main".into(), + modules: vec![( + "main".into(), + TypedModule { + functions: vec![ + ( + DeclarationFunctionKey::with_location("main", "foo").signature( + DeclarationSignature::new() + .inputs(vec![DeclarationType::FieldElement]) + .outputs(vec![DeclarationType::FieldElement]), + ), + TypedFunctionSymbol::Here(foo), + ), + ( + DeclarationFunctionKey::with_location("main", "main").signature( + DeclarationSignature::new() + .inputs(vec![DeclarationType::FieldElement]) + .outputs(vec![DeclarationType::FieldElement]), + ), + TypedFunctionSymbol::Here(main), + ), + ] + .into_iter() + .collect(), + }, + )] + .into_iter() + .collect(), + }; + + let reduced = reduce_program(p); + + let expected_main = TypedFunction { + arguments: vec![DeclarationVariable::field_element("a").into()], + statements: vec![ + TypedStatement::Definition( + 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]) + .outputs(vec![DeclarationType::FieldElement]), + ), + GGenericsAssignment::default(), + ), + TypedStatement::Definition( + Variable::field_element(Identifier::from("a").version(3)).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(), + ), + TypedStatement::Return(vec![FieldElementExpression::Identifier( + Identifier::from("a").version(2), + ) + .into()]), + ], + signature: DeclarationSignature::new() + .inputs(vec![DeclarationType::FieldElement]) + .outputs(vec![DeclarationType::FieldElement]), + }; + + let expected: TypedProgram = TypedProgram { + main: "main".into(), + modules: vec![( + "main".into(), + TypedModule { + functions: vec![( + DeclarationFunctionKey::with_location("main", "main").signature( + DeclarationSignature::new() + .inputs(vec![DeclarationType::FieldElement]) + .outputs(vec![DeclarationType::FieldElement]), + ), + TypedFunctionSymbol::Here(expected_main), + )] + .into_iter() + .collect(), + }, + )] + .into_iter() + .collect(), + }; + + assert_eq!(reduced.unwrap(), expected); + } + + #[test] + fn with_generics() { + // def foo(field[K] a) -> field[K]: + // return a + // def main(field a) -> field: + // u32 n = 42 + // n = n + // field[1] b = [a] + // b = foo(b) + // n = n + // return a + b[0] + + // 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] + + let foo_signature = DeclarationSignature::new() + .generics(vec![Some("K".into())]) + .inputs(vec![DeclarationType::array(( + DeclarationType::FieldElement, + Constant::Generic("K"), + ))]) + .outputs(vec![DeclarationType::array(( + DeclarationType::FieldElement, + Constant::Generic("K"), + ))]); + + let foo: TypedFunction = TypedFunction { + arguments: vec![ + DeclarationVariable::array("a", DeclarationType::FieldElement, "K").into(), + ], + statements: vec![TypedStatement::Return(vec![ + ArrayExpressionInner::Identifier("a".into()) + .annotate(Type::FieldElement, 1u32) + .into(), + ])], + signature: foo_signature.clone(), + }; + + let main: TypedFunction = TypedFunction { + arguments: vec![DeclarationVariable::field_element("a").into()], + statements: vec![ + TypedStatement::Definition( + Variable::uint("n", UBitwidth::B32).into(), + TypedExpression::Uint(42u32.into()), + ), + TypedStatement::Definition( + Variable::uint("n", UBitwidth::B32).into(), + UExpressionInner::Identifier("n".into()) + .annotate(UBitwidth::B32) + .into(), + ), + TypedStatement::Definition( + Variable::array("b", Type::FieldElement, 1u32).into(), + ArrayExpressionInner::Value( + vec![FieldElementExpression::Identifier("a".into()).into()].into(), + ) + .annotate(Type::FieldElement, 1u32) + .into(), + ), + TypedStatement::MultipleDefinition( + vec![Variable::array("b", Type::FieldElement, 1u32).into()], + TypedExpressionList::FunctionCall( + DeclarationFunctionKey::with_location("main", "foo") + .signature(foo_signature.clone()), + vec![None], + vec![ArrayExpressionInner::Identifier("b".into()) + .annotate(Type::FieldElement, 1u32) + .into()], + vec![Type::array((Type::FieldElement, 1u32))], + ), + ), + TypedStatement::Definition( + Variable::uint("n", UBitwidth::B32).into(), + UExpressionInner::Identifier("n".into()) + .annotate(UBitwidth::B32) + .into(), + ), + TypedStatement::Return(vec![(FieldElementExpression::Identifier("a".into()) + + FieldElementExpression::select( + ArrayExpressionInner::Identifier("b".into()) + .annotate(Type::FieldElement, 1u32), + 0u32, + )) + .into()]), + ], + signature: DeclarationSignature::new() + .inputs(vec![DeclarationType::FieldElement]) + .outputs(vec![DeclarationType::FieldElement]), + }; + + let p = TypedProgram { + main: "main".into(), + modules: vec![( + "main".into(), + TypedModule { + functions: vec![ + ( + DeclarationFunctionKey::with_location("main", "foo") + .signature(foo_signature.clone()), + TypedFunctionSymbol::Here(foo), + ), + ( + DeclarationFunctionKey::with_location("main", "main").signature( + DeclarationSignature::new() + .inputs(vec![DeclarationType::FieldElement]) + .outputs(vec![DeclarationType::FieldElement]), + ), + TypedFunctionSymbol::Here(main), + ), + ] + .into_iter() + .collect(), + }, + )] + .into_iter() + .collect(), + }; + + let reduced = reduce_program(p); + + let expected_main = TypedFunction { + arguments: vec![DeclarationVariable::field_element("a").into()], + statements: vec![ + TypedStatement::Definition( + Variable::array("b", Type::FieldElement, 1u32).into(), + ArrayExpressionInner::Value( + vec![FieldElementExpression::Identifier("a".into()).into()].into(), + ) + .annotate(Type::FieldElement, 1u32) + .into(), + ), + TypedStatement::PushCallLog( + DeclarationFunctionKey::with_location("main", "foo") + .signature(foo_signature.clone()), + GGenericsAssignment(vec![("K", 1)].into_iter().collect()), + ), + TypedStatement::Definition( + Variable::array(Identifier::from("a").version(1), Type::FieldElement, 1u32) + .into(), + ArrayExpressionInner::Identifier("b".into()) + .annotate(Type::FieldElement, 1u32) + .into(), + ), + TypedStatement::Definition( + Variable::array( + Identifier::from(CoreIdentifier::Call(0)).version(0), + Type::FieldElement, + 1u32, + ) + .into(), + ArrayExpressionInner::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(), + ArrayExpressionInner::Identifier( + Identifier::from(CoreIdentifier::Call(0)).version(0), + ) + .annotate(Type::FieldElement, 1u32) + .into(), + ), + TypedStatement::Return(vec![(FieldElementExpression::Identifier("a".into()) + + FieldElementExpression::select( + ArrayExpressionInner::Identifier(Identifier::from("b").version(1)) + .annotate(Type::FieldElement, 1u32), + 0u32, + )) + .into()]), + ], + signature: DeclarationSignature::new() + .inputs(vec![DeclarationType::FieldElement]) + .outputs(vec![DeclarationType::FieldElement]), + }; + + let expected = TypedProgram { + main: "main".into(), + modules: vec![( + "main".into(), + TypedModule { + functions: vec![( + DeclarationFunctionKey::with_location("main", "main").signature( + DeclarationSignature::new() + .inputs(vec![DeclarationType::FieldElement]) + .outputs(vec![DeclarationType::FieldElement]), + ), + TypedFunctionSymbol::Here(expected_main), + )] + .into_iter() + .collect(), + }, + )] + .into_iter() + .collect(), + }; + + assert_eq!(reduced.unwrap(), expected); + } + + #[test] + fn with_generics_and_propagation() { + // def foo(field[K] a) -> field[K]: + // return a + // def main(field a) -> field: + // u32 n = 2 + // n = n + // field[n - 1] b = [a] + // b = foo(b) + // n = n + // return a + b[0] + + // 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] + + let foo_signature = DeclarationSignature::new() + .generics(vec![Some("K".into())]) + .inputs(vec![DeclarationType::array(( + DeclarationType::FieldElement, + Constant::Generic("K"), + ))]) + .outputs(vec![DeclarationType::array(( + DeclarationType::FieldElement, + Constant::Generic("K"), + ))]); + + let foo: TypedFunction = TypedFunction { + arguments: vec![ + DeclarationVariable::array("a", DeclarationType::FieldElement, "K").into(), + ], + statements: vec![TypedStatement::Return(vec![ + ArrayExpressionInner::Identifier("a".into()) + .annotate(Type::FieldElement, 1u32) + .into(), + ])], + signature: foo_signature.clone(), + }; + + let main: TypedFunction = TypedFunction { + arguments: vec![DeclarationVariable::field_element("a").into()], + statements: vec![ + TypedStatement::Definition( + Variable::uint("n", UBitwidth::B32).into(), + TypedExpression::Uint(2u32.into()), + ), + TypedStatement::Definition( + Variable::uint("n", UBitwidth::B32).into(), + UExpressionInner::Identifier("n".into()) + .annotate(UBitwidth::B32) + .into(), + ), + TypedStatement::Definition( + Variable::array( + "b", + Type::FieldElement, + UExpressionInner::Sub( + box UExpressionInner::Identifier("n".into()).annotate(UBitwidth::B32), + box 1u32.into(), + ) + .annotate(UBitwidth::B32), + ) + .into(), + ArrayExpressionInner::Value( + vec![FieldElementExpression::Identifier("a".into()).into()].into(), + ) + .annotate(Type::FieldElement, 1u32) + .into(), + ), + TypedStatement::MultipleDefinition( + vec![Variable::array("b", Type::FieldElement, 1u32).into()], + TypedExpressionList::FunctionCall( + DeclarationFunctionKey::with_location("main", "foo") + .signature(foo_signature.clone()), + vec![None], + vec![ArrayExpressionInner::Identifier("b".into()) + .annotate(Type::FieldElement, 1u32) + .into()], + vec![Type::array((Type::FieldElement, 1u32))], + ), + ), + TypedStatement::Definition( + Variable::uint("n", UBitwidth::B32).into(), + UExpressionInner::Identifier("n".into()) + .annotate(UBitwidth::B32) + .into(), + ), + TypedStatement::Return(vec![(FieldElementExpression::Identifier("a".into()) + + FieldElementExpression::select( + ArrayExpressionInner::Identifier("b".into()) + .annotate(Type::FieldElement, 1u32), + 0u32, + )) + .into()]), + ], + signature: DeclarationSignature::new() + .inputs(vec![DeclarationType::FieldElement]) + .outputs(vec![DeclarationType::FieldElement]), + }; + + let p = TypedProgram { + main: "main".into(), + modules: vec![( + "main".into(), + TypedModule { + functions: vec![ + ( + DeclarationFunctionKey::with_location("main", "foo") + .signature(foo_signature.clone()), + TypedFunctionSymbol::Here(foo), + ), + ( + DeclarationFunctionKey::with_location("main", "main").signature( + DeclarationSignature::new() + .inputs(vec![DeclarationType::FieldElement]) + .outputs(vec![DeclarationType::FieldElement]), + ), + TypedFunctionSymbol::Here(main), + ), + ] + .into_iter() + .collect(), + }, + )] + .into_iter() + .collect(), + }; + + let reduced = reduce_program(p); + + let expected_main = TypedFunction { + arguments: vec![DeclarationVariable::field_element("a").into()], + statements: vec![ + TypedStatement::Definition( + Variable::array("b", Type::FieldElement, 1u32).into(), + ArrayExpressionInner::Value( + vec![FieldElementExpression::Identifier("a".into()).into()].into(), + ) + .annotate(Type::FieldElement, 1u32) + .into(), + ), + TypedStatement::PushCallLog( + DeclarationFunctionKey::with_location("main", "foo") + .signature(foo_signature.clone()), + GGenericsAssignment(vec![("K", 1)].into_iter().collect()), + ), + TypedStatement::Definition( + Variable::array(Identifier::from("a").version(1), Type::FieldElement, 1u32) + .into(), + ArrayExpressionInner::Identifier("b".into()) + .annotate(Type::FieldElement, 1u32) + .into(), + ), + TypedStatement::Definition( + Variable::array( + Identifier::from(CoreIdentifier::Call(0)).version(0), + Type::FieldElement, + 1u32, + ) + .into(), + ArrayExpressionInner::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(), + ArrayExpressionInner::Identifier( + Identifier::from(CoreIdentifier::Call(0)).version(0), + ) + .annotate(Type::FieldElement, 1u32) + .into(), + ), + TypedStatement::Return(vec![(FieldElementExpression::Identifier("a".into()) + + FieldElementExpression::select( + ArrayExpressionInner::Identifier(Identifier::from("b").version(1)) + .annotate(Type::FieldElement, 1u32), + 0u32, + )) + .into()]), + ], + signature: DeclarationSignature::new() + .inputs(vec![DeclarationType::FieldElement]) + .outputs(vec![DeclarationType::FieldElement]), + }; + + let expected = TypedProgram { + main: "main".into(), + modules: vec![( + "main".into(), + TypedModule { + functions: vec![( + DeclarationFunctionKey::with_location("main", "main").signature( + DeclarationSignature::new() + .inputs(vec![DeclarationType::FieldElement]) + .outputs(vec![DeclarationType::FieldElement]), + ), + TypedFunctionSymbol::Here(expected_main), + )] + .into_iter() + .collect(), + }, + )] + .into_iter() + .collect(), + }; + + assert_eq!(reduced.unwrap(), expected); + } + + #[test] + fn call_in_call() { + // we use a global ssa counter, hence reusing variable names in called functions + // leads to counter increase + + // def bar(field[K] a) -> field[K]: + // return a + + // def foo(field[K] a) -> field[K]: + // field[K] ret = bar([...a, 0])[0..K] + // return ret + + // def main(): + // field[1] b = foo([1]) + // return + + // expected: + // def main(): + // # PUSH CALL to foo::<1> + // # PUSH CALL to bar::<2> + // field[2] a_1 = [...[1]], 0] + // field[2] #RET_0_1 = a_1 + // # POP CALL + // field[1] ret := #RET_0_1[0..1] + // field[1] #RET_0 = ret + // # POP CALL + // field[1] b_0 := #RET_0 + // return + + let foo_signature = DeclarationSignature::new() + .inputs(vec![DeclarationType::array(( + DeclarationType::FieldElement, + Constant::Generic("K"), + ))]) + .outputs(vec![DeclarationType::array(( + DeclarationType::FieldElement, + Constant::Generic("K"), + ))]) + .generics(vec![Some("K".into())]); + + let foo: TypedFunction = TypedFunction { + arguments: vec![DeclarationVariable::array( + "a", + DeclarationType::FieldElement, + Constant::Generic("K"), + ) + .into()], + statements: vec![ + TypedStatement::Definition( + Variable::array( + "ret", + Type::FieldElement, + UExpressionInner::Identifier("K".into()).annotate(UBitwidth::B32), + ) + .into(), + ArrayExpressionInner::Slice( + box ArrayExpressionInner::FunctionCall( + DeclarationFunctionKey::with_location("main", "bar") + .signature(foo_signature.clone()), + vec![None], + vec![ArrayExpressionInner::Value( + vec![ + TypedExpressionOrSpread::Spread( + ArrayExpressionInner::Identifier("a".into()) + .annotate(Type::FieldElement, 1u32) + .into(), + ), + FieldElementExpression::Number(Bn128Field::from(0)).into(), + ] + .into(), + ) + .annotate( + Type::FieldElement, + UExpressionInner::Identifier("K".into()).annotate(UBitwidth::B32) + + 1u32.into(), + ) + .into()], + ) + .annotate( + Type::FieldElement, + UExpressionInner::Identifier("K".into()).annotate(UBitwidth::B32) + + 1u32.into(), + ), + box 0u32.into(), + box UExpressionInner::Identifier("K".into()).annotate(UBitwidth::B32), + ) + .annotate( + Type::FieldElement, + UExpressionInner::Identifier("K".into()).annotate(UBitwidth::B32), + ) + .into(), + ), + TypedStatement::Return(vec![ArrayExpressionInner::Identifier("ret".into()) + .annotate( + Type::FieldElement, + UExpressionInner::Identifier("K".into()).annotate(UBitwidth::B32), + ) + .into()]), + ], + signature: foo_signature.clone(), + }; + + let bar_signature = foo_signature.clone(); + + let bar: TypedFunction = TypedFunction { + arguments: vec![DeclarationVariable::array( + "a", + DeclarationType::FieldElement, + Constant::Generic("K"), + ) + .into()], + statements: vec![TypedStatement::Return(vec![ + ArrayExpressionInner::Identifier("a".into()) + .annotate( + Type::FieldElement, + UExpressionInner::Identifier("K".into()).annotate(UBitwidth::B32), + ) + .into(), + ])], + signature: bar_signature.clone(), + }; + + let main: TypedFunction = TypedFunction { + arguments: vec![], + statements: vec![ + TypedStatement::MultipleDefinition( + vec![Variable::array("b", Type::FieldElement, 1u32).into()], + TypedExpressionList::FunctionCall( + DeclarationFunctionKey::with_location("main", "foo") + .signature(foo_signature.clone()), + vec![None], + vec![ArrayExpressionInner::Value( + vec![FieldElementExpression::Number(Bn128Field::from(1)).into()].into(), + ) + .annotate(Type::FieldElement, 1u32) + .into()], + vec![Type::array((Type::FieldElement, 1u32))], + ), + ), + TypedStatement::Return(vec![]), + ], + signature: DeclarationSignature::new(), + }; + + let p = TypedProgram { + main: "main".into(), + modules: vec![( + "main".into(), + TypedModule { + functions: vec![ + ( + DeclarationFunctionKey::with_location("main", "bar") + .signature(bar_signature.clone()), + TypedFunctionSymbol::Here(bar), + ), + ( + DeclarationFunctionKey::with_location("main", "foo") + .signature(foo_signature.clone()), + TypedFunctionSymbol::Here(foo), + ), + ( + DeclarationFunctionKey::with_location("main", "main"), + TypedFunctionSymbol::Here(main), + ), + ] + .into_iter() + .collect(), + }, + )] + .into_iter() + .collect(), + }; + + 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![("K", 1)].into_iter().collect()), + ), + TypedStatement::PushCallLog( + DeclarationFunctionKey::with_location("main", "bar") + .signature(foo_signature.clone()), + GGenericsAssignment(vec![("K", 2)].into_iter().collect()), + ), + TypedStatement::Definition( + Variable::array(Identifier::from("a").version(1), Type::FieldElement, 2u32) + .into(), + ArrayExpressionInner::Value( + vec![ + TypedExpressionOrSpread::Spread( + ArrayExpressionInner::Value( + vec![TypedExpressionOrSpread::Expression( + FieldElementExpression::Number(Bn128Field::from(1)).into(), + )] + .into(), + ) + .annotate(Type::FieldElement, 1u32) + .into(), + ), + FieldElementExpression::Number(Bn128Field::from(0)).into(), + ] + .into(), + ) + .annotate(Type::FieldElement, 2u32) + .into(), + ), + TypedStatement::Definition( + Variable::array( + Identifier::from(CoreIdentifier::Call(0)).version(1), + Type::FieldElement, + 2u32, + ) + .into(), + ArrayExpressionInner::Identifier(Identifier::from("a").version(1)) + .annotate(Type::FieldElement, 2u32) + .into(), + ), + TypedStatement::PopCallLog, + TypedStatement::Definition( + Variable::array("ret", Type::FieldElement, 1u32).into(), + ArrayExpressionInner::Slice( + box ArrayExpressionInner::Identifier( + Identifier::from(CoreIdentifier::Call(0)).version(1), + ) + .annotate(Type::FieldElement, 2u32), + box 0u32.into(), + box 1u32.into(), + ) + .annotate(Type::FieldElement, 1u32) + .into(), + ), + TypedStatement::Definition( + Variable::array( + Identifier::from(CoreIdentifier::Call(0)), + Type::FieldElement, + 1u32, + ) + .into(), + ArrayExpressionInner::Identifier("ret".into()) + .annotate(Type::FieldElement, 1u32) + .into(), + ), + TypedStatement::PopCallLog, + TypedStatement::Definition( + Variable::array("b", Type::FieldElement, 1u32).into(), + ArrayExpressionInner::Identifier(Identifier::from(CoreIdentifier::Call(0))) + .annotate(Type::FieldElement, 1u32) + .into(), + ), + TypedStatement::Return(vec![]), + ], + signature: DeclarationSignature::new(), + }; + + let expected = TypedProgram { + main: "main".into(), + modules: vec![( + "main".into(), + TypedModule { + functions: vec![( + DeclarationFunctionKey::with_location("main", "main") + .signature(DeclarationSignature::new()), + TypedFunctionSymbol::Here(expected_main), + )] + .into_iter() + .collect(), + }, + )] + .into_iter() + .collect(), + }; + + assert_eq!(reduced.unwrap(), expected); + } + + #[test] + fn incompatible() { + // def foo(field[K] a) -> field[K]: + // return a + // def main(): + // field[1] b = foo([]) + // return + + // expected: + // Error: Incompatible + + let foo_signature = DeclarationSignature::new() + .generics(vec![Some("K".into())]) + .inputs(vec![DeclarationType::array(( + DeclarationType::FieldElement, + Constant::Generic("K"), + ))]) + .outputs(vec![DeclarationType::array(( + DeclarationType::FieldElement, + Constant::Generic("K"), + ))]); + + let foo: TypedFunction = TypedFunction { + arguments: vec![ + DeclarationVariable::array("a", DeclarationType::FieldElement, "K").into(), + ], + statements: vec![TypedStatement::Return(vec![ + ArrayExpressionInner::Identifier("a".into()) + .annotate(Type::FieldElement, 1u32) + .into(), + ])], + signature: foo_signature.clone(), + }; + + let main: TypedFunction = TypedFunction { + arguments: vec![], + statements: vec![ + TypedStatement::MultipleDefinition( + vec![Variable::array("b", Type::FieldElement, 1u32).into()], + TypedExpressionList::FunctionCall( + DeclarationFunctionKey::with_location("main", "foo") + .signature(foo_signature.clone()), + vec![None], + vec![ArrayExpressionInner::Value(vec![].into()) + .annotate(Type::FieldElement, 0u32) + .into()], + vec![Type::array((Type::FieldElement, 1u32))], + ), + ), + TypedStatement::Return(vec![]), + ], + signature: DeclarationSignature::new().inputs(vec![]).outputs(vec![]), + }; + + let p = TypedProgram { + main: "main".into(), + modules: vec![( + "main".into(), + TypedModule { + functions: vec![ + ( + DeclarationFunctionKey::with_location("main", "foo") + .signature(foo_signature.clone()), + TypedFunctionSymbol::Here(foo), + ), + ( + DeclarationFunctionKey::with_location("main", "main").signature( + DeclarationSignature::new().inputs(vec![]).outputs(vec![]), + ), + TypedFunctionSymbol::Here(main), + ), + ] + .into_iter() + .collect(), + }, + )] + .into_iter() + .collect(), + }; + + let reduced = reduce_program(p); + + assert_eq!( + reduced, + Err(Error::Incompatible("Call site `main/foo<_>(field[0]) -> field[1]` incompatible with declaration `main/foo(field[K]) -> field[K]`".into())) + ); + } +} diff --git a/zokrates_core/src/static_analysis/reducer/shallow_ssa.rs b/zokrates_core/src/static_analysis/reducer/shallow_ssa.rs new file mode 100644 index 000000000..a40ebbfd4 --- /dev/null +++ b/zokrates_core/src/static_analysis/reducer/shallow_ssa.rs @@ -0,0 +1,1007 @@ +// 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 + +// Example: +// def main(field a) -> field: +// u32 n = 42 +// a = a + 1 +// field b = foo(a) +// for u32 i in 0..n: +// +// endfor +// return b + +// Should be turned into +// def main(field a_0) -> field: +// 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 +// endfor +// return b_3 // we leave versions b_1 and b_2 to make b accessible and modifiable inside the for-loop + +use crate::typed_absy::folder::*; +use crate::typed_absy::types::ConcreteGenericsAssignment; +use crate::typed_absy::types::Type; +use crate::typed_absy::*; + +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, +} + +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, + } + } + + // increase all versions by 2 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 += 2); + ret + } + + fn issue_next_identifier(&mut self, c_id: CoreIdentifier<'ast>) -> Identifier<'ast> { + let version = *self + .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 + + Identifier::from(c_id).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), + ..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); + + let f = unroller.fold_function(f, generics); + + match unroller.blocked { + false => Output::Complete(f), + true => Output::Incomplete(f, unroller.for_loop_backups), + } + } + + fn fold_function( + &mut self, + f: TypedFunction<'ast, T>, + generics: &ConcreteGenericsAssignment<'ast>, + ) -> TypedFunction<'ast, T> { + let mut f = f; + + f.statements = generics + .0 + .iter() + .map(|(g, v)| { + TypedStatement::Definition( + TypedAssignee::Identifier(Variable::with_id_and_type( + *g, + Type::Uint(UBitwidth::B32), + )), + UExpression::from(*v as u32).into(), + ) + }) + .chain(f.statements) + .collect(); + + for arg in &f.arguments { + let _ = self.issue_next_identifier(arg.id.id.id.clone()); + } + + fold_function(self, f) + } +} + +impl<'ast, 'a, T: Field> Folder<'ast, T> for ShallowTransformer<'ast, 'a> { + fn fold_statement(&mut self, s: TypedStatement<'ast, T>) -> Vec> { + match s { + TypedStatement::Declaration(_) => vec![], + TypedStatement::Definition(a, e) => { + let e = self.fold_expression(e); + + let a = match a { + TypedAssignee::Identifier(v) => { + let v = self.issue_next_ssa_variable(v); + TypedAssignee::Identifier(self.fold_variable(v)) + } + a => fold_assignee(self, a), + }; + + vec![TypedStatement::Definition(a, e)] + } + TypedStatement::MultipleDefinition(assignees, exprs) => { + let exprs = self.fold_expression_list(exprs); + let assignees = assignees + .into_iter() + .map(|a| match a { + TypedAssignee::Identifier(v) => { + let v = self.issue_next_ssa_variable(v); + TypedAssignee::Identifier(self.fold_variable(v)) + } + a => fold_assignee(self, a), + }) + .collect(); + + vec![TypedStatement::MultipleDefinition(assignees, exprs)] + } + 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), + } + } + + 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_field_expression( + &mut self, + e: FieldElementExpression<'ast, T>, + ) -> FieldElementExpression<'ast, T> { + if let FieldElementExpression::FunctionCall(ref k, _, _) = e { + if !k.id.starts_with('_') { + self.blocked = true; + } + } + + fold_field_expression(self, e) + } + + fn fold_boolean_expression( + &mut self, + e: BooleanExpression<'ast, T>, + ) -> BooleanExpression<'ast, T> { + if let BooleanExpression::FunctionCall(ref k, _, _) = e { + if !k.id.starts_with('_') { + self.blocked = true; + } + }; + + fold_boolean_expression(self, e) + } + + fn fold_uint_expression_inner( + &mut self, + b: UBitwidth, + e: UExpressionInner<'ast, T>, + ) -> UExpressionInner<'ast, T> { + if let UExpressionInner::FunctionCall(ref k, _, _) = e { + if !k.id.starts_with('_') { + self.blocked = true; + } + }; + + fold_uint_expression_inner(self, b, e) + } + + fn fold_array_expression_inner( + &mut self, + ty: &ArrayType<'ast, T>, + e: ArrayExpressionInner<'ast, T>, + ) -> ArrayExpressionInner<'ast, T> { + if let ArrayExpressionInner::FunctionCall(ref k, _, _) = e { + if !k.id.starts_with('_') { + self.blocked = true; + } + }; + + fold_array_expression_inner(self, ty, e) + } + + fn fold_struct_expression_inner( + &mut self, + ty: &StructType<'ast, T>, + e: StructExpressionInner<'ast, T>, + ) -> StructExpressionInner<'ast, T> { + if let StructExpressionInner::FunctionCall(ref k, _, _) = e { + if !k.id.starts_with('_') { + self.blocked = true; + } + }; + + fold_struct_expression_inner(self, ty, e) + } + + fn fold_expression_list( + &mut self, + e: TypedExpressionList<'ast, T>, + ) -> TypedExpressionList<'ast, T> { + match e { + TypedExpressionList::FunctionCall(ref k, _, _, _) => { + if !k.id.starts_with('_') { + self.blocked = true; + } + } + _ => unreachable!(), + }; + + fold_expression_list(self, e) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::typed_absy::types::DeclarationSignature; + use zokrates_field::Bn128Field; + mod normal { + use super::*; + + #[test] + fn detect_non_constant_bound() { + let loops: Vec> = vec![TypedStatement::For( + Variable::uint("i", UBitwidth::B32), + UExpressionInner::Identifier("i".into()).annotate(UBitwidth::B32), + 2u32.into(), + vec![], + )]; + + let statements = loops; + + let f = TypedFunction { + arguments: vec![], + signature: DeclarationSignature::new(), + statements, + }; + + match ShallowTransformer::transform( + f, + &ConcreteGenericsAssignment::default(), + &mut Versions::default(), + ) { + Output::Incomplete(..) => {} + _ => unreachable!(), + }; + } + + #[test] + fn definition() { + // field a + // a = 5 + // a = 6 + // a + + // should be turned into + // a_0 = 5 + // a_1 = 6 + // a_1 + + let mut versions = Versions::new(); + + let mut u = ShallowTransformer::with_versions(&mut versions); + let s: TypedStatement = + TypedStatement::Declaration(Variable::field_element("a")); + assert_eq!(u.fold_statement(s), vec![]); + + let s = TypedStatement::Definition( + TypedAssignee::Identifier(Variable::field_element("a")), + FieldElementExpression::Number(Bn128Field::from(5)).into(), + ); + assert_eq!( + u.fold_statement(s), + vec![TypedStatement::Definition( + TypedAssignee::Identifier(Variable::field_element( + Identifier::from("a").version(0) + )), + FieldElementExpression::Number(Bn128Field::from(5)).into() + )] + ); + + let s = TypedStatement::Definition( + TypedAssignee::Identifier(Variable::field_element("a")), + FieldElementExpression::Number(Bn128Field::from(6)).into(), + ); + assert_eq!( + u.fold_statement(s), + vec![TypedStatement::Definition( + TypedAssignee::Identifier(Variable::field_element( + Identifier::from("a").version(1) + )), + FieldElementExpression::Number(Bn128Field::from(6)).into() + )] + ); + + let e: FieldElementExpression = + FieldElementExpression::Identifier("a".into()); + assert_eq!( + u.fold_field_expression(e), + FieldElementExpression::Identifier(Identifier::from("a").version(1)) + ); + } + + #[test] + fn incremental_definition() { + // field a + // 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 s: TypedStatement = + TypedStatement::Declaration(Variable::field_element("a")); + assert_eq!(u.fold_statement(s), vec![]); + + let s = TypedStatement::Definition( + TypedAssignee::Identifier(Variable::field_element("a")), + FieldElementExpression::Number(Bn128Field::from(5)).into(), + ); + assert_eq!( + u.fold_statement(s), + vec![TypedStatement::Definition( + TypedAssignee::Identifier(Variable::field_element( + Identifier::from("a").version(0) + )), + FieldElementExpression::Number(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)), + ) + .into(), + ); + assert_eq!( + u.fold_statement(s), + vec![TypedStatement::Definition( + 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)) + ) + .into() + )] + ); + } + + #[test] + fn incremental_multiple_definition() { + use crate::typed_absy::types::Type; + + // field a + // a = 2 + // a = foo(a) + + // should be turned into + // a_0 = 2 + // a_1 = foo(a_0) + + let mut versions = Versions::new(); + + let mut u = ShallowTransformer::with_versions(&mut versions); + + let s: TypedStatement = + TypedStatement::Declaration(Variable::field_element("a")); + assert_eq!(u.fold_statement(s), vec![]); + + let s = TypedStatement::Definition( + TypedAssignee::Identifier(Variable::field_element("a")), + FieldElementExpression::Number(Bn128Field::from(2)).into(), + ); + assert_eq!( + u.fold_statement(s), + vec![TypedStatement::Definition( + TypedAssignee::Identifier(Variable::field_element( + Identifier::from("a").version(0) + )), + FieldElementExpression::Number(Bn128Field::from(2)).into() + )] + ); + + let s: TypedStatement = TypedStatement::MultipleDefinition( + vec![Variable::field_element("a").into()], + TypedExpressionList::FunctionCall( + DeclarationFunctionKey::with_location("main", "foo").signature( + DeclarationSignature::new() + .inputs(vec![DeclarationType::FieldElement]) + .outputs(vec![DeclarationType::FieldElement]), + ), + vec![], + vec![FieldElementExpression::Identifier("a".into()).into()], + vec![Type::FieldElement], + ), + ); + assert_eq!( + u.fold_statement(s), + vec![TypedStatement::MultipleDefinition( + vec![Variable::field_element(Identifier::from("a").version(1)).into()], + TypedExpressionList::FunctionCall( + DeclarationFunctionKey::with_location("main", "foo").signature( + DeclarationSignature::new() + .inputs(vec![DeclarationType::FieldElement]) + .outputs(vec![DeclarationType::FieldElement]) + ), + vec![], + vec![ + FieldElementExpression::Identifier(Identifier::from("a").version(0)) + .into() + ], + vec![Type::FieldElement], + ) + )] + ); + } + + #[test] + fn incremental_array_definition() { + // field[2] a = [1, 1] + // a[1] = 2 + + // should be turned into + // a_0 = [1, 1] + // a_0[1] = 2 + + let mut versions = Versions::new(); + + let mut u = ShallowTransformer::with_versions(&mut versions); + + let s: TypedStatement = + TypedStatement::Declaration(Variable::array("a", Type::FieldElement, 2u32)); + assert_eq!(u.fold_statement(s), vec![]); + + 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) + .into(), + ); + + assert_eq!( + u.fold_statement(s), + vec![TypedStatement::Definition( + TypedAssignee::Identifier(Variable::array( + Identifier::from("a").version(0), + Type::FieldElement, + 2u32 + )), + ArrayExpressionInner::Value( + vec![ + FieldElementExpression::Number(Bn128Field::from(1)).into(), + FieldElementExpression::Number(Bn128Field::from(1)).into() + ] + .into() + ) + .annotate(Type::FieldElement, 2u32) + .into() + )] + ); + + let s: TypedStatement = TypedStatement::Definition( + TypedAssignee::Select( + box TypedAssignee::Identifier(Variable::array("a", Type::FieldElement, 2u32)), + box UExpression::from(1u32), + ), + FieldElementExpression::Number(Bn128Field::from(2)).into(), + ); + + assert_eq!(u.fold_statement(s.clone()), vec![s]); + } + + #[test] + fn incremental_array_of_arrays_definition() { + // field[2][2] a = [[0, 1], [2, 3]] + // a[1] = [4, 5] + + // should be turned into + // a_0 = [[0, 1], [2, 3]] + // a_0 = [4, 5] + + let mut versions = Versions::new(); + + let mut u = ShallowTransformer::with_versions(&mut versions); + + let array_of_array_ty = Type::array((Type::array((Type::FieldElement, 2u32)), 2u32)); + + let s: TypedStatement = TypedStatement::Declaration( + Variable::with_id_and_type("a", array_of_array_ty.clone()), + ); + assert_eq!(u.fold_statement(s), vec![]); + + let s = TypedStatement::Definition( + TypedAssignee::Identifier(Variable::with_id_and_type( + "a", + array_of_array_ty.clone(), + )), + 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) + .into(), + ); + + assert_eq!( + u.fold_statement(s), + vec![TypedStatement::Definition( + TypedAssignee::Identifier(Variable::with_id_and_type( + Identifier::from("a").version(0), + array_of_array_ty.clone(), + )), + 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) + .into(), + )] + ); + + let s: TypedStatement = TypedStatement::Definition( + TypedAssignee::Select( + box TypedAssignee::Identifier(Variable::with_id_and_type( + "a", + array_of_array_ty.clone(), + )), + box UExpression::from(1u32), + ), + ArrayExpressionInner::Value( + vec![ + FieldElementExpression::Number(Bn128Field::from(4)).into(), + FieldElementExpression::Number(Bn128Field::from(5)).into(), + ] + .into(), + ) + .annotate(Type::FieldElement, 2u32) + .into(), + ); + + assert_eq!(u.fold_statement(s.clone()), vec![s]); + } + } + + mod for_loop { + use super::*; + use crate::typed_absy::types::GGenericsAssignment; + #[test] + fn treat_loop() { + // def main(field a) -> field: + // u32 n = 42 + // n = n + // a = a + // for u32 i in n..n*n: + // a = a + // endfor + // a = a + // for u32 i in n..n*n: + // a = a + // endfor + // a = a + // return a + + // When called with K := 1, 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} + // for u32 i_0 in n_0..n_0*n_0: + // a_0 = a_0 + // endfor + // a_4 = a_3 + // # versions: {n: 3, a: 4} + // for u32 i_0 in n_0..n_0*n_0: + // a_0 = a_0 + // endfor + // a_7 = a_6 + // return a_7 + // # versions: {n: 5, a: 7} + + let f: TypedFunction = TypedFunction { + arguments: vec![DeclarationVariable::field_element("a").into()], + statements: vec![ + TypedStatement::Definition( + Variable::uint("n", UBitwidth::B32).into(), + TypedExpression::Uint(42u32.into()), + ), + TypedStatement::Definition( + Variable::uint("n", UBitwidth::B32).into(), + UExpressionInner::Identifier("n".into()) + .annotate(UBitwidth::B32) + .into(), + ), + TypedStatement::Definition( + Variable::field_element("a").into(), + FieldElementExpression::Identifier("a".into()).into(), + ), + TypedStatement::For( + Variable::uint("i", UBitwidth::B32), + UExpressionInner::Identifier("n".into()).annotate(UBitwidth::B32), + UExpressionInner::Identifier("n".into()).annotate(UBitwidth::B32) + * UExpressionInner::Identifier("n".into()).annotate(UBitwidth::B32), + vec![TypedStatement::Definition( + Variable::field_element("a").into(), + FieldElementExpression::Identifier("a".into()).into(), + )], + ), + TypedStatement::Definition( + Variable::field_element("a").into(), + FieldElementExpression::Identifier("a".into()).into(), + ), + TypedStatement::For( + Variable::uint("i", UBitwidth::B32), + UExpressionInner::Identifier("n".into()).annotate(UBitwidth::B32), + UExpressionInner::Identifier("n".into()).annotate(UBitwidth::B32) + * UExpressionInner::Identifier("n".into()).annotate(UBitwidth::B32), + vec![TypedStatement::Definition( + Variable::field_element("a").into(), + FieldElementExpression::Identifier("a".into()).into(), + )], + ), + TypedStatement::Definition( + Variable::field_element("a").into(), + FieldElementExpression::Identifier("a".into()).into(), + ), + TypedStatement::Return(vec![ + FieldElementExpression::Identifier("a".into()).into() + ]), + ], + signature: DeclarationSignature::new() + .generics(vec![Some("K".into())]) + .inputs(vec![DeclarationType::FieldElement]) + .outputs(vec![DeclarationType::FieldElement]), + }; + + let mut versions = Versions::default(); + + let ssa = ShallowTransformer::transform( + f, + &GGenericsAssignment(vec![("K", 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()), + ), + TypedStatement::Definition( + Variable::uint(Identifier::from("n").version(1), UBitwidth::B32).into(), + UExpressionInner::Identifier("n".into()) + .annotate(UBitwidth::B32) + .into(), + ), + TypedStatement::Definition( + Variable::field_element(Identifier::from("a").version(1)).into(), + FieldElementExpression::Identifier("a".into()).into(), + ), + TypedStatement::For( + Variable::uint("i", UBitwidth::B32), + UExpressionInner::Identifier(Identifier::from("n").version(1)) + .annotate(UBitwidth::B32), + UExpressionInner::Identifier(Identifier::from("n").version(1)) + .annotate(UBitwidth::B32) + * UExpressionInner::Identifier(Identifier::from("n").version(1)) + .annotate(UBitwidth::B32), + vec![TypedStatement::Definition( + Variable::field_element("a").into(), + FieldElementExpression::Identifier("a".into()).into(), + )], + ), + TypedStatement::Definition( + Variable::field_element(Identifier::from("a").version(4)).into(), + FieldElementExpression::Identifier(Identifier::from("a").version(3)).into(), + ), + TypedStatement::For( + Variable::uint("i", UBitwidth::B32), + UExpressionInner::Identifier(Identifier::from("n").version(3)) + .annotate(UBitwidth::B32), + UExpressionInner::Identifier(Identifier::from("n").version(3)) + .annotate(UBitwidth::B32) + * UExpressionInner::Identifier(Identifier::from("n").version(3)) + .annotate(UBitwidth::B32), + vec![TypedStatement::Definition( + Variable::field_element("a").into(), + FieldElementExpression::Identifier("a".into()).into(), + )], + ), + TypedStatement::Definition( + Variable::field_element(Identifier::from("a").version(7)).into(), + FieldElementExpression::Identifier(Identifier::from("a").version(6)).into(), + ), + TypedStatement::Return(vec![FieldElementExpression::Identifier( + Identifier::from("a").version(7), + ) + .into()]), + ], + signature: DeclarationSignature::new() + .generics(vec![Some("K".into())]) + .inputs(vec![DeclarationType::FieldElement]) + .outputs(vec![DeclarationType::FieldElement]), + }; + + assert_eq!( + versions, + vec![("n".into(), 5), ("a".into(), 7), ("K".into(), 4)] + .into_iter() + .collect::() + ); + + let expected = Output::Incomplete( + expected, + vec![ + vec![("n".into(), 1), ("a".into(), 1), ("K".into(), 0)] + .into_iter() + .collect::(), + vec![("n".into(), 3), ("a".into(), 4), ("K".into(), 2)] + .into_iter() + .collect::(), + ], + ); + + assert_eq!(ssa, expected); + } + } + + mod function_call { + use super::*; + use crate::typed_absy::types::GGenericsAssignment; + // test that function calls are left in + #[test] + fn treat_calls() { + // def main(field a) -> field: + // u32 n = 42 + // n = n + // a = a + // a = foo::(a) + // n = n + // a = a * foo::(a) + // 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) + // return a_3 + // # versions: {n: 2, a: 3} + + let f: TypedFunction = TypedFunction { + arguments: vec![DeclarationVariable::field_element("a").into()], + statements: vec![ + TypedStatement::Definition( + Variable::uint("n", UBitwidth::B32).into(), + TypedExpression::Uint(42u32.into()), + ), + TypedStatement::Definition( + Variable::uint("n", UBitwidth::B32).into(), + UExpressionInner::Identifier("n".into()) + .annotate(UBitwidth::B32) + .into(), + ), + TypedStatement::Definition( + Variable::field_element("a").into(), + FieldElementExpression::Identifier("a".into()).into(), + ), + TypedStatement::MultipleDefinition( + vec![Variable::field_element("a").into()], + TypedExpressionList::FunctionCall( + DeclarationFunctionKey::with_location("main", "foo"), + vec![Some( + UExpressionInner::Identifier("n".into()).annotate(UBitwidth::B32), + )], + vec![FieldElementExpression::Identifier("a".into()).into()], + vec![Type::FieldElement], + ), + ), + TypedStatement::Definition( + Variable::uint("n", UBitwidth::B32).into(), + UExpressionInner::Identifier("n".into()) + .annotate(UBitwidth::B32) + .into(), + ), + TypedStatement::Definition( + Variable::field_element("a").into(), + (FieldElementExpression::Identifier("a".into()) + * FieldElementExpression::FunctionCall( + DeclarationFunctionKey::with_location("main", "foo"), + vec![Some( + UExpressionInner::Identifier("n".into()) + .annotate(UBitwidth::B32), + )], + vec![FieldElementExpression::Identifier("a".into()).into()], + )) + .into(), + ), + TypedStatement::Return(vec![ + FieldElementExpression::Identifier("a".into()).into() + ]), + ], + signature: DeclarationSignature::new() + .generics(vec![Some("K".into())]) + .inputs(vec![DeclarationType::FieldElement]) + .outputs(vec![DeclarationType::FieldElement]), + }; + + let mut versions = Versions::default(); + + let ssa = ShallowTransformer::transform( + f, + &GGenericsAssignment(vec![("K", 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()), + ), + TypedStatement::Definition( + Variable::uint(Identifier::from("n").version(1), UBitwidth::B32).into(), + UExpressionInner::Identifier("n".into()) + .annotate(UBitwidth::B32) + .into(), + ), + TypedStatement::Definition( + Variable::field_element(Identifier::from("a").version(1)).into(), + FieldElementExpression::Identifier("a".into()).into(), + ), + TypedStatement::MultipleDefinition( + vec![Variable::field_element(Identifier::from("a").version(2)).into()], + TypedExpressionList::FunctionCall( + DeclarationFunctionKey::with_location("main", "foo"), + vec![Some( + UExpressionInner::Identifier(Identifier::from("n").version(1)) + .annotate(UBitwidth::B32), + )], + vec![FieldElementExpression::Identifier( + Identifier::from("a").version(1), + ) + .into()], + vec![Type::FieldElement], + ), + ), + TypedStatement::Definition( + Variable::uint(Identifier::from("n").version(2), UBitwidth::B32).into(), + UExpressionInner::Identifier(Identifier::from("n").version(1)) + .annotate(UBitwidth::B32) + .into(), + ), + TypedStatement::Definition( + Variable::field_element(Identifier::from("a").version(3)).into(), + (FieldElementExpression::Identifier(Identifier::from("a").version(2)) + * FieldElementExpression::FunctionCall( + DeclarationFunctionKey::with_location("main", "foo"), + vec![Some( + UExpressionInner::Identifier(Identifier::from("n").version(2)) + .annotate(UBitwidth::B32), + )], + vec![FieldElementExpression::Identifier( + Identifier::from("a").version(2), + ) + .into()], + )) + .into(), + ), + TypedStatement::Return(vec![FieldElementExpression::Identifier( + Identifier::from("a").version(3), + ) + .into()]), + ], + signature: DeclarationSignature::new() + .generics(vec![Some("K".into())]) + .inputs(vec![DeclarationType::FieldElement]) + .outputs(vec![DeclarationType::FieldElement]), + }; + + assert_eq!( + versions, + vec![("n".into(), 2), ("a".into(), 3), ("K".into(), 0)] + .into_iter() + .collect::() + ); + + assert_eq!(ssa, Output::Incomplete(expected, vec![],)); + } + } +} diff --git a/zokrates_core/src/static_analysis/return_binder.rs b/zokrates_core/src/static_analysis/return_binder.rs deleted file mode 100644 index 5320a7f9e..000000000 --- a/zokrates_core/src/static_analysis/return_binder.rs +++ /dev/null @@ -1,58 +0,0 @@ -use crate::typed_absy::folder::fold_statement; -use crate::typed_absy::identifier::CoreIdentifier; -use crate::typed_absy::*; -use zokrates_field::Field; - -pub struct ReturnBinder; - -impl ReturnBinder { - pub fn bind<'ast, T: Field>(p: TypedProgram<'ast, T>) -> TypedProgram<'ast, T> { - ReturnBinder {}.fold_program(p) - } -} - -impl<'ast, T: Field> Folder<'ast, T> for ReturnBinder { - fn fold_statement(&mut self, s: TypedStatement<'ast, T>) -> Vec> { - match s { - TypedStatement::Return(exprs) => { - let ret_identifiers: Vec> = (0..exprs.len()) - .map(|i| CoreIdentifier::Internal("RETURN", i).into()) - .collect(); - - let ret_expressions: Vec> = exprs - .iter() - .zip(ret_identifiers.iter()) - .map(|(e, i)| match e.get_type() { - Type::FieldElement => FieldElementExpression::Identifier(i.clone()).into(), - Type::Boolean => BooleanExpression::Identifier(i.clone()).into(), - Type::Array(array_type) => ArrayExpressionInner::Identifier(i.clone()) - .annotate(*array_type.ty, array_type.size) - .into(), - Type::Struct(struct_type) => StructExpressionInner::Identifier(i.clone()) - .annotate(struct_type) - .into(), - Type::Uint(bitwidth) => UExpressionInner::Identifier(i.clone()) - .annotate(bitwidth) - .into(), - }) - .collect(); - - exprs - .into_iter() - .zip(ret_identifiers.iter()) - .map(|(e, i)| { - TypedStatement::Definition( - TypedAssignee::Identifier(Variable::with_id_and_type( - i.clone(), - e.get_type(), - )), - e, - ) - }) - .chain(std::iter::once(TypedStatement::Return(ret_expressions))) - .collect() - } - s => fold_statement(self, s), - } - } -} diff --git a/zokrates_core/src/static_analysis/trimmer.rs b/zokrates_core/src/static_analysis/trimmer.rs new file mode 100644 index 000000000..1db074005 --- /dev/null +++ b/zokrates_core/src/static_analysis/trimmer.rs @@ -0,0 +1,88 @@ +use crate::typed_absy::TypedModule; +use crate::typed_absy::{TypedFunctionSymbol, TypedProgram}; +use zokrates_field::Field; + +pub struct Trimmer; + +impl Trimmer { + pub fn trim<'ast, T: Field>(p: TypedProgram<'ast, T>) -> TypedProgram<'ast, T> { + let main_module_id = p.main; + + // get the main module + let main_module = p.modules.get(&main_module_id).unwrap().clone(); + + // get the main function in the main module + let (main_key, main_function) = main_module + .functions + .into_iter() + .find(|(k, _)| k.id == "main") + .unwrap() + .clone(); + + // define a function in the main module for the `unpack` embed + let unpack = crate::embed::FlatEmbed::Unpack(T::get_required_bits()); + let unpack_key = unpack.key::(); + + // define a function in the main module for the `u32_to_bits` embed + let u32_to_bits = crate::embed::FlatEmbed::U32ToBits; + let u32_to_bits_key = u32_to_bits.key::(); + + // define a function in the main module for the `u16_to_bits` embed + let u16_to_bits = crate::embed::FlatEmbed::U16ToBits; + let u16_to_bits_key = u16_to_bits.key::(); + + // define a function in the main module for the `u8_to_bits` embed + let u8_to_bits = crate::embed::FlatEmbed::U8ToBits; + let u8_to_bits_key = u8_to_bits.key::(); + + // define a function in the main module for the `u32_from_bits` embed + let u32_from_bits = crate::embed::FlatEmbed::U32FromBits; + let u32_from_bits_key = u32_from_bits.key::(); + + // define a function in the main module for the `u16_from_bits` embed + let u16_from_bits = crate::embed::FlatEmbed::U16FromBits; + let u16_from_bits_key = u16_from_bits.key::(); + + // define a function in the main module for the `u8_from_bits` embed + let u8_from_bits = crate::embed::FlatEmbed::U8FromBits; + let u8_from_bits_key = u8_from_bits.key::(); + + TypedProgram { + main: main_module_id.clone(), + modules: vec![( + main_module_id, + TypedModule { + functions: vec![ + (main_key, main_function), + (unpack_key.into(), TypedFunctionSymbol::Flat(unpack)), + ( + u32_from_bits_key.into(), + TypedFunctionSymbol::Flat(u32_from_bits), + ), + ( + u16_from_bits_key.into(), + TypedFunctionSymbol::Flat(u16_from_bits), + ), + ( + u8_from_bits_key.into(), + TypedFunctionSymbol::Flat(u8_from_bits), + ), + ( + u32_to_bits_key.into(), + TypedFunctionSymbol::Flat(u32_to_bits), + ), + ( + u16_to_bits_key.into(), + TypedFunctionSymbol::Flat(u16_to_bits), + ), + (u8_to_bits_key.into(), TypedFunctionSymbol::Flat(u8_to_bits)), + ] + .into_iter() + .collect(), + }, + )] + .into_iter() + .collect(), + } + } +} diff --git a/zokrates_core/src/static_analysis/uint_optimizer.rs b/zokrates_core/src/static_analysis/uint_optimizer.rs index 83cd31aaa..10296a203 100644 --- a/zokrates_core/src/static_analysis/uint_optimizer.rs +++ b/zokrates_core/src/static_analysis/uint_optimizer.rs @@ -1,3 +1,4 @@ +use crate::embed::FlatEmbed; use crate::zir::folder::*; use crate::zir::*; use std::collections::HashMap; @@ -24,7 +25,7 @@ impl<'ast, T: Field> UintOptimizer<'ast, T> { } } -fn force_reduce<'ast, T: Field>(e: UExpression<'ast, T>) -> UExpression<'ast, T> { +fn force_reduce(e: UExpression) -> UExpression { let metadata = e.metadata.unwrap(); let should_reduce = metadata.should_reduce.make_true(); @@ -38,7 +39,7 @@ fn force_reduce<'ast, T: Field>(e: UExpression<'ast, T>) -> UExpression<'ast, T> } } -fn force_no_reduce<'ast, T: Field>(e: UExpression<'ast, T>) -> UExpression<'ast, T> { +fn force_no_reduce(e: UExpression) -> UExpression { let metadata = e.metadata.unwrap(); let should_reduce = metadata.should_reduce.make_false(); @@ -67,6 +68,42 @@ impl<'ast, T: Field> Folder<'ast, T> for UintOptimizer<'ast, T> { BooleanExpression::UintEq(box left, box right) } + BooleanExpression::UintLt(box left, box right) => { + let left = self.fold_uint_expression(left); + let right = self.fold_uint_expression(right); + + let left = force_reduce(left); + let right = force_reduce(right); + + BooleanExpression::UintLt(box left, box right) + } + BooleanExpression::UintLe(box left, box right) => { + let left = self.fold_uint_expression(left); + let right = self.fold_uint_expression(right); + + let left = force_reduce(left); + let right = force_reduce(right); + + BooleanExpression::UintLe(box left, box right) + } + BooleanExpression::UintGt(box left, box right) => { + let left = self.fold_uint_expression(left); + let right = self.fold_uint_expression(right); + + let left = force_reduce(left); + let right = force_reduce(right); + + BooleanExpression::UintGt(box left, box right) + } + BooleanExpression::UintGe(box left, box right) => { + let left = self.fold_uint_expression(left); + let right = self.fold_uint_expression(right); + + let left = force_reduce(left); + let right = force_reduce(right); + + BooleanExpression::UintGe(box left, box right) + } e => fold_boolean_expression(self, e), } } @@ -80,7 +117,7 @@ impl<'ast, T: Field> Folder<'ast, T> for UintOptimizer<'ast, T> { let range = e.bitwidth.to_usize(); - let range_max: T = (2_usize.pow(range as u32) - 1).into(); + let range_max: T = (2_u128.pow(range as u32) - 1).into(); assert!(range < max_bitwidth / 2); @@ -94,7 +131,7 @@ impl<'ast, T: Field> Folder<'ast, T> for UintOptimizer<'ast, T> { self.ids .get(&Variable::uint(id.clone(), range)) .cloned() - .expect(&format!("identifier should have been defined: {}", id)), + .unwrap_or_else(|| panic!("identifier should have been defined: {}", id)), ), Add(box left, box right) => { // reduce the two terms @@ -109,7 +146,6 @@ impl<'ast, T: Field> Folder<'ast, T> for UintOptimizer<'ast, T> { .map(|max| (false, false, max)) .unwrap_or_else(|| { range_max - .clone() .checked_add(&right_max) .map(|max| (true, false, max)) .unwrap_or_else(|| { @@ -167,7 +203,7 @@ impl<'ast, T: Field> Folder<'ast, T> for UintOptimizer<'ast, T> { // if and only if `right_bitwidth` is `T::get_required_bits() - 1`, then `offset` is out of the interval // [0, 2**(max_bitwidth)[, therefore we need to reduce `right` left_max - .checked_add(&target_offset.clone()) + .checked_add(&target_offset) .map(|max| (false, true, max)) .unwrap_or_else(|| (true, true, range_max.clone() + target_offset)) } else { @@ -234,7 +270,6 @@ impl<'ast, T: Field> Folder<'ast, T> for UintOptimizer<'ast, T> { .map(|max| (false, false, max)) .unwrap_or_else(|| { range_max - .clone() .checked_mul(&right_max) .map(|max| (true, false, max)) .unwrap_or_else(|| { @@ -280,43 +315,56 @@ impl<'ast, T: Field> Folder<'ast, T> for UintOptimizer<'ast, T> { .with_max(range_max) } LeftShift(box e, box by) => { - // reduce the two terms + // reduce both terms let e = self.fold_uint_expression(e); - let by = self.fold_field_expression(by); - - let by_u = match by { - FieldElementExpression::Number(ref by) => { - by.to_dec_string().parse::().unwrap() - } - _ => unreachable!(), - }; - - let bitwidth = e.metadata.clone().unwrap().bitwidth(); - - let max = - T::from(2).pow(std::cmp::min(bitwidth as usize + by_u, range)) - T::from(1); - - UExpression::left_shift(force_reduce(e), by).with_max(max) + let by = self.fold_uint_expression(by); + + let by_max: u128 = by + .metadata + .clone() + .unwrap() + .max + .to_dec_string() + .parse() + .unwrap(); + let e_max: u128 = e + .metadata + .clone() + .unwrap() + .max + .to_dec_string() + .parse() + .unwrap(); + + let max = T::from((e_max << by_max) & (2_u128.pow(range as u32) - 1)); + + UExpression::left_shift(force_reduce(e), force_reduce(by)).with_max(max) } RightShift(box e, box by) => { - // reduce the two terms + // reduce both terms let e = self.fold_uint_expression(e); - let by = self.fold_field_expression(by); + let by = self.fold_uint_expression(by); - let by_u = match by { - FieldElementExpression::Number(ref by) => { - by.to_dec_string().parse::().unwrap() - } - _ => unreachable!(), + // if we don't know the amount by which we shift, the most conservative case (which leads to the biggest value) is 0 + let by_u = match by.as_inner() { + UExpressionInner::Value(by) => *by, + _ => 0, }; - let bitwidth = e.metadata.clone().unwrap().bitwidth(); + let e_max: u128 = e + .metadata + .clone() + .unwrap() + .max + .to_dec_string() + .parse() + .unwrap(); + + let max = (e_max & (2_u128.pow(range as u32) - 1)) >> by_u; - let max = T::from(2) - .pow(bitwidth as usize - std::cmp::min(by_u, bitwidth as usize)) - - T::from(1); + let max = T::from(max); - UExpression::right_shift(force_reduce(e), by).with_max(max) + UExpression::right_shift(force_reduce(e), force_reduce(by)).with_max(max) } IfElse(box condition, box consequence, box alternative) => { let condition = self.fold_boolean_expression(condition); @@ -374,8 +422,23 @@ impl<'ast, T: Field> Folder<'ast, T> for UintOptimizer<'ast, T> { .collect(), )], ZirStatement::MultipleDefinition(lhs, rhs) => match rhs { - ZirExpressionList::FunctionCall(key, arguments, ty) => match key.clone().id { - "_U32_FROM_BITS" => { + ZirExpressionList::EmbedCall(embed, generics, arguments) => match embed { + FlatEmbed::U64FromBits => { + assert_eq!(lhs.len(), 1); + self.register( + lhs[0].clone(), + UMetadata { + max: T::from(2).pow(64) - T::from(1), + should_reduce: ShouldReduce::False, + }, + ); + + vec![ZirStatement::MultipleDefinition( + lhs, + ZirExpressionList::EmbedCall(embed, generics, arguments), + )] + } + FlatEmbed::U32FromBits => { assert_eq!(lhs.len(), 1); self.register( lhs[0].clone(), @@ -384,12 +447,13 @@ impl<'ast, T: Field> Folder<'ast, T> for UintOptimizer<'ast, T> { should_reduce: ShouldReduce::False, }, ); + vec![ZirStatement::MultipleDefinition( lhs, - ZirExpressionList::FunctionCall(key, arguments, ty), + ZirExpressionList::EmbedCall(embed, generics, arguments), )] } - "_U16_FROM_BITS" => { + FlatEmbed::U16FromBits => { assert_eq!(lhs.len(), 1); self.register( lhs[0].clone(), @@ -400,10 +464,10 @@ impl<'ast, T: Field> Folder<'ast, T> for UintOptimizer<'ast, T> { ); vec![ZirStatement::MultipleDefinition( lhs, - ZirExpressionList::FunctionCall(key, arguments, ty), + ZirExpressionList::EmbedCall(embed, generics, arguments), )] } - "_U8_FROM_BITS" => { + FlatEmbed::U8FromBits => { assert_eq!(lhs.len(), 1); self.register( lhs[0].clone(), @@ -414,18 +478,18 @@ impl<'ast, T: Field> Folder<'ast, T> for UintOptimizer<'ast, T> { ); vec![ZirStatement::MultipleDefinition( lhs, - ZirExpressionList::FunctionCall(key, arguments, ty), + ZirExpressionList::EmbedCall(embed, generics, arguments), )] } _ => vec![ZirStatement::MultipleDefinition( lhs, - ZirExpressionList::FunctionCall( - key, + ZirExpressionList::EmbedCall( + embed, + generics, arguments .into_iter() .map(|e| self.fold_expression(e)) .collect(), - ty, ), )], }, @@ -469,19 +533,28 @@ mod tests { use pretty_assertions::assert_eq; + /// generate a test for a binary operator + /// + /// # Arguments + /// + /// * `left_max` the max value of the left argument + /// * `expected_reduce_left` whether we expect the optimizer to reduce the left argument + /// * `right_max` the max value of the right argument + /// * `expected_reduce_right` whether we expect the optimizer to reduce the left argument + /// * `res_max` the expected max value of the output macro_rules! uint_test { - ( $left_max:expr, $left_reduce:expr, $right_max:expr, $right_reduce:expr, $method:ident, $res_max:expr ) => {{ + ( $left_max:expr, $expected_reduce_left:expr, $right_max:expr, $expected_reduce_right:expr, $op:ident, $res_max:expr ) => {{ let left = e_with_max($left_max); let right = e_with_max($right_max); - let left_expected = if $left_reduce { + let left_expected = if $expected_reduce_left { force_reduce(left.clone()) } else { force_no_reduce(left.clone()) }; - let right_expected = if $right_reduce { + let right_expected = if $expected_reduce_right { force_reduce(right.clone()) } else { force_no_reduce(right.clone()) @@ -489,8 +562,8 @@ mod tests { assert_eq!( UintOptimizer::new() - .fold_uint_expression(UExpression::$method(left.clone(), right.clone())), - UExpression::$method(left_expected, right_expected).with_max($res_max) + .fold_uint_expression(UExpression::$op(left.clone(), right.clone())), + UExpression::$op(left_expected, right_expected).with_max($res_max) ); }}; } @@ -621,72 +694,64 @@ mod tests { #[test] fn right_shift() { - let e = e_with_max(255); + // left argument in range, we reduce (no effect) and the max is the original max, as we could be shifting by 0 + uint_test!(0xff_u32, true, 2, true, right_shift, 0xff_u32); + uint_test!(2, true, 2, true, right_shift, 2_u32); - let e_expected = force_reduce(e.clone()); - - assert_eq!( - UintOptimizer::new().fold_uint_expression(UExpression::right_shift( - e, - FieldElementExpression::Number(Bn128Field::from(2)) - )), - UExpression::right_shift( - e_expected, - FieldElementExpression::Number(Bn128Field::from(2)) - ) - .with_max(63) + // left argument out of range, we reduce and the max is the type max, shifted + uint_test!( + 0xffffffffffff_u128, + true, + 2, + true, + right_shift, + 0xffffffff_u32 ); - let e = e_with_max(2); + fn right_shift_test(e_max: u128, by: u32, output_max: u32) { + let left = e_with_max(e_max); - let e_expected = force_reduce(e.clone()); + let right = UExpressionInner::Value(by as u128) + .annotate(crate::zir::types::UBitwidth::B32) + .with_max(by); - assert_eq!( - UintOptimizer::new().fold_uint_expression(UExpression::right_shift( - e, - FieldElementExpression::Number(Bn128Field::from(2)) - )), - UExpression::right_shift( - e_expected, - FieldElementExpression::Number(Bn128Field::from(2)) - ) - .with_max(0) - ); + let left_expected = force_reduce(left.clone()); + + let right_expected = force_reduce(right.clone()); + + assert_eq!( + UintOptimizer::new() + .fold_uint_expression(UExpression::right_shift(left.clone(), right.clone())), + UExpression::right_shift(left_expected, right_expected).with_max(output_max) + ); + } + + right_shift_test(0xff_u128, 2, 0xff >> 2); + right_shift_test(2, 2, 2 >> 2); + right_shift_test(0xffffffffffff_u128, 2, 0xffffffff >> 2); } #[test] fn left_shift() { - let e = e_with_max(255); - - let e_expected = force_reduce(e.clone()); - - assert_eq!( - UintOptimizer::new().fold_uint_expression(UExpression::left_shift( - e, - FieldElementExpression::Number(Bn128Field::from(2)) - )), - UExpression::left_shift( - e_expected, - FieldElementExpression::Number(Bn128Field::from(2)) - ) - .with_max(1023) + uint_test!(0xff_u32, true, 2, true, left_shift, 0xff_u32 << 2); + uint_test!( + 0xffffffff_u32, + true, + 2, + true, + left_shift, + 0xffffffff_u32 << 2 ); - let e = e_with_max(0xffffffff_u32); - - let e_expected = force_reduce(e.clone()); - - assert_eq!( - UintOptimizer::new().fold_uint_expression(UExpression::left_shift( - e, - FieldElementExpression::Number(Bn128Field::from(2)) - )), - UExpression::left_shift( - e_expected, - FieldElementExpression::Number(Bn128Field::from(2)) - ) - .with_max(0xffffffff_u32) - ); + // left argument out of range, we reduce and the max is the type max, shifted + uint_test!( + 0xffffffffffff_u128, + true, + 2, + true, + left_shift, + 0xffffffff_u32 << 2 + ) } #[test] diff --git a/zokrates_core/src/static_analysis/unroll.rs b/zokrates_core/src/static_analysis/unroll.rs deleted file mode 100644 index 567c4f7bf..000000000 --- a/zokrates_core/src/static_analysis/unroll.rs +++ /dev/null @@ -1,616 +0,0 @@ -//! Module containing SSA reduction, including for-loop unrolling -//! -//! @file unroll.rs -//! @author Thibaut Schaeffer -//! @date 2018 - -use crate::typed_absy::folder::*; -use crate::typed_absy::identifier::CoreIdentifier; -use crate::typed_absy::*; -use std::collections::HashMap; -use zokrates_field::Field; - -pub enum Output<'ast, T: Field> { - Complete(TypedProgram<'ast, T>), - Incomplete(TypedProgram<'ast, T>, usize), -} - -pub struct Unroller<'ast> { - // version index for any variable name - substitution: HashMap, usize>, - // whether all statements could be unrolled so far. Loops with variable bounds cannot. - complete: bool, - statement_count: usize, -} - -impl<'ast> Unroller<'ast> { - fn new() -> Self { - Unroller { - substitution: HashMap::new(), - complete: true, - statement_count: 0, - } - } - - fn issue_next_ssa_variable(&mut self, v: Variable<'ast>) -> Variable<'ast> { - let res = match self.substitution.get(&v.id.id) { - Some(i) => Variable { - id: Identifier { - id: v.id.id.clone(), - version: i + 1, - stack: vec![], - }, - ..v - }, - None => Variable { ..v.clone() }, - }; - - self.substitution - .entry(v.id.id) - .and_modify(|e| *e += 1) - .or_insert(0); - res - } - - pub fn unroll(p: TypedProgram) -> Output { - let mut unroller = Unroller::new(); - let p = unroller.fold_program(p); - - match unroller.complete { - true => Output::Complete(p), - false => Output::Incomplete(p, unroller.statement_count), - } - } -} - -impl<'ast, T: Field> Folder<'ast, T> for Unroller<'ast> { - fn fold_statement(&mut self, s: TypedStatement<'ast, T>) -> Vec> { - self.statement_count += 1; - match s { - TypedStatement::Declaration(_) => vec![], - TypedStatement::Definition(a, e) => { - let e = self.fold_expression(e); - - let a = match a { - TypedAssignee::Identifier(v) => { - TypedAssignee::Identifier(self.issue_next_ssa_variable(v)) - } - a => fold_assignee(self, a), - }; - - vec![TypedStatement::Definition(a, e)] - } - TypedStatement::MultipleDefinition(assignees, exprs) => { - let exprs = self.fold_expression_list(exprs); - let assignees = assignees - .into_iter() - .map(|a| match a { - TypedAssignee::Identifier(v) => { - TypedAssignee::Identifier(self.issue_next_ssa_variable(v)) - } - a => fold_assignee(self, a), - }) - .collect(); - - vec![TypedStatement::MultipleDefinition(assignees, exprs)] - } - TypedStatement::For(v, from, to, stats) => { - let from = self.fold_field_expression(from); - let to = self.fold_field_expression(to); - - match (from, to) { - (FieldElementExpression::Number(from), FieldElementExpression::Number(to)) => { - let mut values: Vec = vec![]; - let mut current = from; - while current < to { - values.push(current.clone()); - current = T::one() + ¤t; - } - - let res = values - .into_iter() - .map(|index| { - vec![ - vec![ - TypedStatement::Declaration(v.clone()), - TypedStatement::Definition( - TypedAssignee::Identifier(v.clone()), - FieldElementExpression::Number(index).into(), - ), - ], - stats.clone(), - ] - .into_iter() - .flat_map(|x| x) - }) - .flat_map(|x| x) - .flat_map(|x| self.fold_statement(x)) - .collect(); - - res - } - (from, to) => { - self.complete = false; - vec![TypedStatement::For(v, from, to, stats)] - } - } - } - s => fold_statement(self, s), - } - } - - fn fold_function(&mut self, f: TypedFunction<'ast, T>) -> TypedFunction<'ast, T> { - self.substitution = HashMap::new(); - for arg in &f.arguments { - self.substitution.insert(arg.id.id.id.clone(), 0); - } - - fold_function(self, f) - } - - fn fold_name(&mut self, n: Identifier<'ast>) -> Identifier<'ast> { - Identifier { - version: self.substitution.get(&n.id).unwrap_or(&0).clone(), - ..n - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use zokrates_field::Bn128Field; - - #[cfg(test)] - mod statement { - use super::*; - use crate::typed_absy::types::{FunctionKey, Signature}; - - #[test] - fn for_loop() { - // for field i in 2..5 - // field foo = i - - // should be unrolled to - // i_0 = 2 - // foo_0 = i_0 - // i_1 = 3 - // foo_1 = i_1 - // i_2 = 4 - // foo_2 = i_2 - - let s = TypedStatement::For( - Variable::field_element("i"), - FieldElementExpression::Number(Bn128Field::from(2)), - FieldElementExpression::Number(Bn128Field::from(5)), - vec![ - TypedStatement::Declaration(Variable::field_element("foo")), - TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element("foo")), - FieldElementExpression::Identifier("i".into()).into(), - ), - ], - ); - - let expected = vec![ - TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element( - Identifier::from("i").version(0), - )), - FieldElementExpression::Number(Bn128Field::from(2)).into(), - ), - TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element( - Identifier::from("foo").version(0), - )), - FieldElementExpression::Identifier(Identifier::from("i").version(0)).into(), - ), - TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element( - Identifier::from("i").version(1), - )), - FieldElementExpression::Number(Bn128Field::from(3)).into(), - ), - TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element( - Identifier::from("foo").version(1), - )), - FieldElementExpression::Identifier(Identifier::from("i").version(1)).into(), - ), - TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element( - Identifier::from("i").version(2), - )), - FieldElementExpression::Number(Bn128Field::from(4)).into(), - ), - TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element( - Identifier::from("foo").version(2), - )), - FieldElementExpression::Identifier(Identifier::from("i").version(2)).into(), - ), - ]; - - let mut u = Unroller::new(); - - assert_eq!(u.fold_statement(s), expected); - } - - #[test] - fn idempotence() { - // an already unrolled program should not be modified by unrolling again - - // b = [5] - // b[0] = 1 - // a = 5 - // a_1 = 6 - // a_2 = 7 - - // should be turned into - // b = [5] - // b[0] = 1 - // a = 5 - // a_1 = 6 - // a_2 = 7 - - let mut u = Unroller::new(); - - let s = TypedStatement::Definition( - TypedAssignee::Identifier(Variable::array( - Identifier::from("b").version(0), - Type::FieldElement, - 1, - )), - ArrayExpressionInner::Value(vec![FieldElementExpression::from(Bn128Field::from( - 5, - )) - .into()]) - .annotate(Type::FieldElement, 1) - .into(), - ); - assert_eq!(u.fold_statement(s.clone()), vec![s]); - - let s = TypedStatement::Definition( - TypedAssignee::Select( - box Variable::field_element(Identifier::from("b").version(0)).into(), - box FieldElementExpression::Number(Bn128Field::from(0)), - ), - FieldElementExpression::Number(Bn128Field::from(1)).into(), - ); - assert_eq!(u.fold_statement(s.clone()), vec![s]); - - let s = TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element( - Identifier::from("a").version(0), - )), - FieldElementExpression::Number(Bn128Field::from(5)).into(), - ); - assert_eq!(u.fold_statement(s.clone()), vec![s]); - - let s = TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element( - Identifier::from("a").version(1), - )), - FieldElementExpression::Number(Bn128Field::from(6)).into(), - ); - assert_eq!(u.fold_statement(s.clone()), vec![s]); - - let s = TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element( - Identifier::from("a").version(2), - )), - FieldElementExpression::Number(Bn128Field::from(7)).into(), - ); - assert_eq!(u.fold_statement(s.clone()), vec![s]); - } - - #[test] - fn definition() { - // field a - // a = 5 - // a = 6 - // a - - // should be turned into - // a_0 = 5 - // a_1 = 6 - // a_1 - - let mut u = Unroller::new(); - - let s: TypedStatement = - TypedStatement::Declaration(Variable::field_element("a")); - assert_eq!(u.fold_statement(s), vec![]); - - let s = TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element("a")), - FieldElementExpression::Number(Bn128Field::from(5)).into(), - ); - assert_eq!( - u.fold_statement(s), - vec![TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element( - Identifier::from("a").version(0) - )), - FieldElementExpression::Number(Bn128Field::from(5)).into() - )] - ); - - let s = TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element("a")), - FieldElementExpression::Number(Bn128Field::from(6)).into(), - ); - assert_eq!( - u.fold_statement(s), - vec![TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element( - Identifier::from("a").version(1) - )), - FieldElementExpression::Number(Bn128Field::from(6)).into() - )] - ); - - let e: FieldElementExpression = - FieldElementExpression::Identifier("a".into()); - assert_eq!( - u.fold_field_expression(e), - FieldElementExpression::Identifier(Identifier::from("a").version(1)) - ); - } - - #[test] - fn incremental_definition() { - // field a - // a = 5 - // a = a + 1 - - // should be turned into - // a_0 = 5 - // a_1 = a_0 + 1 - - let mut u = Unroller::new(); - - let s: TypedStatement = - TypedStatement::Declaration(Variable::field_element("a")); - assert_eq!(u.fold_statement(s), vec![]); - - let s = TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element("a")), - FieldElementExpression::Number(Bn128Field::from(5)).into(), - ); - assert_eq!( - u.fold_statement(s), - vec![TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element( - Identifier::from("a").version(0) - )), - FieldElementExpression::Number(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)), - ) - .into(), - ); - assert_eq!( - u.fold_statement(s), - vec![TypedStatement::Definition( - 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)) - ) - .into() - )] - ); - } - - #[test] - fn incremental_multiple_definition() { - use crate::typed_absy::types::Type; - - // field a - // a = 2 - // a = foo(a) - - // should be turned into - // a_0 = 2 - // a_1 = foo(a_0) - - let mut u = Unroller::new(); - - let s: TypedStatement = - TypedStatement::Declaration(Variable::field_element("a")); - assert_eq!(u.fold_statement(s), vec![]); - - let s = TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element("a")), - FieldElementExpression::Number(Bn128Field::from(2)).into(), - ); - assert_eq!( - u.fold_statement(s), - vec![TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element( - Identifier::from("a").version(0) - )), - FieldElementExpression::Number(Bn128Field::from(2)).into() - )] - ); - - let s: TypedStatement = TypedStatement::MultipleDefinition( - vec![Variable::field_element("a").into()], - TypedExpressionList::FunctionCall( - FunctionKey::with_id("foo").signature( - Signature::new() - .inputs(vec![Type::FieldElement]) - .outputs(vec![Type::FieldElement]), - ), - vec![FieldElementExpression::Identifier("a".into()).into()], - vec![Type::FieldElement], - ), - ); - assert_eq!( - u.fold_statement(s), - vec![TypedStatement::MultipleDefinition( - vec![Variable::field_element(Identifier::from("a").version(1)).into()], - TypedExpressionList::FunctionCall( - FunctionKey::with_id("foo").signature( - Signature::new() - .inputs(vec![Type::FieldElement]) - .outputs(vec![Type::FieldElement]) - ), - vec![ - FieldElementExpression::Identifier(Identifier::from("a").version(0)) - .into() - ], - vec![Type::FieldElement], - ) - )] - ); - } - - #[test] - fn incremental_array_definition() { - // field[2] a = [1, 1] - // a[1] = 2 - - // should be turned into - // a_0 = [1, 1] - // a_0[1] = 2 - - let mut u = Unroller::new(); - - let s: TypedStatement = - TypedStatement::Declaration(Variable::field_array("a", 2)); - assert_eq!(u.fold_statement(s), vec![]); - - let s = TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_array("a", 2)), - ArrayExpressionInner::Value(vec![ - FieldElementExpression::Number(Bn128Field::from(1)).into(), - FieldElementExpression::Number(Bn128Field::from(1)).into(), - ]) - .annotate(Type::FieldElement, 2) - .into(), - ); - - assert_eq!( - u.fold_statement(s), - vec![TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_array( - Identifier::from("a").version(0), - 2 - )), - ArrayExpressionInner::Value(vec![ - FieldElementExpression::Number(Bn128Field::from(1)).into(), - FieldElementExpression::Number(Bn128Field::from(1)).into() - ]) - .annotate(Type::FieldElement, 2) - .into() - )] - ); - - let s: TypedStatement = TypedStatement::Definition( - TypedAssignee::Select( - box TypedAssignee::Identifier(Variable::field_array("a", 2)), - box FieldElementExpression::Number(Bn128Field::from(1)), - ), - FieldElementExpression::Number(Bn128Field::from(2)).into(), - ); - - assert_eq!(u.fold_statement(s.clone()), vec![s]); - } - - #[test] - fn incremental_array_of_arrays_definition() { - // field[2][2] a = [[0, 1], [2, 3]] - // a[1] = [4, 5] - - // should be turned into - // a_0 = [[0, 1], [2, 3]] - // a_0 = [4, 5] - - let mut u = Unroller::new(); - - let array_of_array_ty = Type::array(Type::array(Type::FieldElement, 2), 2); - - let s: TypedStatement = TypedStatement::Declaration( - Variable::with_id_and_type("a", array_of_array_ty.clone()), - ); - assert_eq!(u.fold_statement(s), vec![]); - - let s = TypedStatement::Definition( - TypedAssignee::Identifier(Variable::with_id_and_type( - "a", - array_of_array_ty.clone(), - )), - ArrayExpressionInner::Value(vec![ - ArrayExpressionInner::Value(vec![ - FieldElementExpression::Number(Bn128Field::from(0)).into(), - FieldElementExpression::Number(Bn128Field::from(1)).into(), - ]) - .annotate(Type::FieldElement, 2) - .into(), - ArrayExpressionInner::Value(vec![ - FieldElementExpression::Number(Bn128Field::from(2)).into(), - FieldElementExpression::Number(Bn128Field::from(3)).into(), - ]) - .annotate(Type::FieldElement, 2) - .into(), - ]) - .annotate(Type::array(Type::FieldElement, 2), 2) - .into(), - ); - - assert_eq!( - u.fold_statement(s), - vec![TypedStatement::Definition( - TypedAssignee::Identifier(Variable::with_id_and_type( - Identifier::from("a").version(0), - array_of_array_ty.clone(), - )), - ArrayExpressionInner::Value(vec![ - ArrayExpressionInner::Value(vec![ - FieldElementExpression::Number(Bn128Field::from(0)).into(), - FieldElementExpression::Number(Bn128Field::from(1)).into(), - ]) - .annotate(Type::FieldElement, 2) - .into(), - ArrayExpressionInner::Value(vec![ - FieldElementExpression::Number(Bn128Field::from(2)).into(), - FieldElementExpression::Number(Bn128Field::from(3)).into(), - ]) - .annotate(Type::FieldElement, 2) - .into(), - ]) - .annotate(Type::array(Type::FieldElement, 2), 2) - .into(), - )] - ); - - let s: TypedStatement = TypedStatement::Definition( - TypedAssignee::Select( - box TypedAssignee::Identifier(Variable::with_id_and_type( - "a", - array_of_array_ty.clone(), - )), - box FieldElementExpression::Number(Bn128Field::from(1)), - ), - ArrayExpressionInner::Value(vec![ - FieldElementExpression::Number(Bn128Field::from(4)).into(), - FieldElementExpression::Number(Bn128Field::from(5)).into(), - ]) - .annotate(Type::FieldElement, 2) - .into(), - ); - - assert_eq!(u.fold_statement(s.clone()), vec![s]); - } - } -} diff --git a/zokrates_core/src/static_analysis/variable_read_remover.rs b/zokrates_core/src/static_analysis/variable_read_remover.rs index 563dcb4e4..90c25f712 100644 --- a/zokrates_core/src/static_analysis/variable_read_remover.rs +++ b/zokrates_core/src/static_analysis/variable_read_remover.rs @@ -29,41 +29,50 @@ impl<'ast, T: Field> VariableReadRemover<'ast, T> { fn select + IfElse<'ast, T>>( &mut self, a: ArrayExpression<'ast, T>, - i: FieldElementExpression<'ast, T>, + i: UExpression<'ast, T>, ) -> U { - match i { - FieldElementExpression::Number(i) => U::select(a, FieldElementExpression::Number(i)), + match i.into_inner() { + UExpressionInner::Value(i) => { + U::select(a, UExpressionInner::Value(i).annotate(UBitwidth::B32)) + } i => { let size = match a.get_type().clone() { - Type::Array(array_ty) => array_ty.size, + Type::Array(array_ty) => match array_ty.size.into_inner() { + UExpressionInner::Value(size) => size as u32, + _ => unreachable!(), + }, _ => unreachable!(), }; self.statements.push(TypedStatement::Assertion( (0..size) .map(|index| { - BooleanExpression::FieldEq( - box i.clone(), - box FieldElementExpression::Number(index.into()).into(), + BooleanExpression::UintEq( + box i.clone().annotate(UBitwidth::B32), + box index.into(), ) }) .fold(None, |acc, e| match acc { Some(acc) => Some(BooleanExpression::Or(box acc, box e)), None => Some(e), }) - .unwrap() - .into(), + .unwrap(), )); (0..size) - .map(|i| U::select(a.clone(), FieldElementExpression::Number(i.into()))) + .map(|i| { + U::select( + a.clone(), + UExpressionInner::Value(i.into()).annotate(UBitwidth::B32), + ) + }) .enumerate() .rev() .fold(None, |acc, (index, res)| match acc { Some(acc) => Some(U::if_else( - BooleanExpression::FieldEq( - box i.clone(), - box FieldElementExpression::Number(index.into()), + BooleanExpression::UintEq( + box i.clone().annotate(UBitwidth::B32), + box (index as u32).into(), ), res, acc, @@ -99,21 +108,20 @@ impl<'ast, T: Field> Folder<'ast, T> for VariableReadRemover<'ast, T> { fn fold_array_expression_inner( &mut self, - ty: &Type, - size: usize, + ty: &ArrayType<'ast, T>, e: ArrayExpressionInner<'ast, T>, ) -> ArrayExpressionInner<'ast, T> { match e { ArrayExpressionInner::Select(box a, box i) => { self.select::>(a, i).into_inner() } - e => fold_array_expression_inner(self, ty, size, e), + e => fold_array_expression_inner(self, ty, e), } } fn fold_struct_expression_inner( &mut self, - ty: &StructType, + ty: &StructType<'ast, T>, e: StructExpressionInner<'ast, T>, ) -> StructExpressionInner<'ast, T> { match e { @@ -160,8 +168,8 @@ mod tests { let access: TypedStatement = TypedStatement::Definition( TypedAssignee::Identifier(Variable::field_element("b")), FieldElementExpression::Select( - box ArrayExpressionInner::Identifier("a".into()).annotate(Type::FieldElement, 2), - box FieldElementExpression::Identifier("i".into()), + box ArrayExpressionInner::Identifier("a".into()).annotate(Type::FieldElement, 2u32), + box UExpressionInner::Identifier("i".into()).annotate(UBitwidth::B32), ) .into(), ); @@ -169,35 +177,32 @@ mod tests { assert_eq!( VariableReadRemover::new().fold_statement(access), vec![ - TypedStatement::Assertion( - BooleanExpression::Or( - box BooleanExpression::FieldEq( - box FieldElementExpression::Identifier("i".into()), - box FieldElementExpression::Number(0.into()) - ), - box BooleanExpression::FieldEq( - box FieldElementExpression::Identifier("i".into()), - box FieldElementExpression::Number(1.into()) - ) + TypedStatement::Assertion(BooleanExpression::Or( + box BooleanExpression::UintEq( + box UExpressionInner::Identifier("i".into()).annotate(UBitwidth::B32), + box UExpressionInner::Value(0).annotate(UBitwidth::B32) + ), + box BooleanExpression::UintEq( + box UExpressionInner::Identifier("i".into()).annotate(UBitwidth::B32), + box UExpressionInner::Value(1).annotate(UBitwidth::B32) ) - .into(), - ), + )), TypedStatement::Definition( TypedAssignee::Identifier(Variable::field_element("b")), FieldElementExpression::if_else( - BooleanExpression::FieldEq( - box FieldElementExpression::Identifier("i".into()), - box FieldElementExpression::Number(0.into()) + BooleanExpression::UintEq( + box UExpressionInner::Identifier("i".into()).annotate(UBitwidth::B32), + box UExpressionInner::Value(0).annotate(UBitwidth::B32) ), FieldElementExpression::Select( box ArrayExpressionInner::Identifier("a".into()) - .annotate(Type::FieldElement, 2), - box FieldElementExpression::Number(0.into()), + .annotate(Type::FieldElement, 2u32), + box 0u32.into(), ), FieldElementExpression::Select( box ArrayExpressionInner::Identifier("a".into()) - .annotate(Type::FieldElement, 2), - box FieldElementExpression::Number(1.into()), + .annotate(Type::FieldElement, 2u32), + box 1u32.into(), ) ) .into() diff --git a/zokrates_core/src/static_analysis/variable_write_remover.rs b/zokrates_core/src/static_analysis/variable_write_remover.rs index 24aa8f570..fba777bf5 100644 --- a/zokrates_core/src/static_analysis/variable_write_remover.rs +++ b/zokrates_core/src/static_analysis/variable_write_remover.rs @@ -37,33 +37,31 @@ impl<'ast> VariableWriteRemover { let inner_ty = base.inner_type(); let size = base.size(); + let size = match size.as_inner() { + UExpressionInner::Value(v) => *v as u32, + _ => unreachable!(), + }; + let head = indices.remove(0); let tail = indices; match head { Access::Select(head) => { statements.insert(TypedStatement::Assertion( - BooleanExpression::Lt( - box head.clone(), - box FieldElementExpression::Number(T::from(size)), - ) - .into(), + BooleanExpression::UintLt(box head.clone(), box size.into()), )); ArrayExpressionInner::Value( (0..size) .map(|i| match inner_ty { + Type::Int => unreachable!(), Type::Array(..) => ArrayExpression::if_else( - BooleanExpression::FieldEq( - box FieldElementExpression::Number(T::from(i)), + BooleanExpression::UintEq( + box i.into(), box head.clone(), ), match Self::choose_many( - ArrayExpression::select( - base.clone(), - FieldElementExpression::Number(T::from(i)), - ) - .into(), + ArrayExpression::select(base.clone(), i).into(), tail.clone(), new_expression.clone(), statements, @@ -74,23 +72,16 @@ impl<'ast> VariableWriteRemover { e.get_type() ), }, - ArrayExpression::select( - base.clone(), - FieldElementExpression::Number(T::from(i)), - ), + ArrayExpression::select(base.clone(), i), ) .into(), Type::Struct(..) => StructExpression::if_else( - BooleanExpression::FieldEq( - box FieldElementExpression::Number(T::from(i)), + BooleanExpression::UintEq( + box i.into(), box head.clone(), ), match Self::choose_many( - StructExpression::select( - base.clone(), - FieldElementExpression::Number(T::from(i)), - ) - .into(), + StructExpression::select(base.clone(), i).into(), tail.clone(), new_expression.clone(), statements, @@ -101,23 +92,17 @@ impl<'ast> VariableWriteRemover { e.get_type() ), }, - StructExpression::select( - base.clone(), - FieldElementExpression::Number(T::from(i)), - ), + StructExpression::select(base.clone(), i), ) .into(), Type::FieldElement => FieldElementExpression::if_else( - BooleanExpression::FieldEq( - box FieldElementExpression::Number(T::from(i)), + BooleanExpression::UintEq( + box i.into(), box head.clone(), ), match Self::choose_many( - FieldElementExpression::select( - base.clone(), - FieldElementExpression::Number(T::from(i)), - ) - .into(), + FieldElementExpression::select(base.clone(), i) + .into(), tail.clone(), new_expression.clone(), statements, @@ -128,23 +113,16 @@ impl<'ast> VariableWriteRemover { e.get_type() ), }, - FieldElementExpression::select( - base.clone(), - FieldElementExpression::Number(T::from(i)), - ), + FieldElementExpression::select(base.clone(), i), ) .into(), Type::Boolean => BooleanExpression::if_else( - BooleanExpression::FieldEq( - box FieldElementExpression::Number(T::from(i)), + BooleanExpression::UintEq( + box i.into(), box head.clone(), ), match Self::choose_many( - BooleanExpression::select( - base.clone(), - FieldElementExpression::Number(T::from(i)), - ) - .into(), + BooleanExpression::select(base.clone(), i).into(), tail.clone(), new_expression.clone(), statements, @@ -155,23 +133,16 @@ impl<'ast> VariableWriteRemover { e.get_type() ), }, - BooleanExpression::select( - base.clone(), - FieldElementExpression::Number(T::from(i)), - ), + BooleanExpression::select(base.clone(), i), ) .into(), Type::Uint(..) => UExpression::if_else( - BooleanExpression::FieldEq( - box FieldElementExpression::Number(T::from(i)), + BooleanExpression::UintEq( + box i.into(), box head.clone(), ), match Self::choose_many( - UExpression::select( - base.clone(), - FieldElementExpression::Number(T::from(i)), - ) - .into(), + UExpression::select(base.clone(), i).into(), tail.clone(), new_expression.clone(), statements, @@ -182,14 +153,12 @@ impl<'ast> VariableWriteRemover { e.get_type() ), }, - UExpression::select( - base.clone(), - FieldElementExpression::Number(T::from(i)), - ), + UExpression::select(base.clone(), i), ) .into(), }) - .collect(), + .collect::>() + .into(), ) .annotate(inner_ty.clone(), size) .into() @@ -212,6 +181,7 @@ impl<'ast> VariableWriteRemover { .clone() .into_iter() .map(|member| match *member.ty { + Type::Int => unreachable!(), Type::FieldElement => { if member.id == head { Self::choose_many( @@ -225,11 +195,8 @@ impl<'ast> VariableWriteRemover { statements, ) } else { - FieldElementExpression::member( - base.clone(), - member.id.clone(), - ) - .into() + FieldElementExpression::member(base.clone(), member.id) + .into() } } Type::Uint(..) => { @@ -242,8 +209,7 @@ impl<'ast> VariableWriteRemover { statements, ) } else { - UExpression::member(base.clone(), member.id.clone()) - .into() + UExpression::member(base.clone(), member.id).into() } } Type::Boolean => { @@ -259,11 +225,8 @@ impl<'ast> VariableWriteRemover { statements, ) } else { - BooleanExpression::member( - base.clone(), - member.id.clone(), - ) - .into() + BooleanExpression::member(base.clone(), member.id) + .into() } } Type::Array(..) => { @@ -276,8 +239,7 @@ impl<'ast> VariableWriteRemover { statements, ) } else { - ArrayExpression::member(base.clone(), member.id.clone()) - .into() + ArrayExpression::member(base.clone(), member.id).into() } } Type::Struct(..) => { @@ -293,11 +255,7 @@ impl<'ast> VariableWriteRemover { statements, ) } else { - StructExpression::member( - base.clone(), - member.id.clone(), - ) - .into() + StructExpression::member(base.clone(), member.id).into() } } }) @@ -316,12 +274,12 @@ impl<'ast> VariableWriteRemover { #[derive(Clone, Debug)] enum Access<'ast, T: Field> { - Select(FieldElementExpression<'ast, T>), + Select(UExpression<'ast, T>), Member(MemberId), } /// Turn an assignee into its representation as a base variable and a list accesses /// a[2][3][4] -> (a, [2, 3, 4]) -fn linear<'ast, T: Field>(a: TypedAssignee<'ast, T>) -> (Variable, Vec>) { +fn linear(a: TypedAssignee) -> (Variable, Vec>) { match a { TypedAssignee::Identifier(v) => (v, vec![]), TypedAssignee::Select(box array, box index) => { @@ -337,11 +295,11 @@ fn linear<'ast, T: Field>(a: TypedAssignee<'ast, T>) -> (Variable, Vec(assignee: &TypedAssignee<'ast, T>) -> bool { +fn is_constant(assignee: &TypedAssignee) -> bool { match assignee { TypedAssignee::Identifier(_) => true, - TypedAssignee::Select(box assignee, box index) => match index { - FieldElementExpression::Number(_) => is_constant(assignee), + TypedAssignee::Select(box assignee, box index) => match index.as_inner() { + UExpressionInner::Value(_) => is_constant(assignee), _ => false, }, TypedAssignee::Member(box assignee, _) => is_constant(assignee), @@ -362,24 +320,21 @@ impl<'ast, T: Field> Folder<'ast, T> for VariableWriteRemover { let (variable, indices) = linear(assignee); let base = match variable.get_type() { + Type::Int => unreachable!(), Type::FieldElement => { - FieldElementExpression::Identifier(variable.id.clone().into()).into() - } - Type::Boolean => { - BooleanExpression::Identifier(variable.id.clone().into()).into() - } - Type::Uint(bitwidth) => { - UExpressionInner::Identifier(variable.id.clone().into()) - .annotate(bitwidth) - .into() + FieldElementExpression::Identifier(variable.id.clone()).into() } + Type::Boolean => BooleanExpression::Identifier(variable.id.clone()).into(), + Type::Uint(bitwidth) => UExpressionInner::Identifier(variable.id.clone()) + .annotate(bitwidth) + .into(), Type::Array(array_type) => { - ArrayExpressionInner::Identifier(variable.id.clone().into()) + ArrayExpressionInner::Identifier(variable.id.clone()) .annotate(*array_type.ty, array_type.size) .into() } Type::Struct(members) => { - StructExpressionInner::Identifier(variable.id.clone().into()) + StructExpressionInner::Identifier(variable.id.clone()) .annotate(members) .into() } @@ -390,7 +345,7 @@ impl<'ast, T: Field> Folder<'ast, T> for VariableWriteRemover { let indices = indices .into_iter() .map(|a| match a { - Access::Select(i) => Access::Select(self.fold_field_expression(i)), + Access::Select(i) => Access::Select(self.fold_uint_expression(i)), a => a, }) .collect(); diff --git a/zokrates_core/src/typed_absy/abi.rs b/zokrates_core/src/typed_absy/abi.rs index f8ff7a878..3cd1f4254 100644 --- a/zokrates_core/src/typed_absy/abi.rs +++ b/zokrates_core/src/typed_absy/abi.rs @@ -1,15 +1,15 @@ -use crate::typed_absy::{Signature, Type}; +use crate::typed_absy::types::{ConcreteSignature, ConcreteType}; use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)] pub struct AbiInput { pub name: String, pub public: bool, #[serde(flatten)] - pub ty: Type, + pub ty: ConcreteType, } -pub type AbiOutput = Type; +pub type AbiOutput = ConcreteType; #[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] pub struct Abi { @@ -18,8 +18,9 @@ pub struct Abi { } impl Abi { - pub fn signature(&self) -> Signature { - Signature { + pub fn signature(&self) -> ConcreteSignature { + ConcreteSignature { + generics: vec![], inputs: self.inputs.iter().map(|i| i.ty.clone()).collect(), outputs: self.outputs.clone(), } @@ -29,10 +30,12 @@ impl Abi { #[cfg(test)] mod tests { use super::*; - use crate::typed_absy::types::{ArrayType, FunctionKey, StructMember, StructType}; + use crate::typed_absy::types::{ + ConcreteArrayType, ConcreteFunctionKey, ConcreteStructMember, ConcreteStructType, UBitwidth, + }; use crate::typed_absy::{ - Parameter, Type, TypedFunction, TypedFunctionSymbol, TypedModule, TypedProgram, UBitwidth, - Variable, + parameter::DeclarationParameter, variable::DeclarationVariable, ConcreteType, + TypedFunction, TypedFunctionSymbol, TypedModule, TypedProgram, }; use std::collections::HashMap; use zokrates_field::Bn128Field; @@ -41,22 +44,23 @@ mod tests { fn generate_abi_from_typed_ast() { let mut functions = HashMap::new(); functions.insert( - FunctionKey::with_id("main"), + ConcreteFunctionKey::with_location("main", "main").into(), TypedFunctionSymbol::Here(TypedFunction { arguments: vec![ - Parameter { - id: Variable::field_element("a"), + DeclarationParameter { + id: DeclarationVariable::field_element("a"), private: true, }, - Parameter { - id: Variable::boolean("b"), + DeclarationParameter { + id: DeclarationVariable::boolean("b"), private: false, }, ], statements: vec![], - signature: Signature::new() - .inputs(vec![Type::FieldElement, Type::Boolean]) - .outputs(vec![Type::FieldElement]), + signature: ConcreteSignature::new() + .inputs(vec![ConcreteType::FieldElement, ConcreteType::Boolean]) + .outputs(vec![ConcreteType::FieldElement]) + .into(), }), ); @@ -74,15 +78,15 @@ mod tests { AbiInput { name: String::from("a"), public: false, - ty: Type::FieldElement, + ty: ConcreteType::FieldElement, }, AbiInput { name: String::from("b"), public: true, - ty: Type::Boolean, + ty: ConcreteType::Boolean, }, ], - outputs: vec![Type::FieldElement], + outputs: vec![ConcreteType::FieldElement], }; assert_eq!(expected_abi, abi); @@ -101,6 +105,19 @@ mod tests { assert_eq!(de_abi, abi); } + #[test] + #[should_panic] + fn serialize_integer() { + // serializing the Int type should panic as it is not allowed in signatures + + let abi: Abi = Abi { + inputs: vec![], + outputs: vec![ConcreteType::Int], + }; + + let _ = serde_json::to_string_pretty(&abi).unwrap(); + } + #[test] fn serialize_field() { let abi: Abi = Abi { @@ -108,15 +125,15 @@ mod tests { AbiInput { name: String::from("a"), public: true, - ty: Type::FieldElement, + ty: ConcreteType::FieldElement, }, AbiInput { name: String::from("b"), public: true, - ty: Type::FieldElement, + ty: ConcreteType::FieldElement, }, ], - outputs: vec![Type::FieldElement], + outputs: vec![ConcreteType::FieldElement], }; let json = serde_json::to_string_pretty(&abi).unwrap(); @@ -154,17 +171,17 @@ mod tests { AbiInput { name: String::from("a"), public: true, - ty: Type::Uint(UBitwidth::B8), + ty: ConcreteType::Uint(UBitwidth::B8), }, AbiInput { name: String::from("b"), public: true, - ty: Type::Uint(UBitwidth::B16), + ty: ConcreteType::Uint(UBitwidth::B16), }, AbiInput { name: String::from("c"), public: true, - ty: Type::Uint(UBitwidth::B32), + ty: ConcreteType::Uint(UBitwidth::B32), }, ], outputs: vec![], @@ -205,21 +222,21 @@ mod tests { inputs: vec![AbiInput { name: String::from("foo"), public: true, - ty: Type::Struct(StructType::new( + ty: ConcreteType::Struct(ConcreteStructType::new( "".into(), "Foo".into(), vec![ - StructMember::new(String::from("a"), Type::FieldElement), - StructMember::new(String::from("b"), Type::Boolean), + ConcreteStructMember::new(String::from("a"), ConcreteType::FieldElement), + ConcreteStructMember::new(String::from("b"), ConcreteType::Boolean), ], )), }], - outputs: vec![Type::Struct(StructType::new( + outputs: vec![ConcreteType::Struct(ConcreteStructType::new( "".into(), "Foo".into(), vec![ - StructMember::new(String::from("a"), Type::FieldElement), - StructMember::new(String::from("b"), Type::Boolean), + ConcreteStructMember::new(String::from("a"), ConcreteType::FieldElement), + ConcreteStructMember::new(String::from("b"), ConcreteType::Boolean), ], ))], }; @@ -279,17 +296,23 @@ mod tests { inputs: vec![AbiInput { name: String::from("foo"), public: true, - ty: Type::Struct(StructType::new( + ty: ConcreteType::Struct(ConcreteStructType::new( "".into(), "Foo".into(), - vec![StructMember::new( + vec![ConcreteStructMember::new( String::from("bar"), - Type::Struct(StructType::new( + ConcreteType::Struct(ConcreteStructType::new( "".into(), "Bar".into(), vec![ - StructMember::new(String::from("a"), Type::FieldElement), - StructMember::new(String::from("b"), Type::FieldElement), + ConcreteStructMember::new( + String::from("a"), + ConcreteType::FieldElement, + ), + ConcreteStructMember::new( + String::from("b"), + ConcreteType::FieldElement, + ), ], )), )], @@ -345,19 +368,22 @@ mod tests { inputs: vec![AbiInput { name: String::from("a"), public: false, - ty: Type::Array(ArrayType::new( - Type::Struct(StructType::new( + ty: ConcreteType::Array(ConcreteArrayType::new( + ConcreteType::Struct(ConcreteStructType::new( "".into(), "Foo".into(), vec![ - StructMember::new(String::from("b"), Type::FieldElement), - StructMember::new(String::from("c"), Type::Boolean), + ConcreteStructMember::new( + String::from("b"), + ConcreteType::FieldElement, + ), + ConcreteStructMember::new(String::from("c"), ConcreteType::Boolean), ], )), 2, )), }], - outputs: vec![Type::Boolean], + outputs: vec![ConcreteType::Boolean], }; let json = serde_json::to_string_pretty(&abi).unwrap(); @@ -406,12 +432,12 @@ mod tests { inputs: vec![AbiInput { name: String::from("a"), public: false, - ty: Type::Array(ArrayType::new( - Type::Array(ArrayType::new(Type::FieldElement, 2)), + ty: ConcreteType::Array(ConcreteArrayType::new( + ConcreteType::Array(ConcreteArrayType::new(ConcreteType::FieldElement, 2)), 2, )), }], - outputs: vec![Type::FieldElement], + outputs: vec![ConcreteType::FieldElement], }; let json = serde_json::to_string_pretty(&abi).unwrap(); diff --git a/zokrates_core/src/typed_absy/folder.rs b/zokrates_core/src/typed_absy/folder.rs index 76a81ff21..5aaacc158 100644 --- a/zokrates_core/src/typed_absy/folder.rs +++ b/zokrates_core/src/typed_absy/folder.rs @@ -1,5 +1,6 @@ // Generic walk through a typed AST. Not mutating in place +use crate::typed_absy::types::{ArrayType, StructMember, StructType}; use crate::typed_absy::*; use zokrates_field::Field; @@ -23,9 +24,9 @@ pub trait Folder<'ast, T: Field>: Sized { fold_function(self, f) } - fn fold_parameter(&mut self, p: Parameter<'ast>) -> Parameter<'ast> { - Parameter { - id: self.fold_variable(p.id), + fn fold_parameter(&mut self, p: DeclarationParameter<'ast>) -> DeclarationParameter<'ast> { + DeclarationParameter { + id: self.fold_declaration_variable(p.id), ..p } } @@ -34,13 +35,58 @@ pub trait Folder<'ast, T: Field>: Sized { n } - fn fold_variable(&mut self, v: Variable<'ast>) -> Variable<'ast> { + fn fold_variable(&mut self, v: Variable<'ast, T>) -> Variable<'ast, T> { Variable { id: self.fold_name(v.id), - ..v + _type: self.fold_type(v._type), } } + fn fold_declaration_variable( + &mut self, + v: DeclarationVariable<'ast>, + ) -> DeclarationVariable<'ast> { + DeclarationVariable { + id: self.fold_name(v.id), + _type: self.fold_declaration_type(v._type), + } + } + + fn fold_type(&mut self, t: Type<'ast, T>) -> Type<'ast, T> { + use self::GType::*; + + match t { + Array(array_type) => Array(self.fold_array_type(array_type)), + Struct(struct_type) => Struct(self.fold_struct_type(struct_type)), + t => t, + } + } + + fn fold_array_type(&mut self, t: ArrayType<'ast, T>) -> ArrayType<'ast, T> { + ArrayType { + ty: box self.fold_type(*t.ty), + size: self.fold_uint_expression(t.size), + } + } + + fn fold_struct_type(&mut self, t: StructType<'ast, T>) -> StructType<'ast, T> { + StructType { + members: t + .members + .into_iter() + .map(|m| StructMember { + ty: box self.fold_type(*m.ty), + ..m + }) + .collect(), + ..t + } + } + + fn fold_declaration_type(&mut self, t: DeclarationType<'ast>) -> DeclarationType<'ast> { + t + } + fn fold_assignee(&mut self, a: TypedAssignee<'ast, T>) -> TypedAssignee<'ast, T> { fold_assignee(self, a) } @@ -49,6 +95,26 @@ pub trait Folder<'ast, T: Field>: Sized { fold_statement(self, s) } + fn fold_expression_or_spread( + &mut self, + e: TypedExpressionOrSpread<'ast, T>, + ) -> TypedExpressionOrSpread<'ast, T> { + match e { + TypedExpressionOrSpread::Expression(e) => { + TypedExpressionOrSpread::Expression(self.fold_expression(e)) + } + TypedExpressionOrSpread::Spread(s) => { + TypedExpressionOrSpread::Spread(self.fold_spread(s)) + } + } + } + + fn fold_spread(&mut self, s: TypedSpread<'ast, T>) -> TypedSpread<'ast, T> { + TypedSpread { + array: self.fold_array_expression(s.array), + } + } + fn fold_expression(&mut self, e: TypedExpression<'ast, T>) -> TypedExpression<'ast, T> { match e { TypedExpression::FieldElement(e) => self.fold_field_expression(e).into(), @@ -56,6 +122,7 @@ pub trait Folder<'ast, T: Field>: Sized { TypedExpression::Uint(e) => self.fold_uint_expression(e).into(), TypedExpression::Array(e) => self.fold_array_expression(e).into(), TypedExpression::Struct(e) => self.fold_struct_expression(e).into(), + TypedExpression::Int(e) => self.fold_int_expression(e).into(), } } @@ -74,18 +141,11 @@ pub trait Folder<'ast, T: Field>: Sized { &mut self, es: TypedExpressionList<'ast, T>, ) -> TypedExpressionList<'ast, T> { - match es { - TypedExpressionList::FunctionCall(id, arguments, types) => { - TypedExpressionList::FunctionCall( - id, - arguments - .into_iter() - .map(|a| self.fold_expression(a)) - .collect(), - types, - ) - } - } + fold_expression_list(self, es) + } + + fn fold_int_expression(&mut self, e: IntExpression<'ast, T>) -> IntExpression<'ast, T> { + fold_int_expression(self, e) } fn fold_field_expression( @@ -114,15 +174,14 @@ pub trait Folder<'ast, T: Field>: Sized { fn fold_array_expression_inner( &mut self, - ty: &Type, - size: usize, + ty: &ArrayType<'ast, T>, e: ArrayExpressionInner<'ast, T>, ) -> ArrayExpressionInner<'ast, T> { - fold_array_expression_inner(self, ty, size, e) + fold_array_expression_inner(self, ty, e) } fn fold_struct_expression_inner( &mut self, - ty: &StructType, + ty: &StructType<'ast, T>, e: StructExpressionInner<'ast, T>, ) -> StructExpressionInner<'ast, T> { fold_struct_expression_inner(self, ty, e) @@ -139,7 +198,6 @@ pub fn fold_module<'ast, T: Field, F: Folder<'ast, T>>( .into_iter() .map(|(key, fun)| (key, f.fold_function_symbol(fun))) .collect(), - ..p } } @@ -161,8 +219,8 @@ pub fn fold_statement<'ast, T: Field, F: Folder<'ast, T>>( TypedStatement::Assertion(e) => TypedStatement::Assertion(f.fold_boolean_expression(e)), TypedStatement::For(v, from, to, statements) => TypedStatement::For( f.fold_variable(v), - from, - to, + f.fold_uint_expression(from), + f.fold_uint_expression(to), statements .into_iter() .flat_map(|s| f.fold_statement(s)) @@ -172,24 +230,31 @@ pub fn fold_statement<'ast, T: Field, F: Folder<'ast, T>>( assignees.into_iter().map(|a| f.fold_assignee(a)).collect(), f.fold_expression_list(elist), ), + s => s, }; vec![res] } pub fn fold_array_expression_inner<'ast, T: Field, F: Folder<'ast, T>>( f: &mut F, - _: &Type, - _: usize, + _: &ArrayType<'ast, T>, e: ArrayExpressionInner<'ast, T>, ) -> ArrayExpressionInner<'ast, T> { match e { ArrayExpressionInner::Identifier(id) => ArrayExpressionInner::Identifier(f.fold_name(id)), - ArrayExpressionInner::Value(exprs) => { - ArrayExpressionInner::Value(exprs.into_iter().map(|e| f.fold_expression(e)).collect()) - } - ArrayExpressionInner::FunctionCall(id, exps) => { + ArrayExpressionInner::Value(exprs) => ArrayExpressionInner::Value( + exprs + .into_iter() + .map(|e| f.fold_expression_or_spread(e)) + .collect(), + ), + ArrayExpressionInner::FunctionCall(id, generics, exps) => { + let generics = generics + .into_iter() + .map(|g| g.map(|g| f.fold_uint_expression(g))) + .collect(); let exps = exps.into_iter().map(|e| f.fold_expression(e)).collect(); - ArrayExpressionInner::FunctionCall(id, exps) + ArrayExpressionInner::FunctionCall(id, generics, exps) } ArrayExpressionInner::IfElse(box condition, box consequence, box alternative) => { ArrayExpressionInner::IfElse( @@ -204,15 +269,26 @@ pub fn fold_array_expression_inner<'ast, T: Field, F: Folder<'ast, T>>( } ArrayExpressionInner::Select(box array, box index) => { let array = f.fold_array_expression(array); - let index = f.fold_field_expression(index); + let index = f.fold_uint_expression(index); ArrayExpressionInner::Select(box array, box index) } + ArrayExpressionInner::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); + ArrayExpressionInner::Slice(box array, box from, box to) + } + ArrayExpressionInner::Repeat(box e, box count) => { + let e = f.fold_expression(e); + let count = f.fold_uint_expression(count); + ArrayExpressionInner::Repeat(box e, box count) + } } } pub fn fold_struct_expression_inner<'ast, T: Field, F: Folder<'ast, T>>( f: &mut F, - _: &StructType, + _: &StructType<'ast, T>, e: StructExpressionInner<'ast, T>, ) -> StructExpressionInner<'ast, T> { match e { @@ -220,9 +296,13 @@ pub fn fold_struct_expression_inner<'ast, T: Field, F: Folder<'ast, T>>( StructExpressionInner::Value(exprs) => { StructExpressionInner::Value(exprs.into_iter().map(|e| f.fold_expression(e)).collect()) } - StructExpressionInner::FunctionCall(id, exps) => { + StructExpressionInner::FunctionCall(id, generics, exps) => { + let generics = generics + .into_iter() + .map(|g| g.map(|g| f.fold_uint_expression(g))) + .collect(); let exps = exps.into_iter().map(|e| f.fold_expression(e)).collect(); - StructExpressionInner::FunctionCall(id, exps) + StructExpressionInner::FunctionCall(id, generics, exps) } StructExpressionInner::IfElse(box condition, box consequence, box alternative) => { StructExpressionInner::IfElse( @@ -237,7 +317,7 @@ pub fn fold_struct_expression_inner<'ast, T: Field, F: Folder<'ast, T>>( } StructExpressionInner::Select(box array, box index) => { let array = f.fold_array_expression(array); - let index = f.fold_field_expression(index); + let index = f.fold_uint_expression(index); StructExpressionInner::Select(box array, box index) } } @@ -274,18 +354,32 @@ pub fn fold_field_expression<'ast, T: Field, F: Folder<'ast, T>>( } FieldElementExpression::Pow(box e1, box e2) => { let e1 = f.fold_field_expression(e1); - let e2 = f.fold_field_expression(e2); + let e2 = f.fold_uint_expression(e2); FieldElementExpression::Pow(box e1, box e2) } + FieldElementExpression::Neg(box e) => { + let e = f.fold_field_expression(e); + + FieldElementExpression::Neg(box e) + } + FieldElementExpression::Pos(box e) => { + let e = f.fold_field_expression(e); + + FieldElementExpression::Pos(box e) + } FieldElementExpression::IfElse(box cond, box cons, box alt) => { let cond = f.fold_boolean_expression(cond); let cons = f.fold_field_expression(cons); let alt = f.fold_field_expression(alt); FieldElementExpression::IfElse(box cond, box cons, box alt) } - FieldElementExpression::FunctionCall(key, exps) => { + FieldElementExpression::FunctionCall(key, generics, exps) => { + let generics = generics + .into_iter() + .map(|g| g.map(|g| f.fold_uint_expression(g))) + .collect(); let exps = exps.into_iter().map(|e| f.fold_expression(e)).collect(); - FieldElementExpression::FunctionCall(key, exps) + FieldElementExpression::FunctionCall(key, generics, exps) } FieldElementExpression::Member(box s, id) => { let s = f.fold_struct_expression(s); @@ -293,12 +387,19 @@ pub fn fold_field_expression<'ast, T: Field, F: Folder<'ast, T>>( } FieldElementExpression::Select(box array, box index) => { let array = f.fold_array_expression(array); - let index = f.fold_field_expression(index); + let index = f.fold_uint_expression(index); FieldElementExpression::Select(box array, box index) } } } +pub fn fold_int_expression<'ast, T: Field, F: Folder<'ast, T>>( + _: &mut F, + _: IntExpression<'ast, T>, +) -> IntExpression<'ast, T> { + unreachable!() +} + pub fn fold_boolean_expression<'ast, T: Field, F: Folder<'ast, T>>( f: &mut F, e: BooleanExpression<'ast, T>, @@ -331,25 +432,45 @@ pub fn fold_boolean_expression<'ast, T: Field, F: Folder<'ast, T>>( let e2 = f.fold_uint_expression(e2); BooleanExpression::UintEq(box e1, box e2) } - BooleanExpression::Lt(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::Lt(box e1, box e2) + BooleanExpression::FieldLt(box e1, box e2) } - BooleanExpression::Le(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::Le(box e1, box e2) + BooleanExpression::FieldLe(box e1, box e2) } - BooleanExpression::Gt(box e1, box e2) => { + BooleanExpression::FieldGt(box e1, box e2) => { let e1 = f.fold_field_expression(e1); let e2 = f.fold_field_expression(e2); - BooleanExpression::Gt(box e1, box e2) + BooleanExpression::FieldGt(box e1, box e2) } - BooleanExpression::Ge(box e1, box e2) => { + BooleanExpression::FieldGe(box e1, box e2) => { let e1 = f.fold_field_expression(e1); let e2 = f.fold_field_expression(e2); - BooleanExpression::Ge(box e1, box e2) + BooleanExpression::FieldGe(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::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::UintGt(box e1, box e2) => { + let e1 = f.fold_uint_expression(e1); + let e2 = f.fold_uint_expression(e2); + BooleanExpression::UintGt(box e1, box e2) + } + BooleanExpression::UintGe(box e1, box e2) => { + let e1 = f.fold_uint_expression(e1); + let e2 = f.fold_uint_expression(e2); + BooleanExpression::UintGe(box e1, box e2) } BooleanExpression::Or(box e1, box e2) => { let e1 = f.fold_boolean_expression(e1); @@ -365,9 +486,13 @@ pub fn fold_boolean_expression<'ast, T: Field, F: Folder<'ast, T>>( let e = f.fold_boolean_expression(e); BooleanExpression::Not(box e) } - BooleanExpression::FunctionCall(key, exps) => { + BooleanExpression::FunctionCall(key, generics, exps) => { + let generics = generics + .into_iter() + .map(|g| g.map(|g| f.fold_uint_expression(g))) + .collect(); let exps = exps.into_iter().map(|e| f.fold_expression(e)).collect(); - BooleanExpression::FunctionCall(key, exps) + BooleanExpression::FunctionCall(key, generics, exps) } BooleanExpression::IfElse(box cond, box cons, box alt) => { let cond = f.fold_boolean_expression(cond); @@ -381,7 +506,7 @@ pub fn fold_boolean_expression<'ast, T: Field, F: Folder<'ast, T>>( } BooleanExpression::Select(box array, box index) => { let array = f.fold_array_expression(array); - let index = f.fold_field_expression(index); + let index = f.fold_uint_expression(index); BooleanExpression::Select(box array, box index) } } @@ -417,6 +542,12 @@ pub fn fold_uint_expression_inner<'ast, T: Field, F: Folder<'ast, T>>( UExpressionInner::Sub(box left, box right) } + UExpressionInner::FloorSub(box left, box right) => { + let left = f.fold_uint_expression(left); + let right = f.fold_uint_expression(right); + + UExpressionInner::FloorSub(box left, box right) + } UExpressionInner::Mult(box left, box right) => { let left = f.fold_uint_expression(left); let right = f.fold_uint_expression(right); @@ -455,13 +586,13 @@ pub fn fold_uint_expression_inner<'ast, T: Field, F: Folder<'ast, T>>( } UExpressionInner::LeftShift(box e, box by) => { let e = f.fold_uint_expression(e); - let by = f.fold_field_expression(by); + let by = f.fold_uint_expression(by); UExpressionInner::LeftShift(box e, box by) } UExpressionInner::RightShift(box e, box by) => { let e = f.fold_uint_expression(e); - let by = f.fold_field_expression(by); + let by = f.fold_uint_expression(by); UExpressionInner::RightShift(box e, box by) } @@ -470,13 +601,27 @@ pub fn fold_uint_expression_inner<'ast, T: Field, F: Folder<'ast, T>>( UExpressionInner::Not(box e) } - UExpressionInner::FunctionCall(key, exps) => { + UExpressionInner::Neg(box e) => { + let e = f.fold_uint_expression(e); + + UExpressionInner::Neg(box e) + } + UExpressionInner::Pos(box e) => { + let e = f.fold_uint_expression(e); + + UExpressionInner::Pos(box e) + } + UExpressionInner::FunctionCall(key, generics, exps) => { + let generics = generics + .into_iter() + .map(|g| g.map(|g| f.fold_uint_expression(g))) + .collect(); let exps = exps.into_iter().map(|e| f.fold_expression(e)).collect(); - UExpressionInner::FunctionCall(key, exps) + UExpressionInner::FunctionCall(key, generics, exps) } UExpressionInner::Select(box array, box index) => { let array = f.fold_array_expression(array); - let index = f.fold_field_expression(index); + let index = f.fold_uint_expression(index); UExpressionInner::Select(box array, box index) } UExpressionInner::IfElse(box cond, box cons, box alt) => { @@ -515,9 +660,44 @@ pub fn fold_array_expression<'ast, T: Field, F: Folder<'ast, T>>( f: &mut F, e: ArrayExpression<'ast, T>, ) -> ArrayExpression<'ast, T> { + let ty = f.fold_array_type(*e.ty); + ArrayExpression { - inner: f.fold_array_expression_inner(&e.ty, e.size, e.inner), - ..e + inner: f.fold_array_expression_inner(&ty, e.inner), + ty: box ty, + } +} + +pub fn fold_expression_list<'ast, T: Field, F: Folder<'ast, T>>( + f: &mut F, + es: TypedExpressionList<'ast, T>, +) -> TypedExpressionList<'ast, T> { + match es { + TypedExpressionList::FunctionCall(id, generics, arguments, types) => { + TypedExpressionList::FunctionCall( + id, + generics + .into_iter() + .map(|g| g.map(|g| f.fold_uint_expression(g))) + .collect(), + arguments + .into_iter() + .map(|a| f.fold_expression(a)) + .collect(), + types.into_iter().map(|t| f.fold_type(t)).collect(), + ) + } + TypedExpressionList::EmbedCall(embed, generics, arguments, types) => { + TypedExpressionList::EmbedCall( + embed, + generics, + arguments + .into_iter() + .map(|a| f.fold_expression(a)) + .collect(), + types.into_iter().map(|t| f.fold_type(t)).collect(), + ) + } } } @@ -548,7 +728,7 @@ pub fn fold_assignee<'ast, T: Field, F: Folder<'ast, T>>( match a { TypedAssignee::Identifier(v) => TypedAssignee::Identifier(f.fold_variable(v)), TypedAssignee::Select(box a, box index) => { - TypedAssignee::Select(box f.fold_assignee(a), box f.fold_field_expression(index)) + TypedAssignee::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), } diff --git a/zokrates_core/src/typed_absy/identifier.rs b/zokrates_core/src/typed_absy/identifier.rs index eef72c202..145950e08 100644 --- a/zokrates_core/src/typed_absy/identifier.rs +++ b/zokrates_core/src/typed_absy/identifier.rs @@ -1,12 +1,11 @@ -use crate::typed_absy::types::FunctionKeyHash; -use crate::typed_absy::TypedModuleId; +use std::convert::TryInto; use std::fmt; #[derive(Debug, PartialEq, Clone, Hash, Eq)] pub enum CoreIdentifier<'ast> { Source(&'ast str), Internal(&'static str, usize), - Call(FunctionKeyHash, usize), + Call(usize), } impl<'ast> fmt::Display for CoreIdentifier<'ast> { @@ -14,11 +13,17 @@ impl<'ast> fmt::Display for CoreIdentifier<'ast> { match self { CoreIdentifier::Source(s) => write!(f, "{}", s), CoreIdentifier::Internal(s, i) => write!(f, "#INTERNAL#_{}_{}", s, i), - CoreIdentifier::Call(k, i) => write!(f, "{:x}_{}", k, i), + CoreIdentifier::Call(i) => write!(f, "#CALL_RETURN_AT_INDEX_{}", i), } } } +impl<'ast> From<&'ast str> for CoreIdentifier<'ast> { + fn from(s: &str) -> CoreIdentifier { + CoreIdentifier::Source(s) + } +} + /// A identifier for a variable #[derive(Debug, PartialEq, Clone, Hash, Eq)] pub struct Identifier<'ast> { @@ -26,31 +31,25 @@ pub struct Identifier<'ast> { pub id: CoreIdentifier<'ast>, /// the version of the variable, used after SSA transformation pub version: usize, - /// the call stack of the variable, used when inlining - pub stack: Vec<(TypedModuleId, FunctionKeyHash, usize)>, +} + +impl<'ast> TryInto<&'ast str> for Identifier<'ast> { + type Error = (); + + fn try_into(self) -> Result<&'ast str, Self::Error> { + match self.id { + CoreIdentifier::Source(i) => Ok(i), + _ => Err(()), + } + } } impl<'ast> fmt::Display for Identifier<'ast> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if self.stack.len() == 0 && self.version == 0 { + if self.version == 0 { write!(f, "{}", self.id) } else { - write!( - f, - "{}_{}_{}", - self.stack - .iter() - .map(|(name, key_hash, count)| format!( - "{}_{}_{}", - name.display(), - key_hash, - count - )) - .collect::>() - .join("_"), - self.id, - self.version - ) + write!(f, "{}_{}", self.id, self.version) } } } @@ -63,23 +62,13 @@ impl<'ast> From<&'ast str> for Identifier<'ast> { impl<'ast> From> for Identifier<'ast> { fn from(id: CoreIdentifier<'ast>) -> Identifier<'ast> { - Identifier { - id, - version: 0, - stack: vec![], - } + Identifier { id, version: 0 } } } -#[cfg(test)] impl<'ast> Identifier<'ast> { pub fn version(mut self, version: usize) -> Self { self.version = version; self } - - pub fn stack(mut self, stack: Vec<(TypedModuleId, FunctionKeyHash, usize)>) -> Self { - self.stack = stack; - self - } } diff --git a/zokrates_core/src/typed_absy/integer.rs b/zokrates_core/src/typed_absy/integer.rs new file mode 100644 index 000000000..6a30cafa7 --- /dev/null +++ b/zokrates_core/src/typed_absy/integer.rs @@ -0,0 +1,675 @@ +use crate::typed_absy::types::{ArrayType, Type}; +use crate::typed_absy::UBitwidth; +use crate::typed_absy::{ + ArrayExpression, ArrayExpressionInner, BooleanExpression, FieldElementExpression, IfElse, + Select, StructExpression, Typed, TypedExpression, TypedExpressionOrSpread, TypedSpread, + UExpression, UExpressionInner, +}; +use num_bigint::BigUint; +use std::convert::TryFrom; +use std::fmt; +use std::ops::{Add, Div, Mul, Neg, Not, Rem, Sub}; +use zokrates_field::Field; + +type TypedExpressionPair<'ast, T> = (TypedExpression<'ast, T>, TypedExpression<'ast, T>); + +impl<'ast, T: Field> TypedExpressionOrSpread<'ast, T> { + pub fn align_to_type(e: Self, ty: Type<'ast, T>) -> Result)> { + match e { + TypedExpressionOrSpread::Expression(e) => TypedExpression::align_to_type(e, ty) + .map(|e| e.into()) + .map_err(|(e, t)| (e.into(), t)), + TypedExpressionOrSpread::Spread(s) => { + ArrayExpression::try_from_int(s.array, ty.clone()) + .map(|e| TypedExpressionOrSpread::Spread(TypedSpread { array: e })) + .map_err(|e| (e.into(), ty)) + } + } + } +} + +impl<'ast, T: Field> TypedExpression<'ast, T> { + // return two TypedExpression, replacing IntExpression by FieldElement or Uint to try to align the two types if possible. + // Post condition is that (lhs, rhs) cannot be made equal by further removing IntExpressions + pub fn align_without_integers( + lhs: Self, + rhs: Self, + ) -> Result, TypedExpressionPair<'ast, T>> { + use self::TypedExpression::*; + + match (lhs, rhs) { + (Int(lhs), FieldElement(rhs)) => Ok(( + FieldElementExpression::try_from_int(lhs) + .map_err(|lhs| (lhs.into(), rhs.clone().into()))? + .into(), + FieldElement(rhs), + )), + (FieldElement(lhs), Int(rhs)) => Ok(( + FieldElement(lhs.clone()), + FieldElementExpression::try_from_int(rhs) + .map_err(|rhs| (lhs.into(), rhs.into()))? + .into(), + )), + (Int(lhs), Uint(rhs)) => Ok(( + UExpression::try_from_int(lhs, rhs.bitwidth()) + .map_err(|lhs| (lhs.into(), rhs.clone().into()))? + .into(), + Uint(rhs), + )), + (Uint(lhs), Int(rhs)) => { + let bitwidth = lhs.bitwidth(); + Ok(( + Uint(lhs.clone()), + UExpression::try_from_int(rhs, bitwidth) + .map_err(|rhs| (lhs.into(), rhs.into()))? + .into(), + )) + } + (Array(lhs), Array(rhs)) => { + fn get_common_type<'a, T: Field>( + t: Type<'a, T>, + u: Type<'a, T>, + ) -> Result, ()> { + match (t, u) { + (Type::Int, Type::Int) => Err(()), + (Type::Int, u) => Ok(u), + (t, Type::Int) => Ok(t), + (Type::Array(t), Type::Array(u)) => Ok(Type::Array(ArrayType::new( + get_common_type(*t.ty, *u.ty)?, + t.size, + ))), + (t, _) => Ok(t), + } + } + + let common_type = + get_common_type(lhs.inner_type().clone(), rhs.inner_type().clone()) + .map_err(|_| (lhs.clone().into(), rhs.clone().into()))?; + + Ok(( + ArrayExpression::try_from_int(lhs.clone(), common_type.clone()) + .map_err(|lhs| (lhs.clone(), rhs.clone().into()))? + .into(), + ArrayExpression::try_from_int(rhs, common_type) + .map_err(|rhs| (lhs.clone().into(), rhs.clone()))? + .into(), + )) + } + (Struct(lhs), Struct(rhs)) => { + if lhs.get_type() == rhs.get_type() { + Ok((Struct(lhs), Struct(rhs))) + } else { + Err((Struct(lhs), Struct(rhs))) + } + } + (Uint(lhs), Uint(rhs)) => Ok((lhs.into(), rhs.into())), + (Boolean(lhs), Boolean(rhs)) => Ok((lhs.into(), rhs.into())), + (FieldElement(lhs), FieldElement(rhs)) => Ok((lhs.into(), rhs.into())), + (Int(lhs), Int(rhs)) => Ok((lhs.into(), rhs.into())), + (lhs, rhs) => Err((lhs, rhs)), + } + } + + pub fn align_to_type(e: Self, ty: Type<'ast, T>) -> Result)> { + match ty.clone() { + Type::FieldElement => { + FieldElementExpression::try_from_typed(e).map(TypedExpression::from) + } + Type::Boolean => BooleanExpression::try_from_typed(e).map(TypedExpression::from), + Type::Uint(bitwidth) => { + UExpression::try_from_typed(e, bitwidth).map(TypedExpression::from) + } + Type::Array(array_ty) => { + ArrayExpression::try_from_typed(e, *array_ty.ty).map(TypedExpression::from) + } + Type::Struct(struct_ty) => { + StructExpression::try_from_typed(e, struct_ty).map(TypedExpression::from) + } + Type::Int => Err(e), + } + .map_err(|e| (e, ty)) + } +} + +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +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>), + IfElse( + Box>, + Box>, + Box>, + ), + Select(Box>, Box>), + 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) + } +} + +impl<'ast, T> Sub for IntExpression<'ast, T> { + type Output = Self; + + fn sub(self, other: Self) -> Self { + IntExpression::Sub(box self, box other) + } +} + +impl<'ast, T> Mul for IntExpression<'ast, T> { + type Output = Self; + + fn mul(self, other: Self) -> Self { + IntExpression::Mult(box self, box other) + } +} + +impl<'ast, T> Div for IntExpression<'ast, T> { + type Output = Self; + + fn div(self, other: Self) -> Self { + IntExpression::Div(box self, box other) + } +} + +impl<'ast, T> Rem for IntExpression<'ast, T> { + type Output = Self; + + fn rem(self, other: Self) -> Self { + IntExpression::Rem(box self, box other) + } +} + +impl<'ast, T> Not for IntExpression<'ast, T> { + type Output = Self; + + fn not(self) -> Self { + IntExpression::Not(box self) + } +} + +impl<'ast, T> Neg for IntExpression<'ast, T> { + type Output = Self; + + fn neg(self) -> Self { + IntExpression::Neg(box self) + } +} + +impl<'ast, T> IntExpression<'ast, T> { + pub fn pow(self, other: Self) -> Self { + IntExpression::Pow(box self, box other) + } + + pub fn and(self, other: Self) -> Self { + IntExpression::And(box self, box other) + } + + pub fn xor(self, other: Self) -> Self { + IntExpression::Xor(box self, box other) + } + + pub fn or(self, other: Self) -> Self { + IntExpression::Or(box self, box other) + } + + pub fn left_shift(self, by: UExpression<'ast, T>) -> Self { + IntExpression::LeftShift(box self, box by) + } + + pub fn right_shift(self, by: UExpression<'ast, T>) -> Self { + IntExpression::RightShift(box self, box by) + } + + pub fn pos(self) -> Self { + IntExpression::Pos(box self) + } +} + +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::Select(ref id, ref index) => write!(f, "{}[{}]", id, index), + 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::IfElse(ref condition, ref consequent, ref alternative) => write!( + f, + "if {} then {} else {} fi", + condition, consequent, alternative + ), + } + } +} + +impl<'ast, T: Field> BooleanExpression<'ast, T> { + pub fn try_from_typed(e: TypedExpression<'ast, T>) -> Result> { + match e { + TypedExpression::Boolean(e) => Ok(e), + e => Err(e), + } + } +} + +impl<'ast, T: Field> FieldElementExpression<'ast, T> { + pub fn try_from_typed(e: TypedExpression<'ast, T>) -> Result> { + match e { + TypedExpression::FieldElement(e) => Ok(e), + TypedExpression::Int(e) => { + Self::try_from_int(e.clone()).map_err(|_| TypedExpression::Int(e)) + } + e => Err(e), + } + } + + pub fn try_from_int(i: IntExpression<'ast, T>) -> Result> { + 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::Sub(box e1, box e2) => Ok(Self::Sub( + box Self::try_from_int(e1)?, + box Self::try_from_int(e2)?, + )), + IntExpression::Mult(box e1, box e2) => Ok(Self::Mult( + box Self::try_from_int(e1)?, + box Self::try_from_int(e2)?, + )), + IntExpression::Pow(box e1, box e2) => Ok(Self::Pow( + box Self::try_from_int(e1)?, + box UExpression::try_from_int(e2, UBitwidth::B32)?, + )), + IntExpression::Div(box e1, box e2) => Ok(Self::Div( + box Self::try_from_int(e1)?, + box Self::try_from_int(e2)?, + )), + 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::IfElse(box condition, box consequence, box alternative) => { + Ok(Self::IfElse( + box condition, + box Self::try_from_int(consequence)?, + box Self::try_from_int(alternative)?, + )) + } + IntExpression::Select(box array, box index) => { + let size = array.size(); + + match array.into_inner() { + ArrayExpressionInner::Value(values) => { + let values = values + .into_iter() + .map(|v| { + TypedExpressionOrSpread::align_to_type(v, Type::FieldElement) + .map_err(|(e, _)| match e { + TypedExpressionOrSpread::Expression(e) => { + IntExpression::try_from(e).unwrap() + } + TypedExpressionOrSpread::Spread(a) => { + IntExpression::select(a.array, 0u32) + } + }) + }) + .collect::, _>>()?; + Ok(FieldElementExpression::select( + ArrayExpressionInner::Value(values.into()) + .annotate(Type::FieldElement, size), + index, + )) + } + _ => unreachable!(), + } + } + i => Err(i), + } + } +} + +impl<'ast, T: Field> UExpression<'ast, T> { + pub fn try_from_typed( + e: TypedExpression<'ast, T>, + bitwidth: UBitwidth, + ) -> Result> { + match e { + TypedExpression::Uint(e) => match e.bitwidth == bitwidth { + true => Ok(e), + _ => Err(TypedExpression::Uint(e)), + }, + TypedExpression::Int(e) => { + Self::try_from_int(e.clone(), bitwidth).map_err(|_| TypedExpression::Int(e)) + } + e => Err(e), + } + } + + pub fn try_from_int( + i: IntExpression<'ast, T>, + bitwidth: UBitwidth, + ) -> Result> { + use self::IntExpression::*; + + 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(), + ) + .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)?, + )), + Or(box e1, box e2) => Ok(UExpression::or( + Self::try_from_int(e1, bitwidth)?, + Self::try_from_int(e2, 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)?, + )), + RightShift(box e1, box e2) => Ok(UExpression::right_shift( + Self::try_from_int(e1, bitwidth)?, + e2, + )), + LeftShift(box e1, box e2) => Ok(UExpression::left_shift( + Self::try_from_int(e1, bitwidth)?, + e2, + )), + IfElse(box condition, box consequence, box alternative) => Ok(UExpression::if_else( + condition, + Self::try_from_int(consequence, bitwidth)?, + Self::try_from_int(alternative, bitwidth)?, + )), + Select(box array, box index) => { + let size = array.size(); + match array.into_inner() { + ArrayExpressionInner::Value(values) => { + let values = values + .into_iter() + .map(|v| { + TypedExpressionOrSpread::align_to_type(v, Type::Uint(bitwidth)) + .map_err(|(e, _)| match e { + TypedExpressionOrSpread::Expression(e) => { + IntExpression::try_from(e).unwrap() + } + TypedExpressionOrSpread::Spread(a) => { + IntExpression::select(a.array, 0u32) + } + }) + }) + .collect::, _>>()?; + Ok(UExpression::select( + ArrayExpressionInner::Value(values.into()) + .annotate(Type::Uint(bitwidth), size), + index, + )) + } + _ => unreachable!(), + } + } + i => Err(i), + } + } +} + +impl<'ast, T: Field> ArrayExpression<'ast, T> { + pub fn try_from_typed( + e: TypedExpression<'ast, T>, + target_inner_ty: Type<'ast, T>, + ) -> Result> { + match e { + TypedExpression::Array(e) => Self::try_from_int(e.clone(), target_inner_ty) + .map_err(|_| TypedExpression::Array(e)), + e => Err(e), + } + } + + // precondition: `array` is only made of inline arrays unless it does not contain the Integer type + pub fn try_from_int( + array: Self, + target_inner_ty: Type<'ast, T>, + ) -> Result> { + let array_ty = array.get_array_type(); + + // elements must fit in the target type + match array.into_inner() { + ArrayExpressionInner::Value(inline_array) => { + let res = match target_inner_ty.clone() { + Type::Int => Ok(inline_array), + t => { + // try to convert all elements to the target type + inline_array + .into_iter() + .map(|v| { + TypedExpressionOrSpread::align_to_type(v, t.clone()).map_err( + |(e, _)| match e { + TypedExpressionOrSpread::Expression(e) => e, + TypedExpressionOrSpread::Spread(a) => { + TypedExpression::select(a.array, 0u32) + } + }, + ) + }) + .collect::, _>>() + .map(|v| v.into()) + } + }?; + + let inner_ty = res.0[0].get_type().0; + + Ok(ArrayExpressionInner::Value(res).annotate(inner_ty, array_ty.size)) + } + ArrayExpressionInner::Repeat(box e, box count) => { + match target_inner_ty.clone() { + Type::Int => Ok(ArrayExpressionInner::Repeat(box e, box count) + .annotate(Type::Int, array_ty.size)), + // try to convert the repeated element to the target type + t => TypedExpression::align_to_type(e, t) + .map(|e| { + ArrayExpressionInner::Repeat(box e, box count) + .annotate(target_inner_ty, array_ty.size) + }) + .map_err(|(e, _)| e), + } + } + a => { + if array_ty.ty.weak_eq(&target_inner_ty) { + Ok(a.annotate(*array_ty.ty, array_ty.size)) + } else { + Err(a.annotate(*array_ty.ty, array_ty.size).into()) + } + } + } + } +} + +impl<'ast, T> From for IntExpression<'ast, T> { + fn from(v: BigUint) -> Self { + IntExpression::Value(v) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use zokrates_field::Bn128Field; + + #[test] + 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); + let t: FieldElementExpression = Bn128Field::from(42).into(); + let t_a: ArrayExpression = + ArrayExpressionInner::Value(vec![t.clone().into()].into()) + .annotate(Type::FieldElement, 1u32); + let i: UExpression = 42u32.into(); + let c: BooleanExpression = true.into(); + + let expressions = vec![ + n.clone(), + n.clone() + n.clone(), + n.clone() - n.clone(), + n.clone() * n.clone(), + IntExpression::pow(n.clone(), n.clone()), + n.clone() / n.clone(), + IntExpression::if_else(c.clone(), n.clone(), n.clone()), + IntExpression::select(n_a.clone(), i.clone()), + ]; + + let expected = vec![ + t.clone(), + t.clone() + t.clone(), + t.clone() - t.clone(), + t.clone() * t.clone(), + FieldElementExpression::pow(t.clone(), i.clone()), + t.clone() / t.clone(), + FieldElementExpression::if_else(c.clone(), t.clone(), t.clone()), + FieldElementExpression::select(t_a.clone(), i.clone()), + ]; + + assert_eq!( + expressions + .into_iter() + .map(|e| FieldElementExpression::try_from_int(e).unwrap()) + .collect::>(), + expected + ); + + let should_error = vec![ + BigUint::parse_bytes(b"99999999999999999999999999999999999999999999999999999999999999999999999999999999999", 10).unwrap().into(), + IntExpression::xor(n.clone(), n.clone()), + IntExpression::or(n.clone(), n.clone()), + IntExpression::and(n.clone(), n.clone()), + IntExpression::left_shift(n.clone(), i.clone()), + IntExpression::right_shift(n.clone(), i.clone()), + IntExpression::not(n.clone()), + ]; + + for e in should_error + .into_iter() + .map(FieldElementExpression::try_from_int) + { + assert!(e.is_err()); + } + } + + #[test] + 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); + let t: UExpression = 42u32.into(); + let t_a: ArrayExpression = + ArrayExpressionInner::Value(vec![t.clone().into()].into()) + .annotate(Type::Uint(UBitwidth::B32), 1u32); + let i: UExpression = 0u32.into(); + let c: BooleanExpression = true.into(); + + let expressions = vec![ + n.clone(), + n.clone() + n.clone(), + IntExpression::xor(n.clone(), n.clone()), + IntExpression::or(n.clone(), n.clone()), + IntExpression::and(n.clone(), n.clone()), + n.clone() - n.clone(), + n.clone() * n.clone(), + n.clone() / n.clone(), + n.clone() % n.clone(), + IntExpression::left_shift(n.clone(), i.clone()), + IntExpression::right_shift(n.clone(), i.clone()), + !n.clone(), + IntExpression::if_else(c.clone(), n.clone(), n.clone()), + IntExpression::select(n_a.clone(), i.clone()), + ]; + + let expected = vec![ + t.clone(), + t.clone() + t.clone(), + UExpression::xor(t.clone(), t.clone()), + UExpression::or(t.clone(), t.clone()), + UExpression::and(t.clone(), t.clone()), + t.clone() - t.clone(), + t.clone() * t.clone(), + t.clone() / t.clone(), + t.clone() % t.clone(), + UExpression::left_shift(t.clone(), i.clone()), + UExpression::right_shift(t.clone(), i.clone()), + !t.clone(), + UExpression::if_else(c.clone(), t.clone(), t.clone()), + UExpression::select(t_a.clone(), i.clone()), + ]; + + for (r, e) in expressions + .into_iter() + .map(|e| UExpression::try_from_int(e, UBitwidth::B32).unwrap()) + .zip(expected) + { + assert_eq!(r, e); + } + + let should_error = vec![ + BigUint::parse_bytes(b"99999999999999999999999999999999999999999999999999999999999999999999999999999999999", 10).unwrap().into(), + IntExpression::pow(n.clone(), n.clone()), + ]; + + for e in should_error + .into_iter() + .map(|e| UExpression::try_from_int(e, UBitwidth::B32)) + { + assert!(e.is_err()); + } + } +} diff --git a/zokrates_core/src/typed_absy/mod.rs b/zokrates_core/src/typed_absy/mod.rs index 0bb7f7c93..7b5935da7 100644 --- a/zokrates_core/src/typed_absy/mod.rs +++ b/zokrates_core/src/typed_absy/mod.rs @@ -8,48 +8,70 @@ pub mod abi; pub mod folder; pub mod identifier; +pub mod result_folder; +mod integer; mod parameter; pub mod types; mod uint; mod variable; pub use self::identifier::CoreIdentifier; -pub use self::parameter::Parameter; -pub use self::types::{Signature, StructType, Type, UBitwidth}; -pub use self::variable::Variable; +pub use self::parameter::{DeclarationParameter, GParameter}; +pub use self::types::{ + ConcreteFunctionKey, ConcreteSignature, ConcreteType, DeclarationFunctionKey, + DeclarationSignature, DeclarationType, GArrayType, GStructType, GType, GenericIdentifier, + Signature, StructType, Type, UBitwidth, +}; +use crate::typed_absy::types::ConcreteGenericsAssignment; + +pub use self::variable::{ConcreteVariable, DeclarationVariable, GVariable, Variable}; +use std::path::{Path, PathBuf}; + +pub use crate::typed_absy::integer::IntExpression; pub use crate::typed_absy::uint::{bitwidth, UExpression, UExpressionInner, UMetadata}; -use std::path::PathBuf; use crate::embed::FlatEmbed; -use crate::typed_absy::types::{FunctionKey, MemberId}; + use std::collections::HashMap; -use std::convert::TryFrom; +use std::convert::{TryFrom, TryInto}; use std::fmt; + +pub use crate::typed_absy::types::{ArrayType, FunctionKey, MemberId}; + use zokrates_field::Field; pub use self::folder::Folder; use crate::typed_absy::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 TypedModuleId = PathBuf; +pub type OwnedTypedModuleId = PathBuf; +pub type TypedModuleId = Path; /// A collection of `TypedModule`s -pub type TypedModules<'ast, T> = HashMap>; +pub type TypedModules<'ast, T> = HashMap>; /// A collection of `TypedFunctionSymbol`s /// # Remarks /// * It is the role of the semantic checker to make sure there are no duplicates for a given `FunctionKey` /// in a given `TypedModule`, hence the use of a HashMap -pub type TypedFunctionSymbols<'ast, T> = HashMap, TypedFunctionSymbol<'ast, T>>; +pub type TypedFunctionSymbols<'ast, T> = + HashMap, TypedFunctionSymbol<'ast, T>>; /// A typed program as a collection of modules, one of them being the main #[derive(PartialEq, Debug, Clone)] pub struct TypedProgram<'ast, T> { pub modules: TypedModules<'ast, T>, - pub main: TypedModuleId, + pub main: OwnedTypedModuleId, +} + +impl<'ast, T> TypedProgram<'ast, T> { + pub fn main_function(&self) -> TypedFunction<'ast, T> { + unimplemented!() + } } impl<'ast, T: Field> TypedProgram<'ast, T> { @@ -69,13 +91,24 @@ impl<'ast, T: Field> TypedProgram<'ast, T> { inputs: main .arguments .iter() - .map(|p| AbiInput { - public: !p.private, - name: p.id.id.to_string(), - ty: p.id._type.clone(), + .map(|p| { + types::ConcreteType::try_from(types::Type::::from(p.id._type.clone())) + .map(|ty| AbiInput { + public: !p.private, + name: p.id.id.to_string(), + ty, + }) + .unwrap() + }) + .collect(), + outputs: main + .signature + .outputs + .iter() + .map(|ty| { + types::ConcreteType::try_from(types::Type::::from(ty.clone())).unwrap() }) .collect(), - outputs: main.signature.outputs.clone(), } } } @@ -96,7 +129,7 @@ impl<'ast, T: fmt::Display> fmt::Display for TypedProgram<'ast, T> { writeln!(f, "{}", "-".repeat(100))?; writeln!(f, "{}", module)?; writeln!(f, "{}", "-".repeat(100))?; - writeln!(f, "")?; + writeln!(f)?; } write!(f, "") } @@ -112,7 +145,7 @@ pub struct TypedModule<'ast, T> { #[derive(Clone, PartialEq)] pub enum TypedFunctionSymbol<'ast, T> { Here(TypedFunction<'ast, T>), - There(FunctionKey<'ast>, TypedModuleId), + There(DeclarationFunctionKey<'ast>), Flat(FlatEmbed), } @@ -121,24 +154,26 @@ impl<'ast, T: fmt::Debug> fmt::Debug for TypedFunctionSymbol<'ast, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { TypedFunctionSymbol::Here(s) => write!(f, "Here({:?})", s), - TypedFunctionSymbol::There(key, module) => write!(f, "There({:?}, {:?})", key, module), + TypedFunctionSymbol::There(key) => write!(f, "There({:?})", key), TypedFunctionSymbol::Flat(s) => write!(f, "Flat({:?})", s), } } } impl<'ast, T: Field> TypedFunctionSymbol<'ast, T> { - pub fn signature<'a>(&'a self, modules: &'a TypedModules) -> Signature { + pub fn signature<'a>( + &'a self, + modules: &'a TypedModules<'ast, T>, + ) -> DeclarationSignature<'ast> { match self { TypedFunctionSymbol::Here(f) => f.signature.clone(), - TypedFunctionSymbol::There(key, module_id) => modules - .get(module_id) + TypedFunctionSymbol::There(key) => modules + .get(&key.module) .unwrap() .functions .get(key) .unwrap() - .signature(&modules) - .clone(), + .signature(&modules), TypedFunctionSymbol::Flat(flat_fun) => flat_fun.signature(), } } @@ -151,10 +186,10 @@ impl<'ast, T: fmt::Display> fmt::Display for TypedModule<'ast, T> { .iter() .map(|(key, symbol)| match symbol { TypedFunctionSymbol::Here(ref function) => format!("def {}{}", key.id, function), - TypedFunctionSymbol::There(ref fun_key, ref module_id) => format!( + TypedFunctionSymbol::There(ref fun_key) => format!( "import {} from \"{}\" as {} // with signature {}", fun_key.id, - module_id.display(), + fun_key.module.display(), key.id, key.signature ), @@ -182,18 +217,30 @@ impl<'ast, T: fmt::Debug> fmt::Debug for TypedModule<'ast, T> { } /// A typed function -#[derive(Clone, PartialEq)] +#[derive(Clone, PartialEq, Hash)] pub struct TypedFunction<'ast, T> { /// Arguments of the function - pub arguments: Vec>, + pub arguments: Vec>, /// Vector of statements that are executed when running the function pub statements: Vec>, /// function signature - pub signature: Signature, + pub signature: DeclarationSignature<'ast>, } impl<'ast, T: fmt::Display> fmt::Display for TypedFunction<'ast, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if !self.signature.generics.is_empty() { + write!( + f, + "<{}>", + self.signature + .generics + .iter() + .map(|g| g.as_ref().unwrap().to_string()) + .collect::>() + .join(", ") + )?; + } write!( f, "({})", @@ -211,7 +258,7 @@ impl<'ast, T: fmt::Display> fmt::Display for TypedFunction<'ast, T> { 0 => "".into(), 1 => format!(" -> {}", self.signature.outputs[0]), _ => format!( - "{}", + " -> ({})", self.signature .outputs .iter() @@ -222,11 +269,21 @@ impl<'ast, T: fmt::Display> fmt::Display for TypedFunction<'ast, T> { } )?; - writeln!(f, "")?; + writeln!(f)?; + + let mut tab = 0; for s in &self.statements { - s.fmt_indented(f, 1)?; - writeln!(f, "")?; + if let TypedStatement::PopCallLog = s { + tab -= 1; + }; + + s.fmt_indented(f, 1 + tab)?; + writeln!(f)?; + + if let TypedStatement::PushCallLog(..) = s { + tab += 1; + }; } Ok(()) @@ -237,7 +294,8 @@ impl<'ast, T: fmt::Debug> fmt::Debug for TypedFunction<'ast, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, - "TypedFunction(arguments: {:?}, ...):\n{}", + "TypedFunction(signature: {:?}, arguments: {:?}, ...):\n{}", + self.signature, self.arguments, self.statements .iter() @@ -251,22 +309,89 @@ impl<'ast, T: fmt::Debug> fmt::Debug for TypedFunction<'ast, T> { /// Something we can assign to. #[derive(Clone, PartialEq, Hash, Eq)] pub enum TypedAssignee<'ast, T> { - Identifier(Variable<'ast>), - Select( - Box>, - Box>, - ), + Identifier(Variable<'ast, T>), + Select(Box>, Box>), Member(Box>, MemberId), } -impl<'ast, T> From> for TypedAssignee<'ast, T> { - fn from(v: Variable<'ast>) -> Self { +#[derive(Clone, PartialEq, Hash, Eq, Debug)] +pub struct TypedSpread<'ast, T> { + pub array: ArrayExpression<'ast, T>, +} + +impl<'ast, T> From> for TypedSpread<'ast, T> { + fn from(array: ArrayExpression<'ast, T>) -> TypedSpread<'ast, T> { + TypedSpread { array } + } +} + +impl<'ast, T: fmt::Display> fmt::Display for TypedSpread<'ast, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "...{}", self.array) + } +} + +#[derive(Clone, PartialEq, Hash, Eq, Debug)] +pub enum TypedExpressionOrSpread<'ast, T> { + Expression(TypedExpression<'ast, T>), + Spread(TypedSpread<'ast, T>), +} + +impl<'ast, T: Clone> TypedExpressionOrSpread<'ast, T> { + pub fn size(&self) -> UExpression<'ast, T> { + match self { + TypedExpressionOrSpread::Expression(..) => 1u32.into(), + TypedExpressionOrSpread::Spread(s) => s.array.size(), + } + } +} + +impl<'ast, T> TryFrom> for TypedExpression<'ast, T> { + type Error = (); + + fn try_from( + e: TypedExpressionOrSpread<'ast, T>, + ) -> Result, Self::Error> { + if let TypedExpressionOrSpread::Expression(e) = e { + Ok(e) + } else { + Err(()) + } + } +} + +impl<'ast, T, U: Into>> From for TypedExpressionOrSpread<'ast, T> { + fn from(e: U) -> Self { + TypedExpressionOrSpread::Expression(e.into()) + } +} + +impl<'ast, T: Clone> TypedExpressionOrSpread<'ast, T> { + pub fn get_type(&self) -> (Type<'ast, T>, UExpression<'ast, T>) { + match self { + TypedExpressionOrSpread::Expression(e) => (e.get_type(), 1u32.into()), + TypedExpressionOrSpread::Spread(s) => (s.array.inner_type().clone(), s.array.size()), + } + } +} + +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::Spread(s) => write!(f, "{}", s), + } + } +} + +impl<'ast, T> From> for TypedAssignee<'ast, T> { + fn from(v: Variable<'ast, T>) -> Self { TypedAssignee::Identifier(v) } } -impl<'ast, T> Typed for TypedAssignee<'ast, T> { - fn get_type(&self) -> Type { +impl<'ast, T: Clone> Typed<'ast, T> for TypedAssignee<'ast, T> { + fn get_type(&self) -> Type<'ast, T> { match *self { TypedAssignee::Identifier(ref v) => v.get_type(), TypedAssignee::Select(ref a, _) => { @@ -295,7 +420,7 @@ impl<'ast, T> Typed for TypedAssignee<'ast, T> { impl<'ast, T: fmt::Debug> fmt::Debug for TypedAssignee<'ast, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - TypedAssignee::Identifier(ref s) => write!(f, "{}", s.id), + TypedAssignee::Identifier(ref s) => write!(f, "{:?}", s.id), TypedAssignee::Select(ref a, ref e) => write!(f, "Select({:?}, {:?})", a, e), TypedAssignee::Member(ref s, ref m) => write!(f, "Member({:?}, {:?})", s, m), } @@ -313,19 +438,26 @@ impl<'ast, T: fmt::Display> fmt::Display for TypedAssignee<'ast, T> { } /// A statement in a `TypedFunction` +#[allow(clippy::large_enum_variant)] #[derive(Clone, PartialEq, Hash, Eq)] pub enum TypedStatement<'ast, T> { Return(Vec>), Definition(TypedAssignee<'ast, T>, TypedExpression<'ast, T>), - Declaration(Variable<'ast>), + Declaration(Variable<'ast, T>), Assertion(BooleanExpression<'ast, T>), For( - Variable<'ast>, - FieldElementExpression<'ast, T>, - FieldElementExpression<'ast, T>, + Variable<'ast, T>, + UExpression<'ast, T>, + UExpression<'ast, T>, Vec>, ), MultipleDefinition(Vec>, TypedExpressionList<'ast, T>), + // Aux + PushCallLog( + DeclarationFunctionKey<'ast>, + ConcreteGenericsAssignment<'ast>, + ), + PopCallLog, } impl<'ast, T: fmt::Debug> fmt::Debug for TypedStatement<'ast, T> { @@ -341,21 +473,25 @@ impl<'ast, T: fmt::Debug> fmt::Debug for TypedStatement<'ast, T> { } write!(f, ")") } - TypedStatement::Declaration(ref var) => write!(f, "Declaration({:?})", var), + TypedStatement::Declaration(ref var) => write!(f, "({:?})", var), TypedStatement::Definition(ref lhs, ref rhs) => { write!(f, "Definition({:?}, {:?})", lhs, rhs) } TypedStatement::Assertion(ref e) => write!(f, "Assertion({:?})", e), TypedStatement::For(ref var, ref start, ref stop, ref list) => { - write!(f, "for {:?} in {:?}..{:?} do\n", var, start, stop)?; + writeln!(f, "for {:?} in {:?}..{:?} do", var, start, stop)?; for l in list { - write!(f, "\t\t{:?}\n", l)?; + writeln!(f, "\t\t{:?}", l)?; } write!(f, "\tendfor") } TypedStatement::MultipleDefinition(ref lhs, ref rhs) => { write!(f, "MultipleDefinition({:?}, {:?})", lhs, rhs) } + TypedStatement::PushCallLog(ref key, ref generics) => { + write!(f, "PushCallLog({:?}, {:?})", key, generics) + } + TypedStatement::PopCallLog => write!(f, "PopCallLog"), } } } @@ -368,9 +504,9 @@ impl<'ast, T: fmt::Display> TypedStatement<'ast, T> { writeln!(f, "for {} in {}..{} do", variable, from, to)?; for s in statements { s.fmt_indented(f, depth + 1)?; - writeln!(f, "")?; + writeln!(f)?; } - writeln!(f, "{}endfor", "\t".repeat(depth)) + write!(f, "{}endfor", "\t".repeat(depth)) } s => write!(f, "{}{}", "\t".repeat(depth), s), } @@ -394,9 +530,9 @@ impl<'ast, T: fmt::Display> fmt::Display for TypedStatement<'ast, T> { TypedStatement::Definition(ref lhs, ref rhs) => write!(f, "{} = {}", lhs, rhs), TypedStatement::Assertion(ref e) => write!(f, "assert({})", e), TypedStatement::For(ref var, ref start, ref stop, ref list) => { - write!(f, "for {} in {}..{} do\n", var, start, stop)?; + writeln!(f, "for {} in {}..{} do", var, start, stop)?; for l in list { - write!(f, "\t\t{}\n", l)?; + writeln!(f, "\t\t{}", l)?; } write!(f, "\tendfor") } @@ -409,15 +545,24 @@ impl<'ast, T: fmt::Display> fmt::Display for TypedStatement<'ast, T> { } write!(f, " = {}", rhs) } + TypedStatement::PushCallLog(ref key, ref generics) => write!( + f, + "// PUSH CALL TO {}/{}::<{}>", + key.module.display(), + key.id, + generics, + ), + TypedStatement::PopCallLog => write!(f, "// POP CALL",), } } } -pub trait Typed { - fn get_type(&self) -> Type; +pub trait Typed<'ast, T> { + fn get_type(&self) -> Type<'ast, T>; } /// A typed expression +#[allow(clippy::large_enum_variant)] #[derive(Clone, PartialEq, Hash, Eq)] pub enum TypedExpression<'ast, T> { Boolean(BooleanExpression<'ast, T>), @@ -425,6 +570,7 @@ pub enum TypedExpression<'ast, T> { Uint(UExpression<'ast, T>), Array(ArrayExpression<'ast, T>), Struct(StructExpression<'ast, T>), + Int(IntExpression<'ast, T>), } impl<'ast, T> From> for TypedExpression<'ast, T> { @@ -439,6 +585,12 @@ impl<'ast, T> From> for TypedExpression<'ast, T> } } +impl<'ast, T> From> for TypedExpression<'ast, T> { + fn from(e: IntExpression<'ast, T>) -> TypedExpression { + TypedExpression::Int(e) + } +} + impl<'ast, T> From> for TypedExpression<'ast, T> { fn from(e: UExpression<'ast, T>) -> TypedExpression { TypedExpression::Uint(e) @@ -465,6 +617,7 @@ impl<'ast, T: fmt::Display> fmt::Display for TypedExpression<'ast, T> { TypedExpression::Uint(ref e) => write!(f, "{}", e), TypedExpression::Array(ref e) => write!(f, "{}", e), TypedExpression::Struct(ref s) => write!(f, "{}", s), + TypedExpression::Int(ref s) => write!(f, "{}", s), } } } @@ -477,6 +630,7 @@ impl<'ast, T: fmt::Debug> fmt::Debug for TypedExpression<'ast, T> { TypedExpression::Uint(ref e) => write!(f, "{:?}", e), TypedExpression::Array(ref e) => write!(f, "{:?}", e), TypedExpression::Struct(ref s) => write!(f, "{:?}", s), + TypedExpression::Int(ref s) => write!(f, "{:?}", s), } } } @@ -499,7 +653,8 @@ impl<'ast, T: fmt::Display> fmt::Display for StructExpression<'ast, T> { StructExpressionInner::Identifier(ref var) => write!(f, "{}", var), StructExpressionInner::Value(ref values) => write!( f, - "{{{}}}", + "{} {{{}}}", + self.ty.name(), self.ty .iter() .map(|member| member.id.clone()) @@ -508,8 +663,23 @@ impl<'ast, T: fmt::Display> fmt::Display for StructExpression<'ast, T> { .collect::>() .join(", ") ), - StructExpressionInner::FunctionCall(ref key, ref p) => { - write!(f, "{}(", key.id,)?; + StructExpressionInner::FunctionCall(ref key, ref generics, ref p) => { + write!(f, "{}", key.id,)?; + if !generics.is_empty() { + write!( + f, + "::<{}>", + generics + .iter() + .map(|g| g + .as_ref() + .map(|g| g.to_string()) + .unwrap_or_else(|| '_'.to_string())) + .collect::>() + .join(", ") + )?; + } + write!(f, "(")?; for (i, param) in p.iter().enumerate() { write!(f, "{}", param)?; if i < p.len() - 1 { @@ -537,61 +707,74 @@ impl<'ast, T: fmt::Debug> fmt::Debug for StructExpression<'ast, T> { } } -impl<'ast, T> Typed for TypedExpression<'ast, T> { - fn get_type(&self) -> Type { +impl<'ast, T: Clone> Typed<'ast, T> for TypedExpression<'ast, T> { + fn get_type(&self) -> Type<'ast, T> { match *self { TypedExpression::Boolean(ref e) => e.get_type(), TypedExpression::FieldElement(ref e) => e.get_type(), TypedExpression::Array(ref e) => e.get_type(), TypedExpression::Uint(ref e) => e.get_type(), TypedExpression::Struct(ref s) => s.get_type(), + TypedExpression::Int(_) => Type::Int, } } } -impl<'ast, T> Typed for ArrayExpression<'ast, T> { - fn get_type(&self) -> Type { - Type::array(self.ty.clone(), self.size) +impl<'ast, T: Clone> Typed<'ast, T> for ArrayExpression<'ast, T> { + fn get_type(&self) -> Type<'ast, T> { + Type::array(*self.ty.clone()) } } -impl<'ast, T> Typed for StructExpression<'ast, T> { - fn get_type(&self) -> Type { +impl<'ast, T: Clone> Typed<'ast, T> for StructExpression<'ast, T> { + fn get_type(&self) -> Type<'ast, T> { Type::Struct(self.ty.clone()) } } -impl<'ast, T> Typed for FieldElementExpression<'ast, T> { - fn get_type(&self) -> Type { +impl<'ast, T: Clone> Typed<'ast, T> for FieldElementExpression<'ast, T> { + fn get_type(&self) -> Type<'ast, T> { Type::FieldElement } } -impl<'ast, T> Typed for UExpression<'ast, T> { - fn get_type(&self) -> Type { +impl<'ast, T: Clone> Typed<'ast, T> for UExpression<'ast, T> { + fn get_type(&self) -> Type<'ast, T> { Type::Uint(self.bitwidth) } } -impl<'ast, T> Typed for BooleanExpression<'ast, T> { - fn get_type(&self) -> Type { +impl<'ast, T: Clone> Typed<'ast, T> for BooleanExpression<'ast, T> { + fn get_type(&self) -> Type<'ast, T> { Type::Boolean } } -pub trait MultiTyped { - fn get_types(&self) -> &Vec; +pub trait MultiTyped<'ast, T> { + fn get_types(&self) -> &Vec>; } #[derive(Clone, PartialEq, Hash, Eq)] pub enum TypedExpressionList<'ast, T> { - FunctionCall(FunctionKey<'ast>, Vec>, Vec), + FunctionCall( + DeclarationFunctionKey<'ast>, + Vec>>, + Vec>, + Vec>, + ), + EmbedCall( + FlatEmbed, + Vec, + Vec>, + Vec>, + ), } -impl<'ast, T> MultiTyped for TypedExpressionList<'ast, T> { - fn get_types(&self) -> &Vec { +impl<'ast, T> MultiTyped<'ast, T> for TypedExpressionList<'ast, T> { + fn get_types(&self) -> &Vec> { match *self { - TypedExpressionList::FunctionCall(_, _, ref types) => types, + TypedExpressionList::FunctionCall(_, _, _, ref types) => types, + TypedExpressionList::EmbedCall(_, _, _, ref types) => types, } } } @@ -619,19 +802,59 @@ pub enum FieldElementExpression<'ast, T> { ), Pow( Box>, - Box>, + Box>, ), IfElse( Box>, Box>, Box>, ), - FunctionCall(FunctionKey<'ast>, Vec>), - Member(Box>, MemberId), - Select( - Box>, - Box>, + Neg(Box>), + Pos(Box>), + FunctionCall( + DeclarationFunctionKey<'ast>, + Vec>>, + Vec>, ), + Member(Box>, MemberId), + Select(Box>, Box>), +} +impl<'ast, T> Add for FieldElementExpression<'ast, T> { + type Output = Self; + + fn add(self, other: Self) -> Self { + FieldElementExpression::Add(box self, box other) + } +} + +impl<'ast, T> Sub for FieldElementExpression<'ast, T> { + type Output = Self; + + fn sub(self, other: Self) -> Self { + FieldElementExpression::Sub(box self, box other) + } +} + +impl<'ast, T> Mul for FieldElementExpression<'ast, T> { + type Output = Self; + + fn mul(self, other: Self) -> Self { + FieldElementExpression::Mult(box self, box other) + } +} + +impl<'ast, T> Div for FieldElementExpression<'ast, T> { + type Output = Self; + + fn div(self, other: Self) -> Self { + FieldElementExpression::Div(box self, box other) + } +} + +impl<'ast, T> FieldElementExpression<'ast, T> { + pub fn pow(self, other: UExpression<'ast, T>) -> Self { + FieldElementExpression::Pow(box self, box other) + } } impl<'ast, T> From for FieldElementExpression<'ast, T> { @@ -645,14 +868,26 @@ impl<'ast, T> From for FieldElementExpression<'ast, T> { pub enum BooleanExpression<'ast, T> { Identifier(Identifier<'ast>), Value(bool), - Lt( + FieldLt( Box>, Box>, ), - Le( + FieldLe( Box>, Box>, ), + FieldGe( + Box>, + Box>, + ), + FieldGt( + Box>, + Box>, + ), + UintLt(Box>, Box>), + UintLe(Box>, Box>), + UintGe(Box>, Box>), + UintGt(Box>, Box>), FieldEq( Box>, Box>, @@ -667,14 +902,6 @@ pub enum BooleanExpression<'ast, T> { Box>, ), UintEq(Box>, Box>), - Ge( - Box>, - Box>, - ), - Gt( - Box>, - Box>, - ), Or( Box>, Box>, @@ -690,11 +917,18 @@ pub enum BooleanExpression<'ast, T> { Box>, ), Member(Box>, MemberId), - FunctionCall(FunctionKey<'ast>, Vec>), - Select( - Box>, - Box>, + FunctionCall( + DeclarationFunctionKey<'ast>, + Vec>>, + Vec>, ), + Select(Box>, Box>), +} + +impl<'ast, T> From for BooleanExpression<'ast, T> { + fn from(b: bool) -> Self { + BooleanExpression::Value(b) + } } /// An expression of type `array` @@ -704,45 +938,132 @@ pub enum BooleanExpression<'ast, T> { /// type checking #[derive(Clone, PartialEq, Hash, Eq)] pub struct ArrayExpression<'ast, T> { - size: usize, - ty: Type, + ty: Box>, inner: ArrayExpressionInner<'ast, T>, } +#[derive(Debug, PartialEq, Eq, Hash, Clone)] +pub struct ArrayValue<'ast, T>(pub Vec>); + +impl<'ast, T> From>> for ArrayValue<'ast, T> { + fn from(array: Vec>) -> Self { + Self(array) + } +} + +impl<'ast, T> IntoIterator for ArrayValue<'ast, T> { + type Item = TypedExpressionOrSpread<'ast, T>; + type IntoIter = std::vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + +impl<'ast, T: Clone> ArrayValue<'ast, T> { + fn expression_at_aux + Into>>( + v: TypedExpressionOrSpread<'ast, T>, + ) -> Vec>> { + match v { + TypedExpressionOrSpread::Expression(e) => vec![Some(e.clone())], + TypedExpressionOrSpread::Spread(s) => match s.array.size().into_inner() { + UExpressionInner::Value(size) => { + let array_ty = s.array.get_array_type().clone(); + + match s.array.into_inner() { + ArrayExpressionInner::Value(v) => v + .into_iter() + .flat_map(Self::expression_at_aux::) + .collect(), + a => (0..size) + .map(|i| { + Some( + U::select( + a.clone() + .annotate(*array_ty.ty.clone(), array_ty.size.clone()), + i as u32, + ) + .into(), + ) + }) + .collect(), + } + } + _ => vec![None], + }, + } + } + + pub fn expression_at + Into>>( + &self, + index: usize, + ) -> Option> { + self.0 + .iter() + .map(|v| Self::expression_at_aux::(v.clone())) + .flatten() + .take_while(|e| e.is_some()) + .map(|e| e.unwrap()) + .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()) + } +} + #[derive(Clone, PartialEq, Hash, Eq)] pub enum ArrayExpressionInner<'ast, T> { Identifier(Identifier<'ast>), - Value(Vec>), - FunctionCall(FunctionKey<'ast>, Vec>), + Value(ArrayValue<'ast, T>), + FunctionCall( + DeclarationFunctionKey<'ast>, + Vec>>, + Vec>, + ), IfElse( Box>, Box>, Box>, ), Member(Box>, MemberId), - Select( + Select(Box>, Box>), + Slice( Box>, - Box>, + Box>, + Box>, ), + Repeat(Box>, Box>), } impl<'ast, T> ArrayExpressionInner<'ast, T> { - pub fn annotate(self, ty: Type, size: usize) -> ArrayExpression<'ast, T> { + pub fn annotate>>( + self, + ty: Type<'ast, T>, + size: S, + ) -> ArrayExpression<'ast, T> { ArrayExpression { - size, - ty, + ty: box (ty, size.into()).into(), inner: self, } } } -impl<'ast, T> ArrayExpression<'ast, T> { - pub fn inner_type(&self) -> &Type { - &self.ty +impl<'ast, T: Clone> ArrayExpression<'ast, T> { + pub fn inner_type(&self) -> &Type<'ast, T> { + &self.ty.ty } - pub fn size(&self) -> usize { - self.size + pub fn size(&self) -> UExpression<'ast, T> { + self.ty.size.clone() } pub fn as_inner(&self) -> &ArrayExpressionInner<'ast, T> { @@ -756,16 +1077,41 @@ impl<'ast, T> ArrayExpression<'ast, T> { pub fn into_inner(self) -> ArrayExpressionInner<'ast, T> { self.inner } + + pub fn get_array_type(&self) -> ArrayType<'ast, T> { + ArrayType { + size: self.size(), + ty: box self.inner_type().clone(), + } + } } #[derive(Clone, PartialEq, Hash, Eq)] pub struct StructExpression<'ast, T> { - ty: StructType, + ty: StructType<'ast, T>, inner: StructExpressionInner<'ast, T>, } +impl<'ast, T: Field> StructExpression<'ast, T> { + pub fn try_from_typed( + e: TypedExpression<'ast, T>, + target_struct_ty: StructType<'ast, T>, + ) -> Result> { + match e { + TypedExpression::Struct(e) => { + if e.ty() == &target_struct_ty { + Ok(e) + } else { + Err(TypedExpression::Struct(e)) + } + } + e => Err(e), + } + } +} + impl<'ast, T> StructExpression<'ast, T> { - pub fn ty(&self) -> &StructType { + pub fn ty(&self) -> &StructType<'ast, T> { &self.ty } @@ -786,21 +1132,22 @@ impl<'ast, T> StructExpression<'ast, T> { pub enum StructExpressionInner<'ast, T> { Identifier(Identifier<'ast>), Value(Vec>), - FunctionCall(FunctionKey<'ast>, Vec>), + FunctionCall( + DeclarationFunctionKey<'ast>, + Vec>>, + Vec>, + ), IfElse( Box>, Box>, Box>, ), Member(Box>, MemberId), - Select( - Box>, - Box>, - ), + Select(Box>, Box>), } impl<'ast, T> StructExpressionInner<'ast, T> { - pub fn annotate(self, ty: StructType) -> StructExpression<'ast, T> { + pub fn annotate(self, ty: StructType<'ast, T>) -> StructExpression<'ast, T> { StructExpression { ty, inner: self } } } @@ -855,6 +1202,17 @@ impl<'ast, T> TryFrom> for ArrayExpression<'ast, T> { } } +impl<'ast, T> TryFrom> for IntExpression<'ast, T> { + type Error = (); + + fn try_from(te: TypedExpression<'ast, T>) -> Result, Self::Error> { + match te { + TypedExpression::Int(e) => Ok(e), + _ => Err(()), + } + } +} + impl<'ast, T> TryFrom> for StructExpression<'ast, T> { type Error = (); @@ -869,13 +1227,15 @@ impl<'ast, T> TryFrom> for StructExpression<'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::Number(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::IfElse(ref condition, ref consequent, ref alternative) => { write!( f, @@ -883,8 +1243,23 @@ impl<'ast, T: fmt::Display> fmt::Display for FieldElementExpression<'ast, T> { condition, consequent, alternative ) } - FieldElementExpression::FunctionCall(ref k, ref p) => { - write!(f, "{}(", k.id,)?; + FieldElementExpression::FunctionCall(ref k, ref generics, ref p) => { + write!(f, "{}", k.id,)?; + if !generics.is_empty() { + write!( + f, + "::<{}>", + generics + .iter() + .map(|g| g + .as_ref() + .map(|g| g.to_string()) + .unwrap_or_else(|| '_'.to_string())) + .collect::>() + .join(", ") + )?; + } + write!(f, "(")?; for (i, param) in p.iter().enumerate() { write!(f, "{}", param)?; if i < p.len() - 1 { @@ -902,7 +1277,7 @@ impl<'ast, T: fmt::Display> fmt::Display for FieldElementExpression<'ast, T> { impl<'ast, T: fmt::Display> fmt::Display for UExpression<'ast, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.inner { - UExpressionInner::Value(ref v) => write!(f, "0x{:x}", v), + 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), @@ -910,14 +1285,34 @@ impl<'ast, T: fmt::Display> fmt::Display for UExpression<'ast, T> { 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::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::Select(ref id, ref index) => write!(f, "{}[{}]", id, index), - UExpressionInner::FunctionCall(ref k, ref p) => { - write!(f, "{}(", k.id,)?; + UExpressionInner::FunctionCall(ref k, ref generics, ref p) => { + write!(f, "{}", k.id,)?; + if !generics.is_empty() { + write!( + f, + "::<{}>", + generics + .iter() + .map(|g| g + .as_ref() + .map(|g| g.to_string()) + .unwrap_or_else(|| '_'.to_string())) + .collect::>() + .join(", ") + )?; + } + write!(f, "(")?; for (i, param) in p.iter().enumerate() { write!(f, "{}", param)?; if i < p.len() - 1 { @@ -940,21 +1335,40 @@ 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::Lt(ref lhs, ref rhs) => write!(f, "{} < {}", lhs, rhs), - BooleanExpression::Le(ref lhs, ref rhs) => write!(f, "{} <= {}", lhs, rhs), + 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::FieldEq(ref lhs, ref rhs) => write!(f, "{} == {}", lhs, rhs), BooleanExpression::BoolEq(ref lhs, ref rhs) => write!(f, "{} == {}", lhs, rhs), BooleanExpression::ArrayEq(ref lhs, ref rhs) => write!(f, "{} == {}", lhs, rhs), BooleanExpression::StructEq(ref lhs, ref rhs) => write!(f, "{} == {}", lhs, rhs), BooleanExpression::UintEq(ref lhs, ref rhs) => write!(f, "{} == {}", lhs, rhs), - BooleanExpression::Ge(ref lhs, ref rhs) => write!(f, "{} >= {}", lhs, rhs), - BooleanExpression::Gt(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::Value(b) => write!(f, "{}", b), - BooleanExpression::FunctionCall(ref k, ref p) => { - write!(f, "{}(", k.id,)?; + BooleanExpression::FunctionCall(ref k, ref generics, ref p) => { + write!(f, "{}", k.id,)?; + if !generics.is_empty() { + write!( + f, + "::<{}>", + generics + .iter() + .map(|g| g + .as_ref() + .map(|g| g.to_string()) + .unwrap_or_else(|| '_'.to_string())) + .collect::>() + .join(", ") + )?; + } + write!(f, "(")?; for (i, param) in p.iter().enumerate() { write!(f, "{}", param)?; if i < p.len() - 1 { @@ -987,8 +1401,23 @@ impl<'ast, T: fmt::Display> fmt::Display for ArrayExpressionInner<'ast, T> { .collect::>() .join(", ") ), - ArrayExpressionInner::FunctionCall(ref key, ref p) => { - write!(f, "{}(", key.id,)?; + ArrayExpressionInner::FunctionCall(ref key, ref generics, ref p) => { + write!(f, "{}", key.id,)?; + if !generics.is_empty() { + write!( + f, + "::<{}>", + generics + .iter() + .map(|g| g + .as_ref() + .map(|g| g.to_string()) + .unwrap_or_else(|| '_'.to_string())) + .collect::>() + .join(", ") + )?; + } + write!(f, "(")?; for (i, param) in p.iter().enumerate() { write!(f, "{}", param)?; if i < p.len() - 1 { @@ -1004,6 +1433,12 @@ impl<'ast, T: fmt::Display> fmt::Display for ArrayExpressionInner<'ast, T> { ), ArrayExpressionInner::Member(ref s, ref id) => write!(f, "{}.{}", s, id), ArrayExpressionInner::Select(ref id, ref index) => write!(f, "{}[{}]", id, index), + ArrayExpressionInner::Slice(ref a, ref from, ref to) => { + write!(f, "{}[{}..{}]", a, from, to) + } + ArrayExpressionInner::Repeat(ref e, ref count) => { + write!(f, "[{}; {}]", e, count) + } } } } @@ -1018,8 +1453,30 @@ impl<'ast, T: fmt::Debug> fmt::Debug for BooleanExpression<'ast, T> { "IfElse({:?}, {:?}, {:?})", condition, consequent, alternative ), - BooleanExpression::Lt(ref lhs, ref rhs) => write!(f, "Lt({:?}, {:?})", lhs, rhs), - BooleanExpression::Le(ref lhs, ref rhs) => write!(f, "Le({:?}, {:?})", lhs, rhs), + BooleanExpression::FieldLt(ref lhs, ref rhs) => { + write!(f, "FieldLt({:?}, {:?})", lhs, rhs) + } + BooleanExpression::FieldLe(ref lhs, ref rhs) => { + write!(f, "FieldLe({:?}, {:?})", lhs, rhs) + } + BooleanExpression::FieldGe(ref lhs, ref rhs) => { + write!(f, "FieldGe({:?}, {:?})", lhs, rhs) + } + BooleanExpression::FieldGt(ref lhs, ref rhs) => { + write!(f, "FieldGt({:?}, {:?})", lhs, rhs) + } + BooleanExpression::UintLt(ref lhs, ref rhs) => { + write!(f, "UintLt({:?}, {:?})", lhs, rhs) + } + BooleanExpression::UintLe(ref lhs, ref rhs) => { + write!(f, "UintLe({:?}, {:?})", lhs, rhs) + } + BooleanExpression::UintGe(ref lhs, ref rhs) => { + write!(f, "UintGe({:?}, {:?})", lhs, rhs) + } + BooleanExpression::UintGt(ref lhs, ref rhs) => { + write!(f, "UintGt({:?}, {:?})", lhs, rhs) + } BooleanExpression::FieldEq(ref lhs, ref rhs) => { write!(f, "FieldEq({:?}, {:?})", lhs, rhs) } @@ -1035,12 +1492,10 @@ impl<'ast, T: fmt::Debug> fmt::Debug for BooleanExpression<'ast, T> { BooleanExpression::UintEq(ref lhs, ref rhs) => { write!(f, "UintEq({:?}, {:?})", lhs, rhs) } - BooleanExpression::Ge(ref lhs, ref rhs) => write!(f, "Ge({:?}, {:?})", lhs, rhs), - BooleanExpression::Gt(ref lhs, ref rhs) => write!(f, "Gt({:?}, {:?})", lhs, rhs), BooleanExpression::And(ref lhs, ref rhs) => write!(f, "And({:?}, {:?})", lhs, rhs), BooleanExpression::Not(ref exp) => write!(f, "Not({:?})", exp), - BooleanExpression::FunctionCall(ref i, ref p) => { - write!(f, "FunctionCall({:?}, (", i)?; + BooleanExpression::FunctionCall(ref i, ref g, ref p) => { + write!(f, "FunctionCall({:?}, {:?}, (", g, i)?; f.debug_list().entries(p.iter()).finish()?; write!(f, ")") } @@ -1067,6 +1522,8 @@ impl<'ast, T: fmt::Debug> fmt::Debug for FieldElementExpression<'ast, T> { } FieldElementExpression::Div(ref lhs, ref rhs) => write!(f, "Div({:?}, {:?})", lhs, rhs), FieldElementExpression::Pow(ref lhs, ref rhs) => write!(f, "Pow({:?}, {:?})", lhs, rhs), + FieldElementExpression::Neg(ref e) => write!(f, "Neg({:?})", e), + FieldElementExpression::Pos(ref e) => write!(f, "Pos({:?})", e), FieldElementExpression::IfElse(ref condition, ref consequent, ref alternative) => { write!( f, @@ -1074,8 +1531,8 @@ impl<'ast, T: fmt::Debug> fmt::Debug for FieldElementExpression<'ast, T> { condition, consequent, alternative ) } - FieldElementExpression::FunctionCall(ref i, ref p) => { - write!(f, "FunctionCall({:?}, (", i)?; + FieldElementExpression::FunctionCall(ref i, ref g, ref p) => { + write!(f, "FunctionCall({:?}, {:?}, (", g, i)?; f.debug_list().entries(p.iter()).finish()?; write!(f, ")") } @@ -1094,8 +1551,8 @@ impl<'ast, T: fmt::Debug> fmt::Debug for ArrayExpressionInner<'ast, T> { match *self { ArrayExpressionInner::Identifier(ref var) => write!(f, "Identifier({:?})", var), ArrayExpressionInner::Value(ref values) => write!(f, "Value({:?})", values), - ArrayExpressionInner::FunctionCall(ref i, ref p) => { - write!(f, "FunctionCall({:?}, (", i)?; + ArrayExpressionInner::FunctionCall(ref i, ref g, ref p) => { + write!(f, "FunctionCall({:?}, {:?}, (", g, i)?; f.debug_list().entries(p.iter()).finish()?; write!(f, ")") } @@ -1107,8 +1564,14 @@ impl<'ast, T: fmt::Debug> fmt::Debug for ArrayExpressionInner<'ast, T> { ArrayExpressionInner::Member(ref struc, ref id) => { write!(f, "Member({:?}, {:?})", struc, id) } - ArrayExpressionInner::Select(ref id, ref index) => { - write!(f, "Select({:?}, {:?})", id, index) + ArrayExpressionInner::Select(ref array, ref index) => { + write!(f, "Select({:?}, {:?})", array, index) + } + ArrayExpressionInner::Slice(ref array, ref from, ref to) => { + write!(f, "Slice({:?}, {:?}, {:?})", array, from, to) + } + ArrayExpressionInner::Repeat(ref e, ref count) => { + write!(f, "Repeat({:?}, {:?})", e, count) } } } @@ -1119,8 +1582,8 @@ impl<'ast, T: fmt::Debug> fmt::Debug for StructExpressionInner<'ast, T> { match *self { StructExpressionInner::Identifier(ref var) => write!(f, "{:?}", var), StructExpressionInner::Value(ref values) => write!(f, "{:?}", values), - StructExpressionInner::FunctionCall(ref i, ref p) => { - write!(f, "FunctionCall({:?}, (", i)?; + StructExpressionInner::FunctionCall(ref i, ref g, ref p) => { + write!(f, "FunctionCall({:?}, {:?}, (", g, i)?; f.debug_list().entries(p.iter()).finish()?; write!(f, ")") } @@ -1144,8 +1607,45 @@ impl<'ast, T: fmt::Debug> fmt::Debug for StructExpressionInner<'ast, T> { impl<'ast, T: fmt::Display> fmt::Display for TypedExpressionList<'ast, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - TypedExpressionList::FunctionCall(ref key, ref p, _) => { - write!(f, "{}(", key.id,)?; + TypedExpressionList::FunctionCall(ref k, ref generics, ref p, _) => { + write!(f, "{}", k.id,)?; + if !generics.is_empty() { + write!( + f, + "::<{}>", + generics + .iter() + .map(|g| g + .as_ref() + .map(|g| g.to_string()) + .unwrap_or_else(|| '_'.to_string())) + .collect::>() + .join(", ") + )?; + } + write!(f, "(")?; + for (i, param) in p.iter().enumerate() { + write!(f, "{}", param)?; + if i < p.len() - 1 { + write!(f, ", ")?; + } + } + write!(f, ")") + } + TypedExpressionList::EmbedCall(ref embed, ref generics, ref p, _) => { + write!(f, "{}", embed.id())?; + if !generics.is_empty() { + write!( + f, + "::<{}>", + generics + .iter() + .map(|g| g.to_string()) + .collect::>() + .join(", ") + )?; + } + write!(f, "(")?; for (i, param) in p.iter().enumerate() { write!(f, "{}", param)?; if i < p.len() - 1 { @@ -1161,8 +1661,13 @@ impl<'ast, T: fmt::Display> fmt::Display for TypedExpressionList<'ast, T> { impl<'ast, T: fmt::Debug> fmt::Debug for TypedExpressionList<'ast, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - TypedExpressionList::FunctionCall(ref i, ref p, _) => { - write!(f, "FunctionCall({:?}, (", i)?; + TypedExpressionList::FunctionCall(ref i, ref g, ref p, _) => { + write!(f, "FunctionCall({:?}, {:?}, (", g, i)?; + f.debug_list().entries(p.iter()).finish()?; + write!(f, ")") + } + TypedExpressionList::EmbedCall(ref embed, ref g, ref p, _) => { + write!(f, "EmbedCall({:?}, {:?}, (", g, embed)?; f.debug_list().entries(p.iter()).finish()?; write!(f, ")") } @@ -1170,6 +1675,23 @@ impl<'ast, T: fmt::Debug> fmt::Debug for TypedExpressionList<'ast, T> { } } +// Variable to TypedExpression conversion + +impl<'ast, T: Field> From> for TypedExpression<'ast, T> { + fn from(v: Variable<'ast, T>) -> Self { + match v.get_type() { + Type::FieldElement => FieldElementExpression::Identifier(v.id).into(), + Type::Boolean => BooleanExpression::Identifier(v.id).into(), + Type::Array(ty) => ArrayExpressionInner::Identifier(v.id) + .annotate(*ty.ty, ty.size) + .into(), + Type::Struct(ty) => StructExpressionInner::Identifier(v.id).annotate(ty).into(), + Type::Uint(w) => UExpressionInner::Identifier(v.id).annotate(w).into(), + Type::Int => unreachable!(), + } + } +} + // Common behaviour across expressions pub trait IfElse<'ast, T> { @@ -1187,6 +1709,16 @@ impl<'ast, T> IfElse<'ast, T> for FieldElementExpression<'ast, T> { } } +impl<'ast, T> IfElse<'ast, T> for IntExpression<'ast, T> { + fn if_else( + condition: BooleanExpression<'ast, T>, + consequence: Self, + alternative: Self, + ) -> Self { + IntExpression::IfElse(box condition, box consequence, box alternative) + } +} + impl<'ast, T> IfElse<'ast, T> for BooleanExpression<'ast, T> { fn if_else( condition: BooleanExpression<'ast, T>, @@ -1209,7 +1741,7 @@ impl<'ast, T> IfElse<'ast, T> for UExpression<'ast, T> { } } -impl<'ast, T> IfElse<'ast, T> for ArrayExpression<'ast, T> { +impl<'ast, T: Clone> IfElse<'ast, T> for ArrayExpression<'ast, T> { fn if_else( condition: BooleanExpression<'ast, T>, consequence: Self, @@ -1222,7 +1754,7 @@ impl<'ast, T> IfElse<'ast, T> for ArrayExpression<'ast, T> { } } -impl<'ast, T> IfElse<'ast, T> for StructExpression<'ast, T> { +impl<'ast, T: Clone> IfElse<'ast, T> for StructExpression<'ast, T> { fn if_else( condition: BooleanExpression<'ast, T>, consequence: Self, @@ -1234,51 +1766,70 @@ impl<'ast, T> IfElse<'ast, T> for StructExpression<'ast, T> { } pub trait Select<'ast, T> { - fn select(array: ArrayExpression<'ast, T>, index: FieldElementExpression<'ast, T>) -> Self; + fn select>>(array: ArrayExpression<'ast, T>, index: I) -> Self; } impl<'ast, T> Select<'ast, T> for FieldElementExpression<'ast, T> { - fn select(array: ArrayExpression<'ast, T>, index: FieldElementExpression<'ast, T>) -> Self { - FieldElementExpression::Select(box array, box index) + fn select>>(array: ArrayExpression<'ast, T>, index: I) -> Self { + FieldElementExpression::Select(box array, box index.into()) + } +} + +impl<'ast, T> Select<'ast, T> for IntExpression<'ast, T> { + fn select>>(array: ArrayExpression<'ast, T>, index: I) -> Self { + IntExpression::Select(box array, box index.into()) } } impl<'ast, T> Select<'ast, T> for BooleanExpression<'ast, T> { - fn select(array: ArrayExpression<'ast, T>, index: FieldElementExpression<'ast, T>) -> Self { - BooleanExpression::Select(box array, box index) + fn select>>(array: ArrayExpression<'ast, T>, index: I) -> Self { + BooleanExpression::Select(box array, box index.into()) } } -impl<'ast, T> Select<'ast, T> for UExpression<'ast, T> { - fn select(array: ArrayExpression<'ast, T>, index: FieldElementExpression<'ast, T>) -> Self { +impl<'ast, T: Clone> Select<'ast, T> for TypedExpression<'ast, T> { + fn select>>(array: ArrayExpression<'ast, T>, index: I) -> Self { + match *array.get_array_type().ty { + Type::Array(..) => ArrayExpression::select(array, index).into(), + Type::Struct(..) => StructExpression::select(array, index).into(), + Type::FieldElement => FieldElementExpression::select(array, index).into(), + Type::Boolean => BooleanExpression::select(array, index).into(), + Type::Int => IntExpression::select(array, index).into(), + Type::Uint(..) => UExpression::select(array, index).into(), + } + } +} + +impl<'ast, T: Clone> Select<'ast, T> for UExpression<'ast, T> { + fn select>>(array: ArrayExpression<'ast, T>, index: I) -> Self { let bitwidth = match array.inner_type().clone() { Type::Uint(bitwidth) => bitwidth, _ => unreachable!(), }; - UExpressionInner::Select(box array, box index).annotate(bitwidth) + UExpressionInner::Select(box array, box index.into()).annotate(bitwidth) } } -impl<'ast, T> Select<'ast, T> for ArrayExpression<'ast, T> { - fn select(array: ArrayExpression<'ast, T>, index: FieldElementExpression<'ast, T>) -> Self { +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!(), }; - ArrayExpressionInner::Select(box array, box index).annotate(*ty, size) + ArrayExpressionInner::Select(box array, box index.into()).annotate(*ty, size) } } -impl<'ast, T> Select<'ast, T> for StructExpression<'ast, T> { - fn select(array: ArrayExpression<'ast, T>, index: FieldElementExpression<'ast, T>) -> Self { +impl<'ast, T: Clone> Select<'ast, T> for StructExpression<'ast, T> { + fn select>>(array: ArrayExpression<'ast, T>, index: I) -> Self { let members = match array.inner_type().clone() { Type::Struct(members) => members, _ => unreachable!(), }; - StructExpressionInner::Select(box array, box index).annotate(members) + StructExpressionInner::Select(box array, box index.into()).annotate(members) } } @@ -1298,15 +1849,16 @@ impl<'ast, T> Member<'ast, T> for BooleanExpression<'ast, T> { } } -impl<'ast, T> Member<'ast, T> for UExpression<'ast, T> { +impl<'ast, T: Clone> Member<'ast, T> for UExpression<'ast, T> { fn member(s: StructExpression<'ast, T>, member_id: MemberId) -> Self { let members = s.ty().clone(); let ty = members - .into_iter() + .iter() .find(|member| *member.id == member_id) .unwrap() - .ty; + .ty + .clone(); let bitwidth = match *ty { Type::Uint(bitwidth) => bitwidth, @@ -1317,15 +1869,16 @@ impl<'ast, T> Member<'ast, T> for UExpression<'ast, T> { } } -impl<'ast, T> Member<'ast, T> for ArrayExpression<'ast, T> { +impl<'ast, T: Clone> Member<'ast, T> for ArrayExpression<'ast, T> { fn member(s: StructExpression<'ast, T>, member_id: MemberId) -> Self { let members = s.ty().clone(); let ty = members - .into_iter() + .iter() .find(|member| *member.id == member_id) .unwrap() - .ty; + .ty + .clone(); let (ty, size) = match *ty { Type::Array(array_type) => (array_type.ty, array_type.size), @@ -1336,15 +1889,16 @@ impl<'ast, T> Member<'ast, T> for ArrayExpression<'ast, T> { } } -impl<'ast, T> Member<'ast, T> for StructExpression<'ast, T> { +impl<'ast, T: Clone> Member<'ast, T> for StructExpression<'ast, T> { fn member(s: StructExpression<'ast, T>, member_id: MemberId) -> Self { let members = s.ty().clone(); let ty = members - .into_iter() + .iter() .find(|member| *member.id == member_id) .unwrap() - .ty; + .ty + .clone(); let members = match *ty { Type::Struct(members) => members, @@ -1354,3 +1908,83 @@ impl<'ast, T> Member<'ast, T> for StructExpression<'ast, T> { StructExpressionInner::Member(box s, member_id).annotate(members) } } + +pub trait FunctionCall<'ast, T> { + fn function_call( + key: DeclarationFunctionKey<'ast>, + generics: Vec>>, + arguments: Vec>, + output_type: Type<'ast, T>, + ) -> Self; +} + +impl<'ast, T: Field> FunctionCall<'ast, T> for FieldElementExpression<'ast, T> { + fn function_call( + key: DeclarationFunctionKey<'ast>, + generics: Vec>>, + arguments: Vec>, + output_type: Type<'ast, T>, + ) -> Self { + assert_eq!(output_type, Type::FieldElement); + FieldElementExpression::FunctionCall(key, generics, arguments) + } +} + +impl<'ast, T: Field> FunctionCall<'ast, T> for BooleanExpression<'ast, T> { + fn function_call( + key: DeclarationFunctionKey<'ast>, + generics: Vec>>, + arguments: Vec>, + output_type: Type<'ast, T>, + ) -> Self { + assert_eq!(output_type, Type::Boolean); + BooleanExpression::FunctionCall(key, generics, arguments) + } +} + +impl<'ast, T: Field> FunctionCall<'ast, T> for UExpression<'ast, T> { + fn function_call( + key: DeclarationFunctionKey<'ast>, + generics: Vec>>, + arguments: Vec>, + output_type: Type<'ast, T>, + ) -> Self { + let bitwidth = match output_type { + Type::Uint(bitwidth) => bitwidth, + _ => unreachable!(), + }; + UExpressionInner::FunctionCall(key, generics, arguments).annotate(bitwidth) + } +} + +impl<'ast, T: Field> FunctionCall<'ast, T> for ArrayExpression<'ast, T> { + fn function_call( + key: DeclarationFunctionKey<'ast>, + generics: Vec>>, + arguments: Vec>, + output_type: Type<'ast, T>, + ) -> Self { + let array_ty = match output_type { + Type::Array(array_ty) => array_ty, + _ => unreachable!(), + }; + ArrayExpressionInner::FunctionCall(key, generics, arguments) + .annotate(*array_ty.ty, array_ty.size) + } +} + +impl<'ast, T: Field> FunctionCall<'ast, T> for StructExpression<'ast, T> { + fn function_call( + key: DeclarationFunctionKey<'ast>, + generics: Vec>>, + arguments: Vec>, + output_type: Type<'ast, T>, + ) -> Self { + let struct_ty = match output_type { + Type::Struct(struct_ty) => struct_ty, + _ => unreachable!(), + }; + + StructExpressionInner::FunctionCall(key, generics, arguments).annotate(struct_ty) + } +} diff --git a/zokrates_core/src/typed_absy/parameter.rs b/zokrates_core/src/typed_absy/parameter.rs index 277ac5374..6a41c0e2c 100644 --- a/zokrates_core/src/typed_absy/parameter.rs +++ b/zokrates_core/src/typed_absy/parameter.rs @@ -1,30 +1,33 @@ -use crate::typed_absy::Variable; +use crate::typed_absy::types::Constant; +use crate::typed_absy::GVariable; use std::fmt; -#[derive(Clone, PartialEq)] -pub struct Parameter<'ast> { - pub id: Variable<'ast>, +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct GParameter<'ast, S> { + pub id: GVariable<'ast, S>, pub private: bool, } -impl<'ast> Parameter<'ast> { - #[cfg(test)] - pub fn private(v: Variable<'ast>) -> Self { - Parameter { +#[cfg(test)] +impl<'ast, S> From> for GParameter<'ast, S> { + fn from(v: GVariable<'ast, S>) -> Self { + GParameter { id: v, private: true, } } } -impl<'ast> fmt::Display for Parameter<'ast> { +pub type DeclarationParameter<'ast> = GParameter<'ast, Constant<'ast>>; + +impl<'ast, S: fmt::Display + Clone> 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.get_type(), self.id.id) } } -impl<'ast> fmt::Debug for Parameter<'ast> { +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_core/src/typed_absy/result_folder.rs b/zokrates_core/src/typed_absy/result_folder.rs new file mode 100644 index 000000000..16aa40db1 --- /dev/null +++ b/zokrates_core/src/typed_absy/result_folder.rs @@ -0,0 +1,831 @@ +// Generic walk through a typed AST. Not mutating in place + +use crate::typed_absy::types::{ArrayType, StructMember, StructType}; +use crate::typed_absy::*; +use zokrates_field::Field; + +pub trait ResultFolder<'ast, T: Field>: Sized { + type Error; + + fn fold_program( + &mut self, + p: TypedProgram<'ast, T>, + ) -> Result, Self::Error> { + fold_program(self, p) + } + + fn fold_module( + &mut self, + p: TypedModule<'ast, T>, + ) -> Result, Self::Error> { + fold_module(self, p) + } + + fn fold_function_symbol( + &mut self, + s: TypedFunctionSymbol<'ast, T>, + ) -> Result, Self::Error> { + fold_function_symbol(self, s) + } + + fn fold_function( + &mut self, + f: TypedFunction<'ast, T>, + ) -> Result, Self::Error> { + fold_function(self, f) + } + + fn fold_parameter( + &mut self, + p: DeclarationParameter<'ast>, + ) -> Result, Self::Error> { + Ok(DeclarationParameter { + id: self.fold_declaration_variable(p.id)?, + ..p + }) + } + + fn fold_name(&mut self, n: Identifier<'ast>) -> Result, Self::Error> { + Ok(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)?, + }) + } + + fn fold_declaration_variable( + &mut self, + v: DeclarationVariable<'ast>, + ) -> Result, Self::Error> { + Ok(DeclarationVariable { + id: self.fold_name(v.id)?, + _type: self.fold_declaration_type(v._type)?, + }) + } + + fn fold_type(&mut self, t: Type<'ast, T>) -> Result, Self::Error> { + use self::GType::*; + + match t { + Array(array_type) => Ok(Array(self.fold_array_type(array_type)?)), + Struct(struct_type) => Ok(Struct(self.fold_struct_type(struct_type)?)), + t => Ok(t), + } + } + + fn fold_array_type( + &mut self, + t: ArrayType<'ast, T>, + ) -> Result, Self::Error> { + Ok(ArrayType { + ty: box self.fold_type(*t.ty)?, + size: self.fold_uint_expression(t.size)?, + }) + } + + fn fold_struct_type( + &mut self, + t: StructType<'ast, T>, + ) -> Result, Self::Error> { + Ok(StructType { + members: t + .members + .into_iter() + .map(|m| { + let id = m.id; + self.fold_type(*m.ty) + .map(|ty| StructMember { ty: box ty, id }) + }) + .collect::>()?, + ..t + }) + } + + fn fold_declaration_type( + &mut self, + t: DeclarationType<'ast>, + ) -> Result, Self::Error> { + Ok(t) + } + + fn fold_assignee( + &mut self, + a: TypedAssignee<'ast, T>, + ) -> Result, Self::Error> { + match a { + TypedAssignee::Identifier(v) => Ok(TypedAssignee::Identifier(self.fold_variable(v)?)), + TypedAssignee::Select(box a, box index) => Ok(TypedAssignee::Select( + box self.fold_assignee(a)?, + box self.fold_uint_expression(index)?, + )), + TypedAssignee::Member(box s, m) => { + Ok(TypedAssignee::Member(box self.fold_assignee(s)?, m)) + } + } + } + + fn fold_statement( + &mut self, + s: TypedStatement<'ast, T>, + ) -> Result>, Self::Error> { + fold_statement(self, s) + } + + fn fold_expression_or_spread( + &mut self, + e: TypedExpressionOrSpread<'ast, T>, + ) -> Result, Self::Error> { + Ok(match e { + TypedExpressionOrSpread::Expression(e) => { + TypedExpressionOrSpread::Expression(self.fold_expression(e)?) + } + TypedExpressionOrSpread::Spread(s) => { + TypedExpressionOrSpread::Spread(self.fold_spread(s)?) + } + }) + } + + fn fold_spread( + &mut self, + s: TypedSpread<'ast, T>, + ) -> Result, Self::Error> { + Ok(TypedSpread { + array: self.fold_array_expression(s.array)?, + }) + } + + fn fold_expression( + &mut self, + e: TypedExpression<'ast, T>, + ) -> Result, Self::Error> { + match e { + TypedExpression::FieldElement(e) => Ok(self.fold_field_expression(e)?.into()), + TypedExpression::Boolean(e) => Ok(self.fold_boolean_expression(e)?.into()), + TypedExpression::Uint(e) => Ok(self.fold_uint_expression(e)?.into()), + TypedExpression::Array(e) => Ok(self.fold_array_expression(e)?.into()), + TypedExpression::Struct(e) => Ok(self.fold_struct_expression(e)?.into()), + TypedExpression::Int(e) => Ok(self.fold_int_expression(e)?.into()), + } + } + + fn fold_array_expression( + &mut self, + e: ArrayExpression<'ast, T>, + ) -> Result, Self::Error> { + fold_array_expression(self, e) + } + + fn fold_struct_expression( + &mut self, + e: StructExpression<'ast, T>, + ) -> Result, Self::Error> { + fold_struct_expression(self, e) + } + + fn fold_expression_list( + &mut self, + es: TypedExpressionList<'ast, T>, + ) -> Result, Self::Error> { + fold_expression_list(self, es) + } + + fn fold_int_expression( + &mut self, + e: IntExpression<'ast, T>, + ) -> Result, Self::Error> { + fold_int_expression(self, e) + } + + fn fold_field_expression( + &mut self, + e: FieldElementExpression<'ast, T>, + ) -> Result, Self::Error> { + fold_field_expression(self, e) + } + fn fold_boolean_expression( + &mut self, + e: BooleanExpression<'ast, T>, + ) -> Result, Self::Error> { + fold_boolean_expression(self, e) + } + fn fold_uint_expression( + &mut self, + e: UExpression<'ast, T>, + ) -> Result, Self::Error> { + fold_uint_expression(self, e) + } + + fn fold_uint_expression_inner( + &mut self, + bitwidth: UBitwidth, + e: UExpressionInner<'ast, T>, + ) -> Result, Self::Error> { + fold_uint_expression_inner(self, bitwidth, e) + } + + fn fold_array_expression_inner( + &mut self, + ty: &ArrayType<'ast, T>, + e: ArrayExpressionInner<'ast, T>, + ) -> Result, Self::Error> { + fold_array_expression_inner(self, ty, e) + } + fn fold_struct_expression_inner( + &mut self, + ty: &StructType<'ast, T>, + e: StructExpressionInner<'ast, T>, + ) -> Result, Self::Error> { + fold_struct_expression_inner(self, ty, e) + } +} + +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(expressions) => TypedStatement::Return( + expressions + .into_iter() + .map(|e| f.fold_expression(e)) + .collect::>()?, + ), + TypedStatement::Definition(a, e) => { + TypedStatement::Definition(f.fold_assignee(a)?, f.fold_expression(e)?) + } + TypedStatement::Declaration(v) => TypedStatement::Declaration(f.fold_variable(v)?), + TypedStatement::Assertion(e) => TypedStatement::Assertion(f.fold_boolean_expression(e)?), + 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::MultipleDefinition(variables, elist) => TypedStatement::MultipleDefinition( + variables + .into_iter() + .map(|v| f.fold_assignee(v)) + .collect::>()?, + f.fold_expression_list(elist)?, + ), + s => s, + }; + Ok(vec![res]) +} + +pub fn fold_array_expression_inner<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + _: &ArrayType<'ast, T>, + e: ArrayExpressionInner<'ast, T>, +) -> Result, F::Error> { + let e = match e { + ArrayExpressionInner::Identifier(id) => ArrayExpressionInner::Identifier(f.fold_name(id)?), + ArrayExpressionInner::Value(exprs) => ArrayExpressionInner::Value( + exprs + .into_iter() + .map(|e| f.fold_expression_or_spread(e)) + .collect::>()?, + ), + ArrayExpressionInner::FunctionCall(id, generics, exps) => { + let generics = generics + .into_iter() + .map(|g| g.map(|g| f.fold_uint_expression(g)).transpose()) + .collect::>()?; + let exps = exps + .into_iter() + .map(|e| f.fold_expression(e)) + .collect::>()?; + ArrayExpressionInner::FunctionCall(id, generics, exps) + } + ArrayExpressionInner::IfElse(box condition, box consequence, box alternative) => { + ArrayExpressionInner::IfElse( + box f.fold_boolean_expression(condition)?, + box f.fold_array_expression(consequence)?, + box f.fold_array_expression(alternative)?, + ) + } + ArrayExpressionInner::Member(box s, id) => { + let s = f.fold_struct_expression(s)?; + ArrayExpressionInner::Member(box s, id) + } + ArrayExpressionInner::Select(box array, box index) => { + let array = f.fold_array_expression(array)?; + let index = f.fold_uint_expression(index)?; + ArrayExpressionInner::Select(box array, box index) + } + ArrayExpressionInner::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)?; + ArrayExpressionInner::Slice(box array, box from, box to) + } + ArrayExpressionInner::Repeat(box e, box count) => { + let e = f.fold_expression(e)?; + let count = f.fold_uint_expression(count)?; + ArrayExpressionInner::Repeat(box e, box count) + } + }; + Ok(e) +} + +pub fn fold_struct_expression_inner<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + _: &StructType<'ast, T>, + e: StructExpressionInner<'ast, T>, +) -> Result, F::Error> { + let e = match e { + StructExpressionInner::Identifier(id) => { + StructExpressionInner::Identifier(f.fold_name(id)?) + } + StructExpressionInner::Value(exprs) => StructExpressionInner::Value( + exprs + .into_iter() + .map(|e| f.fold_expression(e)) + .collect::>()?, + ), + StructExpressionInner::FunctionCall(id, generics, exps) => { + let generics = generics + .into_iter() + .map(|g| g.map(|g| f.fold_uint_expression(g)).transpose()) + .collect::>()?; + let exps = exps + .into_iter() + .map(|e| f.fold_expression(e)) + .collect::>()?; + StructExpressionInner::FunctionCall(id, generics, exps) + } + StructExpressionInner::IfElse(box condition, box consequence, box alternative) => { + StructExpressionInner::IfElse( + box f.fold_boolean_expression(condition)?, + box f.fold_struct_expression(consequence)?, + box f.fold_struct_expression(alternative)?, + ) + } + StructExpressionInner::Member(box s, id) => { + let s = f.fold_struct_expression(s)?; + StructExpressionInner::Member(box s, id) + } + StructExpressionInner::Select(box array, box index) => { + let array = f.fold_array_expression(array)?; + let index = f.fold_uint_expression(index)?; + StructExpressionInner::Select(box array, box index) + } + }; + Ok(e) +} + +pub fn fold_field_expression<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + e: FieldElementExpression<'ast, T>, +) -> Result, F::Error> { + let e = match e { + FieldElementExpression::Number(n) => FieldElementExpression::Number(n), + FieldElementExpression::Identifier(id) => { + FieldElementExpression::Identifier(f.fold_name(id)?) + } + 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::Neg(box e) => { + let e = f.fold_field_expression(e)?; + + FieldElementExpression::Neg(box e) + } + FieldElementExpression::Pos(box e) => { + let e = f.fold_field_expression(e)?; + + FieldElementExpression::Pos(box e) + } + FieldElementExpression::IfElse(box cond, box cons, box alt) => { + let cond = f.fold_boolean_expression(cond)?; + let cons = f.fold_field_expression(cons)?; + let alt = f.fold_field_expression(alt)?; + FieldElementExpression::IfElse(box cond, box cons, box alt) + } + FieldElementExpression::FunctionCall(key, generics, exps) => { + let generics = generics + .into_iter() + .map(|g| g.map(|g| f.fold_uint_expression(g)).transpose()) + .collect::>()?; + let exps = exps + .into_iter() + .map(|e| f.fold_expression(e)) + .collect::>()?; + FieldElementExpression::FunctionCall(key, generics, exps) + } + FieldElementExpression::Member(box s, id) => { + let s = f.fold_struct_expression(s)?; + FieldElementExpression::Member(box s, id) + } + FieldElementExpression::Select(box array, box index) => { + let array = f.fold_array_expression(array)?; + let index = f.fold_uint_expression(index)?; + FieldElementExpression::Select(box array, box index) + } + }; + Ok(e) +} + +pub fn fold_int_expression<'ast, T: Field, F: ResultFolder<'ast, T>>( + _: &mut F, + _: IntExpression<'ast, T>, +) -> Result, F::Error> { + unreachable!() +} + +pub fn fold_boolean_expression<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + e: BooleanExpression<'ast, T>, +) -> Result, F::Error> { + let e = match e { + BooleanExpression::Value(v) => BooleanExpression::Value(v), + BooleanExpression::Identifier(id) => BooleanExpression::Identifier(f.fold_name(id)?), + 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::ArrayEq(box e1, box e2) => { + let e1 = f.fold_array_expression(e1)?; + let e2 = f.fold_array_expression(e2)?; + BooleanExpression::ArrayEq(box e1, box e2) + } + BooleanExpression::StructEq(box e1, box e2) => { + let e1 = f.fold_struct_expression(e1)?; + let e2 = f.fold_struct_expression(e2)?; + BooleanExpression::StructEq(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::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::FieldGt(box e1, box e2) => { + let e1 = f.fold_field_expression(e1)?; + let e2 = f.fold_field_expression(e2)?; + BooleanExpression::FieldGt(box e1, box e2) + } + BooleanExpression::FieldGe(box e1, box e2) => { + let e1 = f.fold_field_expression(e1)?; + let e2 = f.fold_field_expression(e2)?; + BooleanExpression::FieldGe(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::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::UintGt(box e1, box e2) => { + let e1 = f.fold_uint_expression(e1)?; + let e2 = f.fold_uint_expression(e2)?; + BooleanExpression::UintGt(box e1, box e2) + } + BooleanExpression::UintGe(box e1, box e2) => { + let e1 = f.fold_uint_expression(e1)?; + let e2 = f.fold_uint_expression(e2)?; + BooleanExpression::UintGe(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) + } + BooleanExpression::FunctionCall(key, generics, exps) => { + let generics = generics + .into_iter() + .map(|g| g.map(|g| f.fold_uint_expression(g)).transpose()) + .collect::>()?; + let exps = exps + .into_iter() + .map(|e| f.fold_expression(e)) + .collect::>()?; + BooleanExpression::FunctionCall(key, generics, exps) + } + BooleanExpression::IfElse(box cond, box cons, box alt) => { + let cond = f.fold_boolean_expression(cond)?; + let cons = f.fold_boolean_expression(cons)?; + let alt = f.fold_boolean_expression(alt)?; + BooleanExpression::IfElse(box cond, box cons, box alt) + } + BooleanExpression::Member(box s, id) => { + let s = f.fold_struct_expression(s)?; + BooleanExpression::Member(box s, id) + } + BooleanExpression::Select(box array, box index) => { + let array = f.fold_array_expression(array)?; + let index = f.fold_uint_expression(index)?; + BooleanExpression::Select(box array, box index) + } + }; + Ok(e) +} + +pub fn fold_uint_expression<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + e: UExpression<'ast, T>, +) -> Result, F::Error> { + Ok(UExpression { + inner: f.fold_uint_expression_inner(e.bitwidth, e.inner)?, + ..e + }) +} + +pub fn fold_uint_expression_inner<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + _: UBitwidth, + e: UExpressionInner<'ast, T>, +) -> Result, F::Error> { + let e = match e { + UExpressionInner::Value(v) => UExpressionInner::Value(v), + UExpressionInner::Identifier(id) => UExpressionInner::Identifier(f.fold_name(id)?), + 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::FloorSub(box left, box right) => { + let left = f.fold_uint_expression(left)?; + let right = f.fold_uint_expression(right)?; + + UExpressionInner::FloorSub(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, box by) => { + let e = f.fold_uint_expression(e)?; + let by = f.fold_uint_expression(by)?; + + UExpressionInner::LeftShift(box e, box by) + } + UExpressionInner::RightShift(box e, box by) => { + let e = f.fold_uint_expression(e)?; + let by = f.fold_uint_expression(by)?; + + UExpressionInner::RightShift(box e, box by) + } + UExpressionInner::Not(box e) => { + let e = f.fold_uint_expression(e)?; + + UExpressionInner::Not(box e) + } + UExpressionInner::Neg(box e) => { + let e = f.fold_uint_expression(e)?; + + UExpressionInner::Neg(box e) + } + UExpressionInner::Pos(box e) => { + let e = f.fold_uint_expression(e)?; + + UExpressionInner::Pos(box e) + } + UExpressionInner::FunctionCall(key, generics, exps) => { + let generics = generics + .into_iter() + .map(|g| g.map(|g| f.fold_uint_expression(g)).transpose()) + .collect::>()?; + let exps = exps + .into_iter() + .map(|e| f.fold_expression(e)) + .collect::>()?; + UExpressionInner::FunctionCall(key, generics, exps) + } + UExpressionInner::Select(box array, box index) => { + let array = f.fold_array_expression(array)?; + let index = f.fold_uint_expression(index)?; + UExpressionInner::Select(box array, box index) + } + UExpressionInner::IfElse(box cond, box cons, box alt) => { + let cond = f.fold_boolean_expression(cond)?; + let cons = f.fold_uint_expression(cons)?; + let alt = f.fold_uint_expression(alt)?; + UExpressionInner::IfElse(box cond, box cons, box alt) + } + UExpressionInner::Member(box s, id) => { + let s = f.fold_struct_expression(s)?; + UExpressionInner::Member(box s, id) + } + }; + Ok(e) +} + +pub fn fold_function<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + fun: TypedFunction<'ast, T>, +) -> Result, F::Error> { + Ok(TypedFunction { + arguments: fun + .arguments + .into_iter() + .map(|a| f.fold_parameter(a)) + .collect::>()?, + statements: fun + .statements + .into_iter() + .map(|s| f.fold_statement(s)) + .collect::, _>>()? + .into_iter() + .flatten() + .collect(), + ..fun + }) +} + +pub fn fold_array_expression<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + e: ArrayExpression<'ast, T>, +) -> Result, F::Error> { + let ty = f.fold_array_type(*e.ty)?; + + Ok(ArrayExpression { + inner: f.fold_array_expression_inner(&ty, e.inner)?, + ty: box ty, + }) +} + +pub fn fold_expression_list<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + es: TypedExpressionList<'ast, T>, +) -> Result, F::Error> { + match es { + TypedExpressionList::FunctionCall(id, generics, arguments, types) => { + let generics = generics + .into_iter() + .map(|g| g.map(|g| f.fold_uint_expression(g)).transpose()) + .collect::>()?; + Ok(TypedExpressionList::FunctionCall( + id, + generics, + arguments + .into_iter() + .map(|a| f.fold_expression(a)) + .collect::>()?, + types + .into_iter() + .map(|t| f.fold_type(t)) + .collect::>()?, + )) + } + TypedExpressionList::EmbedCall(embed, generics, arguments, types) => { + Ok(TypedExpressionList::EmbedCall( + embed, + generics, + arguments + .into_iter() + .map(|a| f.fold_expression(a)) + .collect::>()?, + types + .into_iter() + .map(|t| f.fold_type(t)) + .collect::>()?, + )) + } + } +} + +pub fn fold_struct_expression<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + e: StructExpression<'ast, T>, +) -> Result, F::Error> { + Ok(StructExpression { + inner: f.fold_struct_expression_inner(&e.ty, e.inner)?, + ..e + }) +} + +pub fn fold_function_symbol<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + s: TypedFunctionSymbol<'ast, T>, +) -> Result, F::Error> { + match s { + TypedFunctionSymbol::Here(fun) => Ok(TypedFunctionSymbol::Here(f.fold_function(fun)?)), + there => Ok(there), // by default, do not fold modules recursively + } +} + +pub fn fold_module<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + p: TypedModule<'ast, T>, +) -> Result, F::Error> { + Ok(TypedModule { + functions: p + .functions + .into_iter() + .map(|(key, fun)| f.fold_function_symbol(fun).map(|f| (key, f))) + .collect::>()?, + }) +} + +pub fn fold_program<'ast, T: Field, F: ResultFolder<'ast, T>>( + f: &mut F, + p: TypedProgram<'ast, T>, +) -> Result, F::Error> { + Ok(TypedProgram { + modules: p + .modules + .into_iter() + .map(|(module_id, module)| f.fold_module(module).map(|m| (module_id, m))) + .collect::>()?, + main: p.main, + }) +} diff --git a/zokrates_core/src/typed_absy/types.rs b/zokrates_core/src/typed_absy/types.rs index e1831096c..6622bddde 100644 --- a/zokrates_core/src/typed_absy/types.rs +++ b/zokrates_core/src/typed_absy/types.rs @@ -1,24 +1,257 @@ +use crate::typed_absy::{OwnedTypedModuleId, UExpression, UExpressionInner}; +use crate::typed_absy::{TryFrom, TryInto}; use serde::{de::Error, ser::SerializeMap, Deserialize, Deserializer, Serialize, Serializer}; +use std::collections::BTreeMap; use std::fmt; +use std::hash::{Hash, Hasher}; use std::path::{Path, PathBuf}; -pub type Identifier<'ast> = &'ast str; +pub type GenericIdentifier<'ast> = &'ast str; + +#[derive(Debug)] +pub struct SpecializationError; + +#[derive(Debug, Clone)] +pub enum Constant<'ast> { + Generic(GenericIdentifier<'ast>), + Concrete(u32), +} + +// At this stage we want all constants to be equal +impl<'ast> PartialEq for Constant<'ast> { + fn eq(&self, _: &Self) -> bool { + true + } +} + +impl<'ast> PartialOrd for Constant<'ast> { + fn partial_cmp(&self, _: &Self) -> std::option::Option { + Some(std::cmp::Ordering::Equal) + } +} + +impl<'ast> Ord for Constant<'ast> { + fn cmp(&self, _: &Self) -> std::cmp::Ordering { + std::cmp::Ordering::Equal + } +} + +impl<'ast> Eq for Constant<'ast> {} + +impl<'ast> Hash for Constant<'ast> { + fn hash(&self, _: &mut H) + where + H: Hasher, + { + // we do not hash anything, as we want all constant to hash to the same thing + } +} + +impl<'ast> From for Constant<'ast> { + fn from(e: u32) -> Self { + Constant::Concrete(e) + } +} + +impl<'ast> From for Constant<'ast> { + fn from(e: usize) -> Self { + Constant::Concrete(e as u32) + } +} + +impl<'ast> From> for Constant<'ast> { + fn from(e: GenericIdentifier<'ast>) -> Self { + Constant::Generic(e) + } +} + +impl<'ast> fmt::Display for Constant<'ast> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Constant::Generic(i) => write!(f, "{}", i), + Constant::Concrete(v) => write!(f, "{}", v), + } + } +} + +impl<'ast, T> From for UExpression<'ast, T> { + fn from(i: usize) -> Self { + UExpressionInner::Value(i as u128).annotate(UBitwidth::B32) + } +} + +impl<'ast, T> From> for UExpression<'ast, T> { + fn from(c: Constant<'ast>) -> Self { + match c { + Constant::Generic(i) => UExpressionInner::Identifier(i.into()).annotate(UBitwidth::B32), + Constant::Concrete(v) => UExpressionInner::Value(v as u128).annotate(UBitwidth::B32), + } + } +} + +impl<'ast, T> TryInto for UExpression<'ast, T> { + type Error = SpecializationError; + + fn try_into(self) -> Result { + assert_eq!(self.bitwidth, UBitwidth::B32); + + match self.into_inner() { + UExpressionInner::Value(v) => Ok(v as usize), + _ => Err(SpecializationError), + } + } +} + +impl<'ast> TryInto for Constant<'ast> { + type Error = SpecializationError; + + fn try_into(self) -> Result { + match self { + Constant::Concrete(v) => Ok(v as usize), + _ => Err(SpecializationError), + } + } +} pub type MemberId = String; #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord)] -pub struct StructMember { +pub struct GStructMember { #[serde(rename = "name")] pub id: MemberId, #[serde(flatten)] - pub ty: Box, + pub ty: Box>, } -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord)] -pub struct ArrayType { - pub size: usize, +pub type DeclarationStructMember<'ast> = GStructMember>; +pub type ConcreteStructMember = GStructMember; +pub type StructMember<'ast, T> = GStructMember>; + +impl<'ast, T: PartialEq> PartialEq> for StructMember<'ast, T> { + fn eq(&self, other: &DeclarationStructMember<'ast>) -> bool { + self.id == other.id && *self.ty == *other.ty + } +} + +fn try_from_g_struct_member, U>( + t: GStructMember, +) -> Result, SpecializationError> { + Ok(GStructMember { + id: t.id, + ty: box try_from_g_type(*t.ty)?, + }) +} + +impl<'ast, T> TryFrom> for ConcreteStructMember { + type Error = SpecializationError; + + fn try_from(t: StructMember<'ast, T>) -> Result { + try_from_g_struct_member(t) + } +} + +impl<'ast, T> From for StructMember<'ast, T> { + fn from(t: ConcreteStructMember) -> Self { + try_from_g_struct_member(t).unwrap() + } +} + +impl<'ast> From for DeclarationStructMember<'ast> { + fn from(t: ConcreteStructMember) -> Self { + try_from_g_struct_member(t).unwrap() + } +} + +impl<'ast, T> From> for StructMember<'ast, T> { + fn from(t: DeclarationStructMember<'ast>) -> Self { + try_from_g_struct_member(t).unwrap() + } +} + +#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord)] +pub struct GArrayType { + pub size: S, #[serde(flatten)] - pub ty: Box, + pub ty: Box>, +} + +pub type DeclarationArrayType<'ast> = GArrayType>; +pub type ConcreteArrayType = GArrayType; +pub type ArrayType<'ast, T> = GArrayType>; + +impl<'ast, T: PartialEq> PartialEq> for ArrayType<'ast, T> { + fn eq(&self, other: &DeclarationArrayType<'ast>) -> bool { + *self.ty == *other.ty + && match (self.size.as_inner(), &other.size) { + (UExpressionInner::Value(l), Constant::Concrete(r)) => *l as u32 == *r, + _ => true, + } + } +} + +impl fmt::Display for GArrayType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt_aux<'a, S: fmt::Display>( + f: &mut fmt::Formatter, + t: &'a GArrayType, + mut acc: Vec<&'a S>, + ) -> fmt::Result { + acc.push(&t.size); + match &*t.ty { + GType::Array(array_type) => fmt_aux(f, &array_type, acc), + t => { + write!(f, "{}", t)?; + for i in acc { + write!(f, "[{}]", i)?; + } + write!(f, "") + } + } + } + + let acc = vec![]; + + fmt_aux(f, &self, acc) + } +} + +impl<'ast, T: PartialEq + fmt::Display> Type<'ast, T> { + // array type equality with non-strict size checks + // sizes always match unless they are different constants + pub fn weak_eq(&self, other: &Self) -> bool { + match (self, other) { + (Type::Array(t), Type::Array(u)) => t.ty.weak_eq(&u.ty), + (Type::Struct(t), Type::Struct(u)) => t + .members + .iter() + .zip(u.members.iter()) + .all(|(m, n)| m.ty.weak_eq(&n.ty)), + (t, u) => t == u, + } + } +} + +fn try_from_g_array_type, U>( + t: GArrayType, +) -> Result, SpecializationError> { + Ok(GArrayType { + size: t.size.try_into().map_err(|_| SpecializationError)?, + ty: box try_from_g_type(*t.ty)?, + }) +} + +impl<'ast, T> TryFrom> for ConcreteArrayType { + type Error = SpecializationError; + + fn try_from(t: ArrayType<'ast, T>) -> Result { + try_from_g_array_type(t) + } +} + +impl<'ast, T> From for ArrayType<'ast, T> { + fn from(t: ConcreteArrayType) -> Self { + try_from_g_array_type(t).unwrap() + } } #[derive(Debug, Clone, Hash, Serialize, Deserialize, PartialOrd, Ord, Eq, PartialEq)] @@ -28,37 +261,99 @@ pub struct StructLocation { pub name: String, } -#[derive(Debug, Clone, Hash, Serialize, Deserialize, PartialOrd, Ord)] -pub struct StructType { +impl<'ast> From for DeclarationArrayType<'ast> { + fn from(t: ConcreteArrayType) -> Self { + try_from_g_array_type(t).unwrap() + } +} + +impl<'ast, T> From> for ArrayType<'ast, T> { + fn from(t: DeclarationArrayType<'ast>) -> Self { + try_from_g_array_type(t).unwrap() + } +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialOrd, Ord)] +pub struct GStructType { #[serde(flatten)] pub canonical_location: StructLocation, #[serde(skip)] pub location: Option, - pub members: Vec, + pub members: Vec>, } -impl PartialEq for StructType { +pub type DeclarationStructType<'ast> = GStructType>; +pub type ConcreteStructType = GStructType; +pub type StructType<'ast, T> = GStructType>; + +impl PartialEq for GStructType { fn eq(&self, other: &Self) -> bool { - self.canonical_location.eq(&other.canonical_location) && self.members.eq(&other.members) + self.canonical_location.eq(&other.canonical_location) + } +} + +impl Hash for GStructType { + fn hash(&self, state: &mut H) { + self.canonical_location.hash(state); + } +} + +impl Eq for GStructType {} + +fn try_from_g_struct_type, U>( + t: GStructType, +) -> Result, SpecializationError> { + Ok(GStructType { + location: t.location, + canonical_location: t.canonical_location, + members: t + .members + .into_iter() + .map(try_from_g_struct_member) + .collect::>()?, + }) +} + +impl<'ast, T> TryFrom> for ConcreteStructType { + type Error = SpecializationError; + + fn try_from(t: StructType<'ast, T>) -> Result { + try_from_g_struct_type(t) } } -impl Eq for StructType {} +impl<'ast, T> From for StructType<'ast, T> { + fn from(t: ConcreteStructType) -> Self { + try_from_g_struct_type(t).unwrap() + } +} -impl StructType { - pub fn new(module: PathBuf, name: String, members: Vec) -> Self { - StructType { +impl<'ast> From for DeclarationStructType<'ast> { + fn from(t: ConcreteStructType) -> Self { + try_from_g_struct_type(t).unwrap() + } +} + +impl<'ast, T> From> for StructType<'ast, T> { + fn from(t: DeclarationStructType<'ast>) -> Self { + try_from_g_struct_type(t).unwrap() + } +} + +impl GStructType { + pub fn new(module: PathBuf, name: String, members: Vec>) -> Self { + GStructType { canonical_location: StructLocation { module, name }, location: None, members, } } - pub fn len(&self) -> usize { + pub fn members_count(&self) -> usize { self.members.len() } - pub fn iter(&self) -> std::slice::Iter { + pub fn iter(&self) -> std::slice::Iter> { self.members.iter() } @@ -75,8 +370,8 @@ impl StructType { } } -impl IntoIterator for StructType { - type Item = StructMember; +impl IntoIterator for GStructType { + type Item = GStructMember; type IntoIter = std::vec::IntoIter; fn into_iter(self) -> Self::IntoIter { @@ -92,6 +387,8 @@ pub enum UBitwidth { B16 = 16, #[serde(rename = "32")] B32 = 32, + #[serde(rename = "64")] + B64 = 64, } impl UBitwidth { @@ -106,6 +403,7 @@ impl From for UBitwidth { 8 => UBitwidth::B8, 16 => UBitwidth::B16, 32 => UBitwidth::B32, + 64 => UBitwidth::B64, _ => unreachable!(), } } @@ -118,144 +416,222 @@ impl fmt::Display for UBitwidth { } #[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub enum Type { +pub enum GType { FieldElement, Boolean, - Array(ArrayType), - Struct(StructType), + Array(GArrayType), + Struct(GStructType), Uint(UBitwidth), + Int, } -impl serde::Serialize for Type { +impl Serialize for GType { fn serialize(&self, s: S) -> Result<::Ok, ::Error> where S: Serializer, { + use serde::ser::Error; + match self { - Type::FieldElement => s.serialize_newtype_variant("Type", 0, "type", "field"), - Type::Boolean => s.serialize_newtype_variant("Type", 1, "type", "bool"), - Type::Array(array_type) => { + GType::FieldElement => s.serialize_newtype_variant("Type", 0, "type", "field"), + GType::Boolean => s.serialize_newtype_variant("Type", 1, "type", "bool"), + GType::Array(array_type) => { let mut map = s.serialize_map(Some(2))?; map.serialize_entry("type", "array")?; map.serialize_entry("components", array_type)?; map.end() } - Type::Struct(struct_type) => { + GType::Struct(struct_type) => { let mut map = s.serialize_map(Some(2))?; map.serialize_entry("type", "struct")?; map.serialize_entry("components", struct_type)?; map.end() } - Type::Uint(width) => s.serialize_newtype_variant( + GType::Uint(width) => s.serialize_newtype_variant( "Type", 4, "type", format!("u{}", width.to_usize()).as_str(), ), + GType::Int => Err(S::Error::custom( + "Cannot serialize Int type as it's not allowed in function signatures".to_string(), + )), } } } -impl<'de> serde::Deserialize<'de> for Type { +impl<'de, S: Deserialize<'de>> Deserialize<'de> for GType { fn deserialize(d: D) -> Result>::Error> where D: Deserializer<'de>, { - #[derive(Debug, Deserialize)] + #[derive(Deserialize)] #[serde(untagged)] - enum Components { - Array(ArrayType), - Struct(StructType), + enum Components { + Array(GArrayType), + Struct(GStructType), } - #[derive(Debug, Deserialize)] - struct Mapping { + #[derive(Deserialize)] + struct Mapping { #[serde(rename = "type")] ty: String, - components: Option, + components: Option>, } - let strict_type = |m: Mapping, ty: Type| -> Result>::Error> { - match m.components { - Some(_) => Err(D::Error::custom(format!( - "unexpected `components` field for type `{}`", - ty - ))), - None => Ok(ty), - } - }; + let strict_type = + |m: Mapping, ty: GType| -> Result>::Error> { + match m.components { + Some(_) => Err(D::Error::custom(format!( + "unexpected `components` field in type {}", + m.ty + ))), + None => Ok(ty), + } + }; let mapping = Mapping::deserialize(d)?; match mapping.ty.as_str() { - "field" => strict_type(mapping, Type::FieldElement), - "bool" => strict_type(mapping, Type::Boolean), + "field" => strict_type(mapping, GType::FieldElement), + "bool" => strict_type(mapping, GType::Boolean), "array" => { - let components = mapping.components.ok_or(D::Error::custom(format_args!( - "missing `components` field for type `{}'", - mapping.ty - )))?; + let components = mapping + .components + .ok_or_else(|| D::Error::custom("missing `components` field".to_string()))?; match components { - Components::Array(array_type) => Ok(Type::Array(array_type)), - _ => Err(D::Error::custom(format!( - "invalid `components` variant for type `{}`", - mapping.ty - ))), + Components::Array(array_type) => Ok(GType::Array(array_type)), + _ => Err(D::Error::custom("invalid `components` variant".to_string())), } } "struct" => { - let components = mapping.components.ok_or(D::Error::custom(format_args!( - "missing `components` field for type `{}'", - mapping.ty - )))?; + let components = mapping + .components + .ok_or_else(|| D::Error::custom("missing `components` field".to_string()))?; match components { - Components::Struct(struct_type) => Ok(Type::Struct(struct_type)), - _ => Err(D::Error::custom(format!( - "invalid `components` variant for type `{}`", - mapping.ty - ))), + Components::Struct(struct_type) => Ok(GType::Struct(struct_type)), + _ => Err(D::Error::custom("invalid `components` variant".to_string())), } } - "u8" => strict_type(mapping, Type::Uint(UBitwidth::B8)), - "u16" => strict_type(mapping, Type::Uint(UBitwidth::B16)), - "u32" => strict_type(mapping, Type::Uint(UBitwidth::B32)), - _ => Err(D::Error::custom(format!("invalid type `{}`", mapping.ty))), + "u8" => strict_type(mapping, GType::Uint(UBitwidth::B8)), + "u16" => strict_type(mapping, GType::Uint(UBitwidth::B16)), + "u32" => strict_type(mapping, GType::Uint(UBitwidth::B32)), + "u64" => strict_type(mapping, GType::Uint(UBitwidth::B64)), + t => Err(D::Error::custom(format!("invalid type `{}`", t))), + } + } +} + +pub type DeclarationType<'ast> = GType>; +pub type ConcreteType = GType; +pub type Type<'ast, T> = GType>; + +impl<'ast, T: PartialEq> PartialEq> for Type<'ast, T> { + fn eq(&self, other: &DeclarationType<'ast>) -> bool { + use self::GType::*; + + match (self, other) { + (Array(l), Array(r)) => l == r, + (Struct(l), Struct(r)) => l.canonical_location == r.canonical_location, + (FieldElement, FieldElement) | (Boolean, Boolean) => true, + (Uint(l), Uint(r)) => l == r, + _ => false, + } + } +} + +fn try_from_g_type, U>(t: GType) -> Result, SpecializationError> { + match t { + GType::FieldElement => Ok(GType::FieldElement), + GType::Boolean => Ok(GType::Boolean), + GType::Int => Ok(GType::Int), + GType::Uint(bitwidth) => Ok(GType::Uint(bitwidth)), + GType::Array(array_type) => Ok(GType::Array(try_from_g_array_type(array_type)?)), + GType::Struct(struct_type) => Ok(GType::Struct(try_from_g_struct_type(struct_type)?)), + } +} + +impl<'ast, T> TryFrom> for ConcreteType { + type Error = SpecializationError; + + fn try_from(t: Type<'ast, T>) -> Result { + try_from_g_type(t) + } +} + +impl<'ast, T> From for Type<'ast, T> { + fn from(t: ConcreteType) -> Self { + try_from_g_type(t).unwrap() + } +} + +impl<'ast> From for DeclarationType<'ast> { + fn from(t: ConcreteType) -> Self { + try_from_g_type(t).unwrap() + } +} + +impl<'ast, T> From> for Type<'ast, T> { + fn from(t: DeclarationType<'ast>) -> Self { + try_from_g_type(t).unwrap() + } +} + +impl> From<(GType, U)> for GArrayType { + fn from(tup: (GType, U)) -> Self { + GArrayType { + ty: box tup.0, + size: tup.1.into(), } } } -impl ArrayType { - pub fn new(ty: Type, size: usize) -> Self { - ArrayType { +impl GArrayType { + pub fn new(ty: GType, size: S) -> Self { + GArrayType { ty: Box::new(ty), size, } } } -impl StructMember { - pub fn new(id: String, ty: Type) -> Self { - StructMember { +impl GStructMember { + pub fn new(id: String, ty: GType) -> Self { + GStructMember { id, ty: Box::new(ty), } } } -impl fmt::Display for Type { +impl fmt::Display for GType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - Type::FieldElement => write!(f, "field"), - Type::Boolean => write!(f, "bool"), - Type::Uint(ref bitwidth) => write!(f, "u{}", bitwidth), - Type::Array(ref array_type) => write!(f, "{}[{}]", array_type.ty, array_type.size), - Type::Struct(ref struct_type) => write!( + GType::FieldElement => write!(f, "field"), + GType::Boolean => write!(f, "bool"), + GType::Uint(ref bitwidth) => write!(f, "u{}", bitwidth), + GType::Int => write!(f, "{{integer}}"), + GType::Array(ref array_type) => write!(f, "{}", array_type), + GType::Struct(ref struct_type) => write!(f, "{}", struct_type.name(),), + } + } +} + +impl fmt::Debug for GType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + GType::FieldElement => write!(f, "field"), + GType::Boolean => write!(f, "bool"), + GType::Int => write!(f, "integer"), + GType::Uint(ref bitwidth) => write!(f, "u{:?}", bitwidth), + GType::Array(ref array_type) => write!(f, "{:?}[{:?}]", array_type.ty, array_type.size), + GType::Struct(ref struct_type) => write!( f, - "{} {{{}}}", + "{:?} {{{:?}}}", struct_type.name(), struct_type .members .iter() - .map(|member| format!("{}: {}", member.id, member.ty)) + .map(|member| format!("{:?}: {:?}", member.id, member.ty)) .collect::>() .join(", ") ), @@ -263,38 +639,48 @@ impl fmt::Display for Type { } } -impl fmt::Debug for Type { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Type::FieldElement => write!(f, "field"), - Type::Boolean => write!(f, "bool"), - Type::Uint(ref bitwidth) => write!(f, "u{}", bitwidth), - Type::Array(ref array_type) => write!(f, "{}[{}]", array_type.ty, array_type.size), - Type::Struct(ref struct_type) => write!(f, "{:?}", struct_type), - } +impl GType { + pub fn array>>(array_ty: U) -> Self { + GType::Array(array_ty.into()) } -} -impl Type { - pub fn array(ty: Type, size: usize) -> Self { - Type::Array(ArrayType::new(ty, size)) + pub fn struc>>(struct_ty: U) -> Self { + GType::Struct(struct_ty.into()) } - pub fn struc(struct_ty: StructType) -> Self { - Type::Struct(struct_ty) + pub fn uint>(b: W) -> Self { + GType::Uint(b.into()) } +} - pub fn uint>(b: W) -> Self { - Type::Uint(b.into()) +impl<'ast, T: fmt::Display + PartialEq + fmt::Debug> Type<'ast, T> { + pub fn can_be_specialized_to(&self, other: &DeclarationType) -> bool { + use self::GType::*; + + if self == other { + true + } else { + match (self, other) { + (Int, FieldElement) | (Int, Uint(..)) => true, + (Array(l), Array(r)) => l.ty.can_be_specialized_to(&r.ty), + // types do not come into play for Struct equality, only the canonical location. Hence no inference + // can change anything + (Struct(_), Struct(_)) => false, + _ => false, + } + } } +} +impl ConcreteType { fn to_slug(&self) -> String { match self { - Type::FieldElement => String::from("f"), - Type::Boolean => String::from("b"), - Type::Uint(bitwidth) => format!("u{}", bitwidth), - Type::Array(array_type) => format!("{}[{}]", array_type.ty.to_slug(), array_type.size), - Type::Struct(struct_type) => format!( + GType::FieldElement => String::from("f"), + GType::Int => unreachable!(), + GType::Boolean => String::from("b"), + GType::Uint(bitwidth) => format!("u{}", bitwidth), + GType::Array(array_type) => format!("{}[{}]", array_type.ty.to_slug(), array_type.size), + GType::Struct(struct_type) => format!( "{{{}}}", struct_type .iter() @@ -304,15 +690,18 @@ impl Type { ), } } +} +impl ConcreteType { // the number of field elements the type maps to pub fn get_primitive_count(&self) -> usize { match self { - Type::FieldElement => 1, - Type::Boolean => 1, - Type::Uint(_) => 1, - Type::Array(array_type) => array_type.size * array_type.ty.get_primitive_count(), - Type::Struct(struct_type) => struct_type + GType::FieldElement => 1, + GType::Boolean => 1, + GType::Uint(_) => 1, + GType::Array(array_type) => array_type.size * array_type.ty.get_primitive_count(), + GType::Int => unreachable!(), + GType::Struct(struct_type) => struct_type .iter() .map(|member| member.ty.get_primitive_count()) .sum(), @@ -323,71 +712,418 @@ impl Type { pub type FunctionIdentifier<'ast> = &'ast str; #[derive(PartialEq, Eq, Hash, Debug, Clone)] -pub struct FunctionKey<'ast> { +pub struct GFunctionKey<'ast, S> { + pub module: OwnedTypedModuleId, pub id: FunctionIdentifier<'ast>, - pub signature: Signature, + pub signature: GSignature, } -pub type FunctionKeyHash = u64; +pub type DeclarationFunctionKey<'ast> = GFunctionKey<'ast, Constant<'ast>>; +pub type ConcreteFunctionKey<'ast> = GFunctionKey<'ast, usize>; +pub type FunctionKey<'ast, T> = GFunctionKey<'ast, UExpression<'ast, T>>; -impl<'ast> FunctionKey<'ast> { - pub fn with_id>>(id: S) -> Self { - FunctionKey { - id: id.into(), - signature: Signature::new(), - } +impl<'ast, S: fmt::Display> fmt::Display for GFunctionKey<'ast, S> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}/{}{}", self.module.display(), self.id, self.signature) } +} + +#[derive(Debug, PartialEq, Eq, Hash, Clone)] +pub struct GGenericsAssignment<'ast, S>(pub BTreeMap, S>); + +pub type ConcreteGenericsAssignment<'ast> = GGenericsAssignment<'ast, usize>; +pub type GenericsAssignment<'ast, T> = GGenericsAssignment<'ast, UExpression<'ast, T>>; + +impl<'ast, S> Default for GGenericsAssignment<'ast, S> { + fn default() -> Self { + GGenericsAssignment(BTreeMap::new()) + } +} + +impl<'ast, S: fmt::Display> fmt::Display for GGenericsAssignment<'ast, S> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "{}", + self.0 + .iter() + .map(|(k, v)| format!("{}: {}", k, v)) + .collect::>() + .join(", ") + ) + } +} + +impl<'ast> PartialEq> for ConcreteFunctionKey<'ast> { + fn eq(&self, other: &DeclarationFunctionKey<'ast>) -> bool { + self.module == other.module && self.id == other.id && self.signature == other.signature + } +} + +fn try_from_g_function_key, U>( + k: GFunctionKey, +) -> Result, SpecializationError> { + Ok(GFunctionKey { + module: k.module, + signature: signature::try_from_g_signature(k.signature)?, + id: k.id, + }) +} - pub fn hash(&self) -> FunctionKeyHash { - use std::hash::Hasher; +impl<'ast, T> TryFrom> for ConcreteFunctionKey<'ast> { + type Error = SpecializationError; - let mut hasher = std::collections::hash_map::DefaultHasher::new(); - ::hash(self, &mut hasher); - hasher.finish() + fn try_from(k: FunctionKey<'ast, T>) -> Result { + try_from_g_function_key(k) } +} + +// impl<'ast> TryFrom> for ConcreteFunctionKey<'ast> { +// type Error = SpecializationError; - pub fn signature(mut self, signature: Signature) -> Self { +// fn try_from(k: DeclarationFunctionKey<'ast>) -> Result { +// try_from_g_function_key(k) +// } +// } + +impl<'ast, T> From> for FunctionKey<'ast, T> { + fn from(k: ConcreteFunctionKey<'ast>) -> Self { + try_from_g_function_key(k).unwrap() + } +} + +impl<'ast> From> for DeclarationFunctionKey<'ast> { + fn from(k: ConcreteFunctionKey<'ast>) -> Self { + try_from_g_function_key(k).unwrap() + } +} + +impl<'ast, T> From> for FunctionKey<'ast, T> { + fn from(k: DeclarationFunctionKey<'ast>) -> Self { + try_from_g_function_key(k).unwrap() + } +} + +impl<'ast, S> GFunctionKey<'ast, S> { + pub fn with_location, U: Into>>( + module: T, + id: U, + ) -> Self { + GFunctionKey { + module: module.into(), + id: id.into(), + signature: GSignature::new(), + } + } + + pub fn signature(mut self, signature: GSignature) -> Self { self.signature = signature; self } - pub fn id>>(mut self, id: S) -> Self { + pub fn id>>(mut self, id: U) -> Self { self.id = id.into(); self } + pub fn module>(mut self, module: T) -> Self { + self.module = module.into(); + self + } +} + +impl<'ast> ConcreteFunctionKey<'ast> { pub fn to_slug(&self) -> String { - format!("{}_{}", self.id, self.signature.to_slug()) + format!( + "{}/{}_{}", + self.module.display(), + self.id, + self.signature.to_slug() + ) } } -pub use self::signature::Signature; -// use serde::de::Error; -// use serde::ser::SerializeMap; -// use serde::{Deserializer, Serializer}; +pub use self::signature::{ConcreteSignature, DeclarationSignature, GSignature, Signature}; pub mod signature { use super::*; use std::fmt; - #[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Ord, PartialOrd)] - pub struct Signature { - pub inputs: Vec, - pub outputs: Vec, + #[derive(Clone, Serialize, Deserialize, Eq)] + pub struct GSignature { + pub generics: Vec>, + pub inputs: Vec>, + pub outputs: Vec>, + } + + impl PartialOrd for GSignature { + fn partial_cmp(&self, other: &Self) -> std::option::Option { + match self.inputs.partial_cmp(&other.inputs) { + Some(std::cmp::Ordering::Equal) => self.outputs.partial_cmp(&other.outputs), + r => r, + } + } + } + + impl Ord for GSignature { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.partial_cmp(&other).unwrap() + } + } + + impl Hash for GSignature { + fn hash(&self, state: &mut H) { + self.inputs.hash(state); + self.outputs.hash(state); + } + } + + impl PartialEq for GSignature { + fn eq(&self, other: &GSignature) -> bool { + // we ignore generics as we want a generic function to conflict with its specialized (generics free) version + self.inputs == other.inputs && self.outputs == other.outputs + } + } + + impl Default for GSignature { + fn default() -> Self { + GSignature { + generics: vec![], + inputs: vec![], + outputs: vec![], + } + } + } + + pub type DeclarationSignature<'ast> = GSignature>; + pub type ConcreteSignature = GSignature; + pub type Signature<'ast, T> = GSignature>; + + use std::collections::btree_map::Entry; + + fn check_type<'ast, S: Clone + PartialEq + PartialEq>( + decl_ty: &DeclarationType<'ast>, + ty: >ype, + constants: &mut GGenericsAssignment<'ast, S>, + ) -> bool { + match (decl_ty, ty) { + (DeclarationType::Array(t0), GType::Array(t1)) => { + let s1 = t1.size.clone(); + + // both the inner type and the size must match + check_type(&t0.ty, &t1.ty, constants) + && match t0.size { + // if the declared size is an identifier, we insert into the map, or check if the concrete size + // matches if this identifier is already in the map + Constant::Generic(id) => match constants.0.entry(id) { + Entry::Occupied(e) => *e.get() == s1, + Entry::Vacant(e) => { + e.insert(s1); + true + } + }, + Constant::Concrete(s0) => s1 == s0 as usize, + } + } + (DeclarationType::FieldElement, GType::FieldElement) + | (DeclarationType::Boolean, GType::Boolean) => true, + (DeclarationType::Uint(b0), GType::Uint(b1)) => b0 == b1, + (DeclarationType::Struct(s0), GType::Struct(s1)) => { + s0.canonical_location == s1.canonical_location + } + _ => false, + } + } + + fn specialize_type<'ast, S: Clone + PartialEq + PartialEq + From + fmt::Debug>( + decl_ty: DeclarationType<'ast>, + constants: &GGenericsAssignment<'ast, S>, + ) -> Result, GenericIdentifier<'ast>> { + Ok(match decl_ty { + DeclarationType::Int => unreachable!(), + DeclarationType::Array(t0) => { + // let s1 = t1.size.clone(); + + let ty = box specialize_type(*t0.ty, &constants)?; + let size = match t0.size { + Constant::Generic(s) => constants.0.get(&s).cloned().ok_or(s), + Constant::Concrete(s) => Ok(s.into()), + }?; + + GType::Array(GArrayType { size, ty }) + } + DeclarationType::FieldElement => GType::FieldElement, + DeclarationType::Boolean => GType::Boolean, + DeclarationType::Uint(b0) => GType::Uint(b0), + DeclarationType::Struct(s0) => GType::Struct(GStructType { + members: s0 + .members + .into_iter() + .map(|m| { + let id = m.id; + specialize_type(*m.ty, constants).map(|ty| GStructMember { ty: box ty, id }) + }) + .collect::>()?, + canonical_location: s0.canonical_location, + location: s0.location, + }), + }) + } + + impl<'ast> PartialEq> for ConcreteSignature { + fn eq(&self, other: &DeclarationSignature<'ast>) -> bool { + // we keep track of the value of constants in a map, as a given constant can only have one value + let mut constants = ConcreteGenericsAssignment::default(); + + other + .inputs + .iter() + .chain(other.outputs.iter()) + .zip(self.inputs.iter().chain(self.outputs.iter())) + .all(|(decl_ty, ty)| check_type::(decl_ty, ty, &mut constants)) + } + } + + impl<'ast> DeclarationSignature<'ast> { + pub fn specialize( + &self, + values: Vec>, + signature: &ConcreteSignature, + ) -> Result, SpecializationError> { + // we keep track of the value of constants in a map, as a given constant can only have one value + let mut constants = ConcreteGenericsAssignment::default(); + + assert_eq!(self.generics.len(), values.len()); + + let decl_generics = self.generics.iter().map(|g| match g.clone().unwrap() { + Constant::Generic(g) => g, + _ => unreachable!(), + }); + + constants.0.extend( + decl_generics + .zip(values.into_iter()) + .filter_map(|(g, v)| v.map(|v| (g, v as usize))), + ); + + let condition = self + .inputs + .iter() + .chain(self.outputs.iter()) + .zip(signature.inputs.iter().chain(signature.outputs.iter())) + .all(|(decl_ty, ty)| check_type(decl_ty, ty, &mut constants)); + + if constants.0.len() != self.generics.len() { + return Err(SpecializationError); + } + + match condition { + true => Ok(constants), + false => Err(SpecializationError), + } + } + + pub fn get_output_types( + &self, + inputs: Vec>, + ) -> Result>, GenericIdentifier<'ast>> { + // we keep track of the value of constants in a map, as a given constant can only have one value + let mut constants = GenericsAssignment::default(); + + // fill the map with the inputs + let _ = self + .inputs + .iter() + .zip(inputs.iter()) + .all(|(decl_ty, ty)| check_type(decl_ty, ty, &mut constants)); + + // get the outputs from the map + self.outputs + .clone() + .into_iter() + .map(|t| specialize_type(t, &constants)) + .collect::>() + } + } + + pub fn try_from_g_signature, U>( + t: GSignature, + ) -> Result, SpecializationError> { + Ok(GSignature { + generics: t + .generics + .into_iter() + .map(|g| match g { + Some(g) => g.try_into().map(Some).map_err(|_| SpecializationError), + None => Ok(None), + }) + .collect::>()?, + inputs: t + .inputs + .into_iter() + .map(try_from_g_type) + .collect::>()?, + outputs: t + .outputs + .into_iter() + .map(try_from_g_type) + .collect::>()?, + }) + } + + impl<'ast, T> TryFrom> for ConcreteSignature { + type Error = SpecializationError; + + fn try_from(s: Signature<'ast, T>) -> Result { + try_from_g_signature(s) + } + } + + impl<'ast, T> From for Signature<'ast, T> { + fn from(s: ConcreteSignature) -> Self { + try_from_g_signature(s).unwrap() + } + } + + impl<'ast> From for DeclarationSignature<'ast> { + fn from(s: ConcreteSignature) -> Self { + try_from_g_signature(s).unwrap() + } } - impl fmt::Debug for Signature { + impl<'ast, T> From> for Signature<'ast, T> { + fn from(s: DeclarationSignature<'ast>) -> Self { + try_from_g_signature(s).unwrap() + } + } + + impl fmt::Debug for GSignature { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, - "Signature(inputs: {:?}, outputs: {:?})", - self.inputs, self.outputs + "Signature(generics: {:?}, inputs: {:?}, outputs: {:?})", + self.generics, self.inputs, self.outputs ) } } - impl fmt::Display for Signature { + impl fmt::Display for GSignature { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if !self.generics.is_empty() { + write!( + f, + "<{}>", + self.generics + .iter() + .map(|g| g + .as_ref() + .map(|g| g.to_string()) + .unwrap_or_else(|| '_'.to_string())) + .collect::>() + .join(", ") + )?; + } + write!(f, "(")?; for (i, t) in self.inputs.iter().enumerate() { write!(f, "{}", t)?; @@ -413,7 +1149,28 @@ pub mod signature { } } - impl Signature { + impl GSignature { + pub fn new() -> GSignature { + Self::default() + } + + pub fn generics(mut self, generics: Vec>) -> Self { + self.generics = generics; + self + } + + pub fn inputs(mut self, inputs: Vec>) -> Self { + self.inputs = inputs; + self + } + + pub fn outputs(mut self, outputs: Vec>) -> Self { + self.outputs = outputs; + self + } + } + + impl ConcreteSignature { /// Returns a slug for a signature, with the following encoding: /// i{inputs}o{outputs} where {inputs} and {outputs} each encode a list of types. /// A list of types is encoded by compressing sequences of the same type like so: @@ -424,22 +1181,20 @@ pub mod signature { /// [field, field, bool, field] -> 2fbf /// pub fn to_slug(&self) -> String { - let to_slug = |types| { + let to_slug = |types: &[ConcreteType]| { let mut res = vec![]; for t in types { let len = res.len(); if len == 0 { res.push((1, t)) + } else if res[len - 1].1 == t { + res[len - 1].0 += 1; } else { - if res[len - 1].1 == t { - res[len - 1].0 += 1; - } else { - res.push((1, t)) - } + res.push((1, t)) } } res.into_iter() - .map(|(n, t): (usize, &Type)| { + .map(|(n, t): (usize, &ConcreteType)| { let mut r = String::new(); if n > 1 { @@ -456,23 +1211,6 @@ pub mod signature { format!("i{}o{}", to_slug(&self.inputs), to_slug(&self.outputs)) } - - pub fn new() -> Signature { - Signature { - inputs: vec![], - outputs: vec![], - } - } - - pub fn inputs(mut self, inputs: Vec) -> Self { - self.inputs = inputs; - self - } - - pub fn outputs(mut self, outputs: Vec) -> Self { - self.outputs = outputs; - self - } } #[cfg(test)] @@ -481,29 +1219,61 @@ pub mod signature { #[test] fn signature() { - let s = Signature::new() - .inputs(vec![Type::FieldElement, Type::Boolean]) - .outputs(vec![Type::Boolean]); + let s = ConcreteSignature::new() + .inputs(vec![ConcreteType::FieldElement, ConcreteType::Boolean]) + .outputs(vec![ConcreteType::Boolean]); assert_eq!(s.to_string(), String::from("(field, bool) -> bool")); } + #[test] + fn signature_equivalence() { + let generic = DeclarationSignature::new() + .generics(vec![Some("P".into())]) + .inputs(vec![DeclarationType::array(DeclarationArrayType::new( + DeclarationType::FieldElement, + "P".into(), + ))]); + let specialized = DeclarationSignature::new().inputs(vec![DeclarationType::array( + DeclarationArrayType::new(DeclarationType::FieldElement, 3u32.into()), + )]); + + assert_eq!(generic, specialized); + assert_eq!( + { + let mut hasher = std::collections::hash_map::DefaultHasher::new(); + generic.hash(&mut hasher); + hasher.finish() + }, + { + let mut hasher = std::collections::hash_map::DefaultHasher::new(); + specialized.hash(&mut hasher); + hasher.finish() + } + ); + assert_eq!( + generic.partial_cmp(&specialized), + Some(std::cmp::Ordering::Equal) + ); + assert_eq!(generic.cmp(&specialized), std::cmp::Ordering::Equal); + } + #[test] fn slug_0() { - let s = Signature::new().inputs(vec![]).outputs(vec![]); + let s = ConcreteSignature::new().inputs(vec![]).outputs(vec![]); assert_eq!(s.to_slug(), String::from("io")); } #[test] fn slug_1() { - let s = Signature::new() - .inputs(vec![Type::FieldElement, Type::Boolean]) + let s = ConcreteSignature::new() + .inputs(vec![ConcreteType::FieldElement, ConcreteType::Boolean]) .outputs(vec![ - Type::FieldElement, - Type::FieldElement, - Type::Boolean, - Type::FieldElement, + ConcreteType::FieldElement, + ConcreteType::FieldElement, + ConcreteType::Boolean, + ConcreteType::FieldElement, ]); assert_eq!(s.to_slug(), String::from("ifbo2fbf")); @@ -511,23 +1281,27 @@ pub mod signature { #[test] fn slug_2() { - let s = Signature::new() + let s = ConcreteSignature::new() .inputs(vec![ - Type::FieldElement, - Type::FieldElement, - Type::FieldElement, + ConcreteType::FieldElement, + ConcreteType::FieldElement, + ConcreteType::FieldElement, ]) - .outputs(vec![Type::FieldElement, Type::Boolean, Type::FieldElement]); + .outputs(vec![ + ConcreteType::FieldElement, + ConcreteType::Boolean, + ConcreteType::FieldElement, + ]); assert_eq!(s.to_slug(), String::from("i3fofbf")); } #[test] fn array_slug() { - let s = Signature::new() + let s = ConcreteSignature::new() .inputs(vec![ - Type::array(Type::FieldElement, 42), - Type::array(Type::FieldElement, 21), + ConcreteType::array((ConcreteType::FieldElement, 42usize)), + ConcreteType::array((ConcreteType::FieldElement, 21usize)), ]) .outputs(vec![]); @@ -542,7 +1316,17 @@ mod tests { #[test] fn array() { - let t = Type::Array(ArrayType::new(Type::FieldElement, 42)); + let t = ConcreteType::Array(ConcreteArrayType::new(ConcreteType::FieldElement, 42usize)); assert_eq!(t.get_primitive_count(), 42); } + + #[test] + fn array_display() { + // field[1][2] + let t = ConcreteType::Array(ConcreteArrayType::new( + ConcreteType::Array(ConcreteArrayType::new(ConcreteType::FieldElement, 2usize)), + 1usize, + )); + assert_eq!(format!("{}", t), "field[1][2]"); + } } diff --git a/zokrates_core/src/typed_absy/uint.rs b/zokrates_core/src/typed_absy/uint.rs index 0403d15e6..56be9e826 100644 --- a/zokrates_core/src/typed_absy/uint.rs +++ b/zokrates_core/src/typed_absy/uint.rs @@ -1,40 +1,84 @@ -use crate::typed_absy::types::{FunctionKey, UBitwidth}; +use crate::typed_absy::types::UBitwidth; use crate::typed_absy::*; +use std::ops::{Add, Div, Mul, Neg, Not, Rem, Sub}; use zokrates_field::Field; type Bitwidth = usize; -impl<'ast, T: Field> UExpression<'ast, T> { - pub fn add(self, other: Self) -> UExpression<'ast, T> { +impl<'ast, T> Add for UExpression<'ast, T> { + type Output = Self; + + 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) + + match (self.as_inner(), other.as_inner()) { + (UExpressionInner::Value(0), _) => other, + (_, UExpressionInner::Value(0)) => self, + _ => UExpressionInner::Add(box self, box other).annotate(bitwidth), + } } +} + +impl<'ast, T> Sub for UExpression<'ast, T> { + type Output = Self; - pub fn sub(self, other: Self) -> 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) } +} - pub fn mult(self, other: Self) -> UExpression<'ast, T> { +impl<'ast, T> Mul for UExpression<'ast, T> { + type Output = Self; + + 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) } +} + +impl<'ast, T> Div for UExpression<'ast, T> { + type Output = Self; - pub fn div(self, other: Self) -> 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) } +} + +impl<'ast, T> Rem for UExpression<'ast, T> { + type Output = Self; - pub fn rem(self, other: Self) -> 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) } +} +impl<'ast, T> Not for UExpression<'ast, T> { + type Output = Self; + + fn not(self) -> UExpression<'ast, T> { + let bitwidth = self.bitwidth; + UExpressionInner::Not(box self).annotate(bitwidth) + } +} + +impl<'ast, T> Neg for UExpression<'ast, T> { + type Output = Self; + + fn neg(self) -> UExpression<'ast, T> { + let bitwidth = self.bitwidth; + UExpressionInner::Neg(box self).annotate(bitwidth) + } +} + +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); @@ -53,20 +97,28 @@ impl<'ast, T: Field> UExpression<'ast, T> { UExpressionInner::And(box self, box other).annotate(bitwidth) } - pub fn not(self) -> UExpression<'ast, T> { + pub fn pos(self) -> UExpression<'ast, T> { let bitwidth = self.bitwidth; - UExpressionInner::Not(box self).annotate(bitwidth) + UExpressionInner::Pos(box self).annotate(bitwidth) } - pub fn left_shift(self, by: FieldElementExpression<'ast, T>) -> UExpression<'ast, T> { + 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) } - pub fn right_shift(self, by: FieldElementExpression<'ast, T>) -> UExpression<'ast, T> { + 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) } + + 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) + } } impl<'ast, T: Field> From for UExpressionInner<'ast, T> { @@ -94,12 +146,40 @@ pub struct UExpression<'ast, T> { pub inner: UExpressionInner<'ast, T>, } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +impl<'ast, T> From for UExpression<'ast, T> { + fn from(u: u32) -> Self { + UExpressionInner::Value(u as u128).annotate(UBitwidth::B32) + } +} + +impl<'ast, T> From for UExpression<'ast, T> { + fn from(u: u16) -> Self { + UExpressionInner::Value(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) + } +} + +impl<'ast, T> PartialEq for UExpression<'ast, T> { + fn eq(&self, other: &usize) -> bool { + match self.as_inner() { + UExpressionInner::Value(v) => *v == *other as u128, + _ => true, + } + } +} + +#[derive(Clone, PartialEq, Eq, Hash, Debug)] pub enum UExpressionInner<'ast, T> { Identifier(Identifier<'ast>), Value(u128), Add(Box>, Box>), Sub(Box>, Box>), + FloorSub(Box>, Box>), Mult(Box>, Box>), Div(Box>, Box>), Rem(Box>, Box>), @@ -107,25 +187,22 @@ pub enum UExpressionInner<'ast, T> { And(Box>, Box>), Or(Box>, Box>), Not(Box>), - LeftShift( - Box>, - Box>, - ), - RightShift( - Box>, - Box>, + Neg(Box>), + Pos(Box>), + FunctionCall( + DeclarationFunctionKey<'ast>, + Vec>>, + Vec>, ), - FunctionCall(FunctionKey<'ast>, Vec>), + LeftShift(Box>, Box>), + RightShift(Box>, Box>), IfElse( Box>, Box>, Box>, ), Member(Box>, MemberId), - Select( - Box>, - Box>, - ), + Select(Box>, Box>), } impl<'ast, T> UExpressionInner<'ast, T> { @@ -151,7 +228,7 @@ pub fn bitwidth(a: u128) -> Bitwidth { (128 - a.leading_zeros()) as Bitwidth } -impl<'ast, T: Field> UExpression<'ast, T> { +impl<'ast, T> UExpression<'ast, T> { pub fn bitwidth(&self) -> UBitwidth { self.bitwidth } diff --git a/zokrates_core/src/typed_absy/variable.rs b/zokrates_core/src/typed_absy/variable.rs index ca40cca9e..9151dfdcd 100644 --- a/zokrates_core/src/typed_absy/variable.rs +++ b/zokrates_core/src/typed_absy/variable.rs @@ -1,76 +1,102 @@ -use crate::typed_absy::types::Type; -use crate::typed_absy::types::{StructType, UBitwidth}; +use crate::typed_absy::types::{Constant, GStructType, UBitwidth}; +use crate::typed_absy::types::{GType, SpecializationError}; use crate::typed_absy::Identifier; +use crate::typed_absy::UExpression; +use crate::typed_absy::{TryFrom, TryInto}; use std::fmt; #[derive(Clone, PartialEq, Hash, Eq)] -pub struct Variable<'ast> { +pub struct GVariable<'ast, S> { pub id: Identifier<'ast>, - pub _type: Type, + pub _type: GType, } -impl<'ast> Variable<'ast> { - pub fn field_element>>(id: I) -> Variable<'ast> { - Self::with_id_and_type(id, Type::FieldElement) +pub type DeclarationVariable<'ast> = GVariable<'ast, Constant<'ast>>; +pub type ConcreteVariable<'ast> = GVariable<'ast, usize>; +pub type Variable<'ast, T> = GVariable<'ast, UExpression<'ast, T>>; + +impl<'ast, T> TryFrom> for ConcreteVariable<'ast> { + type Error = SpecializationError; + + fn try_from(v: Variable<'ast, T>) -> Result { + let _type = v._type.try_into()?; + + Ok(Self { _type, id: v.id }) + } +} + +// impl<'ast> TryFrom> for ConcreteVariable<'ast> { +// type Error = SpecializationError; + +// fn try_from(v: DeclarationVariable<'ast>) -> Result { +// let _type = v._type.try_into()?; + +// Ok(Self { _type, id: v.id }) +// } +// } + +impl<'ast, T> From> for Variable<'ast, T> { + fn from(v: ConcreteVariable<'ast>) -> Self { + let _type = v._type.into(); + + Self { _type, id: v.id } + } +} + +impl<'ast, T> From> for Variable<'ast, T> { + fn from(v: DeclarationVariable<'ast>) -> Self { + let _type = v._type.into(); + + Self { _type, id: v.id } } +} - pub fn boolean>>(id: I) -> Variable<'ast> { - Self::with_id_and_type(id, Type::Boolean) +impl<'ast, S: Clone> GVariable<'ast, S> { + pub fn field_element>>(id: I) -> Self { + Self::with_id_and_type(id, GType::FieldElement) } - pub fn uint>, W: Into>( - id: I, - bitwidth: W, - ) -> Variable<'ast> { - Self::with_id_and_type(id, Type::uint(bitwidth)) + pub fn boolean>>(id: I) -> Self { + Self::with_id_and_type(id, GType::Boolean) + } + + pub fn uint>, W: Into>(id: I, bitwidth: W) -> Self { + Self::with_id_and_type(id, GType::uint(bitwidth)) } #[cfg(test)] - pub fn field_array>>(id: I, size: usize) -> Variable<'ast> { - Self::array(id, Type::FieldElement, size) + pub fn field_array>>(id: I, size: S) -> Self { + Self::array(id, GType::FieldElement, size) } - pub fn array>>(id: I, ty: Type, size: usize) -> Variable<'ast> { - Self::with_id_and_type(id, Type::array(ty, size)) + pub fn array>, U: Into>(id: I, ty: GType, size: U) -> Self { + Self::with_id_and_type(id, GType::array((ty, size.into()))) } - pub fn struc>>(id: I, ty: StructType) -> Variable<'ast> { - Self::with_id_and_type(id, Type::Struct(ty)) + pub fn struc>>(id: I, ty: GStructType) -> Self { + Self::with_id_and_type(id, GType::Struct(ty)) } - pub fn with_id_and_type>>(id: I, _type: Type) -> Variable<'ast> { - Variable { + pub fn with_id_and_type>>(id: I, _type: GType) -> Self { + GVariable { id: id.into(), _type, } } - pub fn get_type(&self) -> Type { + pub fn get_type(&self) -> GType { self._type.clone() } } -impl<'ast> fmt::Display for Variable<'ast> { +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,) } } -impl<'ast> fmt::Debug for Variable<'ast> { +impl<'ast, S: fmt::Debug> fmt::Debug for GVariable<'ast, S> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Variable(type: {:?}, id: {:?})", self._type, self.id,) } } - -// impl<'ast> From> for Variable<'ast> { -// fn from(v: absy::Variable) -> Variable { -// Variable::with_id_and_type( -// Identifier { -// id: v.id, -// version: 0, -// stack: vec![], -// }, -// v._type, -// ) -// } -// } diff --git a/zokrates_core/src/zir/folder.rs b/zokrates_core/src/zir/folder.rs index 39105214b..f82fbee1f 100644 --- a/zokrates_core/src/zir/folder.rs +++ b/zokrates_core/src/zir/folder.rs @@ -9,17 +9,6 @@ pub trait Folder<'ast, T: Field>: Sized { fold_program(self, p) } - fn fold_module(&mut self, p: ZirModule<'ast, T>) -> ZirModule<'ast, T> { - fold_module(self, p) - } - - fn fold_function_symbol( - &mut self, - s: ZirFunctionSymbol<'ast, T>, - ) -> ZirFunctionSymbol<'ast, T> { - fold_function_symbol(self, s) - } - fn fold_function(&mut self, f: ZirFunction<'ast, T>) -> ZirFunction<'ast, T> { fold_function(self, f) } @@ -63,14 +52,14 @@ pub trait Folder<'ast, T: Field>: Sized { es: ZirExpressionList<'ast, T>, ) -> ZirExpressionList<'ast, T> { match es { - ZirExpressionList::FunctionCall(id, arguments, types) => { - ZirExpressionList::FunctionCall( - id, + ZirExpressionList::EmbedCall(embed, generics, arguments) => { + ZirExpressionList::EmbedCall( + embed, + generics, arguments .into_iter() .map(|a| self.fold_expression(a)) .collect(), - types, ) } } @@ -101,20 +90,6 @@ pub trait Folder<'ast, T: Field>: Sized { } } -pub fn fold_module<'ast, T: Field, F: Folder<'ast, T>>( - f: &mut F, - p: ZirModule<'ast, T>, -) -> ZirModule<'ast, T> { - ZirModule { - functions: p - .functions - .into_iter() - .map(|(key, fun)| (key, f.fold_function_symbol(fun))) - .collect(), - ..p - } -} - pub fn fold_statement<'ast, T: Field, F: Folder<'ast, T>>( f: &mut F, s: ZirStatement<'ast, T>, @@ -170,7 +145,7 @@ pub fn fold_field_expression<'ast, T: Field, F: Folder<'ast, T>>( } FieldElementExpression::Pow(box e1, box e2) => { let e1 = f.fold_field_expression(e1); - let e2 = f.fold_field_expression(e2); + let e2 = f.fold_uint_expression(e2); FieldElementExpression::Pow(box e1, box e2) } FieldElementExpression::IfElse(box cond, box cons, box alt) => { @@ -204,25 +179,45 @@ pub fn fold_boolean_expression<'ast, T: Field, F: Folder<'ast, T>>( let e2 = f.fold_uint_expression(e2); BooleanExpression::UintEq(box e1, box e2) } - BooleanExpression::Lt(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::Lt(box e1, box e2) + BooleanExpression::FieldLt(box e1, box e2) } - BooleanExpression::Le(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::Le(box e1, box e2) + BooleanExpression::FieldLe(box e1, box e2) } - BooleanExpression::Gt(box e1, box e2) => { + BooleanExpression::FieldGt(box e1, box e2) => { let e1 = f.fold_field_expression(e1); let e2 = f.fold_field_expression(e2); - BooleanExpression::Gt(box e1, box e2) + BooleanExpression::FieldGt(box e1, box e2) } - BooleanExpression::Ge(box e1, box e2) => { + BooleanExpression::FieldGe(box e1, box e2) => { let e1 = f.fold_field_expression(e1); let e2 = f.fold_field_expression(e2); - BooleanExpression::Ge(box e1, box e2) + BooleanExpression::FieldGe(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::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::UintGt(box e1, box e2) => { + let e1 = f.fold_uint_expression(e1); + let e2 = f.fold_uint_expression(e2); + BooleanExpression::UintGt(box e1, box e2) + } + BooleanExpression::UintGe(box e1, box e2) => { + let e1 = f.fold_uint_expression(e1); + let e2 = f.fold_uint_expression(e2); + BooleanExpression::UintGe(box e1, box e2) } BooleanExpression::Or(box e1, box e2) => { let e1 = f.fold_boolean_expression(e1); @@ -315,13 +310,13 @@ pub fn fold_uint_expression_inner<'ast, T: Field, F: Folder<'ast, T>>( } UExpressionInner::LeftShift(box e, box by) => { let e = f.fold_uint_expression(e); - let by = f.fold_field_expression(by); + let by = f.fold_uint_expression(by); UExpressionInner::LeftShift(box e, box by) } UExpressionInner::RightShift(box e, box by) => { let e = f.fold_uint_expression(e); - let by = f.fold_field_expression(by); + let by = f.fold_uint_expression(by); UExpressionInner::RightShift(box e, box by) } @@ -358,26 +353,11 @@ pub fn fold_function<'ast, T: Field, F: Folder<'ast, T>>( } } -pub fn fold_function_symbol<'ast, T: Field, F: Folder<'ast, T>>( - f: &mut F, - s: ZirFunctionSymbol<'ast, T>, -) -> ZirFunctionSymbol<'ast, T> { - match s { - ZirFunctionSymbol::Here(fun) => ZirFunctionSymbol::Here(f.fold_function(fun)), - there => there, // by default, do not fold modules recursively - } -} - pub fn fold_program<'ast, T: Field, F: Folder<'ast, T>>( f: &mut F, p: ZirProgram<'ast, T>, ) -> ZirProgram<'ast, T> { ZirProgram { - modules: p - .modules - .into_iter() - .map(|(module_id, module)| (module_id, f.fold_module(module))) - .collect(), - main: p.main, + main: f.fold_function(p.main), } } diff --git a/zokrates_core/src/zir/from_typed.rs b/zokrates_core/src/zir/from_typed.rs index 30309e0bb..3a756b2e1 100644 --- a/zokrates_core/src/zir/from_typed.rs +++ b/zokrates_core/src/zir/from_typed.rs @@ -1,33 +1,28 @@ use crate::typed_absy; use crate::zir; -impl<'ast> From> for zir::types::FunctionKey<'ast> { - fn from(k: typed_absy::types::FunctionKey<'ast>) -> zir::types::FunctionKey<'ast> { - zir::types::FunctionKey { - id: k.id, - signature: k.signature.into(), - } - } -} -impl From for zir::types::Signature { - fn from(s: typed_absy::types::Signature) -> zir::types::Signature { +impl From for zir::types::Signature { + fn from(s: typed_absy::types::ConcreteSignature) -> zir::types::Signature { zir::types::Signature { - inputs: s.inputs.into_iter().flat_map(|t| from_type(t)).collect(), - outputs: s.outputs.into_iter().flat_map(|t| from_type(t)).collect(), + inputs: s.inputs.into_iter().flat_map(from_type).collect(), + outputs: s.outputs.into_iter().flat_map(from_type).collect(), } } } -fn from_type(t: typed_absy::types::Type) -> Vec { +fn from_type(t: typed_absy::types::ConcreteType) -> Vec { match t { - typed_absy::Type::FieldElement => vec![zir::Type::FieldElement], - typed_absy::Type::Boolean => vec![zir::Type::Boolean], - typed_absy::Type::Uint(bitwidth) => vec![zir::Type::uint(bitwidth.to_usize())], - typed_absy::Type::Array(array_type) => { + typed_absy::types::ConcreteType::Int => unreachable!(), + typed_absy::types::ConcreteType::FieldElement => vec![zir::Type::FieldElement], + typed_absy::types::ConcreteType::Boolean => vec![zir::Type::Boolean], + typed_absy::types::ConcreteType::Uint(bitwidth) => { + vec![zir::Type::uint(bitwidth.to_usize())] + } + typed_absy::types::ConcreteType::Array(array_type) => { let inner = from_type(*array_type.ty); (0..array_type.size).flat_map(|_| inner.clone()).collect() } - typed_absy::Type::Struct(members) => members + typed_absy::types::ConcreteType::Struct(members) => members .into_iter() .flat_map(|struct_member| from_type(*struct_member.ty)) .collect(), diff --git a/zokrates_core/src/zir/mod.rs b/zokrates_core/src/zir/mod.rs index 6464951eb..6fb06c47a 100644 --- a/zokrates_core/src/zir/mod.rs +++ b/zokrates_core/src/zir/mod.rs @@ -10,11 +10,9 @@ pub use self::parameter::Parameter; pub use self::types::Type; pub use self::variable::Variable; pub use crate::zir::uint::{ShouldReduce, UExpression, UExpressionInner, UMetadata}; -use std::path::PathBuf; use crate::embed::FlatEmbed; -use crate::zir::types::{FunctionKey, Signature}; -use std::collections::HashMap; +use crate::zir::types::Signature; use std::convert::TryFrom; use std::fmt; use zokrates_field::Field; @@ -23,115 +21,17 @@ pub use self::folder::Folder; pub use self::identifier::{Identifier, SourceIdentifier}; -/// An identifier for a `ZirModule`. Typically a path or uri. -pub type ZirModuleId = PathBuf; - -/// A collection of `ZirModule`s -pub type ZirModules<'ast, T> = HashMap>; - -/// A collection of `ZirFunctionSymbol`s -/// # Remarks -/// * It is the role of the semantic checker to make sure there are no duplicates for a given `FunctionKey` -/// in a given `ZirModule`, hence the use of a HashMap -pub type ZirFunctionSymbols<'ast, T> = HashMap, ZirFunctionSymbol<'ast, T>>; - /// A typed program as a collection of modules, one of them being the main #[derive(PartialEq, Debug)] pub struct ZirProgram<'ast, T> { - pub modules: ZirModules<'ast, T>, - pub main: ZirModuleId, + pub main: ZirFunction<'ast, T>, } impl<'ast, T: fmt::Display> fmt::Display for ZirProgram<'ast, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - for (module_id, module) in &self.modules { - writeln!( - f, - "| {}: |{}", - module_id.display(), - if *module_id == self.main { - "<---- main" - } else { - "" - } - )?; - writeln!(f, "{}", "-".repeat(100))?; - writeln!(f, "{}", module)?; - writeln!(f, "{}", "-".repeat(100))?; - writeln!(f, "")?; - } - write!(f, "") - } -} - -/// A typed program as a collection of functions. Types have been resolved during semantic checking. -#[derive(PartialEq, Clone)] -pub struct ZirModule<'ast, T> { - /// Functions of the program - pub functions: ZirFunctionSymbols<'ast, T>, -} - -#[derive(Debug, Clone, PartialEq)] -pub enum ZirFunctionSymbol<'ast, T> { - Here(ZirFunction<'ast, T>), - There(FunctionKey<'ast>, ZirModuleId), - Flat(FlatEmbed), -} - -impl<'ast, T> ZirFunctionSymbol<'ast, T> { - pub fn signature<'a>(&'a self, modules: &'a ZirModules) -> Signature { - match self { - ZirFunctionSymbol::Here(f) => f.signature.clone(), - ZirFunctionSymbol::There(key, module_id) => modules - .get(module_id) - .unwrap() - .functions - .get(key) - .unwrap() - .signature(&modules) - .clone(), - ZirFunctionSymbol::Flat(flat_fun) => flat_fun.signature().into(), - } - } -} - -impl<'ast, T: fmt::Display> fmt::Display for ZirModule<'ast, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let res = self - .functions - .iter() - .map(|(key, symbol)| match symbol { - ZirFunctionSymbol::Here(ref function) => format!("def {}{}", key.id, function), - ZirFunctionSymbol::There(ref fun_key, ref module_id) => format!( - "import {} from \"{}\" as {} // with signature {}", - fun_key.id, - module_id.display(), - key.id, - key.signature - ), - ZirFunctionSymbol::Flat(ref flat_fun) => { - format!("def {}{}:\n\t// hidden", key.id, flat_fun.signature()) - } - }) - .collect::>(); - write!(f, "{}", res.join("\n")) + write!(f, "{}", self.main) } } - -impl<'ast, T: fmt::Debug> fmt::Debug for ZirModule<'ast, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "module(\n\tfunctions:\n\t\t{}\n)", - self.functions - .iter() - .map(|x| format!("{:?}", x)) - .collect::>() - .join("\n\t\t") - ) - } -} - /// A typed function #[derive(Clone, PartialEq)] pub struct ZirFunction<'ast, T> { @@ -333,15 +233,7 @@ pub trait MultiTyped { #[derive(Clone, PartialEq, Hash, Eq)] pub enum ZirExpressionList<'ast, T> { - FunctionCall(FunctionKey<'ast>, Vec>, Vec), -} - -impl<'ast, T: Field> MultiTyped for ZirExpressionList<'ast, T> { - fn get_types(&self) -> &Vec { - match *self { - ZirExpressionList::FunctionCall(_, _, ref types) => types, - } - } + EmbedCall(FlatEmbed, Vec, Vec>), } /// An expression of type `field` @@ -367,7 +259,7 @@ pub enum FieldElementExpression<'ast, T> { ), Pow( Box>, - Box>, + Box>, ), IfElse( Box>, @@ -381,31 +273,35 @@ pub enum FieldElementExpression<'ast, T> { pub enum BooleanExpression<'ast, T> { Identifier(Identifier<'ast>), Value(bool), - Lt( + FieldLt( Box>, Box>, ), - Le( + FieldLe( Box>, Box>, ), - FieldEq( + FieldGe( Box>, Box>, ), - BoolEq( - Box>, - Box>, - ), - UintEq(Box>, Box>), - Ge( + FieldGt( Box>, Box>, ), - Gt( + UintLt(Box>, Box>), + UintLe(Box>, Box>), + UintGe(Box>, Box>), + UintGt(Box>, Box>), + FieldEq( Box>, Box>, ), + BoolEq( + Box>, + Box>, + ), + UintEq(Box>, Box>), Or( Box>, Box>, @@ -538,13 +434,17 @@ 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::Lt(ref lhs, ref rhs) => write!(f, "{} < {}", lhs, rhs), - BooleanExpression::Le(ref lhs, ref rhs) => write!(f, "{} <= {}", lhs, rhs), + 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::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::Ge(ref lhs, ref rhs) => write!(f, "{} >= {}", lhs, rhs), - BooleanExpression::Gt(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), @@ -590,8 +490,24 @@ impl<'ast, T: fmt::Debug> fmt::Debug for FieldElementExpression<'ast, T> { impl<'ast, T: fmt::Display> fmt::Display for ZirExpressionList<'ast, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - ZirExpressionList::FunctionCall(ref key, ref p, _) => { - write!(f, "{}(", key.id,)?; + ZirExpressionList::EmbedCall(ref embed, ref generics, ref p) => { + write!( + f, + "{}{}(", + embed.id(), + if generics.is_empty() { + "".into() + } else { + format!( + "::<{}>", + generics + .iter() + .map(|g| g.to_string()) + .collect::>() + .join(", ") + ) + } + )?; for (i, param) in p.iter().enumerate() { write!(f, "{}", param)?; if i < p.len() - 1 { @@ -607,8 +523,8 @@ impl<'ast, T: fmt::Display> fmt::Display for ZirExpressionList<'ast, T> { impl<'ast, T: fmt::Debug> fmt::Debug for ZirExpressionList<'ast, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - ZirExpressionList::FunctionCall(ref i, ref p, _) => { - write!(f, "FunctionCall({:?}, (", i)?; + ZirExpressionList::EmbedCall(ref embed, ref generics, ref p) => { + write!(f, "EmbedCall({:?}, {:?}, (", generics, embed)?; f.debug_list().entries(p.iter()).finish()?; write!(f, ")") } diff --git a/zokrates_core/src/zir/types.rs b/zokrates_core/src/zir/types.rs index ac5aa6bd5..de0142d38 100644 --- a/zokrates_core/src/zir/types.rs +++ b/zokrates_core/src/zir/types.rs @@ -1,8 +1,6 @@ use serde::{Deserialize, Serialize}; use std::fmt; -pub type Identifier<'ast> = &'ast str; - pub type MemberId = String; #[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord)] @@ -20,6 +18,8 @@ pub enum UBitwidth { B16 = 16, #[serde(rename = "32")] B32 = 32, + #[serde(rename = "64")] + B64 = 64, } impl UBitwidth { @@ -28,6 +28,7 @@ impl UBitwidth { UBitwidth::B8 => 8, UBitwidth::B16 => 16, UBitwidth::B32 => 32, + UBitwidth::B64 => 64, } } } @@ -38,6 +39,7 @@ impl From for UBitwidth { 8 => UBitwidth::B8, 16 => UBitwidth::B16, 32 => UBitwidth::B32, + 64 => UBitwidth::B64, _ => unreachable!(), } } @@ -92,44 +94,13 @@ impl Type { } } -pub type FunctionIdentifier<'ast> = &'ast str; - -#[derive(PartialEq, Eq, Hash, Debug, Clone)] -pub struct FunctionKey<'ast> { - pub id: FunctionIdentifier<'ast>, - pub signature: Signature, -} - -impl<'ast> FunctionKey<'ast> { - pub fn with_id>>(id: S) -> Self { - FunctionKey { - id: id.into(), - signature: Signature::new(), - } - } - - pub fn signature(mut self, signature: Signature) -> Self { - self.signature = signature; - self - } - - pub fn id>>(mut self, id: S) -> Self { - self.id = id.into(); - self - } - - pub fn to_slug(&self) -> String { - format!("{}_{}", self.id, self.signature.to_slug()) - } -} - pub use self::signature::Signature; pub mod signature { use super::*; use std::fmt; - #[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Ord, PartialOrd)] + #[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Ord, PartialOrd, Default)] pub struct Signature { pub inputs: Vec, pub outputs: Vec, @@ -189,12 +160,10 @@ pub mod signature { let len = res.len(); if len == 0 { res.push((1, t)) + } else if res[len - 1].1 == t { + res[len - 1].0 += 1; } else { - if res[len - 1].1 == t { - res[len - 1].0 += 1; - } else { - res.push((1, t)) - } + res.push((1, t)) } } res.into_iter() @@ -217,10 +186,7 @@ pub mod signature { } pub fn new() -> Signature { - Signature { - inputs: vec![], - outputs: vec![], - } + Signature::default() } pub fn inputs(mut self, inputs: Vec) -> Self { diff --git a/zokrates_core/src/zir/uint.rs b/zokrates_core/src/zir/uint.rs index a6db38637..660e4a549 100644 --- a/zokrates_core/src/zir/uint.rs +++ b/zokrates_core/src/zir/uint.rs @@ -1,6 +1,6 @@ use crate::zir::identifier::Identifier; use crate::zir::types::UBitwidth; -use crate::zir::{BooleanExpression, FieldElementExpression}; +use crate::zir::BooleanExpression; use zokrates_field::Field; impl<'ast, T: Field> UExpression<'ast, T> { @@ -57,13 +57,15 @@ impl<'ast, T: Field> UExpression<'ast, T> { UExpressionInner::And(box self, box other).annotate(bitwidth) } - pub fn left_shift(self, by: FieldElementExpression<'ast, T>) -> UExpression<'ast, T> { + 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) } - pub fn right_shift(self, by: FieldElementExpression<'ast, T>) -> UExpression<'ast, T> { + 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) } } @@ -80,6 +82,12 @@ impl<'ast, T: Field> From<&'ast str> for UExpressionInner<'ast, T> { } } +impl<'ast, T> From for UExpression<'ast, T> { + fn from(u: u32) -> Self { + UExpressionInner::Value(u as u128).annotate(UBitwidth::B32) + } +} + #[derive(Debug, PartialEq, Eq, Clone, Hash)] pub enum ShouldReduce { Unknown, @@ -99,10 +107,7 @@ impl ShouldReduce { } pub fn is_unknown(&self) -> bool { - match self { - ShouldReduce::Unknown => true, - _ => false, - } + *self == ShouldReduce::Unknown } // we can always enable a reduction @@ -165,14 +170,8 @@ pub enum UExpressionInner<'ast, T> { Xor(Box>, Box>), And(Box>, Box>), Or(Box>, Box>), - LeftShift( - Box>, - Box>, - ), - RightShift( - Box>, - Box>, - ), + LeftShift(Box>, Box>), + RightShift(Box>, Box>), Not(Box>), IfElse( Box>, diff --git a/zokrates_core/tests/out_of_range.rs b/zokrates_core/tests/out_of_range.rs index a21426223..ca7f43abe 100644 --- a/zokrates_core/tests/out_of_range.rs +++ b/zokrates_core/tests/out_of_range.rs @@ -36,6 +36,6 @@ fn out_of_range() { let interpreter = Interpreter::try_out_of_range(); assert!(interpreter - .execute(&res.prog(), &vec![Bn128Field::from(10000)]) + .execute(&res.prog(), &[Bn128Field::from(10000)]) .is_err()); } diff --git a/zokrates_core/tests/wasm.rs b/zokrates_core/tests/wasm.rs index 79e6e7b9a..6554beb09 100644 --- a/zokrates_core/tests/wasm.rs +++ b/zokrates_core/tests/wasm.rs @@ -29,7 +29,7 @@ fn generate_proof() { let interpreter = Interpreter::default(); let witness = interpreter - .execute(&program, &vec![Bn128Field::from(42)]) + .execute(&program, &[Bn128Field::from(42)]) .unwrap(); let keypair = >::setup(program.clone()); diff --git a/zokrates_core_test/Cargo.toml b/zokrates_core_test/Cargo.toml index c8db7078d..e0dbcfc10 100644 --- a/zokrates_core_test/Cargo.toml +++ b/zokrates_core_test/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zokrates_core_test" -version = "0.1.5" +version = "0.2.0" authors = ["schaeff "] edition = "2018" diff --git a/zokrates_core_test/tests/tests/fact_up_to_4.zok b/zokrates_core_test/tests/tests/fact_up_to_4.zok index d33b19c06..299cd995a 100644 --- a/zokrates_core_test/tests/tests/fact_up_to_4.zok +++ b/zokrates_core_test/tests/tests/fact_up_to_4.zok @@ -1,8 +1,10 @@ +import "utils/casts/u32_to_field" as to_field + def main(field x) -> field: field f = 1 field counter = 0 - for field i in 1..5 do - f = if counter == x then f else f * i fi + for u32 i in 1..5 do + f = if counter == x then f else f * to_field(i) fi counter = if counter == x then counter else counter + 1 fi endfor return f \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/generics/cache.json b/zokrates_core_test/tests/tests/generics/cache.json new file mode 100644 index 000000000..749eefefd --- /dev/null +++ b/zokrates_core_test/tests/tests/generics/cache.json @@ -0,0 +1,17 @@ +{ + "curves": ["Bn128", "Bls12_381"], + "tests": [ + { + "input": { + "values": [ + ] + }, + "output": { + "Ok": { + "values": [ + ] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/generics/cache.zok b/zokrates_core_test/tests/tests/generics/cache.zok new file mode 100644 index 000000000..2a2f17513 --- /dev/null +++ b/zokrates_core_test/tests/tests/generics/cache.zok @@ -0,0 +1,7 @@ +def id() -> u32: + return N + +def main(): + assert(id::<5>() == 5) + assert(id::<6>() == 6) + return \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/generics/call.json b/zokrates_core_test/tests/tests/generics/call.json new file mode 100644 index 000000000..4e45eccc3 --- /dev/null +++ b/zokrates_core_test/tests/tests/generics/call.json @@ -0,0 +1,4 @@ +{ + "curves": ["Bn128", "Bls12_381"], + "tests": [] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/generics/call.zok b/zokrates_core_test/tests/tests/generics/call.zok new file mode 100644 index 000000000..a0e6aa05f --- /dev/null +++ b/zokrates_core_test/tests/tests/generics/call.zok @@ -0,0 +1,8 @@ +def foo(field[T] b) -> field: + return 1 + +def bar(field[T] b) -> field: + return foo(b) + +def main(field[3] a) -> field: + return foo(a) + bar(a) \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/generics/embed.json b/zokrates_core_test/tests/tests/generics/embed.json new file mode 100644 index 000000000..4e45eccc3 --- /dev/null +++ b/zokrates_core_test/tests/tests/generics/embed.json @@ -0,0 +1,4 @@ +{ + "curves": ["Bn128", "Bls12_381"], + "tests": [] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/generics/embed.zok b/zokrates_core_test/tests/tests/generics/embed.zok new file mode 100644 index 000000000..88160bba0 --- /dev/null +++ b/zokrates_core_test/tests/tests/generics/embed.zok @@ -0,0 +1,5 @@ +import "EMBED/unpack" as unpack + +def main(field x): + bool[1] bits = unpack(x) + return \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/generics/multidef.json b/zokrates_core_test/tests/tests/generics/multidef.json new file mode 100644 index 000000000..4f0d5931c --- /dev/null +++ b/zokrates_core_test/tests/tests/generics/multidef.json @@ -0,0 +1,23 @@ +{ + "curves": ["Bn128", "Bls12_381"], + "tests": [ + { + "input": { + "values": [ + "1", + "2", + "3" + ] + }, + "output": { + "Ok": { + "values": [ + "1", + "2", + "3" + ] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/generics/multidef.zok b/zokrates_core_test/tests/tests/generics/multidef.zok new file mode 100644 index 000000000..dbf3bd3f0 --- /dev/null +++ b/zokrates_core_test/tests/tests/generics/multidef.zok @@ -0,0 +1,6 @@ +def foo(field[T] b) -> field[T]: + return b + +def main(field[3] a) -> field[3]: + field[3] res = foo(a) + return res \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/generics/same_parameter_name.json b/zokrates_core_test/tests/tests/generics/same_parameter_name.json new file mode 100644 index 000000000..b97905d7e --- /dev/null +++ b/zokrates_core_test/tests/tests/generics/same_parameter_name.json @@ -0,0 +1,22 @@ +{ + "curves": ["Bn128", "Bls12_381"], + "tests": [ + { + "input": { + "values": [ + "1", + "2", + "3" + ] + }, + "output": { + "Ok": { + "values": [ + "1", + "2" + ] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/generics/same_parameter_name.zok b/zokrates_core_test/tests/tests/generics/same_parameter_name.zok new file mode 100644 index 000000000..182637fbf --- /dev/null +++ b/zokrates_core_test/tests/tests/generics/same_parameter_name.zok @@ -0,0 +1,10 @@ +def foo(field[N] x) -> field[N]: + return x + +def bar(field[N] x) -> field[N]: + field[N] r = x + return r + +def main(field[3] x) -> field[2]: + field[2] z = foo(x)[0..2] + return bar(z) \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/neg_pos.json b/zokrates_core_test/tests/tests/neg_pos.json new file mode 100644 index 000000000..a5e6d7826 --- /dev/null +++ b/zokrates_core_test/tests/tests/neg_pos.json @@ -0,0 +1,15 @@ +{ + "entry_point": "./tests/tests/neg_pos.zok", + "tests": [ + { + "input": { + "values": ["1", "2", "1", "2"] + }, + "output": { + "Ok": { + "values": ["21888242871839275222246405745257275088548364400416034343698204186575808495615", "21888242871839275222246405745257275088548364400416034343698204186575808495616", "21888242871839275222246405745257275088548364400416034343698204186575808495616", "21888242871839275222246405745257275088548364400416034343698204186575808495616", "254", "255", "255", "255"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/neg_pos.zok b/zokrates_core_test/tests/tests/neg_pos.zok new file mode 100644 index 000000000..2322df367 --- /dev/null +++ b/zokrates_core_test/tests/tests/neg_pos.zok @@ -0,0 +1,15 @@ +def main(field x, field y, u8 z, u8 t) -> (field[4], u8[4]): + field a = -y // should parse to neg + field b = x - y // should parse to sub + field c = x + - y // should parse to add(neg) + field d = x - + y // should parse to sub(pos) + + u8 e = -t // should parse to neg + u8 f = z - t // should parse to sub + u8 g = z + - t // should parse to add(neg) + u8 h = z - + t // should parse to sub(pos) + + assert(-0x00 == 0x00) + assert(-0f == 0) + + return [a, b, c, d], [e, f, g, h] \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/nested_loop.zok b/zokrates_core_test/tests/tests/nested_loop.zok index 2d00f1a07..00ee862f3 100644 --- a/zokrates_core_test/tests/tests/nested_loop.zok +++ b/zokrates_core_test/tests/tests/nested_loop.zok @@ -2,24 +2,24 @@ def main(field[4] values) -> (field, field, field): field res0 = 1 field res1 = 0 - field counter = 0 + u32 counter = 0 - for field i in 0..4 do - for field j in i..4 do + for u32 i in 0..4 do + for u32 j in i..4 do counter = counter + 1 res0 = res0 * (values[i] + values[j]) endfor endfor - for field i in 0..counter do + for u32 i in 0..counter do res1 = res1 + 1 endfor field res2 = 0 - field i = 0 - for field i in i..5 do + u32 i = 0 + for u32 i in i..5 do i = 5 - for field i in 0..i do + for u32 i in 0..i do res2 = res2 + 1 endfor endfor diff --git a/zokrates_core_test/tests/tests/precedence.zok b/zokrates_core_test/tests/tests/precedence.zok index 0d699a9aa..fb2edcefa 100644 --- a/zokrates_core_test/tests/tests/precedence.zok +++ b/zokrates_core_test/tests/tests/precedence.zok @@ -4,15 +4,18 @@ def main(): assert(7 == 2 ** 2 * 2 - 1) assert(3 == 2 ** 2 / 2 + 1) - field a = if 3 == 2 ** 2 / 2 + 1 && true then 1 else 0 fi // combines arithmetic with boolean operators - field b = if 3 == 3 && 4 < 5 then 1 else 0 fi // checks precedence of boolean operators - field c = if 4 < 5 && 3 == 3 then 1 else 0 fi - field d = if 4 > 5 && 2 >= 1 || 1 == 1 then 1 else 0 fi - field e = if 2 >= 1 && 4 > 5 || 1 == 1 then 1 else 0 fi - field f = if 1 < 2 && false || 4 < 5 && 2 >= 1 then 1 else 0 fi + field a = if 3f == 2f ** 2 / 2 + 1 && true then 1 else 0 fi // combines arithmetic with boolean operators + field b = if 3f == 3f && 4f < 5f then 1 else 0 fi // checks precedence of boolean operators + field c = if 4f < 5f && 3f == 3f then 1 else 0 fi + field d = if 4f > 5f && 2f >= 1f || 1f == 1f then 1 else 0 fi + field e = if 2f >= 1f && 4f > 5f || 1f == 1f then 1 else 0 fi + field f = if 1f < 2f && false || 4f < 5f && 2f >= 1f then 1 else 0 fi assert(0x00 ^ 0x00 == 0x00) + assert(0 - 2 ** 2 == -4) + assert(-2**2 == -4) + //check if all statements have evalutated to true assert(a * b * c * d * e * f == 1) return diff --git a/zokrates_core_test/tests/tests/uint/add.json b/zokrates_core_test/tests/tests/uint/add.json deleted file mode 100644 index e42dc1d69..000000000 --- a/zokrates_core_test/tests/tests/uint/add.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "entry_point": "./tests/tests/uint/add.zok", - "max_constraint_count": 29, - "tests": [ - { - "input": { - "values": ["0xff", "0x01"] - }, - "output": { - "Ok": { - "values": ["0x00"] - } - } - }, - { - "input": { - "values": ["0x00", "0x01"] - }, - "output": { - "Ok": { - "values": ["0x01"] - } - } - }, - { - "input": { - "values": ["0xff", "0xff"] - }, - "output": { - "Ok": { - "values": ["0xfe"] - } - } - } - ] -} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/add_loop.zok b/zokrates_core_test/tests/tests/uint/add_loop.zok index 53a0c19b8..cb4162406 100644 --- a/zokrates_core_test/tests/tests/uint/add_loop.zok +++ b/zokrates_core_test/tests/tests/uint/add_loop.zok @@ -1,7 +1,7 @@ // 32 constraints for input constraining def main(u32 a) -> u32: u32 res = 0x00000000 - for field i in 0..10 do + for u32 i in 0..10 do res = res + a endfor return res // 42 constraints (decomposing on 42 bits) \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/and.json b/zokrates_core_test/tests/tests/uint/and.json deleted file mode 100644 index 19217cd1e..000000000 --- a/zokrates_core_test/tests/tests/uint/and.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "entry_point": "./tests/tests/uint/and.zok", - "max_constraint_count": 27, - "tests": [ - { - "input": { - "values": ["0xff", "0xff"] - }, - "output": { - "Ok": { - "values": ["0xff"] - } - } - }, - { - "input": { - "values": ["0xff", "0x00"] - }, - "output": { - "Ok": { - "values": ["0x00"] - } - } - }, - { - "input": { - "values": ["0x23", "0x34"] - }, - "output": { - "Ok": { - "values": ["0x20"] - } - } - } - ] -} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/div.json b/zokrates_core_test/tests/tests/uint/div.json deleted file mode 100644 index 91f0ce15a..000000000 --- a/zokrates_core_test/tests/tests/uint/div.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "entry_point": "./tests/tests/uint/div.zok", - "max_constraint_count": 43, - "tests": [ - { - "input": { - "values": ["255", "1"] - }, - "output": { - "Ok": { - "values": ["255"] - } - } - }, - { - "input": { - "values": ["42", "10"] - }, - "output": { - "Ok": { - "values": ["4"] - } - } - } - ] -} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/div.zok b/zokrates_core_test/tests/tests/uint/div.zok deleted file mode 100644 index 730ce4b23..000000000 --- a/zokrates_core_test/tests/tests/uint/div.zok +++ /dev/null @@ -1,6 +0,0 @@ -def main(u8 x, u8 y) -> u8: - assert(0x02 / 0x02 == 0x01) - assert(0x04 / 0x02 == 0x02) - assert(0x05 / 0x02 == 0x02) - assert(0xff / 0x03 == 0x55) - return x / y \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/div_rem.json b/zokrates_core_test/tests/tests/uint/div_rem.json deleted file mode 100644 index c01879bb3..000000000 --- a/zokrates_core_test/tests/tests/uint/div_rem.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "entry_point": "./tests/tests/uint/div_rem.zok", - "max_constraint_count": 43, - "tests": [ - { - "input": { - "values": ["255", "1"] - }, - "output": { - "Ok": { - "values": ["255", "0"] - } - } - }, - { - "input": { - "values": ["42", "10"] - }, - "output": { - "Ok": { - "values": ["4", "2"] - } - } - } - ] -} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/div_rem.zok b/zokrates_core_test/tests/tests/uint/div_rem.zok deleted file mode 100644 index 73f5f16ff..000000000 --- a/zokrates_core_test/tests/tests/uint/div_rem.zok +++ /dev/null @@ -1,2 +0,0 @@ -def main(u8 n, u8 d) -> (u8, u8): - return n / d, n % d \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/extend.zok b/zokrates_core_test/tests/tests/uint/extend.zok index 576db3649..f50f328a3 100644 --- a/zokrates_core_test/tests/tests/uint/extend.zok +++ b/zokrates_core_test/tests/tests/uint/extend.zok @@ -43,7 +43,7 @@ def right_rotate_25(u32 e) -> u32: // already paying 33 * 64 = 2112 constraints for input constraining. in sha this is done only once. So this is just ~ 152 constraints def main(u32[64] w) -> u32: - field i = 16 + u32 i = 16 u32 s0 = right_rotate_7(w[i-15]) ^ right_rotate_18(w[i-15]) ^ (w[i-15] >> 3) u32 s1 = right_rotate_17(w[i-2]) ^ right_rotate_19(w[i-2]) ^ (w[i-2] >> 10) return w[i-16] + s0 + w[i-7] + s1 \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/from_to_bits.json b/zokrates_core_test/tests/tests/uint/from_to_bits.json index e086d206b..13b554204 100644 --- a/zokrates_core_test/tests/tests/uint/from_to_bits.json +++ b/zokrates_core_test/tests/tests/uint/from_to_bits.json @@ -1,34 +1,34 @@ { "entry_point": "./tests/tests/uint/from_to_bits.zok", - "max_constraint_count": 34, + "max_constraint_count": 128, "tests": [ { "input": { - "values": ["0x00000000", "0x0000", "0x00"] + "values": ["0x0000000000000000", "0x00000000", "0x0000", "0x00"] }, "output": { "Ok": { - "values": ["0x00000000", "0x0000", "0x00"] + "values": ["0x0000000000000000", "0x00000000", "0x0000", "0x00"] } } }, { "input": { - "values": ["0xffffffff", "0xffff", "0xff"] + "values": ["0xffffffffffffffff", "0xffffffff", "0xffff", "0xff"] }, "output": { "Ok": { - "values": ["0xffffffff", "0xffff", "0xff"] + "values": ["0xffffffffffffffff", "0xffffffff", "0xffff", "0xff"] } } }, { "input": { - "values": ["0x12345678", "0x1234", "0x12"] + "values": ["0x1234567812345678", "0x12345678", "0x1234", "0x12"] }, "output": { "Ok": { - "values": ["0x12345678", "0x1234", "0x12"] + "values": ["0x1234567812345678", "0x12345678", "0x1234", "0x12"] } } } diff --git a/zokrates_core_test/tests/tests/uint/from_to_bits.zok b/zokrates_core_test/tests/tests/uint/from_to_bits.zok index 6bb7b804a..b3b52ccce 100644 --- a/zokrates_core_test/tests/tests/uint/from_to_bits.zok +++ b/zokrates_core_test/tests/tests/uint/from_to_bits.zok @@ -1,3 +1,5 @@ +import "EMBED/u64_to_bits" as to_bits_64 +import "EMBED/u64_from_bits" as from_bits_64 import "EMBED/u32_to_bits" as to_bits_32 import "EMBED/u32_from_bits" as from_bits_32 import "EMBED/u16_to_bits" as to_bits_16 @@ -5,8 +7,9 @@ import "EMBED/u16_from_bits" as from_bits_16 import "EMBED/u8_to_bits" as to_bits_8 import "EMBED/u8_from_bits" as from_bits_8 -def main(u32 e, u16 f, u8 g) -> (u32, u16, u8): +def main(u64 d, u32 e, u16 f, u8 g) -> (u64, u32, u16, u8): + bool[64] d_bits = to_bits_64(d) bool[32] e_bits = to_bits_32(e) bool[16] f_bits = to_bits_16(f) bool[8] g_bits = to_bits_8(g) - return from_bits_32(e_bits), from_bits_16(f_bits), from_bits_8(g_bits) \ No newline at end of file + return from_bits_64(d_bits), from_bits_32(e_bits), from_bits_16(f_bits), from_bits_8(g_bits) \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/mul.json b/zokrates_core_test/tests/tests/uint/mul.json deleted file mode 100644 index 628b71ae4..000000000 --- a/zokrates_core_test/tests/tests/uint/mul.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "entry_point": "./tests/tests/uint/mul.zok", - "max_constraint_count": 37, - "tests": [ - { - "input": { - "values": ["2", "2"] - }, - "output": { - "Ok": { - "values": ["4"] - } - } - } - ] -} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/operations.zok b/zokrates_core_test/tests/tests/uint/operations.zok index e5bd49eb3..032ed3a11 100644 --- a/zokrates_core_test/tests/tests/uint/operations.zok +++ b/zokrates_core_test/tests/tests/uint/operations.zok @@ -69,8 +69,8 @@ def main(u32 e, u32 f, u32[4] terms): assert((e ^ f) == 0x1317131f) // shift - assert(e >> 12 == 0x00012345) - assert(e << 12 == 0x45678000) + assert(e >> 0x0000000c == 0x00012345) + assert(e << 0x0000000c == 0x45678000) // not assert(!e == 0xedcba987) diff --git a/zokrates_core_test/tests/tests/uint/or.json b/zokrates_core_test/tests/tests/uint/or.json deleted file mode 100644 index 282738555..000000000 --- a/zokrates_core_test/tests/tests/uint/or.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "entry_point": "./tests/tests/uint/or.zok", - "max_constraint_count": 27, - "tests": [ - { - "input": { - "values": ["0xff", "0xff"] - }, - "output": { - "Ok": { - "values": ["0xff"] - } - } - }, - { - "input": { - "values": ["0xff", "0x00"] - }, - "output": { - "Ok": { - "values": ["0xff"] - } - } - }, - { - "input": { - "values": ["0x23", "0x34"] - }, - "output": { - "Ok": { - "values": ["0x37"] - } - } - } - ] -} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/propagation/rotate.zok b/zokrates_core_test/tests/tests/uint/propagation/rotate.zok index 6d0184bb2..05fdf877a 100644 --- a/zokrates_core_test/tests/tests/uint/propagation/rotate.zok +++ b/zokrates_core_test/tests/tests/uint/propagation/rotate.zok @@ -72,8 +72,8 @@ def main(): assert((e ^ f) == 0x1317131f) // shift - assert(e >> 12 == 0x00012345) - assert(e << 12 == 0x45678000) + assert(e >> 0x0000000c == 0x00012345) + assert(e << 0x0000000c == 0x45678000) // not assert(!e == 0xedcba987) diff --git a/zokrates_core_test/tests/tests/uint/rem.json b/zokrates_core_test/tests/tests/uint/rem.json deleted file mode 100644 index a8a9e7ac7..000000000 --- a/zokrates_core_test/tests/tests/uint/rem.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "entry_point": "./tests/tests/uint/rem.zok", - "max_constraint_count": 43, - "tests": [ - { - "input": { - "values": ["255", "1"] - }, - "output": { - "Ok": { - "values": ["0"] - } - } - }, - { - "input": { - "values": ["42", "10"] - }, - "output": { - "Ok": { - "values": ["2"] - } - } - } - ] -} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/rem.zok b/zokrates_core_test/tests/tests/uint/rem.zok deleted file mode 100644 index c72401dc1..000000000 --- a/zokrates_core_test/tests/tests/uint/rem.zok +++ /dev/null @@ -1,7 +0,0 @@ -def main(u8 x, u8 y) -> u8: - assert(0x02 % 0x02 == 0x00) - assert(0x04 % 0x02 == 0x00) - assert(0x05 % 0x02 == 0x01) - assert(0xff % 0x03 == 0x00) - assert(0xff % 0x01 == 0x00) - return x % y \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/sha256.zok b/zokrates_core_test/tests/tests/uint/sha256.zok index 3b7a1043e..7aabe22cf 100644 --- a/zokrates_core_test/tests/tests/uint/sha256.zok +++ b/zokrates_core_test/tests/tests/uint/sha256.zok @@ -41,7 +41,7 @@ def right_rotate_25(u32 e) -> u32: bool[32] b = to_bits(e) return from_bits([...b[7..], ...b[..7]]) -def extend(u32[64] w, field i) -> u32: +def extend(u32[64] w, u32 i) -> u32: u32 s0 = right_rotate_7(w[i-15]) ^ right_rotate_18(w[i-15]) ^ (w[i-15] >> 3) u32 s1 = right_rotate_17(w[i-2]) ^ right_rotate_19(w[i-2]) ^ (w[i-2] >> 10) return w[i-16] + s0 + w[i-7] + s1 @@ -82,11 +82,11 @@ def main(u32[1][16] input) -> u32[8]: // assume padding is already done // input = input - for field i in 0..1 do + for u32 i in 0..1 do u32[64] w = [...input[0], ...[0x00000000; 48]] - for field i in 16..64 do + for u32 i in 16..64 do u32 r = extend(w, i) w[i] = r endfor @@ -100,7 +100,7 @@ def main(u32[1][16] input) -> u32[8]: u32 g = h6 u32 h = h7 - for field i in 0..64 do + for u32 i in 0..64 do u32 t1 = temp1(e, f, g, h, k[i], w[i]) diff --git a/zokrates_core_test/tests/tests/uint/shift.json b/zokrates_core_test/tests/tests/uint/shift.json deleted file mode 100644 index 654da1150..000000000 --- a/zokrates_core_test/tests/tests/uint/shift.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "entry_point": "./tests/tests/uint/shift.zok", - "max_constraint_count": 34, - "tests": [ - { - "input": { - "values": ["0x12345678"] - }, - "output": { - "Ok": { - "values": ["0x01234567"] - } - } - }, - { - "input": { - "values": ["0x01234567"] - }, - "output": { - "Ok": { - "values": ["0x00123456"] - } - } - } - ] -} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u16/add.json b/zokrates_core_test/tests/tests/uint/u16/add.json new file mode 100644 index 000000000..9cf286bed --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u16/add.json @@ -0,0 +1,36 @@ +{ + "entry_point": "./tests/tests/uint/u16/add.zok", + "max_constraint_count": 53, + "tests": [ + { + "input": { + "values": ["0xffff", "0x0001"] + }, + "output": { + "Ok": { + "values": ["0x0000"] + } + } + }, + { + "input": { + "values": ["0x1000", "0x1000"] + }, + "output": { + "Ok": { + "values": ["0x2000"] + } + } + }, + { + "input": { + "values": ["0xffff", "0xffff"] + }, + "output": { + "Ok": { + "values": ["0xfffe"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u16/add.zok b/zokrates_core_test/tests/tests/uint/u16/add.zok new file mode 100644 index 000000000..9cc1c17c9 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u16/add.zok @@ -0,0 +1,2 @@ +def main(u16 a, u16 b) -> u16: + return a + b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u16/and.json b/zokrates_core_test/tests/tests/uint/u16/and.json new file mode 100644 index 000000000..c20291244 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u16/and.json @@ -0,0 +1,36 @@ +{ + "entry_point": "./tests/tests/uint/u16/and.zok", + "max_constraint_count": 51, + "tests": [ + { + "input": { + "values": ["0xffff", "0xffff"] + }, + "output": { + "Ok": { + "values": ["0xffff"] + } + } + }, + { + "input": { + "values": ["0xffff", "0x0000"] + }, + "output": { + "Ok": { + "values": ["0x0000"] + } + } + }, + { + "input": { + "values": ["0x1234", "0x5678"] + }, + "output": { + "Ok": { + "values": ["0x1230"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u16/and.zok b/zokrates_core_test/tests/tests/uint/u16/and.zok new file mode 100644 index 000000000..a038b1ebf --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u16/and.zok @@ -0,0 +1,2 @@ +def main(u16 a, u16 b) -> u16: + return a & b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u16/div.json b/zokrates_core_test/tests/tests/uint/u16/div.json new file mode 100644 index 000000000..9c22237fa --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u16/div.json @@ -0,0 +1,36 @@ +{ + "entry_point": "./tests/tests/uint/u16/div.zok", + "max_constraint_count": 88, + "tests": [ + { + "input": { + "values": ["0x1000", "0x1000"] + }, + "output": { + "Ok": { + "values": ["0x0001"] + } + } + }, + { + "input": { + "values": ["0x1000", "0x0002"] + }, + "output": { + "Ok": { + "values": ["0x0800"] + } + } + }, + { + "input": { + "values": ["0x1001", "0x0002"] + }, + "output": { + "Ok": { + "values": ["0x0800"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u16/div.zok b/zokrates_core_test/tests/tests/uint/u16/div.zok new file mode 100644 index 000000000..a047e4cba --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u16/div.zok @@ -0,0 +1,2 @@ +def main(u16 x, u16 y) -> u16: + return x / y \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u16/eq.json b/zokrates_core_test/tests/tests/uint/u16/eq.json new file mode 100644 index 000000000..19e68395a --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u16/eq.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u16/eq.zok", + "max_constraint_count": 37, + "tests": [ + { + "input": { + "values": ["0x0002", "0x0002"] + }, + "output": { + "Ok": { + "values": ["1"] + } + } + }, + { + "input": { + "values": ["0x0002", "0x0004"] + }, + "output": { + "Ok": { + "values": ["0"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u16/eq.zok b/zokrates_core_test/tests/tests/uint/u16/eq.zok new file mode 100644 index 000000000..da6bde287 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u16/eq.zok @@ -0,0 +1,2 @@ +def main(u16 a, u16 b) -> bool: + return a == b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u16/gt.json b/zokrates_core_test/tests/tests/uint/u16/gt.json new file mode 100644 index 000000000..f9845b430 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u16/gt.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u16/gt.zok", + "max_constraint_count": 697, + "tests": [ + { + "input": { + "values": ["0x0004", "0x0002"] + }, + "output": { + "Ok": { + "values": ["1"] + } + } + }, + { + "input": { + "values": ["0x0002", "0x0002"] + }, + "output": { + "Ok": { + "values": ["0"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u16/gt.zok b/zokrates_core_test/tests/tests/uint/u16/gt.zok new file mode 100644 index 000000000..41453552b --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u16/gt.zok @@ -0,0 +1,2 @@ +def main(u16 a, u16 b) -> bool: + return a > b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u16/gte.json b/zokrates_core_test/tests/tests/uint/u16/gte.json new file mode 100644 index 000000000..5512846a5 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u16/gte.json @@ -0,0 +1,36 @@ +{ + "entry_point": "./tests/tests/uint/u16/gte.zok", + "max_constraint_count": 699, + "tests": [ + { + "input": { + "values": ["0x0004", "0x0002"] + }, + "output": { + "Ok": { + "values": ["1"] + } + } + }, + { + "input": { + "values": ["0x0002", "0x0002"] + }, + "output": { + "Ok": { + "values": ["1"] + } + } + }, + { + "input": { + "values": ["0x0001", "0x0002"] + }, + "output": { + "Ok": { + "values": ["0"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u16/gte.zok b/zokrates_core_test/tests/tests/uint/u16/gte.zok new file mode 100644 index 000000000..4111057ac --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u16/gte.zok @@ -0,0 +1,2 @@ +def main(u16 a, u16 b) -> bool: + return a >= b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u16/lshift.json b/zokrates_core_test/tests/tests/uint/u16/lshift.json new file mode 100644 index 000000000..466e1b0a0 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u16/lshift.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u16/lshift.zok", + "max_constraint_count": 18, + "tests": [ + { + "input": { + "values": ["0x0002"] + }, + "output": { + "Ok": { + "values": ["0x0004"] + } + } + }, + { + "input": { + "values": ["0xffff"] + }, + "output": { + "Ok": { + "values": ["0xfffe"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u16/lshift.zok b/zokrates_core_test/tests/tests/uint/u16/lshift.zok new file mode 100644 index 000000000..18a30a8fd --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u16/lshift.zok @@ -0,0 +1,2 @@ +def main(u16 x) -> u16: + return x << 1 \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u16/lt.json b/zokrates_core_test/tests/tests/uint/u16/lt.json new file mode 100644 index 000000000..f21f396ad --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u16/lt.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u16/lt.zok", + "max_constraint_count": 697, + "tests": [ + { + "input": { + "values": ["0x0002", "0x0004"] + }, + "output": { + "Ok": { + "values": ["1"] + } + } + }, + { + "input": { + "values": ["0x0002", "0x0002"] + }, + "output": { + "Ok": { + "values": ["0"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u16/lt.zok b/zokrates_core_test/tests/tests/uint/u16/lt.zok new file mode 100644 index 000000000..9a6b2b493 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u16/lt.zok @@ -0,0 +1,2 @@ +def main(u16 a, u16 b) -> bool: + return a < b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u16/lte.json b/zokrates_core_test/tests/tests/uint/u16/lte.json new file mode 100644 index 000000000..a7b170c36 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u16/lte.json @@ -0,0 +1,36 @@ +{ + "entry_point": "./tests/tests/uint/u16/lte.zok", + "max_constraint_count": 699, + "tests": [ + { + "input": { + "values": ["0x0002", "0x0004"] + }, + "output": { + "Ok": { + "values": ["1"] + } + } + }, + { + "input": { + "values": ["0x0002", "0x0002"] + }, + "output": { + "Ok": { + "values": ["1"] + } + } + }, + { + "input": { + "values": ["0x0003", "0x0002"] + }, + "output": { + "Ok": { + "values": ["0"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u16/lte.zok b/zokrates_core_test/tests/tests/uint/u16/lte.zok new file mode 100644 index 000000000..f60160afe --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u16/lte.zok @@ -0,0 +1,2 @@ +def main(u16 a, u16 b) -> bool: + return a <= b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u16/mul.json b/zokrates_core_test/tests/tests/uint/u16/mul.json new file mode 100644 index 000000000..4b8ca5379 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u16/mul.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u16/mul.zok", + "max_constraint_count": 69, + "tests": [ + { + "input": { + "values": ["0x0002", "0x0008"] + }, + "output": { + "Ok": { + "values": ["0x0010"] + } + } + }, + { + "input": { + "values": ["0xffff", "0x0002"] + }, + "output": { + "Ok": { + "values": ["0xfffe"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u16/mul.zok b/zokrates_core_test/tests/tests/uint/u16/mul.zok new file mode 100644 index 000000000..da4655533 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u16/mul.zok @@ -0,0 +1,2 @@ +def main(u16 a, u16 b) -> u16: + return a * b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u16/neq.json b/zokrates_core_test/tests/tests/uint/u16/neq.json new file mode 100644 index 000000000..4a37373da --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u16/neq.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u16/neq.zok", + "max_constraint_count": 37, + "tests": [ + { + "input": { + "values": ["0x0002", "0x0002"] + }, + "output": { + "Ok": { + "values": ["0"] + } + } + }, + { + "input": { + "values": ["0x0002", "0x0004"] + }, + "output": { + "Ok": { + "values": ["1"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u16/neq.zok b/zokrates_core_test/tests/tests/uint/u16/neq.zok new file mode 100644 index 000000000..906da545e --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u16/neq.zok @@ -0,0 +1,2 @@ +def main(u16 a, u16 b) -> bool: + return a != b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u16/not.json b/zokrates_core_test/tests/tests/uint/u16/not.json new file mode 100644 index 000000000..d544a5766 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u16/not.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u16/not.zok", + "max_constraint_count": 18, + "tests": [ + { + "input": { + "values": ["0x0001"] + }, + "output": { + "Ok": { + "values": ["0xfffe"] + } + } + }, + { + "input": { + "values": ["0xffff"] + }, + "output": { + "Ok": { + "values": ["0x0000"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u16/not.zok b/zokrates_core_test/tests/tests/uint/u16/not.zok new file mode 100644 index 000000000..0b03209ca --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u16/not.zok @@ -0,0 +1,2 @@ +def main(u16 a) -> u16: + return !a \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u16/or.json b/zokrates_core_test/tests/tests/uint/u16/or.json new file mode 100644 index 000000000..dafb687b0 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u16/or.json @@ -0,0 +1,36 @@ +{ + "entry_point": "./tests/tests/uint/u16/or.zok", + "max_constraint_count": 51, + "tests": [ + { + "input": { + "values": ["0xffff", "0xffff"] + }, + "output": { + "Ok": { + "values": ["0xffff"] + } + } + }, + { + "input": { + "values": ["0xffff", "0x0000"] + }, + "output": { + "Ok": { + "values": ["0xffff"] + } + } + }, + { + "input": { + "values": ["0x1234", "0x5678"] + }, + "output": { + "Ok": { + "values": ["0x567c"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u16/or.zok b/zokrates_core_test/tests/tests/uint/u16/or.zok new file mode 100644 index 000000000..e3ccc9a66 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u16/or.zok @@ -0,0 +1,2 @@ +def main(u16 x, u16 y) -> u16: + return x | y \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u16/rem.json b/zokrates_core_test/tests/tests/uint/u16/rem.json new file mode 100644 index 000000000..77cd91647 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u16/rem.json @@ -0,0 +1,36 @@ +{ + "entry_point": "./tests/tests/uint/u16/rem.zok", + "max_constraint_count": 88, + "tests": [ + { + "input": { + "values": ["0x0002", "0x0004"] + }, + "output": { + "Ok": { + "values": ["0x0002"] + } + } + }, + { + "input": { + "values": ["0xffff", "0x0001"] + }, + "output": { + "Ok": { + "values": ["0x0000"] + } + } + }, + { + "input": { + "values": ["0x1001", "0x0002"] + }, + "output": { + "Ok": { + "values": ["0x0001"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u16/rem.zok b/zokrates_core_test/tests/tests/uint/u16/rem.zok new file mode 100644 index 000000000..4d53d7323 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u16/rem.zok @@ -0,0 +1,2 @@ +def main(u16 x, u16 y) -> u16: + return x % y \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u16/rshift.json b/zokrates_core_test/tests/tests/uint/u16/rshift.json new file mode 100644 index 000000000..d81290164 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u16/rshift.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u16/rshift.zok", + "max_constraint_count": 18, + "tests": [ + { + "input": { + "values": ["0x1000"] + }, + "output": { + "Ok": { + "values": ["0x0800"] + } + } + }, + { + "input": { + "values": ["0xffff"] + }, + "output": { + "Ok": { + "values": ["0x7fff"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u16/rshift.zok b/zokrates_core_test/tests/tests/uint/u16/rshift.zok new file mode 100644 index 000000000..3d95cd3c5 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u16/rshift.zok @@ -0,0 +1,2 @@ +def main(u16 x) -> u16: + return x >> 1 \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u16/sub.json b/zokrates_core_test/tests/tests/uint/u16/sub.json new file mode 100644 index 000000000..39e6bd1b8 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u16/sub.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u16/sub.zok", + "max_constraint_count": 53, + "tests": [ + { + "input": { + "values": ["0xffff", "0x0001"] + }, + "output": { + "Ok": { + "values": ["0xfffe"] + } + } + }, + { + "input": { + "values": ["0x0000", "0x0001"] + }, + "output": { + "Ok": { + "values": ["0xffff"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u16/sub.zok b/zokrates_core_test/tests/tests/uint/u16/sub.zok new file mode 100644 index 000000000..d6e31c7da --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u16/sub.zok @@ -0,0 +1,2 @@ +def main(u16 a, u16 b) -> u16: + return a - b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u16/xor.json b/zokrates_core_test/tests/tests/uint/u16/xor.json new file mode 100644 index 000000000..cb9c95ee4 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u16/xor.json @@ -0,0 +1,36 @@ +{ + "entry_point": "./tests/tests/uint/u16/xor.zok", + "max_constraint_count": 51, + "tests": [ + { + "input": { + "values": ["0xffff", "0xffff"] + }, + "output": { + "Ok": { + "values": ["0x0000"] + } + } + }, + { + "input": { + "values": ["0xffff", "0x0000"] + }, + "output": { + "Ok": { + "values": ["0xffff"] + } + } + }, + { + "input": { + "values": ["0x1234", "0x5678"] + }, + "output": { + "Ok": { + "values": ["0x444c"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u16/xor.zok b/zokrates_core_test/tests/tests/uint/u16/xor.zok new file mode 100644 index 000000000..620364d8e --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u16/xor.zok @@ -0,0 +1,2 @@ +def main(u16 a, u16 b) -> u16: + return a ^ b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u32/add.json b/zokrates_core_test/tests/tests/uint/u32/add.json new file mode 100644 index 000000000..91c876af7 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u32/add.json @@ -0,0 +1,36 @@ +{ + "entry_point": "./tests/tests/uint/u32/add.zok", + "max_constraint_count": 101, + "tests": [ + { + "input": { + "values": ["0xffffffff", "0x00000001"] + }, + "output": { + "Ok": { + "values": ["0x00000000"] + } + } + }, + { + "input": { + "values": ["0x10000000", "0x10000000"] + }, + "output": { + "Ok": { + "values": ["0x20000000"] + } + } + }, + { + "input": { + "values": ["0xffffffff", "0xffffffff"] + }, + "output": { + "Ok": { + "values": ["0xfffffffe"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u32/add.zok b/zokrates_core_test/tests/tests/uint/u32/add.zok new file mode 100644 index 000000000..f3846ffbc --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u32/add.zok @@ -0,0 +1,2 @@ +def main(u32 a, u32 b) -> u32: + return a + b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u32/and.json b/zokrates_core_test/tests/tests/uint/u32/and.json new file mode 100644 index 000000000..ccac4718a --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u32/and.json @@ -0,0 +1,36 @@ +{ + "entry_point": "./tests/tests/uint/u32/and.zok", + "max_constraint_count": 99, + "tests": [ + { + "input": { + "values": ["0xffffffff", "0xffffffff"] + }, + "output": { + "Ok": { + "values": ["0xffffffff"] + } + } + }, + { + "input": { + "values": ["0xffffffff", "0x00000000"] + }, + "output": { + "Ok": { + "values": ["0x00000000"] + } + } + }, + { + "input": { + "values": ["0x12345678", "0x87654321"] + }, + "output": { + "Ok": { + "values": ["0x02244220"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u32/and.zok b/zokrates_core_test/tests/tests/uint/u32/and.zok new file mode 100644 index 000000000..5b9287cb8 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u32/and.zok @@ -0,0 +1,2 @@ +def main(u32 a, u32 b) -> u32: + return a & b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u32/div.json b/zokrates_core_test/tests/tests/uint/u32/div.json new file mode 100644 index 000000000..ef1574c53 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u32/div.json @@ -0,0 +1,36 @@ +{ + "entry_point": "./tests/tests/uint/u32/div.zok", + "max_constraint_count": 168, + "tests": [ + { + "input": { + "values": ["0x10000000", "0x10000000"] + }, + "output": { + "Ok": { + "values": ["0x00000001"] + } + } + }, + { + "input": { + "values": ["0x10000000", "0x00000002"] + }, + "output": { + "Ok": { + "values": ["0x08000000"] + } + } + }, + { + "input": { + "values": ["0x10000001", "0x00000002"] + }, + "output": { + "Ok": { + "values": ["0x08000000"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u32/div.zok b/zokrates_core_test/tests/tests/uint/u32/div.zok new file mode 100644 index 000000000..1f768959c --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u32/div.zok @@ -0,0 +1,2 @@ +def main(u32 x, u32 y) -> u32: + return x / y \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u32/eq.json b/zokrates_core_test/tests/tests/uint/u32/eq.json new file mode 100644 index 000000000..e5040792a --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u32/eq.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u32/eq.zok", + "max_constraint_count": 69, + "tests": [ + { + "input": { + "values": ["0x00000002", "0x00000002"] + }, + "output": { + "Ok": { + "values": ["1"] + } + } + }, + { + "input": { + "values": ["0x00000002", "0x00000004"] + }, + "output": { + "Ok": { + "values": ["0"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u32/eq.zok b/zokrates_core_test/tests/tests/uint/u32/eq.zok new file mode 100644 index 000000000..b2087fdfd --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u32/eq.zok @@ -0,0 +1,2 @@ +def main(u32 a, u32 b) -> bool: + return a == b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u32/gt.json b/zokrates_core_test/tests/tests/uint/u32/gt.json new file mode 100644 index 000000000..71b7e1d68 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u32/gt.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u32/gt.zok", + "max_constraint_count": 729, + "tests": [ + { + "input": { + "values": ["0x00000004", "0x00000002"] + }, + "output": { + "Ok": { + "values": ["1"] + } + } + }, + { + "input": { + "values": ["0x00000002", "0x00000002"] + }, + "output": { + "Ok": { + "values": ["0"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u32/gt.zok b/zokrates_core_test/tests/tests/uint/u32/gt.zok new file mode 100644 index 000000000..acb0df0ce --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u32/gt.zok @@ -0,0 +1,2 @@ +def main(u32 a, u32 b) -> bool: + return a > b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u32/gte.json b/zokrates_core_test/tests/tests/uint/u32/gte.json new file mode 100644 index 000000000..feb45f8bf --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u32/gte.json @@ -0,0 +1,36 @@ +{ + "entry_point": "./tests/tests/uint/u32/gte.zok", + "max_constraint_count": 731, + "tests": [ + { + "input": { + "values": ["0x00000004", "0x00000002"] + }, + "output": { + "Ok": { + "values": ["1"] + } + } + }, + { + "input": { + "values": ["0x00000002", "0x00000002"] + }, + "output": { + "Ok": { + "values": ["1"] + } + } + }, + { + "input": { + "values": ["0x00000001", "0x00000002"] + }, + "output": { + "Ok": { + "values": ["0"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u32/gte.zok b/zokrates_core_test/tests/tests/uint/u32/gte.zok new file mode 100644 index 000000000..e08264a98 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u32/gte.zok @@ -0,0 +1,2 @@ +def main(u32 a, u32 b) -> bool: + return a >= b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u32/lshift.json b/zokrates_core_test/tests/tests/uint/u32/lshift.json new file mode 100644 index 000000000..9fddb95ee --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u32/lshift.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u32/lshift.zok", + "max_constraint_count": 34, + "tests": [ + { + "input": { + "values": ["0x00000002"] + }, + "output": { + "Ok": { + "values": ["0x00000004"] + } + } + }, + { + "input": { + "values": ["0xffffffff"] + }, + "output": { + "Ok": { + "values": ["0xfffffffe"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u32/lshift.zok b/zokrates_core_test/tests/tests/uint/u32/lshift.zok new file mode 100644 index 000000000..f417823b8 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u32/lshift.zok @@ -0,0 +1,2 @@ +def main(u32 x) -> u32: + return x << 1 \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u32/lt.json b/zokrates_core_test/tests/tests/uint/u32/lt.json new file mode 100644 index 000000000..5a80d005f --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u32/lt.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u32/lt.zok", + "max_constraint_count": 729, + "tests": [ + { + "input": { + "values": ["0x00000002", "0x00000004"] + }, + "output": { + "Ok": { + "values": ["1"] + } + } + }, + { + "input": { + "values": ["0x00000002", "0x00000002"] + }, + "output": { + "Ok": { + "values": ["0"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u32/lt.zok b/zokrates_core_test/tests/tests/uint/u32/lt.zok new file mode 100644 index 000000000..05cc5d53c --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u32/lt.zok @@ -0,0 +1,2 @@ +def main(u32 a, u32 b) -> bool: + return a < b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u32/lte.json b/zokrates_core_test/tests/tests/uint/u32/lte.json new file mode 100644 index 000000000..325329422 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u32/lte.json @@ -0,0 +1,36 @@ +{ + "entry_point": "./tests/tests/uint/u32/lte.zok", + "max_constraint_count": 731, + "tests": [ + { + "input": { + "values": ["0x00000002", "0x00000004"] + }, + "output": { + "Ok": { + "values": ["1"] + } + } + }, + { + "input": { + "values": ["0x00000002", "0x00000002"] + }, + "output": { + "Ok": { + "values": ["1"] + } + } + }, + { + "input": { + "values": ["0x00000003", "0x00000002"] + }, + "output": { + "Ok": { + "values": ["0"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u32/lte.zok b/zokrates_core_test/tests/tests/uint/u32/lte.zok new file mode 100644 index 000000000..0975ee9d4 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u32/lte.zok @@ -0,0 +1,2 @@ +def main(u32 a, u32 b) -> bool: + return a <= b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u32/mul.json b/zokrates_core_test/tests/tests/uint/u32/mul.json new file mode 100644 index 000000000..8504aafba --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u32/mul.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u32/mul.zok", + "max_constraint_count": 133, + "tests": [ + { + "input": { + "values": ["0x00000002", "0x00000008"] + }, + "output": { + "Ok": { + "values": ["0x00000010"] + } + } + }, + { + "input": { + "values": ["0xffffffff", "0x00000002"] + }, + "output": { + "Ok": { + "values": ["0xfffffffe"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u32/mul.zok b/zokrates_core_test/tests/tests/uint/u32/mul.zok new file mode 100644 index 000000000..bfeb9156e --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u32/mul.zok @@ -0,0 +1,2 @@ +def main(u32 a, u32 b) -> u32: + return a * b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u32/neq.json b/zokrates_core_test/tests/tests/uint/u32/neq.json new file mode 100644 index 000000000..c64f2d397 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u32/neq.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u32/neq.zok", + "max_constraint_count": 69, + "tests": [ + { + "input": { + "values": ["0x00000002", "0x00000002"] + }, + "output": { + "Ok": { + "values": ["0"] + } + } + }, + { + "input": { + "values": ["0x00000002", "0x00000004"] + }, + "output": { + "Ok": { + "values": ["1"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u32/neq.zok b/zokrates_core_test/tests/tests/uint/u32/neq.zok new file mode 100644 index 000000000..db6f1b1de --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u32/neq.zok @@ -0,0 +1,2 @@ +def main(u32 a, u32 b) -> bool: + return a != b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u32/not.json b/zokrates_core_test/tests/tests/uint/u32/not.json new file mode 100644 index 000000000..a17fe27d8 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u32/not.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u32/not.zok", + "max_constraint_count": 34, + "tests": [ + { + "input": { + "values": ["0x00000001"] + }, + "output": { + "Ok": { + "values": ["0xfffffffe"] + } + } + }, + { + "input": { + "values": ["0xffffffff"] + }, + "output": { + "Ok": { + "values": ["0x00000000"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/shift.zok b/zokrates_core_test/tests/tests/uint/u32/not.zok similarity index 63% rename from zokrates_core_test/tests/tests/uint/shift.zok rename to zokrates_core_test/tests/tests/uint/u32/not.zok index 07ae59492..8a3545af5 100644 --- a/zokrates_core_test/tests/tests/uint/shift.zok +++ b/zokrates_core_test/tests/tests/uint/u32/not.zok @@ -1,2 +1,2 @@ def main(u32 a) -> u32: - return a >> 4 \ No newline at end of file + return !a \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u32/or.json b/zokrates_core_test/tests/tests/uint/u32/or.json new file mode 100644 index 000000000..3b095d548 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u32/or.json @@ -0,0 +1,36 @@ +{ + "entry_point": "./tests/tests/uint/u32/or.zok", + "max_constraint_count": 99, + "tests": [ + { + "input": { + "values": ["0xffffffff", "0xffffffff"] + }, + "output": { + "Ok": { + "values": ["0xffffffff"] + } + } + }, + { + "input": { + "values": ["0xffffffff", "0x00000000"] + }, + "output": { + "Ok": { + "values": ["0xffffffff"] + } + } + }, + { + "input": { + "values": ["0x12345678", "0x87654321"] + }, + "output": { + "Ok": { + "values": ["0x97755779"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u32/or.zok b/zokrates_core_test/tests/tests/uint/u32/or.zok new file mode 100644 index 000000000..fb9d9a5b7 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u32/or.zok @@ -0,0 +1,2 @@ +def main(u32 x, u32 y) -> u32: + return x | y \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u32/rem.json b/zokrates_core_test/tests/tests/uint/u32/rem.json new file mode 100644 index 000000000..faeda5dbe --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u32/rem.json @@ -0,0 +1,36 @@ +{ + "entry_point": "./tests/tests/uint/u32/rem.zok", + "max_constraint_count": 168, + "tests": [ + { + "input": { + "values": ["0x00000002", "0x00000004"] + }, + "output": { + "Ok": { + "values": ["0x00000002"] + } + } + }, + { + "input": { + "values": ["0xffffffff", "0x00000001"] + }, + "output": { + "Ok": { + "values": ["0x00000000"] + } + } + }, + { + "input": { + "values": ["0x10000001", "0x00000002"] + }, + "output": { + "Ok": { + "values": ["0x00000001"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u32/rem.zok b/zokrates_core_test/tests/tests/uint/u32/rem.zok new file mode 100644 index 000000000..d5a1f22fc --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u32/rem.zok @@ -0,0 +1,2 @@ +def main(u32 x, u32 y) -> u32: + return x % y \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u32/rshift.json b/zokrates_core_test/tests/tests/uint/u32/rshift.json new file mode 100644 index 000000000..1b852b572 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u32/rshift.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u32/rshift.zok", + "max_constraint_count": 34, + "tests": [ + { + "input": { + "values": ["0x10000000"] + }, + "output": { + "Ok": { + "values": ["0x08000000"] + } + } + }, + { + "input": { + "values": ["0xffffffff"] + }, + "output": { + "Ok": { + "values": ["0x7fffffff"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u32/rshift.zok b/zokrates_core_test/tests/tests/uint/u32/rshift.zok new file mode 100644 index 000000000..c70ee2c6c --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u32/rshift.zok @@ -0,0 +1,2 @@ +def main(u32 x) -> u32: + return x >> 1 \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u32/sub.json b/zokrates_core_test/tests/tests/uint/u32/sub.json new file mode 100644 index 000000000..2d6075197 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u32/sub.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u32/sub.zok", + "max_constraint_count": 101, + "tests": [ + { + "input": { + "values": ["0xffffffff", "0x00000001"] + }, + "output": { + "Ok": { + "values": ["0xfffffffe"] + } + } + }, + { + "input": { + "values": ["0x00000000", "0x00000001"] + }, + "output": { + "Ok": { + "values": ["0xffffffff"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u32/sub.zok b/zokrates_core_test/tests/tests/uint/u32/sub.zok new file mode 100644 index 000000000..5700177c6 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u32/sub.zok @@ -0,0 +1,2 @@ +def main(u32 a, u32 b) -> u32: + return a - b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u32/xor.json b/zokrates_core_test/tests/tests/uint/u32/xor.json new file mode 100644 index 000000000..e37db969f --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u32/xor.json @@ -0,0 +1,36 @@ +{ + "entry_point": "./tests/tests/uint/u32/xor.zok", + "max_constraint_count": 99, + "tests": [ + { + "input": { + "values": ["0xffffffff", "0xffffffff"] + }, + "output": { + "Ok": { + "values": ["0x00000000"] + } + } + }, + { + "input": { + "values": ["0xffffffff", "0x00000000"] + }, + "output": { + "Ok": { + "values": ["0xffffffff"] + } + } + }, + { + "input": { + "values": ["0x12345678", "0x87654321"] + }, + "output": { + "Ok": { + "values": ["0x95511559"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u32/xor.zok b/zokrates_core_test/tests/tests/uint/u32/xor.zok new file mode 100644 index 000000000..59cf98d52 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u32/xor.zok @@ -0,0 +1,2 @@ +def main(u32 a, u32 b) -> u32: + return a ^ b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u64/add.json b/zokrates_core_test/tests/tests/uint/u64/add.json new file mode 100644 index 000000000..0663fc03e --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u64/add.json @@ -0,0 +1,36 @@ +{ + "entry_point": "./tests/tests/uint/u64/add.zok", + "max_constraint_count": 197, + "tests": [ + { + "input": { + "values": ["0xffffffffffffffff", "0x0000000000000001"] + }, + "output": { + "Ok": { + "values": ["0x0000000000000000"] + } + } + }, + { + "input": { + "values": ["0x1000000000000000", "0x1000000000000000"] + }, + "output": { + "Ok": { + "values": ["0x2000000000000000"] + } + } + }, + { + "input": { + "values": ["0xffffffffffffffff", "0xffffffffffffffff"] + }, + "output": { + "Ok": { + "values": ["0xfffffffffffffffe"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u64/add.zok b/zokrates_core_test/tests/tests/uint/u64/add.zok new file mode 100644 index 000000000..66077da7e --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u64/add.zok @@ -0,0 +1,2 @@ +def main(u64 a, u64 b) -> u64: + return a + b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u64/and.json b/zokrates_core_test/tests/tests/uint/u64/and.json new file mode 100644 index 000000000..93ada8934 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u64/and.json @@ -0,0 +1,36 @@ +{ + "entry_point": "./tests/tests/uint/u64/and.zok", + "max_constraint_count": 195, + "tests": [ + { + "input": { + "values": ["0xffffffffffffffff", "0xffffffffffffffff"] + }, + "output": { + "Ok": { + "values": ["0xffffffffffffffff"] + } + } + }, + { + "input": { + "values": ["0xffffffffffffffff", "0x0000000000000000"] + }, + "output": { + "Ok": { + "values": ["0x0000000000000000"] + } + } + }, + { + "input": { + "values": ["0x1234567812345678", "0x8765432187654321"] + }, + "output": { + "Ok": { + "values": ["0x224422002244220"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u64/and.zok b/zokrates_core_test/tests/tests/uint/u64/and.zok new file mode 100644 index 000000000..4e693107d --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u64/and.zok @@ -0,0 +1,2 @@ +def main(u64 a, u64 b) -> u64: + return a & b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u64/div.json b/zokrates_core_test/tests/tests/uint/u64/div.json new file mode 100644 index 000000000..a3b92ed6e --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u64/div.json @@ -0,0 +1,36 @@ +{ + "entry_point": "./tests/tests/uint/u64/div.zok", + "max_constraint_count": 328, + "tests": [ + { + "input": { + "values": ["0x1000000000000000", "0x1000000000000000"] + }, + "output": { + "Ok": { + "values": ["0x0000000000000001"] + } + } + }, + { + "input": { + "values": ["0x1000000000000000", "0x0000000000000002"] + }, + "output": { + "Ok": { + "values": ["0x0800000000000000"] + } + } + }, + { + "input": { + "values": ["0x1000000000000001", "0x0000000000000002"] + }, + "output": { + "Ok": { + "values": ["0x0800000000000000"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u64/div.zok b/zokrates_core_test/tests/tests/uint/u64/div.zok new file mode 100644 index 000000000..2b637ddb3 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u64/div.zok @@ -0,0 +1,2 @@ +def main(u64 x, u64 y) -> u64: + return x / y \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u64/eq.json b/zokrates_core_test/tests/tests/uint/u64/eq.json new file mode 100644 index 000000000..01480b029 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u64/eq.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u64/eq.zok", + "max_constraint_count": 133, + "tests": [ + { + "input": { + "values": ["0x0000000000000002", "0x0000000000000002"] + }, + "output": { + "Ok": { + "values": ["1"] + } + } + }, + { + "input": { + "values": ["0x0000000000000002", "0x0000000000000004"] + }, + "output": { + "Ok": { + "values": ["0"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u64/eq.zok b/zokrates_core_test/tests/tests/uint/u64/eq.zok new file mode 100644 index 000000000..ed6c5bbaf --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u64/eq.zok @@ -0,0 +1,2 @@ +def main(u64 a, u64 b) -> bool: + return a == b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u64/gt.json b/zokrates_core_test/tests/tests/uint/u64/gt.json new file mode 100644 index 000000000..7224a66db --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u64/gt.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u64/gt.zok", + "max_constraint_count": 793, + "tests": [ + { + "input": { + "values": ["0x0000000000000004", "0x0000000000000002"] + }, + "output": { + "Ok": { + "values": ["1"] + } + } + }, + { + "input": { + "values": ["0x0000000000000002", "0x0000000000000002"] + }, + "output": { + "Ok": { + "values": ["0"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u64/gt.zok b/zokrates_core_test/tests/tests/uint/u64/gt.zok new file mode 100644 index 000000000..3af2e9eba --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u64/gt.zok @@ -0,0 +1,2 @@ +def main(u64 a, u64 b) -> bool: + return a > b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u64/gte.json b/zokrates_core_test/tests/tests/uint/u64/gte.json new file mode 100644 index 000000000..7ab764a92 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u64/gte.json @@ -0,0 +1,36 @@ +{ + "entry_point": "./tests/tests/uint/u64/gte.zok", + "max_constraint_count": 795, + "tests": [ + { + "input": { + "values": ["0x0000000000000004", "0x0000000000000002"] + }, + "output": { + "Ok": { + "values": ["1"] + } + } + }, + { + "input": { + "values": ["0x0000000000000002", "0x0000000000000002"] + }, + "output": { + "Ok": { + "values": ["1"] + } + } + }, + { + "input": { + "values": ["0x0000000000000001", "0x0000000000000002"] + }, + "output": { + "Ok": { + "values": ["0"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u64/gte.zok b/zokrates_core_test/tests/tests/uint/u64/gte.zok new file mode 100644 index 000000000..fb6f0b5d4 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u64/gte.zok @@ -0,0 +1,2 @@ +def main(u64 a, u64 b) -> bool: + return a >= b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u64/lshift.json b/zokrates_core_test/tests/tests/uint/u64/lshift.json new file mode 100644 index 000000000..70ac4e60b --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u64/lshift.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u64/lshift.zok", + "max_constraint_count": 66, + "tests": [ + { + "input": { + "values": ["0x0000000000000002"] + }, + "output": { + "Ok": { + "values": ["0x0000000000000004"] + } + } + }, + { + "input": { + "values": ["0xffffffffffffffff"] + }, + "output": { + "Ok": { + "values": ["0xfffffffffffffffe"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u64/lshift.zok b/zokrates_core_test/tests/tests/uint/u64/lshift.zok new file mode 100644 index 000000000..55798fe5e --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u64/lshift.zok @@ -0,0 +1,2 @@ +def main(u64 x) -> u64: + return x << 1 \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u64/lt.json b/zokrates_core_test/tests/tests/uint/u64/lt.json new file mode 100644 index 000000000..4c74006a7 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u64/lt.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u64/lt.zok", + "max_constraint_count": 793, + "tests": [ + { + "input": { + "values": ["0x0000000000000002", "0x0000000000000004"] + }, + "output": { + "Ok": { + "values": ["1"] + } + } + }, + { + "input": { + "values": ["0x0000000000000002", "0x0000000000000002"] + }, + "output": { + "Ok": { + "values": ["0"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u64/lt.zok b/zokrates_core_test/tests/tests/uint/u64/lt.zok new file mode 100644 index 000000000..327693928 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u64/lt.zok @@ -0,0 +1,2 @@ +def main(u64 a, u64 b) -> bool: + return a < b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u64/lte.json b/zokrates_core_test/tests/tests/uint/u64/lte.json new file mode 100644 index 000000000..6c35f5d54 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u64/lte.json @@ -0,0 +1,36 @@ +{ + "entry_point": "./tests/tests/uint/u64/lte.zok", + "max_constraint_count": 795, + "tests": [ + { + "input": { + "values": ["0x0000000000000002", "0x0000000000000004"] + }, + "output": { + "Ok": { + "values": ["1"] + } + } + }, + { + "input": { + "values": ["0x0000000000000002", "0x0000000000000002"] + }, + "output": { + "Ok": { + "values": ["1"] + } + } + }, + { + "input": { + "values": ["0x0000000000000003", "0x0000000000000002"] + }, + "output": { + "Ok": { + "values": ["0"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u64/lte.zok b/zokrates_core_test/tests/tests/uint/u64/lte.zok new file mode 100644 index 000000000..3d3351927 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u64/lte.zok @@ -0,0 +1,2 @@ +def main(u64 a, u64 b) -> bool: + return a <= b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u64/mul.json b/zokrates_core_test/tests/tests/uint/u64/mul.json new file mode 100644 index 000000000..3afc1f46b --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u64/mul.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u64/mul.zok", + "max_constraint_count": 261, + "tests": [ + { + "input": { + "values": ["0x0000000000000002", "0x0000000000000008"] + }, + "output": { + "Ok": { + "values": ["0x0000000000000010"] + } + } + }, + { + "input": { + "values": ["0xffffffffffffffff", "0x0000000000000002"] + }, + "output": { + "Ok": { + "values": ["0xfffffffffffffffe"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u64/mul.zok b/zokrates_core_test/tests/tests/uint/u64/mul.zok new file mode 100644 index 000000000..99ad92d6b --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u64/mul.zok @@ -0,0 +1,2 @@ +def main(u64 a, u64 b) -> u64: + return a * b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u64/neq.json b/zokrates_core_test/tests/tests/uint/u64/neq.json new file mode 100644 index 000000000..72e448b7f --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u64/neq.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u64/neq.zok", + "max_constraint_count": 133, + "tests": [ + { + "input": { + "values": ["0x0000000000000002", "0x0000000000000002"] + }, + "output": { + "Ok": { + "values": ["0"] + } + } + }, + { + "input": { + "values": ["0x0000000000000002", "0x0000000000000004"] + }, + "output": { + "Ok": { + "values": ["1"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u64/neq.zok b/zokrates_core_test/tests/tests/uint/u64/neq.zok new file mode 100644 index 000000000..e2db5d37e --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u64/neq.zok @@ -0,0 +1,2 @@ +def main(u64 a, u64 b) -> bool: + return a != b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u64/not.json b/zokrates_core_test/tests/tests/uint/u64/not.json new file mode 100644 index 000000000..244feef68 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u64/not.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u64/not.zok", + "max_constraint_count": 66, + "tests": [ + { + "input": { + "values": ["0x0000000000000001"] + }, + "output": { + "Ok": { + "values": ["0xfffffffffffffffe"] + } + } + }, + { + "input": { + "values": ["0xffffffffffffffff"] + }, + "output": { + "Ok": { + "values": ["0x0000000000000000"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u64/not.zok b/zokrates_core_test/tests/tests/uint/u64/not.zok new file mode 100644 index 000000000..fbbc0009a --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u64/not.zok @@ -0,0 +1,2 @@ +def main(u64 a) -> u64: + return !a \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u64/or.json b/zokrates_core_test/tests/tests/uint/u64/or.json new file mode 100644 index 000000000..2492f9503 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u64/or.json @@ -0,0 +1,36 @@ +{ + "entry_point": "./tests/tests/uint/u64/or.zok", + "max_constraint_count": 195, + "tests": [ + { + "input": { + "values": ["0xffffffffffffffff", "0xffffffffffffffff"] + }, + "output": { + "Ok": { + "values": ["0xffffffffffffffff"] + } + } + }, + { + "input": { + "values": ["0xffffffffffffffff", "0x0000000000000000"] + }, + "output": { + "Ok": { + "values": ["0xffffffffffffffff"] + } + } + }, + { + "input": { + "values": ["0x1234567812345678", "0x8765432187654321"] + }, + "output": { + "Ok": { + "values": ["0x9775577997755779"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u64/or.zok b/zokrates_core_test/tests/tests/uint/u64/or.zok new file mode 100644 index 000000000..f74669ad2 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u64/or.zok @@ -0,0 +1,2 @@ +def main(u64 x, u64 y) -> u64: + return x | y \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u64/rem.json b/zokrates_core_test/tests/tests/uint/u64/rem.json new file mode 100644 index 000000000..8e390e33d --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u64/rem.json @@ -0,0 +1,36 @@ +{ + "entry_point": "./tests/tests/uint/u64/rem.zok", + "max_constraint_count": 328, + "tests": [ + { + "input": { + "values": ["0x0000000000000002", "0x0000000000000004"] + }, + "output": { + "Ok": { + "values": ["0x0000000000000002"] + } + } + }, + { + "input": { + "values": ["0xffffffffffffffff", "0x0000000000000001"] + }, + "output": { + "Ok": { + "values": ["0x0000000000000000"] + } + } + }, + { + "input": { + "values": ["0x1000000000000001", "0x0000000000000002"] + }, + "output": { + "Ok": { + "values": ["0x0000000000000001"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u64/rem.zok b/zokrates_core_test/tests/tests/uint/u64/rem.zok new file mode 100644 index 000000000..7d40d228f --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u64/rem.zok @@ -0,0 +1,2 @@ +def main(u64 x, u64 y) -> u64: + return x % y \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u64/rshift.json b/zokrates_core_test/tests/tests/uint/u64/rshift.json new file mode 100644 index 000000000..e279b3a70 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u64/rshift.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u64/rshift.zok", + "max_constraint_count": 66, + "tests": [ + { + "input": { + "values": ["0x1000000000000000"] + }, + "output": { + "Ok": { + "values": ["0x0800000000000000"] + } + } + }, + { + "input": { + "values": ["0xffffffffffffffff"] + }, + "output": { + "Ok": { + "values": ["0x7fffffffffffffff"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u64/rshift.zok b/zokrates_core_test/tests/tests/uint/u64/rshift.zok new file mode 100644 index 000000000..e2d36c478 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u64/rshift.zok @@ -0,0 +1,2 @@ +def main(u64 x) -> u64: + return x >> 1 \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u64/sub.json b/zokrates_core_test/tests/tests/uint/u64/sub.json new file mode 100644 index 000000000..93b4c3b8c --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u64/sub.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u64/sub.zok", + "max_constraint_count": 197, + "tests": [ + { + "input": { + "values": ["0xffffffffffffffff", "0x0000000000000001"] + }, + "output": { + "Ok": { + "values": ["0xfffffffffffffffe"] + } + } + }, + { + "input": { + "values": ["0x0000000000000000", "0x0000000000000001"] + }, + "output": { + "Ok": { + "values": ["0xffffffffffffffff"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u64/sub.zok b/zokrates_core_test/tests/tests/uint/u64/sub.zok new file mode 100644 index 000000000..deda0fb53 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u64/sub.zok @@ -0,0 +1,2 @@ +def main(u64 a, u64 b) -> u64: + return a - b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u64/xor.json b/zokrates_core_test/tests/tests/uint/u64/xor.json new file mode 100644 index 000000000..8fff5bf2c --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u64/xor.json @@ -0,0 +1,36 @@ +{ + "entry_point": "./tests/tests/uint/u64/xor.zok", + "max_constraint_count": 195, + "tests": [ + { + "input": { + "values": ["0xffffffffffffffff", "0xffffffffffffffff"] + }, + "output": { + "Ok": { + "values": ["0x0000000000000000"] + } + } + }, + { + "input": { + "values": ["0xffffffffffffffff", "0x0000000000000000"] + }, + "output": { + "Ok": { + "values": ["0xffffffffffffffff"] + } + } + }, + { + "input": { + "values": ["0x1234567812345678", "0x8765432187654321"] + }, + "output": { + "Ok": { + "values": ["0x9551155995511559"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u64/xor.zok b/zokrates_core_test/tests/tests/uint/u64/xor.zok new file mode 100644 index 000000000..9f96c6d98 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u64/xor.zok @@ -0,0 +1,2 @@ +def main(u64 a, u64 b) -> u64: + return a ^ b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u8/add.json b/zokrates_core_test/tests/tests/uint/u8/add.json new file mode 100644 index 000000000..4a51cd8ce --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u8/add.json @@ -0,0 +1,36 @@ +{ + "entry_point": "./tests/tests/uint/u8/add.zok", + "max_constraint_count": 29, + "tests": [ + { + "input": { + "values": ["0xff", "0x01"] + }, + "output": { + "Ok": { + "values": ["0x00"] + } + } + }, + { + "input": { + "values": ["0x02", "0x02"] + }, + "output": { + "Ok": { + "values": ["0x04"] + } + } + }, + { + "input": { + "values": ["0xff", "0xff"] + }, + "output": { + "Ok": { + "values": ["0xfe"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/add.zok b/zokrates_core_test/tests/tests/uint/u8/add.zok similarity index 63% rename from zokrates_core_test/tests/tests/uint/add.zok rename to zokrates_core_test/tests/tests/uint/u8/add.zok index 925f2208c..2fc36f434 100644 --- a/zokrates_core_test/tests/tests/uint/add.zok +++ b/zokrates_core_test/tests/tests/uint/u8/add.zok @@ -1,2 +1,2 @@ def main(u8 a, u8 b) -> u8: - return a + b \ No newline at end of file + return a + b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u8/and.json b/zokrates_core_test/tests/tests/uint/u8/and.json new file mode 100644 index 000000000..c2944f1cf --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u8/and.json @@ -0,0 +1,36 @@ +{ + "entry_point": "./tests/tests/uint/u8/and.zok", + "max_constraint_count": 27, + "tests": [ + { + "input": { + "values": ["0xff", "0xff"] + }, + "output": { + "Ok": { + "values": ["0xff"] + } + } + }, + { + "input": { + "values": ["0xff", "0x00"] + }, + "output": { + "Ok": { + "values": ["0x00"] + } + } + }, + { + "input": { + "values": ["0x23", "0x34"] + }, + "output": { + "Ok": { + "values": ["0x20"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/and.zok b/zokrates_core_test/tests/tests/uint/u8/and.zok similarity index 63% rename from zokrates_core_test/tests/tests/uint/and.zok rename to zokrates_core_test/tests/tests/uint/u8/and.zok index f53e0ee4a..8c66852d8 100644 --- a/zokrates_core_test/tests/tests/uint/and.zok +++ b/zokrates_core_test/tests/tests/uint/u8/and.zok @@ -1,2 +1,2 @@ def main(u8 a, u8 b) -> u8: - return a & b \ No newline at end of file + return a & b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u8/div.json b/zokrates_core_test/tests/tests/uint/u8/div.json new file mode 100644 index 000000000..b5cda8d1f --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u8/div.json @@ -0,0 +1,36 @@ +{ + "entry_point": "./tests/tests/uint/u8/div.zok", + "max_constraint_count": 48, + "tests": [ + { + "input": { + "values": ["0x02", "0x02"] + }, + "output": { + "Ok": { + "values": ["0x01"] + } + } + }, + { + "input": { + "values": ["0x04", "0x02"] + }, + "output": { + "Ok": { + "values": ["0x02"] + } + } + }, + { + "input": { + "values": ["0x2a", "0x0a"] + }, + "output": { + "Ok": { + "values": ["0x04"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u8/div.zok b/zokrates_core_test/tests/tests/uint/u8/div.zok new file mode 100644 index 000000000..2c8c2ce10 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u8/div.zok @@ -0,0 +1,2 @@ +def main(u8 x, u8 y) -> u8: + return x / y \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u8/eq.json b/zokrates_core_test/tests/tests/uint/u8/eq.json new file mode 100644 index 000000000..46bf07528 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u8/eq.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u8/eq.zok", + "max_constraint_count": 21, + "tests": [ + { + "input": { + "values": ["0x02", "0x02"] + }, + "output": { + "Ok": { + "values": ["1"] + } + } + }, + { + "input": { + "values": ["0x02", "0x04"] + }, + "output": { + "Ok": { + "values": ["0"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u8/eq.zok b/zokrates_core_test/tests/tests/uint/u8/eq.zok new file mode 100644 index 000000000..fe36c5e6b --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u8/eq.zok @@ -0,0 +1,2 @@ +def main(u8 a, u8 b) -> bool: + return a == b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u8/gt.json b/zokrates_core_test/tests/tests/uint/u8/gt.json new file mode 100644 index 000000000..e14320411 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u8/gt.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u8/gt.zok", + "max_constraint_count": 681, + "tests": [ + { + "input": { + "values": ["0x04", "0x02"] + }, + "output": { + "Ok": { + "values": ["1"] + } + } + }, + { + "input": { + "values": ["0x02", "0x02"] + }, + "output": { + "Ok": { + "values": ["0"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u8/gt.zok b/zokrates_core_test/tests/tests/uint/u8/gt.zok new file mode 100644 index 000000000..689b1548d --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u8/gt.zok @@ -0,0 +1,2 @@ +def main(u8 a, u8 b) -> bool: + return a > b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u8/gte.json b/zokrates_core_test/tests/tests/uint/u8/gte.json new file mode 100644 index 000000000..1b3d35b87 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u8/gte.json @@ -0,0 +1,36 @@ +{ + "entry_point": "./tests/tests/uint/u8/gte.zok", + "max_constraint_count": 681, + "tests": [ + { + "input": { + "values": ["0x04", "0x02"] + }, + "output": { + "Ok": { + "values": ["1"] + } + } + }, + { + "input": { + "values": ["0x02", "0x02"] + }, + "output": { + "Ok": { + "values": ["1"] + } + } + }, + { + "input": { + "values": ["0x01", "0x02"] + }, + "output": { + "Ok": { + "values": ["0"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u8/gte.zok b/zokrates_core_test/tests/tests/uint/u8/gte.zok new file mode 100644 index 000000000..88cb58bb2 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u8/gte.zok @@ -0,0 +1,2 @@ +def main(u8 a, u8 b) -> bool: + return a >= b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u8/lshift.json b/zokrates_core_test/tests/tests/uint/u8/lshift.json new file mode 100644 index 000000000..ca664ad93 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u8/lshift.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u8/lshift.zok", + "max_constraint_count": 10, + "tests": [ + { + "input": { + "values": ["0x02"] + }, + "output": { + "Ok": { + "values": ["0x04"] + } + } + }, + { + "input": { + "values": ["0xff"] + }, + "output": { + "Ok": { + "values": ["0xfe"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u8/lshift.zok b/zokrates_core_test/tests/tests/uint/u8/lshift.zok new file mode 100644 index 000000000..0744d507f --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u8/lshift.zok @@ -0,0 +1,2 @@ +def main(u8 x) -> u8: + return x << 1 \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u8/lt.json b/zokrates_core_test/tests/tests/uint/u8/lt.json new file mode 100644 index 000000000..c290cd94b --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u8/lt.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u8/lt.zok", + "max_constraint_count": 681, + "tests": [ + { + "input": { + "values": ["0x02", "0x04"] + }, + "output": { + "Ok": { + "values": ["1"] + } + } + }, + { + "input": { + "values": ["0x02", "0x02"] + }, + "output": { + "Ok": { + "values": ["0"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u8/lt.zok b/zokrates_core_test/tests/tests/uint/u8/lt.zok new file mode 100644 index 000000000..258c943fb --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u8/lt.zok @@ -0,0 +1,2 @@ +def main(u8 a, u8 b) -> bool: + return a < b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u8/lte.json b/zokrates_core_test/tests/tests/uint/u8/lte.json new file mode 100644 index 000000000..f2bd803f0 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u8/lte.json @@ -0,0 +1,36 @@ +{ + "entry_point": "./tests/tests/uint/u8/lte.zok", + "max_constraint_count": 683, + "tests": [ + { + "input": { + "values": ["0x02", "0x04"] + }, + "output": { + "Ok": { + "values": ["1"] + } + } + }, + { + "input": { + "values": ["0x02", "0x02"] + }, + "output": { + "Ok": { + "values": ["1"] + } + } + }, + { + "input": { + "values": ["0x03", "0x02"] + }, + "output": { + "Ok": { + "values": ["0"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u8/lte.zok b/zokrates_core_test/tests/tests/uint/u8/lte.zok new file mode 100644 index 000000000..47de1f477 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u8/lte.zok @@ -0,0 +1,2 @@ +def main(u8 a, u8 b) -> bool: + return a <= b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u8/mul.json b/zokrates_core_test/tests/tests/uint/u8/mul.json new file mode 100644 index 000000000..72878d750 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u8/mul.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u8/mul.zok", + "max_constraint_count": 37, + "tests": [ + { + "input": { + "values": ["0x02", "0x02"] + }, + "output": { + "Ok": { + "values": ["0x04"] + } + } + }, + { + "input": { + "values": ["0xff", "0x02"] + }, + "output": { + "Ok": { + "values": ["0xfe"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/mul.zok b/zokrates_core_test/tests/tests/uint/u8/mul.zok similarity index 63% rename from zokrates_core_test/tests/tests/uint/mul.zok rename to zokrates_core_test/tests/tests/uint/u8/mul.zok index 195ff2b41..6336ccedb 100644 --- a/zokrates_core_test/tests/tests/uint/mul.zok +++ b/zokrates_core_test/tests/tests/uint/u8/mul.zok @@ -1,2 +1,2 @@ def main(u8 a, u8 b) -> u8: - return a * b \ No newline at end of file + return a * b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u8/neq.json b/zokrates_core_test/tests/tests/uint/u8/neq.json new file mode 100644 index 000000000..fae87c753 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u8/neq.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u8/neq.zok", + "max_constraint_count": 21, + "tests": [ + { + "input": { + "values": ["0x02", "0x02"] + }, + "output": { + "Ok": { + "values": ["0"] + } + } + }, + { + "input": { + "values": ["0x02", "0x04"] + }, + "output": { + "Ok": { + "values": ["1"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u8/neq.zok b/zokrates_core_test/tests/tests/uint/u8/neq.zok new file mode 100644 index 000000000..50dbe3bee --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u8/neq.zok @@ -0,0 +1,2 @@ +def main(u8 a, u8 b) -> bool: + return a != b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u8/not.json b/zokrates_core_test/tests/tests/uint/u8/not.json new file mode 100644 index 000000000..40e9153d9 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u8/not.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u8/not.zok", + "max_constraint_count": 10, + "tests": [ + { + "input": { + "values": ["0x01"] + }, + "output": { + "Ok": { + "values": ["0xfe"] + } + } + }, + { + "input": { + "values": ["0xff"] + }, + "output": { + "Ok": { + "values": ["0x00"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u8/not.zok b/zokrates_core_test/tests/tests/uint/u8/not.zok new file mode 100644 index 000000000..422b309c9 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u8/not.zok @@ -0,0 +1,2 @@ +def main(u8 a) -> u8: + return !a \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u8/or.json b/zokrates_core_test/tests/tests/uint/u8/or.json new file mode 100644 index 000000000..5e756cf16 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u8/or.json @@ -0,0 +1,36 @@ +{ + "entry_point": "./tests/tests/uint/u8/or.zok", + "max_constraint_count": 27, + "tests": [ + { + "input": { + "values": ["0xff", "0xff"] + }, + "output": { + "Ok": { + "values": ["0xff"] + } + } + }, + { + "input": { + "values": ["0xff", "0x00"] + }, + "output": { + "Ok": { + "values": ["0xff"] + } + } + }, + { + "input": { + "values": ["0x23", "0x34"] + }, + "output": { + "Ok": { + "values": ["0x37"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/or.zok b/zokrates_core_test/tests/tests/uint/u8/or.zok similarity index 63% rename from zokrates_core_test/tests/tests/uint/or.zok rename to zokrates_core_test/tests/tests/uint/u8/or.zok index fbd290b0a..315945937 100644 --- a/zokrates_core_test/tests/tests/uint/or.zok +++ b/zokrates_core_test/tests/tests/uint/u8/or.zok @@ -1,2 +1,2 @@ def main(u8 x, u8 y) -> u8: - return x | y \ No newline at end of file + return x | y \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u8/rem.json b/zokrates_core_test/tests/tests/uint/u8/rem.json new file mode 100644 index 000000000..e89ce3eb2 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u8/rem.json @@ -0,0 +1,36 @@ +{ + "entry_point": "./tests/tests/uint/u8/rem.zok", + "max_constraint_count": 48, + "tests": [ + { + "input": { + "values": ["0x02", "0x04"] + }, + "output": { + "Ok": { + "values": ["0x02"] + } + } + }, + { + "input": { + "values": ["0xff", "0x01"] + }, + "output": { + "Ok": { + "values": ["0x00"] + } + } + }, + { + "input": { + "values": ["0x2a", "0x0a"] + }, + "output": { + "Ok": { + "values": ["0x02"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u8/rem.zok b/zokrates_core_test/tests/tests/uint/u8/rem.zok new file mode 100644 index 000000000..e9f6a7b3d --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u8/rem.zok @@ -0,0 +1,2 @@ +def main(u8 x, u8 y) -> u8: + return x % y \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u8/rshift.json b/zokrates_core_test/tests/tests/uint/u8/rshift.json new file mode 100644 index 000000000..1155edbc2 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u8/rshift.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u8/rshift.zok", + "max_constraint_count": 10, + "tests": [ + { + "input": { + "values": ["0x02"] + }, + "output": { + "Ok": { + "values": ["0x01"] + } + } + }, + { + "input": { + "values": ["0xff"] + }, + "output": { + "Ok": { + "values": ["0x7f"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u8/rshift.zok b/zokrates_core_test/tests/tests/uint/u8/rshift.zok new file mode 100644 index 000000000..c92009606 --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u8/rshift.zok @@ -0,0 +1,2 @@ +def main(u8 x) -> u8: + return x >> 1 \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u8/sub.json b/zokrates_core_test/tests/tests/uint/u8/sub.json new file mode 100644 index 000000000..084bce99a --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u8/sub.json @@ -0,0 +1,26 @@ +{ + "entry_point": "./tests/tests/uint/u8/sub.zok", + "max_constraint_count": 29, + "tests": [ + { + "input": { + "values": ["0xff", "0x01"] + }, + "output": { + "Ok": { + "values": ["0xfe"] + } + } + }, + { + "input": { + "values": ["0x00", "0x01"] + }, + "output": { + "Ok": { + "values": ["0xff"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u8/sub.zok b/zokrates_core_test/tests/tests/uint/u8/sub.zok new file mode 100644 index 000000000..7e101a83e --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u8/sub.zok @@ -0,0 +1,2 @@ +def main(u8 a, u8 b) -> u8: + return a - b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/u8/xor.json b/zokrates_core_test/tests/tests/uint/u8/xor.json new file mode 100644 index 000000000..5a814ebec --- /dev/null +++ b/zokrates_core_test/tests/tests/uint/u8/xor.json @@ -0,0 +1,36 @@ +{ + "entry_point": "./tests/tests/uint/u8/xor.zok", + "max_constraint_count": 27, + "tests": [ + { + "input": { + "values": ["0xff", "0xff"] + }, + "output": { + "Ok": { + "values": ["0x00"] + } + } + }, + { + "input": { + "values": ["0xff", "0x00"] + }, + "output": { + "Ok": { + "values": ["0xff"] + } + } + }, + { + "input": { + "values": ["0x23", "0x34"] + }, + "output": { + "Ok": { + "values": ["0x17"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/xor.zok b/zokrates_core_test/tests/tests/uint/u8/xor.zok similarity index 63% rename from zokrates_core_test/tests/tests/uint/xor.zok rename to zokrates_core_test/tests/tests/uint/u8/xor.zok index e2b4ac523..445667a0f 100644 --- a/zokrates_core_test/tests/tests/uint/xor.zok +++ b/zokrates_core_test/tests/tests/uint/u8/xor.zok @@ -1,2 +1,2 @@ def main(u8 a, u8 b) -> u8: - return a ^ b \ No newline at end of file + return a ^ b \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/xor.json b/zokrates_core_test/tests/tests/uint/xor.json deleted file mode 100644 index b9b98ae0b..000000000 --- a/zokrates_core_test/tests/tests/uint/xor.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "entry_point": "./tests/tests/uint/xor.zok", - "max_constraint_count": 27, - "tests": [ - { - "input": { - "values": ["0xff", "0xff"] - }, - "output": { - "Ok": { - "values": ["0x00"] - } - } - }, - { - "input": { - "values": ["0xff", "0x00"] - }, - "output": { - "Ok": { - "values": ["0xff"] - } - } - }, - { - "input": { - "values": ["0x23", "0x34"] - }, - "output": { - "Ok": { - "values": ["0x17"] - } - } - } - ] -} \ No newline at end of file diff --git a/zokrates_embed/Cargo.toml b/zokrates_embed/Cargo.toml index 90e9cccb8..6135df315 100644 --- a/zokrates_embed/Cargo.toml +++ b/zokrates_embed/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zokrates_embed" -version = "0.1.1" +version = "0.1.2" authors = ["schaeff "] edition = "2018" diff --git a/zokrates_embed/src/lib.rs b/zokrates_embed/src/lib.rs index 8d6890553..b7a3e2d5c 100644 --- a/zokrates_embed/src/lib.rs +++ b/zokrates_embed/src/lib.rs @@ -12,13 +12,14 @@ use sapling_crypto::circuit::{ }; #[derive(Debug)] +#[allow(clippy::upper_case_acronyms)] pub struct BellmanR1CS { pub aux_count: usize, pub constraints: Vec>, } -impl BellmanR1CS { - pub fn new() -> Self { +impl Default for BellmanR1CS { + fn default() -> Self { BellmanR1CS { aux_count: 0, constraints: vec![], @@ -40,9 +41,9 @@ pub struct BellmanConstraint { fn sha256_round>( mut cs: CS, - input: &Vec>, - current_hash: &Vec>, -) -> Result<(Vec, Vec, Vec), SynthesisError> { + input: &[Option], + current_hash: &[Option], +) -> (Vec, Vec, Vec) { // Allocate bits for `input` let input_bits = input .iter() @@ -81,7 +82,7 @@ fn sha256_round>( .map(|chunk| { UInt32::from_bits_be( &chunk - .into_iter() + .iter() .map(|i| Boolean::Is(i.clone())) .collect::>(), ) @@ -95,11 +96,10 @@ fn sha256_round>( let output_bits = res .into_iter() .flat_map(|u| u.into_bits_be()) - .map(|b| b.get_variable().unwrap().clone()) - .collect::>(); + .map(|b| b.get_variable().unwrap().clone()); // Return indices of `input`, `current_hash` and `output` in the CS - Ok(( + ( input_bits .into_iter() .map(|b| var_to_index(b.get_variable())) @@ -109,10 +109,9 @@ fn sha256_round>( .map(|b| var_to_index(b.get_variable())) .collect(), output_bits - .into_iter() .map(|b| var_to_index(b.get_variable())) .collect(), - )) + ) } impl ConstraintSystem for BellmanWitness { @@ -206,17 +205,17 @@ impl ConstraintSystem for BellmanR1CS { let a = a .as_ref() - .into_iter() + .iter() .map(|(variable, coefficient)| (var_to_index(*variable), *coefficient)) .collect(); let b = b .as_ref() - .into_iter() + .iter() .map(|(variable, coefficient)| (var_to_index(*variable), *coefficient)) .collect(); let c = c .as_ref() - .into_iter() + .iter() .map(|(variable, coefficient)| (var_to_index(*variable), *coefficient)) .collect(); @@ -242,10 +241,10 @@ impl ConstraintSystem for BellmanR1CS { pub fn generate_sha256_round_constraints( ) -> (BellmanR1CS, Vec, Vec, Vec) { - let mut cs = BellmanR1CS::new(); + let mut cs = BellmanR1CS::default(); let (input_bits, current_hash_bits, output_bits) = - sha256_round(&mut cs, &vec![None; 512], &vec![None; 256]).unwrap(); + sha256_round(&mut cs, &[None; 512], &[None; 256]); // res is now the allocated bits for `input`, `current_hash` and `sha256_output` @@ -265,10 +264,9 @@ pub fn generate_sha256_round_witness( sha256_round( &mut cs, - &input.iter().map(|x| Some(x.clone())).collect(), - ¤t_hash.iter().map(|x| Some(x.clone())).collect(), - ) - .unwrap(); + &input.iter().map(|x| Some(*x)).collect::>(), + ¤t_hash.iter().map(|x| Some(*x)).collect::>(), + ); cs.values } @@ -311,8 +309,7 @@ mod tests { &mut cs, &vec![Some(Fr::zero()); 512], &vec![Some(Fr::one()); 256], - ) - .unwrap(); + ); assert!(cs.is_satisfied()); } diff --git a/zokrates_field/Cargo.toml b/zokrates_field/Cargo.toml index 87b956ae9..cea2f9ec8 100644 --- a/zokrates_field/Cargo.toml +++ b/zokrates_field/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zokrates_field" -version = "0.3.8" +version = "0.4.0" authors = ["Thibaut Schaeffer ", "Guillaume Ballet "] edition = "2018" @@ -23,11 +23,11 @@ num-integer = { version = "0.1", default-features = false } bellman_ce = { version = "^0.3", default-features = false, optional = true } # ark -ark-ff = { git = "https://github.com/arkworks-rs/algebra", default-features = false, optional = true } -ark-ec = { git = "https://github.com/arkworks-rs/algebra", default-features = false, optional = true } -ark-bn254 = { git = "https://github.com/arkworks-rs/curves", features = ["curve"], default-features = false, optional = true } -ark-bls12-377 = { git = "https://github.com/arkworks-rs/curves", features = ["curve"], default-features = false, optional = true } -ark-bw6-761 = { git = "https://github.com/arkworks-rs/curves", default-features = false, optional = true } +ark-ff = { version = "^0.2.0", default-features = false, optional = true } +ark-ec = { version = "^0.2.0", default-features = false, optional = true } +ark-bn254 = { version = "^0.2.0", features = ["curve"], default-features = false, optional = true } +ark-bls12-377 = { version = "^0.2.0", features = ["curve"], default-features = false, optional = true } +ark-bw6-761 = { version = "^0.2.0", default-features = false, optional = true } [dev-dependencies] rand = "0.4" diff --git a/zokrates_field/src/bn128.rs b/zokrates_field/src/bn128.rs index cecca7365..014a222c6 100644 --- a/zokrates_field/src/bn128.rs +++ b/zokrates_field/src/bn128.rs @@ -215,18 +215,6 @@ mod tests { assert_eq!(FieldPrime::from(-12), FieldPrime::from(-85) * res); } - #[test] - fn pow_small() { - assert_eq!( - "8".parse::().unwrap(), - (FieldPrime::from("2").pow(FieldPrime::from("3"))).value - ); - assert_eq!( - "8".parse::().unwrap(), - (FieldPrime::from("2").pow(&FieldPrime::from("3"))).value - ); - } - #[test] fn pow_usize() { assert_eq!( @@ -235,34 +223,6 @@ mod tests { ); } - #[test] - fn pow() { - assert_eq!( - "614787626176508399616".parse::().unwrap(), - (FieldPrime::from("54").pow(FieldPrime::from("12"))).value - ); - assert_eq!( - "614787626176508399616".parse::().unwrap(), - (FieldPrime::from("54").pow(&FieldPrime::from("12"))).value - ); - } - - #[test] - fn pow_negative() { - assert_eq!( - "21888242871839275222246405745257275088548364400416034343686819230535502784513" - .parse::() - .unwrap(), - (FieldPrime::from("-54").pow(FieldPrime::from("11"))).value - ); - assert_eq!( - "21888242871839275222246405745257275088548364400416034343686819230535502784513" - .parse::() - .unwrap(), - (FieldPrime::from("-54").pow(&FieldPrime::from("11"))).value - ); - } - #[test] fn serde_ser_deser() { let serialized = &serialize(&FieldPrime::from("11"), Infinite).unwrap(); @@ -280,7 +240,7 @@ mod tests { #[test] fn bytes_ser_deser() { let fp = FieldPrime::from("101"); - let bv = fp.into_byte_vector(); + let bv = fp.to_byte_vector(); assert_eq!(fp, FieldPrime::from_byte_vector(bv)); } diff --git a/zokrates_field/src/lib.rs b/zokrates_field/src/lib.rs index ae0bdaf6f..d4537e642 100644 --- a/zokrates_field/src/lib.rs +++ b/zokrates_field/src/lib.rs @@ -16,6 +16,7 @@ use num_bigint::BigUint; use num_traits::{CheckedDiv, One, Zero}; use serde::{Deserialize, Serialize}; use std::convert::{From, TryFrom}; +use std::fmt; use std::fmt::{Debug, Display}; use std::hash::Hash; use std::ops::{Add, Div, Mul, Sub}; @@ -44,6 +45,14 @@ pub trait ArkFieldExtensions { fn into_ark(self) -> ::Fr; } +pub struct FieldParseError; + +impl fmt::Debug for FieldParseError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Failed to parse to field element") + } +} + pub trait Field: From + From @@ -60,6 +69,8 @@ pub trait Field: + Ord + Display + Debug + + Default + + Hash + Add + for<'a> Add<&'a Self, Output = Self> + Sub @@ -68,16 +79,15 @@ pub trait Field: + for<'a> Mul<&'a Self, Output = Self> + CheckedDiv + Div + + for<'a> Div<&'a Self, Output = Self> + Pow - + Pow - + for<'a> Pow<&'a Self, Output = Self> + for<'a> Deserialize<'a> + Serialize + num_traits::CheckedAdd + num_traits::CheckedMul { /// Returns this `Field`'s contents as little-endian byte vector - fn into_byte_vector(&self) -> Vec; + fn to_byte_vector(&self) -> Vec; /// Returns an element of this `Field` from a little-endian byte vector fn from_byte_vector(_: Vec) -> Self; /// Returns this `Field`'s contents as decimal string @@ -94,8 +104,8 @@ pub trait Field: /// Returns the number of bits required to represent any element of this field type. fn get_required_bits() -> usize; /// Tries to parse a string into this representation - fn try_from_dec_str<'a>(s: &'a str) -> Result; - fn try_from_str(s: &str, radix: u32) -> Result; + fn try_from_dec_str(s: &str) -> Result; + fn try_from_str(s: &str, radix: u32) -> Result; /// Returns a decimal string representing a the member of the equivalence class of this `Field` in Z/pZ /// which lies in [-(p-1)/2, (p-1)/2] fn to_compact_dec_string(&self) -> String; @@ -114,7 +124,7 @@ pub trait Field: .collect() } - let field_bytes_le = Self::into_byte_vector(&Self::max_value()); + let field_bytes_le = Self::to_byte_vector(&Self::max_value()); // reverse for big-endianess let field_bytes_be = field_bytes_le.into_iter().rev().collect::>(); let field_bits_be = bytes_to_bits(&field_bytes_be); @@ -130,7 +140,7 @@ pub trait Field: mod prime_field { macro_rules! prime_field { ($modulus:expr, $name:expr) => { - use crate::{Field, Pow}; + use crate::{Field, FieldParseError, Pow}; use lazy_static::lazy_static; use num_bigint::{BigInt, BigUint, Sign, ToBigInt}; use num_integer::Integer; @@ -160,7 +170,7 @@ mod prime_field { self.value.to_biguint().unwrap() } - fn into_byte_vector(&self) -> Vec { + fn to_byte_vector(&self) -> Vec { match self.value.to_biguint() { Option::Some(val) => val.to_bytes_le(), Option::None => panic!("Should never happen."), @@ -208,11 +218,11 @@ mod prime_field { fn get_required_bits() -> usize { (*P).bits() } - fn try_from_dec_str<'a>(s: &'a str) -> Result { + fn try_from_dec_str(s: &str) -> Result { Self::try_from_str(s, 10) } - fn try_from_str(s: &str, radix: u32) -> Result { - let x = BigInt::parse_bytes(s.as_bytes(), radix).ok_or(())?; + fn try_from_str(s: &str, radix: u32) -> Result { + let x = BigInt::parse_bytes(s.as_bytes(), radix).ok_or(FieldParseError)?; Ok(FieldPrime { value: &x - x.div_floor(&*P) * &*P, }) @@ -337,6 +347,14 @@ mod prime_field { type Output = FieldPrime; fn add(self, other: FieldPrime) -> FieldPrime { + if self.value == BigInt::zero() { + return other; + } + + if other.value == BigInt::zero() { + return self; + } + FieldPrime { value: (self.value + other.value) % &*P, } @@ -347,8 +365,16 @@ mod prime_field { type Output = FieldPrime; fn add(self, other: &FieldPrime) -> FieldPrime { + if self.value == BigInt::zero() { + return other.clone(); + } + + if other.value == BigInt::zero() { + return self; + } + FieldPrime { - value: (self.value + other.value.clone()) % &*P, + value: (self.value + &other.value) % &*P, } } } @@ -368,7 +394,7 @@ mod prime_field { type Output = FieldPrime; fn sub(self, other: &FieldPrime) -> FieldPrime { - let x = self.value - other.value.clone(); + let x = self.value - &other.value; FieldPrime { value: &x - x.div_floor(&*P) * &*P, } @@ -379,6 +405,14 @@ mod prime_field { type Output = FieldPrime; fn mul(self, other: FieldPrime) -> FieldPrime { + if self.value == BigInt::one() { + return other; + } + + if other.value == BigInt::one() { + return self; + } + FieldPrime { value: (self.value * other.value) % &*P, } @@ -389,8 +423,16 @@ mod prime_field { type Output = FieldPrime; fn mul(self, other: &FieldPrime) -> FieldPrime { + if self.value == BigInt::one() { + return other.clone(); + } + + if other.value == BigInt::one() { + return self; + } + FieldPrime { - value: (self.value * other.value.clone()) % &*P, + value: (self.value * &other.value) % &*P, } } } @@ -429,38 +471,6 @@ mod prime_field { } } - impl Pow for FieldPrime { - type Output = FieldPrime; - - fn pow(self, exp: FieldPrime) -> FieldPrime { - let mut res = FieldPrime::one(); - let mut current = FieldPrime::zero(); - loop { - if current >= exp { - return res; - } - res = res * &self; - current = current + FieldPrime::one(); - } - } - } - - impl<'a> Pow<&'a FieldPrime> for FieldPrime { - type Output = FieldPrime; - - fn pow(self, exp: &'a FieldPrime) -> FieldPrime { - let mut res = FieldPrime::one(); - let mut current = FieldPrime::zero(); - loop { - if ¤t >= exp { - return res; - } - res = res * &self; - current = current + FieldPrime::one(); - } - } - } - impl num_traits::CheckedAdd for FieldPrime { fn checked_add(&self, other: &Self) -> Option { let bound = Self::max_unique_value(); @@ -468,7 +478,7 @@ mod prime_field { assert!(self <= &bound); assert!(other <= &bound); - let big_res = self.value.clone() + other.value.clone(); + let big_res = &self.value + &other.value; if big_res > bound.value { None @@ -485,7 +495,7 @@ mod prime_field { assert!(self <= &bound); assert!(other <= &bound); - let big_res = self.value.clone() * other.value.clone(); + let big_res = &self.value * &other.value; // we only go up to 2**(bitwidth - 1) because after that we lose uniqueness of bit decomposition if big_res > bound.value { diff --git a/zokrates_fs_resolver/src/lib.rs b/zokrates_fs_resolver/src/lib.rs index 9da6900e8..b38a0b17c 100644 --- a/zokrates_fs_resolver/src/lib.rs +++ b/zokrates_fs_resolver/src/lib.rs @@ -37,14 +37,12 @@ impl<'a> Resolver for FileSystemResolver<'a> { // other paths `abc/def` are interpreted relative to the standard library root path let base = match source.components().next() { Some(Component::CurDir) | Some(Component::ParentDir) => { - PathBuf::from(current_location).parent().unwrap().into() + current_location.parent().unwrap().into() } _ => PathBuf::from(self.stdlib_root_path.unwrap_or("")), }; - let path_owned = base - .join(PathBuf::from(import_location.clone())) - .with_extension("zok"); + let path_owned = base.join(import_location.clone()).with_extension("zok"); if !path_owned.is_file() { return Err(io::Error::new( @@ -96,7 +94,7 @@ mod tests { // create a source folder with a zok file let folder = tempfile::tempdir().unwrap(); let dir_path = folder.path().join("dir"); - std::fs::create_dir(dir_path.clone()).unwrap(); + std::fs::create_dir(dir_path).unwrap(); let fs_resolver = FileSystemResolver::default(); let res = fs_resolver.resolve(".".into(), "./dir/".into()); @@ -155,7 +153,7 @@ mod tests { let stdlib_root_path = temp_dir.path().to_owned(); let fs_resolver = FileSystemResolver::with_stdlib_root(stdlib_root_path.to_str().unwrap()); - let result = fs_resolver.resolve(file_path.clone(), "bar.zok".into()); + let result = fs_resolver.resolve(file_path, "bar.zok".into()); assert!(result.is_ok()); // the imported file should be the user's assert_eq!(result.unwrap().0, String::from("\n")); diff --git a/zokrates_js/Cargo.lock b/zokrates_js/Cargo.lock index 1ebfb22b6..3f705b4ff 100644 --- a/zokrates_js/Cargo.lock +++ b/zokrates_js/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "addr2line" version = "0.13.0" diff --git a/zokrates_js/Cargo.toml b/zokrates_js/Cargo.toml index 8add49d4e..bb2585a7d 100644 --- a/zokrates_js/Cargo.toml +++ b/zokrates_js/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zokrates_js" -version = "1.0.28" +version = "1.0.29" authors = ["Darko Macesic"] edition = "2018" diff --git a/zokrates_js/package.json b/zokrates_js/package.json index 6765f16f8..294ccf46a 100644 --- a/zokrates_js/package.json +++ b/zokrates_js/package.json @@ -2,7 +2,7 @@ "name": "zokrates-js", "main": "index.js", "author": "Darko Macesic ", - "version": "1.0.28", + "version": "1.0.29", "keywords": [ "zokrates", "wasm-bindgen", diff --git a/zokrates_js/src/lib.rs b/zokrates_js/src/lib.rs index 41af7fddd..cac9fcc47 100644 --- a/zokrates_js/src/lib.rs +++ b/zokrates_js/src/lib.rs @@ -14,7 +14,7 @@ use zokrates_core::proof_system::bellman::Bellman; use zokrates_core::proof_system::groth16::G16; use zokrates_core::proof_system::{Backend, Proof, Scheme, SolidityAbi, SolidityCompatibleScheme}; use zokrates_core::typed_absy::abi::Abi; -use zokrates_core::typed_absy::types::Signature; +use zokrates_core::typed_absy::types::ConcreteSignature as Signature; use zokrates_field::Bn128Field; #[derive(Serialize, Deserialize)] @@ -144,7 +144,8 @@ pub fn compute_witness(program: &[u8], abi: JsValue, args: JsValue) -> Result"] edition = "2018" @@ -9,4 +9,4 @@ pest = "2.0" pest_derive = "2.0" [dev-dependencies] -glob = "0.2" \ No newline at end of file +glob = "0.2" diff --git a/zokrates_parser/src/ace_mode/index.js b/zokrates_parser/src/ace_mode/index.js index a535a1fed..7855ab53b 100644 --- a/zokrates_parser/src/ace_mode/index.js +++ b/zokrates_parser/src/ace_mode/index.js @@ -37,7 +37,7 @@ ace.define("ace/mode/zokrates_highlight_rules",["require","exports","module","ac var ZoKratesHighlightRules = function () { var keywords = ( - "assert|as|bool|byte|def|do|else|endfor|export|false|field|for|if|then|fi|import|from|in|private|public|return|struct|true|u8|u16|u32" + "assert|as|bool|byte|def|do|else|endfor|export|false|field|for|if|then|fi|import|from|in|private|public|return|struct|true|u8|u16|u32|u64" ); var keywordMapper = this.createKeywordMapper({ diff --git a/zokrates_parser/src/lib.rs b/zokrates_parser/src/lib.rs index 82d205ec7..277c611f0 100644 --- a/zokrates_parser/src/lib.rs +++ b/zokrates_parser/src/lib.rs @@ -1,3 +1,5 @@ +#![allow(clippy::upper_case_acronyms)] // we allow uppercase acronyms because the pest derive generates WHITESPACE and COMMENT which have special meaning in pest + extern crate pest; #[macro_use] extern crate pest_derive; @@ -53,6 +55,9 @@ mod tests { mod rules { use super::*; + + // TODO: uncomment these tests once https://github.com/pest-parser/pest/pull/493 is resolved + // #[test] // fn parse_valid_identifier() { // parses_to! { @@ -69,39 +74,54 @@ mod tests { // fn parse_parameter_list() { // parses_to! { // parser: ZoKratesParser, - // input: "def foo(field a) -> (field, field): return 1 + // input: "def foo(field[P] a) -> (field, field): return 1 // ", // rule: Rule::function_definition, // tokens: [ - // function_definition(0, 45, [ + // function_definition(0, 54, [ // identifier(4, 7), + // identifier(8, 9), + // identifier(11, 12), // // parameter_list is not created (silent rule) - // parameter(8, 15, [ - // ty(8, 13, [ - // ty_basic(8, 13, [ - // ty_field(8, 13) + // parameter(14, 24, [ + // ty(14, 23, [ + // ty_array(14, 23, [ + // ty_basic_or_struct(14, 19, [ + // ty_basic(14, 19, [ + // ty_field(14, 19) + // ]) + // ]), + // expression(20, 21, [ + // term(20, 21, [ + // primary_expression(20, 21, [ + // identifier(20, 21) + // ]) + // ]) + // ]) // ]) // ]), - // identifier(14, 15) + // identifier(23, 24) // ]), // // type_list is not created (silent rule) - // ty(21, 26, [ - // ty_basic(21, 26, [ - // ty_field(21, 26) + // ty(30, 35, [ + // ty_basic(30, 35, [ + // ty_field(30, 35) // ]) // ]), - // ty(28, 33, [ - // ty_basic(28, 33, [ - // ty_field(28, 33) + // ty(37, 42, [ + // ty_basic(37, 42, [ + // ty_field(37, 42) // ]) // ]), - // statement(36, 45, [ - // return_statement(36, 44, [ - // expression(43, 44, [ - // term(43, 44, [ - // primary_expression(43, 44, [ - // constant(43, 44, [ - // decimal_number(43, 44) + // statement(45, 54, [ + // return_statement(45, 53, [ + // expression(52, 53, [ + // term(52, 53, [ + // primary_expression(52, 53, [ + // literal(52, 53, [ + // decimal_literal(52, 53, [ + // decimal_number(52, 53) + // ]) // ]) // ]) // ]) @@ -117,23 +137,38 @@ mod tests { // fn parse_single_def_to_multi() { // parses_to! { // parser: ZoKratesParser, - // input: r#"a = foo() + // input: r#"a = foo::<_>(x) // "#, // rule: Rule::statement, // tokens: [ - // statement(0, 22, [ - // definition_statement(0, 9, [ + // statement(0, 28, [ + // definition_statement(0, 15, [ // optionally_typed_assignee(0, 2, [ // assignee(0, 2, [ // identifier(0, 1) // ]) // ]), - // expression(4, 9, [ - // term(4, 9, [ - // postfix_expression(4, 9, [ + // expression(4, 15, [ + // term(4, 15, [ + // postfix_expression(4, 15, [ // identifier(4, 7), - // access(7, 9, [ - // call_access(7, 9) + // access(7, 15, [ + // call_access(7, 15, [ + // explicit_generics(7, 12, [ + // constant_generics_value(10, 11, [ + // underscore(10, 11) + // ]) + // ]), + // arguments(13, 14, [ + // expression(13, 14, [ + // term(13, 14, [ + // primary_expression(13, 14, [ + // identifier(13, 14) + // ]) + // ]) + // ]) + // ]) + // ]) // ]) // ]) // ]) @@ -169,7 +204,9 @@ mod tests { // postfix_expression(10, 15, [ // identifier(10, 13), // access(13, 15, [ - // call_access(13, 15) + // call_access(13, 15, [ + // arguments(14, 14) + // ]) // ]) // ]) // ]) @@ -205,7 +242,9 @@ mod tests { // postfix_expression(8, 13, [ // identifier(8, 11), // access(11, 13, [ - // call_access(11, 13) + // call_access(11, 13, [ + // arguments(12, 12) + // ]) // ]) // ]) // ]) @@ -257,8 +296,10 @@ mod tests { // expression(30, 31, [ // term(30, 31, [ // primary_expression(30, 31, [ - // constant(30, 31, [ - // decimal_number(30, 31) + // literal(30, 31, [ + // decimal_literal(30, 31, [ + // decimal_number(30, 31) + // ]) // ]) // ]) // ]) diff --git a/zokrates_parser/src/textmate/.vscodeignore b/zokrates_parser/src/textmate/.vscodeignore new file mode 100644 index 000000000..f369b5e55 --- /dev/null +++ b/zokrates_parser/src/textmate/.vscodeignore @@ -0,0 +1,4 @@ +.vscode/** +.vscode-test/** +.gitignore +vsc-extension-quickstart.md diff --git a/zokrates_parser/src/textmate/CHANGELOG.md b/zokrates_parser/src/textmate/CHANGELOG.md new file mode 100644 index 000000000..acd435404 --- /dev/null +++ b/zokrates_parser/src/textmate/CHANGELOG.md @@ -0,0 +1,3 @@ +## [0.0.1] - 2021-03-01 + +- Initial release \ No newline at end of file diff --git a/zokrates_parser/src/textmate/README.md b/zokrates_parser/src/textmate/README.md new file mode 100644 index 000000000..15f478b0c --- /dev/null +++ b/zokrates_parser/src/textmate/README.md @@ -0,0 +1,13 @@ +# ZoKrates Syntax Highlighter + +This is a Textmate-based syntax highlighter for the [ZoKrates language](https://zokrates.github.io) in VSCode. + +## Development + +This project expect the syntax to be provided as a JSON file (see `syntaxes`). +As working with a YAML file instead is easier, it can make sense to convert to that and back. +VSCode offers a command `Convert to {JSON, YAML}-tmLanguage File` that achieves that. + +## Release process + +This extension is currently released manually to the VSCode extension marketplace. \ No newline at end of file diff --git a/zokrates_parser/src/textmate/language-configuration.json b/zokrates_parser/src/textmate/language-configuration.json new file mode 100644 index 000000000..bdf838281 --- /dev/null +++ b/zokrates_parser/src/textmate/language-configuration.json @@ -0,0 +1,28 @@ +{ + "comments": { + // symbol used for single line comment. Remove this entry if your language does not support line comments + "lineComment": "//", + // symbols used for start and end a block comment. Remove this entry if your language does not support block comments + "blockComment": [ "/*", "*/" ] + }, + // symbols used as brackets + "brackets": [ + ["{", "}"], + ["[", "]"], + ["(", ")"] + ], + // symbols that are auto closed when typing + "autoClosingPairs": [ + ["{", "}"], + ["[", "]"], + ["(", ")"], + ["\"", "\""], + ], + // symbols that can be used to surround a selection + "surroundingPairs": [ + ["{", "}"], + ["[", "]"], + ["(", ")"], + ["\"", "\""], + ] +} \ No newline at end of file diff --git a/zokrates_parser/src/textmate/package.json b/zokrates_parser/src/textmate/package.json new file mode 100644 index 000000000..ebacd5de6 --- /dev/null +++ b/zokrates_parser/src/textmate/package.json @@ -0,0 +1,27 @@ +{ + "name": "zokrates", + "displayName": "zokrates", + "description": "Syntax highlighting for the ZoKrates language", + "publisher": "zokrates", + "repository": "https://github.com/ZoKrates/ZoKrates", + "version": "0.0.1", + "engines": { + "vscode": "^1.53.0" + }, + "categories": [ + "Programming Languages" + ], + "contributes": { + "languages": [{ + "id": "zokrates", + "aliases": ["ZoKrates", "zokrates"], + "extensions": [".zok"], + "configuration": "./language-configuration.json" + }], + "grammars": [{ + "language": "zokrates", + "scopeName": "source.zok", + "path": "./syntaxes/zokrates.tmLanguage.json" + }] + } +} \ No newline at end of file diff --git a/zokrates_parser/src/textmate/syntaxes/zokrates.tmLanguage.json b/zokrates_parser/src/textmate/syntaxes/zokrates.tmLanguage.json new file mode 100644 index 000000000..3730240c1 --- /dev/null +++ b/zokrates_parser/src/textmate/syntaxes/zokrates.tmLanguage.json @@ -0,0 +1,600 @@ +{ + "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", + "name": "ZoKrates", + "fileTypes": [ + "zok" + ], + "scopeName": "source.zok", + "patterns": [ + { + "comment": "attributes", + "name": "meta.attribute.zokrates", + "begin": "(#)(\\!?)(\\[)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.attribute.zokrates" + }, + "2": { + "name": "keyword.operator.attribute.inner.zokrates" + }, + "3": { + "name": "punctuation.brackets.attribute.zokrates" + } + }, + "end": "\\]", + "endCaptures": { + "0": { + "name": "punctuation.brackets.attribute.zokrates" + } + }, + "patterns": [ + { + "include": "#block-comments" + }, + { + "include": "#comments" + }, + { + "include": "#keywords" + }, + { + "include": "#lifetimes" + }, + { + "include": "#punctuation" + }, + { + "include": "#strings" + }, + { + "include": "#gtypes" + }, + { + "include": "#types" + } + ] + }, + { + "include": "#block-comments" + }, + { + "include": "#comments" + }, + { + "include": "#constants" + }, + { + "include": "#functions" + }, + { + "include": "#types" + }, + { + "include": "#keywords" + }, + { + "include": "#punctuation" + }, + { + "include": "#strings" + }, + { + "include": "#variables" + } + ], + "repository": { + "comments": { + "patterns": [ + { + "comment": "line comments", + "name": "comment.line.double-slash.zokrates", + "match": "\\s*//.*" + } + ] + }, + "block-comments": { + "patterns": [ + { + "comment": "empty block comments", + "name": "comment.block.zokrates", + "match": "/\\*\\*/" + }, + { + "comment": "block comments", + "name": "comment.block.zokrates", + "begin": "/\\*(?!\\*)", + "end": "\\*/", + "patterns": [ + { + "include": "#block-comments" + } + ] + } + ] + }, + "constants": { + "patterns": [ + { + "comment": "ALL CAPS constants", + "name": "constant.other.caps.zokrates", + "match": "\\b[A-Z]{2}[A-Z0-9_]*\\b" + }, + { + "comment": "decimal integers and floats", + "name": "constant.numeric.decimal.zokrates", + "match": "\\b\\d[\\d_]*(u128|u16|u32|u64|u8|f)?\\b", + "captures": { + "5": { + "name": "entity.name.type.numeric.zokrates" + } + } + }, + { + "comment": "hexadecimal integers", + "name": "constant.numeric.hex.zokrates", + "match": "\\b0x[\\da-fA-F_]+\\b" + }, + { + "comment": "booleans", + "name": "constant.language.bool.zokrates", + "match": "\\b(true|false)\\b" + } + ] + }, + "imports": { + "patterns": [ + { + "comment": "explicit import statement", + "name": "meta.import.explicit.zokrates", + "match": "\\b(from)\\s+(\\\".*\\\")(import)\\s+([A-Za-z0-9_]+)\\s+((as)\\s+[A-Za-z0-9_]+)?\\b", + "patterns": [ + { + "include": "#block-comments" + }, + { + "include": "#comments" + }, + { + "include": "#keywords" + }, + { + "include": "#punctuation" + }, + { + "include": "#types" + }, + { + "include": "#strings" + } + ] + }, + { + "comment": "main import statement", + "name": "meta.import.explicit.zokrates", + "match": "\\b(import)\\s+(\\\".*\\\")\\s+((as)\\s+[A-Za-z0-9_]+)?\\b", + "patterns": [ + { + "include": "#block-comments" + }, + { + "include": "#comments" + }, + { + "include": "#keywords" + }, + { + "include": "#punctuation" + }, + { + "include": "#types" + }, + { + "include": "#strings" + } + ] + } + ] + }, + "functions": { + "patterns": [ + { + "comment": "function definition", + "name": "meta.function.definition.zokrates", + "begin": "\\b(def)\\s+([A-Za-z0-9_]+)((\\()|(<))", + "beginCaptures": { + "1": { + "name": "keyword.other.def.zokrates" + }, + "2": { + "name": "entity.name.function.zokrates" + }, + "4": { + "name": "punctuation.brackets.round.zokrates" + }, + "5": { + "name": "punctuation.brackets.angle.zokrates" + } + }, + "end": "\\:|;", + "endCaptures": { + "0": { + "name": "keyword.punctuation.colon.zokrates" + } + }, + "patterns": [ + { + "include": "#block-comments" + }, + { + "include": "#comments" + }, + { + "include": "#keywords" + }, + { + "include": "#constants" + }, + { + "include": "#functions" + }, + { + "include": "#punctuation" + }, + { + "include": "#strings" + }, + { + "include": "#types" + }, + { + "include": "#variables" + } + ] + }, + { + "comment": "function/method calls, chaining", + "name": "meta.function.call.zokrates", + "begin": "([A-Za-z0-9_]+)(\\()", + "beginCaptures": { + "1": { + "name": "entity.name.function.zokrates" + }, + "2": { + "name": "punctuation.brackets.round.zokrates" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.brackets.round.zokrates" + } + }, + "patterns": [ + { + "include": "#block-comments" + }, + { + "include": "#comments" + }, + { + "include": "#keywords" + }, + { + "include": "#constants" + }, + { + "include": "#functions" + }, + { + "include": "#punctuation" + }, + { + "include": "#strings" + }, + { + "include": "#types" + }, + { + "include": "#variables" + } + ] + }, + { + "comment": "function/method calls with turbofish", + "name": "meta.function.call.zokrates", + "begin": "([A-Za-z0-9_]+)(?=::<.*>\\()", + "beginCaptures": { + "1": { + "name": "entity.name.function.zokrates" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.brackets.round.zokrates" + } + }, + "patterns": [ + { + "include": "#block-comments" + }, + { + "include": "#comments" + }, + { + "include": "#keywords" + }, + { + "include": "#constants" + }, + { + "include": "#functions" + }, + { + "include": "#punctuation" + }, + { + "include": "#strings" + }, + { + "include": "#types" + }, + { + "include": "#variables" + } + ] + } + ] + }, + "keywords": { + "patterns": [ + { + "comment": "argument visibility", + "name": "keyword.visibility.zokrates", + "match": "\\b(public|private)\\b" + }, + { + "comment": "control flow keywords", + "name": "keyword.control.zokrates", + "match": "\\b(do|else|for|do|endfor|if|then|fi|return|assert)\\b" + }, + { + "comment": "storage keywords", + "name": "storage.type.zokrates", + "match": "\\b(struct)\\b" + }, + { + "comment": "def", + "name": "keyword.other.def.zokrates", + "match": "\\bdef\\b" + }, + { + "comment": "import keywords", + "name": "keyword.other.import.zokrates", + "match": "\\b(import|from|as)\\b" + }, + { + "comment": "logical operators", + "name": "keyword.operator.logical.zokrates", + "match": "(\\^|\\||\\|\\||&|&&|<<|>>|!)(?!=)" + }, + { + "comment": "single equal", + "name": "keyword.operator.assignment.equal.zokrates", + "match": "(?])=(?!=|>)" + }, + { + "comment": "comparison operators", + "name": "keyword.operator.comparison.zokrates", + "match": "(=(=)?(?!>)|!=|<=|(?=)" + }, + { + "comment": "math operators", + "name": "keyword.operator.math.zokrates", + "match": "(([+%]|(\\*(?!\\w)))(?!=))|(-(?!>))|(/(?!/))" + }, + { + "comment": "less than, greater than (special case)", + "match": "(?:\\b|(?:(\\))|(\\])|(\\})))[ \\t]+([<>])[ \\t]+(?:\\b|(?:(\\()|(\\[)|(\\{)))", + "captures": { + "1": { + "name": "punctuation.brackets.round.zokrates" + }, + "2": { + "name": "punctuation.brackets.square.zokrates" + }, + "3": { + "name": "punctuation.brackets.curly.zokrates" + }, + "4": { + "name": "keyword.operator.comparison.zokrates" + }, + "5": { + "name": "punctuation.brackets.round.zokrates" + }, + "6": { + "name": "punctuation.brackets.square.zokrates" + }, + "7": { + "name": "punctuation.brackets.curly.zokrates" + } + } + }, + { + "comment": "dot access", + "name": "keyword.operator.access.dot.zokrates", + "match": "\\.(?!\\.)" + }, + { + "comment": "ranges, range patterns", + "name": "keyword.operator.range.zokrates", + "match": "\\.{2}(=|\\.)?" + }, + { + "comment": "colon", + "name": "keyword.operator.colon.zokrates", + "match": ":(?!:)" + }, + { + "comment": "dashrocket, skinny arrow", + "name": "keyword.operator.arrow.skinny.zokrates", + "match": "->" + } + ] + }, + "types": { + "patterns": [ + { + "comment": "numeric types", + "match": "(?", + "endCaptures": { + "0": { + "name": "punctuation.brackets.angle.zokrates" + } + }, + "patterns": [ + { + "include": "#block-comments" + }, + { + "include": "#comments" + }, + { + "include": "#keywords" + }, + { + "include": "#punctuation" + }, + { + "include": "#types" + }, + { + "include": "#variables" + } + ] + }, + { + "comment": "primitive types", + "name": "entity.name.type.primitive.zokrates", + "match": "\\b(bool)\\b" + }, + { + "comment": "struct declarations", + "match": "\\b(struct)\\s+([A-Z][A-Za-z0-9]*)\\b", + "captures": { + "1": { + "name": "storage.type.zokrates" + }, + "2": { + "name": "entity.name.type.struct.zokrates" + } + } + }, + { + "comment": "types", + "name": "entity.name.type.zokrates", + "match": "\\b[A-Z][A-Za-z0-9]*\\b(?!!)" + } + ] + }, + "punctuation": { + "patterns": [ + { + "comment": "comma", + "name": "punctuation.comma.zokrates", + "match": "," + }, + { + "comment": "parentheses, round brackets", + "name": "punctuation.brackets.round.zokrates", + "match": "[()]" + }, + { + "comment": "square brackets", + "name": "punctuation.brackets.square.zokrates", + "match": "[\\[\\]]" + }, + { + "comment": "angle brackets", + "name": "punctuation.brackets.angle.zokrates", + "match": "(?]" + } + ] + }, + "strings": { + "patterns": [ + { + "comment": "double-quoted strings and byte strings", + "name": "string.quoted.double.zokrates", + "begin": "(b?)(\")", + "beginCaptures": { + "1": { + "name": "string.quoted.byte.raw.zokrates" + }, + "2": { + "name": "punctuation.definition.string.zokrates" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.zokrates" + } + } + }, + { + "comment": "double-quoted raw strings and raw byte strings", + "name": "string.quoted.double.zokrates", + "begin": "(b?r)(#*)(\")", + "beginCaptures": { + "1": { + "name": "string.quoted.byte.raw.zokrates" + }, + "2": { + "name": "punctuation.definition.string.raw.zokrates" + }, + "3": { + "name": "punctuation.definition.string.zokrates" + } + }, + "end": "(\")(\\2)", + "endCaptures": { + "1": { + "name": "punctuation.definition.string.zokrates" + }, + "2": { + "name": "punctuation.definition.string.raw.zokrates" + } + } + } + ] + }, + "variables": { + "patterns": [ + { + "comment": "variables", + "name": "variable.other.zokrates", + "match": "\\b(?" ~ ( "(" ~ type_list ~ ")" | ty ))? } +constant_generics_declaration = _{ "<" ~ constant_generics_list ~ ">" } +constant_generics_list = _{ identifier ~ ("," ~ identifier)* } parameter_list = _{(parameter ~ ("," ~ parameter)*)?} parameter = {vis? ~ ty ~ identifier} @@ -18,9 +20,10 @@ parameter = {vis? ~ ty ~ identifier} ty_field = {"field"} ty_bool = {"bool"} ty_u8 = {"u8"} -ty_u32 = {"u32"} ty_u16 = {"u16"} -ty_basic = { ty_field | ty_bool | ty_u8 | ty_u16 | ty_u32 } +ty_u32 = {"u32"} +ty_u64 = {"u64"} +ty_basic = { ty_field | ty_bool | ty_u8 | ty_u16 | ty_u32 | ty_u64 } ty_basic_or_struct = { ty_basic | ty_struct } ty_array = { ty_basic_or_struct ~ ("[" ~ expression ~ "]")+ } ty = { ty_array | ty_basic | ty_struct } @@ -55,8 +58,10 @@ optionally_typed_assignee = { (ty ~ assignee) | (assignee) } // we don't use { t // Expressions expression_list = _{(expression ~ ("," ~ expression)*)?} -expression = { term ~ (op_binary ~ term)* } -term = { ("(" ~ expression ~ ")") | inline_struct_expression | conditional_expression | postfix_expression | primary_expression | inline_array_expression | array_initializer_expression | unary_expression } +expression = { unaried_term ~ (op_binary ~ unaried_term)* } +unaried_term = { op_unary? ~ powered_term } +powered_term = { term ~ (op_pow ~ exponent_expression)? } +term = { ("(" ~ expression ~ ")") | inline_struct_expression | conditional_expression | postfix_expression | primary_expression | inline_array_expression | array_initializer_expression } spread = { "..." ~ expression } range = { from_expression? ~ ".." ~ to_expression? } from_expression = { expression } @@ -64,14 +69,19 @@ to_expression = { expression } conditional_expression = { "if" ~ expression ~ "then" ~ expression ~ "else" ~ expression ~ "fi"} -postfix_expression = { identifier ~ access+ } // we force there to be at least one access, otherwise this matches single identifiers. Not sure that's what we want. +postfix_expression = { identifier ~ access+ } // we force there to be at least one access, otherwise this matches single identifiers access = { array_access | call_access | member_access } array_access = { "[" ~ range_or_expression ~ "]" } -call_access = { "(" ~ expression_list ~ ")" } +call_access = { explicit_generics? ~ "(" ~ arguments ~ ")" } +arguments = { expression_list } +explicit_generics = { "::<" ~ constant_generics_values ~ ">" } +constant_generics_values = _{ constant_generics_value ~ ("," ~ constant_generics_value)* } +constant_generics_value = { literal | identifier | underscore } +underscore = { "_" } member_access = { "." ~ identifier } primary_expression = { identifier - | constant + | literal } inline_struct_expression = { identifier ~ "{" ~ NEWLINE* ~ inline_struct_member_list ~ NEWLINE* ~ "}" } @@ -82,22 +92,39 @@ inline_array_expression = { "[" ~ NEWLINE* ~ inline_array_inner ~ NEWLINE* ~ "]" inline_array_inner = _{(spread_or_expression ~ ("," ~ NEWLINE* ~ spread_or_expression)*)?} spread_or_expression = { spread | expression } range_or_expression = { range | expression } -array_initializer_expression = { "[" ~ expression ~ ";" ~ constant ~ "]" } -unary_expression = { op_unary ~ term } +exponent_expression = { "(" ~ expression ~ ")" | primary_expression } +array_initializer_expression = { "[" ~ expression ~ ";" ~ expression ~ "]" } // End Expressions assignee = { identifier ~ assignee_access* } assignee_access = { array_access | member_access } identifier = @{ ((!keyword ~ ASCII_ALPHA) | (keyword ~ (ASCII_ALPHANUMERIC | "_"))) ~ (ASCII_ALPHANUMERIC | "_")* } -constant = { hex_number | decimal_number | boolean_literal } + +// Literals for all types + +literal = { hex_literal | decimal_literal | boolean_literal } + +decimal_literal = ${ decimal_number ~ decimal_suffix? } decimal_number = @{ "0" | ASCII_NONZERO_DIGIT ~ ASCII_DIGIT* } +decimal_suffix = { decimal_suffix_u8 | decimal_suffix_u16 | decimal_suffix_u32 | decimal_suffix_u64 | decimal_suffix_field } +decimal_suffix_u8 = { "u8" } +decimal_suffix_u16 = { "u16" } +decimal_suffix_u32 = { "u32" } +decimal_suffix_u64 = { "u64" } +decimal_suffix_field = { "f" } + boolean_literal = { "true" | "false" } -hex_number = _{ hex_number_32 | hex_number_16 | hex_number_8 } -hex_number_8 = @{ "0x" ~ ASCII_HEX_DIGIT{2} } -hex_number_16 = @{ "0x" ~ ASCII_HEX_DIGIT{4} } -hex_number_32 = @{ "0x" ~ ASCII_HEX_DIGIT{8} } + +hex_literal = !{ "0x" ~ hex_number } +hex_number = { hex_number_u64 | hex_number_u32 | hex_number_u16 | hex_number_u8 } +hex_number_u8 = { ASCII_HEX_DIGIT{2} } +hex_number_u16 = { ASCII_HEX_DIGIT{4} } +hex_number_u32 = { ASCII_HEX_DIGIT{8} } +hex_number_u64 = { ASCII_HEX_DIGIT{16} } + +// Operators op_or = @{"||"} op_and = @{"&&"} @@ -115,13 +142,15 @@ op_sub = {"-"} op_mul = {"*"} op_div = {"/"} op_rem = {"%"} -op_pow = @{"**"} +op_pow = @{"**"} op_not = {"!"} +op_neg = {"-"} +op_pos = {"+"} op_left_shift = @{"<<"} op_right_shift = @{">>"} -op_binary = _ { op_pow | op_or | op_and | op_bit_xor | op_bit_and | op_bit_or | op_left_shift | op_right_shift | op_equal | op_not_equal | op_lte | op_lt | op_gte | op_gt | op_add | op_sub | op_mul | op_div | op_rem } -op_unary = { op_not } - +// `op_pow` is *not* in `op_binary` because its precedence is handled in this parser rather than down the line in precedence climbing +op_binary = _ { op_or | op_and | op_bit_xor | op_bit_and | op_bit_or | op_left_shift | op_right_shift | op_equal | op_not_equal | op_lte | op_lt | op_gte | op_gt | op_add | op_sub | op_mul | op_div | op_rem } +op_unary = { op_pos | op_neg | op_not } WHITESPACE = _{ " " | "\t" | "\\" ~ NEWLINE} COMMENT = _{ ("/*" ~ (!"*/" ~ ANY)* ~ "*/") | ("//" ~ (!NEWLINE ~ ANY)*) } @@ -129,5 +158,5 @@ COMMENT = _{ ("/*" ~ (!"*/" ~ ANY)* ~ "*/") | ("//" ~ (!NEWLINE ~ ANY)*) } // the ordering of reserved keywords matters: if "as" is before "assert", then "assert" gets parsed as (as)(sert) and incorrectly // accepted keyword = @{"assert"|"as"|"bool"|"byte"|"def"|"do"|"else"|"endfor"|"export"|"false"|"field"|"for"|"if"|"then"|"fi"|"import"|"from"| - "in"|"private"|"public"|"return"|"struct"|"true"|"u8"|"u16"|"u32" + "in"|"private"|"public"|"return"|"struct"|"true"|"u8"|"u16"|"u32"|"u64" } diff --git a/zokrates_pest_ast/Cargo.toml b/zokrates_pest_ast/Cargo.toml index d9f2dddd1..3cbe56e70 100644 --- a/zokrates_pest_ast/Cargo.toml +++ b/zokrates_pest_ast/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "zokrates_pest_ast" -version = "0.1.5" +version = "0.2.0" authors = ["schaeff "] edition = "2018" [dependencies] -zokrates_parser = { version = "0.1.0", path = "../zokrates_parser" } +zokrates_parser = { version = "0.2.0", path = "../zokrates_parser" } pest = "2.0" pest-ast = "0.3.3" from-pest = "0.3.1" diff --git a/zokrates_pest_ast/src/lib.rs b/zokrates_pest_ast/src/lib.rs index 4ba8e2991..3f1ea138d 100644 --- a/zokrates_pest_ast/src/lib.rs +++ b/zokrates_pest_ast/src/lib.rs @@ -8,14 +8,16 @@ use zokrates_parser::Rule; extern crate lazy_static; pub use ast::{ - Access, ArrayAccess, ArrayInitializerExpression, ArrayType, AssertionStatement, Assignee, - AssigneeAccess, BasicOrStructType, BasicType, BinaryExpression, BinaryOperator, CallAccess, - ConstantExpression, DecimalNumberExpression, DefinitionStatement, Expression, FieldType, File, - FromExpression, Function, IdentifierExpression, ImportDirective, ImportSource, + Access, Arguments, ArrayAccess, ArrayInitializerExpression, ArrayType, AssertionStatement, + Assignee, AssigneeAccess, BasicOrStructType, BasicType, BinaryExpression, BinaryOperator, + CallAccess, ConstantGenericValue, DecimalLiteralExpression, DecimalNumber, DecimalSuffix, + DefinitionStatement, ExplicitGenerics, Expression, FieldType, File, FromExpression, Function, + HexLiteralExpression, HexNumberExpression, IdentifierExpression, ImportDirective, ImportSource, InlineArrayExpression, InlineStructExpression, InlineStructMember, IterationStatement, - OptionallyTypedAssignee, Parameter, PostfixExpression, Range, RangeOrExpression, - ReturnStatement, Span, Spread, SpreadOrExpression, Statement, StructDefinition, StructField, - TernaryExpression, ToExpression, Type, UnaryExpression, UnaryOperator, Visibility, + LiteralExpression, OptionallyTypedAssignee, Parameter, PostfixExpression, Range, + RangeOrExpression, ReturnStatement, Span, Spread, SpreadOrExpression, Statement, + StructDefinition, StructField, TernaryExpression, ToExpression, Type, UnaryExpression, + UnaryOperator, Underscore, Visibility, }; mod ast { @@ -52,7 +54,6 @@ mod ast { Operator::new(Rule::op_mul, Assoc::Left) | Operator::new(Rule::op_div, Assoc::Left) | Operator::new(Rule::op_rem, Assoc::Left), - Operator::new(Rule::op_pow, Assoc::Left), ]) } @@ -74,7 +75,6 @@ mod ast { Rule::op_mul => Expression::binary(BinaryOperator::Mul, lhs, rhs, span), Rule::op_div => Expression::binary(BinaryOperator::Div, lhs, rhs, span), Rule::op_rem => Expression::binary(BinaryOperator::Rem, lhs, rhs, span), - Rule::op_pow => Expression::binary(BinaryOperator::Pow, lhs, rhs, span), Rule::op_equal => Expression::binary(BinaryOperator::Eq, lhs, rhs, span), Rule::op_not_equal => Expression::binary(BinaryOperator::NotEq, lhs, rhs, span), Rule::op_lte => Expression::binary(BinaryOperator::Lte, lhs, rhs, span), @@ -97,74 +97,12 @@ mod ast { PREC_CLIMBER.climb(pair.into_inner(), build_factor, infix_rule) } - // Create an Expression from a `term`. - // Precondition: `pair` MUST be a term + // Create an Expression from a `unaried_term`. + // Precondition: `pair` MUST be a `unaried_term` fn build_factor(pair: Pair) -> Box { - Box::new(match pair.as_rule() { - Rule::term => { - // clone the pair to peek into what we should create - let clone = pair.clone(); - // define the child pair - let next = clone.into_inner().next().unwrap(); - match next.as_rule() { - // this happens when we have an expression in parentheses: it needs to be processed as another sequence of terms and operators - Rule::expression => Expression::from_pest(&mut pair.into_inner()).unwrap(), - Rule::conditional_expression => Expression::Ternary( - TernaryExpression::from_pest(&mut pair.into_inner()).unwrap(), - ), - Rule::primary_expression => { - // maybe this could be simplified - let next = next.into_inner().next().unwrap(); - match next.as_rule() { - Rule::constant => Expression::Constant( - ConstantExpression::from_pest( - &mut pair.into_inner().next().unwrap().into_inner(), - ) - .unwrap(), - ), - Rule::identifier => Expression::Identifier( - IdentifierExpression::from_pest( - &mut pair.into_inner().next().unwrap().into_inner(), - ) - .unwrap(), - ), - r => unreachable!("`primary_expression` should contain one of [`constant`, `identifier`], found {:#?}", r), - } - } - Rule::postfix_expression => Expression::Postfix( - PostfixExpression::from_pest(&mut pair.into_inner()).unwrap(), - ), - Rule::inline_struct_expression => Expression::InlineStruct( - InlineStructExpression::from_pest(&mut pair.into_inner()).unwrap(), - ), - Rule::inline_array_expression => Expression::InlineArray( - InlineArrayExpression::from_pest(&mut pair.into_inner()).unwrap(), - ), - Rule::array_initializer_expression => Expression::ArrayInitializer( - ArrayInitializerExpression::from_pest(&mut pair.into_inner()).unwrap() - ), - Rule::unary_expression => { - let span = next.as_span(); - let mut inner = next.into_inner(); - let op = match inner.next().unwrap().as_rule() { - Rule::op_unary => UnaryOperator::from_pest(&mut pair.into_inner().next().unwrap().into_inner()).unwrap(), - r => unreachable!("`unary_expression` should yield `op_unary`, found {:#?}", r) - }; - let expression = build_factor(inner.next().unwrap()); - Expression::Unary(UnaryExpression { - op, - expression, - span - }) - }, - r => unreachable!("`term` should contain one of [`expression`, `conditional_expression`, `primary_expression`, `postfix_expression`, `inline_array_expression`, `unary_expression`, `array_initializer_expression`], found {:#?}", r) - } - } - r => unreachable!( - "`build_factor` can only be called on `term`, found {:#?}", - r - ), - }) + Box::new(Expression::from( + UnariedTerm::from_pest(&mut Pairs::single(pair)).unwrap(), + )) } #[derive(Debug, FromPest, PartialEq, Clone)] @@ -218,6 +156,7 @@ mod ast { #[pest_ast(rule(Rule::function_definition))] pub struct Function<'ast> { pub id: IdentifierExpression<'ast>, + pub generics: Vec>, pub parameters: Vec>, pub returns: Vec>, pub statements: Vec>, @@ -276,6 +215,7 @@ mod ast { U8(U8Type<'ast>), U16(U16Type<'ast>), U32(U32Type<'ast>), + U64(U64Type<'ast>), } #[derive(Debug, FromPest, PartialEq, Clone)] @@ -329,6 +269,13 @@ mod ast { pub span: Span<'ast>, } + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::ty_u64))] + pub struct U64Type<'ast> { + #[pest_ast(outer())] + pub span: Span<'ast>, + } + #[derive(Debug, FromPest, PartialEq, Clone)] #[pest_ast(rule(Rule::ty_struct))] pub struct StructType<'ast> { @@ -362,6 +309,7 @@ mod ast { #[pest_ast(rule(Rule::vis_private))] pub struct PrivateVisibility {} + #[allow(clippy::large_enum_variant)] #[derive(Debug, FromPest, PartialEq, Clone)] #[pest_ast(rule(Rule::statement))] pub enum Statement<'ast> { @@ -431,30 +379,149 @@ mod ast { Pow, } - #[derive(Debug, PartialEq, FromPest, Clone)] - #[pest_ast(rule(Rule::op_unary))] - pub enum UnaryOperator<'ast> { - Not(Not<'ast>), - } - - #[derive(Debug, PartialEq, FromPest, Clone)] - #[pest_ast(rule(Rule::op_not))] - pub struct Not<'ast> { - #[pest_ast(outer())] - pub span: Span<'ast>, - } - #[derive(Debug, PartialEq, Clone)] pub enum Expression<'ast> { Ternary(TernaryExpression<'ast>), Binary(BinaryExpression<'ast>), + Unary(UnaryExpression<'ast>), Postfix(PostfixExpression<'ast>), Identifier(IdentifierExpression<'ast>), - Constant(ConstantExpression<'ast>), + Literal(LiteralExpression<'ast>), InlineArray(InlineArrayExpression<'ast>), InlineStruct(InlineStructExpression<'ast>), ArrayInitializer(ArrayInitializerExpression<'ast>), - Unary(UnaryExpression<'ast>), + } + + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::term))] + pub enum Term<'ast> { + Expression(Expression<'ast>), + InlineStruct(InlineStructExpression<'ast>), + Ternary(TernaryExpression<'ast>), + Postfix(PostfixExpression<'ast>), + Primary(PrimaryExpression<'ast>), + InlineArray(InlineArrayExpression<'ast>), + ArrayInitializer(ArrayInitializerExpression<'ast>), + } + + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::powered_term))] + struct PoweredTerm<'ast> { + base: Term<'ast>, + op: Option, + exponent: Option>, + #[pest_ast(outer())] + span: Span<'ast>, + } + + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::op_pow))] + struct PowOperator; + + impl<'ast> From> for Expression<'ast> { + fn from(t: PoweredTerm<'ast>) -> Self { + let base = Expression::from(t.base); + + match t.exponent { + Some(exponent) => Expression::Binary(BinaryExpression { + op: BinaryOperator::Pow, + left: Box::new(base), + right: Box::new(exponent.into()), + span: t.span, + }), + None => base, + } + } + } + + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::unaried_term))] + struct UnariedTerm<'ast> { + op: Option, + expression: PoweredTerm<'ast>, + #[pest_ast(outer())] + span: Span<'ast>, + } + + impl<'ast> From> for Expression<'ast> { + fn from(t: UnariedTerm<'ast>) -> Self { + let expression = Expression::from(t.expression); + + match t.op { + Some(sign) => Expression::Unary(UnaryExpression { + op: sign, + expression: Box::new(expression), + span: t.span, + }), + None => expression, + } + } + } + + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::op_unary))] + pub enum UnaryOperator { + Pos(PosOperator), + Neg(NegOperator), + Not(NotOperator), + } + + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::op_pos))] + pub struct PosOperator; + + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::op_neg))] + pub struct NegOperator; + + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::op_not))] + pub struct NotOperator; + + impl<'ast> From> for Expression<'ast> { + fn from(t: Term<'ast>) -> Self { + match t { + Term::Expression(e) => e, + Term::Ternary(e) => Expression::Ternary(e), + Term::Postfix(e) => Expression::Postfix(e), + Term::Primary(e) => e.into(), + Term::InlineArray(e) => Expression::InlineArray(e), + Term::InlineStruct(e) => Expression::InlineStruct(e), + Term::ArrayInitializer(e) => Expression::ArrayInitializer(e), + } + } + } + + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::primary_expression))] + pub enum PrimaryExpression<'ast> { + Identifier(IdentifierExpression<'ast>), + Literal(LiteralExpression<'ast>), + } + + impl<'ast> From> for Expression<'ast> { + fn from(e: PrimaryExpression<'ast>) -> Self { + match e { + PrimaryExpression::Literal(c) => Expression::Literal(c), + PrimaryExpression::Identifier(i) => Expression::Identifier(i), + } + } + } + + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::exponent_expression))] + pub enum ExponentExpression<'ast> { + Expression(Expression<'ast>), + Primary(PrimaryExpression<'ast>), + } + + impl<'ast> From> for Expression<'ast> { + fn from(e: ExponentExpression<'ast>) -> Self { + match e { + ExponentExpression::Expression(e) => e, + ExponentExpression::Primary(e) => e.into(), + } + } } #[derive(Debug, FromPest, PartialEq, Clone)] @@ -505,15 +572,6 @@ mod ast { pub span: Span<'ast>, } - #[derive(Debug, FromPest, PartialEq, Clone)] - #[pest_ast(rule(Rule::unary_expression))] - pub struct UnaryExpression<'ast> { - pub op: UnaryOperator<'ast>, - pub expression: Box>, - #[pest_ast(outer())] - pub span: Span<'ast>, - } - #[derive(Debug, FromPest, PartialEq, Clone)] #[pest_ast(rule(Rule::inline_array_expression))] pub struct InlineArrayExpression<'ast> { @@ -544,7 +602,7 @@ mod ast { #[pest_ast(rule(Rule::array_initializer_expression))] pub struct ArrayInitializerExpression<'ast> { pub value: Box>, - pub count: ConstantExpression<'ast>, + pub count: Box>, #[pest_ast(outer())] pub span: Span<'ast>, } @@ -558,6 +616,7 @@ mod ast { pub span: Span<'ast>, } + #[allow(clippy::large_enum_variant)] #[derive(Debug, FromPest, PartialEq, Clone)] #[pest_ast(rule(Rule::access))] pub enum Access<'ast> { @@ -576,6 +635,38 @@ mod ast { #[derive(Debug, FromPest, PartialEq, Clone)] #[pest_ast(rule(Rule::call_access))] pub struct CallAccess<'ast> { + pub explicit_generics: Option>, + pub arguments: Arguments<'ast>, + #[pest_ast(outer())] + pub span: Span<'ast>, + } + + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::explicit_generics))] + pub struct ExplicitGenerics<'ast> { + pub values: Vec>, + #[pest_ast(outer())] + pub span: Span<'ast>, + } + + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::constant_generics_value))] + pub enum ConstantGenericValue<'ast> { + Value(LiteralExpression<'ast>), + Identifier(IdentifierExpression<'ast>), + Underscore(Underscore<'ast>), + } + + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::underscore))] + pub struct Underscore<'ast> { + #[pest_ast(outer())] + pub span: Span<'ast>, + } + + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::arguments))] + pub struct Arguments<'ast> { pub expressions: Vec>, #[pest_ast(outer())] pub span: Span<'ast>, @@ -605,6 +696,13 @@ mod ast { pub span: Span<'ast>, } + #[derive(Debug, PartialEq, Clone)] + pub struct UnaryExpression<'ast> { + pub op: UnaryOperator, + pub expression: Box>, + pub span: Span<'ast>, + } + #[derive(Debug, FromPest, PartialEq, Clone)] #[pest_ast(rule(Rule::conditional_expression))] pub struct TernaryExpression<'ast> { @@ -648,7 +746,7 @@ mod ast { match self { Expression::Binary(b) => &b.span, Expression::Identifier(i) => &i.span, - Expression::Constant(c) => &c.span(), + Expression::Literal(c) => &c.span(), Expression::Ternary(t) => &t.span, Expression::Postfix(p) => &p.span, Expression::InlineArray(a) => &a.span, @@ -683,32 +781,80 @@ mod ast { } #[derive(Debug, FromPest, PartialEq, Clone)] - #[pest_ast(rule(Rule::constant))] - pub enum ConstantExpression<'ast> { - DecimalNumber(DecimalNumberExpression<'ast>), + #[pest_ast(rule(Rule::literal))] + pub enum LiteralExpression<'ast> { + DecimalLiteral(DecimalLiteralExpression<'ast>), BooleanLiteral(BooleanLiteralExpression<'ast>), - U8(U8NumberExpression<'ast>), - U16(U16NumberExpression<'ast>), - U32(U32NumberExpression<'ast>), + HexLiteral(HexLiteralExpression<'ast>), } - impl<'ast> ConstantExpression<'ast> { + impl<'ast> LiteralExpression<'ast> { pub fn span(&self) -> &Span<'ast> { match self { - ConstantExpression::DecimalNumber(n) => &n.span, - ConstantExpression::BooleanLiteral(c) => &c.span, - ConstantExpression::U8(c) => &c.span, - ConstantExpression::U16(c) => &c.span, - ConstantExpression::U32(c) => &c.span, + LiteralExpression::DecimalLiteral(n) => &n.span, + LiteralExpression::BooleanLiteral(c) => &c.span, + LiteralExpression::HexLiteral(h) => &h.span, } } } + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::decimal_suffix))] + pub enum DecimalSuffix<'ast> { + U8(U8Suffix<'ast>), + U16(U16Suffix<'ast>), + U32(U32Suffix<'ast>), + U64(U64Suffix<'ast>), + Field(FieldSuffix<'ast>), + } + + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::decimal_suffix_u8))] + pub struct U8Suffix<'ast> { + #[pest_ast(outer())] + pub span: Span<'ast>, + } + + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::decimal_suffix_u16))] + pub struct U16Suffix<'ast> { + #[pest_ast(outer())] + pub span: Span<'ast>, + } + + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::decimal_suffix_u32))] + pub struct U32Suffix<'ast> { + #[pest_ast(outer())] + pub span: Span<'ast>, + } + + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::decimal_suffix_u64))] + pub struct U64Suffix<'ast> { + #[pest_ast(outer())] + pub span: Span<'ast>, + } + + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::decimal_suffix_field))] + pub struct FieldSuffix<'ast> { + #[pest_ast(outer())] + pub span: Span<'ast>, + } + #[derive(Debug, FromPest, PartialEq, Clone)] #[pest_ast(rule(Rule::decimal_number))] - pub struct DecimalNumberExpression<'ast> { - #[pest_ast(outer(with(span_into_str)))] - pub value: String, + pub struct DecimalNumber<'ast> { + #[pest_ast(outer())] + pub span: Span<'ast>, + } + + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::decimal_literal))] + pub struct DecimalLiteralExpression<'ast> { + pub value: DecimalNumber<'ast>, + pub suffix: Option>, #[pest_ast(outer())] pub span: Span<'ast>, } @@ -723,7 +869,24 @@ mod ast { } #[derive(Debug, FromPest, PartialEq, Clone)] - #[pest_ast(rule(Rule::hex_number_8))] + #[pest_ast(rule(Rule::hex_literal))] + pub struct HexLiteralExpression<'ast> { + pub value: HexNumberExpression<'ast>, + #[pest_ast(outer())] + pub span: Span<'ast>, + } + + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::hex_number))] + pub enum HexNumberExpression<'ast> { + U8(U8NumberExpression<'ast>), + U16(U16NumberExpression<'ast>), + U32(U32NumberExpression<'ast>), + U64(U64NumberExpression<'ast>), + } + + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::hex_number_u8))] pub struct U8NumberExpression<'ast> { #[pest_ast(outer(with(span_into_str)))] pub value: String, @@ -732,7 +895,7 @@ mod ast { } #[derive(Debug, FromPest, PartialEq, Clone)] - #[pest_ast(rule(Rule::hex_number_16))] + #[pest_ast(rule(Rule::hex_number_u16))] pub struct U16NumberExpression<'ast> { #[pest_ast(outer(with(span_into_str)))] pub value: String, @@ -741,7 +904,7 @@ mod ast { } #[derive(Debug, FromPest, PartialEq, Clone)] - #[pest_ast(rule(Rule::hex_number_32))] + #[pest_ast(rule(Rule::hex_number_u32))] pub struct U32NumberExpression<'ast> { #[pest_ast(outer(with(span_into_str)))] pub value: String, @@ -749,6 +912,15 @@ mod ast { pub span: Span<'ast>, } + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::hex_number_u64))] + pub struct U64NumberExpression<'ast> { + #[pest_ast(outer(with(span_into_str)))] + pub value: String, + #[pest_ast(outer())] + pub span: Span<'ast>, + } + #[derive(Debug, FromPest, PartialEq, Clone)] #[pest_ast(rule(Rule::identifier))] pub struct IdentifierExpression<'ast> { @@ -773,6 +945,7 @@ mod ast { #[derive(Debug, FromPest, PartialEq, Clone)] #[pest_ast(rule(Rule::EOI))] + #[allow(clippy::upper_case_acronyms)] pub struct EOI; } @@ -794,7 +967,7 @@ impl fmt::Display for Error { } pub fn generate_ast(input: &str) -> Result { - let parse_tree = parse(input).map_err(|e| Error(e))?; + let parse_tree = parse(input).map_err(Error)?; Ok(Prog::from(parse_tree).0) } @@ -867,6 +1040,7 @@ mod tests { pragma: None, structs: vec![], functions: vec![Function { + generics: vec![], id: IdentifierExpression { value: String::from("main"), span: Span::new(&source, 33, 37).unwrap() @@ -877,15 +1051,21 @@ mod tests { }))], statements: vec![Statement::Return(ReturnStatement { expressions: vec![Expression::add( - Expression::Constant(ConstantExpression::DecimalNumber( - DecimalNumberExpression { - value: String::from("1"), + Expression::Literal(LiteralExpression::DecimalLiteral( + DecimalLiteralExpression { + value: DecimalNumber { + span: Span::new(&source, 59, 60).unwrap() + }, + suffix: None, span: Span::new(&source, 59, 60).unwrap() } )), - Expression::Constant(ConstantExpression::DecimalNumber( - DecimalNumberExpression { - value: String::from("1"), + Expression::Literal(LiteralExpression::DecimalLiteral( + DecimalLiteralExpression { + value: DecimalNumber { + span: Span::new(&source, 63, 64).unwrap() + }, + suffix: None, span: Span::new(&source, 63, 64).unwrap() } )), @@ -920,6 +1100,7 @@ mod tests { pragma: None, structs: vec![], functions: vec![Function { + generics: vec![], id: IdentifierExpression { value: String::from("main"), span: Span::new(&source, 33, 37).unwrap() @@ -930,29 +1111,41 @@ mod tests { }))], statements: vec![Statement::Return(ReturnStatement { expressions: vec![Expression::add( - Expression::Constant(ConstantExpression::DecimalNumber( - DecimalNumberExpression { - value: String::from("1"), + Expression::Literal(LiteralExpression::DecimalLiteral( + DecimalLiteralExpression { + suffix: None, + value: DecimalNumber { + span: Span::new(&source, 59, 60).unwrap() + }, span: Span::new(&source, 59, 60).unwrap() } )), Expression::mul( - Expression::Constant(ConstantExpression::DecimalNumber( - DecimalNumberExpression { - value: String::from("2"), + Expression::Literal(LiteralExpression::DecimalLiteral( + DecimalLiteralExpression { + suffix: None, + value: DecimalNumber { + span: Span::new(&source, 63, 64).unwrap() + }, span: Span::new(&source, 63, 64).unwrap() } )), Expression::pow( - Expression::Constant(ConstantExpression::DecimalNumber( - DecimalNumberExpression { - value: String::from("3"), + Expression::Literal(LiteralExpression::DecimalLiteral( + DecimalLiteralExpression { + suffix: None, + value: DecimalNumber { + span: Span::new(&source, 67, 68).unwrap() + }, span: Span::new(&source, 67, 68).unwrap() } )), - Expression::Constant(ConstantExpression::DecimalNumber( - DecimalNumberExpression { - value: String::from("4"), + Expression::Literal(LiteralExpression::DecimalLiteral( + DecimalLiteralExpression { + suffix: None, + value: DecimalNumber { + span: Span::new(&source, 72, 73).unwrap() + }, span: Span::new(&source, 72, 73).unwrap() } )), @@ -991,6 +1184,7 @@ mod tests { pragma: None, structs: vec![], functions: vec![Function { + generics: vec![], id: IdentifierExpression { value: String::from("main"), span: Span::new(&source, 33, 37).unwrap() @@ -1001,21 +1195,30 @@ mod tests { }))], statements: vec![Statement::Return(ReturnStatement { expressions: vec![Expression::if_else( - Expression::Constant(ConstantExpression::DecimalNumber( - DecimalNumberExpression { - value: String::from("1"), + Expression::Literal(LiteralExpression::DecimalLiteral( + DecimalLiteralExpression { + suffix: None, + value: DecimalNumber { + span: Span::new(&source, 62, 63).unwrap() + }, span: Span::new(&source, 62, 63).unwrap() } )), - Expression::Constant(ConstantExpression::DecimalNumber( - DecimalNumberExpression { - value: String::from("2"), + Expression::Literal(LiteralExpression::DecimalLiteral( + DecimalLiteralExpression { + suffix: None, + value: DecimalNumber { + span: Span::new(&source, 69, 70).unwrap() + }, span: Span::new(&source, 69, 70).unwrap() } )), - Expression::Constant(ConstantExpression::DecimalNumber( - DecimalNumberExpression { - value: String::from("3"), + Expression::Literal(LiteralExpression::DecimalLiteral( + DecimalLiteralExpression { + suffix: None, + value: DecimalNumber { + span: Span::new(&source, 76, 77).unwrap() + }, span: Span::new(&source, 76, 77).unwrap() } )), @@ -1049,6 +1252,7 @@ mod tests { pragma: None, structs: vec![], functions: vec![Function { + generics: vec![], id: IdentifierExpression { value: String::from("main"), span: Span::new(&source, 4, 8).unwrap() @@ -1058,9 +1262,12 @@ mod tests { span: Span::new(&source, 15, 20).unwrap() }))], statements: vec![Statement::Return(ReturnStatement { - expressions: vec![Expression::Constant(ConstantExpression::DecimalNumber( - DecimalNumberExpression { - value: String::from("1"), + expressions: vec![Expression::Literal(LiteralExpression::DecimalLiteral( + DecimalLiteralExpression { + suffix: None, + value: DecimalNumber { + span: Span::new(&source, 31, 32).unwrap() + }, span: Span::new(&source, 31, 32).unwrap() } ))], @@ -1085,6 +1292,7 @@ mod tests { pragma: None, structs: vec![], functions: vec![Function { + generics: vec![], id: IdentifierExpression { value: String::from("main"), span: Span::new(&source, 4, 8).unwrap() @@ -1128,29 +1336,42 @@ mod tests { span: Span::new(&source, 36, 39).unwrap() }, accesses: vec![Access::Call(CallAccess { - expressions: vec![ - Expression::Constant(ConstantExpression::DecimalNumber( - DecimalNumberExpression { - value: String::from("1"), - span: Span::new(&source, 40, 41).unwrap() - } - )), - Expression::add( - Expression::Constant(ConstantExpression::DecimalNumber( - DecimalNumberExpression { - value: String::from("2"), - span: Span::new(&source, 43, 44).unwrap() + explicit_generics: None, + arguments: Arguments { + expressions: vec![ + Expression::Literal(LiteralExpression::DecimalLiteral( + DecimalLiteralExpression { + suffix: None, + value: DecimalNumber { + span: Span::new(&source, 40, 41).unwrap() + }, + span: Span::new(&source, 40, 41).unwrap() } )), - Expression::Constant(ConstantExpression::DecimalNumber( - DecimalNumberExpression { - value: String::from("3"), - span: Span::new(&source, 47, 48).unwrap() - } - )), - Span::new(&source, 43, 48).unwrap() - ), - ], + Expression::add( + Expression::Literal(LiteralExpression::DecimalLiteral( + DecimalLiteralExpression { + suffix: None, + value: DecimalNumber { + span: Span::new(&source, 43, 44).unwrap() + }, + span: Span::new(&source, 43, 44).unwrap() + } + )), + Expression::Literal(LiteralExpression::DecimalLiteral( + DecimalLiteralExpression { + suffix: None, + value: DecimalNumber { + span: Span::new(&source, 47, 48).unwrap() + }, + span: Span::new(&source, 47, 48).unwrap() + } + )), + Span::new(&source, 43, 48).unwrap() + ), + ], + span: Span::new(&source, 40, 48).unwrap() + }, span: Span::new(&source, 39, 49).unwrap() })], span: Span::new(&source, 36, 49).unwrap(), @@ -1168,16 +1389,16 @@ mod tests { #[test] fn playground() { - let source = r#"import "heyman" as yo + let source = r#"import "foo" as bar struct Foo { field[2] foo Bar bar } - def main(private field[23] a) -> (bool[234 + 6]): + def main

(private field[Q] a) -> (bool[234 + 6]): field a = 1 - a[32 + x][55] = y + a[32 + x][55] = foo::(y) for field i in 0..3 do assert(a == 1 + 2 + 3+ 4+ 5+ 6+ 6+ 7+ 8 + 4+ 5+ 3+ 4+ 2+ 3) endfor diff --git a/zokrates_stdlib/Cargo.toml b/zokrates_stdlib/Cargo.toml index 3aa0ac998..84264cb43 100644 --- a/zokrates_stdlib/Cargo.toml +++ b/zokrates_stdlib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zokrates_stdlib" -version = "0.1.8" +version = "0.2.0" authors = ["Stefan Deml ", "schaeff "] edition = "2018" diff --git a/zokrates_stdlib/build.rs b/zokrates_stdlib/build.rs index 5081027dd..cb2dd02cd 100644 --- a/zokrates_stdlib/build.rs +++ b/zokrates_stdlib/build.rs @@ -15,5 +15,5 @@ fn export_stdlib() { let out_dir = env::var("OUT_DIR").unwrap(); let mut options = CopyOptions::new(); options.overwrite = true; - copy_items(&vec!["stdlib"], out_dir, &options).unwrap(); + copy_items(&["stdlib"], out_dir, &options).unwrap(); } diff --git a/zokrates_stdlib/stdlib/ecc/babyjubjubParams.zok b/zokrates_stdlib/stdlib/ecc/babyjubjubParams.zok index fcc433b1f..11fd783a8 100644 --- a/zokrates_stdlib/stdlib/ecc/babyjubjubParams.zok +++ b/zokrates_stdlib/stdlib/ecc/babyjubjubParams.zok @@ -4,7 +4,6 @@ // Note: parameters will be updated soon to be more compatible with zCash's implementation struct BabyJubJubParams { - // field JUBJUBE field JUBJUBC field JUBJUBA field JUBJUBD @@ -17,8 +16,7 @@ struct BabyJubJubParams { def main() -> BabyJubJubParams: -// Order of the curve E - // field JUBJUBE = 21888242871839275222246405745257275088614511777268538073601725287587578984328 + // Order of the curve for reference: 21888242871839275222246405745257275088614511777268538073601725287587578984328 field JUBJUBC = 8 // Cofactor field JUBJUBA = 168700 // Coefficient A field JUBJUBD = 168696 // Coefficient D @@ -40,7 +38,6 @@ return BabyJubJubParams { INFINITY: INFINITY, Gu: Gu, Gv: Gv, - // JUBJUBE: JUBJUBE, JUBJUBC: JUBJUBC, MONTA: MONTA, MONTB: MONTB diff --git a/zokrates_stdlib/stdlib/ecc/edwardsScalarMult.zok b/zokrates_stdlib/stdlib/ecc/edwardsScalarMult.zok index dd7b43000..7e90625ca 100644 --- a/zokrates_stdlib/stdlib/ecc/edwardsScalarMult.zok +++ b/zokrates_stdlib/stdlib/ecc/edwardsScalarMult.zok @@ -15,8 +15,8 @@ def main(bool[256] exponent, field[2] pt, BabyJubJubParams context) -> field[2]: field[2] doubledP = pt field[2] accumulatedP = infinity - for field i in 0..256 do - field j = 255 - i + for u32 i in 0..256 do + u32 j = 255 - i field[2] candidateP = add(accumulatedP, doubledP, context) accumulatedP = if exponent[j] then candidateP else accumulatedP fi doubledP = add(doubledP, doubledP, context) diff --git a/zokrates_stdlib/stdlib/hashes/blake2/blake2s.zok b/zokrates_stdlib/stdlib/hashes/blake2/blake2s.zok new file mode 100644 index 000000000..8bbf125fe --- /dev/null +++ b/zokrates_stdlib/stdlib/hashes/blake2/blake2s.zok @@ -0,0 +1,4 @@ +import "hashes/blake2/blake2s_p" as blake2s_p + +def main(u32[K][16] input) -> (u32[8]): + return blake2s_p(input, [0; 2]) \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/hashes/blake2/blake2s_p.zok b/zokrates_stdlib/stdlib/hashes/blake2/blake2s_p.zok new file mode 100644 index 000000000..239f9fce0 --- /dev/null +++ b/zokrates_stdlib/stdlib/hashes/blake2/blake2s_p.zok @@ -0,0 +1,98 @@ +// https://tools.ietf.org/html/rfc7693 + +import "EMBED/u32_to_bits" as to_bits +import "EMBED/u32_from_bits" as from_bits + +def right_rotate(u32 e) -> u32: + bool[32] b = to_bits(e) + return from_bits([...b[32 - N..], ...b[..32 - N]]) + +def blake2s_iv() -> (u32[8]): + return [ + 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, + 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 + ] + +def blake2s_sigma() -> (u32[10][16]): + return [ + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], + [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3], + [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4], + [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8], + [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13], + [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9], + [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11], + [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10], + [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5], + [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0] + ] + +def mixing_g(u32[16] v, u32 a, u32 b, u32 c, u32 d, u32 x, u32 y) -> (u32[16]): + v[a] = (v[a] + v[b] + x) + v[d] = right_rotate::<16>(v[d] ^ v[a]) + v[c] = (v[c] + v[d]) + v[b] = right_rotate::<12>(v[b] ^ v[c]) + v[a] = (v[a] + v[b] + y) + v[d] = right_rotate::<8>(v[d] ^ v[a]) + v[c] = (v[c] + v[d]) + v[b] = right_rotate::<7>(v[b] ^ v[c]) + return v + +def blake2s_compression(u32[8] h, u32[16] m, u32[2] t, bool last) -> (u32[8]): + u32[16] v = [...h, ...blake2s_iv()] + + v[12] = v[12] ^ t[0] + v[13] = v[13] ^ t[1] + v[14] = if last then v[14] ^ 0xFFFFFFFF else v[14] fi + + u32[10][16] sigma = blake2s_sigma() + + for u32 i in 0..10 do + u32[16] s = sigma[i] + v = mixing_g(v, 0, 4, 8, 12, m[s[0]], m[s[1]]) + v = mixing_g(v, 1, 5, 9, 13, m[s[2]], m[s[3]]) + v = mixing_g(v, 2, 6, 10, 14, m[s[4]], m[s[5]]) + v = mixing_g(v, 3, 7, 11, 15, m[s[6]], m[s[7]]) + v = mixing_g(v, 0, 5, 10, 15, m[s[8]], m[s[9]]) + v = mixing_g(v, 1, 6, 11, 12, m[s[10]], m[s[11]]) + v = mixing_g(v, 2, 7, 8, 13, m[s[12]], m[s[13]]) + v = mixing_g(v, 3, 4, 9, 14, m[s[14]], m[s[15]]) + endfor + + for u32 i in 0..8 do + h[i] = h[i] ^ v[i] ^ v[i + 8] + endfor + + return h + +def blake2s_init(u32[2] p) -> (u32[8]): + u32[8] iv = blake2s_iv() + u32[8] h = [ + iv[0] ^ 0x01010000 ^ 0x00000020, + iv[1], + iv[2], + iv[3], + iv[4], + iv[5], + iv[6] ^ p[0], + iv[7] ^ p[1] + ] + return h + +def main(u32[K][16] input, u32[2] p) -> (u32[8]): + u32[8] h = blake2s_init(p) + + u32 t0 = 0 + u32 t1 = 0 + + for u32 i in 0..K-1 do + t0 = (i + 1) * 64 + t1 = if t0 == 0 then t1 + 1 else t1 fi + h = blake2s_compression(h, input[i], [t0, t1], false) + endfor + + t0 = t0 + 64 + t1 = if t0 == 0 then t1 + 1 else t1 fi + + h = blake2s_compression(h, input[K - 1], [t0, t1], true) + return h \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/hashes/keccak/256bit.zok b/zokrates_stdlib/stdlib/hashes/keccak/256bit.zok new file mode 100644 index 000000000..59d800fe8 --- /dev/null +++ b/zokrates_stdlib/stdlib/hashes/keccak/256bit.zok @@ -0,0 +1,4 @@ +import "hashes/keccak/keccak" as keccak + +def main(u64[N] input) -> u64[4]: + return keccak::(input, 0x0000000000000001)[..4] \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/hashes/keccak/384bit.zok b/zokrates_stdlib/stdlib/hashes/keccak/384bit.zok new file mode 100644 index 000000000..f261ebcc3 --- /dev/null +++ b/zokrates_stdlib/stdlib/hashes/keccak/384bit.zok @@ -0,0 +1,4 @@ +import "hashes/keccak/keccak" as keccak + +def main(u64[N] input) -> u64[6]: + return keccak::(input, 0x0000000000000001)[..6] \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/hashes/keccak/512bit.zok b/zokrates_stdlib/stdlib/hashes/keccak/512bit.zok new file mode 100644 index 000000000..8345df528 --- /dev/null +++ b/zokrates_stdlib/stdlib/hashes/keccak/512bit.zok @@ -0,0 +1,4 @@ +import "hashes/keccak/keccak" as keccak + +def main(u64[N] input) -> u64[8]: + return keccak::(input, 0x0000000000000001)[..8] \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/hashes/keccak/keccak.zok b/zokrates_stdlib/stdlib/hashes/keccak/keccak.zok new file mode 100644 index 000000000..791ef30bc --- /dev/null +++ b/zokrates_stdlib/stdlib/hashes/keccak/keccak.zok @@ -0,0 +1,95 @@ +// based on keccak-f[1600] permutation + +def rho() -> u32[24]: + return [ + 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44 + ] + +def pi() -> u32[24]: + return [ + 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1 + ] + +def rc() -> u64[24]: + return [ + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, + 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, + 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, + 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 + ] + +// left rotation +def rotl64(u64 x, u32 n) -> u64: + return ((x << n) | (x >> (64 - n))) + +// compression function +def keccakf(u64[25] st) -> u64[25]: + u32[24] rotc = rho() + u32[24] piln = pi() + u64[24] rndc = rc() + + u64[5] bc = [0; 5] + u64 t = 0 + + for u32 r in 0..24 do + // theta + for u32 i in 0..5 do + bc[i] = st[i] ^ st[i + 5] ^ st[i + 10] ^ st[i + 15] ^ st[i + 20] + endfor + + for u32 i in 0..5 do + t = bc[(i + 4) % 5] ^ rotl64(bc[(i + 1) % 5], 1) + for u32 j in 0..5 do + st[(j * 5) + i] = st[(j * 5) + i] ^ t + endfor + endfor + + t = st[1] + + // rho pi + for u32 i in 0..24 do + bc[0] = st[piln[i]] + st[piln[i]] = rotl64(t, rotc[i]) + t = bc[0] + endfor + + // chi + for u32 i in 0..5 do + for u32 j in 0..5 do + bc[j] = st[(i * 5) + j] + endfor + for u32 j in 0..5 do + u32 p = (i * 5) + j + st[p] = st[p] ^ (!bc[(j + 1) % 5] & bc[(j + 2) % 5]) + endfor + endfor + + // iota + st[0] = st[0] ^ rndc[r] + endfor + return st + +def main(u64[N] input, u64 pad) -> u64[25]: + u64[25] q = [0; 25] + u32 rate = (200 - (W / 4)) / 8 + u32 pt = 0 + + // update + for u32 i in 0..N do + q[pt] = q[pt] ^ input[i] + pt = (pt + 1) % rate + q = if pt == 0 then keccakf(q) else q fi + endfor + + // finalize + q[pt] = q[pt] ^ pad + q[rate - 1] = q[rate - 1] ^ 0x8000000000000000 + + q = keccakf(q) + return q \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/hashes/mimc7/mimc7.zok b/zokrates_stdlib/stdlib/hashes/mimc7/mimc7.zok new file mode 100644 index 000000000..525d3147c --- /dev/null +++ b/zokrates_stdlib/stdlib/hashes/mimc7/mimc7.zok @@ -0,0 +1,18 @@ +import "./constants" as constants + +def main(field x_in, field k) -> field: + field[91] c = constants() + field t = 0 + field[ROUNDS] t2 = [0; ROUNDS] + field[ROUNDS] t4 = [0; ROUNDS] + field[ROUNDS] t6 = [0; ROUNDS] + field[ROUNDS] t7 = [0; ROUNDS] // we define t7 length +1 to reference implementation as ZoKrates wont allow conditional branching. -> out of bounds array error + for u32 i in 0..ROUNDS do + u32 i2 = if i == 0 then 0 else i - 1 fi + t = if i == 0 then k+x_in else k + t7[i2] + c[i] fi + t2[i] = t*t + t4[i] = t2[i]*t2[i] + t6[i] = t4[i]*t2[i] + t7[i] = t6[i]*t + endfor + return t6[ROUNDS - 1]*t + k \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/hashes/mimc7/mimc7R10.zok b/zokrates_stdlib/stdlib/hashes/mimc7/mimc7R10.zok deleted file mode 100644 index d3a58e6b0..000000000 --- a/zokrates_stdlib/stdlib/hashes/mimc7/mimc7R10.zok +++ /dev/null @@ -1,18 +0,0 @@ -import "./constants" as constants - -def main(field x_in, field k) -> field: - field[91] c = constants() - field t = 0 - field[10] t2 = [0; 10] - field[10] t4 = [0; 10] - field[10] t6 = [0; 10] - field[10] t7 = [0; 10] // we define t7 length +1 to reference implementation as ZoKrates wont allow conditional branching. -> out of bounds array error - for field i in 0..10 do - field i2 = if i == 0 then 0 else i - 1 fi - t = if i == 0 then k+x_in else k + t7[i2] + c[i] fi - t2[i] = t*t - t4[i] = t2[i]*t2[i] - t6[i] = t4[i]*t2[i] - t7[i] = t6[i]*t - endfor - return t6[9]*t + k \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/hashes/mimc7/mimc7R20.zok b/zokrates_stdlib/stdlib/hashes/mimc7/mimc7R20.zok deleted file mode 100644 index f231662f3..000000000 --- a/zokrates_stdlib/stdlib/hashes/mimc7/mimc7R20.zok +++ /dev/null @@ -1,18 +0,0 @@ -import "./constants" as constants - -def main(field x_in, field k) -> field: - field[91] c = constants() - field t = 0 - field[20] t2 = [0; 20] - field[20] t4 = [0; 20] - field[20] t6 = [0; 20] - field[20] t7 = [0; 20] // we define t7 length +1 to reference implementation as ZoKrates wont allow conditional branching. -> out of bounds array error - for field i in 0..20 do - field i2 = if i == 0 then 0 else i - 1 fi - t = if i == 0 then k+x_in else k + t7[i2] + c[i] fi - t2[i] = t*t - t4[i] = t2[i]*t2[i] - t6[i] = t4[i]*t2[i] - t7[i] = t6[i]*t - endfor - return t6[19]*t + k \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/hashes/mimc7/mimc7R50.zok b/zokrates_stdlib/stdlib/hashes/mimc7/mimc7R50.zok deleted file mode 100644 index c3dc3d1ef..000000000 --- a/zokrates_stdlib/stdlib/hashes/mimc7/mimc7R50.zok +++ /dev/null @@ -1,18 +0,0 @@ -import "./constants" as constants - -def main(field x_in, field k) -> field: - field[91] c = constants() - field t = 0 - field[50] t2 = [0; 50] - field[50] t4 = [0; 50] - field[50] t6 = [0; 50] - field[50] t7 = [0; 50] // we define t7 length +1 to reference implementation as ZoKrates wont allow conditional branching. - for field i in 0..50 do - field i2 = if i == 0 then 0 else i - 1 fi - t = if i == 0 then k+x_in else k + t7[i2] + c[i] fi - t2[i] = t*t - t4[i] = t2[i]*t2[i] - t6[i] = t4[i]*t2[i] - t7[i] = t6[i]*t - endfor - return t6[49]*t + k \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/hashes/mimc7/mimc7R90.zok b/zokrates_stdlib/stdlib/hashes/mimc7/mimc7R90.zok deleted file mode 100644 index 83698aaeb..000000000 --- a/zokrates_stdlib/stdlib/hashes/mimc7/mimc7R90.zok +++ /dev/null @@ -1,18 +0,0 @@ -import "./constants" as constants - -def main(field x_in, field k) -> field: - field[91] c = constants() - field t = 0 - field[90] t2 = [0; 90] - field[90] t4 = [0; 90] - field[90] t6 = [0; 90] - field[90] t7 = [0; 90] // we define t7 length +1 to reference implementation as ZoKrates wont allow conditional branching. - for field i in 0..90 do - field i2 = if i == 0 then 0 else i - 1 fi - t = if i == 0 then k+x_in else k + t7[i2] + c[i] fi - t2[i] = t*t - t4[i] = t2[i]*t2[i] - t6[i] = t4[i]*t2[i] - t7[i] = t6[i]*t - endfor - return t6[89]*t + k \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/hashes/mimcSponge/mimcFeistel.zok b/zokrates_stdlib/stdlib/hashes/mimcSponge/mimcFeistel.zok index 7257c39ad..6e23e44f8 100644 --- a/zokrates_stdlib/stdlib/hashes/mimcSponge/mimcFeistel.zok +++ b/zokrates_stdlib/stdlib/hashes/mimcSponge/mimcFeistel.zok @@ -5,15 +5,15 @@ def main(field xL_in, field xR_in, field k) -> field[2]: field[220] IV = IVconstants() field t = 0 - field nRounds = 220 + u32 nRounds = 220 field[220] t2 = [0; 220] //length: nRounds field[220] t4 = [0; 220] //... field[220] xL = [0; 220] //... field[220] xR = [0; 220] //... field c = 0 - for field i in 0..nRounds do - field idx = if i == 0 then 0 else i - 1 fi + for u32 i in 0..nRounds do + u32 idx = if i == 0 then 0 else i - 1 fi c = IV[i] t = if i == 0 then k + xL_in else k + xL[idx] + c fi diff --git a/zokrates_stdlib/stdlib/hashes/mimcSponge/mimcSponge.zok b/zokrates_stdlib/stdlib/hashes/mimcSponge/mimcSponge.zok index 033617ad5..e58c1e37c 100644 --- a/zokrates_stdlib/stdlib/hashes/mimcSponge/mimcSponge.zok +++ b/zokrates_stdlib/stdlib/hashes/mimcSponge/mimcSponge.zok @@ -2,18 +2,18 @@ import "./mimcFeistel" as MiMCFeistel def main(field[2] ins, field k) -> field[3]: //nInputs = 2, nOutputs = 3, - field nInputs = 2 - field nOutputs = 3 + u32 nInputs = 2 + u32 nOutputs = 3 field[4][2] S = [[0; 2]; 4] // Dim: (nInputs + nOutputs - 1, 2) field[3] outs = [0; 3] - for field i in 0..nInputs do - field idx = if i == 0 then 0 else i - 1 fi + for u32 i in 0..nInputs do + u32 idx = if i == 0 then 0 else i - 1 fi S[i] = if i == 0 then MiMCFeistel(ins[0], 0, k) else MiMCFeistel(S[idx][0] + ins[i], S[idx][1], k) fi endfor outs[0] = S[nInputs - 1][0] - for field i in 0..(nOutputs - 1) do + for u32 i in 0..(nOutputs - 1) do field[2] feistelRes = MiMCFeistel(S[nInputs + i - 1][0], S[nInputs + i - 1][1], k) S[nInputs + i] = feistelRes outs[i + 1] = S[nInputs + i][0] diff --git a/zokrates_stdlib/stdlib/hashes/pedersen/512bit.zok b/zokrates_stdlib/stdlib/hashes/pedersen/512bit.zok index 65d317af3..bbc66f9b9 100644 --- a/zokrates_stdlib/stdlib/hashes/pedersen/512bit.zok +++ b/zokrates_stdlib/stdlib/hashes/pedersen/512bit.zok @@ -1,26 +1,9 @@ - -import "utils/multiplexer/lookup3bitSigned" as sel3s -import "utils/multiplexer/lookup2bit" as sel2 -import "ecc/babyjubjubParams" as context -import "ecc/edwardsAdd" as add -import "ecc/edwardsCompress" as edwardsCompress -from "ecc/babyjubjubParams" import BabyJubJubParams +import "./512bitBool.zok" as pedersen import "EMBED/u32_to_bits" as to_bits import "EMBED/u32_from_bits" as from_bits -// Code to export generators used in this example: -// import bitstring -// from zokrates_pycrypto.gadgets.pedersenHasher import PedersenHasher -// import numpy as np - -// #%% -// entropy = np.random.bytes(64) -// hasher = PedersenHasher("test") -// hasher.hash_bytes(entropy) -// print(hasher.dsl_code) - def main(u32[16] inputs) -> u32[8]: - bool[513] e = [\ + bool[512] e = [\ ...to_bits(inputs[0]), ...to_bits(inputs[1]), ...to_bits(inputs[2]), @@ -36,702 +19,10 @@ def main(u32[16] inputs) -> u32[8]: ...to_bits(inputs[12]), ...to_bits(inputs[13]), ...to_bits(inputs[14]), - ...to_bits(inputs[15]), - false + ...to_bits(inputs[15]) ] - BabyJubJubParams context = context() - field[2] a = context.INFINITY //Infinity - field cx = 0 - field cy = 0 - - //Round 0 - cx = sel3s([e[0], e[1], e[2]], [13418723823902222986275588345615650707197303761863176429873001977640541977977 , 8366451672790208592553809639953117385619257483837439526516290319251622927412, 1785026334726838136757054176272745265857971873904476677125553010508875025629, 15763987975760561753692294837740043971877392788040801334205375164715487005236]) - cy = sel2([e[0], e[1]], [15255921313433251341520743036334816584226787412845488772781699434149539664639 , 10916775373885716961512013142444429405184550001421868906213743991404593770484, 18533662942827602783563125901366807026309605479742251601915445402562880550265, 12754584346112149619040942896930712185968371085994381911052593922432846916845]) - a = add(a, [cx, cy], context) - //Round 1 - cx = sel3s([e[3], e[4], e[5]], [10096735692467598736728394557736034054031417419721869067082824451240861468728 , 6979151010236415881632946866847657030447196774231162748523315765559549846746, 12137947022495312670974525048647679757468392619153927921382150023166867027471, 10624360821702266736197468438435445939719745367234393212061381062942588576905]) - cy = sel2([e[3], e[4]], [16704592219657141368520262522286248296157931669321735564513068002743507745908 , 11518684165372839249156788740134693928233608013641661856685773776747280808438, 21502372109496595498116676984635248026663470429940273577484250291841812814697, 17522620677401472201433112250371604936150385414760411280739362011041111141253]) - a = add(a, [cx, cy], context) - //Round 2 - cx = sel3s([e[6], e[7], e[8]], [13312232735691933658355691628172862856002099081831058080743469900077389848112 , 19327977014594608605244544461851908604127577374373936700152837514516831827340, 5965720943494263185596399776343244990255258211404706922145440547143467603204, 11103963817151340664968920805661885925719434417460707046799768750046118166436]) - cy = sel2([e[6], e[7]], [13997829888819279202328839701908695991998552542771378089573544166678617234314 , 13691878221338656794058835175667599549759724338245021721239544263931121101102, 706995887987748628352958611569702130644716818339521451078302067359882016752, 15519367213943391783104357888987456282196269996908068205680088855765566529720]) - a = add(a, [cx, cy], context) - //Round 3 - cx = sel3s([e[9], e[10], e[11]], [3514614172108804338031132171140068954832144631243755202685348634084887116595 , 21412073555057635706619028382831866089835908408883521913045888015461883281372, 471607086653490738521346129178778785664646799897580486044670851346383461743, 10847495464297569158944970563387929708762967645792327184202073895773051681481]) - cy = sel2([e[9], e[10]], [15464894923367337880246198022819299804461472054752016232660084768002214822896 , 12567819427817222147810760128898363854788230435988968217407844445582977743495, 12262870457786134457367539925912446664295463121045105711733382320777142547504, 18045012503832343228779780686530560760323693867512598336456499973983304678718]) - a = add(a, [cx, cy], context) - //Round 4 - cx = sel3s([e[12], e[13], e[14]], [15118628380960917951049569119912548662747322287644759811263888312919249703276 , 16598886614963769408191675395388471256601718506085533073063821434952573740600, 18985834203956331009360396769407075613873303527461874103999130837255502328872, 4433382535573345454766736182894234755024333432764634149565968221321851794725]) - cy = sel2([e[12], e[13]], [20910093482714196883913434341954530700836700132902516503233669201436063149009 , 1519565901492557479831267649363202289903292383838537677400586534724780525304, 10041416515147137792479948105907931790389702515927709045015890740481960188846, 14765380703378616132649352585549040264662795611639979047816682374423451525367]) - a = add(a, [cx, cy], context) - //Round 5 - cx = sel3s([e[15], e[16], e[17]], [12047448614322625640496087488290723061283996543855169192549742347740217312911 , 4511402808301687111378591744698422835937202088514472343139677982999770140261, 12163443309105839408816984443621255269615222157093914420088948521258519452383, 3481629181674207202258216324378273648482838926623855453371874690866818821960]) - cy = sel2([e[15], e[16]], [16179347143471683729835238045770641754106645772730542840306059882771262928390 , 1330606780692172668576026668607748751348574609524694619904517828208139587545, 21047796364446011793075955655871569603152857270194799075248022968227548164989, 19676582441619193608410544431560207171545714550092005317667230665261246116642]) - a = add(a, [cx, cy], context) - //Round 6 - cx = sel3s([e[18], e[19], e[20]], [12701245173613054114260668542643518710151543759808175831262148773821226772548 , 18376560769194320940844431278184909327980744436343482850507604422674089850707, 2108750731998522594975480214785919514173920126687735114472940765769183959289, 8345688345972355310911106597696772464487464098975129504776508629148304380440]) - cy = sel2([e[18], e[19]], [6893882093554801220855651573375911275440312424798351852776449414399981870319 , 10206179889544308860397247082680802082921236707029342452958684549094240474070, 20690576727949006946449925807058663187909753260538825130322359335830578756980, 934097825986417774187883244964416516816295235495828890679674782707274540176]) - a = add(a, [cx, cy], context) - //Round 7 - cx = sel3s([e[21], e[22], e[23]], [2944698428855471170284815781705687753367479016293091716206788980482046638948 , 13677149007138113141214051970478824544363893133343069459792025336510743485579, 8778584537362078914166751980528033062427878768812683022653464796527206882567, 14187573305341020255138644844606451353103636392771375201751096173736574567883]) - cy = sel2([e[21], e[22]], [17360101552805013843890050881314712134389035043192466182420273655548320239406 , 15585069751456986750767880753875189652981026069625633386060310449606941883984, 14103016602951516262329001181468262879087099584460171406752641724802127444882, 20246884593862204796710227582734862797721958090111806492549002716706329529389]) - a = add(a, [cx, cy], context) - //Round 8 - cx = sel3s([e[24], e[25], e[26]], [14561966822440683665541629338358038450751192033904756806839710397580365916408 , 9033289676904424897161301113716021195450524279682799709206671901182123388512, 3130553029765252517071677341132737863162584406047933071036994763690628383497, 478748220028687672909774713203680223481010996519205842697362525656305870550]) - cy = sel2([e[24], e[25]], [2103279357051120614300268561700949519576521616178686690761693996681299230890 , 20408096719725376095564479959189425244640061563902110565713028117867143533071, 10602190247054189080928144476332888853804880952034975460420247853133904008108, 8904086690633759655814572723164827369823592560037992353159979088242240507753]) - a = add(a, [cx, cy], context) - //Round 9 - cx = sel3s([e[27], e[28], e[29]], [6226499033652114521979121779728984801913588832404495199289210905837818402723 , 8038917508002636084872059181598756897599119789741848736002584943229165162988, 2277325821476302201179031013369476744187798789480148846137091219460796268467, 967514222774662330369300003456258491278184516505205753272628639669418183698]) - cy = sel2([e[27], e[28]], [7443974969385276473096219793909172323973358085935860096061435962537700448286 , 16080381380787087259419052592465179031841607813350912826860291224363330298665, 7197183980134554514649915487783920553359271769991651108349414168397349372685, 15259375744392791676426881929656094304768076565231411137199656518314416373020]) - a = add(a, [cx, cy], context) - //Round 10 - cx = sel3s([e[30], e[31], e[32]], [7079401365241105225661961622760419818013463250349580158302569256283647306129 , 14357098412862251375028337875874646262567035230486208703024315026944432279497, 12132744267560027693690759266151433597852816079588628241106105645480008053825, 16149669420758195925157542983134397690644755714433681232247094526660232442631]) - cy = sel2([e[30], e[31]], [11050535702333135359874644130653446287886435768224627066379760227644857448025 , 2102777351898195104147031754958199443749204333224032175429214522075012926330, 4445288497276728579279429434033072747592184765171167503126978668105350002482, 2895400734738526057690008272958539309751728639263619269043890651038357187575]) - a = add(a, [cx, cy], context) - //Round 11 - cx = sel3s([e[33], e[34], e[35]], [20192636532359225751119979205906307972955330178954709766736232115035084682472 , 804195338747219623697418198937917828717652612397835452095971237574002648345, 6394431494852440399081028203192653448308162012036135765292083934292810191518, 11939476767684237945975176292664687849983867031644620074465117021204214089848]) - cy = sel2([e[33], e[34]], [17748517956264309916268005941322895780280007418421226047127160997826331847601 , 19497513174101598882802026674952900838989414265369078336475842766531805130216, 5620469644231252504463650386222007834239202862082473485080174711171599148975, 5516661986429427386078472422851029350005420782971768428739820651749444868271]) - a = add(a, [cx, cy], context) - //Round 12 - cx = sel3s([e[36], e[37], e[38]], [1324920405111324350836746707883938204858273081019435873511569172015916187999 , 15384225309297147198449617653578330654472159141743407174794062987091000857662, 9920404264935487368096005007182799973436766546149561065368669780566156587060, 15254057056535397961799214335179813200885132815863068943475012547021698517077]) - cy = sel2([e[36], e[37]], [16984705452766649815073644511059333480190120433850502120324063182300137456908 , 18046160220855048074367913256918233739227589113215101142291000275961918974523, 13094718066881673586455686749880972268909309391825129019088029831712146780775, 17556146601257932451584708078305104848786797650062537873707738860847250565143]) - a = add(a, [cx, cy], context) - //Round 13 - cx = sel3s([e[39], e[40], e[41]], [10184781845128697471817965179509651550812478664395958690225791623061609959495 , 5456125639262884825452992858423500073570690895733609235845616173174729575569, 2442835875584110487966438996784695688123609547017380844898154175948468234967, 1507509649954376860384651590722437356078107662975164713418836301939281575419]) - cy = sel2([e[39], e[40]], [12481681651435870984379558646813686612408709833154117210578901875084149402369 , 11152008367598826226940260746556525580820232821082556208512958435351250898503, 7567915483885326926315083960846242855523572023844618551872662303018722806760, 20394803059296859730298132333424950360853695629226621934657959417500478188961]) - a = add(a, [cx, cy], context) - //Round 14 - cx = sel3s([e[42], e[43], e[44]], [10680962982327504072121608021689834159178144997131600234373184928312768469752 , 2399077467035346531560164705357209055497431901223015425246039711757880798964, 3423125451159866822107483111524543716819043967842944968651561023348340629866, 9942880027482137313328709914157120920632734642771778240985776643385937071731]) - cy = sel2([e[42], e[43]], [4698845013673361363032641974440465619959991809676353365742268606915462346702 , 16130578759626193985851427947711894136403468334125608062505774040115700327331, 15972516792261738383725187984065495328469263202118598475958253769706945995080, 7601042727654430423755752301100987459144576573414967660631298823059519301944]) - a = add(a, [cx, cy], context) - //Round 15 - cx = sel3s([e[45], e[46], e[47]], [559099661340368706731458173062937049444139592208939239637572972395409815235 , 1445905511768661496314996877214005625534188630127375321650145036638654136508, 12558069540132067621925302006222579198925455408763618011362743955646129467625, 19809789628385980249290251944250230372682953514057413790020001670501854917090]) - cy = sel2([e[45], e[46]], [10744092763718531253355077100374662669098109929848484460119044326894952631009 , 3973362040829593578154878010051739631231888449967620092704468180671355813892, 1362015208311760378785201188340495520529554642363760051915563618841646945115, 11588368620504227678083366267185871581602064602621931713732756924598104334083]) - a = add(a, [cx, cy], context) - //Round 16 - cx = sel3s([e[48], e[49], e[50]], [1678013963086824122518234712588270403106471527976328603364788331772512526348 , 19217446816753374280163957047166499363370322773252755452762764797217084855190, 18251775792701212313037978569776264038974809413837373677702565241405411946778, 7791054681559787609111187809686247485256130898718509173169053332755413410611]) - cy = sel2([e[48], e[49]], [2187428842929094383038114367392650175780437811274194322303902357941058607339 , 8626132368431980635626323475901790012728207722636477570331410763937692048466, 113795593186630447648084123083495614901087109757474270136294009546464903517, 3911253907085777766524239918145094862050185692851156691146764655435644911738]) - a = add(a, [cx, cy], context) - //Round 17 - cx = sel3s([e[51], e[52], e[53]], [12873968423948310899392467568104977730716801401622261861937368089215309803500 , 12347009456329688755313379291270351313162786795095345538842244121034639964166, 1453033777281838070082852447488517173632198407446735454517038916605079634444, 11282290315868048695472900994602235661536258445850718305682561140328404797725]) - cy = sel2([e[51], e[52]], [8139007031385157566567411468459940290231498857090568363629902873306461631248 , 9142412231629797319569179103935970351107774720462787670615972830568683805984, 12672100925996181868477785977558380430714799944709260345359951721012123501095, 16494953398584179618210238266126209360371451946684386111530845235540890038134]) - a = add(a, [cx, cy], context) - //Round 18 - cx = sel3s([e[54], e[55], e[56]], [7778254495039611795685039895928787457435875136389165268120013630439201169232 , 18978376692784498976711790251498129273567483356717340918869164950830208175147, 6786343960634025784864145941287160961224170404722122001422161703472545445301, 963142484718869013546386102939529863406065949253846087785240390647819147126]) - cy = sel2([e[54], e[55]], [7284679595773642123118330714484999203099307921555787993734753019057231440983 , 11863181578147413903879545253723831525079414688349285572164796614141056912840, 14506820856835670503131551890617399661938603609062325089041733284980790009293, 4347670008275218338032617206784753933320201662996772040726919225863771514568]) - a = add(a, [cx, cy], context) - //Round 19 - cx = sel3s([e[57], e[58], e[59]], [3630756302007400417952089805331380555952289748859891438940570770932527475452 , 4733072488758626584177720052077496914661792393101658203493985364120366268281, 4526910185101338883574479225992287789853409001566403159278561225375682298543, 4955992755917650287600423903671744997417781344631255784951922382765227784141]) - cy = sel2([e[57], e[58]], [16596280733402230599955345374089507399680037832193751466748596443674569931646 , 6390381659733151443695336725554471564240651107616043093647301732553182081233, 17125093365984505488419430885232358010204128822674623886572872558984812477756, 7907776458440631594337279500574606181494889317898652109149850067084027888619]) - a = add(a, [cx, cy], context) - //Round 20 - cx = sel3s([e[60], e[61], e[62]], [13428507160783248146944378848829437095621758280249270905793449036777555016842 , 10292076501843933688687976934900220205880058108224904881677407523508189156342, 766857404192368568735095124452313950539381046754211726072981073742394879383, 19929977262929097751573344897093024390473135465066154321364399543253519251540]) - cy = sel2([e[60], e[61]], [16698341695430068847582701171147088836738454320587148532489385958997389524692 , 15892936434362954902510964691481568586089663041057258511149661842770672240332, 7940515703899915602011570921990242082041971424425808524102519499134803569591, 6891504197906111172381550323513759741804319972496414093225387272302697012664]) - a = add(a, [cx, cy], context) - //Round 21 - cx = sel3s([e[63], e[64], e[65]], [9001788585918405588944162583417858847457169702891113291878897002187678929577 , 6471893763677472946002018028525448192731896031469219164732421705849786414080, 6872696243264239672878286181725922526028148800020555100207514569826971690256, 6457059076269833003010871598305386357557482703463879737255688784535353986402]) - cy = sel2([e[63], e[64]], [2208441895306047741608356002988212098270630744976300198681224594148576837458 , 18524825154497781981405149991295652940946623352876024366965123296382603920630, 4474085805150211658090190066955902897001661633303260299025041221776891523378, 7848328793479881488968680696062292137496770320699466501151951135248413225123]) - a = add(a, [cx, cy], context) - //Round 22 - cx = sel3s([e[66], e[67], e[68]], [9370960127159127445266474449258070389736162441470427007490084241211557822341 , 14965609177224099035387154934147530900281499783229343066828915253839198476726, 10228455969106022490302521106014422994204231909208186519000062372321621002715, 329501376630941941063220737355314017862421104304435198239389326959464907258]) - cy = sel2([e[66], e[67]], [10405035931558887078762806053185283924863039263200495982754625705264574757491 , 15502133231749593338314160389347860966662224717441686478526316588882854824409, 16159781620881884595657183508560936205420303661972673108699575582908291222745, 11627201183429653135859532750162240837549070563304757137644487859075461689878]) - a = add(a, [cx, cy], context) - //Round 23 - cx = sel3s([e[69], e[70], e[71]], [9435538689621391149659891449161022313817917158768482063316123517911261629051 , 20034929826130067090642639519998781717754864739607562909796887703087596572733, 2387945787036487514595261230908460627602020385539203589000341684029816345462, 14287010417915184144199881651073103018750205011354171060170509879133644433324]) - cy = sel2([e[69], e[70]], [3766822724536031967241092846229703633913210151222385593884505545907921188272 , 15647190524611689022349999926088308537492889236313676989549224633916679679521, 12082040904926878889054967598271733538467180307938292871588544645957948546982, 18694076414086475523793644660947803814318698157437774233969783951279622080580]) - a = add(a, [cx, cy], context) - //Round 24 - cx = sel3s([e[72], e[73], e[74]], [5859172856191457066677368896012140820864205253768332100482413148381377691822 , 4109040705512320821322629424016219907769924434419769556997996401827477205364, 20898133598840700569835017147086534068242670333567622549169818027799138688520, 2562111968303466794360830608662119102867266861457203102917042145665851057610]) - cy = sel2([e[72], e[73]], [4836009713585714465496581912154882382453931120914721557804515434755336832208 , 15143499611233432306382398214139440479742818510304232326049564749513747791130, 19356118393311375462052662305789820240618686111711161337705029468367145040988, 5688481852857742015073912476996667522213010914545901826896160233670889226775]) - a = add(a, [cx, cy], context) - //Round 25 - cx = sel3s([e[75], e[76], e[77]], [4623242138639627730014370601705308411725596532862597538813607327046410321312 , 20015154717710755506154819006635497782515667453025611627915382742560093423171, 3514612823502534944140986983282927838609295377065173960376131742886885892219, 20191997625806343264590099369325683216271615998169853765554784065039674586670]) - cy = sel2([e[75], e[76]], [6538526769564699401600543915225940144078494544354769810309083421131300518775 , 9118555176257537603156148628736012723504563452923782011591078402032233615522, 12815558970989336318868652718709831589595442899079588636818966291960853991023, 7703616604462929360855592091876031952747180200478430464323567906544600168109]) - a = add(a, [cx, cy], context) - //Round 26 - cx = sel3s([e[78], e[79], e[80]], [7426207409769264985012540642921370782277366662985635838803842004294008785185 , 5999778250617485918891782298009709493035045140093544961901833503446031905913, 14130927440165985043471103750344848991689715792245153118451423398655300689873, 3796482870456559450471870663226834834712024906775762338643689176551263991246]) - cy = sel2([e[78], e[79]], [16458635168452867431186476181702908205218256620571557119181621733008943007186 , 2408736441388526903801723805189252326923776373802231905332653169285504488507, 4539189593448662319023898529532785456602052593687554864880479361284144700884, 6490484418842862735983085938727562049587933870197049726191839108647357897041]) - a = add(a, [cx, cy], context) - //Round 27 - cx = sel3s([e[81], e[82], e[83]], [9274793422641213328277630692090429447322754602554792362167389139799628719939 , 18213562677024477140777501284013103092531757860081519011108723177266099803615, 5928914343334640962747136863911294731157726634392529232872962806197144988571, 17364692793332784962323580622297080260599290963212510860189969183095513710617]) - cy = sel2([e[81], e[82]], [2125001664000799929029867649528637137680130729147235858348667725168119291610 , 15787194912569598784093233335743719308944830093009287397433562464152875584662, 17778173794489364127449950674919162836220066518510591114146982109869842663244, 18328553264273479562530008673792097214292102347103296244385349755449098608225]) - a = add(a, [cx, cy], context) - //Round 28 - cx = sel3s([e[84], e[85], e[86]], [13710259114758767844337497139752382122951774216678047790125818858626546865590 , 3343610505090632166881693615831990684789904804852523835888323130512752436557, 11550335352408668215051239093872906070657140182660747433535878335227749182418, 21793892863650948729507322696305982607072336532791041097212359516991274087980]) - cy = sel2([e[84], e[85]], [11846136982947366289908137269088548542970460276305965388699657623060915691485 , 14439612735106182034303100596819001121085745615069593580210956482903072588413, 11243378354558219750264654469308879862376787156599458648274627817471028307109, 1416613801077957126034351583571856403044235139983509507026555602579721659100]) - a = add(a, [cx, cy], context) - //Round 29 - cx = sel3s([e[87], e[88], e[89]], [16898533007964698268976570330413504736326631860509774315700399063143612293661 , 19762411747110048388233897239023416141949331694011759548598869652948167421240, 11749964437081939283728905999710450041654325285452589389081577137553602604162, 16314155164640857713960417655857498051596153632474886680423284957133775223285]) - cy = sel2([e[87], e[88]], [19301014021919583977567348438857464752913991729661145830439339193394619822674 , 4081042960569737826610743202667127127506276066439423960421657857551695871422, 14520831020919654323745478654766278220911435521609622705053803095115677276928, 10347543397607839527923790122253286529883327940351684415635401368115385858121]) - a = add(a, [cx, cy], context) - //Round 30 - cx = sel3s([e[90], e[91], e[92]], [184222443282411811008485293978090987184574946550463281113036487016967683795 , 4323925196392247451702039714921386345420807454721539995370304513020371659426, 2346825777983317939724845287942565740027799801885272779028341294742495881964, 3497425097320782814346947506403058330145264032565372769682636446824270312453]) - cy = sel2([e[90], e[91]], [13850322095814274715426304026104710047724256505475254494587134658322670671529 , 11511819464672461161880080290029237185728360968222698390620899743097045452336, 8068296678016129536739401811575622149523917897086227154769231758295218255268, 10263809994502353117991909442849926729413925087877766198113026233378613424956]) - a = add(a, [cx, cy], context) - //Round 31 - cx = sel3s([e[93], e[94], e[95]], [8995760760295995916308082490351740974639094331313720900267671545759667549796 , 11019493928623991376174717464416885911906134873939034428175124701672655752839, 14017581177532816290320938368540191606560126820406006677979240977503063555845, 5992767544073504039822155308781253229334004182511050716159238341577147193720]) - cy = sel2([e[93], e[94]], [19514976680591593876219573359164805119998241765130948583982557052811782267484 , 16839145730766072636625126513480100227916490562760284965681235183731245254947, 1021292692554672699619028273609664837317397089685876358558294458673381089032, 19705834660126914988160966717581159186486910721909298688364547098333399879621]) - a = add(a, [cx, cy], context) - //Round 32 - cx = sel3s([e[96], e[97], e[98]], [2527638437523893015660301196665088766965588386392795314680197258969354623363 , 1138471124880305373267488994599338604626881130398552196301155187554578496993, 18796280357765998280755689911684961342287093510307513491082157499389652187596, 17845424627755166990290252831103404879406229534320972756944316138691932923261]) - cy = sel2([e[96], e[97]], [19210721144465266426749734142673856566947869352583355496554030705736452071361 , 14313930380744847001650971451811594041740544882894516063775993860263195402168, 21025107892840987725102949502655791789935181032924916608477285415225533245973, 3555509537083802658278452964512402851284368794121767087246797342866139363946]) - a = add(a, [cx, cy], context) - //Round 33 - cx = sel3s([e[99], e[100], e[101]], [15846792621646742652974245065938230651829248095884295067743275618391603947137 , 252268672903219503110064676037004166486655891926695090023400798499584132445, 19530459807361347014390846162868811023755147873522489974990781147946076957319, 6779173153401014221878658847395058091689669042378445736327791547741105926579]) - cy = sel2([e[99], e[100]], [13124560942345768357314581178595700674622208923899518932907915338485045148127 , 19427900801187548763760894641856199686412861734645157290016060446141874396762, 10578265528433465376709803300626505953445780532420709942597293441366167803051, 2814357683688249343045032287308948679662030207205739212100871663137250686972]) - a = add(a, [cx, cy], context) - //Round 34 - cx = sel3s([e[102], e[103], e[104]], [9161164860624082016500689976633279187120278305601384250238486553068325633742 , 3594465641083658357640727503005755820863340547313408576898849399984296404007, 19745546026637204577602881915206827000693868119693662890799396502208696901732, 18116250696909523241042661347132525872828324429923244627289119813508105665938]) - cy = sel2([e[102], e[103]], [13685063021736046635507535227140671955502404587270095297507854657927533098685 , 21481850865118949667886934355577641333398731968912180643307092533138863580900, 4539145198976864585367021826448478029652078179409326031693175016758410731544, 17461973876416788164599136875394849349337761082750935487057356278682772411162]) - a = add(a, [cx, cy], context) - //Round 35 - cx = sel3s([e[105], e[106], e[107]], [13763732875937305178862849318112327966371606623409616602363024527079535241003 , 7146728911382113235576196126361394323865045988036623175328726379662117800087, 13957018179677684863250069220406779871369347949049594304698838627334319400324, 2983130106134530061974606593769911479536904265326576922594002168086009867582]) - cy = sel2([e[105], e[106]], [15902927258231569893737955890837667742457214947649307818302524420399149241212 , 5394027336566373776896911094388660738090625577337970061356832815458464701108, 5175259754491075858870829756483758144360263281431531384832593797283930411109, 14151565798137996208654994826049340981954317623288904943712618832232605861595]) - a = add(a, [cx, cy], context) - //Round 36 - cx = sel3s([e[108], e[109], e[110]], [3511208839914156996602850728297722115315702089624058744395068873552707949103 , 17785314838779826411805999953134869098297432649970533754606824062794244465005, 19568380235187862245567915799143793188430865272594403468605211965296271194922, 8968217637384711708369798047935037549991275897411766158377778716106218907618]) - cy = sel2([e[108], e[109]], [9113093883676083424918242033136578270322417571556449454840754893578163802387 , 15195400406105586498427391734410887774383134313041084245786188708846588107061, 10391623490262978616498794103188417653962360594423044385370483010810406454393, 262198447430650388196958319338915798147458757989176286529479967365139093614]) - a = add(a, [cx, cy], context) - //Round 37 - cx = sel3s([e[111], e[112], e[113]], [11522295231047132260758343744179190547608150890072723735296048871441325064339 , 6417300850099046536319790332124930285535196168151466782463281196540309297983, 19137291956859275825926699344301804549568562573423342909926469403211747707345, 2774443339156228722046927543564067034026765236710736809480294993459012359549]) - cy = sel2([e[111], e[112]], [10997633658189180813501132314065688584832302881630691645920837501861598079973 , 11230602434226993956802641296087754248529927465162671110571036062223097035285, 62131588140380451567557177282839666875193860544849125919004473298285110712, 10450442472445392653150568721579575112681026302736591474982185692600259786523]) - a = add(a, [cx, cy], context) - //Round 38 - cx = sel3s([e[114], e[115], e[116]], [13408931465122001423751414891302829165042502658140645208130973182525808774770 , 12919550455861565687920656314018840423444710872112059576718885637461594199393, 8902156077182438987081535936092318477847851529427670854791439040325983142815, 10551142139308027026174282362670932774470751296642556552082094389923387853839]) - cy = sel2([e[114], e[115]], [9267742985382681478817853200119409918969418222977519894367804134923874406267 , 19027179442258820884726400809066833518658247567670360715860243154343698445860, 18038603127894002689531978859178109088479567097675385814346786297731217235404, 14150146649091182389991766732798336665028567292472735778013325601175132243538]) - a = add(a, [cx, cy], context) - //Round 39 - cx = sel3s([e[117], e[118], e[119]], [6540890698262697218677202035403667770177820101154223149908034301445959517274 , 435497241504544923461214042595209510655313029058197261483355541334388444061, 12972419969438465538309509757262343703702203355603454637962110103300326018994, 6669959829681253734882192282716498450739929798663147573799606668374867628160]) - cy = sel2([e[117], e[118]], [2642034845320222085946302229307945658183260378358994660373441270519802248925 , 14736341083198246245608013213787697485596965707560872888430876049025049794937, 4329454540840640926293454385395213780440355759242417354895666807552226740059, 13390807756542084619965526671660454489274096296730210772303889980314835989796]) - a = add(a, [cx, cy], context) - //Round 40 - cx = sel3s([e[120], e[121], e[122]], [3375661072576892623715175468380800047905893262660913295358697027074087217513 , 5069202507845220698620539676049456933089654255996130713693017872693588276345, 307360032529211257870367390878851528397463530836715039216723323169226021440, 98081915276387897864111573201930613825497393423677224354881280134376446888]) - cy = sel2([e[120], e[121]], [8987539541637688797931012030256009083390767313291834963652110291129797020941 , 17901947618091300697708370389296420066544823878914604900411880276648078042269, 10639219577401234864823685175468874052621402569992677814844863434253512890795, 13240331547980137691596357784155019878384406802888737259354896076218619627328]) - a = add(a, [cx, cy], context) - //Round 41 - cx = sel3s([e[123], e[124], e[125]], [9662184175454991631880218147488300829920024817382740712599708905755708816803 , 17771020629416708231961523003444615645037663660747267683766850455503462282265, 14494133870721701214401742677540032810309496543890589653927595534007509078658, 16561168866198605810694591274909829276030780262733890202994760647724957996711]) - cy = sel2([e[123], e[124]], [16632142917625566129622048663670437511136716491293457317746859226945397089536 , 18400270017828347077622860778898029123047396355399577145984944065126581795849, 8353334605287102455944569500604056116678191817084945684486328539838325378046, 12147075225903504606648888869906750158496142784038841529413244301117587609138]) - a = add(a, [cx, cy], context) - //Round 42 - cx = sel3s([e[126], e[127], e[128]], [20252038718269174556829574777069549258100538764143309785207012647062643184902 , 19438750079062162172414919070069193686275943617816957878302458952613247286975, 2739523700389893370248547110285910821118647890992955640060929464309561828074, 18986163209792052202203221314221453057559857704913672555327882100075093616752]) - cy = sel2([e[126], e[127]], [1949203652074521007058676904301415827566224382778317340432698169556879788463 , 4017921177690528677848183821427142247358574441895228503258380087834359360501, 10532220115833479369586881444322308530349489476356817032718755221032796227335, 20767633640647488765234831415684490207979213320475813611233243261000228414020]) - a = add(a, [cx, cy], context) - //Round 43 - cx = sel3s([e[129], e[130], e[131]], [13929197264592281054662634434397205757522163835293158725199610804948038924930 , 18983630674546465400919161958500748450652609469567091049588112148279229509416, 21298720061922244441608259922072286340766498728629540286898859613690667559954, 1255771444824172694387038994365972934222854858110644765629654650968093841237]) - cy = sel2([e[129], e[130]], [20928589942441069163400310179733448745002695258624629275677130484867901611592 , 20945151313192869288039616217247173168964585800167278953053768079971885757820, 13394130995265898710013904122336137332320804034657805114241934415456940879520, 8345380486550648681305351465341710151021284756322349929795845243989999089313]) - a = add(a, [cx, cy], context) - //Round 44 - cx = sel3s([e[132], e[133], e[134]], [20820962511183569148336349677594457306122370638840390080208640481304634109972 , 21271204223521868772910817161761075423625575552213963956907846089587689594662, 10733658208915381791180435538254458430504966830986768682084274021501716755708, 3213872100717631866873070659546947812880485326599459130685149408092349854866]) - cy = sel2([e[132], e[133]], [18802948623154501291575097526503171935564067914914679326677986205652424463305 , 18671196065143385675890877955428696189287618414074487330442057564568301653630, 17500512499632911097527623128158674292347613137609268450560746154383855656852, 10140717739675826292242942694935483711727546989965783109636404988746901047250]) - a = add(a, [cx, cy], context) - //Round 45 - cx = sel3s([e[135], e[136], e[137]], [14908874845345243542374913242177817956756346686642792660468745914078612972964 , 6494892024924675012540500602558430897039227451488331729419886431227425262471, 19660118982815103063271284609401904064050204952733042875484811495633642263876, 10404140614423982473417062438060653585074743419249328530274575800693260655367]) - cy = sel2([e[135], e[136]], [5109688569541183345813508363367270401129385455666732942384933494548859595681 , 6488452587861781859966899732568514074249818909310744177483425914897141192195, 19759144330570995637436877834773866770106917696169828968224667729682932948543, 19372158643071160860924236286390794017939077735118276297478085704446653404487]) - a = add(a, [cx, cy], context) - //Round 46 - cx = sel3s([e[138], e[139], e[140]], [1154476465911192808082307928347900064111325728833428891094393674593800812900 , 6647319020085089760145868568636007917712315513936955502164154733998378717177, 12584569464684026880899751873241162942166450853083376779447501714905643756083, 14243280142991602029691394563175478833697759877979687578140951697024930901167]) - cy = sel2([e[138], e[139]], [6461899930945412323497751736369894620103555271239754245787726192367462376648 , 11218209351589240489615573530963044202098579836550413344228327749253510456169, 20533060824796367399322624999408451192171574545415433951669661225068106752784, 11799997625790604641690313275280372066913716290701708574743226300595877165728]) - a = add(a, [cx, cy], context) - //Round 47 - cx = sel3s([e[141], e[142], e[143]], [3106120971963814637086817095821216892657807437909030172048489357608690908664 , 19983788499223635315597700897580134177379185544458724791602486120287361195709, 20011311503290782295958825256275853340402122848359336349363185226433870439371, 17061518479999755720537296647402074631690029621158571296727706119729187756044]) - cy = sel2([e[141], e[142]], [11655780578227604806047758025034240629153798954712964172707380870816316797993 , 622054523287271568164593718522127794491026889292924398674394690726823527200, 16135285950085594062254918487673085571627312978983012587993350339361155816604, 16823182833153464340537049615227906529068252572342151311965980898836651237386]) - a = add(a, [cx, cy], context) - //Round 48 - cx = sel3s([e[144], e[145], e[146]], [20374356410965803131887119977813187747682102078262988894186807366145009893312 , 16140790886679277390055909624981354111468382311692868339667095804914180995816, 5269708933005858910719244518715051229221686961187992215177561544872857207052, 17003669964193566226265890987693478032205879390270724431641892912757008513023]) - cy = sel2([e[144], e[145]], [15298182760377768633156209223343487909782393543670382286190369588693664098885 , 15694313374278606393252570906724471325000910752891934797182427274800382725179, 20211423855194801900153066955584657931131527051780164510917465106404910099513, 15455288363376670716062020330944532534047008363514636685826622499678373390425]) - a = add(a, [cx, cy], context) - //Round 49 - cx = sel3s([e[147], e[148], e[149]], [14165004713755765453589527153323887724160944086658242248604905215519807263185 , 301131970962481505862420187551701457358785403147894839379498410579773149817, 20703780629190814394908582715811669803434202446164042946560257906844612159868, 12367443634404793487462362639029662097550355799821945744713867599113535990920]) - cy = sel2([e[147], e[148]], [20401715072789557220769413113920881979690352159560582443280493351937640089943 , 9512744351810164617160144481900582699060463555523641782334998030336637339295, 19997026788203221539856525472799656962300551306251956395441891331721763269878, 4420107516401930587358239495168429945976230331917756712920657983670672632753]) - a = add(a, [cx, cy], context) - //Round 50 - cx = sel3s([e[150], e[151], e[152]], [8103748105126096403620617531109165346111017883414253359146860083465308290054 , 14803748343013980101691104453457628404765420707022107332787520877316491921572, 6553189032217952509828188229822974795796651131494012230703062173727191718256, 14488140647832162063035434131927730449663617866962750748399561354722976225897]) - cy = sel2([e[150], e[151]], [6900602880532330473224374524196761198151861405485326291615150754345009304151 , 1513115647408875522957756488493462370777248725072062752756727843920832160085, 14896301840535712091808125164986771300932651268478608922083726618785610993431, 18048817115801653510192862998462822947761670069362294686696577131702147477504]) - a = add(a, [cx, cy], context) - //Round 51 - cx = sel3s([e[153], e[154], e[155]], [382543238316875203894587902417533689378617036331411163099475938996384971274 , 9619454944964330535387495829359535093743583319913348616872361595592109685167, 6081261874729821958303230238004699407225832699063899155741932401034312247576, 3156137884201329913786702605630625537320273632812696416791152392474314037759]) - cy = sel2([e[153], e[154]], [4793004393185972052681267640894832507973895495734257655931836941627180322533 , 12524126851245821931846984936446041288760976334671736634358685272033969216980, 6277340058786227516467028124755004985063566609742747175031180490042372405740, 6981569030046806591634476164525159834865090256544287529201527685109358245562]) - a = add(a, [cx, cy], context) - //Round 52 - cx = sel3s([e[156], e[157], e[158]], [7242980429824960501440666232145028986161691674990466362832703971174936796830 , 8045674190780012690331364750465564303458553754280502177743436741257674712579, 11260599103741407968666669605286104777635431193927929500939820855376897097946, 18466264932289657017935069178634633780361979903681010210726608765753592098197]) - cy = sel2([e[156], e[157]], [2313823382391584526084833833122921512331314230217820828722208559851046887792 , 10089801374498501989652677350203014944991951797848003015280234323125565001040, 17328843896403558624774477961071623822106890748911687259696765820336743222251, 9096128104648798569037169791537313868030583174665566146242611146033775655076]) - a = add(a, [cx, cy], context) - //Round 53 - cx = sel3s([e[159], e[160], e[161]], [14129501557712467097681133312480956681237794589418881140932742431414452181802 , 14215253979300894109266393937905007744674886266134853669970409340633353105422, 5101954416353969027375336730301151965881345391948426977373049227857281866232, 14576353231486654843487902119173617652532372118230138091256904812874365465828]) - cy = sel2([e[159], e[160]], [8967890713970048745032869372462848543847652746940083058618452105243173038725 , 6265601060440963621915827684472693851147234848878380918293598569151688236174, 640827344679117882936589383352750227742240703205324868948399729377934123492, 9724475542168570127797711494687143027178927970205326782155651202256929792882]) - a = add(a, [cx, cy], context) - //Round 54 - cx = sel3s([e[162], e[163], e[164]], [5456157947126010471455582105823966618048439614862840203794276433144936442303 , 21043218890179638595653930578748044093798652379401035786184926212259053133276, 1927155268257451951778867733460386031395807546286255979317875653435797662494, 2742904689169248143495331827109449907113748836918731412006506067439664106654]) - cy = sel2([e[162], e[163]], [9440520397717291873292501513394144011971438675685104804031688857727475979708 , 4417998885632129975756353073742958617120204855631898102096412742879398656621, 21718244289007192530526626848367390261419399428442075984244560471039861817138, 8877177915758141474927139565405950662745390581859900899551672907102924557478]) - a = add(a, [cx, cy], context) - //Round 55 - cx = sel3s([e[165], e[166], e[167]], [14850732473677774396477975866215714018387310838284937771253941847508860390570 , 15346251439912975799100173523179670100616030950715800206631108275859894555954, 9806744113621004413976521475016417033548532640900224199389230684453784278689, 21096603979133316753091339975348990230540836494614368335651248862844085270520]) - cy = sel2([e[165], e[166]], [11812452402407343928752680921354215607515699690942611270817873638995622443255 , 6279013985783386608484242724725362666241553499782119548714289191679033556648, 19001277736410456807324578202368992701796359861619482537978016830870842626762, 14081519926521914451511625869848591232696520686473918498999632052868953710854]) - a = add(a, [cx, cy], context) - //Round 56 - cx = sel3s([e[168], e[169], e[170]], [13157890071808158704354468737847471048810392369152727364639634059504126884874 , 8008722424616547903294828680672771630855086822683412918399539174241338981774, 18594694810411494426945160098830123105355833500416479749049639533195702072502, 3003039638546974941710738006242011804553647552380262745534233703293489168909]) - cy = sel2([e[168], e[169]], [893279927671356626449601197530638356692800493991878277093322197544680454846 , 13710236865890222581902901564951693313216932700203676104342205227571583021557, 11991140728188265308988894689292592177761583244141205754043533415013439187396, 7408159576060936012801497750876509797959683640624248586584358220473720101773]) - a = add(a, [cx, cy], context) - //Round 57 - cx = sel3s([e[171], e[172], e[173]], [20379496501734200220097501155104742700678033944324898621914782326376426827694 , 5628902661740155176800052287728775683561775403751721906542502141173662773805, 6649334930850298644282280075473454376493217119135753313843458230202317946465, 13953386616146853105384995231337773651826685901371822028427880819484312577968]) - cy = sel2([e[171], e[172]], [6312536910770269621417292581781438152243262819530627194840110225345012746549 , 6128625960467547051042766267966540761259574034224991328868848127157477007514, 2178504154437332931470309748598630309367590073987406533802402874933913898875, 10049120191768569519993419401578117655266529530568527176008678950298967775522]) - a = add(a, [cx, cy], context) - //Round 58 - cx = sel3s([e[174], e[175], e[176]], [14193197030749382932133736734505537242924559995077781886176225169837220402133 , 2565010016572214675455233006763278152319972391059007175692722972374012019501, 20022269140157840221511080273245661956116845958170472382643581298431129105222, 15951592620529204477279907750991493798200861674998832536410750610279414881478]) - cy = sel2([e[174], e[175]], [10015961841973388881391587018151977950817576225746650865142918877894543270446 , 10962609190943341745700082387389939598903593214578149618076217369020441344245, 10875728650787073188338824979727792178460025858689164586811311106195554874546, 8704250736813220528338393230481759654328677814076110220308209376595986509914]) - a = add(a, [cx, cy], context) - //Round 59 - cx = sel3s([e[177], e[178], e[179]], [21185904177969045625821216347084191287459806531017721293624058180265336503811 , 1250611256248923800378335492392268625608584743125298517147184362502718557754, 4732901842829850758626640836087921620095030893254064254821493648172485065995, 4686012912505407137434711885457531064310116778761775095814150050521297721079]) - cy = sel2([e[177], e[178]], [21681922300753515822840018285496181872470481450737464910861242457369823926925 , 8250546098596619229605270054781796306579374634169772718113961166155976799791, 19064654253935902908485961089200674782438523882800790190859631804189001729500, 7893084863238812828005589178028293328994403260619345443806395973318698162130]) - a = add(a, [cx, cy], context) - //Round 60 - cx = sel3s([e[180], e[181], e[182]], [14071560871369419892033259843192185467358801846474749773427241883409830032328 , 9559459046618636497241065316366978002044190960713451216793292122894012900863, 13031319565545666906249801044337083380860313201803429372439840529717343742035, 20069400641162643493898109922008601219601618686364720341639616051841829074334]) - cy = sel2([e[180], e[181]], [8710777380190521326883551341251426052007249230093350101154473409247609882825 , 10439377650670164179707163339178975058403688089785136107598148495986084488509, 20130072726000251358667317961033491205160472226244307309389477611437739154303, 17216059825244204015919013637129845877195519789582013765405196142334767977705]) - a = add(a, [cx, cy], context) - //Round 61 - cx = sel3s([e[183], e[184], e[185]], [20777314589605673759170070653370407645867665889025835324139659856710113131826 , 17380793433135473426803899659206730936771330488910864786997506181753180852018, 9135535394443552083655851762956576299400389583070951313661035134759057889658, 19259342468126216922767538099314197508403261200862162612026099962268769453780]) - cy = sel2([e[183], e[184]], [2644721599238941245572401477946144870669550581359063534170381908963477379532 , 12369176861935895868206428376006904712013007036288222495431735574326142454609, 17367574625533031619575225680253098966157776114681359698904430545328078639283, 21794479452176520273231597892096817659539111123775968164861961429589103329517]) - a = add(a, [cx, cy], context) - //Round 62 - cx = sel3s([e[186], e[187], e[188]], [11749872627669176692285695179399857264465143297451429569602068921530882657945 , 31939593233430950996158270398727464286178387866161404769182205304632811436, 6016890150518491477122345305716423891405612103278736006824977752295838970965, 10857254852618093631105790010825256882158099527623146563961929227148379359444]) - cy = sel2([e[186], e[187]], [2495745987765795949478491016197984302943511277003077751830848242972604164102 , 6997914616631605853238336322733192620418492595988404136191499921296408710465, 6173428954671571373132804754825927617043378457799815000168451967196664752847, 9007836187082518685036356739793187792845982511088020304887245789556567564055]) - a = add(a, [cx, cy], context) - //Round 63 - cx = sel3s([e[189], e[190], e[191]], [5139361255050232661773452561726452928115803730344567411456642256556217045338 , 18849283619433745348738480276785423370734769795033289874458118507070173353564, 8448578350964247311518616492977206693278225803594287158372550008714482924618, 9689086950770336907190180706142608582993499523814136266854852845122214734392]) - cy = sel2([e[189], e[190]], [14036051510959474100046039284978060652197630794277473374328558492372137493500 , 16611708132761924749528167866816090876717761056993928787802780141779996313373, 830643686092782069152588625317289527987176650776268015346372712951408738404, 7124577892782407025863252010240336830171667706358033009166413008136074540762]) - a = add(a, [cx, cy], context) - //Round 64 - cx = sel3s([e[192], e[193], e[194]], [7037199118537155369331275916815326054696699996573020862644806346516390510132 , 15801832773874273151484928140234822912161499004629735400320792200594998558674, 20529919447890597649764739102616587236240564012012882223198985848792346137419, 15587579342628673804059001440002406839596944474602936992474297171186661645909]) - cy = sel2([e[192], e[193]], [13107688056462500445700480209995877016295689081542565992250464593152667593220 , 2950999836230463387014662253708191376901146777669866592618407913815214817829, 4910645882425237270468350930391794068554002250789220952036477599584216368730, 3842197005807929553563656299566067039385580918555124491435963737335985608367]) - a = add(a, [cx, cy], context) - //Round 65 - cx = sel3s([e[195], e[196], e[197]], [5946112335249256697077095359378565725733629742750694340878812663903909175901 , 19030634249222736450152769682445487635301904450722490014396919999971262563725, 20272077332559936653726679368964023857291782018546895109417787179027229259529, 4325773325239231432990045180370600024086140077952119719002873860984820794777]) - cy = sel2([e[195], e[196]], [7559787099338642680034184654424868894988928943730034769673486129058256478240 , 14955054800505659097184643689663447282484820948805633199847088945313706647256, 20527315092050743721874398127103128550881291654522271023332206474058940158292, 9254615232744118309709861811378827051213745889996697483998530345751148041402]) - a = add(a, [cx, cy], context) - //Round 66 - cx = sel3s([e[198], e[199], e[200]], [41373522534463253583709483090344938032869463670116114182911184041610044395 , 123058269904779894306385100149700584700988943576532400555257363214064615908, 2188259327903131136942811179577591848088244960706164332041753317001971084806, 5677272600001855408525885379297081872841669910685379249005421935936405438326]) - cy = sel2([e[198], e[199]], [1812970364913777725848745565574644898635129603904027984751613694625700239455 , 6325479481133126048154398075474627535983053143312386360869927669212098083218, 13018920334214076613442336156617958094802950850259563883918734414290288034687, 11007863126994999194753256186448493793850907406765917922947224071691321773988]) - a = add(a, [cx, cy], context) - //Round 67 - cx = sel3s([e[201], e[202], e[203]], [19366353265983664793480214800587120487923062015491759603977854723148315579274 , 13009712389497066149642205706505053720391552889715847781477674095579012684216, 7540090586243428109828867879678893096981460680323209865296583411528024312326, 16312880719251887899651071843693753472207446322138586240016038563189666076704]) - cy = sel2([e[201], e[202]], [10425762558101863677692090103799691698591185440858290129753641015260969124568 , 19889759528114345474077603906066211135049113446169104039752988610769598108616, 10189577411425365730046714422122931951193107064366232919940491025624263274830, 19402847860324611226251435664012558569374211845205502575728141649693622181131]) - a = add(a, [cx, cy], context) - //Round 68 - cx = sel3s([e[204], e[205], e[206]], [15647575844595805283124278572298605369081553302159286302039104118434564547757 , 11119588224460846619648329471078205852940427394545403397495758589586019867123, 11531502595396972280500527673404404955773795456604503116176223280757803701142, 8880302652736630728773712083983401143315564427649676162399333300472018402820]) - cy = sel2([e[204], e[205]], [18121989769429113110431033241130632527148185431169035091659247063715924437727 , 20873727571773157361636727287434618496229040659202161464546752313173048350714, 20691117161323169072636575178583071560333787206766658873639451682743014282486, 8341316767034979343476640425183870254531797329971610276320314018660072501097]) - a = add(a, [cx, cy], context) - //Round 69 - cx = sel3s([e[207], e[208], e[209]], [15099126396506559307312697471585164108461593918632286769972271267945539855806 , 19719992822745709208744805037389314455441129806628318848823336999297717461102, 2498623947360180463813005839687911187525292314091943320262937967401409761873, 6773513521666107580427042608663114222160509705880285715315137855519926605076]) - cy = sel2([e[207], e[208]], [11185464183896587792324099270269738719144599552792757002841466742562118002961 , 17962378754832909648632213279341274522205662106198070463591287770511029247082, 9572883626752796327156744085207279145562604122052196885537416403686418306743, 849739335033117039567862203783008236118271414428303942526044722712316390134]) - a = add(a, [cx, cy], context) - //Round 70 - cx = sel3s([e[210], e[211], e[212]], [5586425841805464495367763159434170408121119147683098906675715851224959199555 , 2275887592294698256371035540589451793263643729528648494997423042939590025265, 21623018362589173579186020601617142922337607155324626054728009524185014872882, 6470935377837087985284657580709150204914393986124872780110914178120147824883]) - cy = sel2([e[210], e[211]], [18977748529759410811480134751116373952642146764796083016667926272252310801539 , 15415054474257926323577643558627142211566179025425425674112343915385225979379, 10178696720359974033063364767044087765079200964723755314869211737985682962880, 2751262919149939488788372835165540688204591943865442185170575019042791606144]) - a = add(a, [cx, cy], context) - //Round 71 - cx = sel3s([e[213], e[214], e[215]], [8067396068830332270789178613335432253659758303711969642714931687060160381303 , 8639011650360344590794984878540401640139910601923862912593792315052343319076, 11233915498048422123675368878285943174009257862418242010192825609765986035356, 14474288438243449444797392475230229280689019808482654245523987676777400402951]) - cy = sel2([e[213], e[214]], [1109389204114118726338211511183391561882818362713716952828416479757048480713 , 20658495580821728113676289889282525822016081521980495256710356417074439523320, 5734616557338566574377893898300784804059511397655030429323489999855673254133, 7694030151585859685333610687574701561418848021817379115721565206849330185976]) - a = add(a, [cx, cy], context) - //Round 72 - cx = sel3s([e[216], e[217], e[218]], [14694205333290671963708923368506587408024223912051732033761240288927263651380 , 16846840700984603406007084554481852964137248522784508429412010549513323188912, 13176399412773372610094105377631574988462669519590170596472033646615482615262, 2687848140625094867763341291336975245615611233615607599401834736964978577349]) - cy = sel2([e[216], e[217]], [9656049051507081163863869851380474393220762381365090138663873299937439711626 , 16257833452680722743254377629669121273261457821544261762335781528496650481193, 6465537052899418297534883094198381748729828452125250541158965933076691478294, 709697610986733714785106299677092114124154955937070541190663241187641683175]) - a = add(a, [cx, cy], context) - //Round 73 - cx = sel3s([e[219], e[220], e[221]], [12368397247649882906953915991250714931614715588424094368585746160811998953306 , 18782888042679815293214947449937714827609414183597755427793821090364126288476, 14980906670860851104998617553690749074165805207013703141953243482569349981523, 6579728809126224271038924161669519472291072114357057900231021883849035745958]) - cy = sel2([e[219], e[220]], [813793955589589118694666569995091571992486583635127942664119751723536369919 , 7944299604444967298799338830762202580774561040186193713045849824532426689590, 10002642178009570948907228870686621440930898426698423035982221525801621370935, 8479337223317874954343670583381865510386888037444628897905418707487375421325]) - a = add(a, [cx, cy], context) - //Round 74 - cx = sel3s([e[222], e[223], e[224]], [7187732531650016705045248947412886871494880941757180032721434029527647591174 , 21429737681997573327768382790700665701419541321736653106996131182050077581533, 11836369351087123833634897021408898134248512107687639835461193259880629295891, 19132784475506243814038464623366364810380933540097619300595341694560215897043]) - cy = sel2([e[222], e[223]], [7505964932526905326140236282846132917485872002527800757209057356562826370965 , 7446191000078603169082551991705097881255381261806164450828019975914186121730, 20501368217451607884813098738754813918145802982055856468691458112065708320700, 12111360534733555932929570216465933882611889545473508372687771008732927246750]) - a = add(a, [cx, cy], context) - //Round 75 - cx = sel3s([e[225], e[226], e[227]], [11880592453253678945312808709337779570677968939895786745513483795196121148239 , 15885465855717299709344092447684246292163545547216436459368792952573638150871, 15785265541005027154032372858808930773051366971093462129449868653918773012805, 18569197812514885943202170611076608358219751234067371040250790526837986392838]) - cy = sel2([e[225], e[226]], [19319714983097503154896952315362236888483358620825042533226116711980128027594 , 16203396727641772481371087324762669694595077074099718953937599120235089562441, 8069072007055358551280258194912706575285364270109077890462380604843344248137, 14879918508369225877688675007526587407926006842700210091106836056129459129297]) - a = add(a, [cx, cy], context) - //Round 76 - cx = sel3s([e[228], e[229], e[230]], [4665897628623235203637312232323957679483103295583092141578808282040205079719 , 13624944208440724520944284383225072602905876122550187793344788447894380752405, 13240065107073736104958720757918020581159288509346627802839384665867212601652, 5404872141819776433203748684385984691445987755176034496638153799038857512389]) - cy = sel2([e[228], e[229]], [20713846021060085908071105513304556412817630308151607438714049866357354550752 , 12308156363070414998141304956459569678321247441462175945058420898750569812289, 7869135919638822130359819523186642202243136255410646018113662355856102696554, 18106721900555088660857020092432838491684499647468676099930405315728768226404]) - a = add(a, [cx, cy], context) - //Round 77 - cx = sel3s([e[231], e[232], e[233]], [18212889377782903846034117170355855193339291343619773736161614903123505780500 , 5724371935927035469891307360583032289870105083635885948626519084327837492412, 15018564556029978781532805643572668082137657619876811702006326742091833640503, 1980690392504623526106436839420486135508948878537486163191798777558809427629]) - cy = sel2([e[231], e[232]], [14150007145691261709583376556777715716099818143565185837820917588114159379297 , 20022624235079706615759218203483775626475427851084411515081825296526003331089, 3653600812499303949236693031235500821149221426419723829534939359247593779698, 17687818220966506140783793822520601258809092691114698078370817997514472088683]) - a = add(a, [cx, cy], context) - //Round 78 - cx = sel3s([e[234], e[235], e[236]], [20014362392122060372382978901186124374461219393111624832280409989286374019151 , 7678149165067745993890478281145655203076154350573466295728882151032664933813, 3225698435546178867794794576435022149554488042976954865856749306115721077662, 11309031064526492555710928277445241789558140050876975815061803061421298770441]) - cy = sel2([e[234], e[235]], [3781524301363795687584984812832316590367643113392401377547409393858835211208 , 14954378542264966404669454369751236758988379152056658083888298000396867621936, 1762346050163239223923110798598502612894079706374187891044283390513959164382, 4511820337785812086858556857918524260240820667203320876468844848816354037596]) - a = add(a, [cx, cy], context) - //Round 79 - cx = sel3s([e[237], e[238], e[239]], [9734499467834650890192498500298459962067559704398257089549121433441674087115 , 5215135617552133686060655322881340267001697536486897440412599806944209294580, 4188240743485809003397687109987123955188618656835900004447532212211334022150, 10646753846009034357734238656245532993332944314059322522045789305478499710981]) - cy = sel2([e[237], e[238]], [4354361275489184569727883669567924050940590772506719250562939951242102459556 , 11812679101253609883065116716426172392592451529279171373836703114919477018303, 15938685241828674681356945591247179905945286496762161102822537588243702016335, 2396399767043799129388585002615296373717040489521252489057941017313192676808]) - a = add(a, [cx, cy], context) - //Round 80 - cx = sel3s([e[240], e[241], e[242]], [9547054830379311239093093214427099367592481292385809745992166194109928893132 , 15809211758984123203744250589992081971737344928666499432318524828207451637502, 2317605133926452505125489082200124096354438531853199813212363802981648616781, 11720218057191867199121604823871387192503455956722025424220873115151171617846]) - cy = sel2([e[240], e[241]], [13627319622459471863286677434492810110443625239619395014230589374758547978269 , 1429116229161069264517866355097922507661063351137334983223517731193665190730, 8760550298269703331457356635709373772631633074463698514870757469189354319951, 1695059580774200437965405056230849147697820569205516838038543601601027611172]) - a = add(a, [cx, cy], context) - //Round 81 - cx = sel3s([e[243], e[244], e[245]], [5462734684060346793723051717116621327144354637585189012464556861789633254735 , 1574368603481037100592052661337337694471748163849816976465511323905498090898, 21017620690824743015216528248522045704369427405753453300912995325024062710748, 335774257251677761852834523904277348100779994383726453798657085528043830396]) - cy = sel2([e[243], e[244]], [19956048369873968081515874523485925798105246605761695905870795560621002747577 , 9838187823381646970305000918713399614038197140004128824046441620722100628627, 9761598443789947780667845618272433395258577614354457312915153694570906468084, 5678382193061301565104967410106463714669588791192144419019555111526838349597]) - a = add(a, [cx, cy], context) - //Round 82 - cx = sel3s([e[246], e[247], e[248]], [14120934246971429747829618071104732571014495017644755746350410437296386191831 , 6321525285327330824512104449106606616844709114576208465479970358050873874349, 9828948304711234867338016094087396323909457869737239406325931677882463208355, 18078003119304519959309175940845224181126936983821549690560235900824217790962]) - cy = sel2([e[246], e[247]], [20946993100078048703890437478651577253995893117657499778417778292965813281806 , 14356404021232332461217625395600664517715960389258731685389867303545696108853, 2810577432005044954032138045179699447584646279814848461184496089430514835598, 8767040452903340993130881597424027588451974218686780194782289690479045090015]) - a = add(a, [cx, cy], context) - //Round 83 - cx = sel3s([e[249], e[250], e[251]], [10074124480658003038181060843544012751655263682971006047574974839001332519369 , 12077899488247602319223956898393373607365192976733626340271805296106145121355, 16135938726601100366620437452815649119119591825429317780601932003124015669028, 8179818941824323394614877573129531443686047058703515433852568295536575458823]) - cy = sel2([e[249], e[250]], [6742523042997173838799423244280133352249230789995302906545025471831316165384 , 20571270140927253125417728386763981919687051926731085366043566448009069227191, 923263495309221023264076470401516657594260797987069910555955234338720881738, 10846387476002903807347429282866412191160400241233297902208546470305682775632]) - a = add(a, [cx, cy], context) - //Round 84 - cx = sel3s([e[252], e[253], e[254]], [9734317150772506967195863825775613184177780587009303743393397724706924797808 , 11208201130011695436334652728584169313726840614571295516236997046457697153324, 1222680486642983364052833343811429934453835860106899436901212790725638894713, 12019238493894483056724448289009076436822742112482573063847552596048227585627]) - cy = sel2([e[252], e[253]], [21086552119896541186107689532205383551960199801453516689016972250104900583432 , 3056767815025727154134820681013380076250249612276183869180162238277626532027, 8232281317297626211055636489579107493658454229617058760791605403582002142140, 14549672514437654184453326941604694948116368249587796119338038904533837120165]) - a = add(a, [cx, cy], context) - //Round 85 - cx = sel3s([e[255], e[256], e[257]], [19897146034704593618377175099239959996606643851373776355482440566659528393713 , 13567220274372260527197800746127305934893509881083589343644604005840555405371, 19175080795372179131749429828665039169211560827471558543841205575231867635965, 6917449549804522032498038894724900459329834531091410689621076525743611296938]) - cy = sel2([e[255], e[256]], [12223657826278264815494051932052421695129917274617530304443478482578919678308 , 8295548603728936503708692859047908287111164162226375098145740427985958712611, 6607229719664137890140258196376647042900642854569636028419328459816951119658, 14110421155257010376968111292134385106023449978845823063864491477811661996253]) - a = add(a, [cx, cy], context) - //Round 86 - cx = sel3s([e[258], e[259], e[260]], [8185677100333640041421355126903921619342273914070568426300075868606141405021 , 1670466886055998857358105826250955310011203741639197041742892893805477021056, 671638389102335040808130453738616724135371178235871000115155863725237535561, 15155007602444057841308084879571465766457754342497255444459746080732112337898]) - cy = sel2([e[258], e[259]], [5730721122742653576294802609542803235749403433458024692842251665338778112357 , 14898703166129675283863893661050084311561656604196737234704191900969087474133, 2459074141813559460216507737311533957327810551114696579502401763839835381335, 15516107503085209346875467061340145906150528515154791297494671889511125291207]) - a = add(a, [cx, cy], context) - //Round 87 - cx = sel3s([e[261], e[262], e[263]], [13654034957145907815962106285631017905892861670471883127206658577251723739165 , 8633158844589460452837721754446206625865140330878411953122575379370751622485, 10232722293127899126024059808155635562748968165573438955077544464410325913567, 15328263964181874734867171882863588382257876665732200627067485961683406281267]) - cy = sel2([e[261], e[262]], [14648234277430895067547661111448501238234630914838612427562971477472564218927 , 12394752068682518494797840832073763890437175762631359486643184011399642941695, 19427382571659868487644833684469199967640111942906298364811415181281091481616, 182598521940883711045871251162735110551301299145061787687905605212153955957]) - a = add(a, [cx, cy], context) - //Round 88 - cx = sel3s([e[264], e[265], e[266]], [10625366736090949097208784405733508126867531010210504034282606844498242195460 , 5745457912443473561064508106222759378152708028067817946740487826967842596074, 19720099885004155494384241598041924024056522066497340576395346816817691557959, 4411557748754390593675263772383003703921572549170163035845149756207936580167]) - cy = sel2([e[264], e[265]], [14732913015624058203205922728424826465278063568996784510238321594483738024116 , 8539999814473505400128567752428776172019356440581684960088711125461388816752, 8671134805346361443739204337860301475415660510460401138135319415884938499794, 12889649495366374604591900250806268552879620119403975808021738180701264567775]) - a = add(a, [cx, cy], context) - //Round 89 - cx = sel3s([e[267], e[268], e[269]], [8424620995080153959855099087384460880708718787657472234234125992142104413784 , 1213413054380708818479960383614577938132447492306231448400493113424770669073, 17993616645286674150803280096391639271887381916203322164869533675674274690369, 153030618728554031479557843767027262505356544554897273649773418701874030937]) - cy = sel2([e[267], e[268]], [8774350273413061850499929377371854983526435316805379820854063460345613579740 , 160874859222003480689240665151063301233791348742268400199413950144629148606, 3864981636983763871420661536128329698816776138190284810024785475130342429509, 8927799801878514388025533121285392339945739901708290822291826043102309328947]) - a = add(a, [cx, cy], context) - //Round 90 - cx = sel3s([e[270], e[271], e[272]], [8559837035180670877234803295116293964077309001575836599087921933374799946149 , 18335809791652365585369283816437201104065890639760635850904865621132150615442, 20223042693949477624057496950714682763488956308852238106089638364544757819336, 956531986282862630457073126978994765430652506058410664783115436243377137130]) - cy = sel2([e[270], e[271]], [839500690449928047855071514156387100713350925422279056462945330783580827563 , 16644736196961833445797352798716804869773621626799896168771841453493474463773, 604545836161644183235683876796430911898168138926947606928620724963455977159, 13372011982201734306725124438714782615028067496534473713140957917136368058903]) - a = add(a, [cx, cy], context) - //Round 91 - cx = sel3s([e[273], e[274], e[275]], [2094128027031828157560092686172909842260483168819281235210539106189673022187 , 14831470033363035728579660771199958641838096197597230010879786959469055433282, 14580113677826055589909107333827815551732916495147612562237413782243389891044, 21457439024195964947733246659608329461028391228550531897929776149059108022400]) - cy = sel2([e[273], e[274]], [11349460624897126395359735030876451695289908168621129531254166231469594999395 , 19428708736392770387243553726555356520800900418277262898221664159221843559913, 4432119977004888069457445133143529511285856348699582219607694824086497898807, 9160542608356323143471297830883618199584611885676024272763585312451903134897]) - a = add(a, [cx, cy], context) - //Round 92 - cx = sel3s([e[276], e[277], e[278]], [4354759259287077683606602421630609654573093874872166313972356669642414450557 , 13648951383939395268518611670175324834705441295145081802011558222046663990635, 14109063296906889436525684297777423342039664400074253643711178181120772454442, 7920829805332901764517739207944367186855755092397343817260945923718690867274]) - cy = sel2([e[276], e[277]], [215179997319049227050677351252505122489806707992988193421803248841509506088 , 15514289571504865101354424086151224801481680739860239328031576438563705370521, 5904618612526890474103927634405504783798865056645457180704237978103781216311, 5748211772814574948909294216861178264766343013494657271260147929020820008781]) - a = add(a, [cx, cy], context) - //Round 93 - cx = sel3s([e[279], e[280], e[281]], [8507753630181199902479216321724505843375506218865451254864654248120523505482 , 9450124212352501425016224885075456626937137054710829941179274211424392402188, 14617760695968479875555170000896560124384001439628509056518085157675385430999, 11259792651191057957240332532512267993084988584437199185342993378682410436972]) - cy = sel2([e[279], e[280]], [10815868200773974736475276546832667321164179489094422703987813447328543028788 , 270750089909256057588643640569447562301277634245971255743235422454022028456, 12525264811662854133497240150104162834870195408235601736200987821770575683753, 21492322023082787855062324449039977497952909569982074113097211015628539637105]) - a = add(a, [cx, cy], context) - //Round 94 - cx = sel3s([e[282], e[283], e[284]], [13109291774440010508838814834344208104350382843329321595606001193219335478061 , 18178081082215000330236621415683992037792438414607902561151998975591610672159, 1825689425393769600328701494994687539687903068590739461592021486333291661266, 7793684058500310840246186772109776829776364159558184911962167538064855177290]) - cy = sel2([e[282], e[283]], [12538966751785809241486764416198217361134417700423840996157483469862141526006 , 18918692038570377322252840249784989027502652471358614978414943590808682898821, 10739840318098234656669579810873413661071494114926975536918927404574756289141, 19177195314890990393062332918745346394029203576215723513167013054282705104509]) - a = add(a, [cx, cy], context) - //Round 95 - cx = sel3s([e[285], e[286], e[287]], [10225920463059329189289679689043403756461771898061631555012236633674500607894 , 19821058226025589223575559712382894896410588163797548720897159700660021786692, 4342530929634070742874132949165242936564090903607131574088848141363806195244, 5402483411262228419126012059406829285695506472234034454332016959299908934815]) - cy = sel2([e[285], e[286]], [14845268720181506270843668435047795143673881800644972711347963164805203292028 , 13672974733920510644893233723674603797496603310630434825704649796138313401676, 6411707949262855152252009198588056473458716851460397006471717726058983234993, 18779680229580121519443328584313676056219616039194596697158403462222387132381]) - a = add(a, [cx, cy], context) - //Round 96 - cx = sel3s([e[288], e[289], e[290]], [4836760236524137019788853323648085337078365119204570171912328851849081302469 , 17868028324749251162769441309905628927317218753130618155651317995445082462075, 1772933343466453031175704703581215603932939906355841484695391914536709138761, 3546600638749568273439745161679319484611182076185127936908592367054940973889]) - cy = sel2([e[288], e[289]], [15727462261854339392836033936665994570356817309630572739663218192786419709049 , 1337461376408438722980356088847283448049292537148264126525086899131501823829, 12238707625348281750296588592788256417660177170554983893114345282873428793086, 15525437884516977515442248737754366741726151193578138245479811700230576818338]) - a = add(a, [cx, cy], context) - //Round 97 - cx = sel3s([e[291], e[292], e[293]], [20126221763126240993614454578144859888701958472483256034667342833856637405284 , 19699064573618103786080175406330154847584332570598813466503995653274429215656, 5989506922601319310850294681562133253116809072854033597983216925515271522735, 1000911579713616921402553874631906432389325985380989857769833587362794312630]) - cy = sel2([e[291], e[292]], [20063374408209966489810045113711694748195105838875731221209079272072900704065 , 9194215440981146522641296536570335847038564333573070389731736048602585014353, 9856108459841119062384164372572927792749846793172495377480072007040372623532, 16456996545907573633695460898581306270452076960241899452978065386508672788709]) - a = add(a, [cx, cy], context) - //Round 98 - cx = sel3s([e[294], e[295], e[296]], [335301756618437339439144029360964383534478515390448989496515998200065120560 , 8900295787747118853873347685755889791679080209434225159052383890249026687118, 7128354610803275364524320321498051406687079176221803083268519268078181474486, 10587524605383993790235166395264599817111999691721750015186077104713345396025]) - cy = sel2([e[294], e[295]], [5048381480643837407413881593434054866090196361251156389103862466064034755870 , 5633507321470690754598569732643608340435754341640194463936636395149026354734, 14155759183302230320588700447409830028824433982845500795956824041195173925296, 8029144329154622500871732803176023714578210937344495829905950083327660868243]) - a = add(a, [cx, cy], context) - //Round 99 - cx = sel3s([e[297], e[298], e[299]], [4778598962832696072676642978625204359871247189399816084941520023705687820799 , 1041656446764385248839445285580789894072064765593570151992974139621577464190, 16604772736533716135897718386428759521995904068172209060160905451073360508438, 5434449975739162120230503825057718004673241312353068784008427484008820677975]) - cy = sel2([e[297], e[298]], [6056883361340614567315212379835078890341975776819628834401238537031161511515 , 12948572080347797369632667255105735306309789288527345335385584655912071062991, 2047203431451992701474247296709372094572802843600017662927813418631212656090, 4132565694324682855622172238297326586214736771195057409015171400249163749388]) - a = add(a, [cx, cy], context) - //Round 100 - cx = sel3s([e[300], e[301], e[302]], [6916961985409927380628327393774423923434707859806165446564471158322143896430 , 5992074540412063352415311056228455935293166060283849428112990098777744329018, 15928943908823412922424046027263578805013830577468518797177611363337136608209, 9165805262654590321870254579036281540959358923531526687992873621654142568029]) - cy = sel2([e[300], e[301]], [19113997592137471372275504986229466743101683336744251847362311356790431849943 , 14004712182695079610522706143578502649621084194457654873685315715331271860709, 19337382334092833222650792928980596008310896977712987991984497026496963328127, 19598147310295874176650103171586127283815601834965516057565002042355878900904]) - a = add(a, [cx, cy], context) - //Round 101 - cx = sel3s([e[303], e[304], e[305]], [10948634109523663410073892096301229908363974454242026292710198013874268733721 , 15429431087099938206375989354827088309373134102432374989679474148007045226404, 15424933350139202912640857850279200342934439164947473620816895024212952340734, 7249326591094430300092421476233168005480477057146500206388167575638063334006]) - cy = sel2([e[303], e[304]], [13978844239437491612582517692269818179489578402023377256168376965218369369939 , 2030861900932117628118671150363276958527364035939087076359289004302891739342, 15817916211331592751911789779171300716227893840209480318007078572691072662437, 11627409307299027242340485688430280907603952564355973323102745520536413654480]) - a = add(a, [cx, cy], context) - //Round 102 - cx = sel3s([e[306], e[307], e[308]], [18995578047969205917336954191535061050094635635378379108624715348396977983189 , 4225372875497776800681698864198574622710499387413704002947025943614195612470, 17351437921298308953512714184518159189123423974926314714485788395814969849744, 8648037604000808882689040136601171409077000943524268908332163815927078223586]) - cy = sel2([e[306], e[307]], [13847262887662907650775044616657488013627923118617883909535158774246706595453 , 16327475809001511779800793713087994795688106377254965385366798254360171531485, 9662682437808722890180813130657795806130406684446667889065062080930078837985, 2502962306844881519115529360019706751646009100590601561262014681428188719652]) - a = add(a, [cx, cy], context) - //Round 103 - cx = sel3s([e[309], e[310], e[311]], [15920090333582846150341817050024564335649064112537068561935372152494077145209 , 5605643430930274732542971456995927736808851585930096579266761796229766916419, 16417626123069839752924241752177228747744623168825833393208640134299321885615, 10047503027147056454952493773282171263110464519924564641292405110762258997532]) - cy = sel2([e[309], e[310]], [17200096279975283058225939790642290750952306062383335630123644381672038262866 , 9789126042032908977600199303915152601153926597218655498907321898754260478045, 8000890408406693601499028261723138327296400099255905955307073434675924377491, 4588804177243916206243160261751431868697632792491002746485364561078105548339]) - a = add(a, [cx, cy], context) - //Round 104 - cx = sel3s([e[312], e[313], e[314]], [17405833224461846119127359023602459766899246377474167154738658246656617261320 , 17497966949182265924717994126031328897613192226672854325764486326873236644838, 18112601253331073769860162727184645241197911130662557597456857637926799952771, 18917984642138666446882277898695258545411024830699319452174655151221791211048]) - cy = sel2([e[312], e[313]], [2379006936139604897517171125029127132096844925377650383092744055973319489305 , 12749848257678287712950295235536433677019860991481258729313170570275169590140, 19636804280533422414605179875456610832289030857729756765481423873607782896032, 1918232436869295272222782754406246415048195875894409329377075908962690232744]) - a = add(a, [cx, cy], context) - //Round 105 - cx = sel3s([e[315], e[316], e[317]], [12917351824629483440622737030529674983967542988637720886395195031194160632079 , 8841322465723154205678020011172362816775587975165151786897606627457187155545, 14002729598867581256643018976730132585331390790166577050573493502425421127182, 15268061642248917754819598857052007481406516866069427006418085798086854466171]) - cy = sel2([e[315], e[316]], [16674117998706559220643814233136742237729068875288271911312504301619597199572 , 15156988565931490695937923747057400310765196912391035444903438612244254494193, 10444568487973458741284119360757120950097746658650645740311119491238200646302, 385547467860345680569692008987772843718726855128251196487129380665836896693]) - a = add(a, [cx, cy], context) - //Round 106 - cx = sel3s([e[318], e[319], e[320]], [11485514708661668839797104792911993330100465395538998907154500209956717209980 , 2378564891356297882391172511058064121371341057541144541265151112602629407486, 15431113736930357829525054375951018432490410667610553241393471463868088483568, 15128200972190674116782495538728842150282218770763850888538540847691112710086]) - cy = sel2([e[318], e[319]], [9353349283824572334689034791316525426505799181965760097150790472211583538470 , 2565250682258865603262212838934596650511603775929760392607203509225620090349, 19046693709474252308020355261538860605259941620276924614654553264840108783324, 15978910116968143273641610096037639009526883121076925418594134134597880991636]) - a = add(a, [cx, cy], context) - //Round 107 - cx = sel3s([e[321], e[322], e[323]], [12732753810746517185428320079630798046136898905138090354428070504022561261129 , 14570979590504848605419638850092710612576634760731998010991154705829891960303, 7081876654999237785822068068775175823259789900038464857602167050792131983158, 11911397750859796885754857056361505572472692036239385315518934824432070976827]) - cy = sel2([e[321], e[322]], [18703753174721947326863540292822225800192529767109903887849391280378615950879 , 19613778040124100165889220227898498533129133505873538625549588791740345005884, 15039820717144729975607443780109118368904218216499993640810787891283371396202, 7893305471806697580362861198809218871446498187812275173987543199956558198521]) - a = add(a, [cx, cy], context) - //Round 108 - cx = sel3s([e[324], e[325], e[326]], [4396441250850868966014141809834014631796411613521413364533261157108807304791 , 16836648497150572549121598580118959226192434996387135129991940567405870268725, 19465159793724690099931261171165210166819967882352842855510624454147581274670, 18758053793437253746142721581116755417112792746753684636213054094477781477382]) - cy = sel2([e[324], e[325]], [2981405188098805378415778407831807030725264692497108694734382487084076855210 , 20469108288868835484927940943356623938045830438424196869633899618683134613519, 933161936100801959708943470285929527457537321589386575156679532348625637985, 269411351035529607018992916380602655161076148137839318392666564540836404599]) - a = add(a, [cx, cy], context) - //Round 109 - cx = sel3s([e[327], e[328], e[329]], [18448980711993048271679830178954781281796619509660919482566515137849326949705 , 19744948717433186245821639271216553763028577858032707139265783707853921912155, 19819689638742986969009459074952228930363474994050981268236002838584672060867, 16852310388498099768769862489306840010510354704163417110628769300551675410617]) - cy = sel2([e[327], e[328]], [13538295481673593444396948705042001770075594914797407330259513771278632533788 , 14779507856773747214980057665178562325159137267699293184545672938786460137545, 18422483889209125213732972603904783756680200857795267276573963126785961918198, 4225410028652447730956912638069668360808266049871102249949930413024208501463]) - a = add(a, [cx, cy], context) - //Round 110 - cx = sel3s([e[330], e[331], e[332]], [8789386218557174287787274081526754120821582438440596481230009033085305168336 , 19604730670978725971286378588091820043225493993475360080974783305559899794334, 5754400819903612415922678283536801620301085919072204701407326554289862247, 8133367062275595631112870441047385208403330263311352404563334748971640119238]) - cy = sel2([e[330], e[331]], [14711352054903619189890311113670897561016852508413508359380114647296690234759 , 15505081148609421707654891794900819606599284654426944331953154100271365747946, 10498745521808868190882616751430118808278388180031887838543438537592782154020, 14283723444930116423678497723705206282538086486601870839003576853131844860728]) - a = add(a, [cx, cy], context) - //Round 111 - cx = sel3s([e[333], e[334], e[335]], [16410879947793378178852309134034691965068173351773904636443113803287073468165 , 2459742793248426443467557681746013841012911230130900204552944771295773437965, 14148653292536659971692314351826075143664660164844520450779907656237062521024, 3823568337665129538914482600317854425115614575078537531810182911935066246893]) - cy = sel2([e[333], e[334]], [13525280335627612179489028500357999227382280656020782481971742893960563718069 , 13906986326008385599879221793305773429690045797230325194617940541283670975066, 17928827609489859058711914379940226888033289004797111427100202351646756410052, 7751873896780721346657011057490735623065509677587909473561532470621436328656]) - a = add(a, [cx, cy], context) - //Round 112 - cx = sel3s([e[336], e[337], e[338]], [6360670162449266467030644276184864100593477111108480032796373772347480922189 , 6238026479435781753480651584008291445457129357178771800497280501659229824509, 14372912505742790548866622516086728314858808340582492719789600777407852624706, 2504355035079143757819920622529907675398702401030398889002491033376003993290]) - cy = sel2([e[336], e[337]], [14257529111287275777165336596087530152135443364949890695933859730727871380736 , 362630247512640601958597579829458123399369864147591061426591055098065517091, 17799973102921706872164223253101644481160962872432375782799635148100439645882, 16292554915278539427322523921562887226516459098783274424269678044297404132797]) - a = add(a, [cx, cy], context) - //Round 113 - cx = sel3s([e[339], e[340], e[341]], [10885915218940734071225780147170174316285574070557833147925199753671864395970 , 16952199638513201931184233985077369412021694081253114169931799009969944845190, 6579022618957621849920927439620464464347948481098737101648586523931683396941, 8954730328909621308689740172956171586217761959578457105814991014419829084276]) - cy = sel2([e[339], e[340]], [11029057981581926429073650712620964484769971154264787930046960173769123662678 , 14057756519867963926667557918235357382317971790756175535573262066939972782226, 14508105580605381633693926053140229084417508695027158358695356916669309852365, 8985315555716651207654399675191261186115135312348808559060054412234307291987]) - a = add(a, [cx, cy], context) - //Round 114 - cx = sel3s([e[342], e[343], e[344]], [9591625063099557813317657356201310094684652614430671855551305338577894715651 , 21710627476302748728292369634413673464477226906421695181551559967392730749884, 10189696652015358480306279349674126142601586910844054141319090928400967920492, 14575448555178809619615329760249104735737622500547600222673171666044253032327]) - cy = sel2([e[342], e[343]], [13661097518448111362501604180288489621905168345464166181035334250815558586292 , 6541927678640542532346030316589325212935454830056081625698359290342280209696, 19655534040611331062875671654696954076416928174908705322979343601347718766841, 18893407984789248251370377180059349323487262100431967496838185583910928677618]) - a = add(a, [cx, cy], context) - //Round 115 - cx = sel3s([e[345], e[346], e[347]], [18886312892727437565309004732784060353326028914324367568840970250261109059822 , 4969806713830542782459289156960092729650598975239889678453184524343618399703, 16622981471374298426508813360547940582831388597832992696194782397307736766285, 17207217606628134149600916884515052475396230199786007830822049511835023327746]) - cy = sel2([e[345], e[346]], [20097067895510901824034782908594630518461908899922907976633298936904395310483 , 7549705567086856493177008201999701185795474113091244286639270279144087122600, 6359914741562734059777896085058461481450840152242223222499923214787802554266, 4523686415566243191697029234004097207393002925819292838991423859908963592134]) - a = add(a, [cx, cy], context) - //Round 116 - cx = sel3s([e[348], e[349], e[350]], [9611980085915454916721710377398516249069657290776790665729578385653465657608 , 2808629496317279665377941162907583528406102092075003683612652910715356989065, 5146801454146059628396374424703327885864890381251241815068083494646287896482, 9712822633793199870569132733680515369277288793857035023884821044404624931246]) - cy = sel2([e[348], e[349]], [12531050708955702438977554896456788618229483698488185884652134859969233228127 , 7759740123661798513430229604959580258805004199555419745903987161601748379417, 12676630374277918228347114736241248443643025357735194824989982902529942631987, 7957263793605029493947914798589160413665834659013858298537818906355583201202]) - a = add(a, [cx, cy], context) - //Round 117 - cx = sel3s([e[351], e[352], e[353]], [1741783015222897367309800534949631760951606605798891132137371646304340462458 , 15753951377666759323512681415584732767525844411650049393938120048851867306800, 11318371057965241278094291737048639440256637452901941620275041654781038395027, 9043834682180335510097190442699980857932890158044577184782692529141130240824]) - cy = sel2([e[351], e[352]], [163811524362553669200342941603136686901966525127089114473510248213711571683 , 20253563341205755839890642239029020576032044419644567576263861445077574198624, 1129293390247992239629138633531986375671761935795719290973869330578475352706, 12864200497534810115296604114235985076138506691530959360993894765742849428715]) - a = add(a, [cx, cy], context) - //Round 118 - cx = sel3s([e[354], e[355], e[356]], [19845239752872171546325855177077796460784181475810291663797620022786920823647 , 13524819092286579506826904337550390593582530067994137276480823345309729489925, 6812066149319989921217367650719188106577252681936159930531352608504453614106, 7222950523682776178187164591717978364824407709855563372464941677077475909161]) - cy = sel2([e[354], e[355]], [10413380090476979012716640518612591288231919255093118763710930970879877622297 , 13124406349881024599134718908760433545313158896610258373843772982921905937617, 10544285464977662192736078007137407440374594005235468167522962555324745898878, 4262511480267656654185538760448950673777806215660569720854482040852407424457]) - a = add(a, [cx, cy], context) - //Round 119 - cx = sel3s([e[357], e[358], e[359]], [21840644145325684882015312401601386817913954005861480185552664536266852358123 , 17245795366378478445622830709744244736981686761608208515847580487483274745119, 13807005991933596253278252430914713127227144098393113439031517565273756047729, 7508257045596568083350722191515656587852775770850324460219207057837744147846]) - cy = sel2([e[357], e[358]], [8473655227220833354585864220301666825011510607427101884196854510787991763100 , 12360766780968617496459580910362246207458173665456601955392871687431450155437, 16167977026195109940196928407142099851728373085986722415539043108707307260209, 198020065443013508235269047245522994471757343128188653900779810305583184096]) - a = add(a, [cx, cy], context) - //Round 120 - cx = sel3s([e[360], e[361], e[362]], [408538855946993109150255210001390137328762855947155164309686603040268044308 , 9956106896094805762100856187967638241058986877712947272175178827260922476691, 10413057148806203104120616811444687722773209463542545789320471445420824622479, 11902530720628689665925185225980720963660904880464037650526790156354563593259]) - cy = sel2([e[360], e[361]], [1479997830732538227417547327573357263920837878818360220214252494202287418999 , 14987839414386761194654231515173353164503075512219993482548242568337943854755, 21713504951370328462347781999791817908891510961297311340202728964936620298516, 20863127910126532592439656993995677084099363872120709138917554483343369113988]) - a = add(a, [cx, cy], context) - //Round 121 - cx = sel3s([e[363], e[364], e[365]], [16909060815089078676939420644976457427406147473547024017569298235433420995548 , 13780618743481311116310648367060473410410597997822855004264478650194424563904, 2732495529118703111995546569867225395498452112166729675036576016860030980932, 13122008905793271330592610678764878579485569855365858119720314545298458579129]) - cy = sel2([e[363], e[364]], [9691045028169014905240668289132134803037917344396639164551352440947925851528 , 3058069811496358922966440231506430818794592620746845318344939704361344313857, 5622098116652966523875299529800829301718212684029447361840034988407307855810, 7183269074283900923163991117263230892311528827769843151316519486217947924186]) - a = add(a, [cx, cy], context) - //Round 122 - cx = sel3s([e[366], e[367], e[368]], [20571623498624005071141088211057092924213194074152586837454876463843418144025 , 14097761035973961045955839030064191145683851652701331413184120292691554339371, 4700343263415821617058086844751479864993855871131720446111591033305616384725, 15018715227933376511503870740434993985805930984246159457731592079602230709953]) - cy = sel2([e[366], e[367]], [16001479421972757821409642160488722706981473283972847385882762682377724905156 , 16084059586346766494553050527349239192146155351545756557596881128274718933483, 15099192410657454417038148697642033151361229914558920712490911402249873000238, 6321931552493003117300598295325862984882362303961074819842172524617810976022]) - a = add(a, [cx, cy], context) - //Round 123 - cx = sel3s([e[369], e[370], e[371]], [9888014007610840933022906589732806947017424423907994528302713554488676542739 , 8913934326838155827928873892003131738033383847534784434581587200177151201442, 11175569252941365912268295578620074710236065357166442341964835896122343271089, 14897216243038767404517178131890350534529367853478353360851740975433826101343]) - cy = sel2([e[369], e[370]], [15251452715683470293001422999667336542311051361914428663773647008481320118023 , 13776813195393840721224885537714951191622587841642219673672717728440679190719, 109393055477786022036855578884727112792551641118563108378161158873180208830, 4672879465153093973501790898266208077997221906104002063988725461236876037213]) - a = add(a, [cx, cy], context) - //Round 124 - cx = sel3s([e[372], e[373], e[374]], [11201877561392804928547433284377926158320532448010089457664943460838007583898 , 14898313039936563609742185951856291683792301837166735453885728355621976660447, 271087861779394868518887048853047396941902217944929345703753181641065491942, 4441061173173027475223782298768839441149677456214218957851727123779445089634]) - cy = sel2([e[372], e[373]], [17554707027223374526818340909253875671094356182527312776837442099008513816809 , 20394478950504145529480516245504739970884923781915405632423034600555134724554, 16722605284146576015540826794584204150250626411625717127438407440061496436970, 18186321490023557384895834600063402151493085858585827781091438725428737294598]) - a = add(a, [cx, cy], context) - //Round 125 - cx = sel3s([e[375], e[376], e[377]], [8041169655049264647027531522783115313651111026520000925526843693578880103225 , 14515227610041424277087375692958559713914998916629738058046674629183188354305, 19607007966889476958718540412171510858381328905787578252786377727252482454742, 2784733087979918000560628875496578392394872735862389774966301201852627273440]) - cy = sel2([e[375], e[376]], [16996116430274827689271070440218340032465717731948638724397047789367189212654 , 1334527779675942376452476259926180292226498546209192760351592699867703388666, 2040984273885096997446285553479523685705477968103260410171803510149440153201, 1362381113387759937979242007199225976741286448134891397298462226220340605980]) - a = add(a, [cx, cy], context) - //Round 126 - cx = sel3s([e[378], e[379], e[380]], [19334565048001467439446889504730002771044189757270166846813098304840682799995 , 12950908278008251424596267965839781465537497199604011584300739900170800951940, 21595247577936157693500985718654956851081515776736906827009279412148715287229, 15215490137474227465600889880755209339274086672218612829479984354294020155457]) - cy = sel2([e[378], e[379]], [11177666514768283886285136134046021748603781779508224469021361511080086667157 , 19019917071840025176852012694579443932947880720292648245869222295962307004975, 4637723565271538497699679545822400204099231070875646671160251633445655525972, 17666228617432733285346663026898759021573050617000716798909504211448351974426]) - a = add(a, [cx, cy], context) - //Round 127 - cx = sel3s([e[381], e[382], e[383]], [10764100134342681938975151936530775454161936697333679961141539476099641645903 , 16887585392329741143712714812495679688982136908448490321095843300899468374984, 17732836192725467148065242235309558107289861496038148884513643994394428900356, 1445275363508375975763521380916891145219085429516411016928665376398954093593]) - cy = sel2([e[381], e[382]], [19850691100864531393976360616243718992492409320965998539447518686463634627384 , 11041690436464044133197365654525664032353519287590211059695239069687237542566, 12282683178748394297470306056106686277334235538468988533692942720363799093795, 21342615132598490749588725326967212830166119543678585183102318245731915882892]) - a = add(a, [cx, cy], context) - //Round 128 - cx = sel3s([e[384], e[385], e[386]], [7984775939876417845202037337929702281039643807160799398396389954446436630245 , 11385355274910748832054888360458973063107383418973550712148639893241354902280, 1459026779105998101465829026524789739182470402517704469029876736898952870477, 13412666792048974377925483462948441322790663427949756029941851541794367956141]) - cy = sel2([e[384], e[385]], [11644088529951120466123058306783377782553679447618569394424538939634266570688 , 3423766185322892807020818425845766412060736093511436910964946420904954554780, 4248997486365074893462023447486954255437098681775520477410894095041115503490, 13508520946233121439054409300327739993661203591041357972218149016790406863855]) - a = add(a, [cx, cy], context) - //Round 129 - cx = sel3s([e[387], e[388], e[389]], [5565157198993964726485879908963280627890845525340341493437203971709365228330 , 7321058630137598328136197614874359518495943608220094707772133348409941566403, 7424926497991627209495812948930411917848701932818206777924739403931504666904, 2952280234707044917845773867363672510563637804197143708410321227590096039398]) - cy = sel2([e[387], e[388]], [16047978233091600592523116252839158499254716982332498268149527514947495047441 , 3013461674923738179146278200182113922630443185951298626004001204030842783133, 21733406038088991240575501132398939052212396619770619197864537159847335678397, 9758173327391957613571828756022551933369392423107899686458119829785341358149]) - a = add(a, [cx, cy], context) - //Round 130 - cx = sel3s([e[390], e[391], e[392]], [724617195994552100441707186007100945318061137735042194166321801565168264994 , 21457482305994995060621698878673403410439584990848189791210666985898821778689, 12733018351677357535096192491479720026355634001914123270202692797811692793469, 17876157828650849091584102879830086520321631185862731111337702980715729860154]) - cy = sel2([e[390], e[391]], [1941243639179655563586549731833523575056282199989602716546318426577162114198 , 7186671745389328078718719957510862463188189283547797342924706384031236512232, 181655793349501388675021326982297619804658251127556562657041847324134931318, 17955220324559325573119985254939537965603633897040077737890918084344489169000]) - a = add(a, [cx, cy], context) - //Round 131 - cx = sel3s([e[393], e[394], e[395]], [20917363825188238552045899784153496987535745925685770873105753565860443082365 , 4540090524117153259059229343653410962125958868702729157110889632173091362337, 19931748170703315405614719529478161068009956569206884593254142678501117968416, 2400060542928241404744010463507020801241694851019173560965950546401444426082]) - cy = sel2([e[393], e[394]], [1745736425002501661522536470728945366618822522645696668197436988525466413140 , 3366347972505547411030140128225789817592493957844838153202867496815084725868, 13538672659394937012305631615026094764214309199641714104321427476435723762022, 5730310969197975636538358956003546448924042719236605822193245706535947879790]) - a = add(a, [cx, cy], context) - //Round 132 - cx = sel3s([e[396], e[397], e[398]], [12673489410414637838905637938820402546181123854591818062100393889121109718668 , 2399760455052989852989301770450241617652861646522026007293921167342274767344, 20212599267512455026947565441242728025855774594658042161574807775907652589242, 8096283485634551421043683037450718803162713602325821677928898619562706870069]) - cy = sel2([e[396], e[397]], [2273218791680662828916671149332560291571458847138066661294611637128783792792 , 8189321225342615133315741008578315746871762722980986965249683543300354337817, 15342161105292713352374449802912175534449400959133109035836260415735518836755, 18075013689729624974967362235212984989450911765049481574404064991547015443791]) - a = add(a, [cx, cy], context) - //Round 133 - cx = sel3s([e[399], e[400], e[401]], [1596291013949010721288060595532569432608538778619836480784785471074053165112 , 6808491683819461025655595089437806112418825101974851283793281398274802390485, 364241503925827187366795904611796342209607893955620582589568264631586955422, 16490550871285168246186419126591524969189857825357227166657318003550977024941]) - cy = sel2([e[399], e[400]], [7862378404177401992071889396713852447802454946236648304807328682371781930090 , 507291250759269099980701396020232970806066743976022636589996988193601483784, 10744127551738752560827414410584235701822856001225517338822143012287884858602, 18241779151498711099077315181629505156252250432591841498036131464452558240559]) - a = add(a, [cx, cy], context) - //Round 134 - cx = sel3s([e[402], e[403], e[404]], [13383782376835328120051264492485947246229335501182593669024066132006083860995 , 6829659109797487915393241205795046921708391483622784165963215585089039907693, 9316519590383340417002353253254231934003449806173856616162378794199227402893, 13002922510988749141229072125743986091046064285797312111247897533544865920246]) - cy = sel2([e[402], e[403]], [1452388014885069534714863742557414467294079407912495717272255602231974271039 , 5900502409092025397559171952410984687860230521181044855453255892660864354438, 10043095963739821148582141213281494171132379314509020019652213752752234376602, 9999295030621233000765070897582529515356078631699063530749343953422947829219]) - a = add(a, [cx, cy], context) - //Round 135 - cx = sel3s([e[405], e[406], e[407]], [13165533527694513928104129943149460933916076941607396715443729707678633985673 , 20294369464168299590806576821399517301857816000499415634107985306452722815938, 6067645363539607688922626118164207320418666861212948609146588413602170467017, 119932367132867885429975847232185792475931817114142487620518936723703313296]) - cy = sel2([e[405], e[406]], [17238425515895072477563840544058923640858290538130746390995636765338905591675 , 20628042696308823655110673878535950075986980894297665479048269813590306242580, 11749486899455580256560135562925052584441889327031335669536847121302580177052, 16957619631025354458723169845456497220362554006891490260455748609237426050971]) - a = add(a, [cx, cy], context) - //Round 136 - cx = sel3s([e[408], e[409], e[410]], [7326992374695153334569399469397596928696501586886381702972942656080738560504 , 4198555626333615585226486302590784054103224208504401294485393840072962221472, 18288510281806332963207620050180295922486954421289661405933207406160563376204, 19378648346334975363564386629109544268031565617795572270340255835354171953065]) - cy = sel2([e[408], e[409]], [3441991977044037545935620478935168226411039028254665140927991316702138513190 , 7980022316348851053079344973315144435710609854183180078433220232446348072790, 10703403289781310156812833248447222548151317595810496437901793212311982317063, 16301246072292511450557090225826608132244132307038997545230147196603338285964]) - a = add(a, [cx, cy], context) - //Round 137 - cx = sel3s([e[411], e[412], e[413]], [4380971751033847027929691061398944531722909263311553031455521197665070771642 , 1958998764514462202561805635784673640011091472752464180193064104296547581169, 16607632498550062722823535936950763735998138401664871177932105851574722673362, 18107842395238833528194122400147411460295339366691168281515267029707554163796]) - cy = sel2([e[411], e[412]], [16794605741797752486161164743285493892529567663448780177764044251817860406839 , 627364605348057780240790756195705309805910423716172983190978634837740895756, 15938340690702031578469687601244712133164105954943969813204470601233395408177, 1337728022058609756453976167140964506743665540101352471912041874198880786028]) - a = add(a, [cx, cy], context) - //Round 138 - cx = sel3s([e[414], e[415], e[416]], [4325450975911066881724043517797022496124195434220888316197251865366294339361 , 16239262892194658073042878979066943080253388067983326658313518038231343725333, 3224923392579231188607529005374853676842589239602348970956358059045513499844, 18711810040957806004127569353264972856236116117792057333129328498567653245337]) - cy = sel2([e[414], e[415]], [18556589125306655880844231674670238467511897504977535323905816448582480367724 , 14450907030938846250134541582271892920169763336845349109491176054829079021938, 5489164165718004081061600001298776199757130654902992957321875892970948684039, 3404126456231281994449938636645452663538090331489692208486381139765931389947]) - a = add(a, [cx, cy], context) - //Round 139 - cx = sel3s([e[417], e[418], e[419]], [3049906494165633773067493912990013841965806179225048735919293547905816967010 , 2425405604681482172566807394598240014734338608183001729881716084701331638207, 21560391195338031738549905898033672840916947395960523186297949490337780382461, 10640880946275949996544592530048605056441276931537882586193904453232482475238]) - cy = sel2([e[417], e[418]], [1139270967545262231620743596254789040950691396231510347534297369410226811042 , 20852287956575668107697863776884710196273757688539515338600627283890571581133, 17188605966302742252765339963794720668370341043552053263753117294010969693650, 19246586050423626713095252320183688353765457408019346352862271422811659317777]) - a = add(a, [cx, cy], context) - //Round 140 - cx = sel3s([e[420], e[421], e[422]], [19942746034266536069392101170115851306620344112551007974939114086497358930858 , 15726708481134151732276229872451366695420040201434018827381159241014716358033, 3452250047812572894016965388138239348795538732265416477858038566576272340399, 732825901760241932909222883465959257672029209130800755766287912812473135470]) - cy = sel2([e[420], e[421]], [5234335526367392822375043936890479400588416815383747301372644960641216357795 , 16682782393317738699538698600037172468451638588454521003611347304172554322239, 4800939729460682232720559307513657730880675292200605768084865538547688695396, 13002618796997179002671199181852958465089986403190513123030050511152310206971]) - a = add(a, [cx, cy], context) - //Round 141 - cx = sel3s([e[423], e[424], e[425]], [4345203866646269633300579468877411954334981515932585752657225898484243906660 , 18369957391582635573293322493321958485207102003892958136897534329158731684885, 20673831086732472000273127370905823039882723856850376643114084876980363716192, 2498213507326390169362081908041456736901489034606083564552630396661416090091]) - cy = sel2([e[423], e[424]], [19711785928362785984568609948298550809737208754846854010480265206080190724688 , 11436630733281926268922633177556600595162960771369546050376297927685306050908, 7773194831659524501769470153758921383337560398544153003929463015874290745463, 8133306555008250199402612262687855812899186562206213570420163947809045175265]) - a = add(a, [cx, cy], context) - //Round 142 - cx = sel3s([e[426], e[427], e[428]], [13604959715661441436052939762464429298226713418171390314110026091418525209941 , 771054573202666486644315008474869467749501529120937703475279735897998473318, 10650739155896636131407567213077995361727149157766675911133814003745320974607, 21082274336612203666519840927907859383019309974047946161440422017817660726149]) - cy = sel2([e[426], e[427]], [9106634253925907822997376723908848470389744101982447244238790923479221740587 , 7324910184007890101804849358851153077116609835592182327277588695666568522132, 9210749700131521931808418873690269098719063379384664590576822932928021903283, 12373345790154524492998539937744274645461345882077071841080883186883404184026]) - a = add(a, [cx, cy], context) - //Round 143 - cx = sel3s([e[429], e[430], e[431]], [12272981972646946567553896730199881959247853499104488943992635249117595393209 , 17484113948306348142106921779441669789323552473173221235726133380929727014173, 15117556748390824311921483809280404911428464810641842112990732230853500342878, 18738665459003240153367275566837691463796036422817751002779294781153509048410]) - cy = sel2([e[429], e[430]], [12840198036955871442566173317906222816787870441489199428401326600711994709214 , 13447048657087191261352674553209997835888060694120420289379298057286058954919, 11085124394828809185369563175800089294678889500629428639251047427113804175136, 20040932616180013985013159566209210337758333701488325181237556234029685365086]) - a = add(a, [cx, cy], context) - //Round 144 - cx = sel3s([e[432], e[433], e[434]], [3005593847772820450050205074163314509976806377772621088836578637506564062913 , 2910567614812792758847544159495544141576095133298651646543717734234356651464, 8630893570634023334653627900758492588201195084156991103796478188432785900122, 20068438612873289533893462991408376904784837411837844241529573433855826118434]) - cy = sel2([e[432], e[433]], [17258587025904856892544250820556722922327972240440200527118380921147955645556 , 9839944666562674042904466515196204595921896101136113309540898758440523509232, 382264312380680546118029507176039576064064377468124376294215202312670233326, 16859633470889096937094854459393230196320754799783499045789361347337904723211]) - a = add(a, [cx, cy], context) - //Round 145 - cx = sel3s([e[435], e[436], e[437]], [21553262056684585969628674122764109775958361035991194009613252605155913211334 , 15282636750399879299317591027894754559134990135454294656134105963760417995544, 4066930541781809252860144352581968840798983673586834922803928000950012716773, 17266825085778436273993504052249489036678132768169211810048007631121526004292]) - cy = sel2([e[435], e[436]], [14469270633466381305852216281125837079646617198515099740000541993840798471084 , 16980111987593030332881454298183054033228595894840772569146266548134494583283, 15118688184376333116924615779850360769477969453186921964192734694461085893102, 4748807943449256265621737370336238625547081211863390407052811770007138872316]) - a = add(a, [cx, cy], context) - //Round 146 - cx = sel3s([e[438], e[439], e[440]], [11763347508086007810977359866267798246514404258245360557926263268200652076963 , 8663905006927572311188991703236656874376542152827973004022578290253373528008, 2952845374549988741320721621283121797914244173004620545437372716814928986849, 17071883097921153691621062529879599274949735278299892231358334236565401545899]) - cy = sel2([e[438], e[439]], [14706162498378202954074913829047629685039231677186626739445882650545999503202 , 1719746349330736449674857345290037499267579249273019799523377364214790913723, 21616731410397798448193163892890526448374926979106286339849727909287686706845, 11446919769449393256780992769707214683226878212422736672766658759052425409242]) - a = add(a, [cx, cy], context) - //Round 147 - cx = sel3s([e[441], e[442], e[443]], [4356994949172878276640972387865792898708144237321291982532719592191935134502 , 9058912028451204788275313382642068418310841490274106696805181452416351257146, 15190160120915818686650557755704440198069036613617930484645880424887234233075, 9960154561010441532105561845082645172957096392270554555453954413006726871798]) - cy = sel2([e[441], e[442]], [14574692378125259586817945291111936727424704391123959334117252195469092200764 , 9224728228539828897416026999778106548490158473228676095012930511474594231477, 1760463507739730034367125481096536174852992494939001755761219582349351757169, 17340078450196530212205314520279311841731993777309479440929707007860057490354]) - a = add(a, [cx, cy], context) - //Round 148 - cx = sel3s([e[444], e[445], e[446]], [21880820504467716634106664909402072165472960350877194774465177915127008092893 , 11747606579643600398471099307152208653405848363842457205852065247815894902054, 19027263041564841350573847395951723454691080012198506245692747602145336686229, 5632682422077314837831565983660289273448221389165648008167925020530588300924]) - cy = sel2([e[444], e[445]], [5182168744456816656485869911241149693404052223082761825064601932558781730740 , 2685937932147288674316610675212322222716444961674715249218650895750571659552, 1912852125196207140975649985472776011293820313776376659814516409955251806791, 18263958114524880676274451483937610105571465623681831140376587635788141241088]) - a = add(a, [cx, cy], context) - //Round 149 - cx = sel3s([e[447], e[448], e[449]], [8936781701927368370215210870827508937678765478808217533286287559934624784681 , 5108431664028439851662340341125863641795570652264053957564019035084276122804, 12999653496005517730722186355139904948504508219343877303366358022761375044402, 19179622495081980573635923134343351242929014436693872859625873727501193848932]) - cy = sel2([e[447], e[448]], [4623029543859886044767307470074323247069187031547412019261660683452990785239 , 9857015684855568488276378660083416741199186578332924215590492662945432272825, 5242391447932956625671668911434466570194372869876929059550830464880164528131, 14646928672286452058469223988095085156895208600523868135204725017248298504143]) - a = add(a, [cx, cy], context) - //Round 150 - cx = sel3s([e[450], e[451], e[452]], [7946459614521142644206204774850419894186577869297360917934350740375926112382 , 11530085592691934773947896113217121596676226719554558175458752626759168307130, 12291215261278045612022495371137973264064622535432110273152233125306665396787, 4442266885858584741818610179233325487185053295954810407262511211378152048331]) - cy = sel2([e[450], e[451]], [20393528966549387266343193152712146799161036298032725317477228673291507957942 , 1831259860608244620805838343666664146008857962101286629882205237950513972028, 2581270768505724914793947599867596421087089340177029937008824731251155270286, 1824038414762784797700995677077189626495506231241155951144255369814082278582]) - a = add(a, [cx, cy], context) - //Round 151 - cx = sel3s([e[453], e[454], e[455]], [16996326686259093178712301719114535464147004200933701699216923172711169217776 , 10135668620867881915901635109225909232593721615476228193005378643989870282190, 12684696285143358527008494835928613367424428569071148860201922633463847362163, 19520340433574445384932755965450431313046400213079154403779893187900476007389]) - cy = sel2([e[453], e[454]], [10879703765081907416589976314120373073533854885503210038919805342729980088501 , 3042952377945780941440480619239495862925076770257741464841490662991367990723, 20568201167449878452522309826171296534890589395210499691162182782776592901489, 2515435614825363087293388949409937340469196878839891206929432371588941120828]) - a = add(a, [cx, cy], context) - //Round 152 - cx = sel3s([e[456], e[457], e[458]], [5948355082391370971277814822201259570199411254972015395356071689733858457870 , 14435295688288574008552320445654835668230448171821339773392204385711009673498, 4555707692840173328761632986080641237899354311390885658902712711385985152474, 21377793559898523325502642621273525075966615158530502938404139072744665720725]) - cy = sel2([e[456], e[457]], [18781938632634665629392534748457372928296731257744451684662925940692495070899 , 20870582266287640319635222130472633641883455183531701982867810507045631654099, 6255001622610081365809867580322152519018111820804890853975941295493185079617, 11444903546950465193484459453464362458126976218066241321940461471249831055834]) - a = add(a, [cx, cy], context) - //Round 153 - cx = sel3s([e[459], e[460], e[461]], [4801783634053958699406131208260321653724147389806778300442394152288266622390 , 13657947007455887667569605985083889328718870615545221619668723775205747840135, 177598511756923881728697053947837521554079408931967588956714727282062478754, 1374290142752108446259268973165307183295759382785138144661109763848127727476]) - cy = sel2([e[459], e[460]], [10503832530625380631086165586158401732075983866290617431349835924922749109699 , 8383317413774803586670187834721088561764237477263859389570115631886656905028, 2834233504802602126712103599378293010472650755759227696185340490923006971103, 17330582798076118742935459828744886802843487551551606246519220146369990307779]) - a = add(a, [cx, cy], context) - //Round 154 - cx = sel3s([e[462], e[463], e[464]], [5093610893249308867168031458336741939196884648123926997975341654608609426830 , 12248279767532955250746877738475030196514076889129781370472666862024900770669, 5043009492124624507652527263244758360087085758651362799261288863076362039187, 16591909200159417412409462652077399999824413751859530227695887196356321679228]) - cy = sel2([e[462], e[463]], [10952612598118313917631759693602817846928839860096429550603703046117049639522 , 2884939241145303979172401496138136665819626424676215132904685536232137032921, 21092145374321584925227081195844245213760374840107123770724422721835988876958, 5499840197627421265036310285493143039360364243394878011782966367266344217732]) - a = add(a, [cx, cy], context) - //Round 155 - cx = sel3s([e[465], e[466], e[467]], [3794104339739491010449122661216407115137782001618163380131794160705537757426 , 7514419529276933284458458535371966876401883528785013067210805765651582633130, 2534189532451386749189970776179117832798970009395742348348119108287813471216, 5610243014937776775874159841646817951854662385825951664842167532212856045068]) - cy = sel2([e[465], e[466]], [12842968623255283384772731210441087433561383555541999360200972373794310794093 , 10823437952973686303915120116380996262045441725571077692704581218749963605907, 21253964658659775229061107104903539871763760188604842330476347939642955209002, 1745535366815989039402026181267179197840739481539734000808670009580269211142]) - a = add(a, [cx, cy], context) - //Round 156 - cx = sel3s([e[468], e[469], e[470]], [3459245219635302288341483992140272707638915493010622274381776793623419230591 , 9849021255480129732487752167924340739614806540698786580158805033907788030853, 3255308487469886623287718398314898379309460957968181729113829918571419337145, 15359614079733122216507425018253600855203543497608695539122606260839625565617]) - cy = sel2([e[468], e[469]], [17415928452277952995861857592997544802223350915817518744596816398543561612106 , 9999856236606156376100952785476675300524456948913069129769906530665355058037, 17734497746752242925262857913765409819203458581088950917188119245918082092030, 6881580842463060802624074515204787264906621652045323766233447264566499944530]) - a = add(a, [cx, cy], context) - //Round 157 - cx = sel3s([e[471], e[472], e[473]], [634964597278986129282215293208138156361395902716873910540311662219517773576 , 310253852479958835592393232442887907344502522183801152945448588489452412569, 384881480274621505303330466062621612997526527075542749162723700081976881288, 11767445114097831765826464678890553621483551558949563523534328471079851963281]) - cy = sel2([e[471], e[472]], [17203635141310737823252743409317633065422478971915442288649227045499339781109 , 2545094457118912372548408336893899649182443951551613850781196845141738637170, 8609139198776064973664903858401535131314034007074283879284230416121615542308, 20092107484372320312567981037155807130829118997137612522175958096520972507336]) - a = add(a, [cx, cy], context) - //Round 158 - cx = sel3s([e[474], e[475], e[476]], [20098437969178934435495041700635313630962028038875583770224318127835756299529 , 311104306589906971684844795811359683864786473908061989245919427082915904714, 5007249687217418940511624233021226494914521342148545152148356064906320432035, 9785851145981523672688289938894315309424412779439726667571213830109657407900]) - cy = sel2([e[474], e[475]], [877613904095171787446316454384924363436490179245069691113043218080238972652 , 15255392602742007855606168874483544819258797919038984937824266131810915403967, 3482868076428758563707184390706074120455579821747810434457575250407348632455, 5737555899585712614112644175034540180519345050397396205967955592318835422324]) - a = add(a, [cx, cy], context) - //Round 159 - cx = sel3s([e[477], e[478], e[479]], [17889638686175315317941901427709143202478522471798280927986774735210637820526 , 4586587171981050785204495209615167868746399227792813638212786811256473778221, 1864752565757236746122736751796835904389046064841800598816325031089096557478, 13943403942544820674673437343502779310324858400636923221774342029216604251440]) - cy = sel2([e[477], e[478]], [17728898667133884634264046347611298588924985692465583707491826367590591819161 , 18365428070394378833051912713200271982753415548931989923757430748929339745094, 13355801165885814561827651110098104649674895992244923613944279081535896494292, 12718254346735593182641856097514926990330253814732909832265502852628068735026]) - a = add(a, [cx, cy], context) - //Round 160 - cx = sel3s([e[480], e[481], e[482]], [17159516188699622404527134263356371503443962451842558111890221401200764258125 , 19697000438877661546696672369476849653861527230741461549059757921200307256689, 8082602544025295110701438493605046299287009032703969632384937719700791606339, 5936552380580117855548116310401989958728171511356588061450350806482980900531]) - cy = sel2([e[480], e[481]], [288697205606498046198642124865852628925547477970007319079115715396675917499 , 11438994931015502912944770174743669059446783563412696311667974558402876489825, 2713576975757110627428489368530113978475830565467996635364633792472336700891, 20023822454992925006561366839036620580908513505208980493011483098957399405656]) - a = add(a, [cx, cy], context) - //Round 161 - cx = sel3s([e[483], e[484], e[485]], [11476903323853344813827041345787850966667514952865946400953029235796901464022 , 15662688482882450089332164944545567115920791913333567306810233998084574572841, 16165244090421658682362860955446523155721204004465368156540492359518946703685, 13233236504179066734589049314166320998745790229936719431495551951291164368688]) - cy = sel2([e[483], e[484]], [21544495907681885621399294493301860022991247894450553860102494438499516461036 , 15070356063300726246376329439697612629246560015487953180041607494107482212328, 10932308314438454016363769449242767120417784090441698745502660483728820506459, 15142440904746497443767345573381088273730091577283493618193631903901402378371]) - a = add(a, [cx, cy], context) - //Round 162 - cx = sel3s([e[486], e[487], e[488]], [6740469135284996394159167279126920754449900660887428959259136317440159292867 , 1951789672920637712186229138057234008172951294439716801691622239946406362446, 10614706090196653889949286489862565736131644495539213256761186995450585212820, 20219336380099606710973890974478494924791931389585459347005405927908068729651]) - cy = sel2([e[486], e[487]], [12559437556228574824459283742977065667884462966124147526010574650373707978536 , 11353250997656326728675199688614508617263787972463605193791786351817731868528, 9955679877407075213882986027032271351625902587325271136145291798547578901197, 7587664180577472344145946155058239620135123893989614056504418351234639990359]) - a = add(a, [cx, cy], context) - //Round 163 - cx = sel3s([e[489], e[490], e[491]], [11683193590608313373089435698057644614965227085254736967478627707109364481009 , 5373593679075319624506848608700634791297845735799356231319125589754901432010, 14330496678432059141319543266495924665988744049796260830269932610430618839231, 16147138941500612947680025577703299264094926996519490683694344514795650552030]) - cy = sel2([e[489], e[490]], [14089407095672561058133609212857713657125336981293206062798215054918146117895 , 5921405729554308485753035966317904019193857886291312338471036342984958996974, 14219166018565381341875979253176613205499868708487414627746489465729919459602, 9173206043848059861761039827886516664018988512989876666692360758637877840001]) - a = add(a, [cx, cy], context) - //Round 164 - cx = sel3s([e[492], e[493], e[494]], [12391241461796318677666973225906912103063953603374991439355987755433936571792 , 11342324255021537810533271600486943249554637261483201032733188357979300928906, 6762143596567875242093282841823575455167081327592834568853990326935018728741, 1729094316763263611553329689516612131095524285732807879509329720064037980971]) - cy = sel2([e[492], e[493]], [6256323253756510425990684148198273229283967340029341825763386143854418092931 , 608479563301898577121898469798459144789668559311173727644698121661161535370, 16118965412641868779259712849902459712114606105053804845952965420804403776265, 5207196556914412218334602277590189653542873808697180315162104560234636073976]) - a = add(a, [cx, cy], context) - //Round 165 - cx = sel3s([e[495], e[496], e[497]], [12090834415198821488072985841187199896460619427268475889346428879276625683876 , 20435352555053416469114817994605784220258558984767053371686545934216871498097, 7919766463107746640570694574991853522177141706128568812747727580994437010928, 18791819403195060520893758220974368558662433382958799315116210085990602330263]) - cy = sel2([e[495], e[496]], [11186634643432676423242372187246648742599522445001126220151236883458565017089 , 730264789631663387855933585769199256797088038637783970560657523730947722943, 9789319816975923274967045544277604801648452652703289939384714401867885689451, 20390569650377326057430918388837541684089995685084097630788684319064176189296]) - a = add(a, [cx, cy], context) - //Round 166 - cx = sel3s([e[498], e[499], e[500]], [9073477014345643942359994649331122800736234440180113066690071117218958686221 , 17848891043122277658033397684650904021333601784635518417727821688552518594475, 8394455238188958480130266174842497177830879983439478526032000789572056999540, 3969215253795918818810265899749520158876595254756141389552909935321879395990]) - cy = sel2([e[498], e[499]], [15421230006761899572959376594938017439120427450367920423701622807634638005218 , 691759570775251457416249989322179808019152722619656278259527490301863241777, 19687896560656750069557210923004770524699515901561346847457425701096560281307, 13013403796046695153969709190889488389508063704805702465177729278466953096077]) - a = add(a, [cx, cy], context) - //Round 167 - cx = sel3s([e[501], e[502], e[503]], [17605212659450062681090282709904508607567301109002577655966314961623397498778 , 20706453518066591671344075213608634140534260809172831962434708646209603184096, 20530641835252913976176823270868884490574732596806683216254892843407024651486, 19512520336574558609801187648395617364107060095538444150298099264798316486399]) - cy = sel2([e[501], e[502]], [18088283300102077232647028354145534410326244238430555546504288886091850910025 , 19624767204537830958950503358240075916787006780432673880401115874844576604739, 13389739174441700308398229420122777340874705736681526274430502297758537243393, 2768660518118504029156154123602101814256009402463064802144883490594220059578]) - a = add(a, [cx, cy], context) - //Round 168 - cx = sel3s([e[504], e[505], e[506]], [3898901470837850662399020072718316987511815396623761376502150466549773974269 , 20681259404330431411774484706350104535474957110888110413896201115382255532278, 12146860081497614316907871444885755439616687087776665508013517962132514932126, 10103366418676857183019670163194546750004223272088526675082633522057697832251]) - cy = sel2([e[504], e[505]], [18552945270636575492780160887690665046683842994616480518496617903497833044944 , 16280318807141467057522946128901953503954886894473765482004622686048871784896, 16511259671446150110679883995503700110523460228865394020432354340848786592304, 11820015885519382016829607197866756084707670961286078960070207041832708513141]) - a = add(a, [cx, cy], context) - //Round 169 - cx = sel3s([e[507], e[508], e[509]], [6124403322044682705571649214069113177521499060664580284884665715951975035077 , 3806547960677312456106393355578152447583324120952390972170284549005371006887, 12796416634735923176681417392847285391386920336707070519873332365264500996292, 18113312677912280033934533469627761267183403533244965210112870702471687667512]) - cy = sel2([e[507], e[508]], [18191174947339798787646910619446409943766046946921136035021645191602921923040 , 16559060177998758852323304784771936179434931576336411584121379336820727372618, 13858115732979799183025726471151602712224733686530960054365665740611187232029, 9933192519609817862698304326029579651414877338671776883175639003837130283966]) - a = add(a, [cx, cy], context) - //Round 170 - cx = sel3s([e[510], e[511], e[512]], [3342564788366736273905106071612128667477972061160313630133110787799686301495 , 13766193863701503939885263345152684798552605679140222504700163745347162493183, 18523279471468319520962369406962457727155204375043681943707151819380964978377, 8094164074569624021939357073285075790695279643883973800173037824312344195506]) - cy = sel2([e[510], e[511]], [2329094643034533408459502544740928833981119919633412709248656884170940780093 , 3216329736050668550647765981020076413548845117352735257893224753954595290363, 18710403072495673647060422294369054840513840567808020912157404388689648711093, 9785201456176703812798077455183487364035650707229293534561747881523562553649]) - a = add(a, [cx, cy], context) - - bool[256] aC = edwardsCompress(a) - + bool[256] aC = pedersen(e) return [\ from_bits(aC[0..32]), from_bits(aC[32..64]), diff --git a/zokrates_stdlib/stdlib/hashes/pedersen/512bitBool.zok b/zokrates_stdlib/stdlib/hashes/pedersen/512bitBool.zok new file mode 100644 index 000000000..929d72d0c --- /dev/null +++ b/zokrates_stdlib/stdlib/hashes/pedersen/512bitBool.zok @@ -0,0 +1,718 @@ + +import "utils/multiplexer/lookup3bitSigned" as sel3s +import "utils/multiplexer/lookup2bit" as sel2 +import "ecc/babyjubjubParams" as context +import "ecc/edwardsAdd" as add +import "ecc/edwardsCompress" as edwardsCompress +from "ecc/babyjubjubParams" import BabyJubJubParams + +// Code to export generators used in this example: +// import bitstring +// from zokrates_pycrypto.gadgets.pedersenHasher import PedersenHasher +// import numpy as np + +// #%% +// entropy = np.random.bytes(64) +// hasher = PedersenHasher("test") +// hasher.hash_bytes(entropy) +// print(hasher.dsl_code) + +def main(bool[512] inputs) -> bool[256]: + bool[513] e = [\ + ...inputs, + false + ] + + BabyJubJubParams context = context() + field[2] a = context.INFINITY //Infinity + field cx = 0 + field cy = 0 + + //Round 0 + cx = sel3s([e[0], e[1], e[2]], [13418723823902222986275588345615650707197303761863176429873001977640541977977 , 8366451672790208592553809639953117385619257483837439526516290319251622927412, 1785026334726838136757054176272745265857971873904476677125553010508875025629, 15763987975760561753692294837740043971877392788040801334205375164715487005236]) + cy = sel2([e[0], e[1]], [15255921313433251341520743036334816584226787412845488772781699434149539664639 , 10916775373885716961512013142444429405184550001421868906213743991404593770484, 18533662942827602783563125901366807026309605479742251601915445402562880550265, 12754584346112149619040942896930712185968371085994381911052593922432846916845]) + a = add(a, [cx, cy], context) + //Round 1 + cx = sel3s([e[3], e[4], e[5]], [10096735692467598736728394557736034054031417419721869067082824451240861468728 , 6979151010236415881632946866847657030447196774231162748523315765559549846746, 12137947022495312670974525048647679757468392619153927921382150023166867027471, 10624360821702266736197468438435445939719745367234393212061381062942588576905]) + cy = sel2([e[3], e[4]], [16704592219657141368520262522286248296157931669321735564513068002743507745908 , 11518684165372839249156788740134693928233608013641661856685773776747280808438, 21502372109496595498116676984635248026663470429940273577484250291841812814697, 17522620677401472201433112250371604936150385414760411280739362011041111141253]) + a = add(a, [cx, cy], context) + //Round 2 + cx = sel3s([e[6], e[7], e[8]], [13312232735691933658355691628172862856002099081831058080743469900077389848112 , 19327977014594608605244544461851908604127577374373936700152837514516831827340, 5965720943494263185596399776343244990255258211404706922145440547143467603204, 11103963817151340664968920805661885925719434417460707046799768750046118166436]) + cy = sel2([e[6], e[7]], [13997829888819279202328839701908695991998552542771378089573544166678617234314 , 13691878221338656794058835175667599549759724338245021721239544263931121101102, 706995887987748628352958611569702130644716818339521451078302067359882016752, 15519367213943391783104357888987456282196269996908068205680088855765566529720]) + a = add(a, [cx, cy], context) + //Round 3 + cx = sel3s([e[9], e[10], e[11]], [3514614172108804338031132171140068954832144631243755202685348634084887116595 , 21412073555057635706619028382831866089835908408883521913045888015461883281372, 471607086653490738521346129178778785664646799897580486044670851346383461743, 10847495464297569158944970563387929708762967645792327184202073895773051681481]) + cy = sel2([e[9], e[10]], [15464894923367337880246198022819299804461472054752016232660084768002214822896 , 12567819427817222147810760128898363854788230435988968217407844445582977743495, 12262870457786134457367539925912446664295463121045105711733382320777142547504, 18045012503832343228779780686530560760323693867512598336456499973983304678718]) + a = add(a, [cx, cy], context) + //Round 4 + cx = sel3s([e[12], e[13], e[14]], [15118628380960917951049569119912548662747322287644759811263888312919249703276 , 16598886614963769408191675395388471256601718506085533073063821434952573740600, 18985834203956331009360396769407075613873303527461874103999130837255502328872, 4433382535573345454766736182894234755024333432764634149565968221321851794725]) + cy = sel2([e[12], e[13]], [20910093482714196883913434341954530700836700132902516503233669201436063149009 , 1519565901492557479831267649363202289903292383838537677400586534724780525304, 10041416515147137792479948105907931790389702515927709045015890740481960188846, 14765380703378616132649352585549040264662795611639979047816682374423451525367]) + a = add(a, [cx, cy], context) + //Round 5 + cx = sel3s([e[15], e[16], e[17]], [12047448614322625640496087488290723061283996543855169192549742347740217312911 , 4511402808301687111378591744698422835937202088514472343139677982999770140261, 12163443309105839408816984443621255269615222157093914420088948521258519452383, 3481629181674207202258216324378273648482838926623855453371874690866818821960]) + cy = sel2([e[15], e[16]], [16179347143471683729835238045770641754106645772730542840306059882771262928390 , 1330606780692172668576026668607748751348574609524694619904517828208139587545, 21047796364446011793075955655871569603152857270194799075248022968227548164989, 19676582441619193608410544431560207171545714550092005317667230665261246116642]) + a = add(a, [cx, cy], context) + //Round 6 + cx = sel3s([e[18], e[19], e[20]], [12701245173613054114260668542643518710151543759808175831262148773821226772548 , 18376560769194320940844431278184909327980744436343482850507604422674089850707, 2108750731998522594975480214785919514173920126687735114472940765769183959289, 8345688345972355310911106597696772464487464098975129504776508629148304380440]) + cy = sel2([e[18], e[19]], [6893882093554801220855651573375911275440312424798351852776449414399981870319 , 10206179889544308860397247082680802082921236707029342452958684549094240474070, 20690576727949006946449925807058663187909753260538825130322359335830578756980, 934097825986417774187883244964416516816295235495828890679674782707274540176]) + a = add(a, [cx, cy], context) + //Round 7 + cx = sel3s([e[21], e[22], e[23]], [2944698428855471170284815781705687753367479016293091716206788980482046638948 , 13677149007138113141214051970478824544363893133343069459792025336510743485579, 8778584537362078914166751980528033062427878768812683022653464796527206882567, 14187573305341020255138644844606451353103636392771375201751096173736574567883]) + cy = sel2([e[21], e[22]], [17360101552805013843890050881314712134389035043192466182420273655548320239406 , 15585069751456986750767880753875189652981026069625633386060310449606941883984, 14103016602951516262329001181468262879087099584460171406752641724802127444882, 20246884593862204796710227582734862797721958090111806492549002716706329529389]) + a = add(a, [cx, cy], context) + //Round 8 + cx = sel3s([e[24], e[25], e[26]], [14561966822440683665541629338358038450751192033904756806839710397580365916408 , 9033289676904424897161301113716021195450524279682799709206671901182123388512, 3130553029765252517071677341132737863162584406047933071036994763690628383497, 478748220028687672909774713203680223481010996519205842697362525656305870550]) + cy = sel2([e[24], e[25]], [2103279357051120614300268561700949519576521616178686690761693996681299230890 , 20408096719725376095564479959189425244640061563902110565713028117867143533071, 10602190247054189080928144476332888853804880952034975460420247853133904008108, 8904086690633759655814572723164827369823592560037992353159979088242240507753]) + a = add(a, [cx, cy], context) + //Round 9 + cx = sel3s([e[27], e[28], e[29]], [6226499033652114521979121779728984801913588832404495199289210905837818402723 , 8038917508002636084872059181598756897599119789741848736002584943229165162988, 2277325821476302201179031013369476744187798789480148846137091219460796268467, 967514222774662330369300003456258491278184516505205753272628639669418183698]) + cy = sel2([e[27], e[28]], [7443974969385276473096219793909172323973358085935860096061435962537700448286 , 16080381380787087259419052592465179031841607813350912826860291224363330298665, 7197183980134554514649915487783920553359271769991651108349414168397349372685, 15259375744392791676426881929656094304768076565231411137199656518314416373020]) + a = add(a, [cx, cy], context) + //Round 10 + cx = sel3s([e[30], e[31], e[32]], [7079401365241105225661961622760419818013463250349580158302569256283647306129 , 14357098412862251375028337875874646262567035230486208703024315026944432279497, 12132744267560027693690759266151433597852816079588628241106105645480008053825, 16149669420758195925157542983134397690644755714433681232247094526660232442631]) + cy = sel2([e[30], e[31]], [11050535702333135359874644130653446287886435768224627066379760227644857448025 , 2102777351898195104147031754958199443749204333224032175429214522075012926330, 4445288497276728579279429434033072747592184765171167503126978668105350002482, 2895400734738526057690008272958539309751728639263619269043890651038357187575]) + a = add(a, [cx, cy], context) + //Round 11 + cx = sel3s([e[33], e[34], e[35]], [20192636532359225751119979205906307972955330178954709766736232115035084682472 , 804195338747219623697418198937917828717652612397835452095971237574002648345, 6394431494852440399081028203192653448308162012036135765292083934292810191518, 11939476767684237945975176292664687849983867031644620074465117021204214089848]) + cy = sel2([e[33], e[34]], [17748517956264309916268005941322895780280007418421226047127160997826331847601 , 19497513174101598882802026674952900838989414265369078336475842766531805130216, 5620469644231252504463650386222007834239202862082473485080174711171599148975, 5516661986429427386078472422851029350005420782971768428739820651749444868271]) + a = add(a, [cx, cy], context) + //Round 12 + cx = sel3s([e[36], e[37], e[38]], [1324920405111324350836746707883938204858273081019435873511569172015916187999 , 15384225309297147198449617653578330654472159141743407174794062987091000857662, 9920404264935487368096005007182799973436766546149561065368669780566156587060, 15254057056535397961799214335179813200885132815863068943475012547021698517077]) + cy = sel2([e[36], e[37]], [16984705452766649815073644511059333480190120433850502120324063182300137456908 , 18046160220855048074367913256918233739227589113215101142291000275961918974523, 13094718066881673586455686749880972268909309391825129019088029831712146780775, 17556146601257932451584708078305104848786797650062537873707738860847250565143]) + a = add(a, [cx, cy], context) + //Round 13 + cx = sel3s([e[39], e[40], e[41]], [10184781845128697471817965179509651550812478664395958690225791623061609959495 , 5456125639262884825452992858423500073570690895733609235845616173174729575569, 2442835875584110487966438996784695688123609547017380844898154175948468234967, 1507509649954376860384651590722437356078107662975164713418836301939281575419]) + cy = sel2([e[39], e[40]], [12481681651435870984379558646813686612408709833154117210578901875084149402369 , 11152008367598826226940260746556525580820232821082556208512958435351250898503, 7567915483885326926315083960846242855523572023844618551872662303018722806760, 20394803059296859730298132333424950360853695629226621934657959417500478188961]) + a = add(a, [cx, cy], context) + //Round 14 + cx = sel3s([e[42], e[43], e[44]], [10680962982327504072121608021689834159178144997131600234373184928312768469752 , 2399077467035346531560164705357209055497431901223015425246039711757880798964, 3423125451159866822107483111524543716819043967842944968651561023348340629866, 9942880027482137313328709914157120920632734642771778240985776643385937071731]) + cy = sel2([e[42], e[43]], [4698845013673361363032641974440465619959991809676353365742268606915462346702 , 16130578759626193985851427947711894136403468334125608062505774040115700327331, 15972516792261738383725187984065495328469263202118598475958253769706945995080, 7601042727654430423755752301100987459144576573414967660631298823059519301944]) + a = add(a, [cx, cy], context) + //Round 15 + cx = sel3s([e[45], e[46], e[47]], [559099661340368706731458173062937049444139592208939239637572972395409815235 , 1445905511768661496314996877214005625534188630127375321650145036638654136508, 12558069540132067621925302006222579198925455408763618011362743955646129467625, 19809789628385980249290251944250230372682953514057413790020001670501854917090]) + cy = sel2([e[45], e[46]], [10744092763718531253355077100374662669098109929848484460119044326894952631009 , 3973362040829593578154878010051739631231888449967620092704468180671355813892, 1362015208311760378785201188340495520529554642363760051915563618841646945115, 11588368620504227678083366267185871581602064602621931713732756924598104334083]) + a = add(a, [cx, cy], context) + //Round 16 + cx = sel3s([e[48], e[49], e[50]], [1678013963086824122518234712588270403106471527976328603364788331772512526348 , 19217446816753374280163957047166499363370322773252755452762764797217084855190, 18251775792701212313037978569776264038974809413837373677702565241405411946778, 7791054681559787609111187809686247485256130898718509173169053332755413410611]) + cy = sel2([e[48], e[49]], [2187428842929094383038114367392650175780437811274194322303902357941058607339 , 8626132368431980635626323475901790012728207722636477570331410763937692048466, 113795593186630447648084123083495614901087109757474270136294009546464903517, 3911253907085777766524239918145094862050185692851156691146764655435644911738]) + a = add(a, [cx, cy], context) + //Round 17 + cx = sel3s([e[51], e[52], e[53]], [12873968423948310899392467568104977730716801401622261861937368089215309803500 , 12347009456329688755313379291270351313162786795095345538842244121034639964166, 1453033777281838070082852447488517173632198407446735454517038916605079634444, 11282290315868048695472900994602235661536258445850718305682561140328404797725]) + cy = sel2([e[51], e[52]], [8139007031385157566567411468459940290231498857090568363629902873306461631248 , 9142412231629797319569179103935970351107774720462787670615972830568683805984, 12672100925996181868477785977558380430714799944709260345359951721012123501095, 16494953398584179618210238266126209360371451946684386111530845235540890038134]) + a = add(a, [cx, cy], context) + //Round 18 + cx = sel3s([e[54], e[55], e[56]], [7778254495039611795685039895928787457435875136389165268120013630439201169232 , 18978376692784498976711790251498129273567483356717340918869164950830208175147, 6786343960634025784864145941287160961224170404722122001422161703472545445301, 963142484718869013546386102939529863406065949253846087785240390647819147126]) + cy = sel2([e[54], e[55]], [7284679595773642123118330714484999203099307921555787993734753019057231440983 , 11863181578147413903879545253723831525079414688349285572164796614141056912840, 14506820856835670503131551890617399661938603609062325089041733284980790009293, 4347670008275218338032617206784753933320201662996772040726919225863771514568]) + a = add(a, [cx, cy], context) + //Round 19 + cx = sel3s([e[57], e[58], e[59]], [3630756302007400417952089805331380555952289748859891438940570770932527475452 , 4733072488758626584177720052077496914661792393101658203493985364120366268281, 4526910185101338883574479225992287789853409001566403159278561225375682298543, 4955992755917650287600423903671744997417781344631255784951922382765227784141]) + cy = sel2([e[57], e[58]], [16596280733402230599955345374089507399680037832193751466748596443674569931646 , 6390381659733151443695336725554471564240651107616043093647301732553182081233, 17125093365984505488419430885232358010204128822674623886572872558984812477756, 7907776458440631594337279500574606181494889317898652109149850067084027888619]) + a = add(a, [cx, cy], context) + //Round 20 + cx = sel3s([e[60], e[61], e[62]], [13428507160783248146944378848829437095621758280249270905793449036777555016842 , 10292076501843933688687976934900220205880058108224904881677407523508189156342, 766857404192368568735095124452313950539381046754211726072981073742394879383, 19929977262929097751573344897093024390473135465066154321364399543253519251540]) + cy = sel2([e[60], e[61]], [16698341695430068847582701171147088836738454320587148532489385958997389524692 , 15892936434362954902510964691481568586089663041057258511149661842770672240332, 7940515703899915602011570921990242082041971424425808524102519499134803569591, 6891504197906111172381550323513759741804319972496414093225387272302697012664]) + a = add(a, [cx, cy], context) + //Round 21 + cx = sel3s([e[63], e[64], e[65]], [9001788585918405588944162583417858847457169702891113291878897002187678929577 , 6471893763677472946002018028525448192731896031469219164732421705849786414080, 6872696243264239672878286181725922526028148800020555100207514569826971690256, 6457059076269833003010871598305386357557482703463879737255688784535353986402]) + cy = sel2([e[63], e[64]], [2208441895306047741608356002988212098270630744976300198681224594148576837458 , 18524825154497781981405149991295652940946623352876024366965123296382603920630, 4474085805150211658090190066955902897001661633303260299025041221776891523378, 7848328793479881488968680696062292137496770320699466501151951135248413225123]) + a = add(a, [cx, cy], context) + //Round 22 + cx = sel3s([e[66], e[67], e[68]], [9370960127159127445266474449258070389736162441470427007490084241211557822341 , 14965609177224099035387154934147530900281499783229343066828915253839198476726, 10228455969106022490302521106014422994204231909208186519000062372321621002715, 329501376630941941063220737355314017862421104304435198239389326959464907258]) + cy = sel2([e[66], e[67]], [10405035931558887078762806053185283924863039263200495982754625705264574757491 , 15502133231749593338314160389347860966662224717441686478526316588882854824409, 16159781620881884595657183508560936205420303661972673108699575582908291222745, 11627201183429653135859532750162240837549070563304757137644487859075461689878]) + a = add(a, [cx, cy], context) + //Round 23 + cx = sel3s([e[69], e[70], e[71]], [9435538689621391149659891449161022313817917158768482063316123517911261629051 , 20034929826130067090642639519998781717754864739607562909796887703087596572733, 2387945787036487514595261230908460627602020385539203589000341684029816345462, 14287010417915184144199881651073103018750205011354171060170509879133644433324]) + cy = sel2([e[69], e[70]], [3766822724536031967241092846229703633913210151222385593884505545907921188272 , 15647190524611689022349999926088308537492889236313676989549224633916679679521, 12082040904926878889054967598271733538467180307938292871588544645957948546982, 18694076414086475523793644660947803814318698157437774233969783951279622080580]) + a = add(a, [cx, cy], context) + //Round 24 + cx = sel3s([e[72], e[73], e[74]], [5859172856191457066677368896012140820864205253768332100482413148381377691822 , 4109040705512320821322629424016219907769924434419769556997996401827477205364, 20898133598840700569835017147086534068242670333567622549169818027799138688520, 2562111968303466794360830608662119102867266861457203102917042145665851057610]) + cy = sel2([e[72], e[73]], [4836009713585714465496581912154882382453931120914721557804515434755336832208 , 15143499611233432306382398214139440479742818510304232326049564749513747791130, 19356118393311375462052662305789820240618686111711161337705029468367145040988, 5688481852857742015073912476996667522213010914545901826896160233670889226775]) + a = add(a, [cx, cy], context) + //Round 25 + cx = sel3s([e[75], e[76], e[77]], [4623242138639627730014370601705308411725596532862597538813607327046410321312 , 20015154717710755506154819006635497782515667453025611627915382742560093423171, 3514612823502534944140986983282927838609295377065173960376131742886885892219, 20191997625806343264590099369325683216271615998169853765554784065039674586670]) + cy = sel2([e[75], e[76]], [6538526769564699401600543915225940144078494544354769810309083421131300518775 , 9118555176257537603156148628736012723504563452923782011591078402032233615522, 12815558970989336318868652718709831589595442899079588636818966291960853991023, 7703616604462929360855592091876031952747180200478430464323567906544600168109]) + a = add(a, [cx, cy], context) + //Round 26 + cx = sel3s([e[78], e[79], e[80]], [7426207409769264985012540642921370782277366662985635838803842004294008785185 , 5999778250617485918891782298009709493035045140093544961901833503446031905913, 14130927440165985043471103750344848991689715792245153118451423398655300689873, 3796482870456559450471870663226834834712024906775762338643689176551263991246]) + cy = sel2([e[78], e[79]], [16458635168452867431186476181702908205218256620571557119181621733008943007186 , 2408736441388526903801723805189252326923776373802231905332653169285504488507, 4539189593448662319023898529532785456602052593687554864880479361284144700884, 6490484418842862735983085938727562049587933870197049726191839108647357897041]) + a = add(a, [cx, cy], context) + //Round 27 + cx = sel3s([e[81], e[82], e[83]], [9274793422641213328277630692090429447322754602554792362167389139799628719939 , 18213562677024477140777501284013103092531757860081519011108723177266099803615, 5928914343334640962747136863911294731157726634392529232872962806197144988571, 17364692793332784962323580622297080260599290963212510860189969183095513710617]) + cy = sel2([e[81], e[82]], [2125001664000799929029867649528637137680130729147235858348667725168119291610 , 15787194912569598784093233335743719308944830093009287397433562464152875584662, 17778173794489364127449950674919162836220066518510591114146982109869842663244, 18328553264273479562530008673792097214292102347103296244385349755449098608225]) + a = add(a, [cx, cy], context) + //Round 28 + cx = sel3s([e[84], e[85], e[86]], [13710259114758767844337497139752382122951774216678047790125818858626546865590 , 3343610505090632166881693615831990684789904804852523835888323130512752436557, 11550335352408668215051239093872906070657140182660747433535878335227749182418, 21793892863650948729507322696305982607072336532791041097212359516991274087980]) + cy = sel2([e[84], e[85]], [11846136982947366289908137269088548542970460276305965388699657623060915691485 , 14439612735106182034303100596819001121085745615069593580210956482903072588413, 11243378354558219750264654469308879862376787156599458648274627817471028307109, 1416613801077957126034351583571856403044235139983509507026555602579721659100]) + a = add(a, [cx, cy], context) + //Round 29 + cx = sel3s([e[87], e[88], e[89]], [16898533007964698268976570330413504736326631860509774315700399063143612293661 , 19762411747110048388233897239023416141949331694011759548598869652948167421240, 11749964437081939283728905999710450041654325285452589389081577137553602604162, 16314155164640857713960417655857498051596153632474886680423284957133775223285]) + cy = sel2([e[87], e[88]], [19301014021919583977567348438857464752913991729661145830439339193394619822674 , 4081042960569737826610743202667127127506276066439423960421657857551695871422, 14520831020919654323745478654766278220911435521609622705053803095115677276928, 10347543397607839527923790122253286529883327940351684415635401368115385858121]) + a = add(a, [cx, cy], context) + //Round 30 + cx = sel3s([e[90], e[91], e[92]], [184222443282411811008485293978090987184574946550463281113036487016967683795 , 4323925196392247451702039714921386345420807454721539995370304513020371659426, 2346825777983317939724845287942565740027799801885272779028341294742495881964, 3497425097320782814346947506403058330145264032565372769682636446824270312453]) + cy = sel2([e[90], e[91]], [13850322095814274715426304026104710047724256505475254494587134658322670671529 , 11511819464672461161880080290029237185728360968222698390620899743097045452336, 8068296678016129536739401811575622149523917897086227154769231758295218255268, 10263809994502353117991909442849926729413925087877766198113026233378613424956]) + a = add(a, [cx, cy], context) + //Round 31 + cx = sel3s([e[93], e[94], e[95]], [8995760760295995916308082490351740974639094331313720900267671545759667549796 , 11019493928623991376174717464416885911906134873939034428175124701672655752839, 14017581177532816290320938368540191606560126820406006677979240977503063555845, 5992767544073504039822155308781253229334004182511050716159238341577147193720]) + cy = sel2([e[93], e[94]], [19514976680591593876219573359164805119998241765130948583982557052811782267484 , 16839145730766072636625126513480100227916490562760284965681235183731245254947, 1021292692554672699619028273609664837317397089685876358558294458673381089032, 19705834660126914988160966717581159186486910721909298688364547098333399879621]) + a = add(a, [cx, cy], context) + //Round 32 + cx = sel3s([e[96], e[97], e[98]], [2527638437523893015660301196665088766965588386392795314680197258969354623363 , 1138471124880305373267488994599338604626881130398552196301155187554578496993, 18796280357765998280755689911684961342287093510307513491082157499389652187596, 17845424627755166990290252831103404879406229534320972756944316138691932923261]) + cy = sel2([e[96], e[97]], [19210721144465266426749734142673856566947869352583355496554030705736452071361 , 14313930380744847001650971451811594041740544882894516063775993860263195402168, 21025107892840987725102949502655791789935181032924916608477285415225533245973, 3555509537083802658278452964512402851284368794121767087246797342866139363946]) + a = add(a, [cx, cy], context) + //Round 33 + cx = sel3s([e[99], e[100], e[101]], [15846792621646742652974245065938230651829248095884295067743275618391603947137 , 252268672903219503110064676037004166486655891926695090023400798499584132445, 19530459807361347014390846162868811023755147873522489974990781147946076957319, 6779173153401014221878658847395058091689669042378445736327791547741105926579]) + cy = sel2([e[99], e[100]], [13124560942345768357314581178595700674622208923899518932907915338485045148127 , 19427900801187548763760894641856199686412861734645157290016060446141874396762, 10578265528433465376709803300626505953445780532420709942597293441366167803051, 2814357683688249343045032287308948679662030207205739212100871663137250686972]) + a = add(a, [cx, cy], context) + //Round 34 + cx = sel3s([e[102], e[103], e[104]], [9161164860624082016500689976633279187120278305601384250238486553068325633742 , 3594465641083658357640727503005755820863340547313408576898849399984296404007, 19745546026637204577602881915206827000693868119693662890799396502208696901732, 18116250696909523241042661347132525872828324429923244627289119813508105665938]) + cy = sel2([e[102], e[103]], [13685063021736046635507535227140671955502404587270095297507854657927533098685 , 21481850865118949667886934355577641333398731968912180643307092533138863580900, 4539145198976864585367021826448478029652078179409326031693175016758410731544, 17461973876416788164599136875394849349337761082750935487057356278682772411162]) + a = add(a, [cx, cy], context) + //Round 35 + cx = sel3s([e[105], e[106], e[107]], [13763732875937305178862849318112327966371606623409616602363024527079535241003 , 7146728911382113235576196126361394323865045988036623175328726379662117800087, 13957018179677684863250069220406779871369347949049594304698838627334319400324, 2983130106134530061974606593769911479536904265326576922594002168086009867582]) + cy = sel2([e[105], e[106]], [15902927258231569893737955890837667742457214947649307818302524420399149241212 , 5394027336566373776896911094388660738090625577337970061356832815458464701108, 5175259754491075858870829756483758144360263281431531384832593797283930411109, 14151565798137996208654994826049340981954317623288904943712618832232605861595]) + a = add(a, [cx, cy], context) + //Round 36 + cx = sel3s([e[108], e[109], e[110]], [3511208839914156996602850728297722115315702089624058744395068873552707949103 , 17785314838779826411805999953134869098297432649970533754606824062794244465005, 19568380235187862245567915799143793188430865272594403468605211965296271194922, 8968217637384711708369798047935037549991275897411766158377778716106218907618]) + cy = sel2([e[108], e[109]], [9113093883676083424918242033136578270322417571556449454840754893578163802387 , 15195400406105586498427391734410887774383134313041084245786188708846588107061, 10391623490262978616498794103188417653962360594423044385370483010810406454393, 262198447430650388196958319338915798147458757989176286529479967365139093614]) + a = add(a, [cx, cy], context) + //Round 37 + cx = sel3s([e[111], e[112], e[113]], [11522295231047132260758343744179190547608150890072723735296048871441325064339 , 6417300850099046536319790332124930285535196168151466782463281196540309297983, 19137291956859275825926699344301804549568562573423342909926469403211747707345, 2774443339156228722046927543564067034026765236710736809480294993459012359549]) + cy = sel2([e[111], e[112]], [10997633658189180813501132314065688584832302881630691645920837501861598079973 , 11230602434226993956802641296087754248529927465162671110571036062223097035285, 62131588140380451567557177282839666875193860544849125919004473298285110712, 10450442472445392653150568721579575112681026302736591474982185692600259786523]) + a = add(a, [cx, cy], context) + //Round 38 + cx = sel3s([e[114], e[115], e[116]], [13408931465122001423751414891302829165042502658140645208130973182525808774770 , 12919550455861565687920656314018840423444710872112059576718885637461594199393, 8902156077182438987081535936092318477847851529427670854791439040325983142815, 10551142139308027026174282362670932774470751296642556552082094389923387853839]) + cy = sel2([e[114], e[115]], [9267742985382681478817853200119409918969418222977519894367804134923874406267 , 19027179442258820884726400809066833518658247567670360715860243154343698445860, 18038603127894002689531978859178109088479567097675385814346786297731217235404, 14150146649091182389991766732798336665028567292472735778013325601175132243538]) + a = add(a, [cx, cy], context) + //Round 39 + cx = sel3s([e[117], e[118], e[119]], [6540890698262697218677202035403667770177820101154223149908034301445959517274 , 435497241504544923461214042595209510655313029058197261483355541334388444061, 12972419969438465538309509757262343703702203355603454637962110103300326018994, 6669959829681253734882192282716498450739929798663147573799606668374867628160]) + cy = sel2([e[117], e[118]], [2642034845320222085946302229307945658183260378358994660373441270519802248925 , 14736341083198246245608013213787697485596965707560872888430876049025049794937, 4329454540840640926293454385395213780440355759242417354895666807552226740059, 13390807756542084619965526671660454489274096296730210772303889980314835989796]) + a = add(a, [cx, cy], context) + //Round 40 + cx = sel3s([e[120], e[121], e[122]], [3375661072576892623715175468380800047905893262660913295358697027074087217513 , 5069202507845220698620539676049456933089654255996130713693017872693588276345, 307360032529211257870367390878851528397463530836715039216723323169226021440, 98081915276387897864111573201930613825497393423677224354881280134376446888]) + cy = sel2([e[120], e[121]], [8987539541637688797931012030256009083390767313291834963652110291129797020941 , 17901947618091300697708370389296420066544823878914604900411880276648078042269, 10639219577401234864823685175468874052621402569992677814844863434253512890795, 13240331547980137691596357784155019878384406802888737259354896076218619627328]) + a = add(a, [cx, cy], context) + //Round 41 + cx = sel3s([e[123], e[124], e[125]], [9662184175454991631880218147488300829920024817382740712599708905755708816803 , 17771020629416708231961523003444615645037663660747267683766850455503462282265, 14494133870721701214401742677540032810309496543890589653927595534007509078658, 16561168866198605810694591274909829276030780262733890202994760647724957996711]) + cy = sel2([e[123], e[124]], [16632142917625566129622048663670437511136716491293457317746859226945397089536 , 18400270017828347077622860778898029123047396355399577145984944065126581795849, 8353334605287102455944569500604056116678191817084945684486328539838325378046, 12147075225903504606648888869906750158496142784038841529413244301117587609138]) + a = add(a, [cx, cy], context) + //Round 42 + cx = sel3s([e[126], e[127], e[128]], [20252038718269174556829574777069549258100538764143309785207012647062643184902 , 19438750079062162172414919070069193686275943617816957878302458952613247286975, 2739523700389893370248547110285910821118647890992955640060929464309561828074, 18986163209792052202203221314221453057559857704913672555327882100075093616752]) + cy = sel2([e[126], e[127]], [1949203652074521007058676904301415827566224382778317340432698169556879788463 , 4017921177690528677848183821427142247358574441895228503258380087834359360501, 10532220115833479369586881444322308530349489476356817032718755221032796227335, 20767633640647488765234831415684490207979213320475813611233243261000228414020]) + a = add(a, [cx, cy], context) + //Round 43 + cx = sel3s([e[129], e[130], e[131]], [13929197264592281054662634434397205757522163835293158725199610804948038924930 , 18983630674546465400919161958500748450652609469567091049588112148279229509416, 21298720061922244441608259922072286340766498728629540286898859613690667559954, 1255771444824172694387038994365972934222854858110644765629654650968093841237]) + cy = sel2([e[129], e[130]], [20928589942441069163400310179733448745002695258624629275677130484867901611592 , 20945151313192869288039616217247173168964585800167278953053768079971885757820, 13394130995265898710013904122336137332320804034657805114241934415456940879520, 8345380486550648681305351465341710151021284756322349929795845243989999089313]) + a = add(a, [cx, cy], context) + //Round 44 + cx = sel3s([e[132], e[133], e[134]], [20820962511183569148336349677594457306122370638840390080208640481304634109972 , 21271204223521868772910817161761075423625575552213963956907846089587689594662, 10733658208915381791180435538254458430504966830986768682084274021501716755708, 3213872100717631866873070659546947812880485326599459130685149408092349854866]) + cy = sel2([e[132], e[133]], [18802948623154501291575097526503171935564067914914679326677986205652424463305 , 18671196065143385675890877955428696189287618414074487330442057564568301653630, 17500512499632911097527623128158674292347613137609268450560746154383855656852, 10140717739675826292242942694935483711727546989965783109636404988746901047250]) + a = add(a, [cx, cy], context) + //Round 45 + cx = sel3s([e[135], e[136], e[137]], [14908874845345243542374913242177817956756346686642792660468745914078612972964 , 6494892024924675012540500602558430897039227451488331729419886431227425262471, 19660118982815103063271284609401904064050204952733042875484811495633642263876, 10404140614423982473417062438060653585074743419249328530274575800693260655367]) + cy = sel2([e[135], e[136]], [5109688569541183345813508363367270401129385455666732942384933494548859595681 , 6488452587861781859966899732568514074249818909310744177483425914897141192195, 19759144330570995637436877834773866770106917696169828968224667729682932948543, 19372158643071160860924236286390794017939077735118276297478085704446653404487]) + a = add(a, [cx, cy], context) + //Round 46 + cx = sel3s([e[138], e[139], e[140]], [1154476465911192808082307928347900064111325728833428891094393674593800812900 , 6647319020085089760145868568636007917712315513936955502164154733998378717177, 12584569464684026880899751873241162942166450853083376779447501714905643756083, 14243280142991602029691394563175478833697759877979687578140951697024930901167]) + cy = sel2([e[138], e[139]], [6461899930945412323497751736369894620103555271239754245787726192367462376648 , 11218209351589240489615573530963044202098579836550413344228327749253510456169, 20533060824796367399322624999408451192171574545415433951669661225068106752784, 11799997625790604641690313275280372066913716290701708574743226300595877165728]) + a = add(a, [cx, cy], context) + //Round 47 + cx = sel3s([e[141], e[142], e[143]], [3106120971963814637086817095821216892657807437909030172048489357608690908664 , 19983788499223635315597700897580134177379185544458724791602486120287361195709, 20011311503290782295958825256275853340402122848359336349363185226433870439371, 17061518479999755720537296647402074631690029621158571296727706119729187756044]) + cy = sel2([e[141], e[142]], [11655780578227604806047758025034240629153798954712964172707380870816316797993 , 622054523287271568164593718522127794491026889292924398674394690726823527200, 16135285950085594062254918487673085571627312978983012587993350339361155816604, 16823182833153464340537049615227906529068252572342151311965980898836651237386]) + a = add(a, [cx, cy], context) + //Round 48 + cx = sel3s([e[144], e[145], e[146]], [20374356410965803131887119977813187747682102078262988894186807366145009893312 , 16140790886679277390055909624981354111468382311692868339667095804914180995816, 5269708933005858910719244518715051229221686961187992215177561544872857207052, 17003669964193566226265890987693478032205879390270724431641892912757008513023]) + cy = sel2([e[144], e[145]], [15298182760377768633156209223343487909782393543670382286190369588693664098885 , 15694313374278606393252570906724471325000910752891934797182427274800382725179, 20211423855194801900153066955584657931131527051780164510917465106404910099513, 15455288363376670716062020330944532534047008363514636685826622499678373390425]) + a = add(a, [cx, cy], context) + //Round 49 + cx = sel3s([e[147], e[148], e[149]], [14165004713755765453589527153323887724160944086658242248604905215519807263185 , 301131970962481505862420187551701457358785403147894839379498410579773149817, 20703780629190814394908582715811669803434202446164042946560257906844612159868, 12367443634404793487462362639029662097550355799821945744713867599113535990920]) + cy = sel2([e[147], e[148]], [20401715072789557220769413113920881979690352159560582443280493351937640089943 , 9512744351810164617160144481900582699060463555523641782334998030336637339295, 19997026788203221539856525472799656962300551306251956395441891331721763269878, 4420107516401930587358239495168429945976230331917756712920657983670672632753]) + a = add(a, [cx, cy], context) + //Round 50 + cx = sel3s([e[150], e[151], e[152]], [8103748105126096403620617531109165346111017883414253359146860083465308290054 , 14803748343013980101691104453457628404765420707022107332787520877316491921572, 6553189032217952509828188229822974795796651131494012230703062173727191718256, 14488140647832162063035434131927730449663617866962750748399561354722976225897]) + cy = sel2([e[150], e[151]], [6900602880532330473224374524196761198151861405485326291615150754345009304151 , 1513115647408875522957756488493462370777248725072062752756727843920832160085, 14896301840535712091808125164986771300932651268478608922083726618785610993431, 18048817115801653510192862998462822947761670069362294686696577131702147477504]) + a = add(a, [cx, cy], context) + //Round 51 + cx = sel3s([e[153], e[154], e[155]], [382543238316875203894587902417533689378617036331411163099475938996384971274 , 9619454944964330535387495829359535093743583319913348616872361595592109685167, 6081261874729821958303230238004699407225832699063899155741932401034312247576, 3156137884201329913786702605630625537320273632812696416791152392474314037759]) + cy = sel2([e[153], e[154]], [4793004393185972052681267640894832507973895495734257655931836941627180322533 , 12524126851245821931846984936446041288760976334671736634358685272033969216980, 6277340058786227516467028124755004985063566609742747175031180490042372405740, 6981569030046806591634476164525159834865090256544287529201527685109358245562]) + a = add(a, [cx, cy], context) + //Round 52 + cx = sel3s([e[156], e[157], e[158]], [7242980429824960501440666232145028986161691674990466362832703971174936796830 , 8045674190780012690331364750465564303458553754280502177743436741257674712579, 11260599103741407968666669605286104777635431193927929500939820855376897097946, 18466264932289657017935069178634633780361979903681010210726608765753592098197]) + cy = sel2([e[156], e[157]], [2313823382391584526084833833122921512331314230217820828722208559851046887792 , 10089801374498501989652677350203014944991951797848003015280234323125565001040, 17328843896403558624774477961071623822106890748911687259696765820336743222251, 9096128104648798569037169791537313868030583174665566146242611146033775655076]) + a = add(a, [cx, cy], context) + //Round 53 + cx = sel3s([e[159], e[160], e[161]], [14129501557712467097681133312480956681237794589418881140932742431414452181802 , 14215253979300894109266393937905007744674886266134853669970409340633353105422, 5101954416353969027375336730301151965881345391948426977373049227857281866232, 14576353231486654843487902119173617652532372118230138091256904812874365465828]) + cy = sel2([e[159], e[160]], [8967890713970048745032869372462848543847652746940083058618452105243173038725 , 6265601060440963621915827684472693851147234848878380918293598569151688236174, 640827344679117882936589383352750227742240703205324868948399729377934123492, 9724475542168570127797711494687143027178927970205326782155651202256929792882]) + a = add(a, [cx, cy], context) + //Round 54 + cx = sel3s([e[162], e[163], e[164]], [5456157947126010471455582105823966618048439614862840203794276433144936442303 , 21043218890179638595653930578748044093798652379401035786184926212259053133276, 1927155268257451951778867733460386031395807546286255979317875653435797662494, 2742904689169248143495331827109449907113748836918731412006506067439664106654]) + cy = sel2([e[162], e[163]], [9440520397717291873292501513394144011971438675685104804031688857727475979708 , 4417998885632129975756353073742958617120204855631898102096412742879398656621, 21718244289007192530526626848367390261419399428442075984244560471039861817138, 8877177915758141474927139565405950662745390581859900899551672907102924557478]) + a = add(a, [cx, cy], context) + //Round 55 + cx = sel3s([e[165], e[166], e[167]], [14850732473677774396477975866215714018387310838284937771253941847508860390570 , 15346251439912975799100173523179670100616030950715800206631108275859894555954, 9806744113621004413976521475016417033548532640900224199389230684453784278689, 21096603979133316753091339975348990230540836494614368335651248862844085270520]) + cy = sel2([e[165], e[166]], [11812452402407343928752680921354215607515699690942611270817873638995622443255 , 6279013985783386608484242724725362666241553499782119548714289191679033556648, 19001277736410456807324578202368992701796359861619482537978016830870842626762, 14081519926521914451511625869848591232696520686473918498999632052868953710854]) + a = add(a, [cx, cy], context) + //Round 56 + cx = sel3s([e[168], e[169], e[170]], [13157890071808158704354468737847471048810392369152727364639634059504126884874 , 8008722424616547903294828680672771630855086822683412918399539174241338981774, 18594694810411494426945160098830123105355833500416479749049639533195702072502, 3003039638546974941710738006242011804553647552380262745534233703293489168909]) + cy = sel2([e[168], e[169]], [893279927671356626449601197530638356692800493991878277093322197544680454846 , 13710236865890222581902901564951693313216932700203676104342205227571583021557, 11991140728188265308988894689292592177761583244141205754043533415013439187396, 7408159576060936012801497750876509797959683640624248586584358220473720101773]) + a = add(a, [cx, cy], context) + //Round 57 + cx = sel3s([e[171], e[172], e[173]], [20379496501734200220097501155104742700678033944324898621914782326376426827694 , 5628902661740155176800052287728775683561775403751721906542502141173662773805, 6649334930850298644282280075473454376493217119135753313843458230202317946465, 13953386616146853105384995231337773651826685901371822028427880819484312577968]) + cy = sel2([e[171], e[172]], [6312536910770269621417292581781438152243262819530627194840110225345012746549 , 6128625960467547051042766267966540761259574034224991328868848127157477007514, 2178504154437332931470309748598630309367590073987406533802402874933913898875, 10049120191768569519993419401578117655266529530568527176008678950298967775522]) + a = add(a, [cx, cy], context) + //Round 58 + cx = sel3s([e[174], e[175], e[176]], [14193197030749382932133736734505537242924559995077781886176225169837220402133 , 2565010016572214675455233006763278152319972391059007175692722972374012019501, 20022269140157840221511080273245661956116845958170472382643581298431129105222, 15951592620529204477279907750991493798200861674998832536410750610279414881478]) + cy = sel2([e[174], e[175]], [10015961841973388881391587018151977950817576225746650865142918877894543270446 , 10962609190943341745700082387389939598903593214578149618076217369020441344245, 10875728650787073188338824979727792178460025858689164586811311106195554874546, 8704250736813220528338393230481759654328677814076110220308209376595986509914]) + a = add(a, [cx, cy], context) + //Round 59 + cx = sel3s([e[177], e[178], e[179]], [21185904177969045625821216347084191287459806531017721293624058180265336503811 , 1250611256248923800378335492392268625608584743125298517147184362502718557754, 4732901842829850758626640836087921620095030893254064254821493648172485065995, 4686012912505407137434711885457531064310116778761775095814150050521297721079]) + cy = sel2([e[177], e[178]], [21681922300753515822840018285496181872470481450737464910861242457369823926925 , 8250546098596619229605270054781796306579374634169772718113961166155976799791, 19064654253935902908485961089200674782438523882800790190859631804189001729500, 7893084863238812828005589178028293328994403260619345443806395973318698162130]) + a = add(a, [cx, cy], context) + //Round 60 + cx = sel3s([e[180], e[181], e[182]], [14071560871369419892033259843192185467358801846474749773427241883409830032328 , 9559459046618636497241065316366978002044190960713451216793292122894012900863, 13031319565545666906249801044337083380860313201803429372439840529717343742035, 20069400641162643493898109922008601219601618686364720341639616051841829074334]) + cy = sel2([e[180], e[181]], [8710777380190521326883551341251426052007249230093350101154473409247609882825 , 10439377650670164179707163339178975058403688089785136107598148495986084488509, 20130072726000251358667317961033491205160472226244307309389477611437739154303, 17216059825244204015919013637129845877195519789582013765405196142334767977705]) + a = add(a, [cx, cy], context) + //Round 61 + cx = sel3s([e[183], e[184], e[185]], [20777314589605673759170070653370407645867665889025835324139659856710113131826 , 17380793433135473426803899659206730936771330488910864786997506181753180852018, 9135535394443552083655851762956576299400389583070951313661035134759057889658, 19259342468126216922767538099314197508403261200862162612026099962268769453780]) + cy = sel2([e[183], e[184]], [2644721599238941245572401477946144870669550581359063534170381908963477379532 , 12369176861935895868206428376006904712013007036288222495431735574326142454609, 17367574625533031619575225680253098966157776114681359698904430545328078639283, 21794479452176520273231597892096817659539111123775968164861961429589103329517]) + a = add(a, [cx, cy], context) + //Round 62 + cx = sel3s([e[186], e[187], e[188]], [11749872627669176692285695179399857264465143297451429569602068921530882657945 , 31939593233430950996158270398727464286178387866161404769182205304632811436, 6016890150518491477122345305716423891405612103278736006824977752295838970965, 10857254852618093631105790010825256882158099527623146563961929227148379359444]) + cy = sel2([e[186], e[187]], [2495745987765795949478491016197984302943511277003077751830848242972604164102 , 6997914616631605853238336322733192620418492595988404136191499921296408710465, 6173428954671571373132804754825927617043378457799815000168451967196664752847, 9007836187082518685036356739793187792845982511088020304887245789556567564055]) + a = add(a, [cx, cy], context) + //Round 63 + cx = sel3s([e[189], e[190], e[191]], [5139361255050232661773452561726452928115803730344567411456642256556217045338 , 18849283619433745348738480276785423370734769795033289874458118507070173353564, 8448578350964247311518616492977206693278225803594287158372550008714482924618, 9689086950770336907190180706142608582993499523814136266854852845122214734392]) + cy = sel2([e[189], e[190]], [14036051510959474100046039284978060652197630794277473374328558492372137493500 , 16611708132761924749528167866816090876717761056993928787802780141779996313373, 830643686092782069152588625317289527987176650776268015346372712951408738404, 7124577892782407025863252010240336830171667706358033009166413008136074540762]) + a = add(a, [cx, cy], context) + //Round 64 + cx = sel3s([e[192], e[193], e[194]], [7037199118537155369331275916815326054696699996573020862644806346516390510132 , 15801832773874273151484928140234822912161499004629735400320792200594998558674, 20529919447890597649764739102616587236240564012012882223198985848792346137419, 15587579342628673804059001440002406839596944474602936992474297171186661645909]) + cy = sel2([e[192], e[193]], [13107688056462500445700480209995877016295689081542565992250464593152667593220 , 2950999836230463387014662253708191376901146777669866592618407913815214817829, 4910645882425237270468350930391794068554002250789220952036477599584216368730, 3842197005807929553563656299566067039385580918555124491435963737335985608367]) + a = add(a, [cx, cy], context) + //Round 65 + cx = sel3s([e[195], e[196], e[197]], [5946112335249256697077095359378565725733629742750694340878812663903909175901 , 19030634249222736450152769682445487635301904450722490014396919999971262563725, 20272077332559936653726679368964023857291782018546895109417787179027229259529, 4325773325239231432990045180370600024086140077952119719002873860984820794777]) + cy = sel2([e[195], e[196]], [7559787099338642680034184654424868894988928943730034769673486129058256478240 , 14955054800505659097184643689663447282484820948805633199847088945313706647256, 20527315092050743721874398127103128550881291654522271023332206474058940158292, 9254615232744118309709861811378827051213745889996697483998530345751148041402]) + a = add(a, [cx, cy], context) + //Round 66 + cx = sel3s([e[198], e[199], e[200]], [41373522534463253583709483090344938032869463670116114182911184041610044395 , 123058269904779894306385100149700584700988943576532400555257363214064615908, 2188259327903131136942811179577591848088244960706164332041753317001971084806, 5677272600001855408525885379297081872841669910685379249005421935936405438326]) + cy = sel2([e[198], e[199]], [1812970364913777725848745565574644898635129603904027984751613694625700239455 , 6325479481133126048154398075474627535983053143312386360869927669212098083218, 13018920334214076613442336156617958094802950850259563883918734414290288034687, 11007863126994999194753256186448493793850907406765917922947224071691321773988]) + a = add(a, [cx, cy], context) + //Round 67 + cx = sel3s([e[201], e[202], e[203]], [19366353265983664793480214800587120487923062015491759603977854723148315579274 , 13009712389497066149642205706505053720391552889715847781477674095579012684216, 7540090586243428109828867879678893096981460680323209865296583411528024312326, 16312880719251887899651071843693753472207446322138586240016038563189666076704]) + cy = sel2([e[201], e[202]], [10425762558101863677692090103799691698591185440858290129753641015260969124568 , 19889759528114345474077603906066211135049113446169104039752988610769598108616, 10189577411425365730046714422122931951193107064366232919940491025624263274830, 19402847860324611226251435664012558569374211845205502575728141649693622181131]) + a = add(a, [cx, cy], context) + //Round 68 + cx = sel3s([e[204], e[205], e[206]], [15647575844595805283124278572298605369081553302159286302039104118434564547757 , 11119588224460846619648329471078205852940427394545403397495758589586019867123, 11531502595396972280500527673404404955773795456604503116176223280757803701142, 8880302652736630728773712083983401143315564427649676162399333300472018402820]) + cy = sel2([e[204], e[205]], [18121989769429113110431033241130632527148185431169035091659247063715924437727 , 20873727571773157361636727287434618496229040659202161464546752313173048350714, 20691117161323169072636575178583071560333787206766658873639451682743014282486, 8341316767034979343476640425183870254531797329971610276320314018660072501097]) + a = add(a, [cx, cy], context) + //Round 69 + cx = sel3s([e[207], e[208], e[209]], [15099126396506559307312697471585164108461593918632286769972271267945539855806 , 19719992822745709208744805037389314455441129806628318848823336999297717461102, 2498623947360180463813005839687911187525292314091943320262937967401409761873, 6773513521666107580427042608663114222160509705880285715315137855519926605076]) + cy = sel2([e[207], e[208]], [11185464183896587792324099270269738719144599552792757002841466742562118002961 , 17962378754832909648632213279341274522205662106198070463591287770511029247082, 9572883626752796327156744085207279145562604122052196885537416403686418306743, 849739335033117039567862203783008236118271414428303942526044722712316390134]) + a = add(a, [cx, cy], context) + //Round 70 + cx = sel3s([e[210], e[211], e[212]], [5586425841805464495367763159434170408121119147683098906675715851224959199555 , 2275887592294698256371035540589451793263643729528648494997423042939590025265, 21623018362589173579186020601617142922337607155324626054728009524185014872882, 6470935377837087985284657580709150204914393986124872780110914178120147824883]) + cy = sel2([e[210], e[211]], [18977748529759410811480134751116373952642146764796083016667926272252310801539 , 15415054474257926323577643558627142211566179025425425674112343915385225979379, 10178696720359974033063364767044087765079200964723755314869211737985682962880, 2751262919149939488788372835165540688204591943865442185170575019042791606144]) + a = add(a, [cx, cy], context) + //Round 71 + cx = sel3s([e[213], e[214], e[215]], [8067396068830332270789178613335432253659758303711969642714931687060160381303 , 8639011650360344590794984878540401640139910601923862912593792315052343319076, 11233915498048422123675368878285943174009257862418242010192825609765986035356, 14474288438243449444797392475230229280689019808482654245523987676777400402951]) + cy = sel2([e[213], e[214]], [1109389204114118726338211511183391561882818362713716952828416479757048480713 , 20658495580821728113676289889282525822016081521980495256710356417074439523320, 5734616557338566574377893898300784804059511397655030429323489999855673254133, 7694030151585859685333610687574701561418848021817379115721565206849330185976]) + a = add(a, [cx, cy], context) + //Round 72 + cx = sel3s([e[216], e[217], e[218]], [14694205333290671963708923368506587408024223912051732033761240288927263651380 , 16846840700984603406007084554481852964137248522784508429412010549513323188912, 13176399412773372610094105377631574988462669519590170596472033646615482615262, 2687848140625094867763341291336975245615611233615607599401834736964978577349]) + cy = sel2([e[216], e[217]], [9656049051507081163863869851380474393220762381365090138663873299937439711626 , 16257833452680722743254377629669121273261457821544261762335781528496650481193, 6465537052899418297534883094198381748729828452125250541158965933076691478294, 709697610986733714785106299677092114124154955937070541190663241187641683175]) + a = add(a, [cx, cy], context) + //Round 73 + cx = sel3s([e[219], e[220], e[221]], [12368397247649882906953915991250714931614715588424094368585746160811998953306 , 18782888042679815293214947449937714827609414183597755427793821090364126288476, 14980906670860851104998617553690749074165805207013703141953243482569349981523, 6579728809126224271038924161669519472291072114357057900231021883849035745958]) + cy = sel2([e[219], e[220]], [813793955589589118694666569995091571992486583635127942664119751723536369919 , 7944299604444967298799338830762202580774561040186193713045849824532426689590, 10002642178009570948907228870686621440930898426698423035982221525801621370935, 8479337223317874954343670583381865510386888037444628897905418707487375421325]) + a = add(a, [cx, cy], context) + //Round 74 + cx = sel3s([e[222], e[223], e[224]], [7187732531650016705045248947412886871494880941757180032721434029527647591174 , 21429737681997573327768382790700665701419541321736653106996131182050077581533, 11836369351087123833634897021408898134248512107687639835461193259880629295891, 19132784475506243814038464623366364810380933540097619300595341694560215897043]) + cy = sel2([e[222], e[223]], [7505964932526905326140236282846132917485872002527800757209057356562826370965 , 7446191000078603169082551991705097881255381261806164450828019975914186121730, 20501368217451607884813098738754813918145802982055856468691458112065708320700, 12111360534733555932929570216465933882611889545473508372687771008732927246750]) + a = add(a, [cx, cy], context) + //Round 75 + cx = sel3s([e[225], e[226], e[227]], [11880592453253678945312808709337779570677968939895786745513483795196121148239 , 15885465855717299709344092447684246292163545547216436459368792952573638150871, 15785265541005027154032372858808930773051366971093462129449868653918773012805, 18569197812514885943202170611076608358219751234067371040250790526837986392838]) + cy = sel2([e[225], e[226]], [19319714983097503154896952315362236888483358620825042533226116711980128027594 , 16203396727641772481371087324762669694595077074099718953937599120235089562441, 8069072007055358551280258194912706575285364270109077890462380604843344248137, 14879918508369225877688675007526587407926006842700210091106836056129459129297]) + a = add(a, [cx, cy], context) + //Round 76 + cx = sel3s([e[228], e[229], e[230]], [4665897628623235203637312232323957679483103295583092141578808282040205079719 , 13624944208440724520944284383225072602905876122550187793344788447894380752405, 13240065107073736104958720757918020581159288509346627802839384665867212601652, 5404872141819776433203748684385984691445987755176034496638153799038857512389]) + cy = sel2([e[228], e[229]], [20713846021060085908071105513304556412817630308151607438714049866357354550752 , 12308156363070414998141304956459569678321247441462175945058420898750569812289, 7869135919638822130359819523186642202243136255410646018113662355856102696554, 18106721900555088660857020092432838491684499647468676099930405315728768226404]) + a = add(a, [cx, cy], context) + //Round 77 + cx = sel3s([e[231], e[232], e[233]], [18212889377782903846034117170355855193339291343619773736161614903123505780500 , 5724371935927035469891307360583032289870105083635885948626519084327837492412, 15018564556029978781532805643572668082137657619876811702006326742091833640503, 1980690392504623526106436839420486135508948878537486163191798777558809427629]) + cy = sel2([e[231], e[232]], [14150007145691261709583376556777715716099818143565185837820917588114159379297 , 20022624235079706615759218203483775626475427851084411515081825296526003331089, 3653600812499303949236693031235500821149221426419723829534939359247593779698, 17687818220966506140783793822520601258809092691114698078370817997514472088683]) + a = add(a, [cx, cy], context) + //Round 78 + cx = sel3s([e[234], e[235], e[236]], [20014362392122060372382978901186124374461219393111624832280409989286374019151 , 7678149165067745993890478281145655203076154350573466295728882151032664933813, 3225698435546178867794794576435022149554488042976954865856749306115721077662, 11309031064526492555710928277445241789558140050876975815061803061421298770441]) + cy = sel2([e[234], e[235]], [3781524301363795687584984812832316590367643113392401377547409393858835211208 , 14954378542264966404669454369751236758988379152056658083888298000396867621936, 1762346050163239223923110798598502612894079706374187891044283390513959164382, 4511820337785812086858556857918524260240820667203320876468844848816354037596]) + a = add(a, [cx, cy], context) + //Round 79 + cx = sel3s([e[237], e[238], e[239]], [9734499467834650890192498500298459962067559704398257089549121433441674087115 , 5215135617552133686060655322881340267001697536486897440412599806944209294580, 4188240743485809003397687109987123955188618656835900004447532212211334022150, 10646753846009034357734238656245532993332944314059322522045789305478499710981]) + cy = sel2([e[237], e[238]], [4354361275489184569727883669567924050940590772506719250562939951242102459556 , 11812679101253609883065116716426172392592451529279171373836703114919477018303, 15938685241828674681356945591247179905945286496762161102822537588243702016335, 2396399767043799129388585002615296373717040489521252489057941017313192676808]) + a = add(a, [cx, cy], context) + //Round 80 + cx = sel3s([e[240], e[241], e[242]], [9547054830379311239093093214427099367592481292385809745992166194109928893132 , 15809211758984123203744250589992081971737344928666499432318524828207451637502, 2317605133926452505125489082200124096354438531853199813212363802981648616781, 11720218057191867199121604823871387192503455956722025424220873115151171617846]) + cy = sel2([e[240], e[241]], [13627319622459471863286677434492810110443625239619395014230589374758547978269 , 1429116229161069264517866355097922507661063351137334983223517731193665190730, 8760550298269703331457356635709373772631633074463698514870757469189354319951, 1695059580774200437965405056230849147697820569205516838038543601601027611172]) + a = add(a, [cx, cy], context) + //Round 81 + cx = sel3s([e[243], e[244], e[245]], [5462734684060346793723051717116621327144354637585189012464556861789633254735 , 1574368603481037100592052661337337694471748163849816976465511323905498090898, 21017620690824743015216528248522045704369427405753453300912995325024062710748, 335774257251677761852834523904277348100779994383726453798657085528043830396]) + cy = sel2([e[243], e[244]], [19956048369873968081515874523485925798105246605761695905870795560621002747577 , 9838187823381646970305000918713399614038197140004128824046441620722100628627, 9761598443789947780667845618272433395258577614354457312915153694570906468084, 5678382193061301565104967410106463714669588791192144419019555111526838349597]) + a = add(a, [cx, cy], context) + //Round 82 + cx = sel3s([e[246], e[247], e[248]], [14120934246971429747829618071104732571014495017644755746350410437296386191831 , 6321525285327330824512104449106606616844709114576208465479970358050873874349, 9828948304711234867338016094087396323909457869737239406325931677882463208355, 18078003119304519959309175940845224181126936983821549690560235900824217790962]) + cy = sel2([e[246], e[247]], [20946993100078048703890437478651577253995893117657499778417778292965813281806 , 14356404021232332461217625395600664517715960389258731685389867303545696108853, 2810577432005044954032138045179699447584646279814848461184496089430514835598, 8767040452903340993130881597424027588451974218686780194782289690479045090015]) + a = add(a, [cx, cy], context) + //Round 83 + cx = sel3s([e[249], e[250], e[251]], [10074124480658003038181060843544012751655263682971006047574974839001332519369 , 12077899488247602319223956898393373607365192976733626340271805296106145121355, 16135938726601100366620437452815649119119591825429317780601932003124015669028, 8179818941824323394614877573129531443686047058703515433852568295536575458823]) + cy = sel2([e[249], e[250]], [6742523042997173838799423244280133352249230789995302906545025471831316165384 , 20571270140927253125417728386763981919687051926731085366043566448009069227191, 923263495309221023264076470401516657594260797987069910555955234338720881738, 10846387476002903807347429282866412191160400241233297902208546470305682775632]) + a = add(a, [cx, cy], context) + //Round 84 + cx = sel3s([e[252], e[253], e[254]], [9734317150772506967195863825775613184177780587009303743393397724706924797808 , 11208201130011695436334652728584169313726840614571295516236997046457697153324, 1222680486642983364052833343811429934453835860106899436901212790725638894713, 12019238493894483056724448289009076436822742112482573063847552596048227585627]) + cy = sel2([e[252], e[253]], [21086552119896541186107689532205383551960199801453516689016972250104900583432 , 3056767815025727154134820681013380076250249612276183869180162238277626532027, 8232281317297626211055636489579107493658454229617058760791605403582002142140, 14549672514437654184453326941604694948116368249587796119338038904533837120165]) + a = add(a, [cx, cy], context) + //Round 85 + cx = sel3s([e[255], e[256], e[257]], [19897146034704593618377175099239959996606643851373776355482440566659528393713 , 13567220274372260527197800746127305934893509881083589343644604005840555405371, 19175080795372179131749429828665039169211560827471558543841205575231867635965, 6917449549804522032498038894724900459329834531091410689621076525743611296938]) + cy = sel2([e[255], e[256]], [12223657826278264815494051932052421695129917274617530304443478482578919678308 , 8295548603728936503708692859047908287111164162226375098145740427985958712611, 6607229719664137890140258196376647042900642854569636028419328459816951119658, 14110421155257010376968111292134385106023449978845823063864491477811661996253]) + a = add(a, [cx, cy], context) + //Round 86 + cx = sel3s([e[258], e[259], e[260]], [8185677100333640041421355126903921619342273914070568426300075868606141405021 , 1670466886055998857358105826250955310011203741639197041742892893805477021056, 671638389102335040808130453738616724135371178235871000115155863725237535561, 15155007602444057841308084879571465766457754342497255444459746080732112337898]) + cy = sel2([e[258], e[259]], [5730721122742653576294802609542803235749403433458024692842251665338778112357 , 14898703166129675283863893661050084311561656604196737234704191900969087474133, 2459074141813559460216507737311533957327810551114696579502401763839835381335, 15516107503085209346875467061340145906150528515154791297494671889511125291207]) + a = add(a, [cx, cy], context) + //Round 87 + cx = sel3s([e[261], e[262], e[263]], [13654034957145907815962106285631017905892861670471883127206658577251723739165 , 8633158844589460452837721754446206625865140330878411953122575379370751622485, 10232722293127899126024059808155635562748968165573438955077544464410325913567, 15328263964181874734867171882863588382257876665732200627067485961683406281267]) + cy = sel2([e[261], e[262]], [14648234277430895067547661111448501238234630914838612427562971477472564218927 , 12394752068682518494797840832073763890437175762631359486643184011399642941695, 19427382571659868487644833684469199967640111942906298364811415181281091481616, 182598521940883711045871251162735110551301299145061787687905605212153955957]) + a = add(a, [cx, cy], context) + //Round 88 + cx = sel3s([e[264], e[265], e[266]], [10625366736090949097208784405733508126867531010210504034282606844498242195460 , 5745457912443473561064508106222759378152708028067817946740487826967842596074, 19720099885004155494384241598041924024056522066497340576395346816817691557959, 4411557748754390593675263772383003703921572549170163035845149756207936580167]) + cy = sel2([e[264], e[265]], [14732913015624058203205922728424826465278063568996784510238321594483738024116 , 8539999814473505400128567752428776172019356440581684960088711125461388816752, 8671134805346361443739204337860301475415660510460401138135319415884938499794, 12889649495366374604591900250806268552879620119403975808021738180701264567775]) + a = add(a, [cx, cy], context) + //Round 89 + cx = sel3s([e[267], e[268], e[269]], [8424620995080153959855099087384460880708718787657472234234125992142104413784 , 1213413054380708818479960383614577938132447492306231448400493113424770669073, 17993616645286674150803280096391639271887381916203322164869533675674274690369, 153030618728554031479557843767027262505356544554897273649773418701874030937]) + cy = sel2([e[267], e[268]], [8774350273413061850499929377371854983526435316805379820854063460345613579740 , 160874859222003480689240665151063301233791348742268400199413950144629148606, 3864981636983763871420661536128329698816776138190284810024785475130342429509, 8927799801878514388025533121285392339945739901708290822291826043102309328947]) + a = add(a, [cx, cy], context) + //Round 90 + cx = sel3s([e[270], e[271], e[272]], [8559837035180670877234803295116293964077309001575836599087921933374799946149 , 18335809791652365585369283816437201104065890639760635850904865621132150615442, 20223042693949477624057496950714682763488956308852238106089638364544757819336, 956531986282862630457073126978994765430652506058410664783115436243377137130]) + cy = sel2([e[270], e[271]], [839500690449928047855071514156387100713350925422279056462945330783580827563 , 16644736196961833445797352798716804869773621626799896168771841453493474463773, 604545836161644183235683876796430911898168138926947606928620724963455977159, 13372011982201734306725124438714782615028067496534473713140957917136368058903]) + a = add(a, [cx, cy], context) + //Round 91 + cx = sel3s([e[273], e[274], e[275]], [2094128027031828157560092686172909842260483168819281235210539106189673022187 , 14831470033363035728579660771199958641838096197597230010879786959469055433282, 14580113677826055589909107333827815551732916495147612562237413782243389891044, 21457439024195964947733246659608329461028391228550531897929776149059108022400]) + cy = sel2([e[273], e[274]], [11349460624897126395359735030876451695289908168621129531254166231469594999395 , 19428708736392770387243553726555356520800900418277262898221664159221843559913, 4432119977004888069457445133143529511285856348699582219607694824086497898807, 9160542608356323143471297830883618199584611885676024272763585312451903134897]) + a = add(a, [cx, cy], context) + //Round 92 + cx = sel3s([e[276], e[277], e[278]], [4354759259287077683606602421630609654573093874872166313972356669642414450557 , 13648951383939395268518611670175324834705441295145081802011558222046663990635, 14109063296906889436525684297777423342039664400074253643711178181120772454442, 7920829805332901764517739207944367186855755092397343817260945923718690867274]) + cy = sel2([e[276], e[277]], [215179997319049227050677351252505122489806707992988193421803248841509506088 , 15514289571504865101354424086151224801481680739860239328031576438563705370521, 5904618612526890474103927634405504783798865056645457180704237978103781216311, 5748211772814574948909294216861178264766343013494657271260147929020820008781]) + a = add(a, [cx, cy], context) + //Round 93 + cx = sel3s([e[279], e[280], e[281]], [8507753630181199902479216321724505843375506218865451254864654248120523505482 , 9450124212352501425016224885075456626937137054710829941179274211424392402188, 14617760695968479875555170000896560124384001439628509056518085157675385430999, 11259792651191057957240332532512267993084988584437199185342993378682410436972]) + cy = sel2([e[279], e[280]], [10815868200773974736475276546832667321164179489094422703987813447328543028788 , 270750089909256057588643640569447562301277634245971255743235422454022028456, 12525264811662854133497240150104162834870195408235601736200987821770575683753, 21492322023082787855062324449039977497952909569982074113097211015628539637105]) + a = add(a, [cx, cy], context) + //Round 94 + cx = sel3s([e[282], e[283], e[284]], [13109291774440010508838814834344208104350382843329321595606001193219335478061 , 18178081082215000330236621415683992037792438414607902561151998975591610672159, 1825689425393769600328701494994687539687903068590739461592021486333291661266, 7793684058500310840246186772109776829776364159558184911962167538064855177290]) + cy = sel2([e[282], e[283]], [12538966751785809241486764416198217361134417700423840996157483469862141526006 , 18918692038570377322252840249784989027502652471358614978414943590808682898821, 10739840318098234656669579810873413661071494114926975536918927404574756289141, 19177195314890990393062332918745346394029203576215723513167013054282705104509]) + a = add(a, [cx, cy], context) + //Round 95 + cx = sel3s([e[285], e[286], e[287]], [10225920463059329189289679689043403756461771898061631555012236633674500607894 , 19821058226025589223575559712382894896410588163797548720897159700660021786692, 4342530929634070742874132949165242936564090903607131574088848141363806195244, 5402483411262228419126012059406829285695506472234034454332016959299908934815]) + cy = sel2([e[285], e[286]], [14845268720181506270843668435047795143673881800644972711347963164805203292028 , 13672974733920510644893233723674603797496603310630434825704649796138313401676, 6411707949262855152252009198588056473458716851460397006471717726058983234993, 18779680229580121519443328584313676056219616039194596697158403462222387132381]) + a = add(a, [cx, cy], context) + //Round 96 + cx = sel3s([e[288], e[289], e[290]], [4836760236524137019788853323648085337078365119204570171912328851849081302469 , 17868028324749251162769441309905628927317218753130618155651317995445082462075, 1772933343466453031175704703581215603932939906355841484695391914536709138761, 3546600638749568273439745161679319484611182076185127936908592367054940973889]) + cy = sel2([e[288], e[289]], [15727462261854339392836033936665994570356817309630572739663218192786419709049 , 1337461376408438722980356088847283448049292537148264126525086899131501823829, 12238707625348281750296588592788256417660177170554983893114345282873428793086, 15525437884516977515442248737754366741726151193578138245479811700230576818338]) + a = add(a, [cx, cy], context) + //Round 97 + cx = sel3s([e[291], e[292], e[293]], [20126221763126240993614454578144859888701958472483256034667342833856637405284 , 19699064573618103786080175406330154847584332570598813466503995653274429215656, 5989506922601319310850294681562133253116809072854033597983216925515271522735, 1000911579713616921402553874631906432389325985380989857769833587362794312630]) + cy = sel2([e[291], e[292]], [20063374408209966489810045113711694748195105838875731221209079272072900704065 , 9194215440981146522641296536570335847038564333573070389731736048602585014353, 9856108459841119062384164372572927792749846793172495377480072007040372623532, 16456996545907573633695460898581306270452076960241899452978065386508672788709]) + a = add(a, [cx, cy], context) + //Round 98 + cx = sel3s([e[294], e[295], e[296]], [335301756618437339439144029360964383534478515390448989496515998200065120560 , 8900295787747118853873347685755889791679080209434225159052383890249026687118, 7128354610803275364524320321498051406687079176221803083268519268078181474486, 10587524605383993790235166395264599817111999691721750015186077104713345396025]) + cy = sel2([e[294], e[295]], [5048381480643837407413881593434054866090196361251156389103862466064034755870 , 5633507321470690754598569732643608340435754341640194463936636395149026354734, 14155759183302230320588700447409830028824433982845500795956824041195173925296, 8029144329154622500871732803176023714578210937344495829905950083327660868243]) + a = add(a, [cx, cy], context) + //Round 99 + cx = sel3s([e[297], e[298], e[299]], [4778598962832696072676642978625204359871247189399816084941520023705687820799 , 1041656446764385248839445285580789894072064765593570151992974139621577464190, 16604772736533716135897718386428759521995904068172209060160905451073360508438, 5434449975739162120230503825057718004673241312353068784008427484008820677975]) + cy = sel2([e[297], e[298]], [6056883361340614567315212379835078890341975776819628834401238537031161511515 , 12948572080347797369632667255105735306309789288527345335385584655912071062991, 2047203431451992701474247296709372094572802843600017662927813418631212656090, 4132565694324682855622172238297326586214736771195057409015171400249163749388]) + a = add(a, [cx, cy], context) + //Round 100 + cx = sel3s([e[300], e[301], e[302]], [6916961985409927380628327393774423923434707859806165446564471158322143896430 , 5992074540412063352415311056228455935293166060283849428112990098777744329018, 15928943908823412922424046027263578805013830577468518797177611363337136608209, 9165805262654590321870254579036281540959358923531526687992873621654142568029]) + cy = sel2([e[300], e[301]], [19113997592137471372275504986229466743101683336744251847362311356790431849943 , 14004712182695079610522706143578502649621084194457654873685315715331271860709, 19337382334092833222650792928980596008310896977712987991984497026496963328127, 19598147310295874176650103171586127283815601834965516057565002042355878900904]) + a = add(a, [cx, cy], context) + //Round 101 + cx = sel3s([e[303], e[304], e[305]], [10948634109523663410073892096301229908363974454242026292710198013874268733721 , 15429431087099938206375989354827088309373134102432374989679474148007045226404, 15424933350139202912640857850279200342934439164947473620816895024212952340734, 7249326591094430300092421476233168005480477057146500206388167575638063334006]) + cy = sel2([e[303], e[304]], [13978844239437491612582517692269818179489578402023377256168376965218369369939 , 2030861900932117628118671150363276958527364035939087076359289004302891739342, 15817916211331592751911789779171300716227893840209480318007078572691072662437, 11627409307299027242340485688430280907603952564355973323102745520536413654480]) + a = add(a, [cx, cy], context) + //Round 102 + cx = sel3s([e[306], e[307], e[308]], [18995578047969205917336954191535061050094635635378379108624715348396977983189 , 4225372875497776800681698864198574622710499387413704002947025943614195612470, 17351437921298308953512714184518159189123423974926314714485788395814969849744, 8648037604000808882689040136601171409077000943524268908332163815927078223586]) + cy = sel2([e[306], e[307]], [13847262887662907650775044616657488013627923118617883909535158774246706595453 , 16327475809001511779800793713087994795688106377254965385366798254360171531485, 9662682437808722890180813130657795806130406684446667889065062080930078837985, 2502962306844881519115529360019706751646009100590601561262014681428188719652]) + a = add(a, [cx, cy], context) + //Round 103 + cx = sel3s([e[309], e[310], e[311]], [15920090333582846150341817050024564335649064112537068561935372152494077145209 , 5605643430930274732542971456995927736808851585930096579266761796229766916419, 16417626123069839752924241752177228747744623168825833393208640134299321885615, 10047503027147056454952493773282171263110464519924564641292405110762258997532]) + cy = sel2([e[309], e[310]], [17200096279975283058225939790642290750952306062383335630123644381672038262866 , 9789126042032908977600199303915152601153926597218655498907321898754260478045, 8000890408406693601499028261723138327296400099255905955307073434675924377491, 4588804177243916206243160261751431868697632792491002746485364561078105548339]) + a = add(a, [cx, cy], context) + //Round 104 + cx = sel3s([e[312], e[313], e[314]], [17405833224461846119127359023602459766899246377474167154738658246656617261320 , 17497966949182265924717994126031328897613192226672854325764486326873236644838, 18112601253331073769860162727184645241197911130662557597456857637926799952771, 18917984642138666446882277898695258545411024830699319452174655151221791211048]) + cy = sel2([e[312], e[313]], [2379006936139604897517171125029127132096844925377650383092744055973319489305 , 12749848257678287712950295235536433677019860991481258729313170570275169590140, 19636804280533422414605179875456610832289030857729756765481423873607782896032, 1918232436869295272222782754406246415048195875894409329377075908962690232744]) + a = add(a, [cx, cy], context) + //Round 105 + cx = sel3s([e[315], e[316], e[317]], [12917351824629483440622737030529674983967542988637720886395195031194160632079 , 8841322465723154205678020011172362816775587975165151786897606627457187155545, 14002729598867581256643018976730132585331390790166577050573493502425421127182, 15268061642248917754819598857052007481406516866069427006418085798086854466171]) + cy = sel2([e[315], e[316]], [16674117998706559220643814233136742237729068875288271911312504301619597199572 , 15156988565931490695937923747057400310765196912391035444903438612244254494193, 10444568487973458741284119360757120950097746658650645740311119491238200646302, 385547467860345680569692008987772843718726855128251196487129380665836896693]) + a = add(a, [cx, cy], context) + //Round 106 + cx = sel3s([e[318], e[319], e[320]], [11485514708661668839797104792911993330100465395538998907154500209956717209980 , 2378564891356297882391172511058064121371341057541144541265151112602629407486, 15431113736930357829525054375951018432490410667610553241393471463868088483568, 15128200972190674116782495538728842150282218770763850888538540847691112710086]) + cy = sel2([e[318], e[319]], [9353349283824572334689034791316525426505799181965760097150790472211583538470 , 2565250682258865603262212838934596650511603775929760392607203509225620090349, 19046693709474252308020355261538860605259941620276924614654553264840108783324, 15978910116968143273641610096037639009526883121076925418594134134597880991636]) + a = add(a, [cx, cy], context) + //Round 107 + cx = sel3s([e[321], e[322], e[323]], [12732753810746517185428320079630798046136898905138090354428070504022561261129 , 14570979590504848605419638850092710612576634760731998010991154705829891960303, 7081876654999237785822068068775175823259789900038464857602167050792131983158, 11911397750859796885754857056361505572472692036239385315518934824432070976827]) + cy = sel2([e[321], e[322]], [18703753174721947326863540292822225800192529767109903887849391280378615950879 , 19613778040124100165889220227898498533129133505873538625549588791740345005884, 15039820717144729975607443780109118368904218216499993640810787891283371396202, 7893305471806697580362861198809218871446498187812275173987543199956558198521]) + a = add(a, [cx, cy], context) + //Round 108 + cx = sel3s([e[324], e[325], e[326]], [4396441250850868966014141809834014631796411613521413364533261157108807304791 , 16836648497150572549121598580118959226192434996387135129991940567405870268725, 19465159793724690099931261171165210166819967882352842855510624454147581274670, 18758053793437253746142721581116755417112792746753684636213054094477781477382]) + cy = sel2([e[324], e[325]], [2981405188098805378415778407831807030725264692497108694734382487084076855210 , 20469108288868835484927940943356623938045830438424196869633899618683134613519, 933161936100801959708943470285929527457537321589386575156679532348625637985, 269411351035529607018992916380602655161076148137839318392666564540836404599]) + a = add(a, [cx, cy], context) + //Round 109 + cx = sel3s([e[327], e[328], e[329]], [18448980711993048271679830178954781281796619509660919482566515137849326949705 , 19744948717433186245821639271216553763028577858032707139265783707853921912155, 19819689638742986969009459074952228930363474994050981268236002838584672060867, 16852310388498099768769862489306840010510354704163417110628769300551675410617]) + cy = sel2([e[327], e[328]], [13538295481673593444396948705042001770075594914797407330259513771278632533788 , 14779507856773747214980057665178562325159137267699293184545672938786460137545, 18422483889209125213732972603904783756680200857795267276573963126785961918198, 4225410028652447730956912638069668360808266049871102249949930413024208501463]) + a = add(a, [cx, cy], context) + //Round 110 + cx = sel3s([e[330], e[331], e[332]], [8789386218557174287787274081526754120821582438440596481230009033085305168336 , 19604730670978725971286378588091820043225493993475360080974783305559899794334, 5754400819903612415922678283536801620301085919072204701407326554289862247, 8133367062275595631112870441047385208403330263311352404563334748971640119238]) + cy = sel2([e[330], e[331]], [14711352054903619189890311113670897561016852508413508359380114647296690234759 , 15505081148609421707654891794900819606599284654426944331953154100271365747946, 10498745521808868190882616751430118808278388180031887838543438537592782154020, 14283723444930116423678497723705206282538086486601870839003576853131844860728]) + a = add(a, [cx, cy], context) + //Round 111 + cx = sel3s([e[333], e[334], e[335]], [16410879947793378178852309134034691965068173351773904636443113803287073468165 , 2459742793248426443467557681746013841012911230130900204552944771295773437965, 14148653292536659971692314351826075143664660164844520450779907656237062521024, 3823568337665129538914482600317854425115614575078537531810182911935066246893]) + cy = sel2([e[333], e[334]], [13525280335627612179489028500357999227382280656020782481971742893960563718069 , 13906986326008385599879221793305773429690045797230325194617940541283670975066, 17928827609489859058711914379940226888033289004797111427100202351646756410052, 7751873896780721346657011057490735623065509677587909473561532470621436328656]) + a = add(a, [cx, cy], context) + //Round 112 + cx = sel3s([e[336], e[337], e[338]], [6360670162449266467030644276184864100593477111108480032796373772347480922189 , 6238026479435781753480651584008291445457129357178771800497280501659229824509, 14372912505742790548866622516086728314858808340582492719789600777407852624706, 2504355035079143757819920622529907675398702401030398889002491033376003993290]) + cy = sel2([e[336], e[337]], [14257529111287275777165336596087530152135443364949890695933859730727871380736 , 362630247512640601958597579829458123399369864147591061426591055098065517091, 17799973102921706872164223253101644481160962872432375782799635148100439645882, 16292554915278539427322523921562887226516459098783274424269678044297404132797]) + a = add(a, [cx, cy], context) + //Round 113 + cx = sel3s([e[339], e[340], e[341]], [10885915218940734071225780147170174316285574070557833147925199753671864395970 , 16952199638513201931184233985077369412021694081253114169931799009969944845190, 6579022618957621849920927439620464464347948481098737101648586523931683396941, 8954730328909621308689740172956171586217761959578457105814991014419829084276]) + cy = sel2([e[339], e[340]], [11029057981581926429073650712620964484769971154264787930046960173769123662678 , 14057756519867963926667557918235357382317971790756175535573262066939972782226, 14508105580605381633693926053140229084417508695027158358695356916669309852365, 8985315555716651207654399675191261186115135312348808559060054412234307291987]) + a = add(a, [cx, cy], context) + //Round 114 + cx = sel3s([e[342], e[343], e[344]], [9591625063099557813317657356201310094684652614430671855551305338577894715651 , 21710627476302748728292369634413673464477226906421695181551559967392730749884, 10189696652015358480306279349674126142601586910844054141319090928400967920492, 14575448555178809619615329760249104735737622500547600222673171666044253032327]) + cy = sel2([e[342], e[343]], [13661097518448111362501604180288489621905168345464166181035334250815558586292 , 6541927678640542532346030316589325212935454830056081625698359290342280209696, 19655534040611331062875671654696954076416928174908705322979343601347718766841, 18893407984789248251370377180059349323487262100431967496838185583910928677618]) + a = add(a, [cx, cy], context) + //Round 115 + cx = sel3s([e[345], e[346], e[347]], [18886312892727437565309004732784060353326028914324367568840970250261109059822 , 4969806713830542782459289156960092729650598975239889678453184524343618399703, 16622981471374298426508813360547940582831388597832992696194782397307736766285, 17207217606628134149600916884515052475396230199786007830822049511835023327746]) + cy = sel2([e[345], e[346]], [20097067895510901824034782908594630518461908899922907976633298936904395310483 , 7549705567086856493177008201999701185795474113091244286639270279144087122600, 6359914741562734059777896085058461481450840152242223222499923214787802554266, 4523686415566243191697029234004097207393002925819292838991423859908963592134]) + a = add(a, [cx, cy], context) + //Round 116 + cx = sel3s([e[348], e[349], e[350]], [9611980085915454916721710377398516249069657290776790665729578385653465657608 , 2808629496317279665377941162907583528406102092075003683612652910715356989065, 5146801454146059628396374424703327885864890381251241815068083494646287896482, 9712822633793199870569132733680515369277288793857035023884821044404624931246]) + cy = sel2([e[348], e[349]], [12531050708955702438977554896456788618229483698488185884652134859969233228127 , 7759740123661798513430229604959580258805004199555419745903987161601748379417, 12676630374277918228347114736241248443643025357735194824989982902529942631987, 7957263793605029493947914798589160413665834659013858298537818906355583201202]) + a = add(a, [cx, cy], context) + //Round 117 + cx = sel3s([e[351], e[352], e[353]], [1741783015222897367309800534949631760951606605798891132137371646304340462458 , 15753951377666759323512681415584732767525844411650049393938120048851867306800, 11318371057965241278094291737048639440256637452901941620275041654781038395027, 9043834682180335510097190442699980857932890158044577184782692529141130240824]) + cy = sel2([e[351], e[352]], [163811524362553669200342941603136686901966525127089114473510248213711571683 , 20253563341205755839890642239029020576032044419644567576263861445077574198624, 1129293390247992239629138633531986375671761935795719290973869330578475352706, 12864200497534810115296604114235985076138506691530959360993894765742849428715]) + a = add(a, [cx, cy], context) + //Round 118 + cx = sel3s([e[354], e[355], e[356]], [19845239752872171546325855177077796460784181475810291663797620022786920823647 , 13524819092286579506826904337550390593582530067994137276480823345309729489925, 6812066149319989921217367650719188106577252681936159930531352608504453614106, 7222950523682776178187164591717978364824407709855563372464941677077475909161]) + cy = sel2([e[354], e[355]], [10413380090476979012716640518612591288231919255093118763710930970879877622297 , 13124406349881024599134718908760433545313158896610258373843772982921905937617, 10544285464977662192736078007137407440374594005235468167522962555324745898878, 4262511480267656654185538760448950673777806215660569720854482040852407424457]) + a = add(a, [cx, cy], context) + //Round 119 + cx = sel3s([e[357], e[358], e[359]], [21840644145325684882015312401601386817913954005861480185552664536266852358123 , 17245795366378478445622830709744244736981686761608208515847580487483274745119, 13807005991933596253278252430914713127227144098393113439031517565273756047729, 7508257045596568083350722191515656587852775770850324460219207057837744147846]) + cy = sel2([e[357], e[358]], [8473655227220833354585864220301666825011510607427101884196854510787991763100 , 12360766780968617496459580910362246207458173665456601955392871687431450155437, 16167977026195109940196928407142099851728373085986722415539043108707307260209, 198020065443013508235269047245522994471757343128188653900779810305583184096]) + a = add(a, [cx, cy], context) + //Round 120 + cx = sel3s([e[360], e[361], e[362]], [408538855946993109150255210001390137328762855947155164309686603040268044308 , 9956106896094805762100856187967638241058986877712947272175178827260922476691, 10413057148806203104120616811444687722773209463542545789320471445420824622479, 11902530720628689665925185225980720963660904880464037650526790156354563593259]) + cy = sel2([e[360], e[361]], [1479997830732538227417547327573357263920837878818360220214252494202287418999 , 14987839414386761194654231515173353164503075512219993482548242568337943854755, 21713504951370328462347781999791817908891510961297311340202728964936620298516, 20863127910126532592439656993995677084099363872120709138917554483343369113988]) + a = add(a, [cx, cy], context) + //Round 121 + cx = sel3s([e[363], e[364], e[365]], [16909060815089078676939420644976457427406147473547024017569298235433420995548 , 13780618743481311116310648367060473410410597997822855004264478650194424563904, 2732495529118703111995546569867225395498452112166729675036576016860030980932, 13122008905793271330592610678764878579485569855365858119720314545298458579129]) + cy = sel2([e[363], e[364]], [9691045028169014905240668289132134803037917344396639164551352440947925851528 , 3058069811496358922966440231506430818794592620746845318344939704361344313857, 5622098116652966523875299529800829301718212684029447361840034988407307855810, 7183269074283900923163991117263230892311528827769843151316519486217947924186]) + a = add(a, [cx, cy], context) + //Round 122 + cx = sel3s([e[366], e[367], e[368]], [20571623498624005071141088211057092924213194074152586837454876463843418144025 , 14097761035973961045955839030064191145683851652701331413184120292691554339371, 4700343263415821617058086844751479864993855871131720446111591033305616384725, 15018715227933376511503870740434993985805930984246159457731592079602230709953]) + cy = sel2([e[366], e[367]], [16001479421972757821409642160488722706981473283972847385882762682377724905156 , 16084059586346766494553050527349239192146155351545756557596881128274718933483, 15099192410657454417038148697642033151361229914558920712490911402249873000238, 6321931552493003117300598295325862984882362303961074819842172524617810976022]) + a = add(a, [cx, cy], context) + //Round 123 + cx = sel3s([e[369], e[370], e[371]], [9888014007610840933022906589732806947017424423907994528302713554488676542739 , 8913934326838155827928873892003131738033383847534784434581587200177151201442, 11175569252941365912268295578620074710236065357166442341964835896122343271089, 14897216243038767404517178131890350534529367853478353360851740975433826101343]) + cy = sel2([e[369], e[370]], [15251452715683470293001422999667336542311051361914428663773647008481320118023 , 13776813195393840721224885537714951191622587841642219673672717728440679190719, 109393055477786022036855578884727112792551641118563108378161158873180208830, 4672879465153093973501790898266208077997221906104002063988725461236876037213]) + a = add(a, [cx, cy], context) + //Round 124 + cx = sel3s([e[372], e[373], e[374]], [11201877561392804928547433284377926158320532448010089457664943460838007583898 , 14898313039936563609742185951856291683792301837166735453885728355621976660447, 271087861779394868518887048853047396941902217944929345703753181641065491942, 4441061173173027475223782298768839441149677456214218957851727123779445089634]) + cy = sel2([e[372], e[373]], [17554707027223374526818340909253875671094356182527312776837442099008513816809 , 20394478950504145529480516245504739970884923781915405632423034600555134724554, 16722605284146576015540826794584204150250626411625717127438407440061496436970, 18186321490023557384895834600063402151493085858585827781091438725428737294598]) + a = add(a, [cx, cy], context) + //Round 125 + cx = sel3s([e[375], e[376], e[377]], [8041169655049264647027531522783115313651111026520000925526843693578880103225 , 14515227610041424277087375692958559713914998916629738058046674629183188354305, 19607007966889476958718540412171510858381328905787578252786377727252482454742, 2784733087979918000560628875496578392394872735862389774966301201852627273440]) + cy = sel2([e[375], e[376]], [16996116430274827689271070440218340032465717731948638724397047789367189212654 , 1334527779675942376452476259926180292226498546209192760351592699867703388666, 2040984273885096997446285553479523685705477968103260410171803510149440153201, 1362381113387759937979242007199225976741286448134891397298462226220340605980]) + a = add(a, [cx, cy], context) + //Round 126 + cx = sel3s([e[378], e[379], e[380]], [19334565048001467439446889504730002771044189757270166846813098304840682799995 , 12950908278008251424596267965839781465537497199604011584300739900170800951940, 21595247577936157693500985718654956851081515776736906827009279412148715287229, 15215490137474227465600889880755209339274086672218612829479984354294020155457]) + cy = sel2([e[378], e[379]], [11177666514768283886285136134046021748603781779508224469021361511080086667157 , 19019917071840025176852012694579443932947880720292648245869222295962307004975, 4637723565271538497699679545822400204099231070875646671160251633445655525972, 17666228617432733285346663026898759021573050617000716798909504211448351974426]) + a = add(a, [cx, cy], context) + //Round 127 + cx = sel3s([e[381], e[382], e[383]], [10764100134342681938975151936530775454161936697333679961141539476099641645903 , 16887585392329741143712714812495679688982136908448490321095843300899468374984, 17732836192725467148065242235309558107289861496038148884513643994394428900356, 1445275363508375975763521380916891145219085429516411016928665376398954093593]) + cy = sel2([e[381], e[382]], [19850691100864531393976360616243718992492409320965998539447518686463634627384 , 11041690436464044133197365654525664032353519287590211059695239069687237542566, 12282683178748394297470306056106686277334235538468988533692942720363799093795, 21342615132598490749588725326967212830166119543678585183102318245731915882892]) + a = add(a, [cx, cy], context) + //Round 128 + cx = sel3s([e[384], e[385], e[386]], [7984775939876417845202037337929702281039643807160799398396389954446436630245 , 11385355274910748832054888360458973063107383418973550712148639893241354902280, 1459026779105998101465829026524789739182470402517704469029876736898952870477, 13412666792048974377925483462948441322790663427949756029941851541794367956141]) + cy = sel2([e[384], e[385]], [11644088529951120466123058306783377782553679447618569394424538939634266570688 , 3423766185322892807020818425845766412060736093511436910964946420904954554780, 4248997486365074893462023447486954255437098681775520477410894095041115503490, 13508520946233121439054409300327739993661203591041357972218149016790406863855]) + a = add(a, [cx, cy], context) + //Round 129 + cx = sel3s([e[387], e[388], e[389]], [5565157198993964726485879908963280627890845525340341493437203971709365228330 , 7321058630137598328136197614874359518495943608220094707772133348409941566403, 7424926497991627209495812948930411917848701932818206777924739403931504666904, 2952280234707044917845773867363672510563637804197143708410321227590096039398]) + cy = sel2([e[387], e[388]], [16047978233091600592523116252839158499254716982332498268149527514947495047441 , 3013461674923738179146278200182113922630443185951298626004001204030842783133, 21733406038088991240575501132398939052212396619770619197864537159847335678397, 9758173327391957613571828756022551933369392423107899686458119829785341358149]) + a = add(a, [cx, cy], context) + //Round 130 + cx = sel3s([e[390], e[391], e[392]], [724617195994552100441707186007100945318061137735042194166321801565168264994 , 21457482305994995060621698878673403410439584990848189791210666985898821778689, 12733018351677357535096192491479720026355634001914123270202692797811692793469, 17876157828650849091584102879830086520321631185862731111337702980715729860154]) + cy = sel2([e[390], e[391]], [1941243639179655563586549731833523575056282199989602716546318426577162114198 , 7186671745389328078718719957510862463188189283547797342924706384031236512232, 181655793349501388675021326982297619804658251127556562657041847324134931318, 17955220324559325573119985254939537965603633897040077737890918084344489169000]) + a = add(a, [cx, cy], context) + //Round 131 + cx = sel3s([e[393], e[394], e[395]], [20917363825188238552045899784153496987535745925685770873105753565860443082365 , 4540090524117153259059229343653410962125958868702729157110889632173091362337, 19931748170703315405614719529478161068009956569206884593254142678501117968416, 2400060542928241404744010463507020801241694851019173560965950546401444426082]) + cy = sel2([e[393], e[394]], [1745736425002501661522536470728945366618822522645696668197436988525466413140 , 3366347972505547411030140128225789817592493957844838153202867496815084725868, 13538672659394937012305631615026094764214309199641714104321427476435723762022, 5730310969197975636538358956003546448924042719236605822193245706535947879790]) + a = add(a, [cx, cy], context) + //Round 132 + cx = sel3s([e[396], e[397], e[398]], [12673489410414637838905637938820402546181123854591818062100393889121109718668 , 2399760455052989852989301770450241617652861646522026007293921167342274767344, 20212599267512455026947565441242728025855774594658042161574807775907652589242, 8096283485634551421043683037450718803162713602325821677928898619562706870069]) + cy = sel2([e[396], e[397]], [2273218791680662828916671149332560291571458847138066661294611637128783792792 , 8189321225342615133315741008578315746871762722980986965249683543300354337817, 15342161105292713352374449802912175534449400959133109035836260415735518836755, 18075013689729624974967362235212984989450911765049481574404064991547015443791]) + a = add(a, [cx, cy], context) + //Round 133 + cx = sel3s([e[399], e[400], e[401]], [1596291013949010721288060595532569432608538778619836480784785471074053165112 , 6808491683819461025655595089437806112418825101974851283793281398274802390485, 364241503925827187366795904611796342209607893955620582589568264631586955422, 16490550871285168246186419126591524969189857825357227166657318003550977024941]) + cy = sel2([e[399], e[400]], [7862378404177401992071889396713852447802454946236648304807328682371781930090 , 507291250759269099980701396020232970806066743976022636589996988193601483784, 10744127551738752560827414410584235701822856001225517338822143012287884858602, 18241779151498711099077315181629505156252250432591841498036131464452558240559]) + a = add(a, [cx, cy], context) + //Round 134 + cx = sel3s([e[402], e[403], e[404]], [13383782376835328120051264492485947246229335501182593669024066132006083860995 , 6829659109797487915393241205795046921708391483622784165963215585089039907693, 9316519590383340417002353253254231934003449806173856616162378794199227402893, 13002922510988749141229072125743986091046064285797312111247897533544865920246]) + cy = sel2([e[402], e[403]], [1452388014885069534714863742557414467294079407912495717272255602231974271039 , 5900502409092025397559171952410984687860230521181044855453255892660864354438, 10043095963739821148582141213281494171132379314509020019652213752752234376602, 9999295030621233000765070897582529515356078631699063530749343953422947829219]) + a = add(a, [cx, cy], context) + //Round 135 + cx = sel3s([e[405], e[406], e[407]], [13165533527694513928104129943149460933916076941607396715443729707678633985673 , 20294369464168299590806576821399517301857816000499415634107985306452722815938, 6067645363539607688922626118164207320418666861212948609146588413602170467017, 119932367132867885429975847232185792475931817114142487620518936723703313296]) + cy = sel2([e[405], e[406]], [17238425515895072477563840544058923640858290538130746390995636765338905591675 , 20628042696308823655110673878535950075986980894297665479048269813590306242580, 11749486899455580256560135562925052584441889327031335669536847121302580177052, 16957619631025354458723169845456497220362554006891490260455748609237426050971]) + a = add(a, [cx, cy], context) + //Round 136 + cx = sel3s([e[408], e[409], e[410]], [7326992374695153334569399469397596928696501586886381702972942656080738560504 , 4198555626333615585226486302590784054103224208504401294485393840072962221472, 18288510281806332963207620050180295922486954421289661405933207406160563376204, 19378648346334975363564386629109544268031565617795572270340255835354171953065]) + cy = sel2([e[408], e[409]], [3441991977044037545935620478935168226411039028254665140927991316702138513190 , 7980022316348851053079344973315144435710609854183180078433220232446348072790, 10703403289781310156812833248447222548151317595810496437901793212311982317063, 16301246072292511450557090225826608132244132307038997545230147196603338285964]) + a = add(a, [cx, cy], context) + //Round 137 + cx = sel3s([e[411], e[412], e[413]], [4380971751033847027929691061398944531722909263311553031455521197665070771642 , 1958998764514462202561805635784673640011091472752464180193064104296547581169, 16607632498550062722823535936950763735998138401664871177932105851574722673362, 18107842395238833528194122400147411460295339366691168281515267029707554163796]) + cy = sel2([e[411], e[412]], [16794605741797752486161164743285493892529567663448780177764044251817860406839 , 627364605348057780240790756195705309805910423716172983190978634837740895756, 15938340690702031578469687601244712133164105954943969813204470601233395408177, 1337728022058609756453976167140964506743665540101352471912041874198880786028]) + a = add(a, [cx, cy], context) + //Round 138 + cx = sel3s([e[414], e[415], e[416]], [4325450975911066881724043517797022496124195434220888316197251865366294339361 , 16239262892194658073042878979066943080253388067983326658313518038231343725333, 3224923392579231188607529005374853676842589239602348970956358059045513499844, 18711810040957806004127569353264972856236116117792057333129328498567653245337]) + cy = sel2([e[414], e[415]], [18556589125306655880844231674670238467511897504977535323905816448582480367724 , 14450907030938846250134541582271892920169763336845349109491176054829079021938, 5489164165718004081061600001298776199757130654902992957321875892970948684039, 3404126456231281994449938636645452663538090331489692208486381139765931389947]) + a = add(a, [cx, cy], context) + //Round 139 + cx = sel3s([e[417], e[418], e[419]], [3049906494165633773067493912990013841965806179225048735919293547905816967010 , 2425405604681482172566807394598240014734338608183001729881716084701331638207, 21560391195338031738549905898033672840916947395960523186297949490337780382461, 10640880946275949996544592530048605056441276931537882586193904453232482475238]) + cy = sel2([e[417], e[418]], [1139270967545262231620743596254789040950691396231510347534297369410226811042 , 20852287956575668107697863776884710196273757688539515338600627283890571581133, 17188605966302742252765339963794720668370341043552053263753117294010969693650, 19246586050423626713095252320183688353765457408019346352862271422811659317777]) + a = add(a, [cx, cy], context) + //Round 140 + cx = sel3s([e[420], e[421], e[422]], [19942746034266536069392101170115851306620344112551007974939114086497358930858 , 15726708481134151732276229872451366695420040201434018827381159241014716358033, 3452250047812572894016965388138239348795538732265416477858038566576272340399, 732825901760241932909222883465959257672029209130800755766287912812473135470]) + cy = sel2([e[420], e[421]], [5234335526367392822375043936890479400588416815383747301372644960641216357795 , 16682782393317738699538698600037172468451638588454521003611347304172554322239, 4800939729460682232720559307513657730880675292200605768084865538547688695396, 13002618796997179002671199181852958465089986403190513123030050511152310206971]) + a = add(a, [cx, cy], context) + //Round 141 + cx = sel3s([e[423], e[424], e[425]], [4345203866646269633300579468877411954334981515932585752657225898484243906660 , 18369957391582635573293322493321958485207102003892958136897534329158731684885, 20673831086732472000273127370905823039882723856850376643114084876980363716192, 2498213507326390169362081908041456736901489034606083564552630396661416090091]) + cy = sel2([e[423], e[424]], [19711785928362785984568609948298550809737208754846854010480265206080190724688 , 11436630733281926268922633177556600595162960771369546050376297927685306050908, 7773194831659524501769470153758921383337560398544153003929463015874290745463, 8133306555008250199402612262687855812899186562206213570420163947809045175265]) + a = add(a, [cx, cy], context) + //Round 142 + cx = sel3s([e[426], e[427], e[428]], [13604959715661441436052939762464429298226713418171390314110026091418525209941 , 771054573202666486644315008474869467749501529120937703475279735897998473318, 10650739155896636131407567213077995361727149157766675911133814003745320974607, 21082274336612203666519840927907859383019309974047946161440422017817660726149]) + cy = sel2([e[426], e[427]], [9106634253925907822997376723908848470389744101982447244238790923479221740587 , 7324910184007890101804849358851153077116609835592182327277588695666568522132, 9210749700131521931808418873690269098719063379384664590576822932928021903283, 12373345790154524492998539937744274645461345882077071841080883186883404184026]) + a = add(a, [cx, cy], context) + //Round 143 + cx = sel3s([e[429], e[430], e[431]], [12272981972646946567553896730199881959247853499104488943992635249117595393209 , 17484113948306348142106921779441669789323552473173221235726133380929727014173, 15117556748390824311921483809280404911428464810641842112990732230853500342878, 18738665459003240153367275566837691463796036422817751002779294781153509048410]) + cy = sel2([e[429], e[430]], [12840198036955871442566173317906222816787870441489199428401326600711994709214 , 13447048657087191261352674553209997835888060694120420289379298057286058954919, 11085124394828809185369563175800089294678889500629428639251047427113804175136, 20040932616180013985013159566209210337758333701488325181237556234029685365086]) + a = add(a, [cx, cy], context) + //Round 144 + cx = sel3s([e[432], e[433], e[434]], [3005593847772820450050205074163314509976806377772621088836578637506564062913 , 2910567614812792758847544159495544141576095133298651646543717734234356651464, 8630893570634023334653627900758492588201195084156991103796478188432785900122, 20068438612873289533893462991408376904784837411837844241529573433855826118434]) + cy = sel2([e[432], e[433]], [17258587025904856892544250820556722922327972240440200527118380921147955645556 , 9839944666562674042904466515196204595921896101136113309540898758440523509232, 382264312380680546118029507176039576064064377468124376294215202312670233326, 16859633470889096937094854459393230196320754799783499045789361347337904723211]) + a = add(a, [cx, cy], context) + //Round 145 + cx = sel3s([e[435], e[436], e[437]], [21553262056684585969628674122764109775958361035991194009613252605155913211334 , 15282636750399879299317591027894754559134990135454294656134105963760417995544, 4066930541781809252860144352581968840798983673586834922803928000950012716773, 17266825085778436273993504052249489036678132768169211810048007631121526004292]) + cy = sel2([e[435], e[436]], [14469270633466381305852216281125837079646617198515099740000541993840798471084 , 16980111987593030332881454298183054033228595894840772569146266548134494583283, 15118688184376333116924615779850360769477969453186921964192734694461085893102, 4748807943449256265621737370336238625547081211863390407052811770007138872316]) + a = add(a, [cx, cy], context) + //Round 146 + cx = sel3s([e[438], e[439], e[440]], [11763347508086007810977359866267798246514404258245360557926263268200652076963 , 8663905006927572311188991703236656874376542152827973004022578290253373528008, 2952845374549988741320721621283121797914244173004620545437372716814928986849, 17071883097921153691621062529879599274949735278299892231358334236565401545899]) + cy = sel2([e[438], e[439]], [14706162498378202954074913829047629685039231677186626739445882650545999503202 , 1719746349330736449674857345290037499267579249273019799523377364214790913723, 21616731410397798448193163892890526448374926979106286339849727909287686706845, 11446919769449393256780992769707214683226878212422736672766658759052425409242]) + a = add(a, [cx, cy], context) + //Round 147 + cx = sel3s([e[441], e[442], e[443]], [4356994949172878276640972387865792898708144237321291982532719592191935134502 , 9058912028451204788275313382642068418310841490274106696805181452416351257146, 15190160120915818686650557755704440198069036613617930484645880424887234233075, 9960154561010441532105561845082645172957096392270554555453954413006726871798]) + cy = sel2([e[441], e[442]], [14574692378125259586817945291111936727424704391123959334117252195469092200764 , 9224728228539828897416026999778106548490158473228676095012930511474594231477, 1760463507739730034367125481096536174852992494939001755761219582349351757169, 17340078450196530212205314520279311841731993777309479440929707007860057490354]) + a = add(a, [cx, cy], context) + //Round 148 + cx = sel3s([e[444], e[445], e[446]], [21880820504467716634106664909402072165472960350877194774465177915127008092893 , 11747606579643600398471099307152208653405848363842457205852065247815894902054, 19027263041564841350573847395951723454691080012198506245692747602145336686229, 5632682422077314837831565983660289273448221389165648008167925020530588300924]) + cy = sel2([e[444], e[445]], [5182168744456816656485869911241149693404052223082761825064601932558781730740 , 2685937932147288674316610675212322222716444961674715249218650895750571659552, 1912852125196207140975649985472776011293820313776376659814516409955251806791, 18263958114524880676274451483937610105571465623681831140376587635788141241088]) + a = add(a, [cx, cy], context) + //Round 149 + cx = sel3s([e[447], e[448], e[449]], [8936781701927368370215210870827508937678765478808217533286287559934624784681 , 5108431664028439851662340341125863641795570652264053957564019035084276122804, 12999653496005517730722186355139904948504508219343877303366358022761375044402, 19179622495081980573635923134343351242929014436693872859625873727501193848932]) + cy = sel2([e[447], e[448]], [4623029543859886044767307470074323247069187031547412019261660683452990785239 , 9857015684855568488276378660083416741199186578332924215590492662945432272825, 5242391447932956625671668911434466570194372869876929059550830464880164528131, 14646928672286452058469223988095085156895208600523868135204725017248298504143]) + a = add(a, [cx, cy], context) + //Round 150 + cx = sel3s([e[450], e[451], e[452]], [7946459614521142644206204774850419894186577869297360917934350740375926112382 , 11530085592691934773947896113217121596676226719554558175458752626759168307130, 12291215261278045612022495371137973264064622535432110273152233125306665396787, 4442266885858584741818610179233325487185053295954810407262511211378152048331]) + cy = sel2([e[450], e[451]], [20393528966549387266343193152712146799161036298032725317477228673291507957942 , 1831259860608244620805838343666664146008857962101286629882205237950513972028, 2581270768505724914793947599867596421087089340177029937008824731251155270286, 1824038414762784797700995677077189626495506231241155951144255369814082278582]) + a = add(a, [cx, cy], context) + //Round 151 + cx = sel3s([e[453], e[454], e[455]], [16996326686259093178712301719114535464147004200933701699216923172711169217776 , 10135668620867881915901635109225909232593721615476228193005378643989870282190, 12684696285143358527008494835928613367424428569071148860201922633463847362163, 19520340433574445384932755965450431313046400213079154403779893187900476007389]) + cy = sel2([e[453], e[454]], [10879703765081907416589976314120373073533854885503210038919805342729980088501 , 3042952377945780941440480619239495862925076770257741464841490662991367990723, 20568201167449878452522309826171296534890589395210499691162182782776592901489, 2515435614825363087293388949409937340469196878839891206929432371588941120828]) + a = add(a, [cx, cy], context) + //Round 152 + cx = sel3s([e[456], e[457], e[458]], [5948355082391370971277814822201259570199411254972015395356071689733858457870 , 14435295688288574008552320445654835668230448171821339773392204385711009673498, 4555707692840173328761632986080641237899354311390885658902712711385985152474, 21377793559898523325502642621273525075966615158530502938404139072744665720725]) + cy = sel2([e[456], e[457]], [18781938632634665629392534748457372928296731257744451684662925940692495070899 , 20870582266287640319635222130472633641883455183531701982867810507045631654099, 6255001622610081365809867580322152519018111820804890853975941295493185079617, 11444903546950465193484459453464362458126976218066241321940461471249831055834]) + a = add(a, [cx, cy], context) + //Round 153 + cx = sel3s([e[459], e[460], e[461]], [4801783634053958699406131208260321653724147389806778300442394152288266622390 , 13657947007455887667569605985083889328718870615545221619668723775205747840135, 177598511756923881728697053947837521554079408931967588956714727282062478754, 1374290142752108446259268973165307183295759382785138144661109763848127727476]) + cy = sel2([e[459], e[460]], [10503832530625380631086165586158401732075983866290617431349835924922749109699 , 8383317413774803586670187834721088561764237477263859389570115631886656905028, 2834233504802602126712103599378293010472650755759227696185340490923006971103, 17330582798076118742935459828744886802843487551551606246519220146369990307779]) + a = add(a, [cx, cy], context) + //Round 154 + cx = sel3s([e[462], e[463], e[464]], [5093610893249308867168031458336741939196884648123926997975341654608609426830 , 12248279767532955250746877738475030196514076889129781370472666862024900770669, 5043009492124624507652527263244758360087085758651362799261288863076362039187, 16591909200159417412409462652077399999824413751859530227695887196356321679228]) + cy = sel2([e[462], e[463]], [10952612598118313917631759693602817846928839860096429550603703046117049639522 , 2884939241145303979172401496138136665819626424676215132904685536232137032921, 21092145374321584925227081195844245213760374840107123770724422721835988876958, 5499840197627421265036310285493143039360364243394878011782966367266344217732]) + a = add(a, [cx, cy], context) + //Round 155 + cx = sel3s([e[465], e[466], e[467]], [3794104339739491010449122661216407115137782001618163380131794160705537757426 , 7514419529276933284458458535371966876401883528785013067210805765651582633130, 2534189532451386749189970776179117832798970009395742348348119108287813471216, 5610243014937776775874159841646817951854662385825951664842167532212856045068]) + cy = sel2([e[465], e[466]], [12842968623255283384772731210441087433561383555541999360200972373794310794093 , 10823437952973686303915120116380996262045441725571077692704581218749963605907, 21253964658659775229061107104903539871763760188604842330476347939642955209002, 1745535366815989039402026181267179197840739481539734000808670009580269211142]) + a = add(a, [cx, cy], context) + //Round 156 + cx = sel3s([e[468], e[469], e[470]], [3459245219635302288341483992140272707638915493010622274381776793623419230591 , 9849021255480129732487752167924340739614806540698786580158805033907788030853, 3255308487469886623287718398314898379309460957968181729113829918571419337145, 15359614079733122216507425018253600855203543497608695539122606260839625565617]) + cy = sel2([e[468], e[469]], [17415928452277952995861857592997544802223350915817518744596816398543561612106 , 9999856236606156376100952785476675300524456948913069129769906530665355058037, 17734497746752242925262857913765409819203458581088950917188119245918082092030, 6881580842463060802624074515204787264906621652045323766233447264566499944530]) + a = add(a, [cx, cy], context) + //Round 157 + cx = sel3s([e[471], e[472], e[473]], [634964597278986129282215293208138156361395902716873910540311662219517773576 , 310253852479958835592393232442887907344502522183801152945448588489452412569, 384881480274621505303330466062621612997526527075542749162723700081976881288, 11767445114097831765826464678890553621483551558949563523534328471079851963281]) + cy = sel2([e[471], e[472]], [17203635141310737823252743409317633065422478971915442288649227045499339781109 , 2545094457118912372548408336893899649182443951551613850781196845141738637170, 8609139198776064973664903858401535131314034007074283879284230416121615542308, 20092107484372320312567981037155807130829118997137612522175958096520972507336]) + a = add(a, [cx, cy], context) + //Round 158 + cx = sel3s([e[474], e[475], e[476]], [20098437969178934435495041700635313630962028038875583770224318127835756299529 , 311104306589906971684844795811359683864786473908061989245919427082915904714, 5007249687217418940511624233021226494914521342148545152148356064906320432035, 9785851145981523672688289938894315309424412779439726667571213830109657407900]) + cy = sel2([e[474], e[475]], [877613904095171787446316454384924363436490179245069691113043218080238972652 , 15255392602742007855606168874483544819258797919038984937824266131810915403967, 3482868076428758563707184390706074120455579821747810434457575250407348632455, 5737555899585712614112644175034540180519345050397396205967955592318835422324]) + a = add(a, [cx, cy], context) + //Round 159 + cx = sel3s([e[477], e[478], e[479]], [17889638686175315317941901427709143202478522471798280927986774735210637820526 , 4586587171981050785204495209615167868746399227792813638212786811256473778221, 1864752565757236746122736751796835904389046064841800598816325031089096557478, 13943403942544820674673437343502779310324858400636923221774342029216604251440]) + cy = sel2([e[477], e[478]], [17728898667133884634264046347611298588924985692465583707491826367590591819161 , 18365428070394378833051912713200271982753415548931989923757430748929339745094, 13355801165885814561827651110098104649674895992244923613944279081535896494292, 12718254346735593182641856097514926990330253814732909832265502852628068735026]) + a = add(a, [cx, cy], context) + //Round 160 + cx = sel3s([e[480], e[481], e[482]], [17159516188699622404527134263356371503443962451842558111890221401200764258125 , 19697000438877661546696672369476849653861527230741461549059757921200307256689, 8082602544025295110701438493605046299287009032703969632384937719700791606339, 5936552380580117855548116310401989958728171511356588061450350806482980900531]) + cy = sel2([e[480], e[481]], [288697205606498046198642124865852628925547477970007319079115715396675917499 , 11438994931015502912944770174743669059446783563412696311667974558402876489825, 2713576975757110627428489368530113978475830565467996635364633792472336700891, 20023822454992925006561366839036620580908513505208980493011483098957399405656]) + a = add(a, [cx, cy], context) + //Round 161 + cx = sel3s([e[483], e[484], e[485]], [11476903323853344813827041345787850966667514952865946400953029235796901464022 , 15662688482882450089332164944545567115920791913333567306810233998084574572841, 16165244090421658682362860955446523155721204004465368156540492359518946703685, 13233236504179066734589049314166320998745790229936719431495551951291164368688]) + cy = sel2([e[483], e[484]], [21544495907681885621399294493301860022991247894450553860102494438499516461036 , 15070356063300726246376329439697612629246560015487953180041607494107482212328, 10932308314438454016363769449242767120417784090441698745502660483728820506459, 15142440904746497443767345573381088273730091577283493618193631903901402378371]) + a = add(a, [cx, cy], context) + //Round 162 + cx = sel3s([e[486], e[487], e[488]], [6740469135284996394159167279126920754449900660887428959259136317440159292867 , 1951789672920637712186229138057234008172951294439716801691622239946406362446, 10614706090196653889949286489862565736131644495539213256761186995450585212820, 20219336380099606710973890974478494924791931389585459347005405927908068729651]) + cy = sel2([e[486], e[487]], [12559437556228574824459283742977065667884462966124147526010574650373707978536 , 11353250997656326728675199688614508617263787972463605193791786351817731868528, 9955679877407075213882986027032271351625902587325271136145291798547578901197, 7587664180577472344145946155058239620135123893989614056504418351234639990359]) + a = add(a, [cx, cy], context) + //Round 163 + cx = sel3s([e[489], e[490], e[491]], [11683193590608313373089435698057644614965227085254736967478627707109364481009 , 5373593679075319624506848608700634791297845735799356231319125589754901432010, 14330496678432059141319543266495924665988744049796260830269932610430618839231, 16147138941500612947680025577703299264094926996519490683694344514795650552030]) + cy = sel2([e[489], e[490]], [14089407095672561058133609212857713657125336981293206062798215054918146117895 , 5921405729554308485753035966317904019193857886291312338471036342984958996974, 14219166018565381341875979253176613205499868708487414627746489465729919459602, 9173206043848059861761039827886516664018988512989876666692360758637877840001]) + a = add(a, [cx, cy], context) + //Round 164 + cx = sel3s([e[492], e[493], e[494]], [12391241461796318677666973225906912103063953603374991439355987755433936571792 , 11342324255021537810533271600486943249554637261483201032733188357979300928906, 6762143596567875242093282841823575455167081327592834568853990326935018728741, 1729094316763263611553329689516612131095524285732807879509329720064037980971]) + cy = sel2([e[492], e[493]], [6256323253756510425990684148198273229283967340029341825763386143854418092931 , 608479563301898577121898469798459144789668559311173727644698121661161535370, 16118965412641868779259712849902459712114606105053804845952965420804403776265, 5207196556914412218334602277590189653542873808697180315162104560234636073976]) + a = add(a, [cx, cy], context) + //Round 165 + cx = sel3s([e[495], e[496], e[497]], [12090834415198821488072985841187199896460619427268475889346428879276625683876 , 20435352555053416469114817994605784220258558984767053371686545934216871498097, 7919766463107746640570694574991853522177141706128568812747727580994437010928, 18791819403195060520893758220974368558662433382958799315116210085990602330263]) + cy = sel2([e[495], e[496]], [11186634643432676423242372187246648742599522445001126220151236883458565017089 , 730264789631663387855933585769199256797088038637783970560657523730947722943, 9789319816975923274967045544277604801648452652703289939384714401867885689451, 20390569650377326057430918388837541684089995685084097630788684319064176189296]) + a = add(a, [cx, cy], context) + //Round 166 + cx = sel3s([e[498], e[499], e[500]], [9073477014345643942359994649331122800736234440180113066690071117218958686221 , 17848891043122277658033397684650904021333601784635518417727821688552518594475, 8394455238188958480130266174842497177830879983439478526032000789572056999540, 3969215253795918818810265899749520158876595254756141389552909935321879395990]) + cy = sel2([e[498], e[499]], [15421230006761899572959376594938017439120427450367920423701622807634638005218 , 691759570775251457416249989322179808019152722619656278259527490301863241777, 19687896560656750069557210923004770524699515901561346847457425701096560281307, 13013403796046695153969709190889488389508063704805702465177729278466953096077]) + a = add(a, [cx, cy], context) + //Round 167 + cx = sel3s([e[501], e[502], e[503]], [17605212659450062681090282709904508607567301109002577655966314961623397498778 , 20706453518066591671344075213608634140534260809172831962434708646209603184096, 20530641835252913976176823270868884490574732596806683216254892843407024651486, 19512520336574558609801187648395617364107060095538444150298099264798316486399]) + cy = sel2([e[501], e[502]], [18088283300102077232647028354145534410326244238430555546504288886091850910025 , 19624767204537830958950503358240075916787006780432673880401115874844576604739, 13389739174441700308398229420122777340874705736681526274430502297758537243393, 2768660518118504029156154123602101814256009402463064802144883490594220059578]) + a = add(a, [cx, cy], context) + //Round 168 + cx = sel3s([e[504], e[505], e[506]], [3898901470837850662399020072718316987511815396623761376502150466549773974269 , 20681259404330431411774484706350104535474957110888110413896201115382255532278, 12146860081497614316907871444885755439616687087776665508013517962132514932126, 10103366418676857183019670163194546750004223272088526675082633522057697832251]) + cy = sel2([e[504], e[505]], [18552945270636575492780160887690665046683842994616480518496617903497833044944 , 16280318807141467057522946128901953503954886894473765482004622686048871784896, 16511259671446150110679883995503700110523460228865394020432354340848786592304, 11820015885519382016829607197866756084707670961286078960070207041832708513141]) + a = add(a, [cx, cy], context) + //Round 169 + cx = sel3s([e[507], e[508], e[509]], [6124403322044682705571649214069113177521499060664580284884665715951975035077 , 3806547960677312456106393355578152447583324120952390972170284549005371006887, 12796416634735923176681417392847285391386920336707070519873332365264500996292, 18113312677912280033934533469627761267183403533244965210112870702471687667512]) + cy = sel2([e[507], e[508]], [18191174947339798787646910619446409943766046946921136035021645191602921923040 , 16559060177998758852323304784771936179434931576336411584121379336820727372618, 13858115732979799183025726471151602712224733686530960054365665740611187232029, 9933192519609817862698304326029579651414877338671776883175639003837130283966]) + a = add(a, [cx, cy], context) + //Round 170 + cx = sel3s([e[510], e[511], e[512]], [3342564788366736273905106071612128667477972061160313630133110787799686301495 , 13766193863701503939885263345152684798552605679140222504700163745347162493183, 18523279471468319520962369406962457727155204375043681943707151819380964978377, 8094164074569624021939357073285075790695279643883973800173037824312344195506]) + cy = sel2([e[510], e[511]], [2329094643034533408459502544740928833981119919633412709248656884170940780093 , 3216329736050668550647765981020076413548845117352735257893224753954595290363, 18710403072495673647060422294369054840513840567808020912157404388689648711093, 9785201456176703812798077455183487364035650707229293534561747881523562553649]) + a = add(a, [cx, cy], context) + + return edwardsCompress(a) + + diff --git a/zokrates_stdlib/stdlib/hashes/sha256/1024bit.zok b/zokrates_stdlib/stdlib/hashes/sha256/1024bit.zok index 6f52a95a5..ff5b298b9 100644 --- a/zokrates_stdlib/stdlib/hashes/sha256/1024bit.zok +++ b/zokrates_stdlib/stdlib/hashes/sha256/1024bit.zok @@ -1,14 +1,9 @@ -import "./IVconstants" as IVconstants -import "./shaRound" as sha256 +import "./sha256" as sha256 // A function that takes 4 u32[8] arrays as inputs, concatenates them, // and returns their sha256 compression as a u32[8]. // Note: no padding is applied def main(u32[8] a, u32[8] b, u32[8] c, u32[8] d) -> u32[8]: - - u32[8] IV = IVconstants() - u32[8] digest1 = sha256([...a, ...b], IV) - u32[8] digest2 = sha256([...c, ...d], digest1) - - return digest2 \ No newline at end of file + u32[8] res = sha256([[...a, ...b], [...c, ...d]]) + return res \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/hashes/sha256/1536bit.zok b/zokrates_stdlib/stdlib/hashes/sha256/1536bit.zok index f1b8860c4..12895aad7 100644 --- a/zokrates_stdlib/stdlib/hashes/sha256/1536bit.zok +++ b/zokrates_stdlib/stdlib/hashes/sha256/1536bit.zok @@ -1,15 +1,9 @@ -import "./IVconstants" as IVconstants -import "./shaRound" as sha256 +import "./sha256" as sha256 // A function that takes 6 u32[8] arrays as inputs, concatenates them, // and returns their sha256 compression as a u32[8]. // Note: no padding is applied def main(u32[8] a, u32[8] b, u32[8] c, u32[8] d, u32[8] e, u32[8] f) -> u32[8]: - - u32[8] IV = IVconstants() - u32[8] digest1 = sha256([...a, ...b], IV) - u32[8] digest2 = sha256([...c, ...d], digest1) - u32[8] digest3 = sha256([...e, ...f], digest2) - - return digest3 \ No newline at end of file + u32[8] res = sha256([[...a, ...b], [...c, ...d], [...e, ...f]]) + return res \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/hashes/sha256/512bit.zok b/zokrates_stdlib/stdlib/hashes/sha256/512bit.zok index e7772a13c..4d1c1b608 100644 --- a/zokrates_stdlib/stdlib/hashes/sha256/512bit.zok +++ b/zokrates_stdlib/stdlib/hashes/sha256/512bit.zok @@ -1,5 +1,4 @@ -import "./IVconstants" as IVconstants -import "./shaRound" as sha256 +import "./sha256" as sha256 // A function that takes 2 u32[8] arrays as inputs, concatenates them, // and returns their sha256 compression as a u32[8]. @@ -7,4 +6,4 @@ import "./shaRound" as sha256 def main(u32[8] a, u32[8] b) -> u32[8]: - return sha256([...a, ...b], IVconstants()) + return sha256([[...a, ...b]]) diff --git a/zokrates_stdlib/stdlib/hashes/sha256/sha256.zok b/zokrates_stdlib/stdlib/hashes/sha256/sha256.zok new file mode 100644 index 000000000..cf067e486 --- /dev/null +++ b/zokrates_stdlib/stdlib/hashes/sha256/sha256.zok @@ -0,0 +1,15 @@ +import "./IVconstants" as IVconstants +import "./shaRound" as shaRound + +// A function that takes K u32[8] arrays as inputs, concatenates them, +// and returns their sha256 compression as a u32[8]. +// Note: no padding is applied + +def main(u32[K][16] a) -> u32[8]: + u32[8] current = IVconstants() + + for u32 i in 0..K do + current = shaRound(a[i], current) + endfor + + return current diff --git a/zokrates_stdlib/stdlib/hashes/sha256/shaRound.zok b/zokrates_stdlib/stdlib/hashes/sha256/shaRound.zok index 725d4ed8f..b1248f6de 100644 --- a/zokrates_stdlib/stdlib/hashes/sha256/shaRound.zok +++ b/zokrates_stdlib/stdlib/hashes/sha256/shaRound.zok @@ -42,7 +42,7 @@ def right_rotate_25(u32 e) -> u32: bool[32] b = to_bits(e) return from_bits([...b[7..], ...b[..7]]) -def extend(u32[64] w, field i) -> u32: +def extend(u32[64] w, u32 i) -> u32: u32 s0 = right_rotate_7(w[i-15]) ^ right_rotate_18(w[i-15]) ^ (w[i-15] >> 3) u32 s1 = right_rotate_17(w[i-2]) ^ right_rotate_19(w[i-2]) ^ (w[i-2] >> 10) return w[i-16] + s0 + w[i-7] + s1 @@ -84,7 +84,7 @@ def main(u32[16] input, u32[8] current) -> u32[8]: u32[64] w = [...input, ...[0x00000000; 48]] - for field i in 16..64 do + for u32 i in 16..64 do w[i] = extend(w, i) endfor @@ -97,7 +97,7 @@ def main(u32[16] input, u32[8] current) -> u32[8]: u32 g = h6 u32 h = h7 - for field i in 0..64 do + for u32 i in 0..64 do u32 t1 = temp1(e, f, g, h, k[i], w[i]) diff --git a/zokrates_stdlib/stdlib/hashes/sha3/256bit.zok b/zokrates_stdlib/stdlib/hashes/sha3/256bit.zok new file mode 100644 index 000000000..99d213fa9 --- /dev/null +++ b/zokrates_stdlib/stdlib/hashes/sha3/256bit.zok @@ -0,0 +1,4 @@ +import "hashes/keccak/keccak" as keccak + +def main(u64[N] input) -> (u64[4]): + return keccak::(input, 0x0000000000000006)[..4] \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/hashes/sha3/384bit.zok b/zokrates_stdlib/stdlib/hashes/sha3/384bit.zok new file mode 100644 index 000000000..1b6dfeff5 --- /dev/null +++ b/zokrates_stdlib/stdlib/hashes/sha3/384bit.zok @@ -0,0 +1,4 @@ +import "hashes/keccak/keccak" as keccak + +def main(u64[N] input) -> (u64[6]): + return keccak::(input, 0x0000000000000006)[..6] \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/hashes/sha3/512bit.zok b/zokrates_stdlib/stdlib/hashes/sha3/512bit.zok new file mode 100644 index 000000000..6c37836e2 --- /dev/null +++ b/zokrates_stdlib/stdlib/hashes/sha3/512bit.zok @@ -0,0 +1,4 @@ +import "hashes/keccak/keccak" as keccak + +def main(u64[N] input) -> (u64[8]): + return keccak::(input, 0x0000000000000006)[..8] \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/utils/casts/bool_128_to_u32_4.zok b/zokrates_stdlib/stdlib/utils/casts/bool_128_to_u32_4.zok index 222835bf6..75481860b 100644 --- a/zokrates_stdlib/stdlib/utils/casts/bool_128_to_u32_4.zok +++ b/zokrates_stdlib/stdlib/utils/casts/bool_128_to_u32_4.zok @@ -1,4 +1,5 @@ -import "EMBED/u32_from_bits" as from_bits +import "./bool_array_to_u32_array" as bool_to_u32 def main(bool[128] bits) -> u32[4]: - return [from_bits(bits[0..32]), from_bits(bits[32..64]), from_bits(bits[64..96]), from_bits(bits[96..128])] + u32[4] res = bool_to_u32(bits) + return res \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/utils/casts/bool_256_to_u32_8.zok b/zokrates_stdlib/stdlib/utils/casts/bool_256_to_u32_8.zok index 538cde8b4..6bf0cef93 100644 --- a/zokrates_stdlib/stdlib/utils/casts/bool_256_to_u32_8.zok +++ b/zokrates_stdlib/stdlib/utils/casts/bool_256_to_u32_8.zok @@ -1,4 +1,5 @@ -import "EMBED/u32_from_bits" as from_bits +import "./bool_array_to_u32_array" as bool_to_u32 def main(bool[256] bits) -> u32[8]: - return [from_bits(bits[0..32]), from_bits(bits[32..64]), from_bits(bits[64..96]), from_bits(bits[96..128]), from_bits(bits[128..160]), from_bits(bits[160..192]), from_bits(bits[192..224]), from_bits(bits[224..256])] + u32[8] res = bool_to_u32(bits) + return res \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/utils/casts/bool_array_to_u32_array.zok b/zokrates_stdlib/stdlib/utils/casts/bool_array_to_u32_array.zok new file mode 100644 index 000000000..ba1f2693e --- /dev/null +++ b/zokrates_stdlib/stdlib/utils/casts/bool_array_to_u32_array.zok @@ -0,0 +1,15 @@ +import "EMBED/u32_from_bits" as from_bits + +// convert an array of bool to an array of u32 +// the sizes must match (one u32 for 32 bool) otherwise an error will happen +def main(bool[N] bits) -> u32[P]: + + assert(N == 32 * P) + + u32[P] res = [0; P] + + for u32 i in 0..P do + res[i] = from_bits(bits[32 * i..32 * (i + 1)]) + endfor + + return res \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/utils/casts/field_to_u16.zok b/zokrates_stdlib/stdlib/utils/casts/field_to_u16.zok new file mode 100644 index 000000000..20b5efa59 --- /dev/null +++ b/zokrates_stdlib/stdlib/utils/casts/field_to_u16.zok @@ -0,0 +1,6 @@ +import "EMBED/unpack" as unpack +import "EMBED/u16_from_bits" as from_bits + +def main(field i) -> u16: + bool[16] bits = unpack(i) + return from_bits(bits) \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/utils/casts/field_to_u32.zok b/zokrates_stdlib/stdlib/utils/casts/field_to_u32.zok new file mode 100644 index 000000000..5e9827e8e --- /dev/null +++ b/zokrates_stdlib/stdlib/utils/casts/field_to_u32.zok @@ -0,0 +1,6 @@ +import "EMBED/unpack" as unpack +import "EMBED/u32_from_bits" as from_bits + +def main(field i) -> u32: + bool[32] bits = unpack(i) + return from_bits(bits) \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/utils/casts/field_to_u64.zok b/zokrates_stdlib/stdlib/utils/casts/field_to_u64.zok new file mode 100644 index 000000000..cf72c5fe2 --- /dev/null +++ b/zokrates_stdlib/stdlib/utils/casts/field_to_u64.zok @@ -0,0 +1,6 @@ +import "EMBED/unpack" as unpack +import "EMBED/u64_from_bits" as from_bits + +def main(field i) -> u64: + bool[64] bits = unpack(i) + return from_bits(bits) \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/utils/casts/field_to_u8.zok b/zokrates_stdlib/stdlib/utils/casts/field_to_u8.zok new file mode 100644 index 000000000..7efb927c4 --- /dev/null +++ b/zokrates_stdlib/stdlib/utils/casts/field_to_u8.zok @@ -0,0 +1,6 @@ +import "EMBED/unpack" as unpack +import "EMBED/u8_from_bits" as from_bits + +def main(field i) -> u8: + bool[8] bits = unpack(i) + return from_bits(bits) \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/utils/casts/u16_from_bits.zok b/zokrates_stdlib/stdlib/utils/casts/u16_from_bits.zok new file mode 100644 index 000000000..0bf8cf4f6 --- /dev/null +++ b/zokrates_stdlib/stdlib/utils/casts/u16_from_bits.zok @@ -0,0 +1,4 @@ +import "EMBED/u16_from_bits" as from_bits + +def main(bool[16] a) -> u16: + return from_bits(a) \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/utils/casts/u16_to_bits.zok b/zokrates_stdlib/stdlib/utils/casts/u16_to_bits.zok index 1e3f8bb58..f1dd9fee1 100644 --- a/zokrates_stdlib/stdlib/utils/casts/u16_to_bits.zok +++ b/zokrates_stdlib/stdlib/utils/casts/u16_to_bits.zok @@ -1,4 +1,4 @@ import "EMBED/u16_to_bits" as to_bits def main(u16 a) -> bool[16]: - return to_bits(a) \ No newline at end of file + return to_bits(a) \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/utils/casts/u16_to_field.zok b/zokrates_stdlib/stdlib/utils/casts/u16_to_field.zok index a94dd224b..690419fb5 100644 --- a/zokrates_stdlib/stdlib/utils/casts/u16_to_field.zok +++ b/zokrates_stdlib/stdlib/utils/casts/u16_to_field.zok @@ -1,10 +1,10 @@ import "EMBED/u16_to_bits" as to_bits def main(u16 i) -> field: - bool[16] bits = to_bits(i) - field res = 0 - for field j in 0..16 do - field exponent = 16 - j - 1 - res = res + if bits[j] then 2 ** exponent else 0 fi - endfor - return res \ No newline at end of file + bool[16] bits = to_bits(i) + field res = 0 + for u32 j in 0..16 do + u32 exponent = 16 - j - 1 + res = res + if bits[j] then 2 ** exponent else 0 fi + endfor + return res \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/utils/casts/u32_4_to_bool_128.zok b/zokrates_stdlib/stdlib/utils/casts/u32_4_to_bool_128.zok index 35ad61880..f6bc7976b 100644 --- a/zokrates_stdlib/stdlib/utils/casts/u32_4_to_bool_128.zok +++ b/zokrates_stdlib/stdlib/utils/casts/u32_4_to_bool_128.zok @@ -1,4 +1,5 @@ -import "EMBED/u32_to_bits" as to_bits +import "./u32_array_to_bool_array" as to_bool_array def main(u32[4] input) -> bool[128]: - return [...to_bits(input[0]), ...to_bits(input[1]), ...to_bits(input[2]), ...to_bits(input[3])] + bool[128] res = to_bool_array(input) + return res diff --git a/zokrates_stdlib/stdlib/utils/casts/u32_8_to_bool_256.zok b/zokrates_stdlib/stdlib/utils/casts/u32_8_to_bool_256.zok index 84564fa7c..6b08f2cfd 100644 --- a/zokrates_stdlib/stdlib/utils/casts/u32_8_to_bool_256.zok +++ b/zokrates_stdlib/stdlib/utils/casts/u32_8_to_bool_256.zok @@ -1,4 +1,5 @@ -import "EMBED/u32_to_bits" as to_bits +import "./u32_array_to_bool_array" as to_bool_array def main(u32[8] input) -> bool[256]: - return [...to_bits(input[0]), ...to_bits(input[1]), ...to_bits(input[2]), ...to_bits(input[3]), ...to_bits(input[4]), ...to_bits(input[5]), ...to_bits(input[6]), ...to_bits(input[7])] + bool[256] res = to_bool_array(input) + return res diff --git a/zokrates_stdlib/stdlib/utils/casts/u32_array_to_bool_array.zok b/zokrates_stdlib/stdlib/utils/casts/u32_array_to_bool_array.zok new file mode 100644 index 000000000..28c3d65de --- /dev/null +++ b/zokrates_stdlib/stdlib/utils/casts/u32_array_to_bool_array.zok @@ -0,0 +1,15 @@ +import "EMBED/u32_to_bits" as to_bits + +def main(u32[N] input) -> bool[P]: + assert(P == 32 * N) + + bool[P] res = [false; P] + + for u32 i in 0..N do + bool[32] bits = to_bits(input[i]) + for u32 j in 0..32 do + res[i * 32 + j] = bits[j] + endfor + endfor + + return res diff --git a/zokrates_stdlib/stdlib/utils/casts/u32_from_bits.zok b/zokrates_stdlib/stdlib/utils/casts/u32_from_bits.zok new file mode 100644 index 000000000..f4620c448 --- /dev/null +++ b/zokrates_stdlib/stdlib/utils/casts/u32_from_bits.zok @@ -0,0 +1,4 @@ +import "EMBED/u32_from_bits" as from_bits + +def main(bool[32] a) -> u32: + return from_bits(a) \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/utils/casts/u32_to_bits.zok b/zokrates_stdlib/stdlib/utils/casts/u32_to_bits.zok index 204a0f407..3b68cdbd3 100644 --- a/zokrates_stdlib/stdlib/utils/casts/u32_to_bits.zok +++ b/zokrates_stdlib/stdlib/utils/casts/u32_to_bits.zok @@ -1,4 +1,4 @@ import "EMBED/u32_to_bits" as to_bits def main(u32 a) -> bool[32]: - return to_bits(a) \ No newline at end of file + return to_bits(a) \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/utils/casts/u32_to_field.zok b/zokrates_stdlib/stdlib/utils/casts/u32_to_field.zok index 6475a85c3..7c181d83e 100644 --- a/zokrates_stdlib/stdlib/utils/casts/u32_to_field.zok +++ b/zokrates_stdlib/stdlib/utils/casts/u32_to_field.zok @@ -1,10 +1,10 @@ import "EMBED/u32_to_bits" as to_bits def main(u32 i) -> field: - bool[32] bits = to_bits(i) - field res = 0 - for field j in 0..32 do - field exponent = 32 - j - 1 - res = res + if bits[j] then 2 ** exponent else 0 fi - endfor - return res \ No newline at end of file + bool[32] bits = to_bits(i) + field res = 0 + for u32 j in 0..32 do + u32 exponent = 32 - j - 1 + res = res + if bits[j] then 2 ** exponent else 0 fi + endfor + return res \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/utils/casts/u64_from_bits.zok b/zokrates_stdlib/stdlib/utils/casts/u64_from_bits.zok new file mode 100644 index 000000000..be30561f3 --- /dev/null +++ b/zokrates_stdlib/stdlib/utils/casts/u64_from_bits.zok @@ -0,0 +1,4 @@ +import "EMBED/u64_from_bits" as from_bits + +def main(bool[64] a) -> u64: + return from_bits(a) \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/utils/casts/u64_to_bits.zok b/zokrates_stdlib/stdlib/utils/casts/u64_to_bits.zok new file mode 100644 index 000000000..a7e71ed49 --- /dev/null +++ b/zokrates_stdlib/stdlib/utils/casts/u64_to_bits.zok @@ -0,0 +1,4 @@ +import "EMBED/u64_to_bits" as to_bits + +def main(u64 a) -> bool[64]: + return to_bits(a) \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/utils/casts/u64_to_field.zok b/zokrates_stdlib/stdlib/utils/casts/u64_to_field.zok new file mode 100644 index 000000000..208958674 --- /dev/null +++ b/zokrates_stdlib/stdlib/utils/casts/u64_to_field.zok @@ -0,0 +1,10 @@ +import "EMBED/u64_to_bits" as to_bits + +def main(u64 i) -> field: + bool[64] bits = to_bits(i) + field res = 0 + for u32 j in 0..64 do + u32 exponent = 64 - j - 1 + res = res + if bits[j] then 2 ** exponent else 0 fi + endfor + return res \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/utils/casts/u8_from_bits.zok b/zokrates_stdlib/stdlib/utils/casts/u8_from_bits.zok new file mode 100644 index 000000000..e1a0ade4f --- /dev/null +++ b/zokrates_stdlib/stdlib/utils/casts/u8_from_bits.zok @@ -0,0 +1,4 @@ +import "EMBED/u8_from_bits" as from_bits + +def main(bool[8] a) -> u8: + return from_bits(a) \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/utils/casts/u8_to_bits.zok b/zokrates_stdlib/stdlib/utils/casts/u8_to_bits.zok index 9bb8b5921..d2ffc8ec5 100644 --- a/zokrates_stdlib/stdlib/utils/casts/u8_to_bits.zok +++ b/zokrates_stdlib/stdlib/utils/casts/u8_to_bits.zok @@ -1,4 +1,4 @@ import "EMBED/u8_to_bits" as to_bits def main(u8 a) -> bool[8]: - return to_bits(a) \ No newline at end of file + return to_bits(a) \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/utils/casts/u8_to_field.zok b/zokrates_stdlib/stdlib/utils/casts/u8_to_field.zok index 30a721c69..b1d14ba73 100644 --- a/zokrates_stdlib/stdlib/utils/casts/u8_to_field.zok +++ b/zokrates_stdlib/stdlib/utils/casts/u8_to_field.zok @@ -1,10 +1,10 @@ import "EMBED/u8_to_bits" as to_bits def main(u8 i) -> field: - bool[8] bits = to_bits(i) - field res = 0 - for field j in 0..8 do - field exponent = 8 - j - 1 - res = res + if bits[j] then 2 ** exponent else 0 fi - endfor - return res \ No newline at end of file + bool[8] bits = to_bits(i) + field res = 0 + for u32 j in 0..8 do + u32 exponent = 8 - j - 1 + res = res + if bits[j] then 2 ** exponent else 0 fi + endfor + return res \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/utils/pack/bool/pack.zok b/zokrates_stdlib/stdlib/utils/pack/bool/pack.zok new file mode 100644 index 000000000..cbf853b98 --- /dev/null +++ b/zokrates_stdlib/stdlib/utils/pack/bool/pack.zok @@ -0,0 +1,10 @@ +def main(bool[N] bits) -> field: + + field out = 0 + + for u32 j in 0..N do + u32 i = N - (j + 1) + out = out + if bits[i] then (2 ** j) else 0 fi + endfor + + return out diff --git a/zokrates_stdlib/stdlib/utils/pack/bool/pack128.zok b/zokrates_stdlib/stdlib/utils/pack/bool/pack128.zok index e69ac9434..63962151e 100644 --- a/zokrates_stdlib/stdlib/utils/pack/bool/pack128.zok +++ b/zokrates_stdlib/stdlib/utils/pack/bool/pack128.zok @@ -1,15 +1,7 @@ #pragma curve bn128 +import "./pack" as pack + // pack 128 big-endian bits into one field element def main(bool[128] bits) -> field: - - field out = 0 - - field len = 128 - - for field j in 0..len do - field i = len - (j + 1) - out = out + if bits[i] then (2 ** j) else 0 fi - endfor - - return out \ No newline at end of file + return pack(bits) \ 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 d92ac2a3a..11f3e9b3a 100644 --- a/zokrates_stdlib/stdlib/utils/pack/bool/pack256.zok +++ b/zokrates_stdlib/stdlib/utils/pack/bool/pack256.zok @@ -1,17 +1,9 @@ #pragma curve bn128 +import "./pack" as pack + // pack 256 big-endian bits into one field element // Note: This is not a injective operation as `p` is smaller than `2**256 - 1` for bn128 // For example, `[0, 0,..., 0]` and `bits(p)` both point to `0` def main(bool[256] bits) -> field: - - field out = 0 - - field len = 256 - - for field j in 0..len do - field i = len - (j + 1) - out = out + if bits[i] then (2 ** j) else 0 fi - endfor - - return out + return pack(bits) diff --git a/zokrates_stdlib/stdlib/utils/pack/bool/unpack.zok b/zokrates_stdlib/stdlib/utils/pack/bool/unpack.zok new file mode 100644 index 000000000..38bd04a74 --- /dev/null +++ b/zokrates_stdlib/stdlib/utils/pack/bool/unpack.zok @@ -0,0 +1,12 @@ +#pragma curve bn128 + +import "EMBED/unpack" as unpack + +// Unpack a field element as N big endian bits +def main(field i) -> bool[N]: + + assert(N <= 254) + + bool[N] res = unpack(i) + + return res \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/utils/pack/bool/unpack128.zok b/zokrates_stdlib/stdlib/utils/pack/bool/unpack128.zok index 66d895572..a24a244b0 100644 --- a/zokrates_stdlib/stdlib/utils/pack/bool/unpack128.zok +++ b/zokrates_stdlib/stdlib/utils/pack/bool/unpack128.zok @@ -1,13 +1,9 @@ #pragma curve bn128 -import "EMBED/unpack" as unpack +import "./unpack" as unpack // Unpack a field element as 128 big-endian bits // Precondition: the input is smaller or equal to `2**128 - 1` def main(field i) -> bool[128]: - - bool[254] b = unpack(i) - - assert(b[0..126] == [false; 126]) - - return b[126..254] \ No newline at end of file + bool[128] res = unpack::<128>(i) + return res \ No newline at end of file diff --git a/zokrates_stdlib/stdlib/utils/pack/u32/pack.zok b/zokrates_stdlib/stdlib/utils/pack/u32/pack.zok new file mode 100644 index 000000000..da8d1c686 --- /dev/null +++ b/zokrates_stdlib/stdlib/utils/pack/u32/pack.zok @@ -0,0 +1,9 @@ +import "../../casts/u32_array_to_bool_array" as to_bits +import "../bool/pack" + +// pack N big-endian bits into one field element +def main(u32[N] input) -> field: + + bool[N * 32] bits = to_bits(input) + + return pack(bits) diff --git a/zokrates_stdlib/stdlib/utils/pack/u32/pack128.zok b/zokrates_stdlib/stdlib/utils/pack/u32/pack128.zok index 26e7c28e8..d9ec24b17 100644 --- a/zokrates_stdlib/stdlib/utils/pack/u32/pack128.zok +++ b/zokrates_stdlib/stdlib/utils/pack/u32/pack128.zok @@ -1,9 +1,5 @@ -import "EMBED/u32_to_bits" as to_bits -import "../bool/pack128" +import "./pack" as pack // pack 128 big-endian bits into one field element def main(u32[4] input) -> field: - - bool[128] bits = [...to_bits(input[0]), ...to_bits(input[1]), ...to_bits(input[2]), ...to_bits(input[3])] - - return pack128(bits) + return pack(input) diff --git a/zokrates_stdlib/stdlib/utils/pack/u32/unpack128.zok b/zokrates_stdlib/stdlib/utils/pack/u32/unpack128.zok index ebdb75445..24eeb83af 100644 --- a/zokrates_stdlib/stdlib/utils/pack/u32/unpack128.zok +++ b/zokrates_stdlib/stdlib/utils/pack/u32/unpack128.zok @@ -6,5 +6,4 @@ import "../../casts/bool_128_to_u32_4" as from_bits // Unpack a field element as 128 big-endian bits // Precondition: the input is smaller or equal to `2**128 - 1` def main(field i) -> u32[4]: - return from_bits(unpack(i)) \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/hashes/blake2/blake2s_1024bit.json b/zokrates_stdlib/tests/tests/hashes/blake2/blake2s_1024bit.json new file mode 100644 index 000000000..eb0fe602e --- /dev/null +++ b/zokrates_stdlib/tests/tests/hashes/blake2/blake2s_1024bit.json @@ -0,0 +1,15 @@ +{ + "entry_point": "./tests/tests/hashes/blake2/blake2s_1024bit.zok", + "tests": [ + { + "input": { + "values": [] + }, + "output": { + "Ok": { + "values": [] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/hashes/blake2/blake2s_1024bit.zok b/zokrates_stdlib/tests/tests/hashes/blake2/blake2s_1024bit.zok new file mode 100644 index 000000000..899f120f6 --- /dev/null +++ b/zokrates_stdlib/tests/tests/hashes/blake2/blake2s_1024bit.zok @@ -0,0 +1,6 @@ +import "hashes/blake2/blake2s" + +def main(): + u32[8] h = blake2s::<2>([[0; 16]; 2]) + assert(h == [0x2005424E, 0x7BCE81B9, 0x2CCEF4DB, 0x94DBBA4D, 0x7D9B0750, 0xB53797EB, 0xD3572923, 0xCB01F823]) + return \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/hashes/blake2/blake2s_1536bit.json b/zokrates_stdlib/tests/tests/hashes/blake2/blake2s_1536bit.json new file mode 100644 index 000000000..e637ac91a --- /dev/null +++ b/zokrates_stdlib/tests/tests/hashes/blake2/blake2s_1536bit.json @@ -0,0 +1,15 @@ +{ + "entry_point": "./tests/tests/hashes/blake2/blake2s_1536bit.zok", + "tests": [ + { + "input": { + "values": [] + }, + "output": { + "Ok": { + "values": [] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/hashes/blake2/blake2s_1536bit.zok b/zokrates_stdlib/tests/tests/hashes/blake2/blake2s_1536bit.zok new file mode 100644 index 000000000..28ba15294 --- /dev/null +++ b/zokrates_stdlib/tests/tests/hashes/blake2/blake2s_1536bit.zok @@ -0,0 +1,6 @@ +import "hashes/blake2/blake2s" + +def main(): + u32[8] h = blake2s::<3>([[0x42424242; 16]; 3]) + assert(h == [0x804BD0E6, 0x90AD426E, 0x6BCF0BAD, 0xCB2D22C1, 0xF717B3C3, 0x4D9CB47F, 0xEB541A97, 0x061D9ED0]) + return \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/hashes/blake2/blake2s_512bit.json b/zokrates_stdlib/tests/tests/hashes/blake2/blake2s_512bit.json new file mode 100644 index 000000000..756f20381 --- /dev/null +++ b/zokrates_stdlib/tests/tests/hashes/blake2/blake2s_512bit.json @@ -0,0 +1,15 @@ +{ + "entry_point": "./tests/tests/hashes/blake2/blake2s_512bit.zok", + "tests": [ + { + "input": { + "values": [] + }, + "output": { + "Ok": { + "values": [] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/hashes/blake2/blake2s_512bit.zok b/zokrates_stdlib/tests/tests/hashes/blake2/blake2s_512bit.zok new file mode 100644 index 000000000..28d5edca0 --- /dev/null +++ b/zokrates_stdlib/tests/tests/hashes/blake2/blake2s_512bit.zok @@ -0,0 +1,6 @@ +import "hashes/blake2/blake2s" + +def main(): + u32[8] h = blake2s::<1>([[0; 16]]) + assert(h == [0x7CDB09AE, 0xB4424FD5, 0xB609EF90, 0xF61A54BC, 0x9B95E488, 0x353FC5B8, 0xE3566F9A, 0xA354B48A]) + return \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/hashes/blake2/blake2s_8192bit.json b/zokrates_stdlib/tests/tests/hashes/blake2/blake2s_8192bit.json new file mode 100644 index 000000000..2b7ea18bf --- /dev/null +++ b/zokrates_stdlib/tests/tests/hashes/blake2/blake2s_8192bit.json @@ -0,0 +1,15 @@ +{ + "entry_point": "./tests/tests/hashes/blake2/blake2s_8192bit.zok", + "tests": [ + { + "input": { + "values": [] + }, + "output": { + "Ok": { + "values": [] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/hashes/blake2/blake2s_8192bit.zok b/zokrates_stdlib/tests/tests/hashes/blake2/blake2s_8192bit.zok new file mode 100644 index 000000000..f7a93b80e --- /dev/null +++ b/zokrates_stdlib/tests/tests/hashes/blake2/blake2s_8192bit.zok @@ -0,0 +1,6 @@ +import "hashes/blake2/blake2s" + +def main(): + u32[8] h = blake2s::<16>([[0; 16]; 16]) + assert(h == [0x63665303, 0x046C502A, 0xC8514A5D, 0x67B7E833, 0xA9DAD591, 0xB421A8BC, 0x662A73A2, 0x2DA25AFB]) + return \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/hashes/blake2/blake2s_p.json b/zokrates_stdlib/tests/tests/hashes/blake2/blake2s_p.json new file mode 100644 index 000000000..2412b8f35 --- /dev/null +++ b/zokrates_stdlib/tests/tests/hashes/blake2/blake2s_p.json @@ -0,0 +1,15 @@ +{ + "entry_point": "./tests/tests/hashes/blake2/blake2s_p.zok", + "tests": [ + { + "input": { + "values": [] + }, + "output": { + "Ok": { + "values": [] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/hashes/blake2/blake2s_p.zok b/zokrates_stdlib/tests/tests/hashes/blake2/blake2s_p.zok new file mode 100644 index 000000000..7a861e6ca --- /dev/null +++ b/zokrates_stdlib/tests/tests/hashes/blake2/blake2s_p.zok @@ -0,0 +1,6 @@ +import "hashes/blake2/blake2s_p" as blake2s + +def main(): + u32[8] h = blake2s::<1>([[0; 16]], [0x12345678, 0]) + assert(h == [0xC63C8C31, 0x5FCA3E69, 0x13850D46, 0x1DE48657, 0x208D2534, 0x9AA6E0EF, 0xAFEE7610, 0xFBDFAC13]) + return \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/hashes/keccak/256bit.json b/zokrates_stdlib/tests/tests/hashes/keccak/256bit.json new file mode 100644 index 000000000..fc1db71e6 --- /dev/null +++ b/zokrates_stdlib/tests/tests/hashes/keccak/256bit.json @@ -0,0 +1,15 @@ +{ + "entry_point": "./tests/tests/hashes/keccak/256bit.zok", + "tests": [ + { + "input": { + "values": [] + }, + "output": { + "Ok": { + "values": [] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/hashes/keccak/256bit.zok b/zokrates_stdlib/tests/tests/hashes/keccak/256bit.zok new file mode 100644 index 000000000..36eb36351 --- /dev/null +++ b/zokrates_stdlib/tests/tests/hashes/keccak/256bit.zok @@ -0,0 +1,6 @@ +import "hashes/keccak/256bit" as keccak256 + +def main(): + u64[4] h = keccak256::<20>([42; 20]) + assert(h == [0x09330DD35B609CA9, 0xDACFC1598C95602C, 0xACD911013FB018F3, 0x17233D68F05E0826]) + return \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/hashes/keccak/384bit.json b/zokrates_stdlib/tests/tests/hashes/keccak/384bit.json new file mode 100644 index 000000000..b90c14f3b --- /dev/null +++ b/zokrates_stdlib/tests/tests/hashes/keccak/384bit.json @@ -0,0 +1,15 @@ +{ + "entry_point": "./tests/tests/hashes/keccak/384bit.zok", + "tests": [ + { + "input": { + "values": [] + }, + "output": { + "Ok": { + "values": [] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/hashes/keccak/384bit.zok b/zokrates_stdlib/tests/tests/hashes/keccak/384bit.zok new file mode 100644 index 000000000..019bf5583 --- /dev/null +++ b/zokrates_stdlib/tests/tests/hashes/keccak/384bit.zok @@ -0,0 +1,6 @@ +import "hashes/keccak/384bit" as keccak384 + +def main(): + u64[6] h = keccak384::<20>([42; 20]) + assert(h == [0x2E9DCE590F0A1908, 0x0C4234AB952C5598, 0xFB2DF066B44780C2, 0x717039E101D4A8DA, 0xBAD1EFE140C4B2C4, 0xFAE08DAC3438416E]) + return \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/hashes/keccak/512bit.json b/zokrates_stdlib/tests/tests/hashes/keccak/512bit.json new file mode 100644 index 000000000..6ee6daa5f --- /dev/null +++ b/zokrates_stdlib/tests/tests/hashes/keccak/512bit.json @@ -0,0 +1,15 @@ +{ + "entry_point": "./tests/tests/hashes/keccak/512bit.zok", + "tests": [ + { + "input": { + "values": [] + }, + "output": { + "Ok": { + "values": [] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/hashes/keccak/512bit.zok b/zokrates_stdlib/tests/tests/hashes/keccak/512bit.zok new file mode 100644 index 000000000..4e7d3e918 --- /dev/null +++ b/zokrates_stdlib/tests/tests/hashes/keccak/512bit.zok @@ -0,0 +1,9 @@ +import "hashes/keccak/512bit" as keccak512 + +def main(): + u64[8] h = keccak512::<20>([42; 20]) + assert(h == [ + 0x2716192386255918, 0x68DFF390376BBF13, 0xBD695ADA4CD230E3, 0xF3B00388676A04D3, + 0x484F3F1BB9F36A09, 0x9D0119067282F940, 0xDF27DE0F48072A66, 0xF5957972134160EB + ]) + return \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/hashes/mimc7/mimc7R90.json b/zokrates_stdlib/tests/tests/hashes/mimc7/mimc7.json similarity index 78% rename from zokrates_stdlib/tests/tests/hashes/mimc7/mimc7R90.json rename to zokrates_stdlib/tests/tests/hashes/mimc7/mimc7.json index b5c304e0b..fe7581b2e 100644 --- a/zokrates_stdlib/tests/tests/hashes/mimc7/mimc7R90.json +++ b/zokrates_stdlib/tests/tests/hashes/mimc7/mimc7.json @@ -1,5 +1,5 @@ { - "entry_point": "./tests/tests/hashes/mimc7/mimc7R90.zok", + "entry_point": "./tests/tests/hashes/mimc7/mimc7.zok", "tests": [ { "input": { diff --git a/zokrates_stdlib/tests/tests/hashes/mimc7/mimc7.zok b/zokrates_stdlib/tests/tests/hashes/mimc7/mimc7.zok new file mode 100644 index 000000000..5303eb7cc --- /dev/null +++ b/zokrates_stdlib/tests/tests/hashes/mimc7/mimc7.zok @@ -0,0 +1,15 @@ +import "hashes/mimc7/mimc7" + +def main(): + assert(mimc7::<10>(0, 0) == 6004544488495356385698286530147974336054653445122716140990101827963729149289) + assert(mimc7::<10>(100, 0) == 2977550761518141183167168643824354554080911485709001361112529600968315693145) + + assert(mimc7::<20>(0, 0) == 19139739902058628561064841933381604453445216873412991992755775746150759284829) + assert(mimc7::<20>(100, 0) == 8623418512398828792274158979964869393034224267928014534933203776818702139758) + + assert(mimc7::<50>(0, 0) == 3049953358280347916081509186284461274525472221619157672645224540758481713173) + assert(mimc7::<50>(100, 0) == 18511388995652647480418174218630545482006454713617579894396683237092568946789) + + assert(mimc7::<90>(0, 0) == 20281265111705407344053532742843085357648991805359414661661476832595822221514) + assert(mimc7::<90>(100, 0) == 1010054095264022068840870550831559811104631937745987065544478027572003292636) + return \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/hashes/mimc7/mimc7R10.json b/zokrates_stdlib/tests/tests/hashes/mimc7/mimc7R10.json deleted file mode 100644 index b37df2d60..000000000 --- a/zokrates_stdlib/tests/tests/hashes/mimc7/mimc7R10.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "entry_point": "./tests/tests/hashes/mimc7/mimc7R10.zok", - "tests": [ - { - "input": { - "values": [] - }, - "output": { - "Ok": { - "values": [] - } - } - } - ] -} \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/hashes/mimc7/mimc7R10.zok b/zokrates_stdlib/tests/tests/hashes/mimc7/mimc7R10.zok deleted file mode 100644 index d41fc8c07..000000000 --- a/zokrates_stdlib/tests/tests/hashes/mimc7/mimc7R10.zok +++ /dev/null @@ -1,6 +0,0 @@ -import "hashes/mimc7/mimc7R10" - -def main(): - assert(mimc7R10(0, 0) == 6004544488495356385698286530147974336054653445122716140990101827963729149289) - assert(mimc7R10(100, 0) == 2977550761518141183167168643824354554080911485709001361112529600968315693145) - return \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/hashes/mimc7/mimc7R20.json b/zokrates_stdlib/tests/tests/hashes/mimc7/mimc7R20.json deleted file mode 100644 index d5b121baf..000000000 --- a/zokrates_stdlib/tests/tests/hashes/mimc7/mimc7R20.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "entry_point": "./tests/tests/hashes/mimc7/mimc7R20.zok", - "tests": [ - { - "input": { - "values": [] - }, - "output": { - "Ok": { - "values": [] - } - } - } - ] -} \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/hashes/mimc7/mimc7R20.zok b/zokrates_stdlib/tests/tests/hashes/mimc7/mimc7R20.zok deleted file mode 100644 index 6ef79bbb9..000000000 --- a/zokrates_stdlib/tests/tests/hashes/mimc7/mimc7R20.zok +++ /dev/null @@ -1,6 +0,0 @@ -import "hashes/mimc7/mimc7R20" - -def main(): - assert(mimc7R20(0, 0) == 19139739902058628561064841933381604453445216873412991992755775746150759284829) - assert(mimc7R20(100, 0) == 8623418512398828792274158979964869393034224267928014534933203776818702139758) - return \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/hashes/mimc7/mimc7R50.json b/zokrates_stdlib/tests/tests/hashes/mimc7/mimc7R50.json deleted file mode 100644 index 37933e801..000000000 --- a/zokrates_stdlib/tests/tests/hashes/mimc7/mimc7R50.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "entry_point": "./tests/tests/hashes/mimc7/mimc7R50.zok", - "tests": [ - { - "input": { - "values": [] - }, - "output": { - "Ok": { - "values": [] - } - } - } - ] -} \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/hashes/mimc7/mimc7R50.zok b/zokrates_stdlib/tests/tests/hashes/mimc7/mimc7R50.zok deleted file mode 100644 index 2f6e513ff..000000000 --- a/zokrates_stdlib/tests/tests/hashes/mimc7/mimc7R50.zok +++ /dev/null @@ -1,6 +0,0 @@ -import "hashes/mimc7/mimc7R50" - -def main(): - assert(mimc7R50(0, 0) == 3049953358280347916081509186284461274525472221619157672645224540758481713173) - assert(mimc7R50(100, 0) == 18511388995652647480418174218630545482006454713617579894396683237092568946789) - return \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/hashes/mimc7/mimc7R90.zok b/zokrates_stdlib/tests/tests/hashes/mimc7/mimc7R90.zok deleted file mode 100644 index 0f197d0c0..000000000 --- a/zokrates_stdlib/tests/tests/hashes/mimc7/mimc7R90.zok +++ /dev/null @@ -1,6 +0,0 @@ -import "hashes/mimc7/mimc7R90" - -def main(): - assert(mimc7R90(0, 0) == 20281265111705407344053532742843085357648991805359414661661476832595822221514) - assert(mimc7R90(100, 0) == 1010054095264022068840870550831559811104631937745987065544478027572003292636) - return \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/hashes/mimcSponge/mimcSponge.zok b/zokrates_stdlib/tests/tests/hashes/mimcSponge/mimcSponge.zok index 4ce6771bc..decdfeed9 100644 --- a/zokrates_stdlib/tests/tests/hashes/mimcSponge/mimcSponge.zok +++ b/zokrates_stdlib/tests/tests/hashes/mimcSponge/mimcSponge.zok @@ -1,6 +1,6 @@ import "hashes/mimcSponge/mimcSponge" as mimcSponge def main(): - assert(mimcSponge([1,2], 3) == [20225509322021146255705869525264566735642015554514977326536820959638320229084, 13871743498877225461925335509899475799121918157213219438898506786048812913771, 21633608428713573518356618235457250173701815120501233429160399974209848779097]) - assert(mimcSponge([0,0], 0) == [20636625426020718969131298365984859231982649550971729229988535915544421356929, 6046202021237334713296073963481784771443313518730771623154467767602059802325, 16227963524034219233279650312501310147918176407385833422019760797222680144279]) + assert(mimcSponge([1,2], 3) == [20225509322021146255705869525264566735642015554514977326536820959638320229084,13871743498877225461925335509899475799121918157213219438898506786048812913771,21633608428713573518356618235457250173701815120501233429160399974209848779097f]) + assert(mimcSponge([0,0], 0) == [20636625426020718969131298365984859231982649550971729229988535915544421356929,6046202021237334713296073963481784771443313518730771623154467767602059802325,16227963524034219233279650312501310147918176407385833422019760797222680144279f]) return \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/hashes/pedersen/512bitBool.json b/zokrates_stdlib/tests/tests/hashes/pedersen/512bitBool.json new file mode 100644 index 000000000..535a38d19 --- /dev/null +++ b/zokrates_stdlib/tests/tests/hashes/pedersen/512bitBool.json @@ -0,0 +1,14 @@ +{ + "entry_point": "./tests/tests/hashes/pedersen/512bitBool.zok", + "curves": ["Bn128"], + "tests": [{ + "input": { + "values": [] + }, + "output": { + "Ok": { + "values": ["1"] + } + } + }] +} \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/hashes/pedersen/512bitBool.zok b/zokrates_stdlib/tests/tests/hashes/pedersen/512bitBool.zok new file mode 100644 index 000000000..6ed7809da --- /dev/null +++ b/zokrates_stdlib/tests/tests/hashes/pedersen/512bitBool.zok @@ -0,0 +1,7 @@ +import "hashes/pedersen/512bitBool" as pedersen + +def main() -> (field): + bool[512] input = [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, 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] res = [true,false,true,false,true,true,true,false,true,false,false,false,true,true,false,true,false,true,false,false,true,false,false,true,true,false,true,false,true,true,true,false,false,true,true,false,true,true,false,false,false,true,false,false,false,true,false,false,false,true,false,true,false,true,true,false,true,false,false,false,false,false,true,true,false,true,true,true,true,false,true,true,false,true,false,false,true,false,true,false,true,true,true,true,true,true,false,true,false,false,true,true,false,true,true,false,true,false,false,false,true,true,false,true,false,true,false,true,true,false,true,true,true,true,true,false,true,true,true,false,true,false,true,false,false,true,false,true,false,false,false,true,true,true,false,true,true,true,true,true,false,true,false,false,true,false,false,true,true,false,false,true,false,true,false,true,true,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,true,true,false,false,true,false,true,false,true,true,false,true,true,true,false,true,true,true,false,true,true,true,true,false,false,false,true,true,false,true,true,false,false,false,false,true,false,false,false,false,true,true,true,false,true,false,true,false,false,false,false,true,true,false,false,true,false,true,true,false,false,true,false,true,true,false,true,false,true,true,true,true,false,true,true,true,true,true,true,true,true,true,true] + assert(pedersen(input) == res) + return 1 \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/hashes/sha3/256bit.json b/zokrates_stdlib/tests/tests/hashes/sha3/256bit.json new file mode 100644 index 000000000..86108146f --- /dev/null +++ b/zokrates_stdlib/tests/tests/hashes/sha3/256bit.json @@ -0,0 +1,15 @@ +{ + "entry_point": "./tests/tests/hashes/sha3/256bit.zok", + "tests": [ + { + "input": { + "values": [] + }, + "output": { + "Ok": { + "values": [] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/hashes/sha3/256bit.zok b/zokrates_stdlib/tests/tests/hashes/sha3/256bit.zok new file mode 100644 index 000000000..e5988be99 --- /dev/null +++ b/zokrates_stdlib/tests/tests/hashes/sha3/256bit.zok @@ -0,0 +1,6 @@ +import "hashes/sha3/256bit" as sha3_256 + +def main(): + u64[4] h = sha3_256::<20>([42; 20]) + assert(h == [0x84350A3A90DED183, 0x70518606C7DC401A, 0x2D44F39C0FCEAC92, 0x3E9533A716130C5A]) + return \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/hashes/sha3/384bit.json b/zokrates_stdlib/tests/tests/hashes/sha3/384bit.json new file mode 100644 index 000000000..2d03a2a53 --- /dev/null +++ b/zokrates_stdlib/tests/tests/hashes/sha3/384bit.json @@ -0,0 +1,15 @@ +{ + "entry_point": "./tests/tests/hashes/sha3/384bit.zok", + "tests": [ + { + "input": { + "values": [] + }, + "output": { + "Ok": { + "values": [] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/hashes/sha3/384bit.zok b/zokrates_stdlib/tests/tests/hashes/sha3/384bit.zok new file mode 100644 index 000000000..cfc24b4d2 --- /dev/null +++ b/zokrates_stdlib/tests/tests/hashes/sha3/384bit.zok @@ -0,0 +1,6 @@ +import "hashes/sha3/384bit" as sha3_384 + +def main(): + u64[6] h = sha3_384::<20>([42; 20]) + assert(h == [0x75A036FA8B615B37, 0x6C73086BB56F092C, 0x536E658916EC18AE, 0xB2F2EEE620CDF698, 0xB7E904DE62A70A31, 0x84FDAA0665836ADD]) + return \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/hashes/sha3/512bit.json b/zokrates_stdlib/tests/tests/hashes/sha3/512bit.json new file mode 100644 index 000000000..a5dba0ca0 --- /dev/null +++ b/zokrates_stdlib/tests/tests/hashes/sha3/512bit.json @@ -0,0 +1,15 @@ +{ + "entry_point": "./tests/tests/hashes/sha3/512bit.zok", + "tests": [ + { + "input": { + "values": [] + }, + "output": { + "Ok": { + "values": [] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/hashes/sha3/512bit.zok b/zokrates_stdlib/tests/tests/hashes/sha3/512bit.zok new file mode 100644 index 000000000..b5846a3ef --- /dev/null +++ b/zokrates_stdlib/tests/tests/hashes/sha3/512bit.zok @@ -0,0 +1,9 @@ +import "hashes/sha3/512bit" as sha3_512 + +def main(): + u64[8] h = sha3_512::<20>([42; 20]) + assert(h == [ + 0x22DFD92B47C60DAC, 0xDA47C8C247A84FA2, 0x7C5809F122D6950A, 0x8034D41097680656, + 0xD6D06F820B046994, 0xF62743594A554B88, 0x4966E0821CB4D667, 0x974D4391624C5619 + ]) + return \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/utils/casts/field_to_uint.json b/zokrates_stdlib/tests/tests/utils/casts/field_to_uint.json new file mode 100644 index 000000000..1c988f730 --- /dev/null +++ b/zokrates_stdlib/tests/tests/utils/casts/field_to_uint.json @@ -0,0 +1,16 @@ +{ + "entry_point": "./tests/tests/utils/casts/field_to_uint.zok", + "curves": ["Bn128"], + "tests": [ + { + "input": { + "values": ["0", "1", "18446744073709551615", "42", "0", "1", "4294967295", "42", "0", "1", "65535", "42", "0", "1", "255", "42"] + }, + "output": { + "Ok": { + "values": ["0", "1", "18446744073709551615", "42", "0", "1", "4294967295", "42", "0", "1", "65535", "42", "0", "1", "255", "42"] + } + } + } + ] +} \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/utils/casts/field_to_uint.zok b/zokrates_stdlib/tests/tests/utils/casts/field_to_uint.zok new file mode 100644 index 000000000..b8a3de762 --- /dev/null +++ b/zokrates_stdlib/tests/tests/utils/casts/field_to_uint.zok @@ -0,0 +1,19 @@ +import "utils/casts/field_to_u64" +import "utils/casts/field_to_u32" +import "utils/casts/field_to_u16" +import "utils/casts/field_to_u8" + +def main(field[4] a, field[4] b, field[4] c, field[4] d) -> (u64[4], u32[4], u16[4], u8[4]): + u64[4] e = [0; 4] + u32[4] f = [0; 4] + u16[4] g = [0; 4] + u8[4] h = [0; 4] + + for u32 i in 0..4 do + e[i] = field_to_u64(a[i]) + f[i] = field_to_u32(b[i]) + g[i] = field_to_u16(c[i]) + h[i] = field_to_u8(d[i]) + endfor + + return e, f, g, h \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/utils/casts/to_bits.json b/zokrates_stdlib/tests/tests/utils/casts/to_bits.json index ca4c9840a..c5ce52310 100644 --- a/zokrates_stdlib/tests/tests/utils/casts/to_bits.json +++ b/zokrates_stdlib/tests/tests/utils/casts/to_bits.json @@ -1,29 +1,33 @@ { - "entry_point": "./tests/tests/utils/casts/to_bits.zok", - "curves": ["Bn128"], - "tests": [ - { - "input": { - "values": ["0", "1", "4294967295", "42", "0", "1", "65535", "42", "0", "1", "255", "42"] - }, - "output": { - "Ok": { - "values": [ - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "1", - "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "1", "0", "1", "0", "1", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "1", - "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", - "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "1", "0", "1", "0", "1", "0", - "0", "0", "0", "0", "0", "0", "0", "0", - "0", "0", "0", "0", "0", "0", "0", "1", - "1", "1", "1", "1", "1", "1", "1", "1", - "0", "0", "1", "0", "1", "0", "1", "0" - ] - } - } - } - ] + "entry_point": "./tests/tests/utils/casts/to_bits.zok", + "curves": ["Bn128"], + "tests": [ + { + "input": { + "values": ["0", "1", "18446744073709551615", "42", "0", "1", "4294967295", "42", "0", "1", "65535", "42", "0", "1", "255", "42"] + }, + "output": { + "Ok": { + "values": [ + "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", + "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "1", + "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", + "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "1", "0", "1", "0", "1", "0", + "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", + "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "1", + "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", + "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "1", "0", "1", "0", "1", "0", + "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", + "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "1", + "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", + "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "1", "0", "1", "0", "1", "0", + "0", "0", "0", "0", "0", "0", "0", "0", + "0", "0", "0", "0", "0", "0", "0", "1", + "1", "1", "1", "1", "1", "1", "1", "1", + "0", "0", "1", "0", "1", "0", "1", "0" + ] + } + } + } + ] } \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/utils/casts/to_bits.zok b/zokrates_stdlib/tests/tests/utils/casts/to_bits.zok index 6e445704f..f53126dcb 100644 --- a/zokrates_stdlib/tests/tests/utils/casts/to_bits.zok +++ b/zokrates_stdlib/tests/tests/utils/casts/to_bits.zok @@ -1,16 +1,19 @@ +import "utils/casts/u64_to_bits" import "utils/casts/u32_to_bits" import "utils/casts/u16_to_bits" import "utils/casts/u8_to_bits" -def main(u32[4] a, u16[4] b, u8[4] c) -> (bool[4][32], bool[4][16], bool[4][8]): - bool[4][32] d = [[false; 32]; 4] - bool[4][16] e = [[false; 16]; 4] - bool[4][8] f = [[false; 8]; 4] +def main(u64[4] a, u32[4] b, u16[4] c, u8[4] d) -> (bool[4][64], bool[4][32], bool[4][16], bool[4][8]): + bool[4][64] e = [[false; 64]; 4] + bool[4][32] f = [[false; 32]; 4] + bool[4][16] g = [[false; 16]; 4] + bool[4][8] h = [[false; 8]; 4] - for field i in 0..4 do - d[i] = u32_to_bits(a[i]) - e[i] = u16_to_bits(b[i]) - f[i] = u8_to_bits(c[i]) - endfor + for u32 i in 0..4 do + e[i] = u64_to_bits(a[i]) + f[i] = u32_to_bits(b[i]) + g[i] = u16_to_bits(c[i]) + h[i] = u8_to_bits(d[i]) + endfor - return d, e, f \ No newline at end of file + return e, f, g, h \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/utils/casts/to_field.json b/zokrates_stdlib/tests/tests/utils/casts/to_field.json index 849c543d1..bde8f288d 100644 --- a/zokrates_stdlib/tests/tests/utils/casts/to_field.json +++ b/zokrates_stdlib/tests/tests/utils/casts/to_field.json @@ -1,16 +1,16 @@ { - "entry_point": "./tests/tests/utils/casts/to_field.zok", - "curves": ["Bn128"], - "tests": [ - { - "input": { - "values": ["0", "1", "4294967295", "42", "0", "1", "65535", "42", "0", "1", "255", "42"] - }, - "output": { - "Ok": { - "values": ["0", "1", "4294967295", "42", "0", "1", "65535", "42", "0", "1", "255", "42"] - } - } - } - ] + "entry_point": "./tests/tests/utils/casts/to_field.zok", + "curves": ["Bn128"], + "tests": [ + { + "input": { + "values": ["0", "1", "18446744073709551615", "42", "0", "1", "4294967295", "42", "0", "1", "65535", "42", "0", "1", "255", "42"] + }, + "output": { + "Ok": { + "values": ["0", "1", "18446744073709551615", "42", "0", "1", "4294967295", "42", "0", "1", "65535", "42", "0", "1", "255", "42"] + } + } + } + ] } \ No newline at end of file diff --git a/zokrates_stdlib/tests/tests/utils/casts/to_field.zok b/zokrates_stdlib/tests/tests/utils/casts/to_field.zok index 24851681e..3c3fe61f5 100644 --- a/zokrates_stdlib/tests/tests/utils/casts/to_field.zok +++ b/zokrates_stdlib/tests/tests/utils/casts/to_field.zok @@ -1,19 +1,19 @@ +import "utils/casts/u64_to_field" import "utils/casts/u32_to_field" import "utils/casts/u16_to_field" import "utils/casts/u8_to_field" -def main(u32[4] a, u16[4] b, u8[4] c) -> (field[4], field[4], field[4]): - field[4] d = [0; 4] - field[4] e = [0; 4] - field[4] f = [0; 4] +def main(u64[4] a, u32[4] b, u16[4] c, u8[4] d) -> (field[4], field[4], field[4], field[4]): + field[4] e = [0; 4] + field[4] f = [0; 4] + field[4] g = [0; 4] + field[4] h = [0; 4] - for field i in 0..4 do - field g = u32_to_field(a[i]) - d[i] = g - field h = u16_to_field(b[i]) - e[i] = h - field j = u8_to_field(c[i]) - f[i] = j - endfor + for u32 i in 0..4 do + e[i] = u64_to_field(a[i]) + f[i] = u32_to_field(b[i]) + g[i] = u16_to_field(c[i]) + h[i] = u8_to_field(d[i]) + endfor - return d, e, f \ No newline at end of file + return e, f, g, h \ No newline at end of file diff --git a/zokrates_test/Cargo.toml b/zokrates_test/Cargo.toml index ef9ea39aa..f14507e2f 100644 --- a/zokrates_test/Cargo.toml +++ b/zokrates_test/Cargo.toml @@ -5,8 +5,8 @@ authors = ["schaeff "] edition = "2018" [dependencies] -zokrates_field = { version = "0.3", path = "../zokrates_field" } -zokrates_core = { version = "0.5", path = "../zokrates_core" } +zokrates_field = { version = "0.4", path = "../zokrates_field" } +zokrates_core = { version = "0.6", path = "../zokrates_core" } zokrates_fs_resolver = { version = "0.5", path = "../zokrates_fs_resolver" } serde = "1.0" serde_derive = "1.0" diff --git a/zokrates_test/src/lib.rs b/zokrates_test/src/lib.rs index 47ae16445..7c48ebf47 100644 --- a/zokrates_test/src/lib.rs +++ b/zokrates_test/src/lib.rs @@ -2,9 +2,13 @@ extern crate serde_derive; use std::fs::File; +use std::io::{BufReader, Read}; use std::path::{Path, PathBuf}; + +use zokrates_core::compile::{compile, CompileConfig}; use zokrates_core::ir; use zokrates_field::{Bls12_377Field, Bls12_381Field, Bn128Field, Bw6_761Field, Field}; +use zokrates_fs_resolver::FileSystemResolver; #[derive(Serialize, Deserialize, Clone)] enum Curve { @@ -16,7 +20,7 @@ enum Curve { #[derive(Serialize, Deserialize, Clone)] struct Tests { - pub entry_point: PathBuf, + pub entry_point: Option, pub curves: Option>, pub max_constraint_count: Option, pub tests: Vec, @@ -46,15 +50,8 @@ struct Output { type Val = String; fn parse_val(s: String) -> T { - let s = if s.starts_with("0x") { - u32::from_str_radix(s.trim_start_matches("0x"), 16) - .unwrap() - .to_string() - } else { - s - }; - - T::try_from_dec_str(&s).unwrap() + let radix = if s.starts_with("0x") { 16 } else { 10 }; + T::try_from_str(s.trim_start_matches("0x"), radix).unwrap() } impl From> for ComparableResult { @@ -85,15 +82,19 @@ fn compare(result: ir::ExecutionResult, expected: TestResult) -> Re Ok(()) } -use std::io::{BufReader, Read}; -use zokrates_core::compile::{compile, CompileConfig}; -use zokrates_fs_resolver::FileSystemResolver; - pub fn test_inner(test_path: &str) { let t: Tests = serde_json::from_reader(BufReader::new(File::open(Path::new(test_path)).unwrap())).unwrap(); - let curves = t.curves.clone().unwrap_or(vec![Curve::Bn128]); + let curves = t.curves.clone().unwrap_or_else(|| vec![Curve::Bn128]); + + let t = Tests { + entry_point: Some( + t.entry_point + .unwrap_or_else(|| PathBuf::from(String::from(test_path)).with_extension("zok")), + ), + ..t + }; // this function typically runs in a spawn thread whose stack size is small, leading to stack overflows // to avoid that, run the stack-heavy bit in a thread with a larger stack (8M) @@ -116,13 +117,16 @@ pub fn test_inner(test_path: &str) { } fn compile_and_run(t: Tests) { - let code = std::fs::read_to_string(&t.entry_point).unwrap(); + let entry_point = t.entry_point.unwrap(); + + let code = std::fs::read_to_string(&entry_point).unwrap(); let stdlib = std::fs::canonicalize("../zokrates_stdlib/stdlib").unwrap(); let resolver = FileSystemResolver::with_stdlib_root(stdlib.to_str().unwrap()); + let artifacts = compile::( code, - t.entry_point.clone(), + entry_point.clone(), Some(&resolver), &CompileConfig::default(), ) @@ -130,17 +134,14 @@ fn compile_and_run(t: Tests) { let bin = artifacts.prog(); - match t.max_constraint_count { - Some(target_count) => { - let count = bin.constraint_count(); + if let Some(target_count) = t.max_constraint_count { + let count = bin.constraint_count(); - println!( - "{} at {}% of max", - t.entry_point.display(), - (count as f32) / (target_count as f32) * 100_f32 - ); - } - _ => {} + println!( + "{} at {}% of max", + entry_point.display(), + (count as f32) / (target_count as f32) * 100_f32 + ); }; let interpreter = zokrates_core::ir::Interpreter::default(); @@ -148,25 +149,25 @@ fn compile_and_run(t: Tests) { for test in t.tests.into_iter() { let input = &test.input.values; - let output = interpreter.execute(bin, &(input.iter().cloned().map(parse_val).collect())); - - match compare(output, test.output) { - Err(e) => { - let mut code = File::open(&t.entry_point).unwrap(); - let mut s = String::new(); - code.read_to_string(&mut s).unwrap(); - let context = format!( - "\n{}\nCalled with input ({})\n", - s, - input - .iter() - .map(|i| format!("{}", i)) - .collect::>() - .join(", ") - ); - panic!("{}{}", context, e) - } - Ok(..) => {} - }; + let output = interpreter.execute( + bin, + &(input.iter().cloned().map(parse_val).collect::>()), + ); + + if let Err(e) = compare(output, test.output) { + let mut code = File::open(&entry_point).unwrap(); + let mut s = String::new(); + code.read_to_string(&mut s).unwrap(); + let context = format!( + "\n{}\nCalled with input ({})\n", + s, + input + .iter() + .map(|i| i.to_string()) + .collect::>() + .join(", ") + ); + panic!("{}{}", context, e) + } } }