diff --git a/.github/actions/docs/build-status/script.sh b/.github/actions/docs/build-status/script.sh index a8d31ff4f4b..0b282557cf2 100755 --- a/.github/actions/docs/build-status/script.sh +++ b/.github/actions/docs/build-status/script.sh @@ -18,11 +18,11 @@ while [[ "$DEPLOY_STATUS" != "ready" && $COUNT -lt $MAX_RETRIES ]]; do exit 0 elif [[ "$DEPLOY_STATUS" == "error" ]]; then echo "deploy_status=failure" >> $GITHUB_OUTPUT - exit 0 + exit 1 fi echo "Deploy still running. Retrying..." done echo "deploy_status=failure" >> $GITHUB_OUTPUT -exit 0 +exit 1 diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index a387f6f49f9..23ae0e409e9 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -8,17 +8,57 @@ on: - opened - synchronize - labeled - push: - paths: - - 'docs/**' jobs: - - build_and_deploy: + add_label: + runs-on: ubuntu-latest + outputs: + has_label: ${{ steps.check-labels.outputs.result }} + steps: + - name: Check if label is present + id: check-labels + uses: actions/github-script@v3 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const labels = context.payload.pull_request.labels.map(label => label.name); + if (labels.includes('documentation')) { + return true; + } + + // Fetch the list of files changed in the PR + const { data: files } = await github.pulls.listFiles({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number + }); + + // Check if any file is within the 'docs' folder + const docsChanged = files.some(file => file.filename.startsWith('docs/')); + return docsChanged; + + - name: Add label if not present + if: steps.check-labels.outputs.result == 'true' + uses: actions/github-script@v3 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const labels = context.payload.pull_request.labels.map(label => label.name); + if (!labels.includes('documentation')) { + github.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + labels: ['documentation'] + }) + } + + deploy_docs: runs-on: ubuntu-latest permissions: pull-requests: write - if: contains(github.event.pull_request.labels.*.name, 'documentation') + needs: add_label + if: needs.add_label.outputs.has_label == 'true' steps: - name: Checkout code uses: actions/checkout@v2 @@ -60,9 +100,11 @@ jobs: site-id: ${{ secrets.NETLIFY_SITE_ID }} continue-on-error: true + - name: Debugging - print deploy_status run: echo "${{ steps.check_deploy_status.outputs.deploy_status }}" + - name: Change PR Comment for Successful Deployment if: steps.check_deploy_status.outputs.deploy_status == 'success' uses: mshick/add-pr-comment@v2 @@ -94,3 +136,7 @@ jobs: Deployment didn't succeed. Please check logs below and resolve the issue 🧐 [![Netlify Status](https://api.netlify.com/api/v1/badges/${{ secrets.NETLIFY_SITE_ID }}/deploy-status?branch=${{ github.head_ref || github.ref }})](https://app.netlify.com/sites/noir-docs-v2/deploys) + + - name: Fail the workflow if deployment failed + if: steps.check_deploy_status.outputs.deploy_status == 'failure' + run: exit 1 diff --git a/.github/workflows/gates_report.yml b/.github/workflows/gates_report.yml new file mode 100644 index 00000000000..e2d6bdd56b7 --- /dev/null +++ b/.github/workflows/gates_report.yml @@ -0,0 +1,90 @@ +name: Report gates diff + +on: + push: + branches: + - master + pull_request: + +jobs: + build-nargo: + runs-on: ubuntu-latest + strategy: + matrix: + target: [x86_64-unknown-linux-gnu] + + steps: + - name: Checkout Noir repo + uses: actions/checkout@v4 + + - name: Setup toolchain + uses: dtolnay/rust-toolchain@1.66.0 + + - uses: Swatinem/rust-cache@v2 + with: + key: ${{ matrix.target }} + cache-on-failure: true + save-if: ${{ github.event_name != 'merge_group' }} + + - name: Build Nargo + run: cargo build --package nargo_cli --release + + - name: Package artifacts + run: | + mkdir dist + cp ./target/release/nargo ./dist/nargo + 7z a -ttar -so -an ./dist/* | 7z a -si ./nargo-x86_64-unknown-linux-gnu.tar.gz + + - name: Upload artifact + uses: actions/upload-artifact@v3 + with: + name: nargo + path: ./dist/* + retention-days: 3 + + + compare_gas_reports: + needs: [build-nargo] + runs-on: ubuntu-latest + permissions: + pull-requests: write + + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Download nargo binary + uses: actions/download-artifact@v3 + with: + name: nargo + path: ./nargo + + - name: Set nargo on PATH + run: | + nargo_binary="${{ github.workspace }}/nargo/nargo" + chmod +x $nargo_binary + echo "$(dirname $nargo_binary)" >> $GITHUB_PATH + export PATH="$PATH:$(dirname $nargo_binary)" + nargo -V + + - name: Generate gates report + working-directory: ./tooling/nargo_cli/tests + run: | + ./gates_report.sh + mv gates_report.json ../../../gates_report.json + + - name: Compare gates reports + id: gates_diff + uses: TomAFrench/noir-gates-diff@e7cf131b7e7f044c01615f93f0b855f65ddc02d4 + with: + report: gates_report.json + summaryQuantile: 0.9 # only display the 10% most significant circuit size diffs in the summary (defaults to 20%) + + - name: Add gates diff to sticky comment + if: github.event_name == 'pull_request' || github.event_name == 'pull_request_target' + uses: marocchino/sticky-pull-request-comment@v2 + with: + # delete the comment in case changes no longer impact circuit sizes + delete: ${{ !steps.gates_diff.outputs.markdown }} + message: ${{ steps.gates_diff.outputs.markdown }} diff --git a/.github/workflows/test-acvm-js.yml b/.github/workflows/test-acvm-js.yml index 8a469f6ff1e..c69f4995198 100644 --- a/.github/workflows/test-acvm-js.yml +++ b/.github/workflows/test-acvm-js.yml @@ -1,6 +1,11 @@ name: Test acvm_js -on: [push, pull_request] +on: + pull_request: + merge_group: + push: + branches: + - master # This will cancel previous runs when a branch or PR is updated concurrency: diff --git a/.github/workflows/test-noir_wasm.yml b/.github/workflows/test-noir_wasm.yml index 720e76c2abe..6bc8b70a1f4 100644 --- a/.github/workflows/test-noir_wasm.yml +++ b/.github/workflows/test-noir_wasm.yml @@ -101,12 +101,16 @@ jobs: name: nargo path: ./nargo - - name: Compile test program with Nargo CLI - working-directory: ./compiler/wasm/noir-script + - name: Compile fixtures with Nargo CLI + working-directory: ./compiler/wasm/fixtures run: | nargo_binary=${{ github.workspace }}/nargo/nargo chmod +x $nargo_binary - $nargo_binary compile + for dir in $(ls -d */); do + pushd $dir/noir-script + $nargo_binary compile + popd + done - name: Install Yarn dependencies uses: ./.github/actions/setup diff --git a/.gitignore b/.gitignore index 94e8f1a8db0..169353af2b6 100644 --- a/.gitignore +++ b/.gitignore @@ -40,6 +40,9 @@ result !tooling/nargo_cli/tests/acir_artifacts/*/target !tooling/nargo_cli/tests/acir_artifacts/*/target/witness.gz !compiler/wasm/noir-script/target + +gates_report.json + # Github Actions scratch space # This gives a location to download artifacts into the repository in CI without making git dirty. libbarretenberg-wasm32 diff --git a/.release-please-manifest.json b/.release-please-manifest.json index d085bb9234a..3a52db26d13 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,4 +1,4 @@ { - ".": "0.16.0", - "acvm-repo": "0.28.0" + ".": "0.18.0", + "acvm-repo": "0.30.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index a56f9490edb..68cd1decb44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,117 @@ # Changelog +## [0.18.0](https://github.com/noir-lang/noir/compare/v0.17.0...v0.18.0) (2023-10-25) + + +### ⚠ BREAKING CHANGES + +* expose pedersen hash in acir and bb solver ([#3269](https://github.com/noir-lang/noir/issues/3269)) +* Switch to new pedersen implementation ([#3151](https://github.com/noir-lang/noir/issues/3151)) + +### Features + +* Add crate for pub modifier ([#3271](https://github.com/noir-lang/noir/issues/3271)) ([e7a1a1a](https://github.com/noir-lang/noir/commit/e7a1a1a4b42b6b72c16f2204e33af80dbabba6b5)) +* Cache debug artifacts ([#3133](https://github.com/noir-lang/noir/issues/3133)) ([c5a6229](https://github.com/noir-lang/noir/commit/c5a622983e4049d82589f185be5e96c63ed6066d)) +* **debugger:** Print limited source code context ([#3217](https://github.com/noir-lang/noir/issues/3217)) ([dcda1c7](https://github.com/noir-lang/noir/commit/dcda1c7aed69ae8f55cd3f680e3cc1ece9de7541)) +* Expose pedersen hash in acir and bb solver ([#3269](https://github.com/noir-lang/noir/issues/3269)) ([0108b6c](https://github.com/noir-lang/noir/commit/0108b6c1e8dc0dfc766ab3c4944deae9354dec36)) +* Implement `bound_constraint_with_offset` in terms of `AcirVar`s ([#3233](https://github.com/noir-lang/noir/issues/3233)) ([8d89cb5](https://github.com/noir-lang/noir/commit/8d89cb59fe710859a96eaed4f988952bd727fb7d)) +* Implement euclidean division and signed division in terms of `AcirVar`s ([#3230](https://github.com/noir-lang/noir/issues/3230)) ([b8b7782](https://github.com/noir-lang/noir/commit/b8b77825410c0e1f95549259a51e2c40de1ec342)) +* Noir-wasm takes dependency graph ([#3213](https://github.com/noir-lang/noir/issues/3213)) ([a2c8ebd](https://github.com/noir-lang/noir/commit/a2c8ebd4a800d7ef042ac9cbe5ee6a837c715634)) +* Replace boolean range constraints with arithmetic opcodes ([#3234](https://github.com/noir-lang/noir/issues/3234)) ([949222c](https://github.com/noir-lang/noir/commit/949222c20d9e65152e3814d02da1c4c41ffc23a5)) +* **stdlib:** Optimize constraint counts in sha256/sha512 ([#3253](https://github.com/noir-lang/noir/issues/3253)) ([d3be552](https://github.com/noir-lang/noir/commit/d3be552149ab375b24b509603fcd7237b374ca5a)) +* Switch to new pedersen implementation ([#3151](https://github.com/noir-lang/noir/issues/3151)) ([35fb3f7](https://github.com/noir-lang/noir/commit/35fb3f7076d52db7ca3bef0a70a3dbccaf82f58d)) + + +### Bug Fixes + +* Add size checks to integer literals ([#3236](https://github.com/noir-lang/noir/issues/3236)) ([7f8fe8c](https://github.com/noir-lang/noir/commit/7f8fe8c88eb2d26ae3a93e2f74430fadc74b4836)) +* Fix lexer error formatting ([#3274](https://github.com/noir-lang/noir/issues/3274)) ([74bd517](https://github.com/noir-lang/noir/commit/74bd517fe7839465ff086ffe622462bed5159006)) +* Impl methods are no longer placed in contracts ([#3255](https://github.com/noir-lang/noir/issues/3255)) ([b673b07](https://github.com/noir-lang/noir/commit/b673b071663d9756d6346954fce7d4ec6e1577dd)) +* Recompile artefacts from a different noir version ([#3248](https://github.com/noir-lang/noir/issues/3248)) ([7347b27](https://github.com/noir-lang/noir/commit/7347b2742a5ad38d3d252e657810d061bab83e24)) +* Show println output before an error occurs in `nargo execute` ([#3211](https://github.com/noir-lang/noir/issues/3211)) ([2f0b80d](https://github.com/noir-lang/noir/commit/2f0b80dda8401ce8962c857dbcd9548e7fdde4aa)) + +## [0.17.0](https://github.com/noir-lang/noir/compare/v0.16.0...v0.17.0) (2023-10-20) + + +### ⚠ BREAKING CHANGES + +* Pass ACIR to ACVM by reference rather than passing ownership ([#2872](https://github.com/noir-lang/noir/issues/2872)) +* Make for loops a statement ([#2975](https://github.com/noir-lang/noir/issues/2975)) +* **traits:** trait functions with a default implementation must not be followed by a semicolon ([#2987](https://github.com/noir-lang/noir/issues/2987)) +* **wasm:** improve and simplify wasm compiler interface ([#2976](https://github.com/noir-lang/noir/issues/2976)) +* **wasm:** update wasm artifacts to match cli artifacts ([#2973](https://github.com/noir-lang/noir/issues/2973)) + +### Features + +* **acir:** Set dynamic array values ([#3054](https://github.com/noir-lang/noir/issues/3054)) ([e871866](https://github.com/noir-lang/noir/commit/e871866d2203f0f0f49f3b273d99d385b950b65f)) +* **acvm:** Separate ACVM optimizations and transformations ([#2979](https://github.com/noir-lang/noir/issues/2979)) ([5865d1a](https://github.com/noir-lang/noir/commit/5865d1a1bca16e1853663c71f893ff81fa3f7185)) +* Add `destroy` method to `Noir` ([#3105](https://github.com/noir-lang/noir/issues/3105)) ([7e40274](https://github.com/noir-lang/noir/commit/7e402744a7d64ffcac6db026cec1631230204f0f)) +* Add `execute` method to `Noir` class ([#3081](https://github.com/noir-lang/noir/issues/3081)) ([17bdd7e](https://github.com/noir-lang/noir/commit/17bdd7e3909f0ddd195e5cb7095cd0d30758ed43)) +* Add ACIR serializer C++ codegen ([#2961](https://github.com/noir-lang/noir/issues/2961)) ([7556982](https://github.com/noir-lang/noir/commit/7556982dbebe25eaa17240abbe270b771b55de45)) +* Add an options object to `BarretenbergBackend` constructor ([#3105](https://github.com/noir-lang/noir/issues/3105)) ([7e40274](https://github.com/noir-lang/noir/commit/7e402744a7d64ffcac6db026cec1631230204f0f)) +* Add aztec selectors for event structs ([#2983](https://github.com/noir-lang/noir/issues/2983)) ([982380e](https://github.com/noir-lang/noir/commit/982380e54bb4d696688522c540f1234734ae2e80)) +* Add conditional compilation of methods based on the underlying field being used ([#3045](https://github.com/noir-lang/noir/issues/3045)) ([2e008e2](https://github.com/noir-lang/noir/commit/2e008e2438795bbc41b0641e830378b76bf2e194)) +* Add experimental REPL-based debugger ([#2995](https://github.com/noir-lang/noir/issues/2995)) ([281c696](https://github.com/noir-lang/noir/commit/281c696da61c64b42b9525b8756ffc195f70d775)) +* Add JS types for ABI and input maps ([#3023](https://github.com/noir-lang/noir/issues/3023)) ([599e7a1](https://github.com/noir-lang/noir/commit/599e7a1d6bae5d93273e9ef1265024eac909660d)) +* **debugger:** Highlight current src code loc ([#3174](https://github.com/noir-lang/noir/issues/3174)) ([6b87582](https://github.com/noir-lang/noir/commit/6b87582dfe872ad6c248cf9995d76b0ef1580625)) +* Format infix expressions ([#3001](https://github.com/noir-lang/noir/issues/3001)) ([7926ada](https://github.com/noir-lang/noir/commit/7926ada88ed08ac9d874604834533d900fbb16b0)) +* **formatter:** Add formatter support for array literals ([#3061](https://github.com/noir-lang/noir/issues/3061)) ([a535321](https://github.com/noir-lang/noir/commit/a5353217a1f49b83daf11d5fa55e0bcccebf0271)) +* Implement automatic dereferencing for index expressions ([#3082](https://github.com/noir-lang/noir/issues/3082)) ([8221bfd](https://github.com/noir-lang/noir/commit/8221bfd2ffde7d1dbf71a72d95257acf76ecca74)) +* Implement automatic dereferencing for indexing lvalues ([#3083](https://github.com/noir-lang/noir/issues/3083)) ([6e2b70a](https://github.com/noir-lang/noir/commit/6e2b70ae90b686158957ea29ef1b2a5f0ed38e5f)) +* Implement impl specialization ([#3087](https://github.com/noir-lang/noir/issues/3087)) ([44716fa](https://github.com/noir-lang/noir/commit/44716fae0bae0f78ceee76f7231af49c4abeace1)) +* **lsp:** Add "info" codelens ([#2982](https://github.com/noir-lang/noir/issues/2982)) ([80770d9](https://github.com/noir-lang/noir/commit/80770d9fae7c42e69a62cf01babfc69449600ac5)) +* Nargo test runtime callstacks and assert messages without string matching ([#2953](https://github.com/noir-lang/noir/issues/2953)) ([1b6a4e6](https://github.com/noir-lang/noir/commit/1b6a4e6021929c23a1bca5dff02c004422cc71f8)) +* Old docs issues ([#3195](https://github.com/noir-lang/noir/issues/3195)) ([26746c5](https://github.com/noir-lang/noir/commit/26746c59e12a60f3869a5b885b05926c94f01215)) +* Optimize euclidean division acir-gen ([#3121](https://github.com/noir-lang/noir/issues/3121)) ([2c175c0](https://github.com/noir-lang/noir/commit/2c175c0d886eea390ef97ada1c2a5b0e1bef15e8)) +* Pass ACIR to ACVM by reference rather than passing ownership ([#2872](https://github.com/noir-lang/noir/issues/2872)) ([b3a9c34](https://github.com/noir-lang/noir/commit/b3a9c343993ce3207de62106bda6cb2b2ef3de50)) +* Pass brillig bytecode to VM by reference ([#3030](https://github.com/noir-lang/noir/issues/3030)) ([4ee290b](https://github.com/noir-lang/noir/commit/4ee290b8b6f75bc1974a5750248570eeca8d244e)) +* Prevent unnecessary witness creation in euclidean division ([#2980](https://github.com/noir-lang/noir/issues/2980)) ([c6f660e](https://github.com/noir-lang/noir/commit/c6f660e86d40a106930483f1d6161814e3c0de10)) +* Provide formatting subcommand ([#2640](https://github.com/noir-lang/noir/issues/2640)) ([a38b15f](https://github.com/noir-lang/noir/commit/a38b15f5d8e69faff125d363f2fd1f2f90ae6830)) +* Publish aztec build of noir_wasm ([#3049](https://github.com/noir-lang/noir/issues/3049)) ([3b51f4d](https://github.com/noir-lang/noir/commit/3b51f4df7e808233f6987baec93f4b5de7e5b304)) +* Remove unnecessary truncation of boolean multiplication ([#3122](https://github.com/noir-lang/noir/issues/3122)) ([39dbcf1](https://github.com/noir-lang/noir/commit/39dbcf1ab80d2bb472d08db4de15d4e0c1f2eb52)) +* Return compilation errors from noir_wasm ([#3091](https://github.com/noir-lang/noir/issues/3091)) ([55f63c9](https://github.com/noir-lang/noir/commit/55f63c935cec62fbba63eed421812a4372c1aa4d)) +* Reuse witnesses which have been assigned constant values during ACIR gen ([#3137](https://github.com/noir-lang/noir/issues/3137)) ([9eb43e2](https://github.com/noir-lang/noir/commit/9eb43e2a4665397295e74a593f73d19fa9fa5d27)) +* Save Brillig execution state in ACVM ([#3026](https://github.com/noir-lang/noir/issues/3026)) ([88682da](https://github.com/noir-lang/noir/commit/88682da87ffc9e26da5c9e4b5a4d8e62a6ee43c6)) +* Solve `fixed_base_scalar_mul` black box functions in rust ([#3153](https://github.com/noir-lang/noir/issues/3153)) ([1c1afbc](https://github.com/noir-lang/noir/commit/1c1afbcddf0b5fdb39f00ad28ae90caf699d1265)) +* **traits:** Add impl Trait as function return type [#2397](https://github.com/noir-lang/noir/issues/2397) ([#3176](https://github.com/noir-lang/noir/issues/3176)) ([4cb2024](https://github.com/noir-lang/noir/commit/4cb20244abba0abc49be0376611979a786563565)) +* **traits:** Add trait impl for buildin types ([#2964](https://github.com/noir-lang/noir/issues/2964)) ([2c87b27](https://github.com/noir-lang/noir/commit/2c87b273dfdf033dd8c79b78f006a0e9813559d7)) +* **traits:** Added checks for duplicated trait associated items (types, consts, functions) ([#2927](https://github.com/noir-lang/noir/issues/2927)) ([d49492c](https://github.com/noir-lang/noir/commit/d49492cd80d04ee6acc01247b06b088deefcd0c6)) +* **traits:** Allow multiple traits to share the same associated function name and to be implemented for the same type ([#3126](https://github.com/noir-lang/noir/issues/3126)) ([004f8dd](https://github.com/noir-lang/noir/commit/004f8dd733cb23da4ed57b160f6b86d53bc0b5f1)) +* **traits:** Improve support for traits static method resolution ([#2958](https://github.com/noir-lang/noir/issues/2958)) ([0d0d8f7](https://github.com/noir-lang/noir/commit/0d0d8f7d2b401eb6b534dbb175dfd4b26d2a5f7d)) +* **wasm:** Improve and simplify wasm compiler interface ([#2976](https://github.com/noir-lang/noir/issues/2976)) ([1b5124b](https://github.com/noir-lang/noir/commit/1b5124bc74f7ac5360db04b34d1b7b2284061fd3)) +* **wasm:** Update wasm artifacts to match cli artifacts ([#2973](https://github.com/noir-lang/noir/issues/2973)) ([ce16c0b](https://github.com/noir-lang/noir/commit/ce16c0b14565cfe1bc2c9f09ae71643d2657440b)) + + +### Bug Fixes + +* ACIR optimizer should update assertion messages ([#3010](https://github.com/noir-lang/noir/issues/3010)) ([758b6b6](https://github.com/noir-lang/noir/commit/758b6b62918907c1a39f3090a77419003551745e)) +* Add `pub` modifier to grumpkin functions ([#3036](https://github.com/noir-lang/noir/issues/3036)) ([f8990d7](https://github.com/noir-lang/noir/commit/f8990d75b948ce0a6968db659370f7ece7f5db08)) +* Add compiler error message for invalid input types ([#3220](https://github.com/noir-lang/noir/issues/3220)) ([989e80d](https://github.com/noir-lang/noir/commit/989e80d4ea62e68cfab69a1cd16d481cbccc6c02)) +* Allow constructors in parentheses in `if` conditions and `for` ranges ([#3219](https://github.com/noir-lang/noir/issues/3219)) ([ad192d1](https://github.com/noir-lang/noir/commit/ad192d1b7492f6ecd5fc98bb88201d6c442dc052)) +* Allow two `TypeVariable::Constant(N)` to unify even if their constants are not equal ([#3225](https://github.com/noir-lang/noir/issues/3225)) ([cc4ca4b](https://github.com/noir-lang/noir/commit/cc4ca4bb5f4fed5f531a2040501fcc6ed53a9ab4)) +* Change non-constant argument errors from `to_be_radix` from ICE to proper error ([#3048](https://github.com/noir-lang/noir/issues/3048)) ([19ce286](https://github.com/noir-lang/noir/commit/19ce28638fe3ea42ab4984cb99e3898cd17fa8d9)) +* Check for overflow with hexadecimal inputs ([#3004](https://github.com/noir-lang/noir/issues/3004)) ([db1e736](https://github.com/noir-lang/noir/commit/db1e736240c0b74f6f59504db5a50de1c749d395)) +* Complete debug metadata ([#3228](https://github.com/noir-lang/noir/issues/3228)) ([2f6509d](https://github.com/noir-lang/noir/commit/2f6509d2acdee5014d65efaca9e6a9e0df3ca160)) +* Determinism of fallback transformer ([#3100](https://github.com/noir-lang/noir/issues/3100)) ([12daad1](https://github.com/noir-lang/noir/commit/12daad19c902caf5ee9e2eb4b6847bde5a924353)) +* Disable modulo for fields ([#3009](https://github.com/noir-lang/noir/issues/3009)) ([7e68976](https://github.com/noir-lang/noir/commit/7e689768f4af1188e01a1a300a0d2fa152cea504)) +* Disallow returning constant values ([#2978](https://github.com/noir-lang/noir/issues/2978)) ([79c2e88](https://github.com/noir-lang/noir/commit/79c2e88ebefe71ebc0fe457347570df31b24ac36)) +* Do not perform dead instruction elimination on mod,div unless rhs is constant ([#3141](https://github.com/noir-lang/noir/issues/3141)) ([af3d771](https://github.com/noir-lang/noir/commit/af3d77182054845303fa59de92d783453079a048)) +* **docs:** Update `editUrl` path for docusaurus ([#3184](https://github.com/noir-lang/noir/issues/3184)) ([4646a93](https://github.com/noir-lang/noir/commit/4646a93f5e95604b5710353764b2c4295efaef6b)) +* Download expected `bb` version if installed backend has version mismatch ([#3150](https://github.com/noir-lang/noir/issues/3150)) ([3f03435](https://github.com/noir-lang/noir/commit/3f03435552fe75b5c7a49bfc8d63d06573381220)) +* Fix aztec library after nargo fmt ([#3014](https://github.com/noir-lang/noir/issues/3014)) ([f43083c](https://github.com/noir-lang/noir/commit/f43083c744ff13aefa4d294a090c9445a9b70aac)) +* Fix method `program_counter`, change method signature ([#3012](https://github.com/noir-lang/noir/issues/3012)) ([5ea522b](https://github.com/noir-lang/noir/commit/5ea522b840ca0f6f90d02ca00f0de32f515d450f)) +* Fix panic when using repeated arrays which define variables ([#3221](https://github.com/noir-lang/noir/issues/3221)) ([c4faf3a](https://github.com/noir-lang/noir/commit/c4faf3a0a40eea1ee02e11dfe08b48c6b4438bbf)) +* Include .nr and .sol files in builds ([#3039](https://github.com/noir-lang/noir/issues/3039)) ([ae8d0e9](https://github.com/noir-lang/noir/commit/ae8d0e9013f26b52e8f0bdc9f84866ffec50872d)) +* Make for loops a statement ([#2975](https://github.com/noir-lang/noir/issues/2975)) ([0e266eb](https://github.com/noir-lang/noir/commit/0e266ebc7328866b0b10554e37c9d9012a7b501c)) +* Minor problems with `aztec` publishing ([#3095](https://github.com/noir-lang/noir/issues/3095)) ([0fc8f20](https://github.com/noir-lang/noir/commit/0fc8f20b8b87d033d27ce18db039399c17f81837)) +* Parse parenthesized lvalues ([#3058](https://github.com/noir-lang/noir/issues/3058)) ([50ca58c](https://github.com/noir-lang/noir/commit/50ca58c7b133f8b21091dfd304379429284b0d60)) +* Prevent duplicated assert message transformation ([#3038](https://github.com/noir-lang/noir/issues/3038)) ([082a6d0](https://github.com/noir-lang/noir/commit/082a6d02dad67a25692bed15c340a16a848a320e)) +* Prevent mutating immutable bindings to mutable types ([#3075](https://github.com/noir-lang/noir/issues/3075)) ([d5ee20e](https://github.com/noir-lang/noir/commit/d5ee20ea43ccf1130f7d34231562f13e98ea636b)) +* Return error rather than panicking on unreadable circuits ([#3179](https://github.com/noir-lang/noir/issues/3179)) ([d4f61d3](https://github.com/noir-lang/noir/commit/d4f61d3d51d515e40a5fd02d35315889f841bf53)) +* **traits:** Trait functions with a default implementation must not be followed by a semicolon ([#2987](https://github.com/noir-lang/noir/issues/2987)) ([a3593c0](https://github.com/noir-lang/noir/commit/a3593c042163d89bd012b7f901f3b18446209e82)) +* Transform hir before type checks ([#2994](https://github.com/noir-lang/noir/issues/2994)) ([a29b568](https://github.com/noir-lang/noir/commit/a29b568295e40e19dd354bbe47e31f922e08d8c9)) +* Update link to recursion example ([#3224](https://github.com/noir-lang/noir/issues/3224)) ([10eae15](https://github.com/noir-lang/noir/commit/10eae15c6992442876e184c7d2bd36a34f639ea1)) + ## [0.16.0](https://github.com/noir-lang/noir/compare/v0.15.0...v0.16.0) (2023-10-03) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a9cddd50c55..bc2acd40829 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -58,11 +58,11 @@ Generally, we want to only use the three primary types defined by the specificat - `feat:` - This should be the most used type, as most work we are doing in the project are new features. Commits using this type will always show up in the Changelog. - `fix:` - When fixing a bug, we should use this type. Commits using this type will always show up in the Changelog. -- `chore:` - The least used type, these are **not** included in the Changelog unless they are breaking changes. But remain useful for an understandable commit history. +- `chore:` - The least used type, these are __not__ included in the Changelog unless they are breaking changes. But remain useful for an understandable commit history. ### Conventional Commits: Breaking Changes -Annotating **BREAKING CHANGES** is extremely important to our release process and versioning. To mark a commit as breaking, we add the `!` character after the type, but before the colon. For example: +Annotating __BREAKING CHANGES__ is extremely important to our release process and versioning. To mark a commit as breaking, we add the `!` character after the type, but before the colon. For example: ``` feat!: Rename nargo build to nargo check (#693) @@ -94,10 +94,14 @@ The easiest way to do this is to have multiple Conventional Commits while you wo ### Reviews -For any repository in the noir-lang organization, we require code review & approval by **one** Noir team member before the changes are merged, as enforced by GitHub branch protection. Non-breaking pull requests may be merged at any time. Breaking pull requests should only be merged when the team has general agreement of the changes and is preparing a breaking release. +For any repository in the noir-lang organization, we require code review & approval by __one__ Noir team member before the changes are merged, as enforced by GitHub branch protection. Non-breaking pull requests may be merged at any time. Breaking pull requests should only be merged when the team has general agreement of the changes and is preparing a breaking release. + +If your Pull Request involves changes in the docs folder, please add the `documentation` flag and request an approval by a DevRel team member[^1]. An approval from DevRel is not necessary to merge your PR. ### With Breaking Changes +Breaking changes need to be documented. Please ask for help from a DevRel[^1] team member if this is a problem for any reason. Breaking changes need a mandatory approval from DevRel. + Sometimes, we don't merge pull requests with breaking changes immediately upon approval. Since a breaking change will cause Noir to bump to the next "minor" version, we might want to land some fixes in "patch" releases before we begin working on that next breaking version. ## Merging @@ -156,6 +160,7 @@ Before merging, you should mentally review these questions: - Is continuous integration passing? - Do you have the required amount of approvals? - Does anyone else need to be pinged for thoughts? +- Does it have changes to the docs? If so, did you request an approval from a DevRel[^1] team member? - Will this cause problems for our release schedule? For example: maybe a patch release still needs to be published. - What details do we want to convey to users in the Changelog? @@ -167,11 +172,34 @@ Release Please parses Conventional Commit messages and opens (or updates) a pull When we are ready to release the version, we approve and squash the release pull request into `master`. Release Please will detect this merge and generate the appropriate tags for the release. Additional release steps may be triggered inside the GitHub Action to automate other parts of the release process. +### Documentation releases + +We aim to have every documentation version matching the versions of Noir. However, to avoid unnecessary build time and size to the existent documentation, they aren't currently released alongside the stable releases, and instead are released ad-hoc. + +Please contact any member of the DevRel[^1] team if you believe a new docs version should be cut. + +### Cutting a new version of the docs + +The Noir documentation is versioned according to the [Docusaurus documentation](https://docusaurus.io/docs/versioning). In the `versioned_docs` and `versioned_sidebar` folders you will find the docs and configs for the previous versions. If any change needs to be made to older versions, please do them in this folder. + +In the docs folder, you'll find the current, unreleased version, which we call `dev`. Any change in this folder will be reflected in the next release of the documentation. + +While the versioning is intended to be managed by the core maintainers, we feel it's important for external contributors to understand why and how is it maintained. To bump to a new version, run the following command, replacing with the intended version: + +```bash +npm run docusaurus docs:version +``` + +This should create a new version by copying the docs folder and the sidebars.js file to the relevant folders, as well as adding this version to versions.json. + +You can then open a Pull Request according to the the [PR section](#pull-requests) + ## Changelog Noir's Changelog is automatically managed by Release Please and informed by the Conventional Commits (as discussed above). Given the following commits: + - `feat(syntax): Implement String data type (#123)` - `chore(ci): Use correct rust version` - `fix(optimizer): Compile Boolean to u1` @@ -200,3 +228,5 @@ Release Please would generate add the following to the Changelog: * **optimizer:** Compile Boolean to u1 ``` + +[^1]: Currently, @critesjosh, @catmcgee and @signorecello. For Noir documentation, it is recommended to tag @signorecello diff --git a/Cargo.lock b/Cargo.lock index 0f5f7c9992b..45a198ba0ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,7 +4,7 @@ version = 3 [[package]] name = "acir" -version = "0.28.0" +version = "0.30.0" dependencies = [ "acir_field", "bincode", @@ -22,7 +22,7 @@ dependencies = [ [[package]] name = "acir_field" -version = "0.28.0" +version = "0.30.0" dependencies = [ "ark-bls12-381", "ark-bn254", @@ -36,7 +36,7 @@ dependencies = [ [[package]] name = "acvm" -version = "0.28.0" +version = "0.30.0" dependencies = [ "acir", "acvm_blackbox_solver", @@ -53,7 +53,7 @@ dependencies = [ [[package]] name = "acvm_blackbox_solver" -version = "0.28.0" +version = "0.30.0" dependencies = [ "acir", "blake2", @@ -66,7 +66,7 @@ dependencies = [ [[package]] name = "acvm_js" -version = "0.28.0" +version = "0.30.0" dependencies = [ "acvm", "barretenberg_blackbox_solver", @@ -87,7 +87,7 @@ dependencies = [ [[package]] name = "acvm_stdlib" -version = "0.28.0" +version = "0.30.0" dependencies = [ "acir", ] @@ -217,7 +217,7 @@ checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "arena" -version = "0.16.0" +version = "0.18.0" dependencies = [ "generational-arena", ] @@ -448,7 +448,7 @@ dependencies = [ [[package]] name = "barretenberg_blackbox_solver" -version = "0.28.0" +version = "0.30.0" dependencies = [ "acir", "acvm_blackbox_solver", @@ -572,7 +572,7 @@ dependencies = [ [[package]] name = "brillig" -version = "0.28.0" +version = "0.30.0" dependencies = [ "acir_field", "serde", @@ -580,7 +580,7 @@ dependencies = [ [[package]] name = "brillig_vm" -version = "0.28.0" +version = "0.30.0" dependencies = [ "acir", "acvm_blackbox_solver", @@ -1115,16 +1115,6 @@ dependencies = [ "itertools", ] -[[package]] -name = "crossbeam-channel" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - [[package]] name = "crossbeam-deque" version = "0.8.3" @@ -1610,7 +1600,7 @@ dependencies = [ [[package]] name = "fm" -version = "0.16.0" +version = "0.18.0" dependencies = [ "codespan-reporting", "iter-extended", @@ -2203,7 +2193,7 @@ dependencies = [ [[package]] name = "iter-extended" -version = "0.16.0" +version = "0.18.0" [[package]] name = "itertools" @@ -2422,7 +2412,7 @@ checksum = "7843ec2de400bcbc6a6328c958dc38e5359da6e93e72e37bc5246bf1ae776389" [[package]] name = "nargo" -version = "0.16.0" +version = "0.18.0" dependencies = [ "acvm", "base64", @@ -2442,7 +2432,7 @@ dependencies = [ [[package]] name = "nargo_cli" -version = "0.16.0" +version = "0.18.0" dependencies = [ "acvm", "assert_cmd", @@ -2490,7 +2480,7 @@ dependencies = [ [[package]] name = "nargo_fmt" -version = "0.16.0" +version = "0.18.0" dependencies = [ "bytecount", "noirc_frontend", @@ -2502,7 +2492,7 @@ dependencies = [ [[package]] name = "nargo_toml" -version = "0.16.0" +version = "0.18.0" dependencies = [ "dirs", "fm", @@ -2550,9 +2540,10 @@ dependencies = [ [[package]] name = "noir_debugger" -version = "0.16.0" +version = "0.18.0" dependencies = [ "acvm", + "codespan-reporting", "easy-repl", "nargo", "noirc_printable_type", @@ -2562,7 +2553,7 @@ dependencies = [ [[package]] name = "noir_lsp" -version = "0.16.0" +version = "0.18.0" dependencies = [ "acvm", "async-lsp", @@ -2595,7 +2586,7 @@ dependencies = [ [[package]] name = "noir_wasm" -version = "0.16.0" +version = "0.18.0" dependencies = [ "acvm", "build-data", @@ -2617,7 +2608,7 @@ dependencies = [ [[package]] name = "noirc_abi" -version = "0.16.0" +version = "0.18.0" dependencies = [ "acvm", "iter-extended", @@ -2634,7 +2625,7 @@ dependencies = [ [[package]] name = "noirc_abi_wasm" -version = "0.16.0" +version = "0.18.0" dependencies = [ "acvm", "build-data", @@ -2651,10 +2642,11 @@ dependencies = [ [[package]] name = "noirc_driver" -version = "0.16.0" +version = "0.18.0" dependencies = [ "acvm", "base64", + "build-data", "clap", "fm", "fxhash", @@ -2667,7 +2659,7 @@ dependencies = [ [[package]] name = "noirc_errors" -version = "0.16.0" +version = "0.18.0" dependencies = [ "acvm", "chumsky", @@ -2680,7 +2672,7 @@ dependencies = [ [[package]] name = "noirc_evaluator" -version = "0.16.0" +version = "0.18.0" dependencies = [ "acvm", "fxhash", @@ -2695,7 +2687,7 @@ dependencies = [ [[package]] name = "noirc_frontend" -version = "0.16.0" +version = "0.18.0" dependencies = [ "acvm", "arena", @@ -2706,6 +2698,7 @@ dependencies = [ "noirc_printable_type", "regex", "rustc-hash", + "serde", "serde_json", "small-ord-set", "smol_str", @@ -2716,7 +2709,7 @@ dependencies = [ [[package]] name = "noirc_printable_type" -version = "0.16.0" +version = "0.18.0" dependencies = [ "acvm", "iter-extended", @@ -3209,9 +3202,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" dependencies = [ "either", "rayon-core", @@ -3219,14 +3212,12 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" dependencies = [ - "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "num_cpus", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index cf0b8d8885b..1c0d7101ecc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,7 @@ resolver = "2" [workspace.package] # x-release-please-start-version -version = "0.16.0" +version = "0.18.0" # x-release-please-end authors = ["The Noir Team "] edition = "2021" @@ -78,7 +78,7 @@ chumsky = { git = "https://github.com/jfecher/chumsky", rev = "ad9d312", default dirs = "4" serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0" -smol_str = "0.1.17" +smol_str = { version = "0.1.17", features = ["serde"] } thiserror = "1.0.21" toml = "0.7.2" tower = "0.4" diff --git a/acvm-repo/CHANGELOG.md b/acvm-repo/CHANGELOG.md index 60bdba65a38..b187addf7b7 100644 --- a/acvm-repo/CHANGELOG.md +++ b/acvm-repo/CHANGELOG.md @@ -5,6 +5,78 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.30.0](https://github.com/noir-lang/noir/compare/v0.29.0...v0.30.0) (2023-10-25) + + +### ⚠ BREAKING CHANGES + +* expose pedersen hash in acir and bb solver ([#3269](https://github.com/noir-lang/noir/issues/3269)) +* Switch to new pedersen implementation ([#3151](https://github.com/noir-lang/noir/issues/3151)) +* Pass ACIR to ACVM by reference rather than passing ownership ([#2872](https://github.com/noir-lang/noir/issues/2872)) +* **wasm:** improve and simplify wasm compiler interface ([#2976](https://github.com/noir-lang/noir/issues/2976)) +* Maintain shape of foreign call arguments ([#2935](https://github.com/noir-lang/noir/issues/2935)) + +### Features + +* **acvm_js:** Export black box solver functions ([#2812](https://github.com/noir-lang/noir/issues/2812)) ([da8a98e](https://github.com/noir-lang/noir/commit/da8a98ed312fe69cb0bdb8f9d0a70ee7a981398f)) +* **acvm:** Separate ACVM optimizations and transformations ([#2979](https://github.com/noir-lang/noir/issues/2979)) ([5865d1a](https://github.com/noir-lang/noir/commit/5865d1a1bca16e1853663c71f893ff81fa3f7185)) +* Add ACIR serializer C++ codegen ([#2961](https://github.com/noir-lang/noir/issues/2961)) ([7556982](https://github.com/noir-lang/noir/commit/7556982dbebe25eaa17240abbe270b771b55de45)) +* Add conditional compilation of methods based on the underlying field being used ([#3045](https://github.com/noir-lang/noir/issues/3045)) ([2e008e2](https://github.com/noir-lang/noir/commit/2e008e2438795bbc41b0641e830378b76bf2e194)) +* Expose pedersen hash in acir and bb solver ([#3269](https://github.com/noir-lang/noir/issues/3269)) ([0108b6c](https://github.com/noir-lang/noir/commit/0108b6c1e8dc0dfc766ab3c4944deae9354dec36)) +* Implement euclidean division and signed division in terms of `AcirVar`s ([#3230](https://github.com/noir-lang/noir/issues/3230)) ([b8b7782](https://github.com/noir-lang/noir/commit/b8b77825410c0e1f95549259a51e2c40de1ec342)) +* Maintain shape of foreign call arguments ([#2935](https://github.com/noir-lang/noir/issues/2935)) ([f7869e6](https://github.com/noir-lang/noir/commit/f7869e6fb492b617e776e538ac4babfa56261d26)) +* Pass ACIR to ACVM by reference rather than passing ownership ([#2872](https://github.com/noir-lang/noir/issues/2872)) ([b3a9c34](https://github.com/noir-lang/noir/commit/b3a9c343993ce3207de62106bda6cb2b2ef3de50)) +* Pass brillig bytecode to VM by reference ([#3030](https://github.com/noir-lang/noir/issues/3030)) ([4ee290b](https://github.com/noir-lang/noir/commit/4ee290b8b6f75bc1974a5750248570eeca8d244e)) +* Replace boolean range constraints with arithmetic opcodes ([#3234](https://github.com/noir-lang/noir/issues/3234)) ([949222c](https://github.com/noir-lang/noir/commit/949222c20d9e65152e3814d02da1c4c41ffc23a5)) +* Save Brillig execution state in ACVM ([#3026](https://github.com/noir-lang/noir/issues/3026)) ([88682da](https://github.com/noir-lang/noir/commit/88682da87ffc9e26da5c9e4b5a4d8e62a6ee43c6)) +* Solve `fixed_base_scalar_mul` black box functions in rust ([#3153](https://github.com/noir-lang/noir/issues/3153)) ([1c1afbc](https://github.com/noir-lang/noir/commit/1c1afbcddf0b5fdb39f00ad28ae90caf699d1265)) +* Switch to new pedersen implementation ([#3151](https://github.com/noir-lang/noir/issues/3151)) ([35fb3f7](https://github.com/noir-lang/noir/commit/35fb3f7076d52db7ca3bef0a70a3dbccaf82f58d)) +* **wasm:** Improve and simplify wasm compiler interface ([#2976](https://github.com/noir-lang/noir/issues/2976)) ([1b5124b](https://github.com/noir-lang/noir/commit/1b5124bc74f7ac5360db04b34d1b7b2284061fd3)) + + +### Bug Fixes + +* ACIR optimizer should update assertion messages ([#3010](https://github.com/noir-lang/noir/issues/3010)) ([758b6b6](https://github.com/noir-lang/noir/commit/758b6b62918907c1a39f3090a77419003551745e)) +* **acvm:** Return false rather than panicking on invalid ECDSA signatures ([#2783](https://github.com/noir-lang/noir/issues/2783)) ([155abc0](https://github.com/noir-lang/noir/commit/155abc0d99fff41c79163c16bf297d41e5dff0fa)) +* Determinism of fallback transformer ([#3100](https://github.com/noir-lang/noir/issues/3100)) ([12daad1](https://github.com/noir-lang/noir/commit/12daad19c902caf5ee9e2eb4b6847bde5a924353)) +* Fix method `program_counter`, change method signature ([#3012](https://github.com/noir-lang/noir/issues/3012)) ([5ea522b](https://github.com/noir-lang/noir/commit/5ea522b840ca0f6f90d02ca00f0de32f515d450f)) +* Minor problems with `aztec` publishing ([#3095](https://github.com/noir-lang/noir/issues/3095)) ([0fc8f20](https://github.com/noir-lang/noir/commit/0fc8f20b8b87d033d27ce18db039399c17f81837)) +* Prevent duplicated assert message transformation ([#3038](https://github.com/noir-lang/noir/issues/3038)) ([082a6d0](https://github.com/noir-lang/noir/commit/082a6d02dad67a25692bed15c340a16a848a320e)) +* Return error rather than panicking on unreadable circuits ([#3179](https://github.com/noir-lang/noir/issues/3179)) ([d4f61d3](https://github.com/noir-lang/noir/commit/d4f61d3d51d515e40a5fd02d35315889f841bf53)) + +## [0.29.0](https://github.com/noir-lang/noir/compare/v0.28.0...v0.29.0) (2023-10-20) + + +### ⚠ BREAKING CHANGES + +* Pass ACIR to ACVM by reference rather than passing ownership ([#2872](https://github.com/noir-lang/noir/issues/2872)) +* **wasm:** improve and simplify wasm compiler interface ([#2976](https://github.com/noir-lang/noir/issues/2976)) +* Maintain shape of foreign call arguments ([#2935](https://github.com/noir-lang/noir/issues/2935)) + +### Features + +* **acvm_js:** Export black box solver functions ([#2812](https://github.com/noir-lang/noir/issues/2812)) ([da8a98e](https://github.com/noir-lang/noir/commit/da8a98ed312fe69cb0bdb8f9d0a70ee7a981398f)) +* **acvm:** Separate ACVM optimizations and transformations ([#2979](https://github.com/noir-lang/noir/issues/2979)) ([5865d1a](https://github.com/noir-lang/noir/commit/5865d1a1bca16e1853663c71f893ff81fa3f7185)) +* Add ACIR serializer C++ codegen ([#2961](https://github.com/noir-lang/noir/issues/2961)) ([7556982](https://github.com/noir-lang/noir/commit/7556982dbebe25eaa17240abbe270b771b55de45)) +* Add conditional compilation of methods based on the underlying field being used ([#3045](https://github.com/noir-lang/noir/issues/3045)) ([2e008e2](https://github.com/noir-lang/noir/commit/2e008e2438795bbc41b0641e830378b76bf2e194)) +* Maintain shape of foreign call arguments ([#2935](https://github.com/noir-lang/noir/issues/2935)) ([f7869e6](https://github.com/noir-lang/noir/commit/f7869e6fb492b617e776e538ac4babfa56261d26)) +* Pass ACIR to ACVM by reference rather than passing ownership ([#2872](https://github.com/noir-lang/noir/issues/2872)) ([b3a9c34](https://github.com/noir-lang/noir/commit/b3a9c343993ce3207de62106bda6cb2b2ef3de50)) +* Pass brillig bytecode to VM by reference ([#3030](https://github.com/noir-lang/noir/issues/3030)) ([4ee290b](https://github.com/noir-lang/noir/commit/4ee290b8b6f75bc1974a5750248570eeca8d244e)) +* Save Brillig execution state in ACVM ([#3026](https://github.com/noir-lang/noir/issues/3026)) ([88682da](https://github.com/noir-lang/noir/commit/88682da87ffc9e26da5c9e4b5a4d8e62a6ee43c6)) +* Solve `fixed_base_scalar_mul` black box functions in rust ([#3153](https://github.com/noir-lang/noir/issues/3153)) ([1c1afbc](https://github.com/noir-lang/noir/commit/1c1afbcddf0b5fdb39f00ad28ae90caf699d1265)) +* **wasm:** Improve and simplify wasm compiler interface ([#2976](https://github.com/noir-lang/noir/issues/2976)) ([1b5124b](https://github.com/noir-lang/noir/commit/1b5124bc74f7ac5360db04b34d1b7b2284061fd3)) + + +### Bug Fixes + +* ACIR optimizer should update assertion messages ([#3010](https://github.com/noir-lang/noir/issues/3010)) ([758b6b6](https://github.com/noir-lang/noir/commit/758b6b62918907c1a39f3090a77419003551745e)) +* **acvm:** Return false rather than panicking on invalid ECDSA signatures ([#2783](https://github.com/noir-lang/noir/issues/2783)) ([155abc0](https://github.com/noir-lang/noir/commit/155abc0d99fff41c79163c16bf297d41e5dff0fa)) +* Determinism of fallback transformer ([#3100](https://github.com/noir-lang/noir/issues/3100)) ([12daad1](https://github.com/noir-lang/noir/commit/12daad19c902caf5ee9e2eb4b6847bde5a924353)) +* Fix method `program_counter`, change method signature ([#3012](https://github.com/noir-lang/noir/issues/3012)) ([5ea522b](https://github.com/noir-lang/noir/commit/5ea522b840ca0f6f90d02ca00f0de32f515d450f)) +* Minor problems with `aztec` publishing ([#3095](https://github.com/noir-lang/noir/issues/3095)) ([0fc8f20](https://github.com/noir-lang/noir/commit/0fc8f20b8b87d033d27ce18db039399c17f81837)) +* Prevent duplicated assert message transformation ([#3038](https://github.com/noir-lang/noir/issues/3038)) ([082a6d0](https://github.com/noir-lang/noir/commit/082a6d02dad67a25692bed15c340a16a848a320e)) +* Return error rather than panicking on unreadable circuits ([#3179](https://github.com/noir-lang/noir/issues/3179)) ([d4f61d3](https://github.com/noir-lang/noir/commit/d4f61d3d51d515e40a5fd02d35315889f841bf53)) + ## [0.28.0](https://github.com/noir-lang/noir/compare/v0.27.4...v0.28.0) (2023-10-03) diff --git a/acvm-repo/acir/Cargo.toml b/acvm-repo/acir/Cargo.toml index 087a0f26335..af6429a3a3d 100644 --- a/acvm-repo/acir/Cargo.toml +++ b/acvm-repo/acir/Cargo.toml @@ -2,7 +2,7 @@ name = "acir" description = "ACIR is the IR that the VM processes, it is analogous to LLVM IR" # x-release-please-start-version -version = "0.28.0" +version = "0.30.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/acvm-repo/acir/codegen/acir.cpp b/acvm-repo/acir/codegen/acir.cpp index 1c01c4f23d5..c31fc4abd00 100644 --- a/acvm-repo/acir/codegen/acir.cpp +++ b/acvm-repo/acir/codegen/acir.cpp @@ -82,14 +82,24 @@ namespace Circuit { static SchnorrVerify bincodeDeserialize(std::vector); }; - struct Pedersen { + struct PedersenCommitment { std::vector inputs; uint32_t domain_separator; std::array outputs; - friend bool operator==(const Pedersen&, const Pedersen&); + friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); std::vector bincodeSerialize() const; - static Pedersen bincodeDeserialize(std::vector); + static PedersenCommitment bincodeDeserialize(std::vector); + }; + + struct PedersenHash { + std::vector inputs; + uint32_t domain_separator; + Circuit::Witness output; + + friend bool operator==(const PedersenHash&, const PedersenHash&); + std::vector bincodeSerialize() const; + static PedersenHash bincodeDeserialize(std::vector); }; struct HashToField128Security { @@ -167,7 +177,7 @@ namespace Circuit { static RecursiveAggregation bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; friend bool operator==(const BlackBoxFuncCall&, const BlackBoxFuncCall&); std::vector bincodeSerialize() const; @@ -443,14 +453,24 @@ namespace Circuit { static SchnorrVerify bincodeDeserialize(std::vector); }; - struct Pedersen { + struct PedersenCommitment { Circuit::HeapVector inputs; Circuit::RegisterIndex domain_separator; Circuit::HeapArray output; - friend bool operator==(const Pedersen&, const Pedersen&); + friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); + std::vector bincodeSerialize() const; + static PedersenCommitment bincodeDeserialize(std::vector); + }; + + struct PedersenHash { + Circuit::HeapVector inputs; + Circuit::RegisterIndex domain_separator; + Circuit::RegisterIndex output; + + friend bool operator==(const PedersenHash&, const PedersenHash&); std::vector bincodeSerialize() const; - static Pedersen bincodeDeserialize(std::vector); + static PedersenHash bincodeDeserialize(std::vector); }; struct FixedBaseScalarMul { @@ -463,7 +483,7 @@ namespace Circuit { static FixedBaseScalarMul bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; friend bool operator==(const BlackBoxOp&, const BlackBoxOp&); std::vector bincodeSerialize() const; @@ -1871,22 +1891,22 @@ Circuit::BlackBoxFuncCall::SchnorrVerify serde::Deserializable BlackBoxFuncCall::Pedersen::bincodeSerialize() const { + inline std::vector BlackBoxFuncCall::PedersenCommitment::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxFuncCall::Pedersen BlackBoxFuncCall::Pedersen::bincodeDeserialize(std::vector input) { + inline BlackBoxFuncCall::PedersenCommitment BlackBoxFuncCall::PedersenCommitment::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -1897,7 +1917,7 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::Pedersen &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::PedersenCommitment &obj, Serializer &serializer) { serde::Serializable::serialize(obj.inputs, serializer); serde::Serializable::serialize(obj.domain_separator, serializer); serde::Serializable::serialize(obj.outputs, serializer); @@ -1905,14 +1925,58 @@ void serde::Serializable::serialize(const C template <> template -Circuit::BlackBoxFuncCall::Pedersen serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::Pedersen obj; +Circuit::BlackBoxFuncCall::PedersenCommitment serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxFuncCall::PedersenCommitment obj; obj.inputs = serde::Deserializable::deserialize(deserializer); obj.domain_separator = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } +namespace Circuit { + + inline bool operator==(const BlackBoxFuncCall::PedersenHash &lhs, const BlackBoxFuncCall::PedersenHash &rhs) { + if (!(lhs.inputs == rhs.inputs)) { return false; } + if (!(lhs.domain_separator == rhs.domain_separator)) { return false; } + if (!(lhs.output == rhs.output)) { return false; } + return true; + } + + inline std::vector BlackBoxFuncCall::PedersenHash::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline BlackBoxFuncCall::PedersenHash BlackBoxFuncCall::PedersenHash::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::PedersenHash &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.domain_separator, serializer); + serde::Serializable::serialize(obj.output, serializer); +} + +template <> +template +Circuit::BlackBoxFuncCall::PedersenHash serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxFuncCall::PedersenHash obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.domain_separator = serde::Deserializable::deserialize(deserializer); + obj.output = serde::Deserializable::deserialize(deserializer); + return obj; +} + namespace Circuit { inline bool operator==(const BlackBoxFuncCall::HashToField128Security &lhs, const BlackBoxFuncCall::HashToField128Security &rhs) { @@ -2594,22 +2658,66 @@ Circuit::BlackBoxOp::SchnorrVerify serde::Deserializable BlackBoxOp::PedersenCommitment::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline BlackBoxOp::PedersenCommitment BlackBoxOp::PedersenCommitment::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::BlackBoxOp::PedersenCommitment &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.domain_separator, serializer); + serde::Serializable::serialize(obj.output, serializer); +} + +template <> +template +Circuit::BlackBoxOp::PedersenCommitment serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxOp::PedersenCommitment obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.domain_separator = serde::Deserializable::deserialize(deserializer); + obj.output = serde::Deserializable::deserialize(deserializer); + return obj; +} + +namespace Circuit { + + inline bool operator==(const BlackBoxOp::PedersenHash &lhs, const BlackBoxOp::PedersenHash &rhs) { if (!(lhs.inputs == rhs.inputs)) { return false; } if (!(lhs.domain_separator == rhs.domain_separator)) { return false; } if (!(lhs.output == rhs.output)) { return false; } return true; } - inline std::vector BlackBoxOp::Pedersen::bincodeSerialize() const { + inline std::vector BlackBoxOp::PedersenHash::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxOp::Pedersen BlackBoxOp::Pedersen::bincodeDeserialize(std::vector input) { + inline BlackBoxOp::PedersenHash BlackBoxOp::PedersenHash::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -2620,7 +2728,7 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::Pedersen &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::BlackBoxOp::PedersenHash &obj, Serializer &serializer) { serde::Serializable::serialize(obj.inputs, serializer); serde::Serializable::serialize(obj.domain_separator, serializer); serde::Serializable::serialize(obj.output, serializer); @@ -2628,8 +2736,8 @@ void serde::Serializable::serialize(const Circuit template <> template -Circuit::BlackBoxOp::Pedersen serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::Pedersen obj; +Circuit::BlackBoxOp::PedersenHash serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxOp::PedersenHash obj; obj.inputs = serde::Deserializable::deserialize(deserializer); obj.domain_separator = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); diff --git a/acvm-repo/acir/src/circuit/black_box_functions.rs b/acvm-repo/acir/src/circuit/black_box_functions.rs index c56427a9f1a..9129f44008c 100644 --- a/acvm-repo/acir/src/circuit/black_box_functions.rs +++ b/acvm-repo/acir/src/circuit/black_box_functions.rs @@ -30,7 +30,9 @@ pub enum BlackBoxFunc { /// [grumpkin]: https://hackmd.io/@aztec-network/ByzgNxBfd#2-Grumpkin---A-curve-on-top-of-BN-254-for-SNARK-efficient-group-operations SchnorrVerify, /// Calculates a Pedersen commitment to the inputs. - Pedersen, + PedersenCommitment, + /// Calculates a Pedersen hash to the inputs. + PedersenHash, /// Hashes a set of inputs and applies the field modulus to the result /// to return a value which can be represented as a [`FieldElement`][acir_field::FieldElement] /// @@ -62,7 +64,8 @@ impl BlackBoxFunc { BlackBoxFunc::SHA256 => "sha256", BlackBoxFunc::SchnorrVerify => "schnorr_verify", BlackBoxFunc::Blake2s => "blake2s", - BlackBoxFunc::Pedersen => "pedersen", + BlackBoxFunc::PedersenCommitment => "pedersen", + BlackBoxFunc::PedersenHash => "pedersen_hash", BlackBoxFunc::HashToField128Security => "hash_to_field_128_security", BlackBoxFunc::EcdsaSecp256k1 => "ecdsa_secp256k1", BlackBoxFunc::FixedBaseScalarMul => "fixed_base_scalar_mul", @@ -79,7 +82,8 @@ impl BlackBoxFunc { "sha256" => Some(BlackBoxFunc::SHA256), "schnorr_verify" => Some(BlackBoxFunc::SchnorrVerify), "blake2s" => Some(BlackBoxFunc::Blake2s), - "pedersen" => Some(BlackBoxFunc::Pedersen), + "pedersen" => Some(BlackBoxFunc::PedersenCommitment), + "pedersen_hash" => Some(BlackBoxFunc::PedersenHash), "hash_to_field_128_security" => Some(BlackBoxFunc::HashToField128Security), "ecdsa_secp256k1" => Some(BlackBoxFunc::EcdsaSecp256k1), "ecdsa_secp256r1" => Some(BlackBoxFunc::EcdsaSecp256r1), diff --git a/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs b/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs index 472c4a043ba..22278bdc635 100644 --- a/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs +++ b/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs @@ -46,11 +46,16 @@ pub enum BlackBoxFuncCall { message: Vec, output: Witness, }, - Pedersen { + PedersenCommitment { inputs: Vec, domain_separator: u32, outputs: (Witness, Witness), }, + PedersenHash { + inputs: Vec, + domain_separator: u32, + output: Witness, + }, // 128 here specifies that this function // should have 128 bits of security HashToField128Security { @@ -138,11 +143,16 @@ impl BlackBoxFuncCall { message: vec![], output: Witness(0), }, - BlackBoxFunc::Pedersen => BlackBoxFuncCall::Pedersen { + BlackBoxFunc::PedersenCommitment => BlackBoxFuncCall::PedersenCommitment { inputs: vec![], domain_separator: 0, outputs: (Witness(0), Witness(0)), }, + BlackBoxFunc::PedersenHash => BlackBoxFuncCall::PedersenHash { + inputs: vec![], + domain_separator: 0, + output: Witness(0), + }, BlackBoxFunc::HashToField128Security => { BlackBoxFuncCall::HashToField128Security { inputs: vec![], output: Witness(0) } } @@ -187,7 +197,8 @@ impl BlackBoxFuncCall { BlackBoxFuncCall::SHA256 { .. } => BlackBoxFunc::SHA256, BlackBoxFuncCall::Blake2s { .. } => BlackBoxFunc::Blake2s, BlackBoxFuncCall::SchnorrVerify { .. } => BlackBoxFunc::SchnorrVerify, - BlackBoxFuncCall::Pedersen { .. } => BlackBoxFunc::Pedersen, + BlackBoxFuncCall::PedersenCommitment { .. } => BlackBoxFunc::PedersenCommitment, + BlackBoxFuncCall::PedersenHash { .. } => BlackBoxFunc::PedersenHash, BlackBoxFuncCall::HashToField128Security { .. } => BlackBoxFunc::HashToField128Security, BlackBoxFuncCall::EcdsaSecp256k1 { .. } => BlackBoxFunc::EcdsaSecp256k1, BlackBoxFuncCall::EcdsaSecp256r1 { .. } => BlackBoxFunc::EcdsaSecp256r1, @@ -207,7 +218,8 @@ impl BlackBoxFuncCall { BlackBoxFuncCall::SHA256 { inputs, .. } | BlackBoxFuncCall::Blake2s { inputs, .. } | BlackBoxFuncCall::Keccak256 { inputs, .. } - | BlackBoxFuncCall::Pedersen { inputs, .. } + | BlackBoxFuncCall::PedersenCommitment { inputs, .. } + | BlackBoxFuncCall::PedersenHash { inputs, .. } | BlackBoxFuncCall::HashToField128Security { inputs, .. } => inputs.to_vec(), BlackBoxFuncCall::AND { lhs, rhs, .. } | BlackBoxFuncCall::XOR { lhs, rhs, .. } => { vec![*lhs, *rhs] @@ -304,9 +316,10 @@ impl BlackBoxFuncCall { | BlackBoxFuncCall::HashToField128Security { output, .. } | BlackBoxFuncCall::SchnorrVerify { output, .. } | BlackBoxFuncCall::EcdsaSecp256k1 { output, .. } + | BlackBoxFuncCall::PedersenHash { output, .. } | BlackBoxFuncCall::EcdsaSecp256r1 { output, .. } => vec![*output], BlackBoxFuncCall::FixedBaseScalarMul { outputs, .. } - | BlackBoxFuncCall::Pedersen { outputs, .. } => vec![outputs.0, outputs.1], + | BlackBoxFuncCall::PedersenCommitment { outputs, .. } => vec![outputs.0, outputs.1], BlackBoxFuncCall::RANGE { .. } => vec![], BlackBoxFuncCall::Keccak256VariableLength { outputs, .. } => outputs.to_vec(), } @@ -395,7 +408,7 @@ impl std::fmt::Display for BlackBoxFuncCall { // SPECIFIC PARAMETERS match self { - BlackBoxFuncCall::Pedersen { domain_separator, .. } => { + BlackBoxFuncCall::PedersenCommitment { domain_separator, .. } => { write!(f, " domain_separator: {domain_separator}") } _ => write!(f, ""), diff --git a/acvm-repo/acir/tests/test_program_serialization.rs b/acvm-repo/acir/tests/test_program_serialization.rs index 6b2e85ab449..2a25129df48 100644 --- a/acvm-repo/acir/tests/test_program_serialization.rs +++ b/acvm-repo/acir/tests/test_program_serialization.rs @@ -77,9 +77,9 @@ fn fixed_base_scalar_mul_circuit() { circuit.write(&mut bytes).unwrap(); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 138, 91, 10, 0, 48, 12, 194, 178, 215, 207, 78, 189, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 138, 91, 10, 0, 48, 12, 194, 178, 215, 215, 46, 189, 163, 175, 165, 10, 21, 36, 10, 57, 192, 160, 146, 188, 226, 139, 78, 113, 69, 183, 190, 61, - 111, 218, 182, 231, 124, 68, 185, 243, 207, 92, 0, 0, 0, + 111, 218, 182, 231, 124, 122, 8, 177, 65, 92, 0, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -87,7 +87,7 @@ fn fixed_base_scalar_mul_circuit() { #[test] fn pedersen_circuit() { - let pedersen = Opcode::BlackBoxFuncCall(BlackBoxFuncCall::Pedersen { + let pedersen = Opcode::BlackBoxFuncCall(BlackBoxFuncCall::PedersenCommitment { inputs: vec![FunctionInput { witness: Witness(1), num_bits: FieldElement::max_num_bits() }], outputs: (Witness(2), Witness(3)), domain_separator: 0, diff --git a/acvm-repo/acir_field/Cargo.toml b/acvm-repo/acir_field/Cargo.toml index 10027519d6d..22ec76ff764 100644 --- a/acvm-repo/acir_field/Cargo.toml +++ b/acvm-repo/acir_field/Cargo.toml @@ -2,7 +2,7 @@ name = "acir_field" description = "The field implementation being used by ACIR." # x-release-please-start-version -version = "0.28.0" +version = "0.30.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/acvm-repo/acvm/Cargo.toml b/acvm-repo/acvm/Cargo.toml index f51bb627fd9..d52d39e1285 100644 --- a/acvm-repo/acvm/Cargo.toml +++ b/acvm-repo/acvm/Cargo.toml @@ -2,7 +2,7 @@ name = "acvm" description = "The virtual machine that processes ACIR given a backend/proof system." # x-release-please-start-version -version = "0.28.0" +version = "0.30.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/acvm-repo/acvm/src/compiler/optimizers/redundant_range.rs b/acvm-repo/acvm/src/compiler/optimizers/redundant_range.rs index b1696704108..766d3674113 100644 --- a/acvm-repo/acvm/src/compiler/optimizers/redundant_range.rs +++ b/acvm-repo/acvm/src/compiler/optimizers/redundant_range.rs @@ -1,6 +1,10 @@ use acir::{ - circuit::{opcodes::BlackBoxFuncCall, Circuit, Opcode}, - native_types::Witness, + circuit::{ + opcodes::{BlackBoxFuncCall, FunctionInput}, + Circuit, Opcode, + }, + native_types::{Expression, Witness}, + FieldElement, }; use std::collections::{BTreeMap, HashSet}; @@ -101,7 +105,7 @@ impl RangeOptimizer { if is_lowest_bit_size { already_seen_witness.insert(witness); new_order_list.push(order_list[idx]); - optimized_opcodes.push(opcode); + optimized_opcodes.push(optimized_range_opcode(witness, num_bits)); } } @@ -126,6 +130,20 @@ fn extract_range_opcode(opcode: &Opcode) -> Option<(Witness, u32)> { } } +fn optimized_range_opcode(witness: Witness, num_bits: u32) -> Opcode { + if num_bits == 1 { + Opcode::Arithmetic(Expression { + mul_terms: vec![(FieldElement::one(), witness, witness)], + linear_combinations: vec![(-FieldElement::one(), witness)], + q_c: FieldElement::zero(), + }) + } else { + Opcode::BlackBoxFuncCall(BlackBoxFuncCall::RANGE { + input: FunctionInput { witness, num_bits }, + }) + } +} + #[cfg(test)] mod tests { use std::collections::BTreeSet; diff --git a/acvm-repo/acvm/src/compiler/transformers/mod.rs b/acvm-repo/acvm/src/compiler/transformers/mod.rs index 6f9d78e4b93..d827b759666 100644 --- a/acvm-repo/acvm/src/compiler/transformers/mod.rs +++ b/acvm-repo/acvm/src/compiler/transformers/mod.rs @@ -130,7 +130,10 @@ pub(super) fn transform_internal( outputs, .. } - | acir::circuit::opcodes::BlackBoxFuncCall::Pedersen { outputs, .. } => { + | acir::circuit::opcodes::BlackBoxFuncCall::PedersenCommitment { + outputs, + .. + } => { transformer.mark_solvable(outputs.0); transformer.mark_solvable(outputs.1); } @@ -140,7 +143,8 @@ pub(super) fn transform_internal( } | acir::circuit::opcodes::BlackBoxFuncCall::EcdsaSecp256k1 { output, .. } | acir::circuit::opcodes::BlackBoxFuncCall::EcdsaSecp256r1 { output, .. } - | acir::circuit::opcodes::BlackBoxFuncCall::SchnorrVerify { output, .. } => { + | acir::circuit::opcodes::BlackBoxFuncCall::SchnorrVerify { output, .. } + | acir::circuit::opcodes::BlackBoxFuncCall::PedersenHash { output, .. } => { transformer.mark_solvable(*output); } } diff --git a/acvm-repo/acvm/src/pwg/blackbox/mod.rs b/acvm-repo/acvm/src/pwg/blackbox/mod.rs index c4d9d561f46..7e8ab8b948c 100644 --- a/acvm-repo/acvm/src/pwg/blackbox/mod.rs +++ b/acvm-repo/acvm/src/pwg/blackbox/mod.rs @@ -5,6 +5,8 @@ use acir::{ }; use acvm_blackbox_solver::{blake2s, keccak256, sha256}; +use self::pedersen::pedersen_hash; + use super::{insert_value, OpcodeNotSolvable, OpcodeResolutionError}; use crate::BlackBoxFunctionSolver; @@ -117,9 +119,12 @@ pub(crate) fn solve( message, *output, ), - BlackBoxFuncCall::Pedersen { inputs, domain_separator, outputs } => { + BlackBoxFuncCall::PedersenCommitment { inputs, domain_separator, outputs } => { pedersen(backend, initial_witness, inputs, *domain_separator, *outputs) } + BlackBoxFuncCall::PedersenHash { inputs, domain_separator, output } => { + pedersen_hash(backend, initial_witness, inputs, *domain_separator, *output) + } BlackBoxFuncCall::EcdsaSecp256k1 { public_key_x, public_key_y, diff --git a/acvm-repo/acvm/src/pwg/blackbox/pedersen.rs b/acvm-repo/acvm/src/pwg/blackbox/pedersen.rs index 44b4c91dc63..bb214c1ceaf 100644 --- a/acvm-repo/acvm/src/pwg/blackbox/pedersen.rs +++ b/acvm-repo/acvm/src/pwg/blackbox/pedersen.rs @@ -19,10 +19,28 @@ pub(super) fn pedersen( inputs.iter().map(|input| witness_to_value(initial_witness, input.witness)).collect(); let scalars: Vec<_> = scalars?.into_iter().cloned().collect(); - let (res_x, res_y) = backend.pedersen(&scalars, domain_separator)?; + let (res_x, res_y) = backend.pedersen_commitment(&scalars, domain_separator)?; insert_value(&outputs.0, res_x, initial_witness)?; insert_value(&outputs.1, res_y, initial_witness)?; Ok(()) } + +pub(super) fn pedersen_hash( + backend: &impl BlackBoxFunctionSolver, + initial_witness: &mut WitnessMap, + inputs: &[FunctionInput], + domain_separator: u32, + output: Witness, +) -> Result<(), OpcodeResolutionError> { + let scalars: Result, _> = + inputs.iter().map(|input| witness_to_value(initial_witness, input.witness)).collect(); + let scalars: Vec<_> = scalars?.into_iter().cloned().collect(); + + let res = backend.pedersen_hash(&scalars, domain_separator)?; + + insert_value(&output, res, initial_witness)?; + + Ok(()) +} diff --git a/acvm-repo/acvm/src/pwg/brillig.rs b/acvm-repo/acvm/src/pwg/brillig.rs index 6fc54d42eab..b0e5ec6dd48 100644 --- a/acvm-repo/acvm/src/pwg/brillig.rs +++ b/acvm-repo/acvm/src/pwg/brillig.rs @@ -14,13 +14,14 @@ use crate::{pwg::OpcodeNotSolvable, OpcodeResolutionError}; use super::{get_value, insert_value}; -pub(super) enum BrilligSolverStatus { +#[derive(Debug)] +pub enum BrilligSolverStatus { Finished, InProgress, ForeignCallWait(ForeignCallWaitInfo), } -pub(super) struct BrilligSolver<'b, B: BlackBoxFunctionSolver> { +pub struct BrilligSolver<'b, B: BlackBoxFunctionSolver> { vm: VM<'b, B>, acir_index: usize, } @@ -62,7 +63,7 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { /// Constructs a solver for a Brillig block given the bytecode and initial /// witness. pub(super) fn new( - initial_witness: &mut WitnessMap, + initial_witness: &WitnessMap, brillig: &'b Brillig, bb_solver: &'b B, acir_index: usize, @@ -116,6 +117,15 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { self.handle_vm_status(status) } + pub fn step(&mut self) -> Result { + let status = self.vm.process_opcode(); + self.handle_vm_status(status) + } + + pub fn program_counter(&self) -> usize { + self.vm.program_counter() + } + fn handle_vm_status( &self, vm_status: VMStatus, @@ -185,7 +195,7 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { Ok(()) } - pub(super) fn resolve_pending_foreign_call(&mut self, foreign_call_result: ForeignCallResult) { + pub fn resolve_pending_foreign_call(&mut self, foreign_call_result: ForeignCallResult) { match self.vm.get_status() { VMStatus::ForeignCallWait { .. } => self.vm.resolve_foreign_call(foreign_call_result), _ => unreachable!("Brillig VM is not waiting for a foreign call"), diff --git a/acvm-repo/acvm/src/pwg/mod.rs b/acvm-repo/acvm/src/pwg/mod.rs index 057597e6392..1022ad13800 100644 --- a/acvm-repo/acvm/src/pwg/mod.rs +++ b/acvm-repo/acvm/src/pwg/mod.rs @@ -10,12 +10,7 @@ use acir::{ }; use acvm_blackbox_solver::BlackBoxResolutionError; -use self::{ - arithmetic::ArithmeticSolver, - brillig::{BrilligSolver, BrilligSolverStatus}, - directives::solve_directives, - memory_op::MemoryOpSolver, -}; +use self::{arithmetic::ArithmeticSolver, directives::solve_directives, memory_op::MemoryOpSolver}; use crate::{BlackBoxFunctionSolver, Language}; use thiserror::Error; @@ -30,6 +25,7 @@ mod directives; mod blackbox; mod memory_op; +pub use self::brillig::{BrilligSolver, BrilligSolverStatus}; pub use brillig::ForeignCallWaitInfo; #[derive(Debug, Clone, PartialEq)] @@ -63,6 +59,11 @@ impl std::fmt::Display for ACVMStatus { } } +pub enum StepResult<'a, B: BlackBoxFunctionSolver> { + Status(ACVMStatus), + IntoBrillig(BrilligSolver<'a, B>), +} + // This enum represents the different cases in which an // opcode can be unsolvable. // The most common being that one of its input has not been @@ -263,6 +264,13 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> { res => res.map(|_| ()), }, }; + self.handle_opcode_resolution(resolution) + } + + fn handle_opcode_resolution( + &mut self, + resolution: Result<(), OpcodeResolutionError>, + ) -> ACVMStatus { match resolution { Ok(()) => { self.instruction_pointer += 1; @@ -302,34 +310,64 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> { let Opcode::Brillig(brillig) = &self.opcodes[self.instruction_pointer] else { unreachable!("Not executing a Brillig opcode"); }; + let witness = &mut self.witness_map; if BrilligSolver::::should_skip(witness, brillig)? { - BrilligSolver::::zero_out_brillig_outputs(witness, brillig).map(|_| None) - } else { - // If we're resuming execution after resolving a foreign call then - // there will be a cached `BrilligSolver` to avoid recomputation. - let mut solver: BrilligSolver<'_, B> = match self.brillig_solver.take() { - Some(solver) => solver, - None => { - BrilligSolver::new(witness, brillig, self.backend, self.instruction_pointer)? - } - }; - match solver.solve()? { - BrilligSolverStatus::ForeignCallWait(foreign_call) => { - // Cache the current state of the solver - self.brillig_solver = Some(solver); - Ok(Some(foreign_call)) - } - BrilligSolverStatus::InProgress => { - unreachable!("Brillig solver still in progress") - } - BrilligSolverStatus::Finished => { - // Write execution outputs - solver.finalize(witness, brillig)?; - Ok(None) - } + return BrilligSolver::::zero_out_brillig_outputs(witness, brillig).map(|_| None); + } + + // If we're resuming execution after resolving a foreign call then + // there will be a cached `BrilligSolver` to avoid recomputation. + let mut solver: BrilligSolver<'_, B> = match self.brillig_solver.take() { + Some(solver) => solver, + None => BrilligSolver::new(witness, brillig, self.backend, self.instruction_pointer)?, + }; + match solver.solve()? { + BrilligSolverStatus::ForeignCallWait(foreign_call) => { + // Cache the current state of the solver + self.brillig_solver = Some(solver); + Ok(Some(foreign_call)) + } + BrilligSolverStatus::InProgress => { + unreachable!("Brillig solver still in progress") } + BrilligSolverStatus::Finished => { + // Write execution outputs + solver.finalize(witness, brillig)?; + Ok(None) + } + } + } + + pub fn step_into_brillig_opcode(&mut self) -> StepResult<'a, B> { + let Opcode::Brillig(brillig) = &self.opcodes[self.instruction_pointer] else { + return StepResult::Status(self.solve_opcode()); + }; + + let witness = &mut self.witness_map; + let should_skip = match BrilligSolver::::should_skip(witness, brillig) { + Ok(result) => result, + Err(err) => return StepResult::Status(self.handle_opcode_resolution(Err(err))), + }; + + if should_skip { + let resolution = BrilligSolver::::zero_out_brillig_outputs(witness, brillig); + return StepResult::Status(self.handle_opcode_resolution(resolution)); + } + + let solver = BrilligSolver::new(witness, brillig, self.backend, self.instruction_pointer); + match solver { + Ok(solver) => StepResult::IntoBrillig(solver), + Err(..) => StepResult::Status(self.handle_opcode_resolution(solver.map(|_| ()))), + } + } + + pub fn finish_brillig_with_solver(&mut self, solver: BrilligSolver<'a, B>) -> ACVMStatus { + if !matches!(&self.opcodes[self.instruction_pointer], Opcode::Brillig(..)) { + unreachable!("Not executing a Brillig opcode"); } + self.brillig_solver = Some(solver); + self.solve_opcode() } } diff --git a/acvm-repo/acvm/tests/solver.rs b/acvm-repo/acvm/tests/solver.rs index 1d287d70c1b..d578555c5dc 100644 --- a/acvm-repo/acvm/tests/solver.rs +++ b/acvm-repo/acvm/tests/solver.rs @@ -29,13 +29,20 @@ impl BlackBoxFunctionSolver for StubbedBackend { ) -> Result { panic!("Path not trodden by this test") } - fn pedersen( + fn pedersen_commitment( &self, _inputs: &[FieldElement], _domain_separator: u32, ) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> { panic!("Path not trodden by this test") } + fn pedersen_hash( + &self, + _inputs: &[FieldElement], + _domain_separator: u32, + ) -> Result { + panic!("Path not trodden by this test") + } fn fixed_base_scalar_mul( &self, _low: &FieldElement, diff --git a/acvm-repo/acvm_js/Cargo.toml b/acvm-repo/acvm_js/Cargo.toml index f977eb5234f..b63b0b7be6e 100644 --- a/acvm-repo/acvm_js/Cargo.toml +++ b/acvm-repo/acvm_js/Cargo.toml @@ -2,7 +2,7 @@ name = "acvm_js" description = "Typescript wrapper around the ACVM allowing execution of ACIR code" # x-release-please-start-version -version = "0.28.0" +version = "0.30.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/acvm-repo/acvm_js/package.json b/acvm-repo/acvm_js/package.json index 6c20627400c..4947fee5ad8 100644 --- a/acvm-repo/acvm_js/package.json +++ b/acvm-repo/acvm_js/package.json @@ -1,6 +1,6 @@ { "name": "@noir-lang/acvm_js", - "version": "0.28.0", + "version": "0.30.0", "repository": { "type": "git", "url": "https://github.com/noir-lang/acvm.git" diff --git a/acvm-repo/acvm_js/test/shared/fixed_base_scalar_mul.ts b/acvm-repo/acvm_js/test/shared/fixed_base_scalar_mul.ts index e5f35e2b8fc..0437bebc369 100644 --- a/acvm-repo/acvm_js/test/shared/fixed_base_scalar_mul.ts +++ b/acvm-repo/acvm_js/test/shared/fixed_base_scalar_mul.ts @@ -1,7 +1,7 @@ // See `fixed_base_scalar_mul_circuit` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 138, 91, 10, 0, 48, 12, 194, 178, 215, 207, 78, 189, 163, 175, 165, 10, 21, 36, - 10, 57, 192, 160, 146, 188, 226, 139, 78, 113, 69, 183, 190, 61, 111, 218, 182, 231, 124, 68, 185, 243, 207, 92, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 138, 91, 10, 0, 48, 12, 194, 178, 215, 215, 46, 189, 163, 175, 165, 10, 21, 36, + 10, 57, 192, 160, 146, 188, 226, 139, 78, 113, 69, 183, 190, 61, 111, 218, 182, 231, 124, 122, 8, 177, 65, 92, 0, 0, 0, ]); export const initialWitnessMap = new Map([ diff --git a/acvm-repo/acvm_js/test/shared/pedersen.ts b/acvm-repo/acvm_js/test/shared/pedersen.ts index a973718e31c..668ee2b510b 100644 --- a/acvm-repo/acvm_js/test/shared/pedersen.ts +++ b/acvm-repo/acvm_js/test/shared/pedersen.ts @@ -8,6 +8,6 @@ export const initialWitnessMap = new Map([[1, '0x0000000000000000000000000000000 export const expectedWitnessMap = new Map([ [1, '0x0000000000000000000000000000000000000000000000000000000000000001'], - [2, '0x09489945604c9686e698cb69d7bd6fc0cdb02e9faae3e1a433f1c342c1a5ecc4'], - [3, '0x24f50d25508b4dfb1e8a834e39565f646e217b24cb3a475c2e4991d1bb07a9d8'], + [2, '0x083e7911d835097629f0067531fc15cafd79a89beecb39903f69572c636f4a5a'], + [3, '0x1a7f5efaad7f315c25a918f30cc8d7333fccab7ad7c90f14de81bcc528f9935d'], ]); diff --git a/acvm-repo/acvm_js/test/shared/schnorr_verify.ts b/acvm-repo/acvm_js/test/shared/schnorr_verify.ts index afd57d8ffb5..f88a70ba4a1 100644 --- a/acvm-repo/acvm_js/test/shared/schnorr_verify.ts +++ b/acvm-repo/acvm_js/test/shared/schnorr_verify.ts @@ -15,72 +15,72 @@ export const bytecode = Uint8Array.from([ ]); export const initialWitnessMap = new Map([ - [1, '0x17cbd3ed3151ccfd170efe1d54280a6a4822640bf5c369908ad74ea21518a9c5'], - [2, '0x0e0456e3795c1a31f20035b741cd6158929eeccd320d299cfcac962865a6bc74'], - [3, '0x0000000000000000000000000000000000000000000000000000000000000005'], - [4, '0x00000000000000000000000000000000000000000000000000000000000000ca'], - [5, '0x000000000000000000000000000000000000000000000000000000000000001f'], - [6, '0x0000000000000000000000000000000000000000000000000000000000000092'], - [7, '0x0000000000000000000000000000000000000000000000000000000000000051'], - [8, '0x00000000000000000000000000000000000000000000000000000000000000f2'], - [9, '0x00000000000000000000000000000000000000000000000000000000000000f6'], - [10, '0x0000000000000000000000000000000000000000000000000000000000000045'], - [11, '0x000000000000000000000000000000000000000000000000000000000000002b'], - [12, '0x000000000000000000000000000000000000000000000000000000000000006b'], - [13, '0x00000000000000000000000000000000000000000000000000000000000000f9'], - [14, '0x0000000000000000000000000000000000000000000000000000000000000099'], - [15, '0x00000000000000000000000000000000000000000000000000000000000000c6'], - [16, '0x000000000000000000000000000000000000000000000000000000000000002c'], - [17, '0x000000000000000000000000000000000000000000000000000000000000000e'], - [18, '0x000000000000000000000000000000000000000000000000000000000000006f'], - [19, '0x00000000000000000000000000000000000000000000000000000000000000bf'], - [20, '0x0000000000000000000000000000000000000000000000000000000000000079'], - [21, '0x0000000000000000000000000000000000000000000000000000000000000089'], - [22, '0x00000000000000000000000000000000000000000000000000000000000000a6'], - [23, '0x00000000000000000000000000000000000000000000000000000000000000a0'], - [24, '0x0000000000000000000000000000000000000000000000000000000000000067'], - [25, '0x0000000000000000000000000000000000000000000000000000000000000012'], - [26, '0x00000000000000000000000000000000000000000000000000000000000000b5'], - [27, '0x00000000000000000000000000000000000000000000000000000000000000f3'], - [28, '0x00000000000000000000000000000000000000000000000000000000000000e9'], - [29, '0x00000000000000000000000000000000000000000000000000000000000000e2'], - [30, '0x000000000000000000000000000000000000000000000000000000000000005f'], - [31, '0x0000000000000000000000000000000000000000000000000000000000000043'], - [32, '0x0000000000000000000000000000000000000000000000000000000000000010'], - [33, '0x0000000000000000000000000000000000000000000000000000000000000025'], - [34, '0x0000000000000000000000000000000000000000000000000000000000000080'], - [35, '0x0000000000000000000000000000000000000000000000000000000000000055'], - [36, '0x000000000000000000000000000000000000000000000000000000000000004c'], - [37, '0x0000000000000000000000000000000000000000000000000000000000000013'], - [38, '0x00000000000000000000000000000000000000000000000000000000000000fd'], - [39, '0x000000000000000000000000000000000000000000000000000000000000001e'], - [40, '0x000000000000000000000000000000000000000000000000000000000000004d'], - [41, '0x00000000000000000000000000000000000000000000000000000000000000c0'], - [42, '0x0000000000000000000000000000000000000000000000000000000000000035'], - [43, '0x000000000000000000000000000000000000000000000000000000000000008a'], - [44, '0x00000000000000000000000000000000000000000000000000000000000000cd'], - [45, '0x0000000000000000000000000000000000000000000000000000000000000045'], - [46, '0x0000000000000000000000000000000000000000000000000000000000000021'], - [47, '0x00000000000000000000000000000000000000000000000000000000000000ec'], - [48, '0x00000000000000000000000000000000000000000000000000000000000000a3'], - [49, '0x0000000000000000000000000000000000000000000000000000000000000053'], - [50, '0x00000000000000000000000000000000000000000000000000000000000000c2'], - [51, '0x0000000000000000000000000000000000000000000000000000000000000054'], - [52, '0x0000000000000000000000000000000000000000000000000000000000000089'], - [53, '0x00000000000000000000000000000000000000000000000000000000000000b8'], - [54, '0x00000000000000000000000000000000000000000000000000000000000000dd'], - [55, '0x00000000000000000000000000000000000000000000000000000000000000b0'], - [56, '0x0000000000000000000000000000000000000000000000000000000000000079'], - [57, '0x00000000000000000000000000000000000000000000000000000000000000b3'], - [58, '0x000000000000000000000000000000000000000000000000000000000000001b'], - [59, '0x000000000000000000000000000000000000000000000000000000000000003f'], - [60, '0x0000000000000000000000000000000000000000000000000000000000000046'], - [61, '0x0000000000000000000000000000000000000000000000000000000000000036'], - [62, '0x0000000000000000000000000000000000000000000000000000000000000010'], - [63, '0x00000000000000000000000000000000000000000000000000000000000000b0'], - [64, '0x00000000000000000000000000000000000000000000000000000000000000fa'], - [65, '0x0000000000000000000000000000000000000000000000000000000000000027'], - [66, '0x00000000000000000000000000000000000000000000000000000000000000ef'], + [1, '0x04b260954662e97f00cab9adb773a259097f7a274b83b113532bce27fa3fb96a'], + [2, '0x2fd51571db6c08666b0edfbfbc57d432068bccd0110a39b166ab243da0037197'], + [3, '0x000000000000000000000000000000000000000000000000000000000000002e'], + [4, '0x00000000000000000000000000000000000000000000000000000000000000ce'], + [5, '0x0000000000000000000000000000000000000000000000000000000000000052'], + [6, '0x00000000000000000000000000000000000000000000000000000000000000aa'], + [7, '0x0000000000000000000000000000000000000000000000000000000000000087'], + [8, '0x000000000000000000000000000000000000000000000000000000000000002a'], + [9, '0x0000000000000000000000000000000000000000000000000000000000000049'], + [10, '0x000000000000000000000000000000000000000000000000000000000000009d'], + [11, '0x0000000000000000000000000000000000000000000000000000000000000050'], + [12, '0x000000000000000000000000000000000000000000000000000000000000007c'], + [13, '0x000000000000000000000000000000000000000000000000000000000000009a'], + [14, '0x00000000000000000000000000000000000000000000000000000000000000aa'], + [15, '0x00000000000000000000000000000000000000000000000000000000000000df'], + [16, '0x0000000000000000000000000000000000000000000000000000000000000023'], + [17, '0x0000000000000000000000000000000000000000000000000000000000000034'], + [18, '0x0000000000000000000000000000000000000000000000000000000000000010'], + [19, '0x000000000000000000000000000000000000000000000000000000000000008a'], + [20, '0x0000000000000000000000000000000000000000000000000000000000000047'], + [21, '0x0000000000000000000000000000000000000000000000000000000000000063'], + [22, '0x00000000000000000000000000000000000000000000000000000000000000e8'], + [23, '0x0000000000000000000000000000000000000000000000000000000000000037'], + [24, '0x0000000000000000000000000000000000000000000000000000000000000054'], + [25, '0x0000000000000000000000000000000000000000000000000000000000000096'], + [26, '0x000000000000000000000000000000000000000000000000000000000000003e'], + [27, '0x00000000000000000000000000000000000000000000000000000000000000d5'], + [28, '0x00000000000000000000000000000000000000000000000000000000000000ae'], + [29, '0x0000000000000000000000000000000000000000000000000000000000000024'], + [30, '0x000000000000000000000000000000000000000000000000000000000000002d'], + [31, '0x0000000000000000000000000000000000000000000000000000000000000020'], + [32, '0x0000000000000000000000000000000000000000000000000000000000000080'], + [33, '0x000000000000000000000000000000000000000000000000000000000000004d'], + [34, '0x0000000000000000000000000000000000000000000000000000000000000047'], + [35, '0x00000000000000000000000000000000000000000000000000000000000000a5'], + [36, '0x00000000000000000000000000000000000000000000000000000000000000bb'], + [37, '0x00000000000000000000000000000000000000000000000000000000000000f6'], + [38, '0x00000000000000000000000000000000000000000000000000000000000000c3'], + [39, '0x000000000000000000000000000000000000000000000000000000000000000b'], + [40, '0x000000000000000000000000000000000000000000000000000000000000003b'], + [41, '0x0000000000000000000000000000000000000000000000000000000000000065'], + [42, '0x00000000000000000000000000000000000000000000000000000000000000c9'], + [43, '0x0000000000000000000000000000000000000000000000000000000000000001'], + [44, '0x0000000000000000000000000000000000000000000000000000000000000085'], + [45, '0x0000000000000000000000000000000000000000000000000000000000000006'], + [46, '0x000000000000000000000000000000000000000000000000000000000000009e'], + [47, '0x000000000000000000000000000000000000000000000000000000000000002f'], + [48, '0x0000000000000000000000000000000000000000000000000000000000000010'], + [49, '0x00000000000000000000000000000000000000000000000000000000000000e6'], + [50, '0x0000000000000000000000000000000000000000000000000000000000000030'], + [51, '0x000000000000000000000000000000000000000000000000000000000000004a'], + [52, '0x0000000000000000000000000000000000000000000000000000000000000018'], + [53, '0x000000000000000000000000000000000000000000000000000000000000007c'], + [54, '0x00000000000000000000000000000000000000000000000000000000000000d0'], + [55, '0x00000000000000000000000000000000000000000000000000000000000000ab'], + [56, '0x0000000000000000000000000000000000000000000000000000000000000031'], + [57, '0x00000000000000000000000000000000000000000000000000000000000000d5'], + [58, '0x0000000000000000000000000000000000000000000000000000000000000063'], + [59, '0x0000000000000000000000000000000000000000000000000000000000000084'], + [60, '0x00000000000000000000000000000000000000000000000000000000000000a3'], + [61, '0x00000000000000000000000000000000000000000000000000000000000000a6'], + [62, '0x00000000000000000000000000000000000000000000000000000000000000d5'], + [63, '0x0000000000000000000000000000000000000000000000000000000000000091'], + [64, '0x000000000000000000000000000000000000000000000000000000000000000d'], + [65, '0x000000000000000000000000000000000000000000000000000000000000009c'], + [66, '0x00000000000000000000000000000000000000000000000000000000000000f9'], [67, '0x0000000000000000000000000000000000000000000000000000000000000000'], [68, '0x0000000000000000000000000000000000000000000000000000000000000001'], [69, '0x0000000000000000000000000000000000000000000000000000000000000002'], diff --git a/acvm-repo/barretenberg_blackbox_solver/Cargo.toml b/acvm-repo/barretenberg_blackbox_solver/Cargo.toml index 97e58c2804b..c189c11cd10 100644 --- a/acvm-repo/barretenberg_blackbox_solver/Cargo.toml +++ b/acvm-repo/barretenberg_blackbox_solver/Cargo.toml @@ -2,7 +2,7 @@ name = "barretenberg_blackbox_solver" description = "A wrapper around a barretenberg WASM binary to execute black box functions for which there is no rust implementation" # x-release-please-start-version -version = "0.28.0" +version = "0.30.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/acvm-repo/barretenberg_blackbox_solver/build.rs b/acvm-repo/barretenberg_blackbox_solver/build.rs index 39db930b9d9..4269c86aba0 100644 --- a/acvm-repo/barretenberg_blackbox_solver/build.rs +++ b/acvm-repo/barretenberg_blackbox_solver/build.rs @@ -1,61 +1,14 @@ -use std::{ - fs::File, - io::{Cursor, Read}, - path::{Path, PathBuf}, -}; +use std::path::PathBuf; -const BARRETENBERG_ARCHIVE: &str = "BARRETENBERG_ARCHIVE"; const BARRETENBERG_BIN_DIR: &str = "BARRETENBERG_BIN_DIR"; -const BARRETENBERG_ARCHIVE_FALLBACK: &str = "https://github.com/AztecProtocol/barretenberg/releases/download/barretenberg-v0.5.0/acvm_backend.wasm.tar.gz"; -// const ARCHIVE_SHA256: &str = "1xpycikqlvsjcryi3hkbc4mwmmdz7zshw6f76vyf1qssq53asyfx"; - -fn unpack_wasm(archive_path: &Path, target_dir: &Path) -> Result<(), String> { - if archive_path.exists() && archive_path.is_file() { - let archive = File::open(archive_path).map_err(|_| "Could not read archive")?; - unpack_archive(archive, target_dir); - - Ok(()) - } else { - Err(format!("Unable to locate {BARRETENBERG_ARCHIVE} - Please set the BARRETENBERG_BIN_DIR env var to the directory where it exists, or ensure it's located at {}", archive_path.display())) - } -} - -fn unpack_archive(archive: T, target_dir: &Path) { - use flate2::read::GzDecoder; - use tar::Archive; - - let gz_decoder = GzDecoder::new(archive); - let mut archive = Archive::new(gz_decoder); - - archive.unpack(target_dir).unwrap(); -} - -/// Try to download the specified URL into a buffer which is returned. -fn download_binary_from_url(url: &str) -> Result>, String> { - let response = reqwest::blocking::get(url).map_err(|error| error.to_string())?; - - let bytes = response.bytes().unwrap(); - Ok(Cursor::new(bytes.to_vec())) -} - fn main() -> Result<(), String> { let out_dir = std::env::var("OUT_DIR").unwrap(); - match std::env::var(BARRETENBERG_ARCHIVE) { - Ok(archive_path) => { - unpack_wasm(&PathBuf::from(archive_path), &PathBuf::from(&out_dir))?; - println!("cargo:rustc-env={BARRETENBERG_BIN_DIR}={out_dir}"); - Ok(()) - } - Err(_) => { - let wasm_bytes = download_binary_from_url(BARRETENBERG_ARCHIVE_FALLBACK) - .expect("download should succeed"); + let dest_path = PathBuf::from(out_dir.clone()).join("acvm_backend.wasm"); - unpack_archive(wasm_bytes, &PathBuf::from(&out_dir)); - println!("cargo:rustc-env={BARRETENBERG_BIN_DIR}={out_dir}"); + println!("cargo:rustc-env={BARRETENBERG_BIN_DIR}={out_dir}"); + std::fs::copy("./src/acvm_backend.wasm", dest_path).unwrap(); - Ok(()) - } - } + Ok(()) } diff --git a/acvm-repo/barretenberg_blackbox_solver/src/acvm_backend.wasm b/acvm-repo/barretenberg_blackbox_solver/src/acvm_backend.wasm new file mode 100755 index 00000000000..bcf3bbf27ee Binary files /dev/null and b/acvm-repo/barretenberg_blackbox_solver/src/acvm_backend.wasm differ diff --git a/acvm-repo/barretenberg_blackbox_solver/src/lib.rs b/acvm-repo/barretenberg_blackbox_solver/src/lib.rs index b9486e97bd9..5d2ab834536 100644 --- a/acvm-repo/barretenberg_blackbox_solver/src/lib.rs +++ b/acvm-repo/barretenberg_blackbox_solver/src/lib.rs @@ -63,15 +63,26 @@ impl BlackBoxFunctionSolver for BarretenbergSolver { }) } - fn pedersen( + fn pedersen_commitment( &self, inputs: &[FieldElement], domain_separator: u32, ) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> { #[allow(deprecated)] - self.blackbox_vendor - .encrypt(inputs.to_vec(), domain_separator) - .map_err(|err| BlackBoxResolutionError::Failed(BlackBoxFunc::Pedersen, err.to_string())) + self.blackbox_vendor.encrypt(inputs.to_vec(), domain_separator).map_err(|err| { + BlackBoxResolutionError::Failed(BlackBoxFunc::PedersenCommitment, err.to_string()) + }) + } + + fn pedersen_hash( + &self, + inputs: &[FieldElement], + domain_separator: u32, + ) -> Result { + #[allow(deprecated)] + self.blackbox_vendor.hash(inputs.to_vec(), domain_separator).map_err(|err| { + BlackBoxResolutionError::Failed(BlackBoxFunc::PedersenCommitment, err.to_string()) + }) } fn fixed_base_scalar_mul( diff --git a/acvm-repo/barretenberg_blackbox_solver/src/wasm/pedersen.rs b/acvm-repo/barretenberg_blackbox_solver/src/wasm/pedersen.rs index 05f3f014e64..c19554eb6bc 100644 --- a/acvm-repo/barretenberg_blackbox_solver/src/wasm/pedersen.rs +++ b/acvm-repo/barretenberg_blackbox_solver/src/wasm/pedersen.rs @@ -8,6 +8,8 @@ pub(crate) trait Pedersen { inputs: Vec, hash_index: u32, ) -> Result<(FieldElement, FieldElement), Error>; + + fn hash(&self, inputs: Vec, hash_index: u32) -> Result; } impl Pedersen for Barretenberg { @@ -33,18 +35,36 @@ impl Pedersen for Barretenberg { Ok((point_x, point_y)) } + + fn hash(&self, inputs: Vec, hash_index: u32) -> Result { + let input_buf = Assignments::from(inputs).to_bytes(); + let input_ptr = self.allocate(&input_buf)?; + let result_ptr: usize = 0; + + self.call_multiple( + "pedersen_plookup_compress_with_hash_index", + vec![&input_ptr, &result_ptr.into(), &hash_index.into()], + )?; + + let result_bytes: [u8; FIELD_BYTES] = self.read_memory(result_ptr); + + let hash = FieldElement::from_be_bytes_reduce(&result_bytes); + + Ok(hash) + } } #[test] fn pedersen_hash_to_point() -> Result<(), Error> { let barretenberg = Barretenberg::new(); - let (x, y) = barretenberg.encrypt(vec![FieldElement::zero(), FieldElement::one()], 0)?; + let (x, y) = barretenberg + .encrypt(vec![FieldElement::from(1 as u128), FieldElement::from(1 as u128)], 1)?; let expected_x = FieldElement::from_hex( - "0x0c5e1ddecd49de44ed5e5798d3f6fb7c71fe3d37f5bee8664cf88a445b5ba0af", + "0x12afb43195f5c621d1d2cabb5f629707095c5307fd4185a663d4e80bb083e878", ) .unwrap(); let expected_y = FieldElement::from_hex( - "0x230294a041e26fe80b827c2ef5cb8784642bbaa83842da2714d62b1f3c4f9752", + "0x25793f5b5e62beb92fd18a66050293a9fd554a2ff13bceba0339cae1a038d7c1", ) .unwrap(); diff --git a/acvm-repo/blackbox_solver/Cargo.toml b/acvm-repo/blackbox_solver/Cargo.toml index f0295456977..f1a0444e014 100644 --- a/acvm-repo/blackbox_solver/Cargo.toml +++ b/acvm-repo/blackbox_solver/Cargo.toml @@ -2,7 +2,7 @@ name = "acvm_blackbox_solver" description = "A solver for the blackbox functions found in ACIR and Brillig" # x-release-please-start-version -version = "0.28.0" +version = "0.30.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/acvm-repo/blackbox_solver/src/lib.rs b/acvm-repo/blackbox_solver/src/lib.rs index 0c0fbae2bde..13d0f562415 100644 --- a/acvm-repo/blackbox_solver/src/lib.rs +++ b/acvm-repo/blackbox_solver/src/lib.rs @@ -34,11 +34,16 @@ pub trait BlackBoxFunctionSolver { signature: &[u8], message: &[u8], ) -> Result; - fn pedersen( + fn pedersen_commitment( &self, inputs: &[FieldElement], domain_separator: u32, ) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError>; + fn pedersen_hash( + &self, + inputs: &[FieldElement], + domain_separator: u32, + ) -> Result; fn fixed_base_scalar_mul( &self, low: &FieldElement, diff --git a/acvm-repo/brillig/Cargo.toml b/acvm-repo/brillig/Cargo.toml index c0f230ba55b..7a2592d6d32 100644 --- a/acvm-repo/brillig/Cargo.toml +++ b/acvm-repo/brillig/Cargo.toml @@ -2,7 +2,7 @@ name = "brillig" description = "Brillig is the bytecode ACIR uses for non-determinism." # x-release-please-start-version -version = "0.28.0" +version = "0.30.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/acvm-repo/brillig/src/black_box.rs b/acvm-repo/brillig/src/black_box.rs index be858a43cee..75fae0a10f0 100644 --- a/acvm-repo/brillig/src/black_box.rs +++ b/acvm-repo/brillig/src/black_box.rs @@ -42,7 +42,9 @@ pub enum BlackBoxOp { result: RegisterIndex, }, /// Calculates a Pedersen commitment to the inputs. - Pedersen { inputs: HeapVector, domain_separator: RegisterIndex, output: HeapArray }, + PedersenCommitment { inputs: HeapVector, domain_separator: RegisterIndex, output: HeapArray }, + /// Calculates a Pedersen hash to the inputs. + PedersenHash { inputs: HeapVector, domain_separator: RegisterIndex, output: RegisterIndex }, /// Performs scalar multiplication over the embedded curve. FixedBaseScalarMul { low: RegisterIndex, high: RegisterIndex, result: HeapArray }, } diff --git a/acvm-repo/brillig_vm/Cargo.toml b/acvm-repo/brillig_vm/Cargo.toml index 46d29935685..ac826585b5c 100644 --- a/acvm-repo/brillig_vm/Cargo.toml +++ b/acvm-repo/brillig_vm/Cargo.toml @@ -2,7 +2,7 @@ name = "brillig_vm" description = "The virtual machine that processes Brillig bytecode, used to introduce non-determinism to the ACVM" # x-release-please-start-version -version = "0.28.0" +version = "0.30.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/acvm-repo/brillig_vm/src/arithmetic.rs b/acvm-repo/brillig_vm/src/arithmetic.rs index 51ab8660452..263a733e3c4 100644 --- a/acvm-repo/brillig_vm/src/arithmetic.rs +++ b/acvm-repo/brillig_vm/src/arithmetic.rs @@ -25,18 +25,28 @@ pub(crate) fn evaluate_binary_bigint_op( a: BigUint, b: BigUint, bit_size: u32, -) -> BigUint { +) -> Result { let bit_modulo = &(BigUint::one() << bit_size); - match op { + let result = match op { // Perform addition, subtraction, and multiplication, applying a modulo operation to keep the result within the bit size. BinaryIntOp::Add => (a + b) % bit_modulo, BinaryIntOp::Sub => (bit_modulo + a - b) % bit_modulo, BinaryIntOp::Mul => (a * b) % bit_modulo, // Perform unsigned division using the modulo operation on a and b. - BinaryIntOp::UnsignedDiv => (a % bit_modulo) / (b % bit_modulo), + BinaryIntOp::UnsignedDiv => { + let b_mod = b % bit_modulo; + if b_mod.is_zero() { + return Err("Division by zero".to_owned()); + } + (a % bit_modulo) / b_mod + } // Perform signed division by first converting a and b to signed integers and then back to unsigned after the operation. BinaryIntOp::SignedDiv => { - let signed_div = to_big_signed(a, bit_size) / to_big_signed(b, bit_size); + let b_signed = to_big_signed(b, bit_size); + if b_signed.is_zero() { + return Err("Division by zero".to_owned()); + } + let signed_div = to_big_signed(a, bit_size) / b_signed; to_big_unsigned(signed_div, bit_size) } // Perform a == operation, returning 0 or 1 @@ -77,7 +87,9 @@ pub(crate) fn evaluate_binary_bigint_op( let b = b.to_u128().unwrap(); (a >> b) % bit_modulo } - } + }; + + Ok(result) } fn to_big_signed(a: BigUint, bit_size: u32) -> BigInt { @@ -111,7 +123,7 @@ mod tests { // Convert to big integers let lhs_big = BigUint::from(a); let rhs_big = BigUint::from(b); - let result_value = evaluate_binary_bigint_op(op, lhs_big, rhs_big, bit_size); + let result_value = evaluate_binary_bigint_op(op, lhs_big, rhs_big, bit_size).unwrap(); // Convert back to u128 result_value.to_u128().unwrap() } diff --git a/acvm-repo/brillig_vm/src/black_box.rs b/acvm-repo/brillig_vm/src/black_box.rs index ada8a2f5993..66d40c48aec 100644 --- a/acvm-repo/brillig_vm/src/black_box.rs +++ b/acvm-repo/brillig_vm/src/black_box.rs @@ -147,20 +147,34 @@ pub(crate) fn evaluate_black_box( memory.write_slice(registers.get(result.pointer).to_usize(), &[x.into(), y.into()]); Ok(()) } - BlackBoxOp::Pedersen { inputs, domain_separator, output } => { + BlackBoxOp::PedersenCommitment { inputs, domain_separator, output } => { let inputs: Vec = read_heap_vector(memory, registers, inputs).iter().map(|x| x.to_field()).collect(); let domain_separator: u32 = registers.get(*domain_separator).to_u128().try_into().map_err(|_| { BlackBoxResolutionError::Failed( - BlackBoxFunc::Pedersen, + BlackBoxFunc::PedersenCommitment, "Invalid signature length".to_string(), ) })?; - let (x, y) = solver.pedersen(&inputs, domain_separator)?; + let (x, y) = solver.pedersen_commitment(&inputs, domain_separator)?; memory.write_slice(registers.get(output.pointer).to_usize(), &[x.into(), y.into()]); Ok(()) } + BlackBoxOp::PedersenHash { inputs, domain_separator, output } => { + let inputs: Vec = + read_heap_vector(memory, registers, inputs).iter().map(|x| x.to_field()).collect(); + let domain_separator: u32 = + registers.get(*domain_separator).to_u128().try_into().map_err(|_| { + BlackBoxResolutionError::Failed( + BlackBoxFunc::PedersenCommitment, + "Invalid signature length".to_string(), + ) + })?; + let hash = solver.pedersen_hash(&inputs, domain_separator)?; + registers.set(*output, hash.into()); + Ok(()) + } } } diff --git a/acvm-repo/brillig_vm/src/lib.rs b/acvm-repo/brillig_vm/src/lib.rs index 48f6bf5f1c4..e0d30f7b2e0 100644 --- a/acvm-repo/brillig_vm/src/lib.rs +++ b/acvm-repo/brillig_vm/src/lib.rs @@ -177,8 +177,12 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { self.increment_program_counter() } Opcode::BinaryIntOp { op, bit_size, lhs, rhs, destination: result } => { - self.process_binary_int_op(*op, *bit_size, *lhs, *rhs, *result); - self.increment_program_counter() + if let Err(error) = self.process_binary_int_op(*op, *bit_size, *lhs, *rhs, *result) + { + self.fail(error) + } else { + self.increment_program_counter() + } } Opcode::Jump { location: destination } => self.set_program_counter(*destination), Opcode::JumpIf { condition, location: destination } => { @@ -391,17 +395,18 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { lhs: RegisterIndex, rhs: RegisterIndex, result: RegisterIndex, - ) { + ) -> Result<(), String> { let lhs_value = self.registers.get(lhs); let rhs_value = self.registers.get(rhs); // Convert to big integers let lhs_big = BigUint::from_bytes_be(&lhs_value.to_field().to_be_bytes()); let rhs_big = BigUint::from_bytes_be(&rhs_value.to_field().to_be_bytes()); - let result_value = evaluate_binary_bigint_op(&op, lhs_big, rhs_big, bit_size); + let result_value = evaluate_binary_bigint_op(&op, lhs_big, rhs_big, bit_size)?; // Convert back to field element self.registers .set(result, FieldElement::from_be_bytes_reduce(&result_value.to_bytes_be()).into()); + Ok(()) } } @@ -417,13 +422,20 @@ impl BlackBoxFunctionSolver for DummyBlackBoxSolver { ) -> Result { Ok(true) } - fn pedersen( + fn pedersen_commitment( &self, _inputs: &[FieldElement], _domain_separator: u32, ) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> { Ok((2_u128.into(), 3_u128.into())) } + fn pedersen_hash( + &self, + _inputs: &[FieldElement], + _domain_separator: u32, + ) -> Result { + Ok(6_u128.into()) + } fn fixed_base_scalar_mul( &self, _low: &FieldElement, diff --git a/acvm-repo/stdlib/Cargo.toml b/acvm-repo/stdlib/Cargo.toml index e675e7b284c..daba0fe9bba 100644 --- a/acvm-repo/stdlib/Cargo.toml +++ b/acvm-repo/stdlib/Cargo.toml @@ -2,7 +2,7 @@ name = "acvm_stdlib" description = "The ACVM standard library." # x-release-please-start-version -version = "0.28.0" +version = "0.30.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/compiler/noirc_driver/Cargo.toml b/compiler/noirc_driver/Cargo.toml index f1c21f74aab..f1c120e1687 100644 --- a/compiler/noirc_driver/Cargo.toml +++ b/compiler/noirc_driver/Cargo.toml @@ -7,6 +7,9 @@ license.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[build-dependencies] +build-data = "0.1.3" + [dependencies] clap.workspace = true noirc_errors.workspace = true diff --git a/compiler/noirc_driver/build.rs b/compiler/noirc_driver/build.rs new file mode 100644 index 00000000000..7b5a645c026 --- /dev/null +++ b/compiler/noirc_driver/build.rs @@ -0,0 +1,14 @@ +const GIT_COMMIT: &&str = &"GIT_COMMIT"; + +fn main() { + // Rebuild if the tests have changed + println!("cargo:rerun-if-changed=tests"); + + // Only use build_data if the environment variable isn't set + // The environment variable is always set when working via Nix + if std::env::var(GIT_COMMIT).is_err() { + build_data::set_GIT_COMMIT(); + build_data::set_GIT_DIRTY(); + build_data::no_debug_rebuilds(); + } +} diff --git a/compiler/noirc_driver/src/contract.rs b/compiler/noirc_driver/src/contract.rs index a16da313ff6..da097d4cb86 100644 --- a/compiler/noirc_driver/src/contract.rs +++ b/compiler/noirc_driver/src/contract.rs @@ -28,6 +28,8 @@ pub enum ContractFunctionType { #[derive(Serialize, Deserialize)] pub struct CompiledContract { + pub noir_version: String, + /// The name of the contract. pub name: String, /// Each of the contract's functions are compiled into a separate `CompiledProgram` diff --git a/compiler/noirc_driver/src/debug.rs b/compiler/noirc_driver/src/debug.rs index 9808c9b54a2..144e636b534 100644 --- a/compiler/noirc_driver/src/debug.rs +++ b/compiler/noirc_driver/src/debug.rs @@ -24,7 +24,7 @@ pub(crate) fn filter_relevant_files( function_symbols .locations .values() - .filter_map(|call_stack| call_stack.last().map(|location| location.file)) + .flat_map(|call_stack| call_stack.iter().map(|location| location.file)) }) .collect(); diff --git a/compiler/noirc_driver/src/lib.rs b/compiler/noirc_driver/src/lib.rs index 44e50f94874..f8908efc596 100644 --- a/compiler/noirc_driver/src/lib.rs +++ b/compiler/noirc_driver/src/lib.rs @@ -28,6 +28,15 @@ pub use program::CompiledProgram; const STD_CRATE_NAME: &str = "std"; +pub const GIT_COMMIT: &str = env!("GIT_COMMIT"); +pub const GIT_DIRTY: &str = env!("GIT_DIRTY"); +pub const NOIRC_VERSION: &str = env!("CARGO_PKG_VERSION"); + +/// Version string that gets placed in artifacts that Noir builds. This is semver compatible. +/// Note: You can't directly use the value of a constant produced with env! inside a concat! macro. +pub const NOIR_ARTIFACT_VERSION_STRING: &str = + concat!(env!("CARGO_PKG_VERSION"), "+", env!("GIT_COMMIT")); + #[derive(Args, Clone, Debug, Default, Serialize, Deserialize)] pub struct CompileOptions { /// Emit debug information for the intermediate SSA IR @@ -305,6 +314,7 @@ fn compile_contract_inner( .collect(), functions, file_map, + noir_version: NOIR_ARTIFACT_VERSION_STRING.to_string(), }) } else { Err(errors) @@ -342,5 +352,12 @@ pub fn compile_no_check( let file_map = filter_relevant_files(&[debug.clone()], &context.file_manager); - Ok(CompiledProgram { hash, circuit, debug, abi, file_map }) + Ok(CompiledProgram { + hash, + circuit, + debug, + abi, + file_map, + noir_version: NOIR_ARTIFACT_VERSION_STRING.to_string(), + }) } diff --git a/compiler/noirc_driver/src/program.rs b/compiler/noirc_driver/src/program.rs index 8a13092aeb6..fe991567180 100644 --- a/compiler/noirc_driver/src/program.rs +++ b/compiler/noirc_driver/src/program.rs @@ -12,6 +12,7 @@ use super::debug::DebugFile; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct CompiledProgram { + pub noir_version: String, /// Hash of the [`Program`][noirc_frontend::monomorphization::ast::Program] from which this [`CompiledProgram`] /// was compiled. /// diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs index e1d3f333f59..0d97dd12601 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs @@ -92,14 +92,14 @@ pub(crate) fn convert_black_box_call( ) } } - BlackBoxFunc::Pedersen => { + BlackBoxFunc::PedersenCommitment => { if let ( [message, RegisterOrMemory::RegisterIndex(domain_separator)], [RegisterOrMemory::HeapArray(result_array)], ) = (function_arguments, function_results) { let message_vector = convert_array_or_vector(brillig_context, message, bb_func); - brillig_context.black_box_op_instruction(BlackBoxOp::Pedersen { + brillig_context.black_box_op_instruction(BlackBoxOp::PedersenCommitment { inputs: message_vector, domain_separator: *domain_separator, output: *result_array, @@ -108,6 +108,22 @@ pub(crate) fn convert_black_box_call( unreachable!("ICE: Pedersen expects one array argument, a register for the domain separator, and one array result") } } + BlackBoxFunc::PedersenHash => { + if let ( + [message, RegisterOrMemory::RegisterIndex(domain_separator)], + [RegisterOrMemory::RegisterIndex(result)], + ) = (function_arguments, function_results) + { + let message_vector = convert_array_or_vector(brillig_context, message, bb_func); + brillig_context.black_box_op_instruction(BlackBoxOp::PedersenHash { + inputs: message_vector, + domain_separator: *domain_separator, + output: *result, + }); + } else { + unreachable!("ICE: Pedersen hash expects one array argument, a register for the domain separator, and one register result") + } + } BlackBoxFunc::SchnorrVerify => { if let ( [RegisterOrMemory::RegisterIndex(public_key_x), RegisterOrMemory::RegisterIndex(public_key_y), RegisterOrMemory::HeapArray(signature), message], diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs index a4ea0362f06..880ae95dcd7 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs @@ -1032,13 +1032,20 @@ pub(crate) mod tests { ) -> Result { Ok(true) } - fn pedersen( + fn pedersen_commitment( &self, _inputs: &[FieldElement], _domain_separator: u32, ) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> { Ok((2_u128.into(), 3_u128.into())) } + fn pedersen_hash( + &self, + _inputs: &[FieldElement], + _domain_separator: u32, + ) -> Result { + Ok(6_u128.into()) + } fn fixed_base_scalar_mul( &self, _low: &FieldElement, diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs index cc13b959095..65db47dd2e0 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs @@ -404,7 +404,7 @@ impl DebugShow { result ); } - BlackBoxOp::Pedersen { inputs, domain_separator, output } => { + BlackBoxOp::PedersenCommitment { inputs, domain_separator, output } => { debug_println!( self.enable_debug_trace, " PEDERSEN {} {} -> {}", @@ -413,6 +413,15 @@ impl DebugShow { output ); } + BlackBoxOp::PedersenHash { inputs, domain_separator, output } => { + debug_println!( + self.enable_debug_trace, + " PEDERSEN_HASH {} {} -> {}", + inputs, + domain_separator, + output + ); + } BlackBoxOp::SchnorrVerify { public_key_x, public_key_y, diff --git a/compiler/noirc_evaluator/src/errors.rs b/compiler/noirc_evaluator/src/errors.rs index 3dc0194c8be..58d13c0affd 100644 --- a/compiler/noirc_evaluator/src/errors.rs +++ b/compiler/noirc_evaluator/src/errors.rs @@ -7,12 +7,12 @@ //! An Error of the former is a user Error //! //! An Error of the latter is an error in the implementation of the compiler -use acvm::acir::native_types::Expression; +use acvm::{acir::native_types::Expression, FieldElement}; use iter_extended::vecmap; use noirc_errors::{CustomDiagnostic as Diagnostic, FileDiagnostic}; use thiserror::Error; -use crate::ssa::ir::dfg::CallStack; +use crate::ssa::ir::{dfg::CallStack, types::NumericType}; #[derive(Debug, PartialEq, Eq, Clone, Error)] pub enum RuntimeError { @@ -29,6 +29,8 @@ pub enum RuntimeError { IndexOutOfBounds { index: usize, array_size: usize, call_stack: CallStack }, #[error("Range constraint of {num_bits} bits is too large for the Field size")] InvalidRangeConstraint { num_bits: u32, call_stack: CallStack }, + #[error("{value} does not fit within the type bounds for {typ}")] + IntegerOutOfBounds { value: FieldElement, typ: NumericType, call_stack: CallStack }, #[error("Expected array index to fit into a u64")] TypeConversion { from: String, into: String, call_stack: CallStack }, #[error("{name:?} is not initialized")] @@ -91,6 +93,7 @@ impl RuntimeError { | RuntimeError::UnInitialized { call_stack, .. } | RuntimeError::UnknownLoopBound { call_stack } | RuntimeError::AssertConstantFailed { call_stack } + | RuntimeError::IntegerOutOfBounds { call_stack, .. } | RuntimeError::UnsupportedIntegerSize { call_stack, .. } => call_stack, } } diff --git a/compiler/noirc_evaluator/src/ssa.rs b/compiler/noirc_evaluator/src/ssa.rs index 131cf30a510..7cf51a4f0b3 100644 --- a/compiler/noirc_evaluator/src/ssa.rs +++ b/compiler/noirc_evaluator/src/ssa.rs @@ -39,7 +39,7 @@ pub(crate) fn optimize_into_acir( print_brillig_trace: bool, ) -> Result { let abi_distinctness = program.return_distinctness; - let ssa = SsaBuilder::new(program, print_ssa_passes) + let ssa = SsaBuilder::new(program, print_ssa_passes)? .run_pass(Ssa::defunctionalize, "After Defunctionalization:") .run_pass(Ssa::inline_functions, "After Inlining:") // Run mem2reg with the CFG separated into blocks @@ -129,8 +129,9 @@ struct SsaBuilder { } impl SsaBuilder { - fn new(program: Program, print_ssa_passes: bool) -> SsaBuilder { - SsaBuilder { print_ssa_passes, ssa: ssa_gen::generate_ssa(program) }.print("Initial SSA:") + fn new(program: Program, print_ssa_passes: bool) -> Result { + let ssa = ssa_gen::generate_ssa(program)?; + Ok(SsaBuilder { print_ssa_passes, ssa }.print("Initial SSA:")) } fn finish(self) -> Ssa { diff --git a/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs b/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs index d846ede566f..f54ddd9f4d4 100644 --- a/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs +++ b/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs @@ -22,6 +22,7 @@ use acvm::{ use acvm::{BlackBoxFunctionSolver, BlackBoxResolutionError}; use fxhash::FxHashMap as HashMap; use iter_extended::{try_vecmap, vecmap}; +use num_bigint::BigUint; use std::{borrow::Cow, hash::Hash}; #[derive(Clone, Debug, PartialEq, Eq, Hash)] @@ -427,20 +428,10 @@ impl AcirContext { let diff_expr = &lhs_expr - &rhs_expr; // Check to see if equality can be determined at compile-time. - if diff_expr.is_const() { - if diff_expr.is_zero() { - // Constraint is always true - assertion is unnecessary. - self.mark_variables_equivalent(lhs, rhs)?; - return Ok(()); - } else { - // Constraint is always false - this program is unprovable. - return Err(RuntimeError::FailedConstraint { - lhs: Box::new(lhs_expr), - rhs: Box::new(rhs_expr), - call_stack: self.get_call_stack(), - assert_message, - }); - }; + if diff_expr.is_zero() { + // Constraint is always true - assertion is unnecessary. + self.mark_variables_equivalent(lhs, rhs)?; + return Ok(()); } self.acir_ir.assert_is_zero(diff_expr); @@ -539,6 +530,20 @@ impl AcirContext { Ok(self.add_data(AcirVarData::from(sum_expr))) } + /// Adds a new Variable to context whose value will + /// be constrained to be the expression `lhs + k * rhs` + fn add_mul_var( + &mut self, + lhs: AcirVar, + k: FieldElement, + rhs: AcirVar, + ) -> Result { + let k_var = self.add_constant(k); + + let intermediate = self.mul_var(k_var, rhs)?; + self.add_var(lhs, intermediate) + } + /// Adds a new variable that is constrained to be the logical NOT of `x`. pub(crate) fn not_var(&mut self, x: AcirVar, typ: AcirType) -> Result { let bit_size = typ.bit_size(); @@ -555,19 +560,243 @@ impl AcirContext { bit_size: u32, predicate: AcirVar, ) -> Result<(AcirVar, AcirVar), RuntimeError> { - let lhs_expr = self.var_to_expression(lhs)?; + // lhs = rhs * q + r + // + // If predicate is zero, `q_witness` and `r_witness` will be 0 + let zero = self.add_constant(FieldElement::zero()); + if self.var_to_expression(predicate)?.is_zero() { + return Ok((zero, zero)); + } + + match (self.var_to_expression(lhs)?.to_const(), self.var_to_expression(rhs)?.to_const()) { + // If `lhs` and `rhs` are known constants then we can calculate the result at compile time. + // `rhs` must be non-zero. + (Some(lhs_const), Some(rhs_const)) if rhs_const != FieldElement::zero() => { + let quotient = lhs_const.to_u128() / rhs_const.to_u128(); + let remainder = lhs_const.to_u128() - quotient * rhs_const.to_u128(); + + let quotient_var = self.add_constant(FieldElement::from(quotient)); + let remainder_var = self.add_constant(FieldElement::from(remainder)); + return Ok((quotient_var, remainder_var)); + } + + // If `rhs` is one then the division is a noop. + (_, Some(rhs_const)) if rhs_const == FieldElement::one() => { + return Ok((lhs, zero)); + } + + _ => (), + } + + // Check that we the rhs is not zero. + // Otherwise, when executing the brillig quotient we may attempt to divide by zero, causing a VM panic. + // + // When the predicate is 0, the equation always passes. + // When the predicate is 1, the rhs must not be 0. + let one = self.add_constant(FieldElement::one()); + let rhs_expr = self.var_to_expression(rhs)?; - let predicate_expr = self.var_to_expression(predicate)?; + let rhs_is_nonzero_const = rhs_expr.is_const() && !rhs_expr.is_zero(); + if !rhs_is_nonzero_const { + match self.var_to_expression(predicate)?.to_const() { + Some(predicate) if predicate.is_one() => { + // If the predicate is known to be active, we simply assert that an inverse must exist. + // This implies that `rhs != 0`. + let _inverse = self.inv_var(rhs, one)?; + } - let (quotient, remainder) = - self.acir_ir.euclidean_division(&lhs_expr, &rhs_expr, bit_size, &predicate_expr)?; + _ => { + // Otherwise we must handle both potential cases. + let rhs_is_zero = self.eq_var(rhs, zero)?; + let rhs_is_not_zero = self.mul_var(rhs_is_zero, predicate)?; + self.assert_eq_var(rhs_is_not_zero, zero, None)?; + } + } + } - let quotient_var = self.add_data(AcirVarData::Witness(quotient)); - let remainder_var = self.add_data(AcirVarData::Witness(remainder)); + // maximum bit size for q and for [r and rhs] + let mut max_q_bits = bit_size; + let mut max_rhs_bits = bit_size; + // when rhs is constant, we can better estimate the maximum bit sizes + if let Some(rhs_const) = self.var_to_expression(rhs)?.to_const() { + max_rhs_bits = rhs_const.num_bits(); + if max_rhs_bits != 0 { + if max_rhs_bits > bit_size { + return Ok((zero, zero)); + } + max_q_bits = bit_size - max_rhs_bits + 1; + } + } + + // Avoids overflow: 'q*b+r < 2^max_q_bits*2^max_rhs_bits' + let mut avoid_overflow = false; + if max_q_bits + max_rhs_bits >= FieldElement::max_num_bits() - 1 { + // q*b+r can overflow; we avoid this when b is constant + if self.var_to_expression(rhs)?.is_const() { + avoid_overflow = true; + } else { + // we do not support unbounded division + unreachable!("overflow in unbounded division"); + } + } + + let [q_value, r_value]: [AcirValue; 2] = self + .brillig( + predicate, + brillig_directive::directive_quotient(bit_size + 1), + vec![ + AcirValue::Var(lhs, AcirType::unsigned(bit_size)), + AcirValue::Var(rhs, AcirType::unsigned(bit_size)), + ], + vec![AcirType::unsigned(max_q_bits), AcirType::unsigned(max_rhs_bits)], + )? + .try_into() + .expect("quotient only returns two values"); + let quotient_var = q_value.into_var()?; + let remainder_var = r_value.into_var()?; + + // Constrain `q < 2^{max_q_bits}`. + self.range_constrain_var(quotient_var, &NumericType::Unsigned { bit_size: max_q_bits })?; + + // Constrain `r < 2^{max_rhs_bits}`. + // + // If `rhs` is a power of 2, then is just a looser version of the following bound constraint. + // In the case where `rhs` isn't a power of 2 then this range constraint is required + // as the bound constraint creates a new witness. + // This opcode will be optimized out if it is redundant so we always add it for safety. + self.range_constrain_var(remainder_var, &NumericType::Unsigned { bit_size: max_rhs_bits })?; + + // Constrain `r < rhs`. + self.bound_constraint_with_offset(remainder_var, rhs, predicate, max_rhs_bits)?; + + // a * predicate == (b * q + r) * predicate + // => predicate * (a - b * q - r) == 0 + // When the predicate is 0, the equation always passes. + // When the predicate is 1, the euclidean division needs to be + // true. + let rhs_constraint = self.mul_var(rhs, quotient_var)?; + let rhs_constraint = self.add_var(rhs_constraint, remainder_var)?; + let rhs_constraint = self.mul_var(rhs_constraint, predicate)?; + + let lhs_constraint = self.mul_var(lhs, predicate)?; + self.assert_eq_var(lhs_constraint, rhs_constraint, None)?; + + if let Some(rhs_const) = self.var_to_expression(rhs)?.to_const() { + if avoid_overflow { + // we compute q0 = p/rhs + let rhs_big = BigUint::from_bytes_be(&rhs_const.to_be_bytes()); + let q0_big = FieldElement::modulus() / &rhs_big; + let q0 = FieldElement::from_be_bytes_reduce(&q0_big.to_bytes_be()); + let q0_var = self.add_constant(q0); + // when q == q0, b*q+r can overflow so we need to bound r to avoid the overflow. + + let size_predicate = self.eq_var(q0_var, quotient_var)?; + let predicate = self.mul_var(size_predicate, predicate)?; + // Ensure that there is no overflow, under q == q0 predicate + let max_r_big = FieldElement::modulus() - q0_big * rhs_big; + let max_r = FieldElement::from_be_bytes_reduce(&max_r_big.to_bytes_be()); + let max_r_var = self.add_constant(max_r); + + let max_r_predicate = self.mul_var(predicate, max_r_var)?; + let r_predicate = self.mul_var(remainder_var, predicate)?; + // Bound the remainder to be rhs, rhs-lhs = p+rhs-lhs > p-2^bits >= 2^bits (if log(p) >= bits + 1) + /// n.b: we do NOT check here that lhs and rhs are indeed 'bits' size + /// lhs < rhs <=> a+1<=b + /// TODO: Consolidate this with bounds_check function. + pub(super) fn bound_constraint_with_offset( + &mut self, + lhs: AcirVar, + rhs: AcirVar, + offset: AcirVar, + bits: u32, + ) -> Result<(), RuntimeError> { + const fn num_bits() -> usize { + std::mem::size_of::() * 8 + } + + fn bit_size_u128(a: u128) -> u32 where { + num_bits::() as u32 - a.leading_zeros() + } + + assert!( + bits < FieldElement::max_num_bits(), + "range check with bit size of the prime field is not implemented yet" + ); + + let mut lhs_offset = self.add_var(lhs, offset)?; + + // Optimization when rhs is const and fits within a u128 + let rhs_expr = self.var_to_expression(rhs)?; + if rhs_expr.is_const() && rhs_expr.q_c.fits_in_u128() { + // We try to move the offset to rhs + let rhs_offset = if self.is_constant_one(&offset) && rhs_expr.q_c.to_u128() >= 1 { + lhs_offset = lhs; + rhs_expr.q_c.to_u128() - 1 + } else { + rhs_expr.q_c.to_u128() + }; + // we now have lhs+offset <= rhs <=> lhs_offset <= rhs_offset + + let bit_size = bit_size_u128(rhs_offset); + // r = 2^bit_size - rhs_offset -1, is of bit size 'bit_size' by construction + let r = (1_u128 << bit_size) - rhs_offset - 1; + // however, since it is a constant, we can compute it's actual bit size + let r_bit_size = bit_size_u128(r); + // witness = lhs_offset + r + assert!(bits + r_bit_size < FieldElement::max_num_bits()); //we need to ensure lhs_offset + r does not overflow + + let r_var = self.add_constant(r.into()); + let aor = self.add_var(lhs_offset, r_var)?; + // lhs_offset<=rhs_offset <=> lhs_offset + r < rhs_offset + r = 2^bit_size <=> witness < 2^bit_size + self.range_constrain_var(aor, &NumericType::Unsigned { bit_size })?; + return Ok(()); + } + // General case: lhs_offset<=rhs <=> rhs-lhs_offset>=0 <=> rhs-lhs_offset is a 'bits' bit integer + let sub_expression = self.sub_var(rhs, lhs_offset)?; //rhs-lhs_offset + self.range_constrain_var(sub_expression, &NumericType::Unsigned { bit_size: bits })?; + + Ok(()) + } + + // Returns the 2-complement of lhs, using the provided sign bit in 'leading' + // if leading is zero, it returns lhs + // if leading is one, it returns 2^bit_size-lhs + fn two_complement( + &mut self, + lhs: AcirVar, + leading: AcirVar, + max_bit_size: u32, + ) -> Result { + let max_power_of_two = self.add_constant( + FieldElement::from(2_i128).pow(&FieldElement::from(max_bit_size as i128 - 1)), + ); + + let intermediate = self.sub_var(max_power_of_two, lhs)?; + let intermediate = self.mul_var(intermediate, leading)?; + + self.add_mul_var(lhs, FieldElement::from(2_i128), intermediate) + } + /// Returns the quotient and remainder such that lhs = rhs * quotient + remainder /// and |remainder| < |rhs| /// and remainder has the same sign than lhs @@ -578,14 +807,46 @@ impl AcirContext { rhs: AcirVar, bit_size: u32, ) -> Result<(AcirVar, AcirVar), RuntimeError> { - let l_witness = self.var_to_witness(lhs)?; - let r_witness = self.var_to_witness(rhs)?; + // We derive the signed division from the unsigned euclidean division. + // note that this is not euclidean division! + // If `x` is a signed integer, then `sign(x)x >= 0` + // so if `a` and `b` are signed integers, we can do the unsigned division: + // `sign(a)a = q1*sign(b)b + r1` + // => `a = sign(a)sign(b)q1*b + sign(a)r1` + // => `a = qb+r`, with `|r|<|b|` and `a` and `r` have the same sign. assert_ne!(bit_size, 0, "signed integer should have at least one bit"); - let (q, r) = - self.acir_ir.signed_division(&l_witness.into(), &r_witness.into(), bit_size)?; - Ok((self.add_data(q.into()), self.add_data(r.into()))) + // 2^{max_bit size-1} + let max_power_of_two = self.add_constant( + FieldElement::from(2_i128).pow(&FieldElement::from(bit_size as i128 - 1)), + ); + let one = self.add_constant(FieldElement::one()); + + // Get the sign bit of rhs by computing rhs / max_power_of_two + let (rhs_leading, _) = self.euclidean_division_var(rhs, max_power_of_two, bit_size, one)?; + + // Get the sign bit of lhs by computing lhs / max_power_of_two + let (lhs_leading, _) = self.euclidean_division_var(lhs, max_power_of_two, bit_size, one)?; + + // Signed to unsigned: + let unsigned_lhs = self.two_complement(lhs, lhs_leading, bit_size)?; + let unsigned_rhs = self.two_complement(rhs, rhs_leading, bit_size)?; + + // Performs the division using the unsigned values of lhs and rhs + let (q1, r1) = + self.euclidean_division_var(unsigned_lhs, unsigned_rhs, bit_size - 1, one)?; + + // Unsigned to signed: derive q and r from q1,r1 and the signs of lhs and rhs + // Quotient sign is lhs sign * rhs sign, whose resulting sign bit is the XOR of the sign bits + let sign_sum = self.add_var(lhs_leading, rhs_leading)?; + let sign_prod = self.mul_var(lhs_leading, rhs_leading)?; + let q_sign = self.add_mul_var(sign_sum, -FieldElement::from(2_i128), sign_prod)?; + + let quotient = self.two_complement(q1, q_sign, bit_size)?; + let remainder = self.two_complement(r1, lhs_leading, bit_size)?; + + Ok((quotient, remainder)) } /// Returns a variable which is constrained to be `lhs mod rhs` @@ -616,6 +877,13 @@ impl AcirContext { ) -> Result { match numeric_type { NumericType::Signed { bit_size } | NumericType::Unsigned { bit_size } => { + // If `variable` is constant then we don't need to add a constraint. + // We _do_ add a constraint if `variable` would fail the range check however so that we throw an error. + if let Some(constant) = self.var_to_expression(variable)?.to_const() { + if constant.num_bits() <= *bit_size { + return Ok(variable); + } + } let witness = self.var_to_witness(variable)?; self.acir_ir.range_constraint(witness, *bit_size)?; } @@ -636,19 +904,14 @@ impl AcirContext { max_bit_size: u32, ) -> Result { // 2^{rhs} - let divisor = FieldElement::from(2_i128).pow(&FieldElement::from(rhs as i128)); + let divisor = + self.add_constant(FieldElement::from(2_i128).pow(&FieldElement::from(rhs as i128))); + let one = self.add_constant(FieldElement::one()); - let lhs_data = &self.vars[&lhs]; - let lhs_expr = lhs_data.to_expression(); // Computes lhs = 2^{rhs} * q + r - let (_, remainder) = self.acir_ir.euclidean_division( - &lhs_expr, - &Expression::from_field(divisor), - max_bit_size, - &Expression::one(), - )?; + let (_, remainder) = self.euclidean_division_var(lhs, divisor, max_bit_size, one)?; - Ok(self.add_data(AcirVarData::from(remainder))) + Ok(remainder) } /// Returns an `AcirVar` which will be `1` if lhs >= rhs @@ -657,17 +920,69 @@ impl AcirContext { &mut self, lhs: AcirVar, rhs: AcirVar, - bit_size: u32, + max_bits: u32, predicate: AcirVar, ) -> Result { - let lhs_expr = self.var_to_expression(lhs)?; - let rhs_expr = self.var_to_expression(rhs)?; - let predicate_expr = self.var_to_expression(predicate)?; - - let is_greater_than_eq = - self.acir_ir.more_than_eq_comparison(&lhs_expr, &rhs_expr, bit_size, predicate_expr)?; + // Returns a `Witness` that is constrained to be: + // - `1` if lhs >= rhs + // - `0` otherwise + // + // We essentially computes the sign bit of `b-a` + // For this we sign-extend `b-a` with `c = 2^{max_bits} - (b - a)`, since both `a` and `b` are less than `2^{max_bits}` + // Then we get the bit sign of `c`, the 2-complement representation of `(b-a)`, which is a `max_bits+1` integer, + // by doing the euclidean division `c / 2^{max_bits}` + // + // To see why it really works; + // We first note that `c` is an integer of `(max_bits+1)` bits. Therefore, + // if `b-a>0`, then `c < 2^{max_bits}`, so the division by `2^{max_bits}` will give `0` + // If `b-a<=0`, then `c >= 2^{max_bits}`, so the division by `2^{max_bits}` will give `1`. + // + // In other words, `1` means `a >= b` and `0` means `b > a`. + // The important thing here is that `c` does not overflow nor underflow the field; + // - By construction we have `c >= 0`, so there is no underflow + // - We assert at the beginning that `2^{max_bits+1}` does not overflow the field, so neither c. - Ok(self.add_data(AcirVarData::Witness(is_greater_than_eq))) + // Ensure that 2^{max_bits + 1} is less than the field size + // + // TODO: perhaps this should be a user error, instead of an assert + assert!(max_bits + 1 < FieldElement::max_num_bits()); + let two_max_bits = self + .add_constant(FieldElement::from(2_i128).pow(&FieldElement::from(max_bits as i128))); + let diff = self.sub_var(lhs, rhs)?; + let comparison_evaluation = self.add_var(diff, two_max_bits)?; + + // Euclidean division by 2^{max_bits} : 2^{max_bits} + a - b = q * 2^{max_bits} + r + // + // 2^{max_bits} is of max_bits+1 bit size + // If a>b, then a-b is less than 2^{max_bits} - 1, so 2^{max_bits} + a - b is less than 2^{max_bits} + 2^{max_bits} - 1 = 2^{max_bits+1} - 1 + // If a <= b, then 2^{max_bits} + a - b is less than 2^{max_bits} <= 2^{max_bits+1} - 1 + // This means that both operands of the division have at most max_bits+1 bit size. + // + // case: a == b + // + // let k = 0; + // - 2^{max_bits} == q * 2^{max_bits} + r + // - This is only the case when q == 1 and r == 0 (assuming r is bounded to be less than 2^{max_bits}) + // + // case: a > b + // + // let k = a - b; + // - k + 2^{max_bits} == q * 2^{max_bits} + r + // - This is the case when q == 1 and r = k + // + // case: a < b + // + // let k = b - a + // - 2^{max_bits} - k == q * 2^{max_bits} + r + // - This is only the case when q == 0 and r == 2^{max_bits} - k + // + let (q, _) = self.euclidean_division_var( + comparison_evaluation, + two_max_bits, + max_bits + 1, + predicate, + )?; + Ok(q) } /// Returns an `AcirVar` which will be `1` if lhs < rhs @@ -697,7 +1012,7 @@ impl AcirContext { ) -> Result, RuntimeError> { // Separate out any arguments that should be constants let constants = match name { - BlackBoxFunc::Pedersen => { + BlackBoxFunc::PedersenCommitment | BlackBoxFunc::PedersenHash => { // The last argument of pedersen is the domain separator, which must be a constant let domain_var = match inputs.pop() { Some(domain_var) => domain_var.into_var()?, @@ -1264,12 +1579,19 @@ fn execute_brillig( ) -> Result { Err(BlackBoxResolutionError::Unsupported(BlackBoxFunc::SchnorrVerify)) } - fn pedersen( + fn pedersen_commitment( &self, _inputs: &[FieldElement], _domain_separator: u32, ) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> { - Err(BlackBoxResolutionError::Unsupported(BlackBoxFunc::Pedersen)) + Err(BlackBoxResolutionError::Unsupported(BlackBoxFunc::PedersenCommitment)) + } + fn pedersen_hash( + &self, + _inputs: &[FieldElement], + _domain_separator: u32, + ) -> Result { + Err(BlackBoxResolutionError::Unsupported(BlackBoxFunc::PedersenHash)) } fn fixed_base_scalar_mul( &self, diff --git a/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs b/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs index 3ce1c8893fa..221137b9dab 100644 --- a/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs +++ b/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs @@ -167,11 +167,16 @@ impl GeneratedAcir { output: outputs[0], } } - BlackBoxFunc::Pedersen => BlackBoxFuncCall::Pedersen { + BlackBoxFunc::PedersenCommitment => BlackBoxFuncCall::PedersenCommitment { inputs: inputs[0].clone(), outputs: (outputs[0], outputs[1]), domain_separator: constants[0].to_u128() as u32, }, + BlackBoxFunc::PedersenHash => BlackBoxFuncCall::PedersenHash { + inputs: inputs[0].clone(), + output: outputs[0], + domain_separator: constants[0].to_u128() as u32, + }, BlackBoxFunc::EcdsaSecp256k1 => { BlackBoxFuncCall::EcdsaSecp256k1 { // 32 bytes for each public key co-ordinate @@ -290,24 +295,6 @@ impl GeneratedAcir { Ok(limb_witnesses) } - // Returns the 2-complement of lhs, using the provided sign bit in 'leading' - // if leading is zero, it returns lhs - // if leading is one, it returns 2^bit_size-lhs - fn two_complement( - &mut self, - lhs: &Expression, - leading: Witness, - max_bit_size: u32, - ) -> Expression { - let max_power_of_two = - FieldElement::from(2_i128).pow(&FieldElement::from(max_bit_size as i128 - 1)); - - let intermediate = - self.mul_with_witness(&(&Expression::from(max_power_of_two) - lhs), &leading.into()); - - lhs.add_mul(FieldElement::from(2_i128), &intermediate) - } - /// Returns an expression which represents `lhs * rhs` /// /// If one has multiplicative term and the other is of degree one or more, @@ -357,286 +344,6 @@ impl GeneratedAcir { (&*lhs_reduced * &*rhs_reduced).expect("Both expressions are reduced to be degree <= 1") } - /// Signed division lhs / rhs - /// We derive the signed division from the unsigned euclidean division. - /// note that this is not euclidean division! - // if x is a signed integer, then sign(x)x >= 0 - // so if a and b are signed integers, we can do the unsigned division: - // sign(a)a = q1*sign(b)b + r1 - // => a = sign(a)sign(b)q1*b + sign(a)r1 - // => a = qb+r, with |r|<|b| and a and r have the same sign. - pub(crate) fn signed_division( - &mut self, - lhs: &Expression, - rhs: &Expression, - max_bit_size: u32, - ) -> Result<(Expression, Expression), RuntimeError> { - // 2^{max_bit size-1} - let max_power_of_two = - FieldElement::from(2_i128).pow(&FieldElement::from(max_bit_size as i128 - 1)); - - // Get the sign bit of rhs by computing rhs / max_power_of_two - let (rhs_leading_witness, _) = self.euclidean_division( - rhs, - &max_power_of_two.into(), - max_bit_size, - &Expression::one(), - )?; - - // Get the sign bit of lhs by computing lhs / max_power_of_two - let (lhs_leading_witness, _) = self.euclidean_division( - lhs, - &max_power_of_two.into(), - max_bit_size, - &Expression::one(), - )?; - - // Signed to unsigned: - let unsigned_lhs = self.two_complement(lhs, lhs_leading_witness, max_bit_size); - let unsigned_rhs = self.two_complement(rhs, rhs_leading_witness, max_bit_size); - let unsigned_l_witness = self.get_or_create_witness(&unsigned_lhs); - let unsigned_r_witness = self.get_or_create_witness(&unsigned_rhs); - - // Performs the division using the unsigned values of lhs and rhs - let (q1, r1) = self.euclidean_division( - &unsigned_l_witness.into(), - &unsigned_r_witness.into(), - max_bit_size - 1, - &Expression::one(), - )?; - - // Unsigned to signed: derive q and r from q1,r1 and the signs of lhs and rhs - // Quotient sign is lhs sign * rhs sign, whose resulting sign bit is the XOR of the sign bits - let sign_sum = - &Expression::from(lhs_leading_witness) + &Expression::from(rhs_leading_witness); - let sign_prod = (&Expression::from(lhs_leading_witness) - * &Expression::from(rhs_leading_witness)) - .expect("Product of two witnesses so result is degree 2"); - let q_sign = sign_sum.add_mul(-FieldElement::from(2_i128), &sign_prod); - - let q_sign_witness = self.get_or_create_witness(&q_sign); - let quotient = self.two_complement(&q1.into(), q_sign_witness, max_bit_size); - let remainder = self.two_complement(&r1.into(), lhs_leading_witness, max_bit_size); - Ok((quotient, remainder)) - } - - /// Computes lhs/rhs by using euclidean division. - /// - /// Returns `q` for quotient and `r` for remainder such - /// that lhs = rhs * q + r - pub(crate) fn euclidean_division( - &mut self, - lhs: &Expression, - rhs: &Expression, - max_bit_size: u32, - predicate: &Expression, - ) -> Result<(Witness, Witness), RuntimeError> { - // lhs = rhs * q + r - // - // If predicate is zero, `q_witness` and `r_witness` will be 0 - - // Check that we the rhs is not zero. - // Otherwise, when executing the brillig quotient we may attempt to divide by zero, causing a VM panic. - // - // When the predicate is 0, the equation always passes. - // When the predicate is 1, the rhs must not be 0. - let rhs_is_nonzero_const = rhs.is_const() && !rhs.is_zero(); - if !rhs_is_nonzero_const { - match predicate.to_const() { - Some(predicate) if predicate.is_zero() => { - // If predicate is known to be inactive, we don't need to lay down constraints. - } - - Some(predicate) if predicate.is_one() => { - // If the predicate is known to be active, we simply assert that an inverse must exist. - // This implies that `rhs != 0`. - let unsafe_inverse = self.brillig_inverse(rhs.clone()); - let rhs_has_inverse = - self.mul_with_witness(rhs, &unsafe_inverse.into()) - FieldElement::one(); - self.assert_is_zero(rhs_has_inverse); - } - - _ => { - // Otherwise we must handle both potential cases. - let rhs_is_zero = self.is_zero(rhs); - let rhs_is_not_zero = self.mul_with_witness(&rhs_is_zero.into(), predicate); - self.assert_is_zero(rhs_is_not_zero); - } - } - } - - // maximum bit size for q and for [r and rhs] - let mut max_q_bits = max_bit_size; - let mut max_rhs_bits = max_bit_size; - // when rhs is constant, we can better estimate the maximum bit sizes - if let Some(rhs_const) = rhs.to_const() { - max_rhs_bits = rhs_const.num_bits(); - if max_rhs_bits != 0 { - if max_rhs_bits > max_bit_size { - let zero = self.get_or_create_witness(&Expression::zero()); - return Ok((zero, zero)); - } - max_q_bits = max_bit_size - max_rhs_bits + 1; - } - } - - // Avoids overflow: 'q*b+r < 2^max_q_bits*2^max_rhs_bits' - let mut avoid_overflow = false; - if max_q_bits + max_rhs_bits >= FieldElement::max_num_bits() - 1 { - // q*b+r can overflow; we avoid this when b is constant - if rhs.is_const() { - avoid_overflow = true; - } else { - // we do not support unbounded division - unreachable!("overflow in unbounded division"); - } - } - - let (q_witness, r_witness) = - self.brillig_quotient(lhs.clone(), rhs.clone(), predicate.clone(), max_bit_size + 1); - - // Constrain `q < 2^{max_q_bits}`. - self.range_constraint(q_witness, max_q_bits)?; - - // Constrain `r < 2^{max_rhs_bits}`. - // - // If `rhs` is a power of 2, then is just a looser version of the following bound constraint. - // In the case where `rhs` isn't a power of 2 then this range constraint is required - // as the bound constraint creates a new witness. - // This opcode will be optimized out if it is redundant so we always add it for safety. - self.range_constraint(r_witness, max_rhs_bits)?; - - // Constrain `r < rhs`. - self.bound_constraint_with_offset(&r_witness.into(), rhs, predicate, max_rhs_bits)?; - - // a * predicate == (b * q + r) * predicate - // => predicate * (a - b * q - r) == 0 - // When the predicate is 0, the equation always passes. - // When the predicate is 1, the euclidean division needs to be - // true. - let rhs_constraint = &self.mul_with_witness(rhs, &q_witness.into()) + r_witness; - let div_euclidean = &self.mul_with_witness(lhs, predicate) - - &self.mul_with_witness(&rhs_constraint, predicate); - - if let Some(rhs_const) = rhs.to_const() { - if avoid_overflow { - // we compute q0 = p/rhs - let rhs_big = BigUint::from_bytes_be(&rhs_const.to_be_bytes()); - let q0_big = FieldElement::modulus() / &rhs_big; - let q0 = FieldElement::from_be_bytes_reduce(&q0_big.to_bytes_be()); - // when q == q0, b*q+r can overflow so we need to bound r to avoid the overflow. - let size_predicate = - self.is_equal(&Expression::from_field(q0), &Expression::from(q_witness)); - let predicate = self.mul_with_witness(&size_predicate.into(), predicate); - // Ensure that there is no overflow, under q == q0 predicate - let max_r_big = FieldElement::modulus() - q0_big * rhs_big; - let max_r = FieldElement::from_be_bytes_reduce(&max_r_big.to_bytes_be()); - let max_r_predicate = - self.mul_with_witness(&predicate, &Expression::from_field(max_r)); - let r_predicate = self.mul_with_witness(&Expression::from(r_witness), &predicate); - // Bound the remainder to be (Witness, Witness) { - // Create the witness for the result - let q_witness = self.next_witness_index(); - let r_witness = self.next_witness_index(); - - let quotient_code = brillig_directive::directive_quotient(max_bit_size); - let inputs = vec![BrilligInputs::Single(lhs), BrilligInputs::Single(rhs)]; - let outputs = vec![BrilligOutputs::Simple(q_witness), BrilligOutputs::Simple(r_witness)]; - self.brillig(Some(predicate), quotient_code, inputs, outputs); - - (q_witness, r_witness) - } - - /// Generate constraints that are satisfied iff - /// lhs < rhs , when offset is 1, or - /// lhs <= rhs, when offset is 0 - /// bits is the bit size of a and b (or an upper bound of the bit size) - /// - /// lhs<=rhs is done by constraining b-a to a bit size of 'bits': - /// if lhs<=rhs, 0 <= rhs-lhs <= b < 2^bits - /// if lhs>rhs, rhs-lhs = p+rhs-lhs > p-2^bits >= 2^bits (if log(p) >= bits + 1) - /// n.b: we do NOT check here that lhs and rhs are indeed 'bits' size - /// lhs < rhs <=> a+1<=b - /// TODO: Consolidate this with bounds_check function. - fn bound_constraint_with_offset( - &mut self, - lhs: &Expression, - rhs: &Expression, - offset: &Expression, - bits: u32, - ) -> Result<(), RuntimeError> { - const fn num_bits() -> usize { - std::mem::size_of::() * 8 - } - - fn bit_size_u128(a: u128) -> u32 where { - num_bits::() as u32 - a.leading_zeros() - } - - assert!( - bits < FieldElement::max_num_bits(), - "range check with bit size of the prime field is not implemented yet" - ); - - let mut lhs_offset = lhs + offset; - - // Optimization when rhs is const and fits within a u128 - if rhs.is_const() && rhs.q_c.fits_in_u128() { - // We try to move the offset to rhs - let rhs_offset = if *offset == Expression::one() && rhs.q_c.to_u128() >= 1 { - lhs_offset = lhs.clone(); - rhs.q_c.to_u128() - 1 - } else { - rhs.q_c.to_u128() - }; - // we now have lhs+offset <= rhs <=> lhs_offset <= rhs_offset - - let bit_size = bit_size_u128(rhs_offset); - // r = 2^bit_size - rhs_offset -1, is of bit size 'bit_size' by construtction - let r = (1_u128 << bit_size) - rhs_offset - 1; - // however, since it is a constant, we can compute it's actual bit size - let r_bit_size = bit_size_u128(r); - // witness = lhs_offset + r - assert!(bits + r_bit_size < FieldElement::max_num_bits()); //we need to ensure lhs_offset + r does not overflow - let mut aor = lhs_offset; - aor.q_c += FieldElement::from(r); - let witness = self.get_or_create_witness(&aor); - // lhs_offset<=rhs_offset <=> lhs_offset + r < rhs_offset + r = 2^bit_size <=> witness < 2^bit_size - self.range_constraint(witness, bit_size)?; - return Ok(()); - } - // General case: lhs_offset<=rhs <=> rhs-lhs_offset>=0 <=> rhs-lhs_offset is a 'bits' bit integer - let sub_expression = rhs - &lhs_offset; //rhs-lhs_offset - let w = self.create_witness_for_expression(&sub_expression); - self.range_constraint(w, bits)?; - - Ok(()) - } - /// Adds an inversion brillig opcode. /// /// This code will invert `expr` without applying constraints @@ -786,75 +493,6 @@ impl GeneratedAcir { Ok(()) } - /// Returns a `Witness` that is constrained to be: - /// - `1` if lhs >= rhs - /// - `0` otherwise - /// - /// We essentially computes the sign bit of `b-a` - /// For this we sign-extend `b-a` with `c = 2^{max_bits} - (b - a)`, since both `a` and `b` are less than `2^{max_bits}` - /// Then we get the bit sign of `c`, the 2-complement representation of `(b-a)`, which is a `max_bits+1` integer, - /// by doing the euclidean division `c / 2^{max_bits}` - /// - /// To see why it really works; - /// We first note that `c` is an integer of `(max_bits+1)` bits. Therefore, - /// if `b-a>0`, then `c < 2^{max_bits}`, so the division by `2^{max_bits}` will give `0` - /// If `b-a<=0`, then `c >= 2^{max_bits}`, so the division by `2^{max_bits}` will give `1`. - /// - /// In other words, `1` means `a >= b` and `0` means `b > a`. - /// The important thing here is that `c` does not overflow nor underflow the field; - /// - By construction we have `c >= 0`, so there is no underflow - /// - We assert at the beginning that `2^{max_bits+1}` does not overflow the field, so neither c. - pub(crate) fn more_than_eq_comparison( - &mut self, - a: &Expression, - b: &Expression, - max_bits: u32, - predicate: Expression, - ) -> Result { - // Ensure that 2^{max_bits + 1} is less than the field size - // - // TODO: perhaps this should be a user error, instead of an assert - assert!(max_bits + 1 < FieldElement::max_num_bits()); - - // Compute : 2^{max_bits} + a - b - let two = FieldElement::from(2_i128); - let two_max_bits: FieldElement = two.pow(&FieldElement::from(max_bits as i128)); - let comparison_evaluation = (a - b) + two_max_bits; - - // euclidean division by 2^{max_bits} : 2^{max_bits} + a - b = q * 2^{max_bits} + r - // - // 2^{max_bits} is of max_bits+1 bit size - // If a>b, then a-b is less than 2^{max_bits} - 1, so 2^{max_bits} + a - b is less than 2^{max_bits} + 2^{max_bits} - 1 = 2^{max_bits+1} - 1 - // If a <= b, then 2^{max_bits} + a - b is less than 2^{max_bits} <= 2^{max_bits+1} - 1 - // This means that both operands of the division have at most max_bits+1 bit size. - // - // case: a == b - // - // let k = 0; - // - 2^{max_bits} == q * 2^{max_bits} + r - // - This is only the case when q == 1 and r == 0 (assuming r is bounded to be less than 2^{max_bits}) - // - // case: a > b - // - // let k = a - b; - // - k + 2^{max_bits} == q * 2^{max_bits} + r - // - This is the case when q == 1 and r = k - // - // case: a < b - // - // let k = b - a - // - 2^{max_bits} - k == q * 2^{max_bits} + r - // - This is only the case when q == 0 and r == 2^{max_bits} - k - // - let (q, _) = self.euclidean_division( - &comparison_evaluation, - &Expression::from(two_max_bits), - max_bits + 1, - &predicate, - )?; - Ok(q) - } - pub(crate) fn brillig( &mut self, predicate: Option, @@ -933,7 +571,8 @@ fn black_box_func_expected_input_size(name: BlackBoxFunc) -> Option { BlackBoxFunc::Keccak256 | BlackBoxFunc::SHA256 | BlackBoxFunc::Blake2s - | BlackBoxFunc::Pedersen + | BlackBoxFunc::PedersenCommitment + | BlackBoxFunc::PedersenHash | BlackBoxFunc::HashToField128Security => None, // Can only apply a range constraint to one @@ -964,8 +603,10 @@ fn black_box_expected_output_size(name: BlackBoxFunc) -> Option { BlackBoxFunc::Keccak256 | BlackBoxFunc::SHA256 | BlackBoxFunc::Blake2s => Some(32), // Hash to field returns a field element BlackBoxFunc::HashToField128Security => Some(1), - // Pedersen returns a point - BlackBoxFunc::Pedersen => Some(2), + // Pedersen commitment returns a point + BlackBoxFunc::PedersenCommitment => Some(2), + // Pedersen hash returns a field + BlackBoxFunc::PedersenHash => Some(1), // Can only apply a range constraint to one // witness at a time. BlackBoxFunc::RANGE => Some(0), diff --git a/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs b/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs index 546a614a27f..155e5a7baba 100644 --- a/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs @@ -183,6 +183,10 @@ impl FunctionBuilder { self } + pub(crate) fn get_call_stack(&self) -> CallStack { + self.call_stack.clone() + } + /// Insert a Load instruction at the end of the current block, loading from the given offset /// of the given address which should point to a previous Allocate instruction. Note that /// this is limited to loading a single value. Loading multiple values (such as a tuple) diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs index 26d6739902d..b07e2df7bd3 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs @@ -413,7 +413,10 @@ fn simplify_black_box_func( simplify_signature(dfg, arguments, acvm::blackbox_solver::ecdsa_secp256r1_verify) } - BlackBoxFunc::FixedBaseScalarMul | BlackBoxFunc::SchnorrVerify | BlackBoxFunc::Pedersen => { + BlackBoxFunc::FixedBaseScalarMul + | BlackBoxFunc::SchnorrVerify + | BlackBoxFunc::PedersenCommitment + | BlackBoxFunc::PedersenHash => { // Currently unsolvable here as we rely on an implementation in the backend. SimplifyResult::None } diff --git a/compiler/noirc_evaluator/src/ssa/ir/types.rs b/compiler/noirc_evaluator/src/ssa/ir/types.rs index b576ee12d45..e69e936372d 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/types.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/types.rs @@ -1,5 +1,6 @@ use std::rc::Rc; +use acvm::FieldElement; use iter_extended::vecmap; /// A numeric type in the Intermediate representation @@ -11,7 +12,7 @@ use iter_extended::vecmap; /// Fields do not have a notion of ordering, so this distinction /// is reasonable. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)] -pub(crate) enum NumericType { +pub enum NumericType { Signed { bit_size: u32 }, Unsigned { bit_size: u32 }, NativeField, @@ -94,6 +95,26 @@ impl Type { } } +impl NumericType { + /// Returns true if the given Field value is within the numeric limits + /// for the current NumericType. + pub(crate) fn value_is_within_limits(self, field: FieldElement) -> bool { + match self { + NumericType::Signed { bit_size } => { + let min = -(2i128.pow(bit_size - 1)); + let max = 2u128.pow(bit_size - 1) - 1; + // Signed integers are odd since they will overflow the field value + field <= max.into() || field >= min.into() + } + NumericType::Unsigned { bit_size } => { + let max = 2u128.pow(bit_size) - 1; + field <= max.into() + } + NumericType::NativeField => true, + } + } +} + /// Composite Types are essentially flattened struct or tuple types. /// Array types may have these as elements where each flattened field is /// included in the array sequentially. diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs index 44dc8b098e7..f35e8023584 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs @@ -1284,8 +1284,8 @@ mod test { let zero = builder.field_constant(0_u128); let zero_array = builder.array_constant(im::Vector::unit(zero), array_type); let i_zero = builder.numeric_constant(0_u128, Type::unsigned(32)); - let pedersen = - builder.import_intrinsic_id(Intrinsic::BlackBox(acvm::acir::BlackBoxFunc::Pedersen)); + let pedersen = builder + .import_intrinsic_id(Intrinsic::BlackBox(acvm::acir::BlackBoxFunc::PedersenCommitment)); let v4 = builder.insert_call( pedersen, vec![zero_array, i_zero], diff --git a/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs b/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs index 142e9f81397..26c818250dc 100644 --- a/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs +++ b/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs @@ -8,6 +8,7 @@ use noirc_frontend::monomorphization::ast::{self, LocalId, Parameters}; use noirc_frontend::monomorphization::ast::{FuncId, Program}; use noirc_frontend::{BinaryOpKind, Signedness}; +use crate::errors::RuntimeError; use crate::ssa::function_builder::FunctionBuilder; use crate::ssa::ir::dfg::DataFlowGraph; use crate::ssa::ir::function::FunctionId as IrFunctionId; @@ -240,6 +241,30 @@ impl<'a> FunctionContext<'a> { Values::empty() } + /// Insert a numeric constant into the current function + /// + /// Unlike FunctionBuilder::numeric_constant, this version checks the given constant + /// is within the range of the given type. This is needed for user provided values where + /// otherwise values like 2^128 can be assigned to a u8 without error or wrapping. + pub(super) fn checked_numeric_constant( + &mut self, + value: impl Into, + typ: Type, + ) -> Result { + let value = value.into(); + + if let Type::Numeric(typ) = typ { + if !typ.value_is_within_limits(value) { + let call_stack = self.builder.get_call_stack(); + return Err(RuntimeError::IntegerOutOfBounds { value, typ, call_stack }); + } + } else { + panic!("Expected type for numeric constant to be a numeric type, found {typ}"); + } + + Ok(self.builder.numeric_constant(value, typ)) + } + /// Insert ssa instructions which computes lhs << rhs by doing lhs*2^rhs fn insert_shift_left(&mut self, lhs: ValueId, rhs: ValueId) -> ValueId { let base = self.builder.field_constant(FieldElement::from(2_u128)); @@ -544,8 +569,11 @@ impl<'a> FunctionContext<'a> { /// This is operationally equivalent to extract_current_value_recursive, but splitting these /// into two separate functions avoids cloning the outermost `Values` returned by the recursive /// version, as it is only needed for recursion. - pub(super) fn extract_current_value(&mut self, lvalue: &ast::LValue) -> LValue { - match lvalue { + pub(super) fn extract_current_value( + &mut self, + lvalue: &ast::LValue, + ) -> Result { + Ok(match lvalue { ast::LValue::Ident(ident) => { let (reference, should_auto_deref) = self.ident_lvalue(ident); if should_auto_deref { @@ -555,18 +583,18 @@ impl<'a> FunctionContext<'a> { } } ast::LValue::Index { array, index, location, .. } => { - self.index_lvalue(array, index, location).2 + self.index_lvalue(array, index, location)?.2 } ast::LValue::MemberAccess { object, field_index } => { - let (old_object, object_lvalue) = self.extract_current_value_recursive(object); + let (old_object, object_lvalue) = self.extract_current_value_recursive(object)?; let object_lvalue = Box::new(object_lvalue); LValue::MemberAccess { old_object, object_lvalue, index: *field_index } } ast::LValue::Dereference { reference, .. } => { - let (reference, _) = self.extract_current_value_recursive(reference); + let (reference, _) = self.extract_current_value_recursive(reference)?; LValue::Dereference { reference } } - } + }) } fn dereference_lvalue(&mut self, values: &Values, element_type: &ast::Type) -> Values { @@ -596,16 +624,16 @@ impl<'a> FunctionContext<'a> { array: &ast::LValue, index: &ast::Expression, location: &Location, - ) -> (ValueId, ValueId, LValue, Option) { - let (old_array, array_lvalue) = self.extract_current_value_recursive(array); - let index = self.codegen_non_tuple_expression(index); + ) -> Result<(ValueId, ValueId, LValue, Option), RuntimeError> { + let (old_array, array_lvalue) = self.extract_current_value_recursive(array)?; + let index = self.codegen_non_tuple_expression(index)?; let array_lvalue = Box::new(array_lvalue); let array_values = old_array.clone().into_value_list(self); let location = *location; // A slice is represented as a tuple (length, slice contents). // We need to fetch the second value. - if array_values.len() > 1 { + Ok(if array_values.len() > 1 { let slice_lvalue = LValue::SliceIndex { old_slice: old_array, index, @@ -617,37 +645,45 @@ impl<'a> FunctionContext<'a> { let array_lvalue = LValue::Index { old_array: array_values[0], index, array_lvalue, location }; (array_values[0], index, array_lvalue, None) - } + }) } - fn extract_current_value_recursive(&mut self, lvalue: &ast::LValue) -> (Values, LValue) { + fn extract_current_value_recursive( + &mut self, + lvalue: &ast::LValue, + ) -> Result<(Values, LValue), RuntimeError> { match lvalue { ast::LValue::Ident(ident) => { let (variable, should_auto_deref) = self.ident_lvalue(ident); if should_auto_deref { let dereferenced = self.dereference_lvalue(&variable, &ident.typ); - (dereferenced, LValue::Dereference { reference: variable }) + Ok((dereferenced, LValue::Dereference { reference: variable })) } else { - (variable.clone(), LValue::Ident) + Ok((variable.clone(), LValue::Ident)) } } ast::LValue::Index { array, index, element_type, location } => { let (old_array, index, index_lvalue, max_length) = - self.index_lvalue(array, index, location); - let element = - self.codegen_array_index(old_array, index, element_type, *location, max_length); - (element, index_lvalue) + self.index_lvalue(array, index, location)?; + let element = self.codegen_array_index( + old_array, + index, + element_type, + *location, + max_length, + )?; + Ok((element, index_lvalue)) } ast::LValue::MemberAccess { object, field_index: index } => { - let (old_object, object_lvalue) = self.extract_current_value_recursive(object); + let (old_object, object_lvalue) = self.extract_current_value_recursive(object)?; let object_lvalue = Box::new(object_lvalue); let element = Self::get_field_ref(&old_object, *index).clone(); - (element, LValue::MemberAccess { old_object, object_lvalue, index: *index }) + Ok((element, LValue::MemberAccess { old_object, object_lvalue, index: *index })) } ast::LValue::Dereference { reference, element_type } => { - let (reference, _) = self.extract_current_value_recursive(reference); + let (reference, _) = self.extract_current_value_recursive(reference)?; let dereferenced = self.dereference_lvalue(&reference, element_type); - (dereferenced, LValue::Dereference { reference }) + Ok((dereferenced, LValue::Dereference { reference })) } } } diff --git a/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs b/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs index d990a95c540..7677f5669cb 100644 --- a/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs @@ -5,14 +5,17 @@ mod value; pub(crate) use program::Ssa; use context::SharedContext; -use iter_extended::vecmap; +use iter_extended::{try_vecmap, vecmap}; use noirc_errors::Location; use noirc_frontend::{ monomorphization::ast::{self, Binary, Expression, Program}, BinaryOpKind, }; -use crate::ssa::ir::{instruction::Intrinsic, types::NumericType}; +use crate::{ + errors::RuntimeError, + ssa::ir::{instruction::Intrinsic, types::NumericType}, +}; use self::{ context::FunctionContext, @@ -29,7 +32,7 @@ use super::ir::{ /// Generates SSA for the given monomorphized program. /// /// This function will generate the SSA but does not perform any optimizations on it. -pub(crate) fn generate_ssa(program: Program) -> Ssa { +pub(crate) fn generate_ssa(program: Program) -> Result { let return_location = program.return_location; let context = SharedContext::new(program); @@ -45,7 +48,7 @@ pub(crate) fn generate_ssa(program: Program) -> Ssa { if main.unconstrained { RuntimeType::Brillig } else { RuntimeType::Acir }, &context, ); - function_context.codegen_function_body(&main.body); + function_context.codegen_function_body(&main.body)?; if let Some(return_location) = return_location { let block = function_context.builder.current_block(); @@ -69,24 +72,25 @@ pub(crate) fn generate_ssa(program: Program) -> Ssa { while let Some((src_function_id, dest_id)) = context.pop_next_function_in_queue() { let function = &context.program[src_function_id]; function_context.new_function(dest_id, function); - function_context.codegen_function_body(&function.body); + function_context.codegen_function_body(&function.body)?; } - function_context.builder.finish() + Ok(function_context.builder.finish()) } impl<'a> FunctionContext<'a> { /// Codegen a function's body and set its return value to that of its last parameter. /// For functions returning nothing, this will be an empty list. - fn codegen_function_body(&mut self, body: &Expression) { - let return_value = self.codegen_expression(body); + fn codegen_function_body(&mut self, body: &Expression) -> Result<(), RuntimeError> { + let return_value = self.codegen_expression(body)?; let results = return_value.into_value_list(self); self.builder.terminate_with_return(results); + Ok(()) } - fn codegen_expression(&mut self, expr: &Expression) -> Values { + fn codegen_expression(&mut self, expr: &Expression) -> Result { match expr { - Expression::Ident(ident) => self.codegen_ident(ident), + Expression::Ident(ident) => Ok(self.codegen_ident(ident)), Expression::Literal(literal) => self.codegen_literal(literal), Expression::Block(block) => self.codegen_block(block), Expression::Unary(unary) => self.codegen_unary(unary), @@ -111,8 +115,8 @@ impl<'a> FunctionContext<'a> { /// Codegen any non-tuple expression so that we can unwrap the Values /// tree to return a single value for use with most SSA instructions. - fn codegen_non_tuple_expression(&mut self, expr: &Expression) -> ValueId { - self.codegen_expression(expr).into_leaf().eval(self) + fn codegen_non_tuple_expression(&mut self, expr: &Expression) -> Result { + Ok(self.codegen_expression(expr)?.into_leaf().eval(self)) } /// Codegen a reference to an ident. @@ -140,17 +144,19 @@ impl<'a> FunctionContext<'a> { self.codegen_ident_reference(ident).map(|value| value.eval(self).into()) } - fn codegen_literal(&mut self, literal: &ast::Literal) -> Values { + fn codegen_literal(&mut self, literal: &ast::Literal) -> Result { match literal { ast::Literal::Array(array) => { - let elements = vecmap(&array.contents, |element| self.codegen_expression(element)); + let elements = + try_vecmap(&array.contents, |element| self.codegen_expression(element))?; let typ = Self::convert_type(&array.typ).flatten(); - match array.typ { + Ok(match array.typ { ast::Type::Array(_, _) => self.codegen_array(elements, typ[0].clone()), ast::Type::Slice(_) => { let slice_length = self.builder.field_constant(array.contents.len() as u128); + let slice_contents = self.codegen_array(elements, typ[1].clone()); Tree::Branch(vec![slice_length.into(), slice_contents]) } @@ -158,37 +164,37 @@ impl<'a> FunctionContext<'a> { "ICE: array literal type must be an array or a slice, but got {}", array.typ ), - } + }) } - ast::Literal::Integer(value, typ) => { + ast::Literal::Integer(value, typ, location) => { + self.builder.set_location(*location); let typ = Self::convert_non_tuple_type(typ); - self.builder.numeric_constant(*value, typ).into() + self.checked_numeric_constant(*value, typ).map(Into::into) } ast::Literal::Bool(value) => { - self.builder.numeric_constant(*value as u128, Type::bool()).into() - } - ast::Literal::Str(string) => { - let elements = vecmap(string.as_bytes(), |byte| { - self.builder.numeric_constant(*byte as u128, Type::field()).into() - }); - let typ = Self::convert_non_tuple_type(&ast::Type::String(elements.len() as u64)); - self.codegen_array(elements, typ) + // Don't need to call checked_numeric_constant here since `value` can only be true or false + Ok(self.builder.numeric_constant(*value as u128, Type::bool()).into()) } + ast::Literal::Str(string) => Ok(self.codegen_string(string)), ast::Literal::FmtStr(string, number_of_fields, fields) => { // A caller needs multiple pieces of information to make use of a format string // The message string, the number of fields to be formatted, and the fields themselves - let string = Expression::Literal(ast::Literal::Str(string.clone())); - let number_of_fields = Expression::Literal(ast::Literal::Integer( - (*number_of_fields as u128).into(), - ast::Type::Field, - )); - let fields = *fields.clone(); - let fmt_str_tuple = &[string, number_of_fields, fields]; - self.codegen_tuple(fmt_str_tuple) + let string = self.codegen_string(string); + let field_count = self.builder.field_constant(*number_of_fields as u128); + let fields = self.codegen_expression(fields)?; + + Ok(Tree::Branch(vec![string, field_count.into(), fields])) } } } + fn codegen_string(&mut self, string: &str) -> Values { + let elements = + vecmap(string.as_bytes(), |byte| self.builder.field_constant(*byte as u128).into()); + let typ = Self::convert_non_tuple_type(&ast::Type::String(elements.len() as u64)); + self.codegen_array(elements, typ) + } + /// Codegen an array by allocating enough space for each element and inserting separate /// store instructions until each element is stored. The store instructions will be separated /// by add instructions to calculate the new offset address to store to next. @@ -211,35 +217,35 @@ impl<'a> FunctionContext<'a> { self.builder.array_constant(array, typ).into() } - fn codegen_block(&mut self, block: &[Expression]) -> Values { + fn codegen_block(&mut self, block: &[Expression]) -> Result { let mut result = Self::unit_value(); for expr in block { - result = self.codegen_expression(expr); + result = self.codegen_expression(expr)?; } - result + Ok(result) } - fn codegen_unary(&mut self, unary: &ast::Unary) -> Values { + fn codegen_unary(&mut self, unary: &ast::Unary) -> Result { match unary.operator { noirc_frontend::UnaryOp::Not => { - let rhs = self.codegen_expression(&unary.rhs); + let rhs = self.codegen_expression(&unary.rhs)?; let rhs = rhs.into_leaf().eval(self); - self.builder.insert_not(rhs).into() + Ok(self.builder.insert_not(rhs).into()) } noirc_frontend::UnaryOp::Minus => { - let rhs = self.codegen_expression(&unary.rhs); + let rhs = self.codegen_expression(&unary.rhs)?; let rhs = rhs.into_leaf().eval(self); let typ = self.builder.type_of_value(rhs); let zero = self.builder.numeric_constant(0u128, typ); - self.insert_binary( + Ok(self.insert_binary( zero, noirc_frontend::BinaryOpKind::Subtract, rhs, unary.location, - ) + )) } noirc_frontend::UnaryOp::MutableReference => { - self.codegen_reference(&unary.rhs).map(|rhs| { + Ok(self.codegen_reference(&unary.rhs)?.map(|rhs| { match rhs { value::Value::Normal(value) => { let alloc = self.builder.insert_allocate(); @@ -250,11 +256,11 @@ impl<'a> FunctionContext<'a> { // a Value::Normal so it is no longer automatically dereferenced. value::Value::Mutable(reference, _) => reference.into(), } - }) + })) } noirc_frontend::UnaryOp::Dereference { .. } => { - let rhs = self.codegen_expression(&unary.rhs); - self.dereference(&rhs, &unary.result_type) + let rhs = self.codegen_expression(&unary.rhs)?; + Ok(self.dereference(&rhs, &unary.result_type)) } } } @@ -267,26 +273,26 @@ impl<'a> FunctionContext<'a> { }) } - fn codegen_reference(&mut self, expr: &Expression) -> Values { + fn codegen_reference(&mut self, expr: &Expression) -> Result { match expr { - Expression::Ident(ident) => self.codegen_ident_reference(ident), + Expression::Ident(ident) => Ok(self.codegen_ident_reference(ident)), Expression::ExtractTupleField(tuple, index) => { - let tuple = self.codegen_reference(tuple); - Self::get_field(tuple, *index) + let tuple = self.codegen_reference(tuple)?; + Ok(Self::get_field(tuple, *index)) } other => self.codegen_expression(other), } } - fn codegen_binary(&mut self, binary: &ast::Binary) -> Values { - let lhs = self.codegen_non_tuple_expression(&binary.lhs); - let rhs = self.codegen_non_tuple_expression(&binary.rhs); - self.insert_binary(lhs, binary.operator, rhs, binary.location) + fn codegen_binary(&mut self, binary: &ast::Binary) -> Result { + let lhs = self.codegen_non_tuple_expression(&binary.lhs)?; + let rhs = self.codegen_non_tuple_expression(&binary.rhs)?; + Ok(self.insert_binary(lhs, binary.operator, rhs, binary.location)) } - fn codegen_index(&mut self, index: &ast::Index) -> Values { - let array_or_slice = self.codegen_expression(&index.collection).into_value_list(self); - let index_value = self.codegen_non_tuple_expression(&index.index); + fn codegen_index(&mut self, index: &ast::Index) -> Result { + let array_or_slice = self.codegen_expression(&index.collection)?.into_value_list(self); + let index_value = self.codegen_non_tuple_expression(&index.index)?; // Slices are represented as a tuple in the form: (length, slice contents). // Thus, slices require two value ids for their representation. let (array, slice_length) = if array_or_slice.len() > 1 { @@ -316,7 +322,7 @@ impl<'a> FunctionContext<'a> { element_type: &ast::Type, location: Location, length: Option, - ) -> Values { + ) -> Result { // base_index = index * type_size let type_size = Self::convert_type(element_type).size_of_type(); let type_size = self.builder.field_constant(type_size as u128); @@ -324,7 +330,7 @@ impl<'a> FunctionContext<'a> { self.builder.set_location(location).insert_binary(index, BinaryOp::Mul, type_size); let mut field_index = 0u128; - Self::map_type(element_type, |typ| { + Ok(Self::map_type(element_type, |typ| { let offset = self.make_offset(base_index, field_index); field_index += 1; @@ -339,7 +345,7 @@ impl<'a> FunctionContext<'a> { _ => unreachable!("must have array or slice but got {array_type}"), } self.builder.insert_array_get(array, offset, typ).into() - }) + })) } /// Prepare a slice access. @@ -374,11 +380,11 @@ impl<'a> FunctionContext<'a> { ); } - fn codegen_cast(&mut self, cast: &ast::Cast) -> Values { - let lhs = self.codegen_non_tuple_expression(&cast.lhs); + fn codegen_cast(&mut self, cast: &ast::Cast) -> Result { + let lhs = self.codegen_non_tuple_expression(&cast.lhs)?; let typ = Self::convert_non_tuple_type(&cast.r#type); self.builder.set_location(cast.location); - self.builder.insert_cast(lhs, typ).into() + Ok(self.builder.insert_cast(lhs, typ).into()) } /// Codegens a for loop, creating three new blocks in the process. @@ -398,7 +404,7 @@ impl<'a> FunctionContext<'a> { /// br loop_entry(v4) /// loop_end(): /// ... This is the current insert point after codegen_for finishes ... - fn codegen_for(&mut self, for_expr: &ast::For) -> Values { + fn codegen_for(&mut self, for_expr: &ast::For) -> Result { let loop_entry = self.builder.insert_block(); let loop_body = self.builder.insert_block(); let loop_end = self.builder.insert_block(); @@ -408,10 +414,10 @@ impl<'a> FunctionContext<'a> { let loop_index = self.builder.add_block_parameter(loop_entry, index_type); self.builder.set_location(for_expr.start_range_location); - let start_index = self.codegen_non_tuple_expression(&for_expr.start_range); + let start_index = self.codegen_non_tuple_expression(&for_expr.start_range)?; self.builder.set_location(for_expr.end_range_location); - let end_index = self.codegen_non_tuple_expression(&for_expr.end_range); + let end_index = self.codegen_non_tuple_expression(&for_expr.end_range)?; // Set the location of the initial jmp instruction to the start range. This is the location // used to issue an error if the start range cannot be determined at compile-time. @@ -431,13 +437,13 @@ impl<'a> FunctionContext<'a> { // Compile the loop body self.builder.switch_to_block(loop_body); self.define(for_expr.index_variable, loop_index.into()); - self.codegen_expression(&for_expr.block); + self.codegen_expression(&for_expr.block)?; let new_loop_index = self.make_offset(loop_index, 1); self.builder.terminate_with_jmp(loop_entry, vec![new_loop_index]); // Finish by switching back to the end of the loop self.builder.switch_to_block(loop_end); - Self::unit_value() + Ok(Self::unit_value()) } /// Codegens an if expression, handling the case of what to do if there is no 'else'. @@ -464,8 +470,8 @@ impl<'a> FunctionContext<'a> { /// br end_if() /// end_if: // No block parameter is needed. Without an else, the unit value is always returned. /// ... This is the current insert point after codegen_if finishes ... - fn codegen_if(&mut self, if_expr: &ast::If) -> Values { - let condition = self.codegen_non_tuple_expression(&if_expr.condition); + fn codegen_if(&mut self, if_expr: &ast::If) -> Result { + let condition = self.codegen_non_tuple_expression(&if_expr.condition)?; let then_block = self.builder.insert_block(); let else_block = self.builder.insert_block(); @@ -473,7 +479,7 @@ impl<'a> FunctionContext<'a> { self.builder.terminate_with_jmpif(condition, then_block, else_block); self.builder.switch_to_block(then_block); - let then_value = self.codegen_expression(&if_expr.consequence); + let then_value = self.codegen_expression(&if_expr.consequence)?; let mut result = Self::unit_value(); @@ -483,7 +489,7 @@ impl<'a> FunctionContext<'a> { self.builder.terminate_with_jmp(end_block, then_values); self.builder.switch_to_block(else_block); - let else_value = self.codegen_expression(alternative); + let else_value = self.codegen_expression(alternative)?; let else_values = else_value.into_value_list(self); self.builder.terminate_with_jmp(end_block, else_values); @@ -501,31 +507,36 @@ impl<'a> FunctionContext<'a> { self.builder.switch_to_block(else_block); } - result + Ok(result) } - fn codegen_tuple(&mut self, tuple: &[Expression]) -> Values { - Tree::Branch(vecmap(tuple, |expr| self.codegen_expression(expr))) + fn codegen_tuple(&mut self, tuple: &[Expression]) -> Result { + Ok(Tree::Branch(try_vecmap(tuple, |expr| self.codegen_expression(expr))?)) } - fn codegen_extract_tuple_field(&mut self, tuple: &Expression, field_index: usize) -> Values { - let tuple = self.codegen_expression(tuple); - Self::get_field(tuple, field_index) + fn codegen_extract_tuple_field( + &mut self, + tuple: &Expression, + field_index: usize, + ) -> Result { + let tuple = self.codegen_expression(tuple)?; + Ok(Self::get_field(tuple, field_index)) } /// Generate SSA for a function call. Note that calls to built-in functions /// and intrinsics are also represented by the function call instruction. - fn codegen_call(&mut self, call: &ast::Call) -> Values { - let function = self.codegen_non_tuple_expression(&call.func); - let arguments = call - .arguments - .iter() - .flat_map(|argument| self.codegen_expression(argument).into_value_list(self)) - .collect::>(); + fn codegen_call(&mut self, call: &ast::Call) -> Result { + let function = self.codegen_non_tuple_expression(&call.func)?; + let mut arguments = Vec::with_capacity(call.arguments.len()); + + for argument in &call.arguments { + let mut values = self.codegen_expression(argument)?.into_value_list(self); + arguments.append(&mut values); + } self.codegen_intrinsic_call_checks(function, &arguments, call.location); - self.insert_call(function, arguments, &call.return_type, call.location) + Ok(self.insert_call(function, arguments, &call.return_type, call.location)) } fn codegen_intrinsic_call_checks( @@ -539,7 +550,8 @@ impl<'a> FunctionContext<'a> { { match intrinsic { Intrinsic::SliceInsert => { - let one = self.builder.numeric_constant(1u128, Type::field()); + let one = self.builder.field_constant(1u128); + // We add one here in the case of a slice insert as a slice insert at the length of the slice // can be converted to a slice push back let len_plus_one = self.builder.insert_binary(arguments[0], BinaryOp::Add, one); @@ -560,8 +572,8 @@ impl<'a> FunctionContext<'a> { /// If the variable is immutable, no special handling is necessary and we can return the given /// ValueId directly. If it is mutable, we'll need to allocate space for the value and store /// the initial value before returning the allocate instruction. - fn codegen_let(&mut self, let_expr: &ast::Let) -> Values { - let mut values = self.codegen_expression(&let_expr.expression); + fn codegen_let(&mut self, let_expr: &ast::Let) -> Result { + let mut values = self.codegen_expression(&let_expr.expression)?; if let_expr.mutable { values = values.map(|value| { @@ -571,7 +583,7 @@ impl<'a> FunctionContext<'a> { } self.define(let_expr.id, values); - Self::unit_value() + Ok(Self::unit_value()) } fn codegen_constrain( @@ -579,17 +591,17 @@ impl<'a> FunctionContext<'a> { expr: &Expression, location: Location, assert_message: Option, - ) -> Values { + ) -> Result { match expr { // If we're constraining an equality to be true then constrain the two sides directly. Expression::Binary(Binary { lhs, operator: BinaryOpKind::Equal, rhs, .. }) => { - let lhs = self.codegen_non_tuple_expression(lhs); - let rhs = self.codegen_non_tuple_expression(rhs); + let lhs = self.codegen_non_tuple_expression(lhs)?; + let rhs = self.codegen_non_tuple_expression(rhs)?; self.builder.set_location(location).insert_constrain(lhs, rhs, assert_message); } _ => { - let expr = self.codegen_non_tuple_expression(expr); + let expr = self.codegen_non_tuple_expression(expr)?; let true_literal = self.builder.numeric_constant(true, Type::bool()); self.builder.set_location(location).insert_constrain( expr, @@ -598,19 +610,19 @@ impl<'a> FunctionContext<'a> { ); } } - Self::unit_value() + Ok(Self::unit_value()) } - fn codegen_assign(&mut self, assign: &ast::Assign) -> Values { - let lhs = self.extract_current_value(&assign.lvalue); - let rhs = self.codegen_expression(&assign.expression); + fn codegen_assign(&mut self, assign: &ast::Assign) -> Result { + let lhs = self.extract_current_value(&assign.lvalue)?; + let rhs = self.codegen_expression(&assign.expression)?; self.assign_new_value(lhs, rhs); - Self::unit_value() + Ok(Self::unit_value()) } - fn codegen_semi(&mut self, expr: &Expression) -> Values { - self.codegen_expression(expr); - Self::unit_value() + fn codegen_semi(&mut self, expr: &Expression) -> Result { + self.codegen_expression(expr)?; + Ok(Self::unit_value()) } } diff --git a/compiler/noirc_frontend/Cargo.toml b/compiler/noirc_frontend/Cargo.toml index 1cb6e0c5c51..6cc7b07126c 100644 --- a/compiler/noirc_frontend/Cargo.toml +++ b/compiler/noirc_frontend/Cargo.toml @@ -18,6 +18,7 @@ chumsky.workspace = true thiserror.workspace = true smol_str.workspace = true serde_json.workspace = true +serde.workspace = true rustc-hash = "1.1.0" small-ord-set = "0.1.3" regex = "1.9.1" @@ -27,4 +28,5 @@ strum = "0.24" strum_macros = "0.24" [features] -aztec = [] \ No newline at end of file +default = [] +aztec = [] diff --git a/compiler/noirc_frontend/src/ast/expression.rs b/compiler/noirc_frontend/src/ast/expression.rs index 4c8e98a0d4d..66b94797822 100644 --- a/compiler/noirc_frontend/src/ast/expression.rs +++ b/compiler/noirc_frontend/src/ast/expression.rs @@ -3,7 +3,7 @@ use std::fmt::Display; use crate::token::{Attributes, Token}; use crate::{ - Distinctness, Ident, Path, Pattern, Recoverable, Statement, StatementKind, + Distinctness, FunctionVisibility, Ident, Path, Pattern, Recoverable, Statement, StatementKind, UnresolvedTraitConstraint, UnresolvedType, UnresolvedTypeData, Visibility, }; use acvm::FieldElement; @@ -366,8 +366,8 @@ pub struct FunctionDefinition { /// True if this function was defined with the 'unconstrained' keyword pub is_unconstrained: bool, - /// True if this function was defined with the 'pub' keyword - pub is_public: bool, + /// Indicate if this function was defined with the 'pub' keyword + pub visibility: FunctionVisibility, pub generics: UnresolvedGenerics, pub parameters: Vec<(Pattern, UnresolvedType, Visibility)>, @@ -644,7 +644,7 @@ impl FunctionDefinition { is_open: false, is_internal: false, is_unconstrained: false, - is_public: false, + visibility: FunctionVisibility::Private, generics: generics.clone(), parameters: p, body: body.clone(), diff --git a/compiler/noirc_frontend/src/ast/mod.rs b/compiler/noirc_frontend/src/ast/mod.rs index 662c3b28bef..7ce01f461ed 100644 --- a/compiler/noirc_frontend/src/ast/mod.rs +++ b/compiler/noirc_frontend/src/ast/mod.rs @@ -44,6 +44,9 @@ pub enum UnresolvedTypeData { /// A Named UnresolvedType can be a struct type or a type variable Named(Path, Vec), + /// A Trait as return type or parameter of function, including its generics + TraitAsType(Path, Vec), + /// &mut T MutableReference(Box), @@ -112,6 +115,14 @@ impl std::fmt::Display for UnresolvedTypeData { write!(f, "{}<{}>", s, args.join(", ")) } } + TraitAsType(s, args) => { + let args = vecmap(args, |arg| ToString::to_string(&arg.typ)); + if args.is_empty() { + write!(f, "impl {s}") + } else { + write!(f, "impl {}<{}>", s, args.join(", ")) + } + } Tuple(elements) => { let elements = vecmap(elements, ToString::to_string); write!(f, "({})", elements.join(", ")) @@ -259,6 +270,14 @@ impl UnresolvedTypeExpression { } } +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +/// Represents whether the function can be called outside its module/crate +pub enum FunctionVisibility { + Public, + Private, + PublicCrate, +} + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] /// Represents whether the parameter is public or known only to the prover. pub enum Visibility { diff --git a/compiler/noirc_frontend/src/ast/statement.rs b/compiler/noirc_frontend/src/ast/statement.rs index 639d4d8f763..9fe78f40c59 100644 --- a/compiler/noirc_frontend/src/ast/statement.rs +++ b/compiler/noirc_frontend/src/ast/statement.rs @@ -413,7 +413,14 @@ pub enum LValue { } #[derive(Debug, PartialEq, Eq, Clone)] -pub struct ConstrainStatement(pub Expression, pub Option); +pub struct ConstrainStatement(pub Expression, pub Option, pub ConstrainKind); + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum ConstrainKind { + Assert, + AssertEq, + Constrain, +} #[derive(Debug, PartialEq, Eq, Clone)] pub enum Pattern { diff --git a/compiler/noirc_frontend/src/graph/mod.rs b/compiler/noirc_frontend/src/graph/mod.rs index 3a40c87d8e7..452aef74b36 100644 --- a/compiler/noirc_frontend/src/graph/mod.rs +++ b/compiler/noirc_frontend/src/graph/mod.rs @@ -8,6 +8,7 @@ use std::{fmt::Display, str::FromStr}; use fm::FileId; use rustc_hash::{FxHashMap, FxHashSet}; +use serde::{Deserialize, Serialize}; use smol_str::SmolStr; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] @@ -32,7 +33,7 @@ impl CrateId { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, Serialize, Deserialize)] pub struct CrateName(SmolStr); impl CrateName { @@ -90,6 +91,11 @@ mod crate_name { assert!(!CrateName::is_valid_name(&bad_char_string)); } } + + #[test] + fn it_rejects_bad_crate_names_when_deserializing() { + assert!(serde_json::from_str::("bad-name").is_err()); + } } #[derive(Debug, Clone, Default, PartialEq, Eq)] diff --git a/compiler/noirc_frontend/src/hir/aztec_library.rs b/compiler/noirc_frontend/src/hir/aztec_library.rs index 6f988577839..24dd79efc6c 100644 --- a/compiler/noirc_frontend/src/hir/aztec_library.rs +++ b/compiler/noirc_frontend/src/hir/aztec_library.rs @@ -16,8 +16,8 @@ use crate::{ UnresolvedType, UnresolvedTypeData, Visibility, }; use crate::{ - ForLoopStatement, FunctionDefinition, ImportStatement, NoirStruct, PrefixExpression, - Signedness, StatementKind, StructType, Type, TypeImpl, UnaryOp, + ForLoopStatement, FunctionDefinition, FunctionVisibility, ImportStatement, NoirStruct, + PrefixExpression, Signedness, StatementKind, StructType, Type, TypeImpl, UnaryOp, }; use fm::FileId; @@ -434,7 +434,7 @@ fn generate_selector_impl(structure: &NoirStruct) -> TypeImpl { &FunctionReturnType::Ty(make_type(UnresolvedTypeData::FieldElement)), ); - selector_fn_def.is_public = true; + selector_fn_def.visibility = FunctionVisibility::Public; // Seems to be necessary on contract modules selector_fn_def.return_visibility = Visibility::Public; diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs index a458814ce9e..aa2bedb37b7 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -1173,6 +1173,11 @@ fn resolve_function_set( resolver.set_self_type(self_type.clone()); resolver.set_trait_id(unresolved_functions.trait_id); + // Without this, impl methods can accidentally be placed in contracts. See #3254 + if self_type.is_some() { + resolver.set_in_contract(false); + } + let (hir_func, func_meta, errs) = resolver.resolve_function(func, func_id); interner.push_fn_meta(func_meta, func_id); interner.update_fn(func_id, hir_func); diff --git a/compiler/noirc_frontend/src/hir/def_map/mod.rs b/compiler/noirc_frontend/src/hir/def_map/mod.rs index 006e00d2d07..345e5447bf5 100644 --- a/compiler/noirc_frontend/src/hir/def_map/mod.rs +++ b/compiler/noirc_frontend/src/hir/def_map/mod.rs @@ -173,9 +173,9 @@ impl CrateDefMap { .value_definitions() .filter_map(|id| { id.as_function().map(|function_id| { - let attributes = interner.function_attributes(&function_id); - let is_entry_point = !attributes.has_contract_library_method() - && !attributes.is_test_function(); + let is_entry_point = interner + .function_attributes(&function_id) + .is_contract_entry_point(); ContractFunctionMeta { function_id, is_entry_point } }) }) diff --git a/compiler/noirc_frontend/src/hir/resolution/errors.rs b/compiler/noirc_frontend/src/hir/resolution/errors.rs index 80a0b557465..c2f787313c6 100644 --- a/compiler/noirc_frontend/src/hir/resolution/errors.rs +++ b/compiler/noirc_frontend/src/hir/resolution/errors.rs @@ -78,6 +78,10 @@ pub enum ResolverError { InvalidClosureEnvironment { typ: Type, span: Span }, #[error("{name} is private and not visible from the current module")] PrivateFunctionCalled { name: String, span: Span }, + #[error("{name} is not visible from the current crate")] + NonCrateFunctionCalled { name: String, span: Span }, + #[error("Only sized types may be used in the entry point to a program")] + InvalidTypeForEntryPoint { span: Span }, } impl ResolverError { @@ -294,6 +298,12 @@ impl From for Diagnostic { ResolverError::PrivateFunctionCalled { span, name } => Diagnostic::simple_warning( format!("{name} is private and not visible from the current module"), format!("{name} is private"), span), + ResolverError::NonCrateFunctionCalled { span, name } => Diagnostic::simple_warning( + format!("{name} is not visible from the current crate"), + format!("{name} is only visible within its crate"), span), + ResolverError::InvalidTypeForEntryPoint { span } => Diagnostic::simple_error( + "Only sized types may be used in the entry point to a program".to_string(), + "Slices, references, or any type containing them may not be used in main or a contract function".to_string(), span), } } } diff --git a/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/compiler/noirc_frontend/src/hir/resolution/resolver.rs index f9bf01c0957..b3796418ab3 100644 --- a/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -36,10 +36,10 @@ use crate::{ StatementKind, }; use crate::{ - ArrayLiteral, ContractFunctionType, Distinctness, Generics, LValue, NoirStruct, NoirTypeAlias, - Path, PathKind, Pattern, Shared, StructType, Type, TypeAliasType, TypeBinding, TypeVariable, - UnaryOp, UnresolvedGenerics, UnresolvedTraitConstraint, UnresolvedType, UnresolvedTypeData, - UnresolvedTypeExpression, Visibility, ERROR_IDENT, + ArrayLiteral, ContractFunctionType, Distinctness, FunctionVisibility, Generics, LValue, + NoirStruct, NoirTypeAlias, Path, PathKind, Pattern, Shared, StructType, Type, TypeAliasType, + TypeBinding, TypeVariable, UnaryOp, UnresolvedGenerics, UnresolvedTraitConstraint, + UnresolvedType, UnresolvedTypeData, UnresolvedTypeExpression, Visibility, ERROR_IDENT, }; use fm::FileId; use iter_extended::vecmap; @@ -87,6 +87,14 @@ pub struct Resolver<'a> { /// Set to the current type if we're resolving an impl self_type: Option, + /// True if the current module is a contract. + /// This is usually determined by self.path_resolver.module_id(), but it can + /// be overriden for impls. Impls are an odd case since the methods within resolve + /// as if they're in the parent module, but should be placed in a child module. + /// Since they should be within a child module, in_contract is manually set to false + /// for these so we can still resolve them in the parent module without them being in a contract. + in_contract: bool, + /// Contains a mapping of the current struct or functions's generics to /// unique type variables if we're resolving a struct. Empty otherwise. /// This is a Vec rather than a map to preserve the order a functions generics @@ -119,6 +127,9 @@ impl<'a> Resolver<'a> { def_maps: &'a BTreeMap, file: FileId, ) -> Resolver<'a> { + let module_id = path_resolver.module_id(); + let in_contract = module_id.module(def_maps).is_contract; + Self { path_resolver, def_maps, @@ -131,6 +142,7 @@ impl<'a> Resolver<'a> { errors: Vec::new(), lambda_stack: Vec::new(), file, + in_contract, } } @@ -376,6 +388,8 @@ impl<'a> Resolver<'a> { Unspecified => Type::Error, Error => Type::Error, Named(path, args) => self.resolve_named_type(path, args, new_variables), + TraitAsType(path, args) => self.resolve_trait_as_type(path, args, new_variables), + Tuple(fields) => { Type::Tuple(vecmap(fields, |field| self.resolve_type_inner(field, new_variables))) } @@ -479,6 +493,19 @@ impl<'a> Resolver<'a> { } } + fn resolve_trait_as_type( + &mut self, + path: Path, + _args: Vec, + _new_variables: &mut Generics, + ) -> Type { + if let Some(t) = self.lookup_trait_or_error(path) { + Type::TraitAsType(t) + } else { + Type::Error + } + } + fn verify_generics_count( &mut self, expected_count: usize, @@ -721,6 +748,10 @@ impl<'a> Resolver<'a> { }); } + if self.is_entry_point_function(func) { + self.verify_type_valid_for_program_input(&typ); + } + let pattern = self.resolve_pattern(pattern, DefinitionKind::Local(None)); let typ = self.resolve_type_inner(typ, &mut generics); @@ -786,18 +817,33 @@ impl<'a> Resolver<'a> { } } + /// Override whether this name resolver is within a contract or not. + /// This will affect which types are allowed as parameters to methods as well + /// as which modifiers are allowed on a function. + pub(crate) fn set_in_contract(&mut self, in_contract: bool) { + self.in_contract = in_contract; + } + /// True if the 'pub' keyword is allowed on parameters in this function fn pub_allowed(&self, func: &NoirFunction) -> bool { - if self.in_contract() { + if self.in_contract { !func.def.is_unconstrained } else { func.name() == MAIN_FUNCTION } } + fn is_entry_point_function(&self, func: &NoirFunction) -> bool { + if self.in_contract { + func.attributes().is_contract_entry_point() + } else { + func.name() == MAIN_FUNCTION + } + } + /// True if the `distinct` keyword is allowed on a function's return type fn distinct_allowed(&self, func: &NoirFunction) -> bool { - if self.in_contract() { + if self.in_contract { // "open" and "unconstrained" functions are compiled to brillig and thus duplication of // witness indices in their abis is not a concern. !func.def.is_unconstrained && !func.def.is_open @@ -809,7 +855,7 @@ impl<'a> Resolver<'a> { fn handle_function_type(&mut self, function: &FuncId) { let function_type = self.interner.function_modifiers(function).contract_function_type; - if !self.in_contract() && function_type == Some(ContractFunctionType::Open) { + if !self.in_contract && function_type == Some(ContractFunctionType::Open) { let span = self.interner.function_ident(function).span(); self.errors.push(ResolverError::ContractFunctionTypeInNormalFunction { span }); self.interner.function_modifiers_mut(function).contract_function_type = None; @@ -817,7 +863,7 @@ impl<'a> Resolver<'a> { } fn handle_is_function_internal(&mut self, function: &FuncId) { - if !self.in_contract() { + if !self.in_contract { if self.interner.function_modifiers(function).is_internal == Some(true) { let span = self.interner.function_ident(function).span(); self.push_err(ResolverError::ContractFunctionInternalInNormalFunction { span }); @@ -874,6 +920,7 @@ impl<'a> Resolver<'a> { | Type::Constant(_) | Type::NamedGeneric(_, _) | Type::NotConstant + | Type::TraitAsType(_) | Type::Forall(_, _) => (), Type::Array(length, element_type) => { @@ -1011,20 +1058,39 @@ impl<'a> Resolver<'a> { } } - // Issue an error if the given private function is being called from a non-child module - fn check_can_reference_private_function(&mut self, func: FuncId, span: Span) { + // Issue an error if the given private function is being called from a non-child module, or + // if the given pub(crate) function is being called from another crate + fn check_can_reference_function( + &mut self, + func: FuncId, + span: Span, + visibility: FunctionVisibility, + ) { let function_module = self.interner.function_module(func); let current_module = self.path_resolver.module_id(); let same_crate = function_module.krate == current_module.krate; let krate = function_module.krate; let current_module = current_module.local_id; - - if !same_crate - || !self.module_descendent_of_target(krate, function_module.local_id, current_module) - { - let name = self.interner.function_name(&func).to_string(); - self.errors.push(ResolverError::PrivateFunctionCalled { span, name }); + let name = self.interner.function_name(&func).to_string(); + match visibility { + FunctionVisibility::Public => (), + FunctionVisibility::Private => { + if !same_crate + || !self.module_descendent_of_target( + krate, + function_module.local_id, + current_module, + ) + { + self.errors.push(ResolverError::PrivateFunctionCalled { span, name }); + } + } + FunctionVisibility::PublicCrate => { + if !same_crate { + self.errors.push(ResolverError::NonCrateFunctionCalled { span, name }); + } + } } } @@ -1118,9 +1184,15 @@ impl<'a> Resolver<'a> { if hir_ident.id != DefinitionId::dummy_id() { match self.interner.definition(hir_ident.id).kind { DefinitionKind::Function(id) => { - if self.interner.function_visibility(id) == Visibility::Private { + if self.interner.function_visibility(id) + != FunctionVisibility::Public + { let span = hir_ident.location.span; - self.check_can_reference_private_function(id, span); + self.check_can_reference_function( + id, + span, + self.interner.function_visibility(id), + ); } } DefinitionKind::Global(_) => {} @@ -1430,6 +1502,17 @@ impl<'a> Resolver<'a> { } } + /// Lookup a given trait by name/path. + fn lookup_trait_or_error(&mut self, path: Path) -> Option { + match self.lookup(path) { + Ok(trait_id) => Some(self.get_trait(trait_id)), + Err(error) => { + self.push_err(error); + None + } + } + } + /// Looks up a given type by name. /// This will also instantiate any struct types found. fn lookup_type_or_error(&mut self, path: Path) -> Option { @@ -1566,11 +1649,6 @@ impl<'a> Resolver<'a> { } } - fn in_contract(&self) -> bool { - let module_id = self.path_resolver.module_id(); - module_id.module(self.def_maps).is_contract - } - fn resolve_fmt_str_literal(&mut self, str: String, call_expr_span: Span) -> HirLiteral { let re = Regex::new(r"\{([a-zA-Z0-9_]+)\}") .expect("ICE: an invalid regex pattern was used for checking format strings"); @@ -1600,6 +1678,88 @@ impl<'a> Resolver<'a> { } HirLiteral::FmtStr(str, fmt_str_idents) } + + /// Only sized types are valid to be used as main's parameters or the parameters to a contract + /// function. If the given type is not sized (e.g. contains a slice or NamedGeneric type), an + /// error is issued. + fn verify_type_valid_for_program_input(&mut self, typ: &UnresolvedType) { + match &typ.typ { + UnresolvedTypeData::FieldElement + | UnresolvedTypeData::Integer(_, _) + | UnresolvedTypeData::Bool + | UnresolvedTypeData::Unit + | UnresolvedTypeData::Error => (), + + UnresolvedTypeData::MutableReference(_) + | UnresolvedTypeData::Function(_, _, _) + | UnresolvedTypeData::FormatString(_, _) + | UnresolvedTypeData::TraitAsType(..) + | UnresolvedTypeData::Unspecified => { + let span = typ.span.expect("Function parameters should always have spans"); + self.push_err(ResolverError::InvalidTypeForEntryPoint { span }); + } + + UnresolvedTypeData::Array(length, element) => { + if let Some(length) = length { + self.verify_type_expression_valid_for_program_input(length); + } else { + let span = typ.span.expect("Function parameters should always have spans"); + self.push_err(ResolverError::InvalidTypeForEntryPoint { span }); + } + self.verify_type_valid_for_program_input(element); + } + UnresolvedTypeData::Expression(expression) => { + self.verify_type_expression_valid_for_program_input(expression); + } + UnresolvedTypeData::String(length) => { + if let Some(length) = length { + self.verify_type_expression_valid_for_program_input(length); + } else { + let span = typ.span.expect("Function parameters should always have spans"); + self.push_err(ResolverError::InvalidTypeForEntryPoint { span }); + } + } + UnresolvedTypeData::Named(path, generics) => { + // Since the type is named, we need to resolve it to see what it actually refers to + // in order to check whether it is valid. Since resolving it may lead to a + // resolution error, we have to truncate our error count to the previous count just + // in case. This is to ensure resolution errors are not issued twice when this type + // is later resolved properly. + let error_count = self.errors.len(); + let resolved = self.resolve_named_type(path.clone(), generics.clone(), &mut vec![]); + self.errors.truncate(error_count); + + if !resolved.is_valid_for_program_input() { + let span = typ.span.expect("Function parameters should always have spans"); + self.push_err(ResolverError::InvalidTypeForEntryPoint { span }); + } + } + UnresolvedTypeData::Tuple(elements) => { + for element in elements { + self.verify_type_valid_for_program_input(element); + } + } + } + } + + fn verify_type_expression_valid_for_program_input(&mut self, expr: &UnresolvedTypeExpression) { + match expr { + UnresolvedTypeExpression::Constant(_, _) => (), + UnresolvedTypeExpression::Variable(path) => { + let error_count = self.errors.len(); + let resolved = self.resolve_named_type(path.clone(), vec![], &mut vec![]); + self.errors.truncate(error_count); + + if !resolved.is_valid_for_program_input() { + self.push_err(ResolverError::InvalidTypeForEntryPoint { span: path.span() }); + } + } + UnresolvedTypeExpression::BinaryOperation(lhs, _, rhs, _) => { + self.verify_type_expression_valid_for_program_input(lhs); + self.verify_type_expression_valid_for_program_input(rhs); + } + } + } } /// Gives an error if a user tries to create a mutable reference diff --git a/compiler/noirc_frontend/src/hir/type_check/expr.rs b/compiler/noirc_frontend/src/hir/type_check/expr.rs index 27820922100..7f21bdbebda 100644 --- a/compiler/noirc_frontend/src/hir/type_check/expr.rs +++ b/compiler/noirc_frontend/src/hir/type_check/expr.rs @@ -35,6 +35,7 @@ impl<'interner> TypeChecker<'interner> { } } } + /// Infers a type for a given expression, and return this type. /// As a side-effect, this function will also remember this type in the NodeInterner /// for the given expr_id key. @@ -50,7 +51,7 @@ impl<'interner> TypeChecker<'interner> { // E.g. `fn foo(t: T, field: Field) -> T` has type `forall T. fn(T, Field) -> T`. // We must instantiate identifiers at every call site to replace this T with a new type // variable to handle generic functions. - let t = self.interner.id_type(ident.id); + let t = self.interner.id_type_substitute_trait_as_type(ident.id); let (typ, bindings) = t.instantiate(self.interner); self.interner.store_instantiation_bindings(*expr_id, bindings); typ @@ -131,7 +132,6 @@ impl<'interner> TypeChecker<'interner> { HirExpression::Index(index_expr) => self.check_index_expression(expr_id, index_expr), HirExpression::Call(call_expr) => { self.check_if_deprecated(&call_expr.func); - let function = self.check_expression(&call_expr.func); let args = vecmap(&call_expr.arguments, |arg| { let typ = self.check_expression(arg); @@ -839,6 +839,14 @@ impl<'interner> TypeChecker<'interner> { } } } + Type::TraitAsType(_trait) => { + self.errors.push(TypeCheckError::UnresolvedMethodCall { + method_name: method_name.to_string(), + object_type: object_type.clone(), + span: self.interner.expr_span(expr_id), + }); + None + } Type::NamedGeneric(_, _) => { let func_meta = self.interner.function_meta( &self.current_function.expect("unexpected method outside a function"), diff --git a/compiler/noirc_frontend/src/hir/type_check/mod.rs b/compiler/noirc_frontend/src/hir/type_check/mod.rs index a3c5a5eb98d..035dbbc3518 100644 --- a/compiler/noirc_frontend/src/hir/type_check/mod.rs +++ b/compiler/noirc_frontend/src/hir/type_check/mod.rs @@ -15,7 +15,7 @@ pub use errors::TypeCheckError; use crate::{ hir_def::{expr::HirExpression, stmt::HirStatement}, - node_interner::{ExprId, FuncId, NodeInterner, StmtId}, + node_interner::{ExprId, FuncId, NodeInterner, StmtId, TraitImplKey}, Type, }; @@ -63,30 +63,41 @@ pub fn type_check_func(interner: &mut NodeInterner, func_id: FuncId) -> Vec(...) {}`. Unlike TypeVariables, they cannot be bound over. NamedGeneric(TypeVariable, Rc), @@ -483,7 +488,8 @@ impl Type { | Type::Constant(_) | Type::NamedGeneric(_, _) | Type::NotConstant - | Type::Forall(_, _) => false, + | Type::Forall(_, _) + | Type::TraitAsType(_) => false, Type::Array(length, elem) => { elem.contains_numeric_typevar(target_id) || named_generic_id_matches_target(length) @@ -514,6 +520,46 @@ impl Type { } } } + + /// True if this type can be used as a parameter to `main` or a contract function. + /// This is only false for unsized types like slices or slices that do not make sense + /// as a program input such as named generics or mutable references. + /// + /// This function should match the same check done in `create_value_from_type` in acir_gen. + /// If this function does not catch a case where a type should be valid, it will later lead to a + /// panic in that function instead of a user-facing compiler error message. + pub(crate) fn is_valid_for_program_input(&self) -> bool { + match self { + // Type::Error is allowed as usual since it indicates an error was already issued and + // we don't need to issue further errors about this likely unresolved type + Type::FieldElement + | Type::Integer(_, _) + | Type::Bool + | Type::Unit + | Type::Constant(_) + | Type::Error => true, + + Type::FmtString(_, _) + | Type::TypeVariable(_, _) + | Type::NamedGeneric(_, _) + | Type::Function(_, _, _) + | Type::MutableReference(_) + | Type::Forall(_, _) + | Type::TraitAsType(..) + | Type::NotConstant => false, + + Type::Array(length, element) => { + length.is_valid_for_program_input() && element.is_valid_for_program_input() + } + Type::String(length) => length.is_valid_for_program_input(), + Type::Tuple(elements) => elements.iter().all(|elem| elem.is_valid_for_program_input()), + Type::Struct(definition, generics) => definition + .borrow() + .get_fields(generics) + .into_iter() + .all(|(_, field)| field.is_valid_for_program_input()), + } + } } impl std::fmt::Display for Type { @@ -560,6 +606,9 @@ impl std::fmt::Display for Type { write!(f, "{}<{}>", s.borrow(), args.join(", ")) } } + Type::TraitAsType(tr) => { + write!(f, "impl {}", tr.name) + } Type::Tuple(elements) => { let elements = vecmap(elements, ToString::to_string); write!(f, "({})", elements.join(", ")) @@ -675,9 +724,16 @@ impl Type { *binding.borrow_mut() = TypeBinding::Bound(clone); Ok(()) } - TypeVariableKind::Constant(_) | TypeVariableKind::IntegerOrField => { - Err(UnificationError) + // The lengths don't match, but neither are set in stone so we can + // just set them both to NotConstant. See issue 2370 + TypeVariableKind::Constant(_) => { + // *length != target_length + drop(borrow); + *var.borrow_mut() = TypeBinding::Bound(Type::NotConstant); + *binding.borrow_mut() = TypeBinding::Bound(Type::NotConstant); + Ok(()) } + TypeVariableKind::IntegerOrField => Err(UnificationError), }, } } @@ -1057,6 +1113,7 @@ impl Type { let fields = vecmap(fields, |field| field.substitute(type_bindings)); Type::Tuple(fields) } + Type::TraitAsType(_) => todo!(), Type::Forall(typevars, typ) => { // Trying to substitute a variable defined within a nested Forall // is usually impossible and indicative of an error in the type checker somewhere. @@ -1096,6 +1153,7 @@ impl Type { let field_occurs = fields.occurs(target_id); len_occurs || field_occurs } + Type::TraitAsType(_) => todo!(), Type::Struct(_, generic_args) => generic_args.iter().any(|arg| arg.occurs(target_id)), Type::Tuple(fields) => fields.iter().any(|field| field.occurs(target_id)), Type::NamedGeneric(binding, _) | Type::TypeVariable(binding, _) => { @@ -1147,7 +1205,6 @@ impl Type { Struct(def.clone(), args) } Tuple(args) => Tuple(vecmap(args, |arg| arg.follow_bindings())), - TypeVariable(var, _) | NamedGeneric(var, _) => { if let TypeBinding::Bound(typ) = &*var.borrow() { return typ.follow_bindings(); @@ -1166,10 +1223,14 @@ impl Type { // Expect that this function should only be called on instantiated types Forall(..) => unreachable!(), - - FieldElement | Integer(_, _) | Bool | Constant(_) | Unit | Error | NotConstant => { - self.clone() - } + TraitAsType(_) + | FieldElement + | Integer(_, _) + | Bool + | Constant(_) + | Unit + | Error + | NotConstant => self.clone(), } } } @@ -1270,6 +1331,7 @@ impl From<&Type> for PrintableType { let fields = vecmap(fields, |(name, typ)| (name, typ.into())); PrintableType::Struct { fields, name: struct_type.name.to_string() } } + Type::TraitAsType(_) => unreachable!(), Type::Tuple(_) => todo!("printing tuple types is not yet implemented"), Type::TypeVariable(_, _) => unreachable!(), Type::NamedGeneric(..) => unreachable!(), diff --git a/compiler/noirc_frontend/src/lexer/errors.rs b/compiler/noirc_frontend/src/lexer/errors.rs index 9bc9a820239..a2a4056f1d0 100644 --- a/compiler/noirc_frontend/src/lexer/errors.rs +++ b/compiler/noirc_frontend/src/lexer/errors.rs @@ -11,15 +11,15 @@ use thiserror::Error; pub enum LexerErrorKind { #[error("An unexpected character {:?} was found.", found)] UnexpectedCharacter { span: Span, expected: String, found: Option }, - #[error("NotADoubleChar : {:?} is not a double char token", found)] + #[error("Internal error: Tried to lex {:?} as a double char token", found)] NotADoubleChar { span: Span, found: Token }, - #[error("InvalidIntegerLiteral : {:?} is not a integer", found)] + #[error("Invalid integer literal, {:?} is not a integer", found)] InvalidIntegerLiteral { span: Span, found: String }, - #[error("MalformedFuncAttribute : {:?} is not a valid attribute", found)] + #[error("{:?} is not a valid attribute", found)] MalformedFuncAttribute { span: Span, found: String }, - #[error("TooManyBits")] + #[error("Integer type is larger than the maximum supported size of u127")] TooManyBits { span: Span, max: u32, got: u32 }, - #[error("LogicalAnd used instead of bitwise and")] + #[error("Logical and used instead of bitwise and")] LogicalAnd { span: Span }, #[error("Unterminated block comment")] UnterminatedBlockComment { span: Span }, diff --git a/compiler/noirc_frontend/src/lexer/lexer.rs b/compiler/noirc_frontend/src/lexer/lexer.rs index 593c5bdfb05..2576b7a08ab 100644 --- a/compiler/noirc_frontend/src/lexer/lexer.rs +++ b/compiler/noirc_frontend/src/lexer/lexer.rs @@ -1,4 +1,4 @@ -use crate::token::Attribute; +use crate::token::{Attribute, DocStyle}; use super::{ errors::LexerErrorKind, @@ -67,6 +67,13 @@ impl<'a> Lexer<'a> { self.char_iter.peek().map(|(c, _)| *c) } + /// Peeks at the character two positions ahead. Does not iterate the cursor + fn peek2_char(&mut self) -> Option { + let mut chars = self.char_iter.clone(); + chars.next(); + chars.next().map(|(c, _)| c) + } + /// Peeks at the next char and returns true if it is equal to the char argument fn peek_char_is(&mut self, ch: char) -> bool { self.peek_char() == Some(ch) @@ -388,14 +395,39 @@ impl<'a> Lexer<'a> { } fn parse_comment(&mut self, start: u32) -> SpannedTokenResult { + let doc_style = match self.peek_char() { + Some('!') => { + self.next_char(); + Some(DocStyle::Inner) + } + Some('/') if self.peek2_char() != '/'.into() => { + self.next_char(); + Some(DocStyle::Outer) + } + _ => None, + }; let comment = self.eat_while(None, |ch| ch != '\n'); + if self.skip_comments { return self.next_token(); } - Ok(Token::LineComment(comment).into_span(start, self.position)) + + Ok(Token::LineComment(comment, doc_style).into_span(start, self.position)) } fn parse_block_comment(&mut self, start: u32) -> SpannedTokenResult { + let doc_style = match self.peek_char() { + Some('!') => { + self.next_char(); + Some(DocStyle::Inner) + } + Some('*') if !matches!(self.peek2_char(), Some('*' | '/')) => { + self.next_char(); + Some(DocStyle::Outer) + } + _ => None, + }; + let mut depth = 1usize; let mut content = String::new(); @@ -424,7 +456,7 @@ impl<'a> Lexer<'a> { if self.skip_comments { return self.next_token(); } - Ok(Token::BlockComment(content).into_span(start, self.position)) + Ok(Token::BlockComment(content, doc_style).into_span(start, self.position)) } else { let span = Span::inclusive(start, self.position); Err(LexerErrorKind::UnterminatedBlockComment { span }) @@ -734,6 +766,32 @@ mod tests { } } + #[test] + fn test_comments() { + let input = " + // comment + /// comment + //! comment + /* comment */ + /** outer doc block */ + /*! inner doc block */ + "; + let expected = [ + Token::LineComment(" comment".into(), None), + Token::LineComment(" comment".into(), DocStyle::Outer.into()), + Token::LineComment(" comment".into(), DocStyle::Inner.into()), + Token::BlockComment(" comment ".into(), None), + Token::BlockComment(" outer doc block ".into(), DocStyle::Outer.into()), + Token::BlockComment(" inner doc block ".into(), DocStyle::Inner.into()), + ]; + + let mut lexer = Lexer::new(input).skip_comments(false); + for token in expected { + let first_lexer_output = lexer.next_token().unwrap(); + assert_eq!(token, first_lexer_output); + } + } + #[test] fn test_nested_block_comments() { let input = " diff --git a/compiler/noirc_frontend/src/lexer/token.rs b/compiler/noirc_frontend/src/lexer/token.rs index 8b2acb5b28e..fe3e9476318 100644 --- a/compiler/noirc_frontend/src/lexer/token.rs +++ b/compiler/noirc_frontend/src/lexer/token.rs @@ -19,8 +19,8 @@ pub enum Token { Keyword(Keyword), IntType(IntType), Attribute(Attribute), - LineComment(String), - BlockComment(String), + LineComment(String, Option), + BlockComment(String, Option), /// < Less, /// <= @@ -97,6 +97,12 @@ pub enum Token { Invalid(char), } +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)] +pub enum DocStyle { + Outer, + Inner, +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct SpannedToken(Spanned); @@ -151,8 +157,8 @@ impl fmt::Display for Token { Token::FmtStr(ref b) => write!(f, "f{b}"), Token::Keyword(k) => write!(f, "{k}"), Token::Attribute(ref a) => write!(f, "{a}"), - Token::LineComment(ref s) => write!(f, "//{s}"), - Token::BlockComment(ref s) => write!(f, "/*{s}*/"), + Token::LineComment(ref s, _style) => write!(f, "//{s}"), + Token::BlockComment(ref s, _style) => write!(f, "/*{s}*/"), Token::IntType(ref i) => write!(f, "{i}"), Token::Less => write!(f, "<"), Token::LessEqual => write!(f, "<="), @@ -392,6 +398,13 @@ impl Attributes { matches!(self.function, Some(FunctionAttribute::Test(_))) } + /// True if these attributes mean the given function is an entry point function if it was + /// defined within a contract. Note that this does not check if the function is actually part + /// of a contract. + pub fn is_contract_entry_point(&self) -> bool { + !self.has_contract_library_method() && !self.is_test_function() + } + /// Returns note if a deprecated secondary attribute is found pub fn get_deprecated_note(&self) -> Option> { self.secondary.iter().find_map(|attr| match attr { diff --git a/compiler/noirc_frontend/src/monomorphization/ast.rs b/compiler/noirc_frontend/src/monomorphization/ast.rs index c67b8f8bcec..0a005d766fe 100644 --- a/compiler/noirc_frontend/src/monomorphization/ast.rs +++ b/compiler/noirc_frontend/src/monomorphization/ast.rs @@ -81,7 +81,7 @@ pub struct For { #[derive(Debug, Clone, Hash)] pub enum Literal { Array(ArrayLiteral), - Integer(FieldElement, Type), + Integer(FieldElement, Type, Location), Bool(bool), Str(String), FmtStr(String, u64, Box), diff --git a/compiler/noirc_frontend/src/monomorphization/mod.rs b/compiler/noirc_frontend/src/monomorphization/mod.rs index b2c12746a8c..6891bcf2872 100644 --- a/compiler/noirc_frontend/src/monomorphization/mod.rs +++ b/compiler/noirc_frontend/src/monomorphization/mod.rs @@ -222,9 +222,15 @@ impl<'interner> Monomorphizer<'interner> { let modifiers = self.interner.function_modifiers(&f); let name = self.interner.function_name(&f).to_owned(); - let return_type = self.convert_type(meta.return_type()); + let body_expr_id = *self.interner.function(&f).as_expr(); + let body_return_type = self.interner.id_type(body_expr_id); + let return_type = self.convert_type(match meta.return_type() { + Type::TraitAsType(_) => &body_return_type, + _ => meta.return_type(), + }); + let parameters = self.parameters(meta.parameters); - let body = self.expr(*self.interner.function(&f).as_expr()); + let body = self.expr(body_expr_id); let unconstrained = modifiers.is_unconstrained || matches!(modifiers.contract_function_type, Some(ContractFunctionType::Open)); @@ -306,7 +312,8 @@ impl<'interner> Monomorphizer<'interner> { HirExpression::Literal(HirLiteral::Bool(value)) => Literal(Bool(value)), HirExpression::Literal(HirLiteral::Integer(value)) => { let typ = self.convert_type(&self.interner.id_type(expr)); - Literal(Integer(value, typ)) + let location = self.interner.id_location(expr); + Literal(Integer(value, typ, location)) } HirExpression::Literal(HirLiteral::Array(array)) => match array { HirArrayLiteral::Standard(array) => self.standard_array(expr, array), @@ -381,8 +388,8 @@ impl<'interner> Monomorphizer<'interner> { } } - HirExpression::MethodCall(_) => { - unreachable!("Encountered HirExpression::MethodCall during monomorphization") + HirExpression::MethodCall(hir_method_call) => { + unreachable!("Encountered HirExpression::MethodCall during monomorphization {hir_method_call:?}") } HirExpression::Error => unreachable!("Encountered Error node during monomorphization"), } @@ -406,12 +413,11 @@ impl<'interner> Monomorphizer<'interner> { ) -> ast::Expression { let typ = self.convert_type(&self.interner.id_type(array)); - let contents = self.expr(repeated_element); let length = length .evaluate_to_u64() .expect("Length of array is unknown when evaluating numeric generic"); - let contents = vec![contents; length as usize]; + let contents = vecmap(0..length, |_| self.expr(repeated_element)); ast::Expression::Literal(ast::Literal::Array(ast::ArrayLiteral { contents, typ })) } @@ -635,7 +641,6 @@ impl<'interner> Monomorphizer<'interner> { let location = Some(ident.location); let name = definition.name.clone(); let typ = self.interner.id_type(expr_id); - let definition = self.lookup_function(*func_id, expr_id, &typ); let typ = self.convert_type(&typ); let ident = ast::Ident { location, mutable, definition, name, typ: typ.clone() }; @@ -668,7 +673,8 @@ impl<'interner> Monomorphizer<'interner> { }; let value = FieldElement::from(value as u128); - ast::Expression::Literal(ast::Literal::Integer(value, ast::Type::Field)) + let location = self.interner.id_location(expr_id); + ast::Expression::Literal(ast::Literal::Integer(value, ast::Type::Field, location)) } } } @@ -686,7 +692,6 @@ impl<'interner> Monomorphizer<'interner> { ast::Type::FmtString(size, fields) } HirType::Unit => ast::Type::Unit, - HirType::Array(length, element) => { let element = Box::new(self.convert_type(element.as_ref())); @@ -696,7 +701,9 @@ impl<'interner> Monomorphizer<'interner> { ast::Type::Slice(element) } } - + HirType::TraitAsType(_) => { + unreachable!("All TraitAsType should be replaced before calling convert_type"); + } HirType::NamedGeneric(binding, _) => { if let TypeBinding::Bound(binding) = &*binding.borrow() { return self.convert_type(binding); @@ -780,8 +787,7 @@ impl<'interner> Monomorphizer<'interner> { } } - fn is_function_closure(&self, raw_func_id: node_interner::ExprId) -> bool { - let t = self.convert_type(&self.interner.id_type(raw_func_id)); + fn is_function_closure(&self, t: ast::Type) -> bool { if self.is_function_closure_type(&t) { true } else if let ast::Type::Tuple(elements) = t { @@ -850,6 +856,7 @@ impl<'interner> Monomorphizer<'interner> { let func: Box; let return_type = self.interner.id_type(id); let return_type = self.convert_type(&return_type); + let location = call.location; if let ast::Expression::Ident(ident) = original_func.as_ref() { @@ -863,8 +870,9 @@ impl<'interner> Monomorphizer<'interner> { } let mut block_expressions = vec![]; - - let is_closure = self.is_function_closure(call.func); + let func_type = self.interner.id_type(call.func); + let func_type = self.convert_type(&func_type); + let is_closure = self.is_function_closure(func_type); if is_closure { let local_id = self.next_local_id(); @@ -984,30 +992,32 @@ impl<'interner> Monomorphizer<'interner> { if let ast::Expression::Ident(ident) = func { if let Definition::Builtin(opcode) = &ident.definition { // TODO(#1736): Move this builtin to the SSA pass + let location = self.interner.expr_location(expr_id); return match opcode.as_str() { - "modulus_num_bits" => Some(ast::Expression::Literal(ast::Literal::Integer( - (FieldElement::max_num_bits() as u128).into(), - ast::Type::Field, - ))), + "modulus_num_bits" => { + let bits = (FieldElement::max_num_bits() as u128).into(); + let typ = ast::Type::Field; + Some(ast::Expression::Literal(ast::Literal::Integer(bits, typ, location))) + } "zeroed" => { let location = self.interner.expr_location(expr_id); Some(self.zeroed_value_of_type(result_type, location)) } "modulus_le_bits" => { let bits = FieldElement::modulus().to_radix_le(2); - Some(self.modulus_array_literal(bits, 1)) + Some(self.modulus_array_literal(bits, 1, location)) } "modulus_be_bits" => { let bits = FieldElement::modulus().to_radix_be(2); - Some(self.modulus_array_literal(bits, 1)) + Some(self.modulus_array_literal(bits, 1, location)) } "modulus_be_bytes" => { let bytes = FieldElement::modulus().to_bytes_be(); - Some(self.modulus_array_literal(bytes, 8)) + Some(self.modulus_array_literal(bytes, 8, location)) } "modulus_le_bytes" => { let bytes = FieldElement::modulus().to_bytes_le(); - Some(self.modulus_array_literal(bytes, 8)) + Some(self.modulus_array_literal(bytes, 8, location)) } _ => None, }; @@ -1016,12 +1026,17 @@ impl<'interner> Monomorphizer<'interner> { None } - fn modulus_array_literal(&self, bytes: Vec, arr_elem_bits: u32) -> ast::Expression { + fn modulus_array_literal( + &self, + bytes: Vec, + arr_elem_bits: u32, + location: Location, + ) -> ast::Expression { use ast::*; let int_type = Type::Integer(crate::Signedness::Unsigned, arr_elem_bits); let bytes_as_expr = vecmap(bytes, |byte| { - Expression::Literal(Literal::Integer((byte as u128).into(), int_type.clone())) + Expression::Literal(Literal::Integer((byte as u128).into(), int_type.clone(), location)) }); let typ = Type::Array(bytes_as_expr.len() as u64, Box::new(int_type)); @@ -1271,7 +1286,8 @@ impl<'interner> Monomorphizer<'interner> { ) -> ast::Expression { match typ { ast::Type::Field | ast::Type::Integer(..) => { - ast::Expression::Literal(ast::Literal::Integer(0_u128.into(), typ.clone())) + let typ = typ.clone(); + ast::Expression::Literal(ast::Literal::Integer(0_u128.into(), typ, location)) } ast::Type::Bool => ast::Expression::Literal(ast::Literal::Bool(false)), // There is no unit literal currently. Replace it with 'false' since it should be ignored diff --git a/compiler/noirc_frontend/src/monomorphization/printer.rs b/compiler/noirc_frontend/src/monomorphization/printer.rs index ff2b7d0d256..e79330de6f8 100644 --- a/compiler/noirc_frontend/src/monomorphization/printer.rs +++ b/compiler/noirc_frontend/src/monomorphization/printer.rs @@ -93,7 +93,7 @@ impl AstPrinter { self.print_comma_separated(&array.contents, f)?; write!(f, "]") } - super::ast::Literal::Integer(x, _) => x.fmt(f), + super::ast::Literal::Integer(x, _, _) => x.fmt(f), super::ast::Literal::Bool(x) => x.fmt(f), super::ast::Literal::Str(s) => s.fmt(f), super::ast::Literal::FmtStr(s, _, _) => { diff --git a/compiler/noirc_frontend/src/node_interner.rs b/compiler/noirc_frontend/src/node_interner.rs index c4497331fae..514a65d37a2 100644 --- a/compiler/noirc_frontend/src/node_interner.rs +++ b/compiler/noirc_frontend/src/node_interner.rs @@ -21,8 +21,8 @@ use crate::hir_def::{ }; use crate::token::{Attributes, SecondaryAttribute}; use crate::{ - ContractFunctionType, FunctionDefinition, Generics, Shared, TypeAliasType, TypeBinding, - TypeBindings, TypeVariable, TypeVariableId, TypeVariableKind, Visibility, + ContractFunctionType, FunctionDefinition, FunctionVisibility, Generics, Shared, TypeAliasType, + TypeBinding, TypeBindings, TypeVariable, TypeVariableId, TypeVariableKind, }; #[derive(Eq, PartialEq, Hash, Clone)] @@ -132,7 +132,7 @@ pub struct FunctionModifiers { pub name: String, /// Whether the function is `pub` or not. - pub visibility: Visibility, + pub visibility: FunctionVisibility, pub attributes: Attributes, @@ -155,7 +155,7 @@ impl FunctionModifiers { pub fn new() -> Self { Self { name: String::new(), - visibility: Visibility::Public, + visibility: FunctionVisibility::Public, attributes: Attributes::empty(), is_unconstrained: false, is_internal: None, @@ -637,7 +637,7 @@ impl NodeInterner { // later during name resolution. let modifiers = FunctionModifiers { name: function.name.0.contents.clone(), - visibility: if function.is_public { Visibility::Public } else { Visibility::Private }, + visibility: function.visibility, attributes: function.attributes.clone(), is_unconstrained: function.is_unconstrained, contract_function_type: Some(if function.is_open { Open } else { Secret }), @@ -670,7 +670,7 @@ impl NodeInterner { /// /// The underlying function_visibilities map is populated during def collection, /// so this function can be called anytime afterward. - pub fn function_visibility(&self, func: FuncId) -> Visibility { + pub fn function_visibility(&self, func: FuncId) -> FunctionVisibility { self.function_modifiers[&func].visibility } @@ -820,6 +820,23 @@ impl NodeInterner { self.id_to_type.get(&index.into()).cloned().unwrap_or(Type::Error) } + pub fn id_type_substitute_trait_as_type(&self, def_id: DefinitionId) -> Type { + let typ = self.id_type(def_id); + if let Type::Function(args, ret, env) = &typ { + let def = self.definition(def_id); + if let Type::TraitAsType(_trait) = ret.as_ref() { + if let DefinitionKind::Function(func_id) = def.kind { + let f = self.function(&func_id); + let func_body = f.as_expr(); + let ret_type = self.id_type(func_body); + let new_type = Type::Function(args.clone(), Box::new(ret_type), env.clone()); + return new_type; + } + } + } + typ + } + /// Returns the span of an item stored in the Interner pub fn id_location(&self, index: impl Into) -> Location { self.id_to_location.get(&index.into()).copied().unwrap() @@ -943,6 +960,7 @@ impl NodeInterner { | Type::Forall(..) | Type::NotConstant | Type::Constant(..) + | Type::TraitAsType(..) | Type::Error => false, } } @@ -1051,6 +1069,7 @@ fn get_type_method_key(typ: &Type) -> Option { | Type::Error | Type::NotConstant | Type::Struct(_, _) + | Type::TraitAsType(_) | Type::FmtString(_, _) => None, } } diff --git a/compiler/noirc_frontend/src/parser/errors.rs b/compiler/noirc_frontend/src/parser/errors.rs index 0c0d4e7645c..b9b11d8c99e 100644 --- a/compiler/noirc_frontend/src/parser/errors.rs +++ b/compiler/noirc_frontend/src/parser/errors.rs @@ -128,7 +128,7 @@ impl std::fmt::Display for ParserError { impl From for Diagnostic { fn from(error: ParserError) -> Diagnostic { - match &error.reason { + match error.reason { Some(reason) => { match reason { ParserErrorReason::ConstrainDeprecated => Diagnostic::simple_error( @@ -146,11 +146,11 @@ impl From for Diagnostic { "".into(), error.span, ), - reason @ ParserErrorReason::ExpectedPatternButFoundType(ty) => { - Diagnostic::simple_error(reason.to_string(), format!("{ty} is a type and cannot be used as a variable name"), error.span) + ParserErrorReason::ExpectedPatternButFoundType(ty) => { + Diagnostic::simple_error("Expected a ; separating these two statements".into(), format!("{ty} is a type and cannot be used as a variable name"), error.span) } + ParserErrorReason::Lexer(error) => error.into(), other => { - Diagnostic::simple_error(format!("{other}"), String::new(), error.span) } } diff --git a/compiler/noirc_frontend/src/parser/parser.rs b/compiler/noirc_frontend/src/parser/parser.rs index 89cc792c4f0..cee824a51c9 100644 --- a/compiler/noirc_frontend/src/parser/parser.rs +++ b/compiler/noirc_frontend/src/parser/parser.rs @@ -37,11 +37,12 @@ use crate::lexer::Lexer; use crate::parser::{force, ignore_then_commit, statement_recovery}; use crate::token::{Attribute, Attributes, Keyword, SecondaryAttribute, Token, TokenKind}; use crate::{ - BinaryOp, BinaryOpKind, BlockExpression, ConstrainStatement, Distinctness, FunctionDefinition, - FunctionReturnType, Ident, IfExpression, InfixExpression, LValue, Lambda, Literal, - NoirFunction, NoirStruct, NoirTrait, NoirTraitImpl, NoirTypeAlias, Path, PathKind, Pattern, - Recoverable, Statement, TraitBound, TraitImplItem, TraitItem, TypeImpl, UnaryOp, - UnresolvedTraitConstraint, UnresolvedTypeExpression, UseTree, UseTreeKind, Visibility, + BinaryOp, BinaryOpKind, BlockExpression, ConstrainKind, ConstrainStatement, Distinctness, + FunctionDefinition, FunctionReturnType, FunctionVisibility, Ident, IfExpression, + InfixExpression, LValue, Lambda, Literal, NoirFunction, NoirStruct, NoirTrait, NoirTraitImpl, + NoirTypeAlias, Path, PathKind, Pattern, Recoverable, Statement, TraitBound, TraitImplItem, + TraitItem, TypeImpl, UnaryOp, UnresolvedTraitConstraint, UnresolvedTypeExpression, UseTree, + UseTreeKind, Visibility, }; use chumsky::prelude::*; @@ -183,9 +184,15 @@ fn function_definition(allow_self: bool) -> impl NoirParser { name, attributes: attrs, is_unconstrained: modifiers.0, - is_open: modifiers.1, - is_internal: modifiers.2, - is_public: modifiers.3, + is_open: modifiers.2, + is_internal: modifiers.3, + visibility: if modifiers.1 { + FunctionVisibility::PublicCrate + } else if modifiers.4 { + FunctionVisibility::Public + } else { + FunctionVisibility::Private + }, generics, parameters, body, @@ -198,19 +205,34 @@ fn function_definition(allow_self: bool) -> impl NoirParser { }) } -/// function_modifiers: 'unconstrained'? 'open'? 'internal'? +/// function_modifiers: 'unconstrained'? 'pub(crate)'? 'pub'? 'open'? 'internal'? /// -/// returns (is_unconstrained, is_open, is_internal) for whether each keyword was present -fn function_modifiers() -> impl NoirParser<(bool, bool, bool, bool)> { +/// returns (is_unconstrained, is_pub_crate, is_open, is_internal, is_pub) for whether each keyword was present +fn function_modifiers() -> impl NoirParser<(bool, bool, bool, bool, bool)> { keyword(Keyword::Unconstrained) .or_not() + .then(is_pub_crate()) .then(keyword(Keyword::Pub).or_not()) .then(keyword(Keyword::Open).or_not()) .then(keyword(Keyword::Internal).or_not()) - .map(|(((unconstrained, public), open), internal)| { - (unconstrained.is_some(), open.is_some(), internal.is_some(), public.is_some()) + .map(|((((unconstrained, pub_crate), public), open), internal)| { + ( + unconstrained.is_some(), + pub_crate, + open.is_some(), + internal.is_some(), + public.is_some(), + ) }) } +fn is_pub_crate() -> impl NoirParser { + (keyword(Keyword::Pub) + .then_ignore(just(Token::LeftParen)) + .then_ignore(keyword(Keyword::Crate)) + .then_ignore(just(Token::RightParen))) + .or_not() + .map(|a| a.is_some()) +} /// non_empty_ident_list: ident ',' non_empty_ident_list /// | ident @@ -789,7 +811,7 @@ where } fn fresh_statement() -> impl NoirParser { - statement(expression(), expression_no_constructors()) + statement(expression(), expression_no_constructors(expression())) } fn constrain<'a, P>(expr_parser: P) -> impl NoirParser + 'a @@ -800,7 +822,7 @@ where keyword(Keyword::Constrain).labelled(ParsingRuleLabel::Statement), expr_parser, ) - .map(|expr| StatementKind::Constrain(ConstrainStatement(expr, None))) + .map(|expr| StatementKind::Constrain(ConstrainStatement(expr, None, ConstrainKind::Constrain))) .validate(|expr, span, emit| { emit(ParserError::with_reason(ParserErrorReason::ConstrainDeprecated, span)); expr @@ -828,7 +850,11 @@ where } } - StatementKind::Constrain(ConstrainStatement(condition, message_str)) + StatementKind::Constrain(ConstrainStatement( + condition, + message_str, + ConstrainKind::Assert, + )) }) } @@ -859,7 +885,11 @@ where emit(ParserError::with_reason(ParserErrorReason::AssertMessageNotString, span)); } } - StatementKind::Constrain(ConstrainStatement(predicate, message_str)) + StatementKind::Constrain(ConstrainStatement( + predicate, + message_str, + ConstrainKind::AssertEq, + )) }) } @@ -996,6 +1026,7 @@ fn parse_type_inner( string_type(), format_string_type(recursive_type_parser.clone()), named_type(recursive_type_parser.clone()), + named_trait(recursive_type_parser.clone()), array_type(recursive_type_parser.clone()), recursive_type_parser.clone().delimited_by(just(Token::LeftParen), just(Token::RightParen)), tuple_type(recursive_type_parser.clone()), @@ -1085,6 +1116,12 @@ fn named_type(type_parser: impl NoirParser) -> impl NoirParser) -> impl NoirParser { + keyword(Keyword::Impl).ignore_then(path()).then(generic_type_args(type_parser)).map_with_span( + |(path, args), span| UnresolvedTypeData::TraitAsType(path, args).with_span(span), + ) +} + fn generic_type_args( type_parser: impl NoirParser, ) -> impl NoirParser> { @@ -1182,8 +1219,8 @@ fn expression() -> impl ExprParser { expression_with_precedence( Precedence::Lowest, expr.clone(), - expression_no_constructors(), - statement(expr, expression_no_constructors()), + expression_no_constructors(expr.clone()), + statement(expr.clone(), expression_no_constructors(expr)), false, true, ) @@ -1191,13 +1228,16 @@ fn expression() -> impl ExprParser { .labelled(ParsingRuleLabel::Expression) } -fn expression_no_constructors() -> impl ExprParser { - recursive(|expr| { +fn expression_no_constructors<'a, P>(expr_parser: P) -> impl ExprParser + 'a +where + P: ExprParser + 'a, +{ + recursive(|expr_no_constructors| { expression_with_precedence( Precedence::Lowest, - expr.clone(), - expr.clone(), - statement(expr.clone(), expr), + expr_parser.clone(), + expr_no_constructors.clone(), + statement(expr_parser, expr_no_constructors), false, false, ) @@ -1765,7 +1805,7 @@ mod test { parse_all( atom_or_right_unary( expression(), - expression_no_constructors(), + expression_no_constructors(expression()), fresh_statement(), true, ), @@ -1774,7 +1814,7 @@ mod test { parse_all_failing( atom_or_right_unary( expression(), - expression_no_constructors(), + expression_no_constructors(expression()), fresh_statement(), true, ), @@ -1794,7 +1834,7 @@ mod test { parse_all( atom_or_right_unary( expression(), - expression_no_constructors(), + expression_no_constructors(expression()), fresh_statement(), true, ), @@ -1983,7 +2023,7 @@ mod test { match parse_with(assertion(expression()), "assert(x == y, \"assertion message\")").unwrap() { - StatementKind::Constrain(ConstrainStatement(_, message)) => { + StatementKind::Constrain(ConstrainStatement(_, message, _)) => { assert_eq!(message, Some("assertion message".to_owned())); } _ => unreachable!(), @@ -2007,7 +2047,7 @@ mod test { match parse_with(assertion_eq(expression()), "assert_eq(x, y, \"assertion message\")") .unwrap() { - StatementKind::Constrain(ConstrainStatement(_, message)) => { + StatementKind::Constrain(ConstrainStatement(_, message, _)) => { assert_eq!(message, Some("assertion message".to_owned())); } _ => unreachable!(), @@ -2033,12 +2073,12 @@ mod test { #[test] fn parse_for_loop() { parse_all( - for_loop(expression_no_constructors(), fresh_statement()), + for_loop(expression_no_constructors(expression()), fresh_statement()), vec!["for i in x+y..z {}", "for i in 0..100 { foo; bar }"], ); parse_all_failing( - for_loop(expression_no_constructors(), fresh_statement()), + for_loop(expression_no_constructors(expression()), fresh_statement()), vec![ "for 1 in x+y..z {}", // Cannot have a literal as the loop identifier "for i in 0...100 {}", // Only '..' is supported, there are no inclusive ranges yet @@ -2133,11 +2173,11 @@ mod test { #[test] fn parse_parenthesized_expression() { parse_all( - atom(expression(), expression_no_constructors(), fresh_statement(), true), + atom(expression(), expression_no_constructors(expression()), fresh_statement(), true), vec!["(0)", "(x+a)", "({(({{({(nested)})}}))})"], ); parse_all_failing( - atom(expression(), expression_no_constructors(), fresh_statement(), true), + atom(expression(), expression_no_constructors(expression()), fresh_statement(), true), vec!["(x+a", "((x+a)", "(,)"], ); } @@ -2150,12 +2190,12 @@ mod test { #[test] fn parse_if_expr() { parse_all( - if_expr(expression_no_constructors(), fresh_statement()), + if_expr(expression_no_constructors(expression()), fresh_statement()), vec!["if x + a { } else { }", "if x {}", "if x {} else if y {} else {}"], ); parse_all_failing( - if_expr(expression_no_constructors(), fresh_statement()), + if_expr(expression_no_constructors(expression()), fresh_statement()), vec!["if (x / a) + 1 {} else", "if foo then 1 else 2", "if true { 1 }else 3"], ); } @@ -2249,11 +2289,11 @@ mod test { #[test] fn parse_unary() { parse_all( - term(expression(), expression_no_constructors(), fresh_statement(), true), + term(expression(), expression_no_constructors(expression()), fresh_statement(), true), vec!["!hello", "-hello", "--hello", "-!hello", "!-hello"], ); parse_all_failing( - term(expression(), expression_no_constructors(), fresh_statement(), true), + term(expression(), expression_no_constructors(expression()), fresh_statement(), true), vec!["+hello", "/hello"], ); } @@ -2431,4 +2471,52 @@ mod test { assert_eq!(vecmap(&results, |t| t.0.clone()), vecmap(&results, |t| t.1.clone()),); } + + #[test] + fn expr_no_constructors() { + let cases = vec![ + ( + "{ if structure { a: 1 } {} }", + 1, + "{\n if plain::structure {\n Error\n }\n {\n }\n}", + ), + ( + "{ if ( structure { a: 1 } ) {} }", + 0, + "{\n if ((plain::structure { a: 1 })) {\n }\n}", + ), + ("{ if ( structure {} ) {} }", 0, "{\n if ((plain::structure { })) {\n }\n}"), + ( + "{ if (a { x: 1 }, b { y: 2 }) {} }", + 0, + "{\n if ((plain::a { x: 1 }), (plain::b { y: 2 })) {\n }\n}", + ), + ( + "{ if ({ let foo = bar { baz: 42 }; foo == bar { baz: 42 }}) {} }", + 0, + "{\n if ({\n let foo: unspecified = (plain::bar { baz: 42 })\ + \n (plain::foo == (plain::bar { baz: 42 }))\n }) {\n }\n}", + ), + ]; + + let show_errors = |v| vecmap(&v, ToString::to_string).join("\n"); + + let results = vecmap(&cases, |&(src, expected_errors, expected_result)| { + let (opt, errors) = parse_recover(block(fresh_statement()), src); + let actual = opt.map(|ast| ast.to_string()); + let actual = if let Some(s) = &actual { s.to_string() } else { "(none)".to_string() }; + + let result = + ((errors.len(), actual.clone()), (expected_errors, expected_result.to_string())); + if result.0 != result.1 { + let num_errors = errors.len(); + let shown_errors = show_errors(errors); + eprintln!( + "\nExpected {expected_errors} error(s) and got {num_errors}:\n\n{shown_errors}\n\nFrom input: {src}\nExpected AST: {expected_result}\nActual AST: {actual}\n"); + } + result + }); + + assert_eq!(vecmap(&results, |t| t.0.clone()), vecmap(&results, |t| t.1.clone()),); + } } diff --git a/compiler/source-resolver/package.json b/compiler/source-resolver/package.json index 7f9530324b6..0726b544610 100644 --- a/compiler/source-resolver/package.json +++ b/compiler/source-resolver/package.json @@ -1,6 +1,6 @@ { "name": "@noir-lang/source-resolver", - "version": "0.16.0", + "version": "0.18.0", "license": "MIT", "main": "./lib-node/index_node.js", "types": "./types/index_node.d.ts", diff --git a/compiler/wasm/build.rs b/compiler/wasm/build.rs index 3b96be74ef3..dc46037a1d9 100644 --- a/compiler/wasm/build.rs +++ b/compiler/wasm/build.rs @@ -1,14 +1,4 @@ -const GIT_COMMIT: &&str = &"GIT_COMMIT"; - fn main() { - // Only use build_data if the environment variable isn't set - // The environment variable is always set when working via Nix - if std::env::var(GIT_COMMIT).is_err() { - build_data::set_GIT_COMMIT(); - build_data::set_GIT_DIRTY(); - build_data::no_debug_rebuilds(); - } - build_data::set_SOURCE_TIMESTAMP(); build_data::no_debug_rebuilds(); } diff --git a/compiler/wasm/fixtures/deps/lib-a/Nargo.toml b/compiler/wasm/fixtures/deps/lib-a/Nargo.toml new file mode 100644 index 00000000000..3a02ccc1086 --- /dev/null +++ b/compiler/wasm/fixtures/deps/lib-a/Nargo.toml @@ -0,0 +1,8 @@ +[package] +name="lib_a" +type="lib" +authors = [""] +compiler_version = "0.1" + +[dependencies] +lib_b = { path = "../lib-b" } diff --git a/compiler/wasm/fixtures/deps/lib-a/src/lib.nr b/compiler/wasm/fixtures/deps/lib-a/src/lib.nr new file mode 100644 index 00000000000..abb4302ba38 --- /dev/null +++ b/compiler/wasm/fixtures/deps/lib-a/src/lib.nr @@ -0,0 +1,7 @@ + +use dep::lib_b::assert_non_zero; + +pub fn divide(a: u64, b: u64) -> u64 { + assert_non_zero(b); + a / b +} diff --git a/compiler/wasm/fixtures/deps/lib-b/Nargo.toml b/compiler/wasm/fixtures/deps/lib-b/Nargo.toml new file mode 100644 index 00000000000..99db61e4bfa --- /dev/null +++ b/compiler/wasm/fixtures/deps/lib-b/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name="lib_b" +type="lib" +authors = [""] +compiler_version = "0.1" + +[dependencies] diff --git a/compiler/wasm/fixtures/deps/lib-b/src/lib.nr b/compiler/wasm/fixtures/deps/lib-b/src/lib.nr new file mode 100644 index 00000000000..ad8b26020e3 --- /dev/null +++ b/compiler/wasm/fixtures/deps/lib-b/src/lib.nr @@ -0,0 +1,4 @@ + +pub fn assert_non_zero(x: u64) { + assert(x != 0); +} diff --git a/compiler/wasm/fixtures/deps/noir-script/Nargo.toml b/compiler/wasm/fixtures/deps/noir-script/Nargo.toml new file mode 100644 index 00000000000..0df22c2be7e --- /dev/null +++ b/compiler/wasm/fixtures/deps/noir-script/Nargo.toml @@ -0,0 +1,8 @@ +[package] +name="noir_wasm_testing" +type="bin" +authors = [""] +compiler_version = "0.1" + +[dependencies] +lib_a = { path="../lib-a" } diff --git a/compiler/wasm/fixtures/deps/noir-script/src/main.nr b/compiler/wasm/fixtures/deps/noir-script/src/main.nr new file mode 100644 index 00000000000..d46597fca2e --- /dev/null +++ b/compiler/wasm/fixtures/deps/noir-script/src/main.nr @@ -0,0 +1,4 @@ +use dep::lib_a::divide; +fn main(x : u64, y : pub u64) { + divide(x, y); +} diff --git a/compiler/wasm/noir-script/Nargo.toml b/compiler/wasm/fixtures/simple/noir-script/Nargo.toml similarity index 100% rename from compiler/wasm/noir-script/Nargo.toml rename to compiler/wasm/fixtures/simple/noir-script/Nargo.toml diff --git a/compiler/wasm/noir-script/src/main.nr b/compiler/wasm/fixtures/simple/noir-script/src/main.nr similarity index 100% rename from compiler/wasm/noir-script/src/main.nr rename to compiler/wasm/fixtures/simple/noir-script/src/main.nr diff --git a/compiler/wasm/package.json b/compiler/wasm/package.json index 2b47227c5f8..3ed8d03cf5d 100644 --- a/compiler/wasm/package.json +++ b/compiler/wasm/package.json @@ -3,7 +3,7 @@ "collaborators": [ "The Noir Team " ], - "version": "0.16.0", + "version": "0.18.0", "license": "(MIT OR Apache-2.0)", "main": "./nodejs/noir_wasm.js", "types": "./web/noir_wasm.d.ts", @@ -29,7 +29,6 @@ "lint": "NODE_NO_WARNINGS=1 eslint . --ext .ts --ignore-path ./.eslintignore --max-warnings 0", "build:nix": "nix build -L .#noir_wasm", "install:from:nix": "yarn clean && yarn build:nix && cp -rL ./result/noir_wasm/nodejs ./ && cp -rL ./result/noir_wasm/web ./" - }, "peerDependencies": { "@noir-lang/source-resolver": "workspace:*" diff --git a/compiler/wasm/src/compile.rs b/compiler/wasm/src/compile.rs index 0f7baff4819..ac6219ee625 100644 --- a/compiler/wasm/src/compile.rs +++ b/compiler/wasm/src/compile.rs @@ -1,37 +1,62 @@ use fm::FileManager; use gloo_utils::format::JsValueSerdeExt; -use js_sys::Array; +use js_sys::Object; use nargo::artifacts::{ contract::{PreprocessedContract, PreprocessedContractFunction}, program::PreprocessedProgram, }; use noirc_driver::{ add_dep, compile_contract, compile_main, prepare_crate, prepare_dependency, CompileOptions, - CompiledContract, CompiledProgram, + CompiledContract, CompiledProgram, NOIR_ARTIFACT_VERSION_STRING, }; -use noirc_frontend::{graph::CrateGraph, hir::Context}; -use std::path::Path; +use noirc_frontend::{ + graph::{CrateGraph, CrateId, CrateName}, + hir::Context, +}; +use serde::Deserialize; +use std::{collections::HashMap, path::Path}; use wasm_bindgen::prelude::*; -use crate::errors::JsCompileError; +use crate::errors::{CompileError, JsCompileError}; const BACKEND_IDENTIFIER: &str = "acvm-backend-barretenberg"; +#[wasm_bindgen(typescript_custom_section)] +const DEPENDENCY_GRAPH: &'static str = r#" +export type DependencyGraph = { + root_dependencies: readonly string[]; + library_dependencies: Readonly>; +} +"#; + #[wasm_bindgen] extern "C" { - #[wasm_bindgen(extends = Array, js_name = "StringArray", typescript_type = "string[]")] + #[wasm_bindgen(extends = Object, js_name = "DependencyGraph", typescript_type = "DependencyGraph")] #[derive(Clone, Debug, PartialEq, Eq)] - pub type StringArray; + pub type JsDependencyGraph; +} + +#[derive(Deserialize)] +struct DependencyGraph { + root_dependencies: Vec, + library_dependencies: HashMap>, } #[wasm_bindgen] pub fn compile( entry_point: String, contracts: Option, - dependencies: Option, + dependency_graph: Option, ) -> Result { console_error_panic_hook::set_once(); + let dependency_graph: DependencyGraph = if let Some(dependency_graph) = dependency_graph { + ::into_serde(&JsValue::from(dependency_graph)) + .map_err(|err| err.to_string())? + } else { + DependencyGraph { root_dependencies: vec![], library_dependencies: HashMap::new() } + }; + let root = Path::new("/"); let fm = FileManager::new(root, Box::new(get_non_stdlib_asset)); let graph = CrateGraph::default(); @@ -40,12 +65,7 @@ pub fn compile( let path = Path::new(&entry_point); let crate_id = prepare_crate(&mut context, path); - let dependencies: Vec = dependencies - .map(|array| array.iter().map(|element| element.as_string().unwrap()).collect()) - .unwrap_or_default(); - for dependency in dependencies { - add_noir_lib(&mut context, dependency.as_str()); - } + process_dependency_graph(&mut context, dependency_graph); let compile_options = CompileOptions::default(); @@ -57,7 +77,11 @@ pub fn compile( if contracts.unwrap_or_default() { let compiled_contract = compile_contract(&mut context, crate_id, &compile_options) .map_err(|errs| { - JsCompileError::new("Failed to compile contract", errs, &context.file_manager) + CompileError::with_file_diagnostics( + "Failed to compile contract", + errs, + &context.file_manager, + ) })? .0; @@ -71,7 +95,11 @@ pub fn compile( } else { let compiled_program = compile_main(&mut context, crate_id, &compile_options, None, true) .map_err(|errs| { - JsCompileError::new("Failed to compile program", errs, &context.file_manager) + CompileError::with_file_diagnostics( + "Failed to compile program", + errs, + &context.file_manager, + ) })? .0; @@ -85,39 +113,44 @@ pub fn compile( } } -fn add_noir_lib(context: &mut Context, library_name: &str) { - let path_to_lib = Path::new(&library_name).join("lib.nr"); - let library_crate_id = prepare_dependency(context, &path_to_lib); - - add_dep(context, *context.root_crate_id(), library_crate_id, library_name.parse().unwrap()); - - // TODO: Remove this code that attaches every crate to every other crate as a dependency - let root_crate_id = context.root_crate_id(); - let stdlib_crate_id = context.stdlib_crate_id(); - let other_crate_ids: Vec<_> = context - .crate_graph - .iter_keys() - .filter(|crate_id| { - // We don't want to attach this crate to itself or stdlib, nor re-attach it to the root crate - crate_id != &library_crate_id - && crate_id != root_crate_id - && crate_id != stdlib_crate_id - }) - .collect(); +fn process_dependency_graph(context: &mut Context, dependency_graph: DependencyGraph) { + let mut crate_names: HashMap<&CrateName, CrateId> = HashMap::new(); - for crate_id in other_crate_ids { - context - .crate_graph - .add_dep(crate_id, library_name.parse().unwrap(), library_crate_id) - .unwrap_or_else(|_| panic!("ICE: Cyclic error triggered by {library_name} library")); + for lib in &dependency_graph.root_dependencies { + let crate_id = add_noir_lib(context, lib); + crate_names.insert(lib, crate_id); + + add_dep(context, *context.root_crate_id(), crate_id, lib.clone()); + } + + for (lib_name, dependencies) in &dependency_graph.library_dependencies { + // first create the library crate if needed + // this crate might not have been registered yet because of the order of the HashMap + // e.g. {root: [lib1], libs: { lib2 -> [lib3], lib1 -> [lib2] }} + let crate_id = + *crate_names.entry(lib_name).or_insert_with(|| add_noir_lib(context, lib_name)); + + for dependency_name in dependencies { + let dep_crate_id: &CrateId = crate_names + .entry(dependency_name) + .or_insert_with(|| add_noir_lib(context, dependency_name)); + + add_dep(context, crate_id, *dep_crate_id, dependency_name.clone()); + } } } +fn add_noir_lib(context: &mut Context, library_name: &CrateName) -> CrateId { + let path_to_lib = Path::new(&library_name.to_string()).join("lib.nr"); + prepare_dependency(context, &path_to_lib) +} + fn preprocess_program(program: CompiledProgram) -> PreprocessedProgram { PreprocessedProgram { hash: program.hash, backend: String::from(BACKEND_IDENTIFIER), abi: program.abi, + noir_version: NOIR_ARTIFACT_VERSION_STRING.to_string(), bytecode: program.circuit, } } @@ -136,6 +169,7 @@ fn preprocess_contract(contract: CompiledContract) -> PreprocessedContract { .collect(); PreprocessedContract { + noir_version: String::from(NOIR_ARTIFACT_VERSION_STRING), name: contract.name, backend: String::from(BACKEND_IDENTIFIER), functions: preprocessed_functions, @@ -166,3 +200,101 @@ cfg_if::cfg_if! { } } } + +#[cfg(test)] +mod test { + use fm::FileManager; + use noirc_driver::prepare_crate; + use noirc_frontend::{ + graph::{CrateGraph, CrateName}, + hir::Context, + }; + + use super::{process_dependency_graph, DependencyGraph}; + use std::{collections::HashMap, path::Path}; + + fn mock_get_non_stdlib_asset(_path_to_file: &Path) -> std::io::Result { + Ok("".to_string()) + } + + fn setup_test_context() -> Context { + let fm = FileManager::new(Path::new("/"), Box::new(mock_get_non_stdlib_asset)); + let graph = CrateGraph::default(); + let mut context = Context::new(fm, graph); + + prepare_crate(&mut context, Path::new("/main.nr")); + + context + } + + fn crate_name(name: &str) -> CrateName { + name.parse().unwrap() + } + + #[test] + fn test_works_with_empty_dependency_graph() { + let mut context = setup_test_context(); + let dependency_graph = + DependencyGraph { root_dependencies: vec![], library_dependencies: HashMap::new() }; + + process_dependency_graph(&mut context, dependency_graph); + + // one stdlib + one root crate + assert_eq!(context.crate_graph.number_of_crates(), 2); + } + + #[test] + fn test_works_with_root_dependencies() { + let mut context = setup_test_context(); + let dependency_graph = DependencyGraph { + root_dependencies: vec![crate_name("lib1")], + library_dependencies: HashMap::new(), + }; + + process_dependency_graph(&mut context, dependency_graph); + + assert_eq!(context.crate_graph.number_of_crates(), 3); + } + + #[test] + fn test_works_with_duplicate_root_dependencies() { + let mut context = setup_test_context(); + let dependency_graph = DependencyGraph { + root_dependencies: vec![crate_name("lib1"), crate_name("lib1")], + library_dependencies: HashMap::new(), + }; + + process_dependency_graph(&mut context, dependency_graph); + + assert_eq!(context.crate_graph.number_of_crates(), 3); + } + + #[test] + fn test_works_with_transitive_dependencies() { + let mut context = setup_test_context(); + let dependency_graph = DependencyGraph { + root_dependencies: vec![crate_name("lib1")], + library_dependencies: HashMap::from([ + (crate_name("lib1"), vec![crate_name("lib2")]), + (crate_name("lib2"), vec![crate_name("lib3")]), + ]), + }; + + process_dependency_graph(&mut context, dependency_graph); + + assert_eq!(context.crate_graph.number_of_crates(), 5); + } + + #[test] + fn test_works_with_missing_dependencies() { + let mut context = setup_test_context(); + let dependency_graph = DependencyGraph { + root_dependencies: vec![crate_name("lib1")], + library_dependencies: HashMap::from([(crate_name("lib2"), vec![crate_name("lib3")])]), + }; + + process_dependency_graph(&mut context, dependency_graph); + + assert_eq!(context.crate_graph.number_of_crates(), 5); + } +} diff --git a/compiler/wasm/src/errors.rs b/compiler/wasm/src/errors.rs index 7090bf6f19f..9aafcadc27f 100644 --- a/compiler/wasm/src/errors.rs +++ b/compiler/wasm/src/errors.rs @@ -1,5 +1,6 @@ use gloo_utils::format::JsValueSerdeExt; -use serde::{Deserialize, Serialize}; +use js_sys::JsString; +use serde::Serialize; use wasm_bindgen::prelude::*; use fm::FileManager; @@ -9,7 +10,7 @@ use noirc_errors::FileDiagnostic; const DIAGNOSTICS: &'static str = r#" export type Diagnostic = { message: string; - file_path: string; + file: string; secondaries: ReadonlyArray<{ message: string; start: number; @@ -17,66 +18,116 @@ export type Diagnostic = { }>; } -interface CompileError { +export interface CompileError extends Error { + message: string; diagnostics: ReadonlyArray; } "#; -#[derive(Serialize, Deserialize)] -struct JsDiagnosticLabel { +#[wasm_bindgen] +extern "C" { + #[wasm_bindgen(extends = js_sys::Error, js_name = "CompileError", typescript_type = "CompileError")] + #[derive(Clone, Debug, PartialEq, Eq)] + pub type JsCompileError; + + #[wasm_bindgen(constructor, js_class = "Error")] + fn constructor(message: JsString) -> JsCompileError; +} + +impl JsCompileError { + const DIAGNOSTICS_PROP: &'static str = "diagnostics"; + const NAME_PROP: &'static str = "name"; + const ERROR_NAME: &'static str = "CompileError"; + + pub fn new(message: String, diagnostics: Vec) -> Self { + let err = JsCompileError::constructor(JsString::from(message)); + + js_sys::Reflect::set( + &err, + &JsString::from(JsCompileError::NAME_PROP), + &JsString::from(JsCompileError::ERROR_NAME), + ) + .unwrap(); + + js_sys::Reflect::set( + &err, + &JsString::from(JsCompileError::DIAGNOSTICS_PROP), + &::from_serde(&diagnostics).unwrap(), + ) + .unwrap(); + + err + } +} + +impl From for JsCompileError { + fn from(value: String) -> Self { + JsCompileError::new(value, vec![]) + } +} + +impl From for JsCompileError { + fn from(value: CompileError) -> Self { + JsCompileError::new(value.message, value.diagnostics) + } +} + +#[derive(Serialize)] +struct DiagnosticLabel { message: String, start: u32, end: u32, } -#[derive(Serialize, Deserialize)] -struct JsDiagnostic { +#[derive(Serialize)] +pub struct Diagnostic { message: String, - file_path: String, - secondaries: Vec, + file: String, + secondaries: Vec, } -impl JsDiagnostic { - fn new(file_diagnostic: &FileDiagnostic, file_path: String) -> JsDiagnostic { +impl Diagnostic { + fn new(file_diagnostic: &FileDiagnostic, file: String) -> Diagnostic { let diagnostic = &file_diagnostic.diagnostic; let message = diagnostic.message.clone(); let secondaries = diagnostic .secondaries .iter() - .map(|label| JsDiagnosticLabel { + .map(|label| DiagnosticLabel { message: label.message.clone(), start: label.span.start(), end: label.span.end(), }) .collect(); - JsDiagnostic { message, file_path, secondaries } + Diagnostic { message, file, secondaries } } } -#[wasm_bindgen(getter_with_clone, js_name = "CompileError")] -pub struct JsCompileError { - pub message: js_sys::JsString, - pub diagnostics: JsValue, +#[derive(Serialize)] +pub struct CompileError { + pub message: String, + pub diagnostics: Vec, } -impl JsCompileError { - pub fn new( +impl CompileError { + pub fn new(message: &str) -> CompileError { + CompileError { message: message.to_string(), diagnostics: vec![] } + } + + pub fn with_file_diagnostics( message: &str, file_diagnostics: Vec, file_manager: &FileManager, - ) -> JsCompileError { + ) -> CompileError { let diagnostics: Vec<_> = file_diagnostics .iter() .map(|err| { - JsDiagnostic::new(err, file_manager.path(err.file_id).to_str().unwrap().to_string()) + Diagnostic::new(err, file_manager.path(err.file_id).to_str().unwrap().to_string()) }) .collect(); - JsCompileError { - message: js_sys::JsString::from(message.to_string()), - diagnostics: ::from_serde(&diagnostics).unwrap(), - } + CompileError { message: message.to_string(), diagnostics } } } diff --git a/compiler/wasm/src/lib.rs b/compiler/wasm/src/lib.rs index 3a8e00bc6dd..9f2f558f85c 100644 --- a/compiler/wasm/src/lib.rs +++ b/compiler/wasm/src/lib.rs @@ -7,6 +7,7 @@ use getrandom as _; use gloo_utils::format::JsValueSerdeExt; use log::Level; +use noirc_driver::{GIT_COMMIT, GIT_DIRTY, NOIRC_VERSION}; use serde::{Deserialize, Serialize}; use std::str::FromStr; use wasm_bindgen::prelude::*; @@ -37,11 +38,8 @@ pub fn init_log_level(level: String) { }); } -const BUILD_INFO: BuildInfo = BuildInfo { - git_hash: env!("GIT_COMMIT"), - version: env!("CARGO_PKG_VERSION"), - dirty: env!("GIT_DIRTY"), -}; +const BUILD_INFO: BuildInfo = + BuildInfo { git_hash: GIT_COMMIT, version: NOIRC_VERSION, dirty: GIT_DIRTY }; #[wasm_bindgen] pub fn build_info() -> JsValue { diff --git a/compiler/wasm/test/browser/index.test.ts b/compiler/wasm/test/browser/index.test.ts index 02263d9adfb..cad2ada0c61 100644 --- a/compiler/wasm/test/browser/index.test.ts +++ b/compiler/wasm/test/browser/index.test.ts @@ -1,68 +1,98 @@ import { expect } from '@esm-bundle/chai'; import initNoirWasm, { compile } from '@noir-lang/noir_wasm'; import { initializeResolver } from '@noir-lang/source-resolver'; -import { nargoArtifactPath, noirSourcePath } from '../shared'; +import { + depsScriptExpectedArtifact, + depsScriptSourcePath, + libASourcePath, + libBSourcePath, + simpleScriptExpectedArtifact, + simpleScriptSourcePath, +} from '../shared'; beforeEach(async () => { await initNoirWasm(); }); async function getFileContent(path: string): Promise { - const mainnrSourceURL = new URL(path, import.meta.url); - const response = await fetch(mainnrSourceURL); + const url = new URL(path, import.meta.url); + const response = await fetch(url); return await response.text(); } -async function getSource(): Promise { - return getFileContent(noirSourcePath); -} - // eslint-disable-next-line @typescript-eslint/no-explicit-any -async function getPrecompiledSource(): Promise { - const compiledData = await getFileContent(nargoArtifactPath); +async function getPrecompiledSource(path: string): Promise { + const compiledData = await getFileContent(path); return JSON.parse(compiledData); } -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export async function compileNoirSource(noir_source: string): Promise { - console.log('Compiling Noir source...'); +describe('noir wasm', () => { + describe('can compile script without dependencies', () => { + beforeEach(async () => { + const source = await getFileContent(simpleScriptSourcePath); + initializeResolver((id: string) => { + console.log(`Resolving source ${id}`); - initializeResolver((id: string) => { - console.log(`Resolving source ${id}`); + if (typeof source === 'undefined') { + throw Error(`Could not resolve source for '${id}'`); + } else if (id !== '/main.nr') { + throw Error(`Unexpected id: '${id}'`); + } else { + return source; + } + }); + }); - const source = noir_source; + it('matching nargos compilation', async () => { + const wasmCircuit = await compile('/main.nr'); + const cliCircuit = await getPrecompiledSource(simpleScriptExpectedArtifact); - if (typeof source === 'undefined') { - throw Error(`Could not resolve source for '${id}'`); - } else if (id !== '/main.nr') { - throw Error(`Unexpected id: '${id}'`); - } else { - return source; - } + // We don't expect the hashes to match due to how `noir_wasm` handles dependencies + expect(wasmCircuit.bytecode).to.eq(cliCircuit.bytecode); + expect(wasmCircuit.abi).to.deep.eq(cliCircuit.abi); + expect(wasmCircuit.backend).to.eq(cliCircuit.backend); + }).timeout(20e3); // 20 seconds }); - try { - const compiled_noir = compile('main.nr'); + describe('can compile script with dependencies', () => { + beforeEach(async () => { + const [scriptSource, libASource, libBSource] = await Promise.all([ + getFileContent(depsScriptSourcePath), + getFileContent(libASourcePath), + getFileContent(libBSourcePath), + ]); - console.log('Noir source compilation done.'); + initializeResolver((file: string) => { + switch (file) { + case '/script/main.nr': + return scriptSource; - return compiled_noir; - } catch (e) { - console.log('Error while compiling:', e); - } -} + case '/lib_a/lib.nr': + return libASource; + + case '/lib_b/lib.nr': + return libBSource; -describe('noir wasm compilation', () => { - it('matches nargos compilation', async () => { - const source = await getSource(); + default: + return ''; + } + }); + }); - const wasmCircuit = await compileNoirSource(source); + it('matching nargos compilation', async () => { + const wasmCircuit = await compile('/script/main.nr', false, { + root_dependencies: ['lib_a'], + library_dependencies: { + lib_a: ['lib_b'], + }, + }); - const cliCircuit = await getPrecompiledSource(); + const cliCircuit = await getPrecompiledSource(depsScriptExpectedArtifact); - // We don't expect the hashes to match due to how `noir_wasm` handles dependencies - expect(wasmCircuit.bytecode).to.eq(cliCircuit.bytecode); - expect(wasmCircuit.abi).to.deep.eq(cliCircuit.abi); - expect(wasmCircuit.backend).to.eq(cliCircuit.backend); - }).timeout(20e3); // 20 seconds + // We don't expect the hashes to match due to how `noir_wasm` handles dependencies + expect(wasmCircuit.bytecode).to.eq(cliCircuit.bytecode); + expect(wasmCircuit.abi).to.deep.eq(cliCircuit.abi); + expect(wasmCircuit.backend).to.eq(cliCircuit.backend); + }).timeout(20e3); // 20 seconds + }); }); diff --git a/compiler/wasm/test/node/index.test.ts b/compiler/wasm/test/node/index.test.ts index 4ec6d83c3c3..2b430abdca4 100644 --- a/compiler/wasm/test/node/index.test.ts +++ b/compiler/wasm/test/node/index.test.ts @@ -1,26 +1,70 @@ import { expect } from 'chai'; -import { nargoArtifactPath, noirSourcePath } from '../shared'; +import { + depsScriptSourcePath, + depsScriptExpectedArtifact, + libASourcePath, + libBSourcePath, + simpleScriptSourcePath, + simpleScriptExpectedArtifact, +} from '../shared'; import { readFileSync } from 'node:fs'; -import { join } from 'node:path'; +import { join, resolve } from 'node:path'; import { compile } from '@noir-lang/noir_wasm'; - -const absoluteNoirSourcePath = join(__dirname, noirSourcePath); -const absoluteNargoArtifactPath = join(__dirname, nargoArtifactPath); +import { initializeResolver } from '@noir-lang/source-resolver'; // eslint-disable-next-line @typescript-eslint/no-explicit-any -async function getPrecompiledSource(): Promise { - const compiledData = readFileSync(absoluteNargoArtifactPath).toString(); +async function getPrecompiledSource(path: string): Promise { + const compiledData = readFileSync(resolve(__dirname, path)).toString(); return JSON.parse(compiledData); } describe('noir wasm compilation', () => { - it('matches nargos compilation', async () => { - const wasmCircuit = await compile(absoluteNoirSourcePath); - const cliCircuit = await getPrecompiledSource(); - - // We don't expect the hashes to match due to how `noir_wasm` handles dependencies - expect(wasmCircuit.bytecode).to.eq(cliCircuit.bytecode); - expect(wasmCircuit.abi).to.deep.eq(cliCircuit.abi); - expect(wasmCircuit.backend).to.eq(cliCircuit.backend); - }).timeout(10e3); + describe('can compile simple scripts', () => { + it('matching nargos compilation', async () => { + const wasmCircuit = await compile(join(__dirname, simpleScriptSourcePath)); + const cliCircuit = await getPrecompiledSource(simpleScriptExpectedArtifact); + + // We don't expect the hashes to match due to how `noir_wasm` handles dependencies + expect(wasmCircuit.bytecode).to.eq(cliCircuit.bytecode); + expect(wasmCircuit.abi).to.deep.eq(cliCircuit.abi); + expect(wasmCircuit.backend).to.eq(cliCircuit.backend); + }).timeout(10e3); + }); + + describe('can compile scripts with dependencies', () => { + beforeEach(() => { + // this test requires a custom resolver in order to correctly resolve dependencies + initializeResolver((file) => { + switch (file) { + case '/script/main.nr': + return readFileSync(join(__dirname, depsScriptSourcePath), 'utf-8'); + + case '/lib_a/lib.nr': + return readFileSync(join(__dirname, libASourcePath), 'utf-8'); + + case '/lib_b/lib.nr': + return readFileSync(join(__dirname, libBSourcePath), 'utf-8'); + + default: + return ''; + } + }); + }); + + it('matching nargos compilation', async () => { + const wasmCircuit = await compile('/script/main.nr', false, { + root_dependencies: ['lib_a'], + library_dependencies: { + lib_a: ['lib_b'], + }, + }); + + const cliCircuit = await getPrecompiledSource(depsScriptExpectedArtifact); + + // We don't expect the hashes to match due to how `noir_wasm` handles dependencies + expect(wasmCircuit.bytecode).to.eq(cliCircuit.bytecode); + expect(wasmCircuit.abi).to.deep.eq(cliCircuit.abi); + expect(wasmCircuit.backend).to.eq(cliCircuit.backend); + }).timeout(10e3); + }); }); diff --git a/compiler/wasm/test/shared.ts b/compiler/wasm/test/shared.ts index f726316cd74..6fc370f7ac8 100644 --- a/compiler/wasm/test/shared.ts +++ b/compiler/wasm/test/shared.ts @@ -1,2 +1,8 @@ -export const noirSourcePath = '../../noir-script/src/main.nr'; -export const nargoArtifactPath = '../../noir-script/target/noir_wasm_testing.json'; +export const simpleScriptSourcePath = '../../fixtures/simple/noir-script/src/main.nr'; +export const simpleScriptExpectedArtifact = '../../fixtures/simple/noir-script/target/noir_wasm_testing.json'; + +export const depsScriptSourcePath = '../../fixtures/deps/noir-script/src/main.nr'; +export const depsScriptExpectedArtifact = '../../fixtures/deps/noir-script/target/noir_wasm_testing.json'; + +export const libASourcePath = '../../fixtures/deps/lib-a/src/lib.nr'; +export const libBSourcePath = '../../fixtures/deps/lib-b/src/lib.nr'; diff --git a/cspell.json b/cspell.json index ac7953e0653..4df858ffcfa 100644 --- a/cspell.json +++ b/cspell.json @@ -88,6 +88,7 @@ "prettytable", "printstd", "pseudocode", + "quantile", "rustc", "rustup", "schnorr", diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md deleted file mode 100644 index 2b1f293fd64..00000000000 --- a/docs/CONTRIBUTING.md +++ /dev/null @@ -1,57 +0,0 @@ -# Contributing to Noir - -Thank you for your interest in contributing to Noir documentation! We value your contributions in making Noir better. - -This guide will discuss how the Noir team handles [Commits](#commits), [Pull Requests](#pull-requests), [Merging](#merging), and [Versioning](#versioning). - -__Note:__ We won't force external contributors to follow this verbatim, but following these guidelines definitely helps us in accepting your contributions. - -## Commits - -We want to keep our commits small and focused. This allows for easily reviewing individual commits and/or splitting up pull requests when they grow too big. Additionally, this allows us to merge smaller changes quicker and release more often. - -When committing, it's often useful to use the `git add -p` workflow to decide on what parts of the changeset to stage for commit. - -We don't currently enforce any commit standard, however that may change at any time. Mind that the [Noir](https://github.com/noir-lang/noir) repo does enforce the [Conventional Commit](https://www.conventionalcommits.org/en/v1.0.0/) standard. - -## Pull Requests - -Before you create a pull request, search for any issues related to the change you are making. If none exist already, create an issue that thoroughly describes the problem that you are trying to solve. These are used to inform reviewers of the original intent and should be referenced via the pull request template. - -Pull Requests should be focused on the specific change they are working towards. If prerequisite work is required to complete the original pull request, that work should be submitted as a separate pull request. - -This strategy avoids scenarios where pull requests grow too large/out-of-scope and don't get proper reviews—we want to avoid "LGTM, I trust you" reviews. - -The easiest way to do this is to have multiple commits while you work and then you can cherry-pick the smaller changes into separate branches for pull requesting. - -### Reviews - -For any repository in the noir-lang organization, we require code review & approval by __one__ Noir team member before the changes are merged. However, while the docs repository is still getting up-to-speed with the current Noir fetures, we do allow for non-breaking pull requests to be merged at any time. Breaking pull requests should only be merged when the team has general agreement of the changes. - -The CI/CD workflow at Netlify should provide you with a preview of the website once merged. Use this preview to thoroughly test the changes before requesting reviews or merging. - -## Merging - -Once approved by the required number of team members, the pull request can be merged into the `master` branch. Sometimes, especially for external contributions, the final approver may merge the pull request instead of the submitter. - -### Merge Checklist - -Before merging, you should mentally review these questions: - -- Is continuous integration passing? -- Do you have the required amount of approvals? -- Does anyone else need to be pinged for thoughts? - -## Versioning - -The Noir documentation is versioned according to the [Docusaurus documentation](https://docusaurus.io/docs/versioning). In the `versioned_docs` and `versioned_sidebar` folders you will find the docs and configs for the previous versions. If any change needs to be made to older versions, please do it in this folder. - -In the `docs` folder, you'll find the current, unreleased version, which we call `dev`. Any change in this folder will be reflected in the next version, once the Noir team decides to release. - -We aim to have every version matching the versions of [Noir](https://github.com/noir-lang/noir). However, we would only cut a new version of the docs if there are breaking or otherwise significant changes, to avoid unecessary build time and size to the existent documentation. - -While the versioning is intended to be managed by the core maintainers, we feel it's important for external contributors to understand why and how is it maintained. To bump to a new version, run the following command, replacing with the intended version: - -`npm run docusaurus docs:version ` - -This should create a new version by copying the `docs` folder and the `sidebars.js` file to the relevant folders, as well as adding this version to `versions.json`. diff --git a/docs/README.md b/docs/README.md index 21c6b7f7ad6..92f6c5f41f7 100644 --- a/docs/README.md +++ b/docs/README.md @@ -9,20 +9,20 @@ generator. Interested in contributing to the docs? -Check out the contributing guide [here](./CONTRIBUTING.md). +Check out the contributing guide [here](../CONTRIBUTING.md). ## Development ### Installation ``` -$ yarn +yarn ``` ### Local Development ``` -$ yarn start +yarn start ``` This command starts a local development server and opens up a browser window. Most changes are @@ -31,7 +31,7 @@ reflected live without having to restart the server. ### Build ``` -$ yarn build +yarn build ``` This command generates static content into the `build` directory and can be served using any static diff --git a/docs/docs/language_concepts/01_functions.md b/docs/docs/language_concepts/01_functions.md index 2b5f29aac35..47cdea0cf04 100644 --- a/docs/docs/language_concepts/01_functions.md +++ b/docs/docs/language_concepts/01_functions.md @@ -20,6 +20,12 @@ By default, functions are visible only within the package they are defined. To m pub fn foo() {} ``` +You can also restrict the visibility of the function to only the crate it was defined in, by specifying `pub(crate)`: + +```rust +pub(crate) fn foo() {} //foo can only be called within its crate +``` + All parameters in a function must have a type and all types are known at compile time. The parameter is pre-pended with a colon and the parameter type. Multiple parameters are separated using a comma. @@ -40,6 +46,45 @@ fn foo(x : Field, y : pub Field) -> Field { Note that a `return` keyword is unneeded in this case - the last expression in a function's body is returned. +## Main function + +If you're writing a binary, the `main` function is the starting point of your program. You can pass all types of expressions to it, as long as they have a fixed size at compile time: + +```rust +fn main(x : Field) // this is fine: passing a Field +fn main(x : [Field; 2]) // this is also fine: passing a Field with known size at compile-time +fn main(x : (Field, bool)) // 👌: passing a (Field, bool) tuple means size 2 +fn main(x : str<5>) // this is fine, as long as you pass a string of size 5 + +fn main(x : Vec) // can't compile, has variable size +fn main(x : [Field]) // can't compile, has variable size +fn main(....// i think you got it by now +``` + +Keep in mind [tests](../nargo/02_testing.md) don't differentiate between `main` and any other function. The following snippet passes tests, but won't compile or prove: + +```rust +fn main(x : [Field]) { + assert(x[0] == 1); +} + +#[test] +fn test_one() { + main([1, 2]); +} +``` + +```bash +$ nargo test +[testing] Running 1 test functions +[testing] Testing test_one... ok +[testing] All tests passed + +$ nargo check +The application panicked (crashed). +Message: Cannot have variable sized arrays as a parameter to main +``` + ## Call Expressions Calling a function in Noir is executed by using the function name and passing in the necessary @@ -93,6 +138,36 @@ follows: assert(MyStruct::sum(s) == 42); ``` +It is also possible to specialize which method is chosen depending on the [generic](./06_generics.md) type that is used. In this example, the `foo` function returns different values depending on its type: + +```rust +struct Foo {} + +impl Foo { + fn foo(self) -> Field { 1 } +} + +impl Foo { + fn foo(self) -> Field { 2 } +} + +fn main() { + let f1: Foo = Foo{}; + let f2: Foo = Foo{}; + assert(f1.foo() + f2.foo() == 3); +} +``` + +Also note that impls with the same method name defined in them cannot overlap. For example, if we already have `foo` defined for `Foo` and `Foo` like we do above, we cannot also define `foo` in an `impl Foo` since it would be ambiguous which version of `foo` to choose. + +```rust +// Including this impl in the same project as the above snippet would +// cause an overlapping impls error +impl Foo { + fn foo(self) -> Field { 3 } +} +``` + ## Lambdas Lambdas are anonymous functions. They follow the syntax of Rust - `|arg1, arg2, ..., argN| return_expression`. @@ -103,3 +178,48 @@ assert(add_50(100) == 150); ``` See [Lambdas](./08_lambdas.md) for more details. + +## Attributes + +Attributes are metadata that can be applied to a function, using the following syntax: `#[attribute(value)]`. + +Supported attributes include: + +- **builtin**: the function is implemented by the compiler, for efficiency purposes. +- **deprecated**: mark the function as _deprecated_. Calling the function will generate a warning: `warning: use of deprecated function` +- **field**: Used to enable conditional compilation of code depending on the field size. See below for more details +- **oracle**: mark the function as _oracle_; meaning it is an external unconstrained function, implemented in noir_js. See [Unconstrained](./05_unconstrained.md) and [NoirJS](../noir_js/noir_js.md) for more details. +- **test**: mark the function as unit tests. See [Tests](../nargo/02_testing.md) for more details + +### Field Attribute + +The field attribute defines which field the function is compatible for. The function is conditionally compiled, under the condition that the field attribute matches the Noir native field. +The field can be defined implicitly, by using the name of the elliptic curve usually associated to it - for instance bn254, bls12_381 - or explicitly by using the field (prime) order, in decimal or hexadecimal form. +As a result, it is possible to define multiple versions of a function with each version specialized for a different field attribute. This can be useful when a function requires different parameters depending on the underlying elliptic curve. + +Example: we define the function `foo()` three times below. Once for the default Noir bn254 curve, once for the field $\mathbb F_{23}$, which will normally never be used by Noir, and once again for the bls12_381 curve. + +```rust +#[field(bn254)] +fn foo() -> u32 { + 1 +} + +#[field(23)] +fn foo() -> u32 { + 2 +} + +// This commented code would not compile as foo would be defined twice because it is the same field as bn254 +// #[field(21888242871839275222246405745257275088548364400416034343698204186575808495617)] +// fn foo() -> u32 { +// 2 +// } + +#[field(bls12_381)] +fn foo() -> u32 { + 3 +} +``` + +If the field name is not known to Noir, it will discard the function. Field names are case insensitive. diff --git a/docs/docs/modules_packages_crates/workspaces.md b/docs/docs/modules_packages_crates/workspaces.md index eaa09506698..d9ac92667c9 100644 --- a/docs/docs/modules_packages_crates/workspaces.md +++ b/docs/docs/modules_packages_crates/workspaces.md @@ -34,6 +34,6 @@ default-member = "crates/a" `default-member` indicates which package various commands process by default. -Libraries can be defined in a workspace. We just don't have a way to consume libraries from inside a workspace as external dependencies right now. +Libraries can be defined in a workspace. Inside a workspace, these are consumed as `{ path = "../to_lib" }` dependencies in Nargo.toml. Inside a workspace, these are consumed as `{ path = "../to_lib" }` dependencies in Nargo.toml. diff --git a/docs/docs/nargo/01_commands.md b/docs/docs/nargo/01_commands.md index 14c23290ce0..65e2bdb44e3 100644 --- a/docs/docs/nargo/01_commands.md +++ b/docs/docs/nargo/01_commands.md @@ -20,12 +20,12 @@ keywords: ## General options -``` -Options: - --show-ssa Emit debug information for the intermediate SSA IR - --deny-warnings Quit execution when warnings are emitted - -h, --help Print help -``` +| Option | Description | +| -------------------- | -------------------------------------------------- | +| `--show-ssa` | Emit debug information for the intermediate SSA IR | +| `--deny-warnings` | Quit execution when warnings are emitted | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | ## `nargo help [subcommand]` @@ -33,7 +33,9 @@ Prints the list of available commands or specific information of a subcommand. _Arguments_ -- `` - The subcommand whose help message to display +| Argument | Description | +| -------------- | -------------------------------------------- | +| `` | The subcommand whose help message to display | ## `nargo backend` @@ -41,20 +43,20 @@ Installs and selects custom backends used to generate and verify proofs. ### Commands -``` - current Prints the name of the currently active backend - ls Prints the list of currently installed backends - use Select the backend to use - install Install a new backend from a URL - uninstall Uninstalls a backend - help Print this message or the help of the given subcommand(s) -``` +| Command | Description | +| ----------- | --------------------------------------------------------- | +| `current` | Prints the name of the currently active backend | +| `ls` | Prints the list of currently installed backends | +| `use` | Select the backend to use | +| `install` | Install a new backend from a URL | +| `uninstall` | Uninstalls a backend | +| `help` | Print this message or the help of the given subcommand(s) | ### Options -``` --h, --help Print help -``` +| Option | Description | +| ------------ | ----------- | +| `-h, --help` | Print help | ## `nargo check` @@ -63,13 +65,14 @@ values of the Noir program respectively. ### Options -``` - --package The name of the package to check - --workspace Check all packages in the workspace - --print-acir Display the ACIR for compiled circuit - --deny-warnings Treat all warnings as errors --h, --help Print help -``` +| Option | Description | +| --------------------- | ------------------------------------- | +| `--package ` | The name of the package to check | +| `--workspace` | Check all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | ### `nargo codegen-verifier` @@ -77,13 +80,14 @@ Generate a Solidity verifier smart contract for the program. ### Options -``` - --package The name of the package to codegen - --workspace Codegen all packages in the workspace - --print-acir Display the ACIR for compiled circuit - --deny-warnings Treat all warnings as errors --h, --help Print help -``` +| Option | Description | +| --------------------- | ------------------------------------- | +| `--package ` | The name of the package to codegen | +| `--workspace` | Codegen all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | ## `nargo compile` @@ -94,14 +98,15 @@ You can also use "build" as an alias for compile (e.g. `nargo build`). ### Options -``` - --include-keys Include Proving and Verification keys in the build artifacts - --package The name of the package to compile - --workspace Compile all packages in the workspace - --print-acir Display the ACIR for compiled circuit - --deny-warnings Treat all warnings as errors --h, --help Print help -``` +| Option | Description | +| --------------------- | ------------------------------------------------------------ | +| `--include-keys` | Include Proving and Verification keys in the build artifacts | +| `--package ` | The name of the package to compile | +| `--workspace` | Compile all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | ## `nargo new ` @@ -109,19 +114,19 @@ Creates a new Noir project in a new folder. **Arguments** -``` - The path to save the new project -``` +| Argument | Description | +| -------- | -------------------------------- | +| `` | The path to save the new project | ### Options -``` - --name Name of the package [default: package directory name] - --lib Use a library template - --bin Use a binary template [default] - --contract Use a contract template --h, --help Print help -``` +| Option | Description | +| --------------- | ----------------------------------------------------- | +| `--name ` | Name of the package [default: package directory name] | +| `--lib` | Use a library template | +| `--bin` | Use a binary template [default] | +| `--contract` | Use a contract template | +| `-h, --help` | Print help | ## `nargo init` @@ -129,13 +134,13 @@ Creates a new Noir project in the current directory. ### Options -``` - --name Name of the package [default: current directory name] - --lib Use a library template - --bin Use a binary template [default] - --contract Use a contract template --h, --help Print help -``` +| Option | Description | +| --------------- | ----------------------------------------------------- | +| `--name ` | Name of the package [default: current directory name] | +| `--lib` | Use a library template | +| `--bin` | Use a binary template [default] | +| `--contract` | Use a contract template | +| `-h, --help` | Print help | ## `nargo execute [WITNESS_NAME]` @@ -143,20 +148,21 @@ Runs the Noir program and prints its return value. **Arguments** -``` -[WITNESS_NAME] Write the execution witness to named file -``` +| Argument | Description | +| ---------------- | ----------------------------------------- | +| `[WITNESS_NAME]` | Write the execution witness to named file | ### Options -``` --p, --prover-name The name of the toml file which contains the inputs for the prover [default: Prover] - --package The name of the package to execute - --workspace Execute all packages in the workspace - --print-acir Display the ACIR for compiled circuit - --deny-warnings Treat all warnings as errors --h, --help Print help -``` +| Option | Description | +| --------------------------------- | ------------------------------------------------------------------------------------ | +| `-p, --prover-name ` | The name of the toml file which contains the inputs for the prover [default: Prover] | +| `--package ` | The name of the package to execute | +| `--workspace` | Execute all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | _Usage_ @@ -172,16 +178,17 @@ Creates a proof for the program. ### Options -``` --p, --prover-name The name of the toml file which contains the inputs for the prover [default: Prover] --v, --verifier-name The name of the toml file which contains the inputs for the verifier [default: Verifier] - --verify Verify proof after proving - --package The name of the package to prove - --workspace Prove all packages in the workspace - --print-acir Display the ACIR for compiled circuit - --deny-warnings Treat all warnings as errors --h, --help Print help -``` +| Option | Description | +| ------------------------------------- | ---------------------------------------------------------------------------------------- | +| `-p, --prover-name ` | The name of the toml file which contains the inputs for the prover [default: Prover] | +| `-v, --verifier-name ` | The name of the toml file which contains the inputs for the verifier [default: Verifier] | +| `--verify` | Verify proof after proving | +| `--package ` | The name of the package to prove | +| `--workspace` | Prove all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | ## `nargo verify` @@ -189,14 +196,15 @@ Given a proof and a program, verify whether the proof is valid. ### Options -``` --v, --verifier-name The name of the toml file which contains the inputs for the verifier [default: Verifier] - --package The name of the package verify - --workspace Verify all packages in the workspace - --print-acir Display the ACIR for compiled circuit - --deny-warnings Treat all warnings as errors --h, --help Print help -``` +| Option | Description | +| ------------------------------------- | ---------------------------------------------------------------------------------------- | +| `-v, --verifier-name ` | The name of the toml file which contains the inputs for the verifier [default: Verifier] | +| `--package ` | The name of the package to verify | +| `--workspace` | Verify all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | ## `nargo test [TEST_NAME]` @@ -209,15 +217,16 @@ See an example on the [testing page](./testing). ### Options -``` - --show-output Display output of `println` statements - --exact Only run tests that match exactly - --package The name of the package to test - --workspace Test all packages in the workspace - --print-acir Display the ACIR for compiled circuit - --deny-warnings Treat all warnings as errors --h, --help Print help -``` +| Option | Description | +| --------------------- | -------------------------------------- | +| `--show-output` | Display output of `println` statements | +| `--exact` | Only run tests that match exactly | +| `--package ` | The name of the package to test | +| `--workspace` | Test all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | ## `nargo info` @@ -235,3 +244,7 @@ above information about each function of the contract. Start a long-running Language Server process that communicates over stdin/stdout. Usually this command is not run by a user, but instead will be run by a Language Client, such as [vscode-noir](https://github.com/noir-lang/vscode-noir). + +## `nargo fmt` + +Automatically formats your Noir source code based on the default formatting settings. diff --git a/docs/docs/nargo/04_language_server.md b/docs/docs/nargo/04_language_server.md index 8a81d7232d8..144cd249c4b 100644 --- a/docs/docs/nargo/04_language_server.md +++ b/docs/docs/nargo/04_language_server.md @@ -1,9 +1,7 @@ --- title: Language Server -description: - Learn about the Noir Language Server, how to install the components, and configuration that may be required. -keywords: - [Nargo, Language Server, LSP, VSCode, Visual Studio Code] +description: Learn about the Noir Language Server, how to install the components, and configuration that may be required. +keywords: [Nargo, Language Server, LSP, VSCode, Visual Studio Code] --- This section helps you install and configure the Noir Language Server. @@ -23,7 +21,11 @@ The Client component is usually an editor plugin that launches the Server. It co Currently, Noir provides a Language Client for Visual Studio Code via the [vscode-noir](https://github.com/noir-lang/vscode-noir) extension. You can install it via the [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=noir-lang.vscode-noir). -When you language server is running correctly and the VSCode plugin is installed, you should see handy codelens buttons for compilation, execution, and tests: +> **Note:** Noir's Language Server Protocol support currently assumes users' VSCode workspace root to be the same as users' Noir project root (i.e. where Nargo.toml lies). +> +> If LSP features seem to be missing / malfunctioning, make sure you are opening your Noir project directly (instead of as a sub-folder) in your VSCode instance. + +When your language server is running correctly and the VSCode plugin is installed, you should see handy codelens buttons for compilation, measuring circuit size, execution, and tests: ![Compile and Execute](./../../static/img/codelens_compile_execute.png) ![Run test](../../static/img/codelens_run_test.png) @@ -34,7 +36,7 @@ You should also see your tests in the `testing` panel: ### Configuration -* __Noir: Enable LSP__ - If checked, the extension will launch the Language Server via `nargo lsp` and communicate with it. -* __Noir: Nargo Flags__ - Additional flags may be specified if you require them to be added when the extension calls `nargo lsp`. -* __Noir: Nargo Path__ - An absolute path to a Nargo binary with the `lsp` command. This may be useful if Nargo is not within the `PATH` of your editor. -* __Noir > Trace: Server__ - Setting this to `"messages"` or `"verbose"` will log LSP messages between the Client and Server. Useful for debugging. +- **Noir: Enable LSP** - If checked, the extension will launch the Language Server via `nargo lsp` and communicate with it. +- **Noir: Nargo Flags** - Additional flags may be specified if you require them to be added when the extension calls `nargo lsp`. +- **Noir: Nargo Path** - An absolute path to a Nargo binary with the `lsp` command. This may be useful if Nargo is not within the `PATH` of your editor. +- **Noir > Trace: Server** - Setting this to `"messages"` or `"verbose"` will log LSP messages between the Client and Server. Useful for debugging. diff --git a/docs/docs/noir_js/getting_started/01_tiny_noir_app.md b/docs/docs/noir_js/getting_started/01_tiny_noir_app.md index 629a88fd2f1..1b0c8bfc353 100644 --- a/docs/docs/noir_js/getting_started/01_tiny_noir_app.md +++ b/docs/docs/noir_js/getting_started/01_tiny_noir_app.md @@ -1,16 +1,24 @@ --- -title: Full Stack Noir App +title: End-to-end description: Learn how to setup a new app that uses Noir to generate and verify zero-knowledge SNARK proofs in a typescript or javascript environment keywords: [how to, guide, javascript, typescript, noir, barretenberg, zero-knowledge, proofs] --- -Noir JS works both on the browser and on the server, and works for both ESM and CJS module systems. In this page, we will learn how can we write a simple test and a simple web app to verify the standard Noir example. +NoirJS works both on the browser and on the server, and works for both ESM and CJS module systems. In this page, we will learn how can we write a simple test and a simple web app to verify the standard Noir example. ## Before we start +:::note + +Feel free to use whatever versions, just keep in mind that Nargo and the NoirJS packages are meant to be in sync. For example, Nargo 0.18.x matches `noir_js@0.18.x`, etc. + +In this guide, we will be pinned to 0.17.0. + +::: + Make sure you have Node installed on your machine by opening a terminal and executing `node --version`. If you don't see a version, you should install [node](https://github.com/nvm-sh/nvm). You can also use `yarn` if you prefer that package manager over npm (which comes with node). -First of all, follow the the [Nargo guide](../../getting_started/00_nargo_installation.md) to install nargo and create a new project with `nargo new circuit`. Once there, `cd` into the `circuit` folder. You should then be able to compile your circuit into `json` format and see it inside the `target` folder: +First of all, follow the the [Nargo guide](../../getting_started/00_nargo_installation.md) to install nargo version 0.17.0 and create a new project with `nargo new circuit`. Once there, `cd` into the `circuit` folder. You should then be able to compile your circuit into `json` format and see it inside the `target` folder: ```bash nargo compile @@ -34,10 +42,10 @@ Go back to the previous folder and start a new project by running run `npm init` ## Installing dependencies -We'll need two `npm` packages. These packages will provide us the methods we need to run and verify proofs. Let's install them: +We'll need two `npm` packages. These packages will provide us the methods we need to run and verify proofs: ```bash -npm i @noir-lang/backend_barretenberg @noir-lang/noir_js +npm i @noir-lang/backend_barretenberg@^0.17.0 @noir-lang/noir_js@^0.17.0 ``` To serve our page, we can use a build tool such as `vite`. Because we're gonna use some `wasm` files, we need to install a plugin as well. Run: @@ -175,7 +183,7 @@ You'll see other files and folders showing up (like `package-lock.json`, `yarn.l ## Importing our dependencies -We're starting with the good stuff now. At the top of a new the typescript file, import the packages: +We're starting with the good stuff now. At the top of the new javascript file, import the packages: ```ts import { BarretenbergBackend } from '@noir-lang/backend_barretenberg'; @@ -209,18 +217,8 @@ Our dependencies exported two classes: `BarretenbergBackend` and `Noir`. Let's ` ```ts const backend = new BarretenbergBackend(circuit); const noir = new Noir(circuit, backend); - -display('logs', 'Init... ⌛'); -await noir.init(); -display('logs', 'Init... ✅'); ``` -You're probably eager to see stuff happening, so go and run your app now! - -From your terminal, run `npm start` (or `yarn start`). If it doesn't open a browser for you, just visit `localhost:5173`. You'll see your app with the two logs: - -![Getting Started 0](./../../../static/img/noir_getting_started_0.png) - ## Proving Now we're ready to prove stuff! Let's feed some inputs to our circuit and calculate the proof: @@ -230,10 +228,12 @@ const input = { x: 1, y: 2 }; display('logs', 'Generating proof... ⌛'); const proof = await noir.generateFinalProof(input); display('logs', 'Generating proof... ✅'); -display('results', proof); +display('results', proof.proof); ``` -Save your doc and vite should refresh your page automatically. On a modern laptop, proof will generate in less than 100ms, and you'll see this: +You're probably eager to see stuff happening, so go and run your app now! + +From your terminal, run `npm start` (or `yarn start`). If it doesn't open a browser for you, just visit `localhost:5173`. On a modern laptop, proof will generate in less than 100ms, and you'll see this: ![Getting Started 0](./../../../static/img/noir_getting_started_1.png) @@ -248,3 +248,9 @@ if (verification) display('logs', 'Verifying proof... ✅'); ``` By saving, your app will refresh and here's our complete Tiny Noir App! + +## Further Reading + +You can see how noirjs is used in a full stack Next.js hardhat application in the [noir-starter repo here](https://github.com/noir-lang/noir-starter/tree/main/next-hardhat). The example shows how to calculate a proof in the browser and verify it with a deployed Solidity verifier contract from noirjs. + +You should also check out the more advanced examples in the [noir-examples repo](https://github.com/noir-lang/noir-examples), where you'll find reference usage for some cool apps. diff --git a/docs/docs/noir_js/noir_js.md b/docs/docs/noir_js/noir_js.md index a4609215f92..23ea550e156 100644 --- a/docs/docs/noir_js/noir_js.md +++ b/docs/docs/noir_js/noir_js.md @@ -1,22 +1,36 @@ --- -title: Noir JS -description: Learn how to use noir js to use Noir in a Typescript or Javascript environment +title: NoirJS +description: Interact with Noir in Typescript or Javascript keywords: [Noir project, javascript, typescript, node.js, browser, react] --- -Noir JS are a set of typescript libraries that make it easy to use Noir on your dapp, webapp, node.js server, website, etc. +NoirJS is a TypeScript library that make it easy to use Noir on your dapp, webapp, Node.js server, website, etc. -It is composed of two major elements: +A typical workflow would be composed of two major elements: -- Noir -- Backend proving system +- NoirJS +- Proving backend of choice's JavaScript package -Your only concern should be to write Noir. Noir.js will work out-of-the box and abstract all the components, such as the ACVM and others. +To install NoirJS, install Node.js if you have not already and run this in your JavaScript project: -## Barretenberg +```bash +npm i @noir-lang/noir_js +``` -Since Noir is backend agnostic, you can instantiate `noir_js` with supported backends through their own `js` interface. +## Proving backend -Aztec Labs maintains the `barretenberg` backend. You can use it to instantiate your `Noir` class. +Since Noir is backend agnostic, you can instantiate NoirJS without any backend (i.e. to execute a function). But for proving, you would have to instantiate NoirJS with any of the supported backends through their own `js` interface. + +### Barretenberg + +Aztec Labs maintains the `barretenberg` proving backend, which you can instantiate and make use of alongside NoirJS. It is also the default proving backend installed and used with Nargo, the Noir CLI tool. + +To install its JavaScript library, run this in your project: + +```bash +npm i @noir-lang/backend_barretenberg +``` + +For more details on how to instantiate and use the libraries, refer to the [Full Noir App Guide](./getting_started/01_tiny_noir_app.md) and [Reference](./reference/01_noirjs.md) sections. diff --git a/docs/docs/noir_js/reference/02_noirjs.md b/docs/docs/noir_js/reference/01_noirjs.md similarity index 78% rename from docs/docs/noir_js/reference/02_noirjs.md rename to docs/docs/noir_js/reference/01_noirjs.md index 07baf1e0bbe..d9e5a0c6115 100644 --- a/docs/docs/noir_js/reference/02_noirjs.md +++ b/docs/docs/noir_js/reference/01_noirjs.md @@ -54,6 +54,35 @@ This method takes no parameters await noirInstance.init(); ``` +## `execute` + +This async method allows to execute a circuit to get its witness and return value. [`generateFinalProof`](#generatefinalproof) calls it for you, but you can call it directly (i.e. to feed directly to a backend, or to get the return value). + +### Syntax + +```js +async execute(inputs) +``` + +### Parameters + +| Parameter | Type | Description | +| --------- | ------ | ------------------------------------------------ | +| `inputs` | Object | An object containing the inputs to your circuit. | + +### Returns + +| Return value | Type | Description | +| ------------ | --------------------- | --------------------------------------------------- | +| `witness` | Promise | The witness | +| `returnValue` | Promise | The return value | + +### Usage + +```js +const { witness, returnValue } = await noir.execute(inputs) +``` + ## `generateFinalProof` This async method generates a witness and a proof given an object as input. diff --git a/docs/docs/noir_js/reference/01_bb_backend.md b/docs/docs/noir_js/reference/02_bb_backend.md similarity index 99% rename from docs/docs/noir_js/reference/01_bb_backend.md rename to docs/docs/noir_js/reference/02_bb_backend.md index 446bf9820ea..21c2ff32b57 100644 --- a/docs/docs/noir_js/reference/01_bb_backend.md +++ b/docs/docs/noir_js/reference/02_bb_backend.md @@ -41,7 +41,7 @@ constructor(acirCircuit, (numberOfThreads = 1)); | Parameter | Type | Description | | ----------------- | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `acirCircuit` | Object | A circuit represented in a `json` format, containing the ABI and bytecode Tipically obtained by running [`nargo compile`](../../nargo/01_commands.md). This is the same circuit expected to be passed to [the Noir class](02_noirjs.md) | +| `acirCircuit` | Object | A circuit represented in a `json` format, containing the ABI and bytecode Tipically obtained by running [`nargo compile`](../../nargo/01_commands.md). This is the same circuit expected to be passed to [the Noir class](01_noirjs.md) | | `numberOfThreads` | Number (optional) | The number of threads to be used by the backend. Defaults to 1. | ### Usage diff --git a/docs/sidebars.js b/docs/sidebars.js index 205ecb76038..8fddb677a58 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -98,7 +98,7 @@ const sidebars = { }, { type: 'category', - label: 'Noir JS', + label: 'NoirJS', link: { type: 'doc', id: 'noir_js/noir_js', @@ -106,21 +106,21 @@ const sidebars = { items: [ { type: 'category', - label: 'Reference', + label: 'Guides', items: [ { type: 'autogenerated', - dirName: 'noir_js/reference', + dirName: 'noir_js/getting_started', }, ], }, { type: 'category', - label: 'Guides', + label: 'Reference', items: [ { type: 'autogenerated', - dirName: 'noir_js/getting_started', + dirName: 'noir_js/reference', }, ], }, diff --git a/docs/static/img/codelens_compile_execute.png b/docs/static/img/codelens_compile_execute.png index 347490f529f..040e3af2704 100644 Binary files a/docs/static/img/codelens_compile_execute.png and b/docs/static/img/codelens_compile_execute.png differ diff --git a/docs/static/img/codelens_run_test.png b/docs/static/img/codelens_run_test.png index 3ff94df0903..568869fb839 100644 Binary files a/docs/static/img/codelens_run_test.png and b/docs/static/img/codelens_run_test.png differ diff --git a/docs/static/img/noir_getting_started_0.png b/docs/static/img/noir_getting_started_0.png deleted file mode 100644 index 9e1f569ceec..00000000000 Binary files a/docs/static/img/noir_getting_started_0.png and /dev/null differ diff --git a/docs/versioned_docs/version-0.10.5/standard_library/recursion.md b/docs/versioned_docs/version-0.10.5/standard_library/recursion.md index 4705ae6c575..ff4c63acaa7 100644 --- a/docs/versioned_docs/version-0.10.5/standard_library/recursion.md +++ b/docs/versioned_docs/version-0.10.5/standard_library/recursion.md @@ -93,4 +93,4 @@ The next verifier can either perform a final verification (returning true or fal ## Example -You can see an example of how to do recursive proofs in [this example recursion demo repo](https://github.com/Savio-Sou/recursion-demo/tree/main). +You can see an example of how to do recursive proofs in [this example recursion demo repo](https://github.com/noir-lang/noir-examples/tree/master/recursion). diff --git a/flake.nix b/flake.nix index d0342e79966..1a52fcc639e 100644 --- a/flake.nix +++ b/flake.nix @@ -73,15 +73,15 @@ # Configuration shared between builds config = { # x-release-please-start-version - version = "0.16.0"; + version = "0.18.0"; # x-release-please-end src = pkgs.lib.cleanSourceWith { src = craneLib.path ./.; # Custom filter with various file extensions that we rely upon to build packages - # Currently: `.nr`, `.sol`, `.sh`, `.json`, `.md` + # Currently: `.nr`, `.sol`, `.sh`, `.json`, `.md` and `.wasm` filter = path: type: - (builtins.match ".*\.(nr|sol|sh|json|md)$" path != null) || (craneLib.filterCargoSources path type); + (builtins.match ".*\.(nr|sol|sh|json|md|wasm)$" path != null) || (craneLib.filterCargoSources path type); }; # TODO(#1198): It'd be nice to include these flags when running `cargo clippy` in a devShell. diff --git a/noir_stdlib/src/hash.nr b/noir_stdlib/src/hash.nr index 78e71aefb65..fb79038a06c 100644 --- a/noir_stdlib/src/hash.nr +++ b/noir_stdlib/src/hash.nr @@ -13,6 +13,13 @@ pub fn pedersen(input : [Field; N]) -> [Field; 2] { #[foreign(pedersen)] pub fn pedersen_with_separator(_input : [Field; N], _separator : u32) -> [Field; 2] {} +pub fn pedersen_hash(input : [Field; N]) -> Field { + pedersen_hash_with_separator(input, 0) +} + +#[foreign(pedersen_hash)] +pub fn pedersen_hash_with_separator(_input : [Field; N], _separator : u32) -> Field {} + #[foreign(hash_to_field_128_security)] pub fn hash_to_field(_input : [Field; N]) -> Field {} diff --git a/noir_stdlib/src/sha256.nr b/noir_stdlib/src/sha256.nr index f6c22aa1d5f..d2afd21db8a 100644 --- a/noir_stdlib/src/sha256.nr +++ b/noir_stdlib/src/sha256.nr @@ -5,7 +5,9 @@ // Auxiliary mappings; names as in FIPS PUB 180-4 fn rotr32(a: u32, b: u32) -> u32 // 32-bit right rotation { - (a >> b) | (a << (32 as u32 - b)) + // None of the bits overlap between `(a >> b)` and `(a << (32 - b))` + // Addition is then equivalent to OR, with fewer constraints. + (a >> b) + (a << (32 - b)) } fn ch(x: u32, y: u32, z: u32) -> u32 diff --git a/noir_stdlib/src/sha512.nr b/noir_stdlib/src/sha512.nr index e5cac7b1554..c565b16c098 100644 --- a/noir_stdlib/src/sha512.nr +++ b/noir_stdlib/src/sha512.nr @@ -5,7 +5,9 @@ // Auxiliary mappings; names as in FIPS PUB 180-4 fn rotr64(a: u64, b: u64) -> u64 // 64-bit right rotation { - (a >> b) | (a << (64 - b)) + // None of the bits overlap between `(a >> b)` and `(a << (64 - b))` + // Addition is then equivalent to OR, with fewer constraints. + (a >> b) + (a << (64 - b)) } fn sha_ch(x: u64, y: u64, z: u64) -> u64 diff --git a/release-tests/test/version.test.js b/release-tests/test/version.test.js index 07051d1edce..7a70639d83e 100644 --- a/release-tests/test/version.test.js +++ b/release-tests/test/version.test.js @@ -21,9 +21,12 @@ test("promise resolved", async () => { test("prints version", async () => { const processOutput = (await $`${NARGO_BIN} --version`).toString(); - assert.match(processOutput, /nargo\s\d{1,2}.\d{1,2}/); + + // Regex to match the "nargo version" part of the output + assert.match(processOutput, /nargo version = \d{1,2}\.\d{1,2}\.\d{1,2}/); }); + test("reports a clean commit", async () => { const processOutput = (await $`${NARGO_BIN} --version`).toString(); assert.not.match(processOutput, /is dirty: true/) diff --git a/tooling/backend_interface/src/cli/mod.rs b/tooling/backend_interface/src/cli/mod.rs index d1eebb1ba8e..3ea65f28103 100644 --- a/tooling/backend_interface/src/cli/mod.rs +++ b/tooling/backend_interface/src/cli/mod.rs @@ -3,17 +3,21 @@ mod contract; mod gates; mod info; +mod proof_as_fields; mod prove; mod verify; mod version; +mod vk_as_fields; mod write_vk; pub(crate) use contract::ContractCommand; pub(crate) use gates::GatesCommand; pub(crate) use info::InfoCommand; +pub(crate) use proof_as_fields::ProofAsFieldsCommand; pub(crate) use prove::ProveCommand; pub(crate) use verify::VerifyCommand; pub(crate) use version::VersionCommand; +pub(crate) use vk_as_fields::VkAsFieldsCommand; pub(crate) use write_vk::WriteVkCommand; #[test] diff --git a/tooling/backend_interface/src/cli/proof_as_fields.rs b/tooling/backend_interface/src/cli/proof_as_fields.rs new file mode 100644 index 00000000000..7eb1c1ef35c --- /dev/null +++ b/tooling/backend_interface/src/cli/proof_as_fields.rs @@ -0,0 +1,38 @@ +use std::path::{Path, PathBuf}; + +use acvm::FieldElement; + +use crate::BackendError; + +use super::string_from_stderr; + +/// `ProofAsFieldsCommand` will call the barretenberg binary +/// to split a proof into a representation as [`FieldElement`]s. +pub(crate) struct ProofAsFieldsCommand { + pub(crate) proof_path: PathBuf, + pub(crate) vk_path: PathBuf, +} + +impl ProofAsFieldsCommand { + pub(crate) fn run(self, binary_path: &Path) -> Result, BackendError> { + let mut command = std::process::Command::new(binary_path); + + command + .arg("proof_as_fields") + .arg("-p") + .arg(self.proof_path) + .arg("-k") + .arg(self.vk_path) + .arg("-o") + .arg("-"); + + let output = command.output()?; + if output.status.success() { + let string_output = String::from_utf8(output.stdout).unwrap(); + serde_json::from_str(&string_output) + .map_err(|err| BackendError::CommandFailed(err.to_string())) + } else { + Err(BackendError::CommandFailed(string_from_stderr(&output.stderr))) + } + } +} diff --git a/tooling/backend_interface/src/cli/vk_as_fields.rs b/tooling/backend_interface/src/cli/vk_as_fields.rs new file mode 100644 index 00000000000..1b0212241c4 --- /dev/null +++ b/tooling/backend_interface/src/cli/vk_as_fields.rs @@ -0,0 +1,39 @@ +use std::path::{Path, PathBuf}; + +use acvm::FieldElement; + +use crate::BackendError; + +use super::string_from_stderr; + +/// VkAsFieldsCommand will call the barretenberg binary +/// to split a verification key into a representation as [`FieldElement`]s. +/// +/// The hash of the verification key will also be returned. +pub(crate) struct VkAsFieldsCommand { + pub(crate) vk_path: PathBuf, +} + +impl VkAsFieldsCommand { + pub(crate) fn run( + self, + binary_path: &Path, + ) -> Result<(FieldElement, Vec), BackendError> { + let mut command = std::process::Command::new(binary_path); + + command.arg("vk_as_fields").arg("-k").arg(self.vk_path).arg("-o").arg("-"); + + let output = command.output()?; + if output.status.success() { + let string_output = String::from_utf8(output.stdout).unwrap(); + let mut fields: Vec = serde_json::from_str(&string_output) + .map_err(|err| BackendError::CommandFailed(err.to_string()))?; + + // The first element of this vector is the hash of the verification key, we want to split that off. + let hash = fields.remove(0); + Ok((hash, fields)) + } else { + Err(BackendError::CommandFailed(string_from_stderr(&output.stderr))) + } + } +} diff --git a/tooling/backend_interface/src/proof_system.rs b/tooling/backend_interface/src/proof_system.rs index 7d6e7d51888..c4fc6e743e5 100644 --- a/tooling/backend_interface/src/proof_system.rs +++ b/tooling/backend_interface/src/proof_system.rs @@ -7,7 +7,10 @@ use acvm::FieldElement; use acvm::Language; use tempfile::tempdir; -use crate::cli::{GatesCommand, InfoCommand, ProveCommand, VerifyCommand, WriteVkCommand}; +use crate::cli::{ + GatesCommand, InfoCommand, ProofAsFieldsCommand, ProveCommand, VerifyCommand, + VkAsFieldsCommand, WriteVkCommand, +}; use crate::{Backend, BackendError, BackendOpcodeSupport}; impl Backend { @@ -86,17 +89,9 @@ impl Backend { let temp_directory = tempdir().expect("could not create a temporary directory"); let temp_directory = temp_directory.path().to_path_buf(); - // Unlike when proving, we omit any unassigned witnesses. - // Witness values should be ordered by their index but we skip over any indices without an assignment. - let flattened_public_inputs: Vec = - public_inputs.into_iter().map(|(_, el)| el).collect(); - - let proof_with_public_inputs = bb_abstraction_leaks::prepend_public_inputs( - proof.to_vec(), - flattened_public_inputs.to_vec(), - ); - // Create a temporary file for the proof + let proof_with_public_inputs = + bb_abstraction_leaks::prepend_public_inputs(proof.to_vec(), public_inputs); let proof_path = temp_directory.join("proof").with_extension("proof"); write_to_file(&proof_with_public_inputs, &proof_path); @@ -119,6 +114,51 @@ impl Backend { VerifyCommand { crs_path: self.crs_directory(), is_recursive, proof_path, vk_path } .run(binary_path) } + + pub fn get_intermediate_proof_artifacts( + &self, + circuit: &Circuit, + proof: &[u8], + public_inputs: WitnessMap, + ) -> Result<(Vec, FieldElement, Vec), BackendError> { + let binary_path = self.assert_binary_exists()?; + self.assert_correct_version()?; + + let temp_directory = tempdir().expect("could not create a temporary directory"); + let temp_directory = temp_directory.path().to_path_buf(); + + // Create a temporary file for the circuit + // + let bytecode_path = temp_directory.join("circuit").with_extension("bytecode"); + let serialized_circuit = serialize_circuit(circuit); + write_to_file(&serialized_circuit, &bytecode_path); + + // Create the verification key and write it to the specified path + let vk_path = temp_directory.join("vk"); + + WriteVkCommand { + crs_path: self.crs_directory(), + bytecode_path, + vk_path_output: vk_path.clone(), + } + .run(binary_path)?; + + // Create a temporary file for the proof + + let proof_with_public_inputs = + bb_abstraction_leaks::prepend_public_inputs(proof.to_vec(), public_inputs); + let proof_path = temp_directory.join("proof").with_extension("proof"); + write_to_file(&proof_with_public_inputs, &proof_path); + + // Now ready to generate intermediate artifacts. + + let proof_as_fields = + ProofAsFieldsCommand { proof_path, vk_path: vk_path.clone() }.run(binary_path)?; + + let (vk_hash, vk_as_fields) = VkAsFieldsCommand { vk_path }.run(binary_path)?; + + Ok((proof_as_fields, vk_hash, vk_as_fields)) + } } pub(super) fn write_to_file(bytes: &[u8], path: &Path) -> String { diff --git a/tooling/backend_interface/test-binaries/mock_backend/src/info_cmd.rs b/tooling/backend_interface/test-binaries/mock_backend/src/info_cmd.rs index 043cef5934c..e9a7842ba24 100644 --- a/tooling/backend_interface/test-binaries/mock_backend/src/info_cmd.rs +++ b/tooling/backend_interface/test-binaries/mock_backend/src/info_cmd.rs @@ -17,6 +17,7 @@ const INFO_RESPONSE: &str = r#"{ "keccak256", "schnorr_verify", "pedersen", + "pedersen_hash", "hash_to_field_128_security", "ecdsa_secp256k1", "ecdsa_secp256r1", diff --git a/tooling/bb_abstraction_leaks/build.rs b/tooling/bb_abstraction_leaks/build.rs index 1ae5a28f5a8..8d490416094 100644 --- a/tooling/bb_abstraction_leaks/build.rs +++ b/tooling/bb_abstraction_leaks/build.rs @@ -10,7 +10,7 @@ use const_format::formatcp; const USERNAME: &str = "AztecProtocol"; const REPO: &str = "aztec-packages"; -const VERSION: &str = "0.8.10"; +const VERSION: &str = "0.11.1"; const TAG: &str = formatcp!("aztec-packages-v{}", VERSION); const API_URL: &str = diff --git a/tooling/bb_abstraction_leaks/src/lib.rs b/tooling/bb_abstraction_leaks/src/lib.rs index e0fdc467c53..fec53809ad4 100644 --- a/tooling/bb_abstraction_leaks/src/lib.rs +++ b/tooling/bb_abstraction_leaks/src/lib.rs @@ -1,7 +1,7 @@ #![warn(unused_crate_dependencies, unused_extern_crates)] #![warn(unreachable_pub)] -use acvm::FieldElement; +use acvm::{acir::native_types::WitnessMap, FieldElement}; pub const ACVM_BACKEND_BARRETENBERG: &str = "acvm-backend-barretenberg"; pub const BB_DOWNLOAD_URL: &str = env!("BB_BINARY_URL"); @@ -23,13 +23,11 @@ pub fn remove_public_inputs(num_pub_inputs: usize, proof: &[u8]) -> Vec { } /// Prepends a set of public inputs to a proof. -pub fn prepend_public_inputs(proof: Vec, public_inputs: Vec) -> Vec { - if public_inputs.is_empty() { - return proof; - } - +pub fn prepend_public_inputs(proof: Vec, public_inputs: WitnessMap) -> Vec { + // We omit any unassigned witnesses. + // Witness values should be ordered by their index but we skip over any indices without an assignment. let public_inputs_bytes = - public_inputs.into_iter().flat_map(|assignment| assignment.to_be_bytes()); + public_inputs.into_iter().flat_map(|(_, assignment)| assignment.to_be_bytes()); public_inputs_bytes.chain(proof).collect() } diff --git a/tooling/debugger/Cargo.toml b/tooling/debugger/Cargo.toml index e01abd9ac61..1f9a54b4fe8 100644 --- a/tooling/debugger/Cargo.toml +++ b/tooling/debugger/Cargo.toml @@ -13,5 +13,6 @@ acvm.workspace = true nargo.workspace = true noirc_printable_type.workspace = true thiserror.workspace = true +codespan-reporting.workspace = true easy-repl = "0.2.1" -owo-colors = "3" \ No newline at end of file +owo-colors = "3" diff --git a/tooling/debugger/src/lib.rs b/tooling/debugger/src/lib.rs index f8e9db19234..42f447ac857 100644 --- a/tooling/debugger/src/lib.rs +++ b/tooling/debugger/src/lib.rs @@ -1,19 +1,27 @@ use acvm::acir::circuit::OpcodeLocation; -use acvm::pwg::{ACVMStatus, ErrorLocation, OpcodeResolutionError, ACVM}; +use acvm::pwg::{ + ACVMStatus, BrilligSolver, BrilligSolverStatus, ErrorLocation, OpcodeResolutionError, + StepResult, ACVM, +}; use acvm::BlackBoxFunctionSolver; use acvm::{acir::circuit::Circuit, acir::native_types::WitnessMap}; use nargo::artifacts::debug::DebugArtifact; -use nargo::errors::ExecutionError; +use nargo::errors::{ExecutionError, Location}; use nargo::NargoError; use nargo::ops::ForeignCallExecutor; use easy_repl::{command, CommandStatus, Critical, Repl}; -use std::cell::{Cell, RefCell}; +use std::{ + cell::{Cell, RefCell}, + ops::Range, +}; use owo_colors::OwoColorize; +use codespan_reporting::files::Files; + enum SolveResult { Done, Ok, @@ -21,6 +29,7 @@ enum SolveResult { struct DebugContext<'backend, B: BlackBoxFunctionSolver> { acvm: ACVM<'backend, B>, + brillig_solver: Option>, debug_artifact: DebugArtifact, foreign_call_executor: ForeignCallExecutor, circuit: &'backend Circuit, @@ -28,10 +37,52 @@ struct DebugContext<'backend, B: BlackBoxFunctionSolver> { } impl<'backend, B: BlackBoxFunctionSolver> DebugContext<'backend, B> { + fn step_brillig_opcode(&mut self) -> Result { + let Some(mut solver) = self.brillig_solver.take() else { + unreachable!("Missing Brillig solver"); + }; + match solver.step() { + Ok(status) => { + println!("Brillig step result: {:?}", status); + println!("Brillig program counter: {:?}", solver.program_counter()); + match status { + BrilligSolverStatus::InProgress => { + self.brillig_solver = Some(solver); + Ok(SolveResult::Ok) + } + BrilligSolverStatus::Finished => { + let status = self.acvm.finish_brillig_with_solver(solver); + self.handle_acvm_status(status) + } + BrilligSolverStatus::ForeignCallWait(foreign_call) => { + let foreign_call_result = + self.foreign_call_executor.execute(&foreign_call, self.show_output)?; + solver.resolve_pending_foreign_call(foreign_call_result); + self.brillig_solver = Some(solver); + Ok(SolveResult::Ok) + } + } + } + Err(err) => self.handle_acvm_status(ACVMStatus::Failure(err)), + } + } + fn step_opcode(&mut self) -> Result { - let solver_status = self.acvm.solve_opcode(); + if matches!(self.brillig_solver, Some(_)) { + self.step_brillig_opcode() + } else { + match self.acvm.step_into_brillig_opcode() { + StepResult::IntoBrillig(solver) => { + self.brillig_solver = Some(solver); + self.step_brillig_opcode() + } + StepResult::Status(status) => self.handle_acvm_status(status), + } + } + } - match solver_status { + fn handle_acvm_status(&mut self, status: ACVMStatus) -> Result { + match status { ACVMStatus::Solved => Ok(SolveResult::Done), ACVMStatus::InProgress => Ok(SolveResult::Ok), ACVMStatus::Failure(error) => { @@ -74,25 +125,72 @@ impl<'backend, B: BlackBoxFunctionSolver> DebugContext<'backend, B> { println!("Finished execution"); } else { println!("Stopped at opcode {}: {}", ip, opcodes[ip]); - Self::show_source_code_location(&OpcodeLocation::Acir(ip), &self.debug_artifact); + self.show_source_code_location(&OpcodeLocation::Acir(ip), &self.debug_artifact); } } - fn show_source_code_location(location: &OpcodeLocation, debug_artifact: &DebugArtifact) { + fn print_location_path(&self, loc: Location) { + let line_number = self.debug_artifact.location_line_number(loc).unwrap(); + let column_number = self.debug_artifact.location_column_number(loc).unwrap(); + + println!( + "At {}:{line_number}:{column_number}", + self.debug_artifact.name(loc.file).unwrap() + ); + } + + fn show_source_code_location(&self, location: &OpcodeLocation, debug_artifact: &DebugArtifact) { let locations = debug_artifact.debug_symbols[0].opcode_location(location); - if let Some(locations) = locations { - for loc in locations { - let file = &debug_artifact.file_map[&loc.file]; - let source = &file.source.as_str(); - let start = loc.span.start() as usize; - let end = loc.span.end() as usize; - println!("At {}:{start}-{end}", file.path.as_path().display()); - println!( - "\n{}{}{}\n", - &source[0..start].to_string().dimmed(), - &source[start..end], - &source[end..].to_string().dimmed(), - ); + let Some(locations) = locations else { return }; + for loc in locations { + self.print_location_path(loc); + + let loc_line_index = debug_artifact.location_line_index(loc).unwrap(); + + // How many lines before or after the location's line we + // print + let context_lines = 5; + + let first_line_to_print = + if loc_line_index < context_lines { 0 } else { loc_line_index - context_lines }; + + let last_line_index = debug_artifact.last_line_index(loc).unwrap(); + let last_line_to_print = std::cmp::min(loc_line_index + context_lines, last_line_index); + + let source = debug_artifact.location_source_code(loc).unwrap(); + for (current_line_index, line) in source.lines().enumerate() { + let current_line_number = current_line_index + 1; + + if current_line_index < first_line_to_print { + // Ignore lines before range starts + continue; + } else if current_line_index == first_line_to_print && current_line_index > 0 { + // Denote that there's more lines before but we're not showing them + print_line_of_ellipsis(current_line_index); + } + + if current_line_index > last_line_to_print { + // Denote that there's more lines after but we're not showing them, + // and stop printing + print_line_of_ellipsis(current_line_number); + break; + } + + if current_line_index == loc_line_index { + // Highlight current location + let Range { start: loc_start, end: loc_end } = + debug_artifact.location_in_line(loc).unwrap(); + println!( + "{:>3} {:2} {}{}{}", + current_line_number, + "->", + &line[0..loc_start].to_string().dimmed(), + &line[loc_start..loc_end], + &line[loc_end..].to_string().dimmed() + ); + } else { + print_dimmed_line(current_line_number, line); + } } } } @@ -112,6 +210,14 @@ impl<'backend, B: BlackBoxFunctionSolver> DebugContext<'backend, B> { } } +fn print_line_of_ellipsis(line_number: usize) { + println!("{}", format!("{:>3} {}", line_number, "...").dimmed()); +} + +fn print_dimmed_line(line_number: usize, line: &str) { + println!("{}", format!("{:>3} {:2} {}", line_number, "", line).dimmed()); +} + fn map_command_status(result: SolveResult) -> CommandStatus { match result { SolveResult::Ok => CommandStatus::Done, @@ -129,6 +235,7 @@ pub fn debug_circuit( let context = RefCell::new(DebugContext { acvm: ACVM::new(blackbox_solver, &circuit.opcodes, initial_witness), foreign_call_executor: ForeignCallExecutor::default(), + brillig_solver: None, circuit, debug_artifact, show_output, diff --git a/tooling/lsp/src/solver.rs b/tooling/lsp/src/solver.rs index 2e8bf6ddc0a..090f71d63b4 100644 --- a/tooling/lsp/src/solver.rs +++ b/tooling/lsp/src/solver.rs @@ -16,12 +16,12 @@ impl BlackBoxFunctionSolver for WrapperSolver { self.0.schnorr_verify(public_key_x, public_key_y, signature, message) } - fn pedersen( + fn pedersen_commitment( &self, inputs: &[acvm::FieldElement], domain_separator: u32, ) -> Result<(acvm::FieldElement, acvm::FieldElement), acvm::BlackBoxResolutionError> { - self.0.pedersen(inputs, domain_separator) + self.0.pedersen_commitment(inputs, domain_separator) } fn fixed_base_scalar_mul( @@ -31,6 +31,14 @@ impl BlackBoxFunctionSolver for WrapperSolver { ) -> Result<(acvm::FieldElement, acvm::FieldElement), acvm::BlackBoxResolutionError> { self.0.fixed_base_scalar_mul(low, high) } + + fn pedersen_hash( + &self, + inputs: &[acvm::FieldElement], + domain_separator: u32, + ) -> Result { + self.0.pedersen_hash(inputs, domain_separator) + } } // We also have a mocked implementation of the `BlackBoxFunctionSolver` trait for use in tests @@ -50,7 +58,7 @@ impl BlackBoxFunctionSolver for MockBackend { unimplemented!() } - fn pedersen( + fn pedersen_commitment( &self, _inputs: &[acvm::FieldElement], _domain_separator: u32, @@ -65,4 +73,12 @@ impl BlackBoxFunctionSolver for MockBackend { ) -> Result<(acvm::FieldElement, acvm::FieldElement), acvm::BlackBoxResolutionError> { unimplemented!() } + + fn pedersen_hash( + &self, + _inputs: &[acvm::FieldElement], + _domain_separator: u32, + ) -> Result { + unimplemented!() + } } diff --git a/tooling/nargo/src/artifacts/contract.rs b/tooling/nargo/src/artifacts/contract.rs index fa161b63a5b..4f1ae0e10a0 100644 --- a/tooling/nargo/src/artifacts/contract.rs +++ b/tooling/nargo/src/artifacts/contract.rs @@ -10,6 +10,8 @@ use serde::{Deserialize, Serialize}; /// - Proving and verification keys have been pregenerated based on this ACIR. #[derive(Serialize, Deserialize)] pub struct PreprocessedContract { + /// Version of noir used to compile this contract + pub noir_version: String, /// The name of the contract. pub name: String, /// The identifier of the proving backend which this contract has been compiled for. diff --git a/tooling/nargo/src/artifacts/debug.rs b/tooling/nargo/src/artifacts/debug.rs index 3c173f34876..d2e2eb9f311 100644 --- a/tooling/nargo/src/artifacts/debug.rs +++ b/tooling/nargo/src/artifacts/debug.rs @@ -1,6 +1,6 @@ use codespan_reporting::files::{Error, Files, SimpleFile}; use noirc_driver::DebugFile; -use noirc_errors::debug_info::DebugInfo; +use noirc_errors::{debug_info::DebugInfo, Location}; use serde::{Deserialize, Serialize}; use std::{ collections::{BTreeMap, BTreeSet}, @@ -27,7 +27,7 @@ impl DebugArtifact { function_symbols .locations .values() - .filter_map(|call_stack| call_stack.last().map(|location| location.file)) + .flat_map(|call_stack| call_stack.iter().map(|location| location.file)) }) .collect(); @@ -45,6 +45,53 @@ impl DebugArtifact { Self { debug_symbols, file_map } } + + /// Given a location, returns its file's source code + pub fn location_source_code(&self, location: Location) -> Result<&str, Error> { + self.source(location.file) + } + + /// Given a location, returns the index of the line it starts at + pub fn location_line_index(&self, location: Location) -> Result { + let location_start = location.span.start() as usize; + self.line_index(location.file, location_start) + } + + /// Given a location, returns the line number it starts at + pub fn location_line_number(&self, location: Location) -> Result { + let location_start = location.span.start() as usize; + let line_index = self.line_index(location.file, location_start)?; + self.line_number(location.file, line_index) + } + + /// Given a location, returns the column number it starts at + pub fn location_column_number(&self, location: Location) -> Result { + let location_start = location.span.start() as usize; + let line_index = self.line_index(location.file, location_start)?; + self.column_number(location.file, line_index, location_start) + } + + /// Given a location, returns a Span relative to its line's + /// position in the file. This is useful when processing a file's + /// contents on a per-line-basis. + pub fn location_in_line(&self, location: Location) -> Result, Error> { + let location_start = location.span.start() as usize; + let location_end = location.span.end() as usize; + let line_index = self.line_index(location.file, location_start)?; + let line_span = self.line_range(location.file, line_index)?; + + let start_in_line = location_start - line_span.start; + let end_in_line = location_end - line_span.start; + + Ok(Range { start: start_in_line, end: end_in_line }) + } + + /// Given a location, returns the last line index + /// of its file + pub fn last_line_index(&self, location: Location) -> Result { + let source = self.source(location.file)?; + self.line_index(location.file, source.len()) + } } impl<'a> Files<'a> for DebugArtifact { diff --git a/tooling/nargo/src/artifacts/program.rs b/tooling/nargo/src/artifacts/program.rs index 190b4c76897..5988f3f59cb 100644 --- a/tooling/nargo/src/artifacts/program.rs +++ b/tooling/nargo/src/artifacts/program.rs @@ -9,6 +9,8 @@ use serde::{Deserialize, Serialize}; /// - Proving and verification keys have been pregenerated based on this ACIR. #[derive(Serialize, Deserialize, Debug)] pub struct PreprocessedProgram { + pub noir_version: String, + /// Hash of the [`Program`][noirc_frontend::monomorphization::ast::Program] from which this [`PreprocessedProgram`] /// was compiled. /// diff --git a/tooling/nargo/src/errors.rs b/tooling/nargo/src/errors.rs index ea6e7fa8108..0c920716f2a 100644 --- a/tooling/nargo/src/errors.rs +++ b/tooling/nargo/src/errors.rs @@ -2,7 +2,10 @@ use acvm::{ acir::circuit::OpcodeLocation, pwg::{ErrorLocation, OpcodeResolutionError}, }; -use noirc_errors::{debug_info::DebugInfo, CustomDiagnostic, FileDiagnostic, Location}; +use noirc_errors::{debug_info::DebugInfo, CustomDiagnostic, FileDiagnostic}; + +pub use noirc_errors::Location; + use noirc_printable_type::ForeignCallError; use thiserror::Error; diff --git a/tooling/nargo_cli/Cargo.toml b/tooling/nargo_cli/Cargo.toml index cb824b41428..a1440dc2ecb 100644 --- a/tooling/nargo_cli/Cargo.toml +++ b/tooling/nargo_cli/Cargo.toml @@ -37,7 +37,7 @@ toml.workspace = true serde.workspace = true serde_json.workspace = true prettytable-rs = "0.10" -rayon = "1.7.0" +rayon = "1.8.0" thiserror.workspace = true tower.workspace = true async-lsp = { version = "0.0.5", default-features = false, features = [ diff --git a/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs b/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs index 35538ef1a83..856970544b8 100644 --- a/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs +++ b/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs @@ -76,7 +76,6 @@ fn smart_contract_for_package( workspace, package, compile_options, - false, np_language, &is_opcode_supported, )?; diff --git a/tooling/nargo_cli/src/cli/compile_cmd.rs b/tooling/nargo_cli/src/cli/compile_cmd.rs index a332d63e062..039fee5dbc4 100644 --- a/tooling/nargo_cli/src/cli/compile_cmd.rs +++ b/tooling/nargo_cli/src/cli/compile_cmd.rs @@ -1,6 +1,6 @@ -use std::collections::BTreeMap; use std::path::Path; +use acvm::acir::circuit::opcodes::BlackBoxFuncCall; use acvm::acir::circuit::Opcode; use acvm::Language; use backend_interface::BackendOpcodeSupport; @@ -14,8 +14,8 @@ use nargo::package::Package; use nargo::prepare_package; use nargo::workspace::Workspace; use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelection}; +use noirc_driver::NOIR_ARTIFACT_VERSION_STRING; use noirc_driver::{CompilationResult, CompileOptions, CompiledContract, CompiledProgram}; -use noirc_errors::debug_info::DebugInfo; use noirc_frontend::graph::CrateName; use clap::Args; @@ -23,9 +23,9 @@ use clap::Args; use crate::backends::Backend; use crate::errors::{CliError, CompileError}; -use super::fs::program::read_program_from_file; use super::fs::program::{ - save_contract_to_file, save_debug_artifact_to_file, save_program_to_file, + read_debug_artifact_from_file, read_program_from_file, save_contract_to_file, + save_debug_artifact_to_file, save_program_to_file, }; use super::NargoConfig; use rayon::prelude::*; @@ -40,10 +40,6 @@ pub(crate) struct CompileCommand { #[arg(long)] include_keys: bool, - /// Output debug files - #[arg(long, hide = true)] - output_debug: bool, - /// The name of the package to compile #[clap(long, conflicts_with = "workspace")] package: Option, @@ -82,12 +78,11 @@ pub(crate) fn run( np_language, &opcode_support, &args.compile_options, - args.output_debug, )?; // Save build artifacts to disk. for (package, contract) in contract_packages.into_iter().zip(compiled_contracts) { - save_contract(contract, &package, &circuit_dir, args.output_debug); + save_contract(contract, &package, &circuit_dir); } Ok(()) @@ -100,7 +95,6 @@ pub(super) fn compile_workspace( np_language: Language, opcode_support: &BackendOpcodeSupport, compile_options: &CompileOptions, - output_debug: bool, ) -> Result<(Vec, Vec), CliError> { let is_opcode_supported = |opcode: &_| opcode_support.is_opcode_supported(opcode); @@ -108,14 +102,7 @@ pub(super) fn compile_workspace( let program_results: Vec<(FileManager, CompilationResult)> = binary_packages .par_iter() .map(|package| { - compile_program( - workspace, - package, - compile_options, - output_debug, - np_language, - &is_opcode_supported, - ) + compile_program(workspace, package, compile_options, np_language, &is_opcode_supported) }) .collect(); let contract_results: Vec<(FileManager, CompilationResult)> = @@ -157,7 +144,6 @@ pub(crate) fn compile_bin_package( workspace: &Workspace, package: &Package, compile_options: &CompileOptions, - output_debug: bool, np_language: Language, is_opcode_supported: &impl Fn(&Opcode) -> bool, ) -> Result { @@ -165,14 +151,8 @@ pub(crate) fn compile_bin_package( return Err(CompileError::LibraryCrate(package.name.clone()).into()); } - let (file_manager, compilation_result) = compile_program( - workspace, - package, - compile_options, - output_debug, - np_language, - &is_opcode_supported, - ); + let (file_manager, compilation_result) = + compile_program(workspace, package, compile_options, np_language, &is_opcode_supported); let program = report_errors( compilation_result, @@ -188,31 +168,33 @@ fn compile_program( workspace: &Workspace, package: &Package, compile_options: &CompileOptions, - output_debug: bool, np_language: Language, is_opcode_supported: &impl Fn(&Opcode) -> bool, ) -> (FileManager, CompilationResult) { let (mut context, crate_id) = prepare_package(package, Box::new(|path| std::fs::read_to_string(path))); - let cached_program = if let Ok(preprocessed_program) = - read_program_from_file(workspace.package_build_path(package)) - { - // TODO: Load debug information. + let program_artifact_path = workspace.package_build_path(package); + let mut debug_artifact_path = program_artifact_path.clone(); + debug_artifact_path.set_file_name(format!("debug_{}.json", package.name)); + let cached_program = if let (Ok(preprocessed_program), Ok(mut debug_artifact)) = ( + read_program_from_file(program_artifact_path), + read_debug_artifact_from_file(debug_artifact_path), + ) { Some(CompiledProgram { hash: preprocessed_program.hash, circuit: preprocessed_program.bytecode, abi: preprocessed_program.abi, - debug: DebugInfo::default(), - file_map: BTreeMap::new(), + noir_version: preprocessed_program.noir_version, + debug: debug_artifact.debug_symbols.remove(0), + file_map: debug_artifact.file_map, }) } else { None }; - // If we want to output the debug information then we need to perform a full recompilation of the ACIR. - let force_recompile = output_debug; - + let force_recompile = + cached_program.as_ref().map_or(false, |p| p.noir_version != NOIR_ARTIFACT_VERSION_STRING); let (program, warnings) = match noirc_driver::compile_main( &mut context, crate_id, @@ -226,17 +208,21 @@ fn compile_program( } }; + // TODO: we say that pedersen hashing is supported by all backends for now + let is_opcode_supported_pedersen_hash = |opcode: &Opcode| -> bool { + if let Opcode::BlackBoxFuncCall(BlackBoxFuncCall::PedersenHash { .. }) = opcode { + true + } else { + is_opcode_supported(opcode) + } + }; + // Apply backend specific optimizations. let optimized_program = - nargo::ops::optimize_program(program, np_language, &is_opcode_supported) + nargo::ops::optimize_program(program, np_language, &is_opcode_supported_pedersen_hash) .expect("Backend does not support an opcode that is in the IR"); - save_program( - optimized_program.clone(), - package, - &workspace.target_directory_path(), - output_debug, - ); + save_program(optimized_program.clone(), package, &workspace.target_directory_path()); (context.file_manager, Ok((optimized_program, warnings))) } @@ -264,35 +250,24 @@ fn compile_contract( (context.file_manager, Ok((optimized_contract, warnings))) } -fn save_program( - program: CompiledProgram, - package: &Package, - circuit_dir: &Path, - output_debug: bool, -) { +fn save_program(program: CompiledProgram, package: &Package, circuit_dir: &Path) { let preprocessed_program = PreprocessedProgram { hash: program.hash, backend: String::from(BACKEND_IDENTIFIER), abi: program.abi, + noir_version: program.noir_version, bytecode: program.circuit, }; save_program_to_file(&preprocessed_program, &package.name, circuit_dir); - if output_debug { - let debug_artifact = - DebugArtifact { debug_symbols: vec![program.debug], file_map: program.file_map }; - let circuit_name: String = (&package.name).into(); - save_debug_artifact_to_file(&debug_artifact, &circuit_name, circuit_dir); - } + let debug_artifact = + DebugArtifact { debug_symbols: vec![program.debug], file_map: program.file_map }; + let circuit_name: String = (&package.name).into(); + save_debug_artifact_to_file(&debug_artifact, &circuit_name, circuit_dir); } -fn save_contract( - contract: CompiledContract, - package: &Package, - circuit_dir: &Path, - output_debug: bool, -) { +fn save_contract(contract: CompiledContract, package: &Package, circuit_dir: &Path) { // TODO(#1389): I wonder if it is incorrect for nargo-core to know anything about contracts. // As can be seen here, It seems like a leaky abstraction where ContractFunctions (essentially CompiledPrograms) // are compiled via nargo-core and then the PreprocessedContract is constructed here. @@ -311,6 +286,7 @@ fn save_contract( }); let preprocessed_contract = PreprocessedContract { + noir_version: contract.noir_version, name: contract.name, backend: String::from(BACKEND_IDENTIFIER), functions: preprocessed_functions, @@ -323,13 +299,11 @@ fn save_contract( circuit_dir, ); - if output_debug { - save_debug_artifact_to_file( - &debug_artifact, - &format!("{}-{}", package.name, preprocessed_contract.name), - circuit_dir, - ); - } + save_debug_artifact_to_file( + &debug_artifact, + &format!("{}-{}", package.name, preprocessed_contract.name), + circuit_dir, + ); } /// Helper function for reporting any errors in a `CompilationResult` diff --git a/tooling/nargo_cli/src/cli/debug_cmd.rs b/tooling/nargo_cli/src/cli/debug_cmd.rs index 7d8c0dc9a15..82cd3349ec4 100644 --- a/tooling/nargo_cli/src/cli/debug_cmd.rs +++ b/tooling/nargo_cli/src/cli/debug_cmd.rs @@ -52,14 +52,10 @@ pub(crate) fn run( return Ok(()); }; - let compiled_program = compile_bin_package( - &workspace, - package, - &args.compile_options, - true, - np_language, - &|opcode| opcode_support.is_opcode_supported(opcode), - )?; + let compiled_program = + compile_bin_package(&workspace, package, &args.compile_options, np_language, &|opcode| { + opcode_support.is_opcode_supported(opcode) + })?; println!("[{}] Starting debugger", package.name); let (return_value, solved_witness) = diff --git a/tooling/nargo_cli/src/cli/execute_cmd.rs b/tooling/nargo_cli/src/cli/execute_cmd.rs index c61dc6db69c..1819c9a6f06 100644 --- a/tooling/nargo_cli/src/cli/execute_cmd.rs +++ b/tooling/nargo_cli/src/cli/execute_cmd.rs @@ -57,7 +57,6 @@ pub(crate) fn run( &workspace, package, &args.compile_options, - false, np_language, &|opcode| opcode_support.is_opcode_supported(opcode), )?; diff --git a/tooling/nargo_cli/src/cli/fs/program.rs b/tooling/nargo_cli/src/cli/fs/program.rs index 377786627be..e82f2d55264 100644 --- a/tooling/nargo_cli/src/cli/fs/program.rs +++ b/tooling/nargo_cli/src/cli/fs/program.rs @@ -60,3 +60,14 @@ pub(crate) fn read_program_from_file>( Ok(program) } + +pub(crate) fn read_debug_artifact_from_file>( + debug_artifact_path: P, +) -> Result { + let input_string = std::fs::read(&debug_artifact_path) + .map_err(|_| FilesystemError::PathNotValid(debug_artifact_path.as_ref().into()))?; + let program = serde_json::from_slice(&input_string) + .map_err(|err| FilesystemError::ProgramSerializationError(err.to_string()))?; + + Ok(program) +} diff --git a/tooling/nargo_cli/src/cli/info_cmd.rs b/tooling/nargo_cli/src/cli/info_cmd.rs index e55b1b7886f..50021e842c4 100644 --- a/tooling/nargo_cli/src/cli/info_cmd.rs +++ b/tooling/nargo_cli/src/cli/info_cmd.rs @@ -63,7 +63,6 @@ pub(crate) fn run( np_language, &opcode_support, &args.compile_options, - false, )?; let program_info = binary_packages diff --git a/tooling/nargo_cli/src/cli/init_cmd.rs b/tooling/nargo_cli/src/cli/init_cmd.rs index 6dc7b9bd98e..9d7700a6598 100644 --- a/tooling/nargo_cli/src/cli/init_cmd.rs +++ b/tooling/nargo_cli/src/cli/init_cmd.rs @@ -2,10 +2,11 @@ use crate::backends::Backend; use crate::errors::CliError; use super::fs::{create_named_dir, write_to_file}; -use super::{NargoConfig, CARGO_PKG_VERSION}; +use super::NargoConfig; use clap::Args; use nargo::constants::{PKG_FILE, SRC_DIR}; use nargo::package::PackageType; +use noirc_driver::NOIRC_VERSION; use noirc_frontend::graph::CrateName; use std::path::PathBuf; @@ -72,7 +73,7 @@ pub(crate) fn initialize_project( name = "{package_name}" type = "{package_type}" authors = [""] -compiler_version = "{CARGO_PKG_VERSION}" +compiler_version = "{NOIRC_VERSION}" [dependencies]"# ); diff --git a/tooling/nargo_cli/src/cli/mod.rs b/tooling/nargo_cli/src/cli/mod.rs index a0ef778e1a5..8d22fb1b204 100644 --- a/tooling/nargo_cli/src/cli/mod.rs +++ b/tooling/nargo_cli/src/cli/mod.rs @@ -1,6 +1,7 @@ use clap::{Args, Parser, Subcommand}; use const_format::formatcp; use nargo_toml::find_package_root; +use noirc_driver::NOIR_ARTIFACT_VERSION_STRING; use std::path::PathBuf; use color_eyre::eyre; @@ -26,10 +27,15 @@ mod verify_cmd; const GIT_HASH: &str = env!("GIT_COMMIT"); const IS_DIRTY: &str = env!("GIT_DIRTY"); -const CARGO_PKG_VERSION: &str = env!("CARGO_PKG_VERSION"); - -static VERSION_STRING: &str = - formatcp!("{} (git version hash: {}, is dirty: {})", CARGO_PKG_VERSION, GIT_HASH, IS_DIRTY); +const NARGO_VERSION: &str = env!("CARGO_PKG_VERSION"); + +static VERSION_STRING: &str = formatcp!( + "version = {}\nnoirc version = {}\n(git version hash: {}, is dirty: {})", + NARGO_VERSION, + NOIR_ARTIFACT_VERSION_STRING, + GIT_HASH, + IS_DIRTY +); #[derive(Parser, Debug)] #[command(name="nargo", author, version=VERSION_STRING, about, long_about = None)] diff --git a/tooling/nargo_cli/src/cli/prove_cmd.rs b/tooling/nargo_cli/src/cli/prove_cmd.rs index 5571117e2d4..af300b7ebe0 100644 --- a/tooling/nargo_cli/src/cli/prove_cmd.rs +++ b/tooling/nargo_cli/src/cli/prove_cmd.rs @@ -59,7 +59,6 @@ pub(crate) fn run( &workspace, package, &args.compile_options, - false, np_language, &|opcode| opcode_support.is_opcode_supported(opcode), )?; diff --git a/tooling/nargo_cli/src/cli/verify_cmd.rs b/tooling/nargo_cli/src/cli/verify_cmd.rs index a5a39e9aef9..6ae2b78fd0c 100644 --- a/tooling/nargo_cli/src/cli/verify_cmd.rs +++ b/tooling/nargo_cli/src/cli/verify_cmd.rs @@ -50,7 +50,6 @@ pub(crate) fn run( &workspace, package, &args.compile_options, - false, np_language, &|opcode| opcode_support.is_opcode_supported(opcode), )?; diff --git a/tooling/nargo_cli/tests/acir_artifacts/2_div/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/2_div/target/acir.gz index 42caed06578..37012dece4e 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/2_div/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/2_div/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/3_add/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/3_add/target/acir.gz index cef79cbc46c..490b5f41330 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/3_add/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/3_add/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/4_sub/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/4_sub/target/acir.gz index a6681ca770d..633bec13563 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/4_sub/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/4_sub/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/4_sub/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/4_sub/target/witness.gz index ce60a15c551..68e9df80789 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/4_sub/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/4_sub/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/5_over/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/5_over/target/acir.gz index 053840dca8b..681a0290f75 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/5_over/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/5_over/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/5_over/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/5_over/target/witness.gz index 122614793e2..b0a38188cab 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/5_over/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/5_over/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/6_array/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/6_array/target/acir.gz index bbc40bbae03..f25a320b01e 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/6_array/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/6_array/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/6_array/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/6_array/target/witness.gz index e1ab57f56a1..6aba7ca03c0 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/6_array/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/6_array/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/7_function/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/7_function/target/acir.gz index d08ebb1a635..8b417c250a3 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/7_function/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/7_function/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/7_function/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/7_function/target/witness.gz index 250f96eab04..9dcb6d30140 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/7_function/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/7_function/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/arithmetic_binary_operations/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/arithmetic_binary_operations/target/acir.gz index fb233f84cbf..fd31cc3bfa6 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/arithmetic_binary_operations/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/arithmetic_binary_operations/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/array_dynamic/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/array_dynamic/target/acir.gz index 1b4f0912b08..ba3c09529b1 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/array_dynamic/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/array_dynamic/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/array_dynamic/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/array_dynamic/target/witness.gz index 41a4ec0817e..3cacd507613 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/array_dynamic/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/array_dynamic/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/array_sort/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/array_sort/target/acir.gz index 08ff95bdd92..42d701ede8a 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/array_sort/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/array_sort/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/bit_and/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/bit_and/target/acir.gz index bb100a3693a..5fb7041cdf1 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/bit_and/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/bit_and/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/bit_shifts_comptime/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/bit_shifts_comptime/target/acir.gz index fdea9f57fa8..647dc586b04 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/bit_shifts_comptime/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/bit_shifts_comptime/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/bit_shifts_comptime/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/bit_shifts_comptime/target/witness.gz index 5de81c483c2..13d2ec1b7b5 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/bit_shifts_comptime/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/bit_shifts_comptime/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/bit_shifts_runtime/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/bit_shifts_runtime/target/acir.gz index e6a8f03a590..7a59062156f 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/bit_shifts_runtime/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/bit_shifts_runtime/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/bit_shifts_runtime/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/bit_shifts_runtime/target/witness.gz index 105d4dc8781..28357d49cd1 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/bit_shifts_runtime/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/bit_shifts_runtime/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/bool_not/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/bool_not/target/acir.gz index bffd6c3f723..233a1e25f33 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/bool_not/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/bool_not/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/bool_or/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/bool_or/target/acir.gz index b2550099bf6..697832be207 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/bool_or/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/bool_or/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/brillig_acir_as_brillig/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/brillig_acir_as_brillig/target/acir.gz index bdd4d5bed9d..b7a2d88a36e 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/brillig_acir_as_brillig/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/brillig_acir_as_brillig/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/brillig_assert/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/brillig_assert/target/acir.gz index db07a3c5aa3..2cf3b7251e6 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/brillig_assert/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/brillig_assert/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/brillig_calls/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/brillig_calls/target/acir.gz index e60666c73c8..b91295d3cec 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/brillig_calls/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/brillig_calls/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/brillig_fns_as_values/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/brillig_fns_as_values/target/acir.gz index eb55a029ec8..e8bede3cbed 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/brillig_fns_as_values/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/brillig_fns_as_values/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/brillig_keccak/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/brillig_keccak/target/acir.gz index ae815259717..1a64fd03980 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/brillig_keccak/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/brillig_keccak/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/brillig_not/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/brillig_not/target/acir.gz index 3d625215150..9702ca340a5 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/brillig_not/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/brillig_not/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/brillig_pedersen/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/brillig_pedersen/target/acir.gz index d876646a63e..b8eaf5a13a0 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/brillig_pedersen/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/brillig_pedersen/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/brillig_pedersen/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/brillig_pedersen/target/witness.gz index 860141e7ad9..b26110156a0 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/brillig_pedersen/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/brillig_pedersen/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/brillig_scalar_mul/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/brillig_scalar_mul/target/acir.gz index dfeb06cc1f0..9f5f787c655 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/brillig_scalar_mul/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/brillig_scalar_mul/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/brillig_schnorr/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/brillig_schnorr/target/witness.gz index 8992e084146..17d93cc4d19 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/brillig_schnorr/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/brillig_schnorr/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/conditional_1/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/conditional_1/target/acir.gz index 0bad56713bd..7380f30d354 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/conditional_1/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/conditional_1/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/conditional_1/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/conditional_1/target/witness.gz index bd0870eefc9..2ff44d73044 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/conditional_1/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/conditional_1/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_547/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_547/target/acir.gz deleted file mode 100644 index 090578ca4e3..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_547/target/acir.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_547/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_547/target/witness.gz deleted file mode 100644 index 16880cedea2..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_547/target/witness.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_579/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_579/target/acir.gz deleted file mode 100644 index 2639a2e0809..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_579/target/acir.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_579/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_579/target/witness.gz deleted file mode 100644 index 4e90289d5e1..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_579/target/witness.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_661/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_661/target/acir.gz index 41a4dbd0a2c..01de08c56d2 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_661/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_661/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_to_bits/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_to_bits/target/acir.gz deleted file mode 100644 index 2639a2e0809..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_to_bits/target/acir.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_to_bits/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_to_bits/target/witness.gz deleted file mode 100644 index 4e90289d5e1..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_to_bits/target/witness.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/double_verify_proof/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/double_verify_proof/target/acir.gz index 45f9234a182..a2faad65143 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/double_verify_proof/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/double_verify_proof/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/double_verify_proof/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/double_verify_proof/target/witness.gz index a8a403956a5..251984d6292 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/double_verify_proof/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/double_verify_proof/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/ecdsa_secp256k1/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/ecdsa_secp256k1/target/acir.gz index 2b594788817..9108d663e86 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/ecdsa_secp256k1/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/ecdsa_secp256k1/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/ecdsa_secp256r1/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/ecdsa_secp256r1/target/acir.gz index 0b8cf56b8d5..ec6bc2c73a0 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/ecdsa_secp256r1/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/ecdsa_secp256r1/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/eddsa/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/eddsa/target/acir.gz index 049b7326ea8..275afa4c6e0 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/eddsa/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/eddsa/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/eddsa/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/eddsa/target/witness.gz index fcce3069d87..f87a868de3d 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/eddsa/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/eddsa/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/field_attribute/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/field_attribute/target/acir.gz index a68a3a3b566..9401237fd8c 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/field_attribute/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/field_attribute/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/hash_to_field/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/hash_to_field/target/acir.gz index 4c5bcaa1a31..c2c8c9f9469 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/hash_to_field/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/hash_to_field/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/higher_order_functions/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/higher_order_functions/target/acir.gz index 53bbd84e74c..eab354be13d 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/higher_order_functions/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/higher_order_functions/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/higher_order_functions/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/higher_order_functions/target/witness.gz index 3998fbc8d59..329d15dfb17 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/higher_order_functions/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/higher_order_functions/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/keccak256/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/keccak256/target/acir.gz index 6b57ed0fb85..cb74273e4d7 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/keccak256/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/keccak256/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/main_bool_arg/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/main_bool_arg/target/acir.gz index 753ad7c9687..d054abe1df0 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/main_bool_arg/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/main_bool_arg/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/main_return/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/main_return/target/acir.gz deleted file mode 100644 index 4763c63284d..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/main_return/target/acir.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/main_return/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/main_return/target/witness.gz deleted file mode 100644 index 8083b6de7e4..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/main_return/target/witness.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/merkle_insert/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/merkle_insert/target/acir.gz index 5db7b8b1539..889352e685f 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/merkle_insert/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/merkle_insert/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/merkle_insert/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/merkle_insert/target/witness.gz index 7fdb4d1f9e5..c4ded4eea08 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/merkle_insert/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/merkle_insert/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/modulus/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/modulus/target/acir.gz index 3ac23ecd933..a99124a5e3a 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/modulus/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/modulus/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/nested_array_dynamic/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/nested_array_dynamic/target/acir.gz index 8eb05c0382d..e78bf59102d 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/nested_array_dynamic/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/nested_array_dynamic/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/nested_array_dynamic/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/nested_array_dynamic/target/witness.gz index d5dc73c9bb4..d2ff2ed1b94 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/nested_array_dynamic/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/nested_array_dynamic/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/nested_slice_dynamic/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/nested_slice_dynamic/target/acir.gz index d76d3a08041..fcfd2ab066d 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/nested_slice_dynamic/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/nested_slice_dynamic/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/nested_slice_dynamic/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/nested_slice_dynamic/target/witness.gz index 8d168b8c19c..ba1f5565170 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/nested_slice_dynamic/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/nested_slice_dynamic/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/pedersen_check/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/pedersen_check/target/acir.gz index 0c96568b826..02c9f32e3c5 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/pedersen_check/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/pedersen_check/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/pedersen_check/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/pedersen_check/target/witness.gz index a2cef03fe16..caf34e2b734 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/pedersen_check/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/pedersen_check/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/references_aliasing/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/references_aliasing/target/acir.gz deleted file mode 100644 index 2639a2e0809..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/references_aliasing/target/acir.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/references_aliasing/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/references_aliasing/target/witness.gz deleted file mode 100644 index 4e90289d5e1..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/references_aliasing/target/witness.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/regression/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/regression/target/acir.gz index be72e6abb75..ed80135203d 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/regression/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/regression/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/regression/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/regression/target/witness.gz index 10c1c42caa0..76afd0975f6 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/regression/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/regression/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/regression_2854/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/regression_2854/target/acir.gz index 8a9e4ed2b65..6f4ffaa488f 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/regression_2854/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/regression_2854/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/regression_mem_op_predicate/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/regression_mem_op_predicate/target/acir.gz index 403c0dd43f1..bb54dc5f548 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/regression_mem_op_predicate/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/regression_mem_op_predicate/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/regression_mem_op_predicate/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/regression_mem_op_predicate/target/witness.gz index e8dc551cf13..e8653567d5f 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/regression_mem_op_predicate/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/regression_mem_op_predicate/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/scalar_mul/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/scalar_mul/target/acir.gz index e06ad09e176..0bf8db7df70 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/scalar_mul/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/scalar_mul/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/schnorr/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/schnorr/target/acir.gz index 84a646ab241..4005c95b18d 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/schnorr/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/schnorr/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/schnorr/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/schnorr/target/witness.gz index ebc1ed7f713..91324bd7284 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/schnorr/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/schnorr/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/sha256/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/sha256/target/acir.gz index 8537218ec5c..a2de8064bb5 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/sha256/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/sha256/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/sha2_blocks/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/sha2_blocks/target/acir.gz index 3c21d9a4bf8..1e9c237d083 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/sha2_blocks/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/sha2_blocks/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/sha2_blocks/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/sha2_blocks/target/witness.gz index 40ca3d3f63f..6bedf3922b0 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/sha2_blocks/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/sha2_blocks/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/sha2_byte/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/sha2_byte/target/acir.gz index b285f9c24e5..881bf967590 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/sha2_byte/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/sha2_byte/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/sha2_byte/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/sha2_byte/target/witness.gz index 66d8125a852..746c6fc56a2 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/sha2_byte/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/sha2_byte/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/signed_arithmetic/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/signed_arithmetic/target/acir.gz index a5305fbd1bd..505e8f56bb9 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/signed_arithmetic/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/signed_arithmetic/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/signed_arithmetic/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/signed_arithmetic/target/witness.gz index 5a1d190cdf0..c180c733428 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/signed_arithmetic/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/signed_arithmetic/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/signed_division/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/signed_division/target/acir.gz index e3663c2a7c9..906e4f2010b 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/signed_division/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/signed_division/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/signed_division/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/signed_division/target/witness.gz index 598c8658469..c56799e636a 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/signed_division/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/signed_division/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/simple_array_param/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/simple_array_param/target/acir.gz deleted file mode 100644 index e908711b098..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/simple_array_param/target/acir.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/simple_array_param/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/simple_array_param/target/witness.gz deleted file mode 100644 index a8e277ea795..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/simple_array_param/target/witness.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/simple_bitwise/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/simple_bitwise/target/acir.gz index 71e5cc3ce65..25a54000fdb 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/simple_bitwise/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/simple_bitwise/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/simple_comparison/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/simple_comparison/target/acir.gz index 87ad6a62a57..452780c4d30 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/simple_comparison/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/simple_comparison/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/simple_not/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/simple_not/target/acir.gz index 8f3fd60cc4d..a47defb9fe6 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/simple_not/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/simple_not/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/simple_radix/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/simple_radix/target/acir.gz index 78096c19e45..80a70ba7ee3 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/simple_radix/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/simple_radix/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/simple_radix/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/simple_radix/target/witness.gz index 6ecc30eb054..e730d65c475 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/simple_radix/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/simple_radix/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/simple_shield/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/simple_shield/target/acir.gz index 8fbb88d62bd..9a9f3a76992 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/simple_shield/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/simple_shield/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/simple_shield/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/simple_shield/target/witness.gz index 1a33f9f79e2..0bc6d3e8fbc 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/simple_shield/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/simple_shield/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/slice_dynamic_index/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/slice_dynamic_index/target/acir.gz index f53fbca1f59..30b5d36a2e3 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/slice_dynamic_index/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/slice_dynamic_index/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/slice_dynamic_index/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/slice_dynamic_index/target/witness.gz index 0075dd044dc..1cbd7129bb0 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/slice_dynamic_index/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/slice_dynamic_index/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/slices/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/slices/target/acir.gz index b8a2b19d38b..70a32bccf6f 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/slices/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/slices/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/slices/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/slices/target/witness.gz index d9d8d036339..ac4ffe17323 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/slices/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/slices/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/strings/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/strings/target/witness.gz index 8ee2f7c9148..72a93aabbfe 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/strings/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/strings/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/submodules/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/submodules/target/acir.gz index b2550099bf6..697832be207 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/submodules/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/submodules/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/to_be_bytes/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/to_be_bytes/target/acir.gz index f0742c6cf2b..aec6f367127 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/to_be_bytes/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/to_be_bytes/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/to_be_bytes/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/to_be_bytes/target/witness.gz index 9ffa155a84f..88ed370f861 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/to_be_bytes/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/to_be_bytes/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/to_bytes_consistent/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/to_bytes_consistent/target/acir.gz index a69c76b3198..c505c205faa 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/to_bytes_consistent/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/to_bytes_consistent/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/to_bytes_consistent/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/to_bytes_consistent/target/witness.gz index 3b931590419..5f82918d57a 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/to_bytes_consistent/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/to_bytes_consistent/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/to_bytes_integration/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/to_bytes_integration/target/acir.gz index 4e34c8da2d1..247509bd50a 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/to_bytes_integration/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/to_bytes_integration/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/to_bytes_integration/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/to_bytes_integration/target/witness.gz index b25db55391c..a672966388a 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/to_bytes_integration/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/to_bytes_integration/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/to_le_bytes/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/to_le_bytes/target/acir.gz index 1445a969536..14286c04ef9 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/to_le_bytes/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/to_le_bytes/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/to_le_bytes/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/to_le_bytes/target/witness.gz index b3948caad12..44c71164ae4 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/to_le_bytes/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/to_le_bytes/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/trait_allowed_item_name_matches/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/trait_allowed_item_name_matches/target/acir.gz deleted file mode 100644 index 2639a2e0809..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/trait_allowed_item_name_matches/target/acir.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/trait_allowed_item_name_matches/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/trait_allowed_item_name_matches/target/witness.gz deleted file mode 100644 index 4e90289d5e1..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/trait_allowed_item_name_matches/target/witness.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/trait_as_return_type/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/trait_as_return_type/target/acir.gz new file mode 100644 index 00000000000..1d34f5becaa Binary files /dev/null and b/tooling/nargo_cli/tests/acir_artifacts/trait_as_return_type/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/trait_default_implementation/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/trait_as_return_type/target/witness.gz similarity index 100% rename from tooling/nargo_cli/tests/acir_artifacts/trait_default_implementation/target/witness.gz rename to tooling/nargo_cli/tests/acir_artifacts/trait_as_return_type/target/witness.gz diff --git a/tooling/nargo_cli/tests/acir_artifacts/trait_associated_member_names_clashes/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/trait_associated_member_names_clashes/target/acir.gz deleted file mode 100644 index 2639a2e0809..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/trait_associated_member_names_clashes/target/acir.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/trait_associated_member_names_clashes/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/trait_associated_member_names_clashes/target/witness.gz deleted file mode 100644 index 4e90289d5e1..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/trait_associated_member_names_clashes/target/witness.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/trait_default_implementation/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/trait_default_implementation/target/acir.gz deleted file mode 100644 index b3a99dacb66..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/trait_default_implementation/target/acir.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/trait_function_calls/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/trait_function_calls/target/acir.gz deleted file mode 100644 index 2639a2e0809..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/trait_function_calls/target/acir.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/trait_function_calls/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/trait_function_calls/target/witness.gz deleted file mode 100644 index 4e90289d5e1..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/trait_function_calls/target/witness.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/trait_multi_module_test/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/trait_multi_module_test/target/acir.gz deleted file mode 100644 index 2639a2e0809..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/trait_multi_module_test/target/acir.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/trait_multi_module_test/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/trait_multi_module_test/target/witness.gz deleted file mode 100644 index 4e90289d5e1..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/trait_multi_module_test/target/witness.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/trait_override_implementation/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/trait_override_implementation/target/acir.gz deleted file mode 100644 index b3a99dacb66..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/trait_override_implementation/target/acir.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/trait_override_implementation/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/trait_override_implementation/target/witness.gz deleted file mode 100644 index c3b8e758662..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/trait_override_implementation/target/witness.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/trait_self/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/trait_self/target/acir.gz deleted file mode 100644 index 2639a2e0809..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/trait_self/target/acir.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/trait_self/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/trait_self/target/witness.gz deleted file mode 100644 index 4e90289d5e1..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/trait_self/target/witness.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/trait_where_clause/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/trait_where_clause/target/acir.gz deleted file mode 100644 index 2639a2e0809..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/trait_where_clause/target/acir.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/trait_where_clause/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/trait_where_clause/target/witness.gz deleted file mode 100644 index 4e90289d5e1..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/trait_where_clause/target/witness.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/tuple_inputs/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/tuple_inputs/target/acir.gz index cf2b43945fe..79ae7dccb3d 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/tuple_inputs/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/tuple_inputs/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/tuples/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/tuples/target/acir.gz index 154974745fa..a053f565e5b 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/tuples/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/tuples/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/tuples/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/tuples/target/witness.gz index e48187b08c1..10cffba7141 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/tuples/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/tuples/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/compile_failure/integer_literal_overflow/Nargo.toml b/tooling/nargo_cli/tests/compile_failure/integer_literal_overflow/Nargo.toml new file mode 100644 index 00000000000..f29ec0408ea --- /dev/null +++ b/tooling/nargo_cli/tests/compile_failure/integer_literal_overflow/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "integer_literal_overflow" +type = "bin" +authors = [""] +compiler_version = "0.16.0" + +[dependencies] \ No newline at end of file diff --git a/tooling/nargo_cli/tests/compile_failure/integer_literal_overflow/src/main.nr b/tooling/nargo_cli/tests/compile_failure/integer_literal_overflow/src/main.nr new file mode 100644 index 00000000000..ab1cb457fee --- /dev/null +++ b/tooling/nargo_cli/tests/compile_failure/integer_literal_overflow/src/main.nr @@ -0,0 +1,6 @@ + +fn main() { + foo(1234) +} + +fn foo(_x: u4) {} diff --git a/tooling/nargo_cli/tests/compile_success_contract/contract_with_impl/Nargo.toml b/tooling/nargo_cli/tests/compile_success_contract/contract_with_impl/Nargo.toml new file mode 100644 index 00000000000..99340cf80b5 --- /dev/null +++ b/tooling/nargo_cli/tests/compile_success_contract/contract_with_impl/Nargo.toml @@ -0,0 +1,8 @@ +[package] +name = "simple_contract" +type = "contract" +authors = [""] +compiler_version = "0.1" + +[dependencies] + diff --git a/tooling/nargo_cli/tests/compile_success_contract/contract_with_impl/src/main.nr b/tooling/nargo_cli/tests/compile_success_contract/contract_with_impl/src/main.nr new file mode 100644 index 00000000000..fa04e0d3e7b --- /dev/null +++ b/tooling/nargo_cli/tests/compile_success_contract/contract_with_impl/src/main.nr @@ -0,0 +1,8 @@ + +contract Foo { + struct T { x: [Field] } + + impl T { + fn t(self){} + } +} diff --git a/tooling/nargo_cli/tests/compile_success_empty/brillig_modulo/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/brillig_modulo/src/main.nr index 1cab78ecb95..c2c15f88b91 100644 --- a/tooling/nargo_cli/tests/compile_success_empty/brillig_modulo/src/main.nr +++ b/tooling/nargo_cli/tests/compile_success_empty/brillig_modulo/src/main.nr @@ -7,16 +7,18 @@ fn main() { assert(signed_modulo(5, 3) == 2); assert(signed_modulo(2, 3) == 2); - let minus_two: i4 = 14; - let minus_three: i4 = 13; - let minus_five: i4 = 11; + // See #3275. + // Commented out for now since the previous values which would overflow an i4 are now a compiler error. + // let minus_two: i4 = -2; // 14 + // let minus_three: i4 = -3; // 13 + // let minus_five: i4 = -5; // 11 - // (5 / -3) * -3 + 2 = -1 * -3 + 2 = 3 + 2 = 5 - assert(signed_modulo(5, minus_three) == 2); - // (-5 / 3) * 3 - 2 = -1 * 3 - 2 = -3 - 2 = -5 - assert(signed_modulo(minus_five, 3) == minus_two); - // (-5 / -3) * -3 - 2 = 1 * -3 - 2 = -3 - 2 = -5 - assert(signed_modulo(minus_five, minus_three) == minus_two); + // // (5 / -3) * -3 + 2 = -1 * -3 + 2 = 3 + 2 = 5 + // assert(signed_modulo(5, minus_three) == 2); + // // (-5 / 3) * 3 - 2 = -1 * 3 - 2 = -3 - 2 = -5 + // assert(signed_modulo(minus_five, 3) == minus_two); + // // (-5 / -3) * -3 - 2 = 1 * -3 - 2 = -3 - 2 = -5 + // assert(signed_modulo(minus_five, minus_three) == minus_two); } unconstrained fn modulo(x: u32, y: u32) -> u32 { diff --git a/tooling/nargo_cli/tests/execution_success/conditional_regression_547/Nargo.toml b/tooling/nargo_cli/tests/compile_success_empty/conditional_regression_547/Nargo.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/conditional_regression_547/Nargo.toml rename to tooling/nargo_cli/tests/compile_success_empty/conditional_regression_547/Nargo.toml diff --git a/tooling/nargo_cli/tests/execution_success/conditional_regression_547/Prover.toml b/tooling/nargo_cli/tests/compile_success_empty/conditional_regression_547/Prover.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/conditional_regression_547/Prover.toml rename to tooling/nargo_cli/tests/compile_success_empty/conditional_regression_547/Prover.toml diff --git a/tooling/nargo_cli/tests/execution_success/conditional_regression_547/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/conditional_regression_547/src/main.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/conditional_regression_547/src/main.nr rename to tooling/nargo_cli/tests/compile_success_empty/conditional_regression_547/src/main.nr diff --git a/tooling/nargo_cli/tests/execution_success/conditional_regression_579/Nargo.toml b/tooling/nargo_cli/tests/compile_success_empty/conditional_regression_579/Nargo.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/conditional_regression_579/Nargo.toml rename to tooling/nargo_cli/tests/compile_success_empty/conditional_regression_579/Nargo.toml diff --git a/tooling/nargo_cli/tests/execution_success/conditional_regression_579/Prover.toml b/tooling/nargo_cli/tests/compile_success_empty/conditional_regression_579/Prover.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/conditional_regression_579/Prover.toml rename to tooling/nargo_cli/tests/compile_success_empty/conditional_regression_579/Prover.toml diff --git a/tooling/nargo_cli/tests/execution_success/conditional_regression_579/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/conditional_regression_579/src/main.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/conditional_regression_579/src/main.nr rename to tooling/nargo_cli/tests/compile_success_empty/conditional_regression_579/src/main.nr diff --git a/tooling/nargo_cli/tests/execution_success/conditional_regression_to_bits/Nargo.toml b/tooling/nargo_cli/tests/compile_success_empty/conditional_regression_to_bits/Nargo.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/conditional_regression_to_bits/Nargo.toml rename to tooling/nargo_cli/tests/compile_success_empty/conditional_regression_to_bits/Nargo.toml diff --git a/tooling/nargo_cli/tests/execution_success/conditional_regression_to_bits/Prover.toml b/tooling/nargo_cli/tests/compile_success_empty/conditional_regression_to_bits/Prover.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/conditional_regression_to_bits/Prover.toml rename to tooling/nargo_cli/tests/compile_success_empty/conditional_regression_to_bits/Prover.toml diff --git a/tooling/nargo_cli/tests/execution_success/conditional_regression_to_bits/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/conditional_regression_to_bits/src/main.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/conditional_regression_to_bits/src/main.nr rename to tooling/nargo_cli/tests/compile_success_empty/conditional_regression_to_bits/src/main.nr diff --git a/tooling/nargo_cli/tests/compile_success_empty/let_stmt/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/let_stmt/src/main.nr index d24a77851e4..6c63ecd6e12 100644 --- a/tooling/nargo_cli/tests/compile_success_empty/let_stmt/src/main.nr +++ b/tooling/nargo_cli/tests/compile_success_empty/let_stmt/src/main.nr @@ -7,4 +7,5 @@ fn main() { let _ = 42; let Foo { a: _ } = Foo { a: 42 }; + let _regression_2786 = [Foo { a: 1 }; 8]; } diff --git a/tooling/nargo_cli/tests/execution_success/main_return/Nargo.toml b/tooling/nargo_cli/tests/compile_success_empty/main_return/Nargo.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/main_return/Nargo.toml rename to tooling/nargo_cli/tests/compile_success_empty/main_return/Nargo.toml diff --git a/tooling/nargo_cli/tests/execution_success/main_return/Prover.toml b/tooling/nargo_cli/tests/compile_success_empty/main_return/Prover.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/main_return/Prover.toml rename to tooling/nargo_cli/tests/compile_success_empty/main_return/Prover.toml diff --git a/tooling/nargo_cli/tests/execution_success/main_return/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/main_return/src/main.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/main_return/src/main.nr rename to tooling/nargo_cli/tests/compile_success_empty/main_return/src/main.nr diff --git a/tooling/nargo_cli/tests/compile_success_empty/references_aliasing/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/references_aliasing/src/main.nr index 4582444c8f7..02057732f35 100644 --- a/tooling/nargo_cli/tests/compile_success_empty/references_aliasing/src/main.nr +++ b/tooling/nargo_cli/tests/compile_success_empty/references_aliasing/src/main.nr @@ -1,10 +1,29 @@ -fn increment(mut r: &mut Field) { - *r = *r + 1; -} - fn main() { let mut x = 100; let mut xref = &mut x; increment(xref); assert(*xref == 101); + + regression_2445(); +} + +fn increment(mut r: &mut Field) { + *r = *r + 1; +} + +// If aliasing within arrays and constant folding within the mem2reg pass aren't +// handled, we'll fail to optimize out all the references in this function. +fn regression_2445() { + let mut var = 0; + let ref = &mut &mut var; + + let mut array = [ref, ref]; + + **array[0] = 1; + **array[1] = 2; + + assert(var == 2); + assert(**ref == 2); + assert(**array[0] == 2); + assert(**array[1] == 2); } diff --git a/tooling/nargo_cli/tests/execution_success/simple_array_param/Nargo.toml b/tooling/nargo_cli/tests/compile_success_empty/simple_array_param/Nargo.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/simple_array_param/Nargo.toml rename to tooling/nargo_cli/tests/compile_success_empty/simple_array_param/Nargo.toml diff --git a/tooling/nargo_cli/tests/execution_success/simple_array_param/Prover.toml b/tooling/nargo_cli/tests/compile_success_empty/simple_array_param/Prover.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/simple_array_param/Prover.toml rename to tooling/nargo_cli/tests/compile_success_empty/simple_array_param/Prover.toml diff --git a/tooling/nargo_cli/tests/execution_success/simple_array_param/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/simple_array_param/src/main.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/simple_array_param/src/main.nr rename to tooling/nargo_cli/tests/compile_success_empty/simple_array_param/src/main.nr diff --git a/tooling/nargo_cli/tests/execution_success/trait_allowed_item_name_matches/Nargo.toml b/tooling/nargo_cli/tests/compile_success_empty/trait_allowed_item_name_matches/Nargo.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_allowed_item_name_matches/Nargo.toml rename to tooling/nargo_cli/tests/compile_success_empty/trait_allowed_item_name_matches/Nargo.toml diff --git a/tooling/nargo_cli/tests/execution_success/references_aliasing/Prover.toml b/tooling/nargo_cli/tests/compile_success_empty/trait_allowed_item_name_matches/Prover.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/references_aliasing/Prover.toml rename to tooling/nargo_cli/tests/compile_success_empty/trait_allowed_item_name_matches/Prover.toml diff --git a/tooling/nargo_cli/tests/execution_success/trait_allowed_item_name_matches/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/trait_allowed_item_name_matches/src/main.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_allowed_item_name_matches/src/main.nr rename to tooling/nargo_cli/tests/compile_success_empty/trait_allowed_item_name_matches/src/main.nr diff --git a/tooling/nargo_cli/tests/execution_success/trait_associated_member_names_clashes/Nargo.toml b/tooling/nargo_cli/tests/compile_success_empty/trait_associated_member_names_clashes/Nargo.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_associated_member_names_clashes/Nargo.toml rename to tooling/nargo_cli/tests/compile_success_empty/trait_associated_member_names_clashes/Nargo.toml diff --git a/tooling/nargo_cli/tests/execution_success/trait_allowed_item_name_matches/Prover.toml b/tooling/nargo_cli/tests/compile_success_empty/trait_associated_member_names_clashes/Prover.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_allowed_item_name_matches/Prover.toml rename to tooling/nargo_cli/tests/compile_success_empty/trait_associated_member_names_clashes/Prover.toml diff --git a/tooling/nargo_cli/tests/execution_success/trait_associated_member_names_clashes/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/trait_associated_member_names_clashes/src/main.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_associated_member_names_clashes/src/main.nr rename to tooling/nargo_cli/tests/compile_success_empty/trait_associated_member_names_clashes/src/main.nr diff --git a/tooling/nargo_cli/tests/execution_success/trait_default_implementation/Nargo.toml b/tooling/nargo_cli/tests/compile_success_empty/trait_default_implementation/Nargo.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_default_implementation/Nargo.toml rename to tooling/nargo_cli/tests/compile_success_empty/trait_default_implementation/Nargo.toml diff --git a/tooling/nargo_cli/tests/execution_success/trait_default_implementation/Prover.toml b/tooling/nargo_cli/tests/compile_success_empty/trait_default_implementation/Prover.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_default_implementation/Prover.toml rename to tooling/nargo_cli/tests/compile_success_empty/trait_default_implementation/Prover.toml diff --git a/tooling/nargo_cli/tests/execution_success/trait_default_implementation/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/trait_default_implementation/src/main.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_default_implementation/src/main.nr rename to tooling/nargo_cli/tests/compile_success_empty/trait_default_implementation/src/main.nr diff --git a/tooling/nargo_cli/tests/execution_success/trait_function_calls/Nargo.toml b/tooling/nargo_cli/tests/compile_success_empty/trait_function_calls/Nargo.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_function_calls/Nargo.toml rename to tooling/nargo_cli/tests/compile_success_empty/trait_function_calls/Nargo.toml diff --git a/tooling/nargo_cli/tests/execution_success/trait_associated_member_names_clashes/Prover.toml b/tooling/nargo_cli/tests/compile_success_empty/trait_function_calls/Prover.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_associated_member_names_clashes/Prover.toml rename to tooling/nargo_cli/tests/compile_success_empty/trait_function_calls/Prover.toml diff --git a/tooling/nargo_cli/tests/execution_success/trait_function_calls/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/trait_function_calls/src/main.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_function_calls/src/main.nr rename to tooling/nargo_cli/tests/compile_success_empty/trait_function_calls/src/main.nr diff --git a/tooling/nargo_cli/tests/execution_success/trait_multi_module_test/Nargo.toml b/tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/Nargo.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_multi_module_test/Nargo.toml rename to tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/Nargo.toml diff --git a/tooling/nargo_cli/tests/execution_success/trait_function_calls/Prover.toml b/tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/Prover.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_function_calls/Prover.toml rename to tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/Prover.toml diff --git a/tooling/nargo_cli/tests/execution_success/trait_multi_module_test/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/src/main.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_multi_module_test/src/main.nr rename to tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/src/main.nr diff --git a/tooling/nargo_cli/tests/execution_success/trait_multi_module_test/src/module1.nr b/tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/src/module1.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_multi_module_test/src/module1.nr rename to tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/src/module1.nr diff --git a/tooling/nargo_cli/tests/execution_success/trait_multi_module_test/src/module2.nr b/tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/src/module2.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_multi_module_test/src/module2.nr rename to tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/src/module2.nr diff --git a/tooling/nargo_cli/tests/execution_success/trait_multi_module_test/src/module3.nr b/tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/src/module3.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_multi_module_test/src/module3.nr rename to tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/src/module3.nr diff --git a/tooling/nargo_cli/tests/execution_success/trait_multi_module_test/src/module4.nr b/tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/src/module4.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_multi_module_test/src/module4.nr rename to tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/src/module4.nr diff --git a/tooling/nargo_cli/tests/execution_success/trait_multi_module_test/src/module5.nr b/tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/src/module5.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_multi_module_test/src/module5.nr rename to tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/src/module5.nr diff --git a/tooling/nargo_cli/tests/execution_success/trait_multi_module_test/src/module6.nr b/tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/src/module6.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_multi_module_test/src/module6.nr rename to tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/src/module6.nr diff --git a/tooling/nargo_cli/tests/execution_success/trait_override_implementation/Nargo.toml b/tooling/nargo_cli/tests/compile_success_empty/trait_override_implementation/Nargo.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_override_implementation/Nargo.toml rename to tooling/nargo_cli/tests/compile_success_empty/trait_override_implementation/Nargo.toml diff --git a/tooling/nargo_cli/tests/execution_success/trait_override_implementation/Prover.toml b/tooling/nargo_cli/tests/compile_success_empty/trait_override_implementation/Prover.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_override_implementation/Prover.toml rename to tooling/nargo_cli/tests/compile_success_empty/trait_override_implementation/Prover.toml diff --git a/tooling/nargo_cli/tests/execution_success/trait_override_implementation/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/trait_override_implementation/src/main.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_override_implementation/src/main.nr rename to tooling/nargo_cli/tests/compile_success_empty/trait_override_implementation/src/main.nr diff --git a/tooling/nargo_cli/tests/execution_success/trait_self/Nargo.toml b/tooling/nargo_cli/tests/compile_success_empty/trait_self/Nargo.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_self/Nargo.toml rename to tooling/nargo_cli/tests/compile_success_empty/trait_self/Nargo.toml diff --git a/tooling/nargo_cli/tests/execution_success/trait_self/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/trait_self/src/main.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_self/src/main.nr rename to tooling/nargo_cli/tests/compile_success_empty/trait_self/src/main.nr diff --git a/tooling/nargo_cli/tests/execution_success/trait_self/trait_self/Nargo.toml b/tooling/nargo_cli/tests/compile_success_empty/trait_self/trait_self/Nargo.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_self/trait_self/Nargo.toml rename to tooling/nargo_cli/tests/compile_success_empty/trait_self/trait_self/Nargo.toml diff --git a/tooling/nargo_cli/tests/execution_success/trait_self/trait_self/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/trait_self/trait_self/src/main.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_self/trait_self/src/main.nr rename to tooling/nargo_cli/tests/compile_success_empty/trait_self/trait_self/src/main.nr diff --git a/tooling/nargo_cli/tests/execution_success/trait_where_clause/Nargo.toml b/tooling/nargo_cli/tests/compile_success_empty/trait_where_clause/Nargo.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_where_clause/Nargo.toml rename to tooling/nargo_cli/tests/compile_success_empty/trait_where_clause/Nargo.toml diff --git a/tooling/nargo_cli/tests/execution_success/trait_where_clause/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/trait_where_clause/src/main.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_where_clause/src/main.nr rename to tooling/nargo_cli/tests/compile_success_empty/trait_where_clause/src/main.nr diff --git a/tooling/nargo_cli/tests/execution_success/trait_where_clause/src/the_trait.nr b/tooling/nargo_cli/tests/compile_success_empty/trait_where_clause/src/the_trait.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_where_clause/src/the_trait.nr rename to tooling/nargo_cli/tests/compile_success_empty/trait_where_clause/src/the_trait.nr diff --git a/tooling/nargo_cli/tests/execution_success/brillig_pedersen/Prover.toml b/tooling/nargo_cli/tests/execution_success/brillig_pedersen/Prover.toml index 2fb3b1e1abf..db1ebdf6c51 100644 --- a/tooling/nargo_cli/tests/execution_success/brillig_pedersen/Prover.toml +++ b/tooling/nargo_cli/tests/execution_success/brillig_pedersen/Prover.toml @@ -2,5 +2,6 @@ x = "0" y = "1" salt = "42" -out_x = "0x0c5e1ddecd49de44ed5e5798d3f6fb7c71fe3d37f5bee8664cf88a445b5ba0af" -out_y = "0x230294a041e26fe80b827c2ef5cb8784642bbaa83842da2714d62b1f3c4f9752" \ No newline at end of file +out_x = "0x054aa86a73cb8a34525e5bbed6e43ba1198e860f5f3950268f71df4591bde402" +out_y = "0x209dcfbf2cfb57f9f6046f44d71ac6faf87254afc7407c04eb621a6287cac126" +out_hash = "0x0d98561fb02ca04d00801dfdc118b2a24cea0351963587712a28d368041370e1" diff --git a/tooling/nargo_cli/tests/execution_success/brillig_pedersen/src/main.nr b/tooling/nargo_cli/tests/execution_success/brillig_pedersen/src/main.nr index 24de7f0ac83..dfa10c96663 100644 --- a/tooling/nargo_cli/tests/execution_success/brillig_pedersen/src/main.nr +++ b/tooling/nargo_cli/tests/execution_success/brillig_pedersen/src/main.nr @@ -1,9 +1,13 @@ use dep::std; -unconstrained fn main(x: Field, y: Field, salt: Field, out_x: Field, out_y: Field ) { +unconstrained fn main(x: Field, y: Field, salt: Field, out_x: Field, out_y: Field, out_hash: Field) { let res = std::hash::pedersen_with_separator([x, y], 0); assert(res[0] == out_x); assert(res[1] == out_y); + let res_hash = std::hash::pedersen_hash_with_separator([x, y], 0); + assert_eq(res_hash, out_hash); + + assert(res_hash != res[0]); let raw_data = [x,y]; let mut state = 0; diff --git a/tooling/nargo_cli/tests/execution_success/brillig_schnorr/Prover.toml b/tooling/nargo_cli/tests/execution_success/brillig_schnorr/Prover.toml index 5fe6bd2546f..2faf2018e07 100644 --- a/tooling/nargo_cli/tests/execution_success/brillig_schnorr/Prover.toml +++ b/tooling/nargo_cli/tests/execution_success/brillig_schnorr/Prover.toml @@ -1,10 +1,70 @@ -message = [0,1,2,3,4,5,6,7,8,9] +message = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] message_field = "0x010203040506070809" -pub_key_x = "0x17cbd3ed3151ccfd170efe1d54280a6a4822640bf5c369908ad74ea21518a9c5" -pub_key_y = "0x0e0456e3795c1a31f20035b741cd6158929eeccd320d299cfcac962865a6bc74" +pub_key_x = "0x04b260954662e97f00cab9adb773a259097f7a274b83b113532bce27fa3fb96a" +pub_key_y = "0x2fd51571db6c08666b0edfbfbc57d432068bccd0110a39b166ab243da0037197" signature = [ - 5, 202, 31, 146, 81, 242, 246, 69, 43, 107, 249, 153, 198, 44, 14, 111, 191, 121, 137, 166, - 160, 103, 18, 181, 243, 233, 226, 95, 67, 16, 37, 128, 85, 76, 19, 253, 30, 77, 192, 53, 138, - 205, 69, 33, 236, 163, 83, 194, 84, 137, 184, 221, 176, 121, 179, 27, 63, 70, 54, 16, 176, - 250, 39, 239, -] \ No newline at end of file + 1, + 13, + 119, + 112, + 212, + 39, + 233, + 41, + 84, + 235, + 255, + 93, + 245, + 172, + 186, + 83, + 157, + 253, + 76, + 77, + 33, + 128, + 178, + 15, + 214, + 67, + 105, + 107, + 177, + 234, + 77, + 48, + 27, + 237, + 155, + 84, + 39, + 84, + 247, + 27, + 22, + 8, + 176, + 230, + 24, + 115, + 145, + 220, + 254, + 122, + 135, + 179, + 171, + 4, + 214, + 202, + 64, + 199, + 19, + 84, + 239, + 138, + 124, + 12, +] diff --git a/tooling/nargo_cli/tests/execution_success/double_verify_proof/Prover.toml b/tooling/nargo_cli/tests/execution_success/double_verify_proof/Prover.toml index aa7b1e1371c..3e6d996d0e1 100644 --- a/tooling/nargo_cli/tests/execution_success/double_verify_proof/Prover.toml +++ b/tooling/nargo_cli/tests/execution_success/double_verify_proof/Prover.toml @@ -1,6 +1,12 @@ input_aggregation_object = ["0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"] -key_hash = "0x17a5d2b205c1bf45b015ba33bc2f0beb7fbb36682f31f953b8d4d093c8644be5" -proof = ["0x0000000000000000000000000000000000000000000000000000000000000003","0x0000000000000000000000000000008f66908323784e7c5259f4eefab77ca881","0x0000000000000000000000000000000000109cac7b943f9b737d7b023d4f5d8a","0x000000000000000000000000000000e991d3ac0a68a252bd3cd09cd1b43fe1b4","0x000000000000000000000000000000000014213d346a426777351fdabaa0fa26","0x000000000000000000000000000000e4603692a76af630015380b08d0e13c239","0x0000000000000000000000000000000000149e7046461203c1b72392bb93c262","0x000000000000000000000000000000c27ffc719f223ca6ef5476a5b66f03a4a8","0x000000000000000000000000000000000003718c62098243e3c1f38090e61753","0x000000000000000000000000000000749492aa98716ce5bf7c06e5c2a0a8a528","0x000000000000000000000000000000000018e4c7d33848bccdc3eed924bfaa15","0x0000000000000000000000000000004e10a37f41fd7c4fe32982daa498530d62","0x00000000000000000000000000000000001b76c8c59489c63f11280187109dd7","0x0000000000000000000000000000002a6cd84d3b8537a7c3cb0cb9461f02e4bb","0x0000000000000000000000000000000000197e524fd48ca5ccb30d6c5ffe689d","0x0000000000000000000000000000000013bf25498ce1f51078c06dac450c0325","0x000000000000000000000000000000000018d347b88a0c32e32571deb9b40466","0x00000000000000000000000000000060d496191298eb1b1c2ce18f9a4afcfc55","0x000000000000000000000000000000000024e11b8e8fcb45b8628cb9cc565513","0x00000000000000000000000000000004e976f6d12fff6250eea2d21c570d3d6a","0x00000000000000000000000000000000000967dbd89d2c7dc0121ea71ded7203","0x000000000000000000000000000000d96f810588c0daa43e88d765a3f82ea9b7","0x00000000000000000000000000000000001f69d7015fe6694bd1d4d61049dae9","0x000000000000000000000000000000c539910d0f81a890fa3d996a676db39640","0x000000000000000000000000000000000026d8b64020a669e24f740b4eba633a","0x000000000000000000000000000000c53cc90f99c40eb5d449f38180d9e9c8b6","0x00000000000000000000000000000000001071ddf2bacc2367dfb2c5084b7dd1","0x0000000000000000000000000000001b9791181eb174db1a50d903fa9fea9999","0x0000000000000000000000000000000000118c059d41a95311a5c361c6a9a00d","0x0000000000000000000000000000003caf4ad04551a3ffba19cc6a1fff457370","0x00000000000000000000000000000000001dc4d8be804c5289fbf54183f93149","0x00000000000000000000000000000050766764bb82799df5172043c515956263","0x00000000000000000000000000000000000a5849adbac9c33e53571b29aab672","0x0000000000000000000000000000002edb078e589d44ac93e283680b34adf574","0x000000000000000000000000000000000015e9e187c4fb683ca78d52a2a0301b","0x00000000000000000000000000000048ac0f1db3575ed0f84d61ab6cbdd53d9f","0x00000000000000000000000000000000002ddc4243fbc7104347d29a823194ae","0x00000000000000000000000000000070ad92aeea2bdea4277ffdfa3d3ed93443","0x000000000000000000000000000000000003bad3e3aae806c278094cb682a8e0","0x000000000000000000000000000000fb74b99eb44c80d8f7ba83d7e9e2efa5c0","0x00000000000000000000000000000000002819cc14e399c1dadc4f921e2a58fa","0x000000000000000000000000000000e3938bb3e7866c6499ec44fb72549efca0","0x00000000000000000000000000000000002d8264d5cdc2109da12e1864aca147","0x000000000000000000000000000000b12d7828cacbe86350f0b171b0cb0d1cd4","0x0000000000000000000000000000000000244155cecb315326f05641cac9475c","0x070b059f9471e22eed5a9ea08093dba3c59c941634611884c5f0f1a1a6b93e5c","0x118124ada70b46c7d23a6ca8b90d545f30e028b1689fe5c55c86bf55f42e0401","0x25dca6ad78c03ce1f7783cc39a5ea5ef90b318d5edf4f1367d4451c1db3c113e","0x0d9557b4e661b5c53b84fcb41f05d15c0ca112430db16f56d0ab54032fffe734","0x06aedf13a3b182784f4d64162f4706759f95e42fc8dc17d1b8b5f551dafdc007","0x132f97ab5f1f8817689b17e336125c5273d6970a1b3b0901fd26d193a4d2dce4","0x1b0c9980b5b09343e807d82bad307a06d1bfadcd1fa50be666c2907d31ef43e1","0x1ce7000cb24ecc1f2ff9d9507b2290513fed574a84d893811cb54a3c0bc51ccc","0x2e1df58d36444c2dfda98991847422f56ef66f079d26eb7f8110d0d7c46b2c0c","0x166c2f821be7c3e3e4440980e73770840194f14d003778b7fbcdd2690776255c","0x1ae8390287e2eb117851a5011575ba3801e5ee5c66a8f7432e2a2fb13c276008","0x047c09806bfb272d940d9b802e3e49b40050fd0f66717e8b325c5d4834b13aac","0x08f81300d7f64e5b281b37005c7c936800a1fa1ecce2fd1664b8ba9069627558","0x2ed7260e623b68d580304751341bb72141314b881e9e8dade626bf5cde8a077c","0x23e04c035fd9396ca06cdc0171f24da00287e87b338bf45992e2ea41a589d560","0x285c5583cbd4609a347a7781a030975402d8e58a99fd72e4c53f4789da3b100c","0x2cd85f0437cf87c7c8881301ce6ee1080329e29a006ef16ff79ba4d20eec4ab8","0x12eb74da267caf98c494db16c87f90f510fdca1f8095b40156a6f0bb066e3400","0x2267004535c434df4cbee1a356e48b1f317cb849ac69c3eb94e377d2274f1e08","0x2c9d4ce9d1d8b8cf1cb90cbc3e121f570c8260c53b48ed2070d474d5a6f12c4e","0x2c6c83ffaad6f30da5aa696973ccfbd0337cb7a5e5f9e5fc8e826dce21e8f51c","0x056c23922e9435f93853044ba96a1c12db97f47053987df5187269ce884ec00f","0x09e82d129a8f5d26cc609fcbd7a865c6dbe8f17fba09fc804acec716bcfffabb","0x0e643693068a8454606e3b4c05e6af7adc39ee8f207b7b0b7d2b245ef1b13567","0x12e040137285ab81f47bd6cc3424f92edc8aeb9e86ecf996af8781a726627013","0x00f01a11c2990ecba44568cb7b2bd25edb46f760ed26ff69e6160c86539d8563","0x28a91699dfa4e85e18e8621d39a147a40930701d2d88546e01adb71a1f8e407f","0x000000000000000000000000000000009d7cc0b2d2bdef816f4fb17e7a6f6c08","0x00000000000000000000000000000000bcfc1a7030171f681f2c6e97c61f4e70","0x00000000000000000000000000000000dc7b742d8d704f4ecf092bb111cf30d8","0x13b099dc4869006fde9df04bf36f4c8f08d4491cc6229ac36a98f93214c79b6a","0x008fa95e0d431d617d8d3288fde7f8bbe36492019943e2018564633528575892","0x0fc66c06bdff20dba4dc491d5cd13cc209c4d2d9e29802db665bb397c2a4e754","0x0fe48ae6623efbaadce6d6b75b87be6caa19c2fd4d94a74149ceb6bcb88251e1","0x1bb41738028855cb5e0085edcd62cff208121427ea19a57425a0cf6bb68deb93","0x0fbc646333ddc21ab1a77b01a35973a56d5a617c482a21a231497fd3cc9b74c1","0x19ab9eaa1a902faff2dd9baa19ff00cea9086baa8c28bcdb95f7a3549eaf09b4","0x25e2b7a7643df4d964cd787b593888b00abfe3ce79e8deaa6d68fd1686b84bcb","0x2d134d7eea07414451e54854d61d5b71245434d0638bba9a1184914f65f2521c","0x03df94e38e9eed8586acd277d180d5d515b49d89d37525f871be2ff4552c586c","0x0b102abb146839f073c4a2514e65a8962f48ee8bbd1801e815d9c42d34665ebd","0x000000000000000000000000000000b7a4109cb92b514401fb63667454a9c892","0x0000000000000000000000000000000000016fce7f8ef56fef466636f3fbc3de","0x00000000000000000000000000000005f2d1c401a7aa14ac7e9fce7c21ec2e1a","0x00000000000000000000000000000000000621322c74c5d0da5eb71a4f2b046f","0x00000000000000000000000000000073d774ad7f61b1c1b93800f7838cca6bde","0x00000000000000000000000000000000002d603cc025e6af192394df113d4677","0x00000000000000000000000000000066a2a702b4d4b1a24af9c56cacb18ae4b8","0x00000000000000000000000000000000000124a3c25b427cfb6fca07525c5b8d"] +# key_hash = "0x17a5d2b205c1bf45b015ba33bc2f0beb7fbb36682f31f953b8d4d093c8644be5" +# proof = ["0x0000000000000000000000000000000000000000000000000000000000000003","0x0000000000000000000000000000008f66908323784e7c5259f4eefab77ca881","0x0000000000000000000000000000000000109cac7b943f9b737d7b023d4f5d8a","0x000000000000000000000000000000e991d3ac0a68a252bd3cd09cd1b43fe1b4","0x000000000000000000000000000000000014213d346a426777351fdabaa0fa26","0x000000000000000000000000000000e4603692a76af630015380b08d0e13c239","0x0000000000000000000000000000000000149e7046461203c1b72392bb93c262","0x000000000000000000000000000000c27ffc719f223ca6ef5476a5b66f03a4a8","0x000000000000000000000000000000000003718c62098243e3c1f38090e61753","0x000000000000000000000000000000749492aa98716ce5bf7c06e5c2a0a8a528","0x000000000000000000000000000000000018e4c7d33848bccdc3eed924bfaa15","0x0000000000000000000000000000004e10a37f41fd7c4fe32982daa498530d62","0x00000000000000000000000000000000001b76c8c59489c63f11280187109dd7","0x0000000000000000000000000000002a6cd84d3b8537a7c3cb0cb9461f02e4bb","0x0000000000000000000000000000000000197e524fd48ca5ccb30d6c5ffe689d","0x0000000000000000000000000000000013bf25498ce1f51078c06dac450c0325","0x000000000000000000000000000000000018d347b88a0c32e32571deb9b40466","0x00000000000000000000000000000060d496191298eb1b1c2ce18f9a4afcfc55","0x000000000000000000000000000000000024e11b8e8fcb45b8628cb9cc565513","0x00000000000000000000000000000004e976f6d12fff6250eea2d21c570d3d6a","0x00000000000000000000000000000000000967dbd89d2c7dc0121ea71ded7203","0x000000000000000000000000000000d96f810588c0daa43e88d765a3f82ea9b7","0x00000000000000000000000000000000001f69d7015fe6694bd1d4d61049dae9","0x000000000000000000000000000000c539910d0f81a890fa3d996a676db39640","0x000000000000000000000000000000000026d8b64020a669e24f740b4eba633a","0x000000000000000000000000000000c53cc90f99c40eb5d449f38180d9e9c8b6","0x00000000000000000000000000000000001071ddf2bacc2367dfb2c5084b7dd1","0x0000000000000000000000000000001b9791181eb174db1a50d903fa9fea9999","0x0000000000000000000000000000000000118c059d41a95311a5c361c6a9a00d","0x0000000000000000000000000000003caf4ad04551a3ffba19cc6a1fff457370","0x00000000000000000000000000000000001dc4d8be804c5289fbf54183f93149","0x00000000000000000000000000000050766764bb82799df5172043c515956263","0x00000000000000000000000000000000000a5849adbac9c33e53571b29aab672","0x0000000000000000000000000000002edb078e589d44ac93e283680b34adf574","0x000000000000000000000000000000000015e9e187c4fb683ca78d52a2a0301b","0x00000000000000000000000000000048ac0f1db3575ed0f84d61ab6cbdd53d9f","0x00000000000000000000000000000000002ddc4243fbc7104347d29a823194ae","0x00000000000000000000000000000070ad92aeea2bdea4277ffdfa3d3ed93443","0x000000000000000000000000000000000003bad3e3aae806c278094cb682a8e0","0x000000000000000000000000000000fb74b99eb44c80d8f7ba83d7e9e2efa5c0","0x00000000000000000000000000000000002819cc14e399c1dadc4f921e2a58fa","0x000000000000000000000000000000e3938bb3e7866c6499ec44fb72549efca0","0x00000000000000000000000000000000002d8264d5cdc2109da12e1864aca147","0x000000000000000000000000000000b12d7828cacbe86350f0b171b0cb0d1cd4","0x0000000000000000000000000000000000244155cecb315326f05641cac9475c","0x070b059f9471e22eed5a9ea08093dba3c59c941634611884c5f0f1a1a6b93e5c","0x118124ada70b46c7d23a6ca8b90d545f30e028b1689fe5c55c86bf55f42e0401","0x25dca6ad78c03ce1f7783cc39a5ea5ef90b318d5edf4f1367d4451c1db3c113e","0x0d9557b4e661b5c53b84fcb41f05d15c0ca112430db16f56d0ab54032fffe734","0x06aedf13a3b182784f4d64162f4706759f95e42fc8dc17d1b8b5f551dafdc007","0x132f97ab5f1f8817689b17e336125c5273d6970a1b3b0901fd26d193a4d2dce4","0x1b0c9980b5b09343e807d82bad307a06d1bfadcd1fa50be666c2907d31ef43e1","0x1ce7000cb24ecc1f2ff9d9507b2290513fed574a84d893811cb54a3c0bc51ccc","0x2e1df58d36444c2dfda98991847422f56ef66f079d26eb7f8110d0d7c46b2c0c","0x166c2f821be7c3e3e4440980e73770840194f14d003778b7fbcdd2690776255c","0x1ae8390287e2eb117851a5011575ba3801e5ee5c66a8f7432e2a2fb13c276008","0x047c09806bfb272d940d9b802e3e49b40050fd0f66717e8b325c5d4834b13aac","0x08f81300d7f64e5b281b37005c7c936800a1fa1ecce2fd1664b8ba9069627558","0x2ed7260e623b68d580304751341bb72141314b881e9e8dade626bf5cde8a077c","0x23e04c035fd9396ca06cdc0171f24da00287e87b338bf45992e2ea41a589d560","0x285c5583cbd4609a347a7781a030975402d8e58a99fd72e4c53f4789da3b100c","0x2cd85f0437cf87c7c8881301ce6ee1080329e29a006ef16ff79ba4d20eec4ab8","0x12eb74da267caf98c494db16c87f90f510fdca1f8095b40156a6f0bb066e3400","0x2267004535c434df4cbee1a356e48b1f317cb849ac69c3eb94e377d2274f1e08","0x2c9d4ce9d1d8b8cf1cb90cbc3e121f570c8260c53b48ed2070d474d5a6f12c4e","0x2c6c83ffaad6f30da5aa696973ccfbd0337cb7a5e5f9e5fc8e826dce21e8f51c","0x056c23922e9435f93853044ba96a1c12db97f47053987df5187269ce884ec00f","0x09e82d129a8f5d26cc609fcbd7a865c6dbe8f17fba09fc804acec716bcfffabb","0x0e643693068a8454606e3b4c05e6af7adc39ee8f207b7b0b7d2b245ef1b13567","0x12e040137285ab81f47bd6cc3424f92edc8aeb9e86ecf996af8781a726627013","0x00f01a11c2990ecba44568cb7b2bd25edb46f760ed26ff69e6160c86539d8563","0x28a91699dfa4e85e18e8621d39a147a40930701d2d88546e01adb71a1f8e407f","0x000000000000000000000000000000009d7cc0b2d2bdef816f4fb17e7a6f6c08","0x00000000000000000000000000000000bcfc1a7030171f681f2c6e97c61f4e70","0x00000000000000000000000000000000dc7b742d8d704f4ecf092bb111cf30d8","0x13b099dc4869006fde9df04bf36f4c8f08d4491cc6229ac36a98f93214c79b6a","0x008fa95e0d431d617d8d3288fde7f8bbe36492019943e2018564633528575892","0x0fc66c06bdff20dba4dc491d5cd13cc209c4d2d9e29802db665bb397c2a4e754","0x0fe48ae6623efbaadce6d6b75b87be6caa19c2fd4d94a74149ceb6bcb88251e1","0x1bb41738028855cb5e0085edcd62cff208121427ea19a57425a0cf6bb68deb93","0x0fbc646333ddc21ab1a77b01a35973a56d5a617c482a21a231497fd3cc9b74c1","0x19ab9eaa1a902faff2dd9baa19ff00cea9086baa8c28bcdb95f7a3549eaf09b4","0x25e2b7a7643df4d964cd787b593888b00abfe3ce79e8deaa6d68fd1686b84bcb","0x2d134d7eea07414451e54854d61d5b71245434d0638bba9a1184914f65f2521c","0x03df94e38e9eed8586acd277d180d5d515b49d89d37525f871be2ff4552c586c","0x0b102abb146839f073c4a2514e65a8962f48ee8bbd1801e815d9c42d34665ebd","0x000000000000000000000000000000b7a4109cb92b514401fb63667454a9c892","0x0000000000000000000000000000000000016fce7f8ef56fef466636f3fbc3de","0x00000000000000000000000000000005f2d1c401a7aa14ac7e9fce7c21ec2e1a","0x00000000000000000000000000000000000621322c74c5d0da5eb71a4f2b046f","0x00000000000000000000000000000073d774ad7f61b1c1b93800f7838cca6bde","0x00000000000000000000000000000000002d603cc025e6af192394df113d4677","0x00000000000000000000000000000066a2a702b4d4b1a24af9c56cacb18ae4b8","0x00000000000000000000000000000000000124a3c25b427cfb6fca07525c5b8d"] +# public_inputs = ["0x0000000000000000000000000000000000000000000000000000000000000003"] +# verification_key = ["0x2b337de1c8c14f22ec9b9e2f96afef3652627366f8170a0a948dad4ac1bd5e80","0x0000000000000000000000000000000000000000000000000000000000000008","0x0000000000000000000000000000000000000000000000000000000000000005","0x0000000000000000000000000000000000000000000000000000000000000008","0x0000000000000000000000000000000000000000000000000000000000000001","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x00000000000000000000000000000092139c61bae1a44f0fc7689507414be688","0x00000000000000000000000000000000000160ce4e279582f91bde4f03f5e9a2","0x0000000000000000000000000000005dc2d37f658c3b2d60f24740eb13b65d79","0x000000000000000000000000000000000007e3e8a5d98a1177ec85bf88f163a5","0x000000000000000000000000000000dc3035fbd7ff16412a8fd7da587a935298","0x000000000000000000000000000000000023d08e2817ac16990004ed11d8fc66","0x000000000000000000000000000000356a5ad59c646c746a8d09f5d154e47c4f","0x00000000000000000000000000000000000708529196af3c8e16ffa580c26182","0x0000000000000000000000000000002ddfe70eb7a1280596e8e4a804f118a6dd","0x000000000000000000000000000000000013757e15a0905f298303784a161b21","0x000000000000000000000000000000a23a729df796935c7824e3a26be794829b","0x000000000000000000000000000000000005775b6c146c4a59856e869fe5a70e","0x000000000000000000000000000000eef0c9e088fd2d45aa40311082d1f2809b","0x00000000000000000000000000000000001d539ccbfc556d0ad59307a218de65","0x000000000000000000000000000000a2c848beceb6ab7806fd3b88037b8410fc","0x0000000000000000000000000000000000177004deeb1f9d401fd7b1af1a5ac8","0x0000000000000000000000000000002508eb63672a733f20de1a97644be4f540","0x00000000000000000000000000000000000d82d51f2f75d806285fd248c819b8","0x000000000000000000000000000000d002f9100cbba8a29f13b11513c53c59d0","0x000000000000000000000000000000000006cd3b0e3460533b9e5ea2cdc0fcbb","0x000000000000000000000000000000f45ea38a93b2f810c5633ddb54927c1c96","0x000000000000000000000000000000000021791de65f9a28ec7024b1a87ab4f3","0x000000000000000000000000000000926511a0439502c86885a8c6f0327aa7ad","0x000000000000000000000000000000000029fa14a969c5d81ed3abbbfb11220a","0x000000000000000000000000000000b84c3258e8206f560e5b5b18cbeafef87e","0x00000000000000000000000000000000002a910445cd8fc895e5d235cd8ea185","0x000000000000000000000000000000887e67f15e84bcb8507a5064a363f6043b","0x000000000000000000000000000000000014dc6643d801c3ef27c2066b6e2bb4","0x000000000000000000000000000000e38e900b42c314ba803088e8fbf125203f","0x000000000000000000000000000000000020690fd4869db418306046b38161dc","0x0000000000000000000000000000001e2fa856bf7951b8292b1e88185993629c","0x0000000000000000000000000000000000048a85e0bbac7c60ad3d78f601f63c","0x0000000000000000000000000000006f457719495073d3666d77a625aeab0c51","0x00000000000000000000000000000000002623ad892dc62b1fa7d0a650f0d470","0x000000000000000000000000000000dbfcc8a467e021c03b13f74a9f79c3a10c","0x0000000000000000000000000000000000295f6f10976c37bd9c6f96bb7187d5","0x000000000000000000000000000000c13ef9a937cc12420fb38d9ab8e848e85e","0x000000000000000000000000000000000003560a3b334e887532f605c9cb7628","0x0000000000000000000000000000009bcebf08a4599cdda0fb96312d4dc0c7a9","0x000000000000000000000000000000000015adc8bb1e01c835f48959d1237bd6","0x00000000000000000000000000000047762ab839e4ff63c77605a9f383da37c2","0x000000000000000000000000000000000016a8c3c53d89660cf271522cd301fb","0x000000000000000000000000000000f0c8539a0b5f94420a513f9c305b932bfe","0x00000000000000000000000000000000002957ba01d9de5638f808f88a692533","0x000000000000000000000000000000ab17c6189d67d3bf5dd2f3885de0151b6f","0x0000000000000000000000000000000000060d8aa43fdc434d1942263f364d95","0x0000000000000000000000000000005d292333b3adb497f00b4bc32d45229060","0x00000000000000000000000000000000001a1018a66221883639f2898a66f345","0x00000000000000000000000000000006555a806b1993291deba0dc44e2abf431","0x00000000000000000000000000000000000cacff7099a9d5e35a21f4a00b2dc3","0x000000000000000000000000000000f50c11ba95d349c36d143eefd12e494950","0x00000000000000000000000000000000001022e8c5f02d639bc9dd8bc4407f99","0x000000000000000000000000000000c76828795098eda73d50b4b585c60afc60","0x00000000000000000000000000000000002bf09c0ec7011e93888962f2406630","0x00000000000000000000000000000049e5c83a8978d832fb8e144548e3ca1adb","0x00000000000000000000000000000000000e0ec242c2e160a984f61ca5adf5f5","0x0000000000000000000000000000009c5d6e08a6605ab4513748ac0fa017dd1c","0x00000000000000000000000000000000001f54baa07558e5fb055bd9ba49c067","0x0000000000000000000000000000001e1ee7ee29bbb5e4b080c6091c1433ce62","0x000000000000000000000000000000000024aec62a9d9763499267dc98c33428","0x0000000000000000000000000000001a96755946ff16f0d6632365f0eb0ab4d4","0x000000000000000000000000000000000028cf3e22bcd53782ebc3e0490e27e5","0x00000000000000000000000000000043148d7d8c9ba43f2133fab4201435a364","0x0000000000000000000000000000000000234ce541f1f5117dd404cfaf01a229","0x000000000000000000000000000000a7fb95ffb461d9514a1070e2d2403982ef","0x00000000000000000000000000000000003016955028b6390f446c3fd0c5b424","0x00000000000000000000000000000008863c3b7cd7cddc20ba79ce915051c56e","0x000000000000000000000000000000000013ef666111b0be56a235983d397d2a","0x000000000000000000000000000000e3993f465fc9f56e93ac769e597b752c1c","0x0000000000000000000000000000000000217f7c4235161e9a3c16c45b6ca499","0x0000000000000000000000000000008ffa4cd96bc67b0b7df5678271e1114075","0x0000000000000000000000000000000000256467bfcb63d9fdcb5dde397757ad","0x00000000000000000000000000000054e5eb270bb64bde6e6ececadfd8c3236c","0x00000000000000000000000000000000000e52d1bd75812c33c6f3d79ee4b94c","0x000000000000000000000000000000484a2c641dce55bc2dd64ef0cd790a7fea","0x00000000000000000000000000000000000ff417d256be43e73c8b1aa85bdda3","0x0000000000000000000000000000000b72e7b7713ab5da44e0f864182e748a23","0x00000000000000000000000000000000001a221055f1625ad833a44705f5f74e","0x00000000000000000000000000000067a99a34e9b81a17ad001db02e29bcb82a","0x000000000000000000000000000000000018a6c02e398389827568fa960e86e2","0x000000000000000000000000000000bb29f26f9890d6cc6401f4921d5884edca","0x00000000000000000000000000000000000868357b28039385c5a5058b6d358e","0x00000000000000000000000000000036fb6e229dde8edf7ec858b12d7e8be485","0x00000000000000000000000000000000001060afe929554ca473103f5e68193c","0x00000000000000000000000000000015226e07e207744c0857074dcab883af4a","0x00000000000000000000000000000000000b1c02619282755533457230b19b4a","0x0000000000000000000000000000001f2a0277e4807e6e1cbabca21dde5eb5e1","0x00000000000000000000000000000000000d928deafed363659688ed4ccdef52","0x000000000000000000000000000000363f0c994e91cecad25835338edee2294f","0x00000000000000000000000000000000002eea648c8732596b1314fe2a4d2f05","0x000000000000000000000000000000b2671d2ae51d31c1210433c3972bb64578","0x00000000000000000000000000000000000ab49886c2b94bd0bd3f6ed1dbbe2c"] +# proof_b = ["0x0000000000000000000000000000000000000000000000000000000000000003","0x0000000000000000000000000000002ab91b132e624f2a408aa8c9bf31cca8d7","0x000000000000000000000000000000000015ad57528e0f065c820cc5ad4eab81","0x0000000000000000000000000000001acb78b1b6a5c9a6ec8bf2272b463014da","0x0000000000000000000000000000000000117fd65346e04bf3666d2ab3f24c90","0x000000000000000000000000000000aad0adaf9a768ba6a178f804edac5c8943","0x000000000000000000000000000000000004a11c7d31f25c20e3af16f9b01f71","0x0000000000000000000000000000001f0ae9bb921893ce2710148eb1fcd99e39","0x0000000000000000000000000000000000123fda5008d3709f5afeda01de1930","0x000000000000000000000000000000971c2a8d0119097fd82b7a8074a14853f8","0x000000000000000000000000000000000009965b998750710678da7891d8aba6","0x0000000000000000000000000000002d6ef3813ba14a5f5202afed6b1c41de1c","0x000000000000000000000000000000000020366bfdb2f9279c43d66f90dfdf4d","0x00000000000000000000000000000041389f221eadec33e1b87518668c3bc92e","0x00000000000000000000000000000000000d3858169bb0432ab761d4be8ef03e","0x000000000000000000000000000000c1dbfe670dc912cb0fa1a0f633f81a4cef","0x00000000000000000000000000000000000fc0c403e668b0f51e07089082c32f","0x0000000000000000000000000000009a4fba9bf1369f637fd295c8bf795c9d02","0x00000000000000000000000000000000001d6d1e7286ce52401e6ea79d2cfa3d","0x0000000000000000000000000000004762bf7702ffe7a2c147e704280cd50bba","0x0000000000000000000000000000000000205797cdeaeff9a8d5ea4b95d41b1a","0x000000000000000000000000000000b3d43cc863ba8d98f51118c0db70761079","0x00000000000000000000000000000000002d2a3d10381bc6b47a693c1692b1b6","0x000000000000000000000000000000d35a69fb0e68729f71e651799c0d19e9eb","0x00000000000000000000000000000000002ade1dc7741b7f397271c10e596557","0x0000000000000000000000000000001a67b44714687085004e4142f700043298","0x00000000000000000000000000000000001bb7bbb7f45876b1d72e5d20cee106","0x00000000000000000000000000000025f1f1cbf43fad70cba255b37a19e88b0c","0x00000000000000000000000000000000000cc46b215fbd8e4b233cc74aab250b","0x0000000000000000000000000000008168026f51135fc1670664bc50e629917f","0x000000000000000000000000000000000004d822d80ba0c1bcbd4b000573c6f9","0x000000000000000000000000000000d85756249b937277eba3f5dcb89c56e7bb","0x000000000000000000000000000000000019a3a7a5b20dac138d7ddb1d499134","0x0000000000000000000000000000007621614c7ebc31a2177011f9da01668eb3","0x000000000000000000000000000000000024e9beb5d616ab120073170fc431e8","0x00000000000000000000000000000031fbf901896e958fbbed3e5c57aebbdd04","0x0000000000000000000000000000000000005ac0f10fcc255e179a40518875d4","0x0000000000000000000000000000002dab820c019bcca563b7dbdd26974653e9","0x00000000000000000000000000000000001a5655ec1a67f722b14c65d5c2197f","0x0000000000000000000000000000008e277e490196db5c19d09a9034e10c6432","0x000000000000000000000000000000000003f13b1af07db07eec88698d0aaf2a","0x0000000000000000000000000000002d618452e2b4c790d0551ea5863ed62e76","0x00000000000000000000000000000000001a7171e790a433a972d80218fb482d","0x0000000000000000000000000000005669975cd5bf65a739c0a35a8ab9b7963b","0x00000000000000000000000000000000000d27ffb6f00c86a0ce76a8067d1bce","0x03a0054fe9f93ab96e7c7ed6ec1ac641dffd99a1c804ee5db52cf1efa1a12c15","0x059324381c89c12c87d0f6c27963c31647721fdb02c125961da1a21cbfb3ed1c","0x04a5ead891b7c3f30329e6abcf2ac6903c3c1d8e68874f6baf3a6fc00e84533a","0x03c02f6b862734acf9d0c5133f8141b3a008c5499336a588b376a5dd86d9c837","0x1dd26b35c21c584c410df89d1fd549e7f5da9bb4fd290b7c528d92fbd652f5ad","0x2c8e7ef6f7a130769ae74d0f47aeab5c443492ef4b1ed0b3a9d61dfca80cbdda","0x2b074486c21c62e6eccf3191b3ab3c8df0fb98f0c44b9f0e9e2c281b908b83a6","0x149a6d620be135bba6bbfe8ac826df37567c8be78007e47cdcf5d6e4683d339e","0x119fdfd330036bde31af71e43bd5e191460605e4760d08a6e0ebddbdb5abfeeb","0x1713efc63c00b2de4f68e696d9d30c5603963484f4829e716de2796640864b09","0x1bb1862114cda3712c177b1b6bca0ecd9de7723925698aee83dc91ade7078d3e","0x049d965ad8ccf092dcae948491f702779a513db430e6ec7d15fa1847a6814235","0x093b2cb5b199e125b95d290923ee04ef34a27b6861cdd8fa2bf4308f4d02846a","0x2710c6cd6f14f8071976509d1002e915bfc182b843a3967134de380302423c72","0x24ecb2d6c6678496e574a4248fb813bcd289eda1873763e8afd0c23d340a11a8","0x298a49319f347529c22338a921af16346cdb2b55b81e5065c5cada84da8b53dd","0x2e27df8c780165bc9ed1cd2db3a618ac072c6909e9053ce2dbc4f2cc810c9612","0x07350f3a2e23c1ccbde0d39370159060de5b8df40ae7c58d3f9852b371f1adac","0x2fdf8bf8e2fa2acad0f6d6a3f73e7dc516e8e2d167128bf3a560972339122835","0x0d3ec457703c228d4b6cd1635df9d9bde51997d0228edef64d667cbd16f3cb70","0x148320b9ceab1f3be840dc38b0344e7db0755283d1eacf2dd472e99ee0fb473f","0x06febdcf4869a6b89fdeb0805612c53e139afc29d119a54bc3d72dc7de0f1a7b","0x0b9c542a2136974b7c8d4504e809c7b5adec39de020091c8d9d1460f84905cb0","0x1039ea84fa0387de593bd9897a00ca2d483d779232e77e45efcb5e572b119ee5","0x14d780dfd2d0787135ea6e0e0bf7cca4e28eb54663ce6ac305c5769ed192e11a","0x026127746f9cb625c3301bfbc41bc2c67949be75a032b8ceaddd1580378dd846","0x123cf1180af5fdf09444de423947c9a71790f2c85468b51ecc25fb7bf075a0d5","0x000000000000000000000000000000008419a4f769ceb72c3ac28f559331a5df","0x000000000000000000000000000000009e852c5c1891a89b79b64599e3d52d72","0x00000000000000000000000000000000b8f0b3c0c7549a0ab8a9fbde3478b505","0x056af493dda97ae84cdbbf9ce379e35bdd66e1223eebacdc4a6c2c92553604f4","0x023624c49a722bc8dc5d945b4b10be8ed6c608020e65038a470b5a407375c8aa","0x0ed9f8dd445bda548ef08b7a2ff233867c41b72786f98054597833a68cc9b900","0x2cbf3d04669aa3a0dcda95e19da879f36029abe28317f1ee69be28ddef2a0b87","0x284ca7049611e293aa4535dd7841a540996609d541814373b387b00069636f14","0x246a69ce4030b1e8a675eec89960bfe188bd4073f07afe74f7a77c0698c80bc5","0x1bbdab5d007c4743fbcbf3cc89252baf0b0e1b645b977434ccd4e7560d124761","0x210427e70ee1b484bbb0b4e98263faf24a45325236eed618d51dcb1cb3a9f60d","0x1fbc24b0bd5b0b8c514e138317cc332962714dd306b34939768d723d6ea2ca8e","0x1e74217a6bd46293e6eb721cad346b607a9d6953d677bc5a17fd195e299b9f0f","0x1d2c1e441a4db99b7c88d0b6429ca39792c984d4a63c2f7ab96cc07ee4947390","0x00000000000000000000000000000005b1e3524625c466540f3f7468172403cb","0x000000000000000000000000000000000013bb985f9d5562699347b5dfbc441e","0x000000000000000000000000000000f4fb87d7f481bb198aa6237a0c9ffd3c22","0x0000000000000000000000000000000000254c5f1b76e278f4c71cf5e71533dd","0x0000000000000000000000000000005a72a28b51be9c538b4d28b5106b9239b8","0x00000000000000000000000000000000000d02d80e1a73c82cb0dd8af1aabb3f","0x000000000000000000000000000000434c46502fc1c425a72a4717a3e44c3415","0x00000000000000000000000000000000001c8d74d967b9b65ff2772592a15d0e"] + +key_hash = "0x096129b1c6e108252fc5c829c4cc9b7e8f0d1fd9f29c2532b563d6396645e08f" +proof = ["0x0000000000000000000000000000000000000000000000000000000000000003","0x000000000000000000000000000000d62b795bec274279129a71195796825fcc","0x00000000000000000000000000000000000793ab763140f20a68a6bd2721fd74","0x00000000000000000000000000000053141d06d3307b36153f321511199e579c","0x00000000000000000000000000000000000a4b55d6c21f98a9c434911dcb5c67","0x0000000000000000000000000000005f9d324c0abd22cec92d99dbec438e9491","0x0000000000000000000000000000000000240dfafe1b53dc27147cbab14ea893","0x000000000000000000000000000000044a61d3aac32c6931247cf334a19d9611","0x000000000000000000000000000000000003f0f8cf4207bfa85c23ec9f8d0c88","0x00000000000000000000000000000002168a470e39ba2ac266f6b474de12045f","0x000000000000000000000000000000000025791e7d3feab542345c00ec5a30df","0x000000000000000000000000000000dcafd76d4c3640969c80e017b951ef6397","0x00000000000000000000000000000000001d27f75a1256771e88e0c86fc42dbc","0x0000000000000000000000000000007347ae7d2d9d7fc2b8f0baa014ee1fed9f","0x000000000000000000000000000000000018bd927f42bf7caf9555f56f09000d","0x000000000000000000000000000000041f765f83cbe5904c8f453f70a4531d10","0x00000000000000000000000000000000001858aabeeb5331a221419f4fed1c19","0x000000000000000000000000000000d254a54caaedf8287b9af951b2f2611121","0x000000000000000000000000000000000005ab493623c9563cf2e55ba5f18200","0x00000000000000000000000000000014f24cddc1a02440dc63637df8032c8074","0x000000000000000000000000000000000011950c16cef98471b1d78b935195a4","0x000000000000000000000000000000b0340b459e6bd5cc8f031c8654a502897f","0x00000000000000000000000000000000000e1cf3968dac4545a76a2ae58e512c","0x0000000000000000000000000000002adf7218aa06ca0d2c2e600dcc39193a2d","0x00000000000000000000000000000000001302e7e4b0f14749bd885ca25588b6","0x00000000000000000000000000000092009ce4056e79ab815d8cdfd4491138ae","0x000000000000000000000000000000000018af11e853c6cf2f0f6274b0da8133","0x000000000000000000000000000000dd3dc6f49232141718527b3a0e4b26e21d","0x00000000000000000000000000000000001a877853348a8b695c4f9a9aa4ce68","0x000000000000000000000000000000aecfc56ba07155450b368140d6324023b5","0x000000000000000000000000000000000029c11052798c57ece614617d33fcc2","0x000000000000000000000000000000eb106ffc816d16fb84e84b0b61157b2603","0x000000000000000000000000000000000026c3cac16206899a21cb5126841446","0x000000000000000000000000000000a782ed54805fe845068b362b58e2fa34ec","0x00000000000000000000000000000000000cf046a1bfcc666b7f28b572676073","0x000000000000000000000000000000b931c8dda60bb4aca4cc817f5540f1209f","0x000000000000000000000000000000000024ad50c3936fafc3d190e6a4874223","0x000000000000000000000000000000cce90cfbaf5671c8c8652db28a3a9566f7","0x000000000000000000000000000000000003574db9d0f84380c9635660f86354","0x0000000000000000000000000000003eb3e1dc31846a90f721e7a08c6d6dc4f7","0x000000000000000000000000000000000028999a700cd1abae1a288eebb9a91c","0x000000000000000000000000000000c1be4d385b11387e14eb9817050d772f78","0x000000000000000000000000000000000003c56b5bad8b4484c66ac921f1f102","0x000000000000000000000000000000ace245cabf0f00dc7fd253dd8af0377a14","0x0000000000000000000000000000000000107f1731fcf34b364c813599fa1df7","0x035b937d404932b542b706eb810ef4a7dca4566d4dde1ad6a8717f46167ead7e","0x17608cef3dc7960f41cb1295706df663727d45ee598a61e05e989d111449fb65","0x054712a950ad67da3aa860e49e6891f99b586b7f37caff94eb013fdb374b61ee","0x04b755083086c769b7f593e0e48d68dc54be808203351380ca5566a48149d8bb","0x17d7670b0915235f626fdc1d7e1134d2be906ef138d7843384b3ebc23b1d630f","0x064cf544ab5f4e3dab47960502cccc83321fb275068dfbdd3a2fcbc6dddcaa65","0x083338262712e2b66769ea40d9f412b18caa1bc81a51ff5a50b6c41f8c4b3d23","0x0cdd38958cab97defde00f4a5961b6fd676e29d9f2c352f6bb2c68b91f83f8af","0x02c8bdd005c2f43a0a8cbb2744916ce5c322dfa5b23367a829c12699f4036d32","0x25bac73c7e7b659fbea3135b7a0decf9db8dc3045bd2837dae337c64cc722546","0x19eb361aa419d37bce3d2e8b2b7692a02a9559e83d7f3d8fe9169970fbbc2cba","0x2494bd5106d00e05c7ea60e632e9fe03773b7f2c5b662aa37ec512a01f4a0775","0x18c52c2f2c6e7be1d7847c15e452a3a9c64316103d12e4b5b9a82fac4e940ee9","0x0e0342810456ef78f498c1bfa085a5f3cbc06db1f32fabd0ea9ad27dccac1680","0x024c13d6ef56af33ed7164ea8e47ddecc8a487b000d8b1b45edcd3895a503ba2","0x26e0d127f626bd39b55bc5d0c131dbf03fe006dc5c3edc57dda1e629799a4317","0x1b1140061bc52b15c4f5e100729a81968ee79dc03deb966a18850335a8e44a8b","0x1bb76f945199e71d531a89288912087a02dd0e83020e65d671485bf2e5e86e1a","0x29269900859c6d86e404185b415bf3b279cd100f38cfdb0077e8d6a299c4fd35","0x22b5e94bae2f6f0cdb424a3b12c4bf82cec3fb228e012c1974ed457827bbe012","0x18d3543a93249778e7a57936170dae85ffc47c2567f2d0076a32c0bb86fcf10a","0x03721dc2670206cde42a175fd56bcce32cf6cb8801450a8e8e4b3d4e07785973","0x2806db136dd214d3ac1478460855cae6a4324ab45cab35320d104fee26c260e8","0x1c3749f1937082afbbae9375b9be708cf339e1983e57ef4447f36cfa560c685c","0x1067b8cfb90ef08bcb48aea56b2716334241787c2004a95682d68a0685566fd0","0x0f41aee4416398f1d48ffc302403273cddef34a41f98507c53682041d82e51ff","0x10d854c9f0bfbdff7ca91a68f4978e9a79e7b14243d92f465f17bdf88d9f64f8","0x00000000000000000000000000000000018938b11099e0cdc05ddab84a153a97","0x0000000000000000000000000000000001d7dda1471f0dc3b3a3d3438c197982","0x00000000000000000000000000000000022682917da43ab9a6e9cbcece1db86d","0x2453913e6b0f36eab883ac4b0e0604d56aaeb9c55e641135173e63c342f1a660","0x05216c1b58dc43a49d01aaba3113b0e86be450fc17d28016e648e7162a1b67fb","0x152b34845a0222a2b41354c0d395a250d8363dc18748647d85acd89d6934ec56","0x1dfc6e971ce82b7dcda1f7f282713c6e22a8c79258a61209bda69719806da544","0x2968dd8b3af8e3953f1fbbd72f4c49b8270597bb27d4037adc157ac6083bee60","0x1b9425b88a4c7d39b3d75afe66917a9aa1d2055724392bc01fb918d84ff1410e","0x04ab571f236d8e750904dc307dd274003d9130f1a7110e4c1521cfb408877c73","0x2ad84f26fdc5831545272d02b806bb0e6dae44e71f73552c4eb9ff06030748c7","0x020e632b99d325db774b8630fb50b9a4e74d35b7f27d9fc02c65087ee747e42c","0x09a8c5a3171268cb61c02515c01c109889200ed13f415ae54df2078bbb887f92","0x1143281a9451abbb4c34c3fa84e7678c2af2e7ea8c05160a6f7f06988fc91af8","0x000000000000000000000000000000cbda736ca5cf6bc75413c2cc9e28ab0a68","0x00000000000000000000000000000000001ee78c9cc56aa5991062ae2e338587","0x000000000000000000000000000000bc9bfcdebb486f4cb314e681d2cc5f8df6","0x00000000000000000000000000000000000ad538431d04771bca7f633cb659ff","0x000000000000000000000000000000d45b317afcefa466a59bba9e171f1af70c","0x0000000000000000000000000000000000133c50180ea17932e4881124e7a7c6","0x000000000000000000000000000000fc9ed37f543775849f3e84eaa06f77f992","0x00000000000000000000000000000000001372873c9c051d1baff99248b8f70e"] public_inputs = ["0x0000000000000000000000000000000000000000000000000000000000000003"] verification_key = ["0x2b337de1c8c14f22ec9b9e2f96afef3652627366f8170a0a948dad4ac1bd5e80","0x0000000000000000000000000000000000000000000000000000000000000008","0x0000000000000000000000000000000000000000000000000000000000000005","0x0000000000000000000000000000000000000000000000000000000000000008","0x0000000000000000000000000000000000000000000000000000000000000001","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x00000000000000000000000000000092139c61bae1a44f0fc7689507414be688","0x00000000000000000000000000000000000160ce4e279582f91bde4f03f5e9a2","0x0000000000000000000000000000005dc2d37f658c3b2d60f24740eb13b65d79","0x000000000000000000000000000000000007e3e8a5d98a1177ec85bf88f163a5","0x000000000000000000000000000000dc3035fbd7ff16412a8fd7da587a935298","0x000000000000000000000000000000000023d08e2817ac16990004ed11d8fc66","0x000000000000000000000000000000356a5ad59c646c746a8d09f5d154e47c4f","0x00000000000000000000000000000000000708529196af3c8e16ffa580c26182","0x0000000000000000000000000000002ddfe70eb7a1280596e8e4a804f118a6dd","0x000000000000000000000000000000000013757e15a0905f298303784a161b21","0x000000000000000000000000000000a23a729df796935c7824e3a26be794829b","0x000000000000000000000000000000000005775b6c146c4a59856e869fe5a70e","0x000000000000000000000000000000eef0c9e088fd2d45aa40311082d1f2809b","0x00000000000000000000000000000000001d539ccbfc556d0ad59307a218de65","0x000000000000000000000000000000a2c848beceb6ab7806fd3b88037b8410fc","0x0000000000000000000000000000000000177004deeb1f9d401fd7b1af1a5ac8","0x0000000000000000000000000000002508eb63672a733f20de1a97644be4f540","0x00000000000000000000000000000000000d82d51f2f75d806285fd248c819b8","0x000000000000000000000000000000d002f9100cbba8a29f13b11513c53c59d0","0x000000000000000000000000000000000006cd3b0e3460533b9e5ea2cdc0fcbb","0x000000000000000000000000000000f45ea38a93b2f810c5633ddb54927c1c96","0x000000000000000000000000000000000021791de65f9a28ec7024b1a87ab4f3","0x000000000000000000000000000000926511a0439502c86885a8c6f0327aa7ad","0x000000000000000000000000000000000029fa14a969c5d81ed3abbbfb11220a","0x000000000000000000000000000000b84c3258e8206f560e5b5b18cbeafef87e","0x00000000000000000000000000000000002a910445cd8fc895e5d235cd8ea185","0x000000000000000000000000000000887e67f15e84bcb8507a5064a363f6043b","0x000000000000000000000000000000000014dc6643d801c3ef27c2066b6e2bb4","0x000000000000000000000000000000e38e900b42c314ba803088e8fbf125203f","0x000000000000000000000000000000000020690fd4869db418306046b38161dc","0x0000000000000000000000000000001e2fa856bf7951b8292b1e88185993629c","0x0000000000000000000000000000000000048a85e0bbac7c60ad3d78f601f63c","0x0000000000000000000000000000006f457719495073d3666d77a625aeab0c51","0x00000000000000000000000000000000002623ad892dc62b1fa7d0a650f0d470","0x000000000000000000000000000000dbfcc8a467e021c03b13f74a9f79c3a10c","0x0000000000000000000000000000000000295f6f10976c37bd9c6f96bb7187d5","0x000000000000000000000000000000c13ef9a937cc12420fb38d9ab8e848e85e","0x000000000000000000000000000000000003560a3b334e887532f605c9cb7628","0x0000000000000000000000000000009bcebf08a4599cdda0fb96312d4dc0c7a9","0x000000000000000000000000000000000015adc8bb1e01c835f48959d1237bd6","0x00000000000000000000000000000047762ab839e4ff63c77605a9f383da37c2","0x000000000000000000000000000000000016a8c3c53d89660cf271522cd301fb","0x000000000000000000000000000000f0c8539a0b5f94420a513f9c305b932bfe","0x00000000000000000000000000000000002957ba01d9de5638f808f88a692533","0x000000000000000000000000000000ab17c6189d67d3bf5dd2f3885de0151b6f","0x0000000000000000000000000000000000060d8aa43fdc434d1942263f364d95","0x0000000000000000000000000000005d292333b3adb497f00b4bc32d45229060","0x00000000000000000000000000000000001a1018a66221883639f2898a66f345","0x00000000000000000000000000000006555a806b1993291deba0dc44e2abf431","0x00000000000000000000000000000000000cacff7099a9d5e35a21f4a00b2dc3","0x000000000000000000000000000000f50c11ba95d349c36d143eefd12e494950","0x00000000000000000000000000000000001022e8c5f02d639bc9dd8bc4407f99","0x000000000000000000000000000000c76828795098eda73d50b4b585c60afc60","0x00000000000000000000000000000000002bf09c0ec7011e93888962f2406630","0x00000000000000000000000000000049e5c83a8978d832fb8e144548e3ca1adb","0x00000000000000000000000000000000000e0ec242c2e160a984f61ca5adf5f5","0x0000000000000000000000000000009c5d6e08a6605ab4513748ac0fa017dd1c","0x00000000000000000000000000000000001f54baa07558e5fb055bd9ba49c067","0x0000000000000000000000000000001e1ee7ee29bbb5e4b080c6091c1433ce62","0x000000000000000000000000000000000024aec62a9d9763499267dc98c33428","0x0000000000000000000000000000001a96755946ff16f0d6632365f0eb0ab4d4","0x000000000000000000000000000000000028cf3e22bcd53782ebc3e0490e27e5","0x00000000000000000000000000000043148d7d8c9ba43f2133fab4201435a364","0x0000000000000000000000000000000000234ce541f1f5117dd404cfaf01a229","0x000000000000000000000000000000a7fb95ffb461d9514a1070e2d2403982ef","0x00000000000000000000000000000000003016955028b6390f446c3fd0c5b424","0x00000000000000000000000000000008863c3b7cd7cddc20ba79ce915051c56e","0x000000000000000000000000000000000013ef666111b0be56a235983d397d2a","0x000000000000000000000000000000e3993f465fc9f56e93ac769e597b752c1c","0x0000000000000000000000000000000000217f7c4235161e9a3c16c45b6ca499","0x0000000000000000000000000000008ffa4cd96bc67b0b7df5678271e1114075","0x0000000000000000000000000000000000256467bfcb63d9fdcb5dde397757ad","0x00000000000000000000000000000054e5eb270bb64bde6e6ececadfd8c3236c","0x00000000000000000000000000000000000e52d1bd75812c33c6f3d79ee4b94c","0x000000000000000000000000000000484a2c641dce55bc2dd64ef0cd790a7fea","0x00000000000000000000000000000000000ff417d256be43e73c8b1aa85bdda3","0x0000000000000000000000000000000b72e7b7713ab5da44e0f864182e748a23","0x00000000000000000000000000000000001a221055f1625ad833a44705f5f74e","0x00000000000000000000000000000067a99a34e9b81a17ad001db02e29bcb82a","0x000000000000000000000000000000000018a6c02e398389827568fa960e86e2","0x000000000000000000000000000000bb29f26f9890d6cc6401f4921d5884edca","0x00000000000000000000000000000000000868357b28039385c5a5058b6d358e","0x00000000000000000000000000000036fb6e229dde8edf7ec858b12d7e8be485","0x00000000000000000000000000000000001060afe929554ca473103f5e68193c","0x00000000000000000000000000000015226e07e207744c0857074dcab883af4a","0x00000000000000000000000000000000000b1c02619282755533457230b19b4a","0x0000000000000000000000000000001f2a0277e4807e6e1cbabca21dde5eb5e1","0x00000000000000000000000000000000000d928deafed363659688ed4ccdef52","0x000000000000000000000000000000363f0c994e91cecad25835338edee2294f","0x00000000000000000000000000000000002eea648c8732596b1314fe2a4d2f05","0x000000000000000000000000000000b2671d2ae51d31c1210433c3972bb64578","0x00000000000000000000000000000000000ab49886c2b94bd0bd3f6ed1dbbe2c"] -proof_b = ["0x0000000000000000000000000000000000000000000000000000000000000003","0x0000000000000000000000000000002ab91b132e624f2a408aa8c9bf31cca8d7","0x000000000000000000000000000000000015ad57528e0f065c820cc5ad4eab81","0x0000000000000000000000000000001acb78b1b6a5c9a6ec8bf2272b463014da","0x0000000000000000000000000000000000117fd65346e04bf3666d2ab3f24c90","0x000000000000000000000000000000aad0adaf9a768ba6a178f804edac5c8943","0x000000000000000000000000000000000004a11c7d31f25c20e3af16f9b01f71","0x0000000000000000000000000000001f0ae9bb921893ce2710148eb1fcd99e39","0x0000000000000000000000000000000000123fda5008d3709f5afeda01de1930","0x000000000000000000000000000000971c2a8d0119097fd82b7a8074a14853f8","0x000000000000000000000000000000000009965b998750710678da7891d8aba6","0x0000000000000000000000000000002d6ef3813ba14a5f5202afed6b1c41de1c","0x000000000000000000000000000000000020366bfdb2f9279c43d66f90dfdf4d","0x00000000000000000000000000000041389f221eadec33e1b87518668c3bc92e","0x00000000000000000000000000000000000d3858169bb0432ab761d4be8ef03e","0x000000000000000000000000000000c1dbfe670dc912cb0fa1a0f633f81a4cef","0x00000000000000000000000000000000000fc0c403e668b0f51e07089082c32f","0x0000000000000000000000000000009a4fba9bf1369f637fd295c8bf795c9d02","0x00000000000000000000000000000000001d6d1e7286ce52401e6ea79d2cfa3d","0x0000000000000000000000000000004762bf7702ffe7a2c147e704280cd50bba","0x0000000000000000000000000000000000205797cdeaeff9a8d5ea4b95d41b1a","0x000000000000000000000000000000b3d43cc863ba8d98f51118c0db70761079","0x00000000000000000000000000000000002d2a3d10381bc6b47a693c1692b1b6","0x000000000000000000000000000000d35a69fb0e68729f71e651799c0d19e9eb","0x00000000000000000000000000000000002ade1dc7741b7f397271c10e596557","0x0000000000000000000000000000001a67b44714687085004e4142f700043298","0x00000000000000000000000000000000001bb7bbb7f45876b1d72e5d20cee106","0x00000000000000000000000000000025f1f1cbf43fad70cba255b37a19e88b0c","0x00000000000000000000000000000000000cc46b215fbd8e4b233cc74aab250b","0x0000000000000000000000000000008168026f51135fc1670664bc50e629917f","0x000000000000000000000000000000000004d822d80ba0c1bcbd4b000573c6f9","0x000000000000000000000000000000d85756249b937277eba3f5dcb89c56e7bb","0x000000000000000000000000000000000019a3a7a5b20dac138d7ddb1d499134","0x0000000000000000000000000000007621614c7ebc31a2177011f9da01668eb3","0x000000000000000000000000000000000024e9beb5d616ab120073170fc431e8","0x00000000000000000000000000000031fbf901896e958fbbed3e5c57aebbdd04","0x0000000000000000000000000000000000005ac0f10fcc255e179a40518875d4","0x0000000000000000000000000000002dab820c019bcca563b7dbdd26974653e9","0x00000000000000000000000000000000001a5655ec1a67f722b14c65d5c2197f","0x0000000000000000000000000000008e277e490196db5c19d09a9034e10c6432","0x000000000000000000000000000000000003f13b1af07db07eec88698d0aaf2a","0x0000000000000000000000000000002d618452e2b4c790d0551ea5863ed62e76","0x00000000000000000000000000000000001a7171e790a433a972d80218fb482d","0x0000000000000000000000000000005669975cd5bf65a739c0a35a8ab9b7963b","0x00000000000000000000000000000000000d27ffb6f00c86a0ce76a8067d1bce","0x03a0054fe9f93ab96e7c7ed6ec1ac641dffd99a1c804ee5db52cf1efa1a12c15","0x059324381c89c12c87d0f6c27963c31647721fdb02c125961da1a21cbfb3ed1c","0x04a5ead891b7c3f30329e6abcf2ac6903c3c1d8e68874f6baf3a6fc00e84533a","0x03c02f6b862734acf9d0c5133f8141b3a008c5499336a588b376a5dd86d9c837","0x1dd26b35c21c584c410df89d1fd549e7f5da9bb4fd290b7c528d92fbd652f5ad","0x2c8e7ef6f7a130769ae74d0f47aeab5c443492ef4b1ed0b3a9d61dfca80cbdda","0x2b074486c21c62e6eccf3191b3ab3c8df0fb98f0c44b9f0e9e2c281b908b83a6","0x149a6d620be135bba6bbfe8ac826df37567c8be78007e47cdcf5d6e4683d339e","0x119fdfd330036bde31af71e43bd5e191460605e4760d08a6e0ebddbdb5abfeeb","0x1713efc63c00b2de4f68e696d9d30c5603963484f4829e716de2796640864b09","0x1bb1862114cda3712c177b1b6bca0ecd9de7723925698aee83dc91ade7078d3e","0x049d965ad8ccf092dcae948491f702779a513db430e6ec7d15fa1847a6814235","0x093b2cb5b199e125b95d290923ee04ef34a27b6861cdd8fa2bf4308f4d02846a","0x2710c6cd6f14f8071976509d1002e915bfc182b843a3967134de380302423c72","0x24ecb2d6c6678496e574a4248fb813bcd289eda1873763e8afd0c23d340a11a8","0x298a49319f347529c22338a921af16346cdb2b55b81e5065c5cada84da8b53dd","0x2e27df8c780165bc9ed1cd2db3a618ac072c6909e9053ce2dbc4f2cc810c9612","0x07350f3a2e23c1ccbde0d39370159060de5b8df40ae7c58d3f9852b371f1adac","0x2fdf8bf8e2fa2acad0f6d6a3f73e7dc516e8e2d167128bf3a560972339122835","0x0d3ec457703c228d4b6cd1635df9d9bde51997d0228edef64d667cbd16f3cb70","0x148320b9ceab1f3be840dc38b0344e7db0755283d1eacf2dd472e99ee0fb473f","0x06febdcf4869a6b89fdeb0805612c53e139afc29d119a54bc3d72dc7de0f1a7b","0x0b9c542a2136974b7c8d4504e809c7b5adec39de020091c8d9d1460f84905cb0","0x1039ea84fa0387de593bd9897a00ca2d483d779232e77e45efcb5e572b119ee5","0x14d780dfd2d0787135ea6e0e0bf7cca4e28eb54663ce6ac305c5769ed192e11a","0x026127746f9cb625c3301bfbc41bc2c67949be75a032b8ceaddd1580378dd846","0x123cf1180af5fdf09444de423947c9a71790f2c85468b51ecc25fb7bf075a0d5","0x000000000000000000000000000000008419a4f769ceb72c3ac28f559331a5df","0x000000000000000000000000000000009e852c5c1891a89b79b64599e3d52d72","0x00000000000000000000000000000000b8f0b3c0c7549a0ab8a9fbde3478b505","0x056af493dda97ae84cdbbf9ce379e35bdd66e1223eebacdc4a6c2c92553604f4","0x023624c49a722bc8dc5d945b4b10be8ed6c608020e65038a470b5a407375c8aa","0x0ed9f8dd445bda548ef08b7a2ff233867c41b72786f98054597833a68cc9b900","0x2cbf3d04669aa3a0dcda95e19da879f36029abe28317f1ee69be28ddef2a0b87","0x284ca7049611e293aa4535dd7841a540996609d541814373b387b00069636f14","0x246a69ce4030b1e8a675eec89960bfe188bd4073f07afe74f7a77c0698c80bc5","0x1bbdab5d007c4743fbcbf3cc89252baf0b0e1b645b977434ccd4e7560d124761","0x210427e70ee1b484bbb0b4e98263faf24a45325236eed618d51dcb1cb3a9f60d","0x1fbc24b0bd5b0b8c514e138317cc332962714dd306b34939768d723d6ea2ca8e","0x1e74217a6bd46293e6eb721cad346b607a9d6953d677bc5a17fd195e299b9f0f","0x1d2c1e441a4db99b7c88d0b6429ca39792c984d4a63c2f7ab96cc07ee4947390","0x00000000000000000000000000000005b1e3524625c466540f3f7468172403cb","0x000000000000000000000000000000000013bb985f9d5562699347b5dfbc441e","0x000000000000000000000000000000f4fb87d7f481bb198aa6237a0c9ffd3c22","0x0000000000000000000000000000000000254c5f1b76e278f4c71cf5e71533dd","0x0000000000000000000000000000005a72a28b51be9c538b4d28b5106b9239b8","0x00000000000000000000000000000000000d02d80e1a73c82cb0dd8af1aabb3f","0x000000000000000000000000000000434c46502fc1c425a72a4717a3e44c3415","0x00000000000000000000000000000000001c8d74d967b9b65ff2772592a15d0e"] \ No newline at end of file +proof_b = ["0x0000000000000000000000000000000000000000000000000000000000000003","0x000000000000000000000000000000f05c69448ca29bdf52076f9b073bb30fed","0x000000000000000000000000000000000028c86bb3e27b4aaaaef126f7df5349","0x00000000000000000000000000000026ae031fc93594375dfc7f3bbe027f97d5","0x000000000000000000000000000000000000dd12c7290fe7f775796a233b8590","0x000000000000000000000000000000c1ee6631704de424d010c5c4ac8293ac49","0x00000000000000000000000000000000002f41818c9aa83f5c8d9bdd128015b9","0x000000000000000000000000000000b50a5801482f7e3a5de8ab3cce0f10b0d3","0x000000000000000000000000000000000022a0bc69c293dbf293b25bc9eef7f8","0x0000000000000000000000000000003b02abf1967ef394154dc15d763135e903","0x00000000000000000000000000000000000d8a2ee46acc6d1ed8d517b56d47c8","0x00000000000000000000000000000039bf0d1b3d8cf9de898f101c626e978d78","0x0000000000000000000000000000000000008faa7df2451a24d291a9b584f1a5","0x000000000000000000000000000000c1dae329ed7adf63a2d89a5f16fb98b6d8","0x00000000000000000000000000000000001ff0bc16fc0bd4aa2d6255690453c2","0x000000000000000000000000000000d12d7589f853a9b472613efa56689beaf1","0x00000000000000000000000000000000002d6fbc798f4403751df6aeee8bedd3","0x0000000000000000000000000000007c1fa069cb17194fecf88db9dd54a4ee36","0x0000000000000000000000000000000000268e026f9814822a42b2d59eec5d24","0x000000000000000000000000000000c3fb56beab774218cd63498fc050a5fd9b","0x00000000000000000000000000000000000071c014d7b5063f005a0bc2ee1af4","0x000000000000000000000000000000ae12b25371c6af42bbe0a85cddd2eaebc7","0x000000000000000000000000000000000026d270e1ffc9c7c344c694dfadda83","0x00000000000000000000000000000080280858c6be461716921caa3c26f3f6f3","0x000000000000000000000000000000000001dcdd3f39e27d0ce6aa5d14dff4c1","0x000000000000000000000000000000080e1d2c913c834ebcf7e0600c076c08fd","0x00000000000000000000000000000000002df3d142217694e65fb7c355d62764","0x000000000000000000000000000000e5e336f3f59d77e500f49771bfbeb12e83","0x000000000000000000000000000000000028fffe08bdc4c0690643d2e1a1275f","0x000000000000000000000000000000db5618b32afc13e18f21b39f3fbede9d11","0x00000000000000000000000000000000001d244818370d43fb7e8bc67e03787b","0x0000000000000000000000000000006bcc1fd3f9f78449ad1df1bc11bc379edd","0x000000000000000000000000000000000009ac9cbb285edbf5b3a973f3f5f1cb","0x000000000000000000000000000000fd885905b6c0fc95bb4dd0b11f6797d4b3","0x000000000000000000000000000000000021f07995cdd835145e19c38127c562","0x000000000000000000000000000000bbbf2b975c2c97ae4b45c4a52059e53ee3","0x000000000000000000000000000000000024158163788841cf4590bbc1e89a90","0x0000000000000000000000000000009aca93d2b1386ea412d4b36ea5bb9894a8","0x00000000000000000000000000000000002532d1d210e8ed4c2f5c00cbaaa475","0x000000000000000000000000000000634a88caa1d77cb6b5fe77cac31458fc31","0x00000000000000000000000000000000000bdf18bae92fce7cfddab5520cac6e","0x000000000000000000000000000000622e9626255170ccec77602c755aa193e1","0x000000000000000000000000000000000001d4edba370e04436a988bad05dada","0x000000000000000000000000000000b52934323a0aec8f803cdaafee2ab7bfb2","0x0000000000000000000000000000000000155312af5e0e25ca9fd61aef9e58ed","0x06270b517855f6f6a608e432883d1d1030a12a1e33022dc142b7728691421da2","0x2af7c794d7b720b25eb1df0afd8c8e3c15b6e518194c3caea7966a5f8210ff04","0x073fe573aeb27d81a5713be93e1365390dcbc3c8e7439ff1d36a84cc014f5642","0x11351b961147431e54535248b58b35cf5cddb9b13827899167617d7a96794d64","0x297c9421c9c3db286770787c35b86bc41583386491b4ae55e5fa81aefa21efc4","0x0f4eeca3ff4a3495f859898937688652d33f9b4dd3e003e12adf15278e0997c3","0x133e3d8b82721d40d919f2326810ba6f07eff3f7d20d86b2bde692a811522019","0x2c502f53c9698b73bb8c8f9b9cf2d705d16a64a7040348b4b39c637a2064316c","0x0cbc1971e1c566cde9d9125c91cdc88e817db182692f836c1a5170a6246eaf73","0x12c47793e7db706c637cd4b4d96d227f569850176b852b1fe8ad522ddb38ef0e","0x0cd7b300e9309a135285be1aeb02b152f97931a7357ab6d609a2cb1970aab877","0x2a7789dfe286c9d0a7592f1c9316e730cb14c9d843aefc4764d76e7f8571c96a","0x248ac54ce3dbf37796621882a4ac76046df5ab680da487fd85cce76b1ae392d3","0x149d1d07cebe320f77b03533e34912545cedeae62bd9778d37724728762b5710","0x00fe29daebdaed61309790e70e2dcefa3f3af4c6c965ce424b8dbcf09b8e4b49","0x2b75b3bace61b731d7f0c003a144b62b0a4fbe9f0d14ca89b0652b70210014b3","0x2588ef27cfb6e0d8c6f9a969b2da44fead30a02ed70a563fd15aa45bb671de1c","0x2b74d7674b55642697b4a1e226eddb0e4918b2d57aa5b99093dc46cadcdea000","0x244c626845d3a5040f08f01e9611f968ad675ca857789149b13a0cfa83a2e064","0x2cb8d02f90cae33fd7bcfb80af4aff067c4f5fc4b3f9228d5b8f768bc8f6c971","0x1372f3d1f04e0c39a50e823d5da03d70bebe19a1b8e28f8c2ff601cc0bfc0095","0x19af6601d2613426a50b7c35d60562a5f2f2634e6af56dac13459632e15570ee","0x13c2a16ed3b65dcd9414659be79af17995d344de34eaf962343b0f1e76c73a57","0x0dd5dcdbd50b8774831d4f01f930804d38b4266dfee085185530880a0c3903c0","0x07e91848d660b11b722638680ac60f20db9507fdc8d610ce762600f5a1aacd29","0x1f9c2a94d10c0a7fb60292cfc46fd3d2501181bea0ffe1f5f2501d474be3a785","0x14edb9c5bd389eae08a5ea2a7a1662894e1e878c142084d966a625bef68cf7c3","0x00000000000000000000000000000000cecd01810814d175f0a533f0067618c4","0x00000000000000000000000000000000f82935013ce5c82720c63e533af41db8","0x000000000000000000000000000000012185688171b6bed850e748b66f7222ac","0x2dd7f5ff2150155c2ac86ebe28d9ecbca2eea812b0021ab2bceae111cfea8325","0x04ea6c2daf2b9e827d2213c3d03953410dcf1ed67ba34a3c00e772be92606a8b","0x163f2bd18dcde52f99b9867c944780fd718d1612927053b139b280fc55013d1b","0x05e388fd160ccac30a8f7b18a4bd042f705e92b5937e8c0e9478e2ff623907c6","0x00ba3f6f527d6ed3ff17a63b1d5be3c42bdfae88fdf63311fc7b871157939309","0x16187d9daa8c2e5a1a9ab15be7ca6a8feebfb31bea76f9a3ca69381881c70561","0x0f64522e4904edb7377b14a7b9dad848829167324ef5c016346b3ad8251191ee","0x273bbe6000a4001dce369e5a36cc0b0ca3fd351665b688238aa8c556a6ca6b8e","0x022d2232efb2faa8307846c9a4c697aabad1b7f1336b35ad72fa8922975b49d9","0x0d82d478bff3955c4b0a34ef94427ca5f9da23147ad953c89f2e428277ec2825","0x18d886be90343010659c231583be61a138e28e37c24771e3cb61fbe2587d0671","0x000000000000000000000000000000196ba6a58dbeb7c34cb1d6287e23d434de","0x00000000000000000000000000000000001df8ae8a1589590f8863c1fefd8dfd","0x000000000000000000000000000000f30e11b2c5fbefa166cbb9f58c5f8e1a4c","0x000000000000000000000000000000000026420ade7666bc0ab1cf1fd9d0c534","0x0000000000000000000000000000000feb5b7d8260d25a1ee1ce76ff461673fc","0x00000000000000000000000000000000002bd2ac6223a80671b777bf5dca70a4","0x000000000000000000000000000000690f757006d2fa1ddb0114c9f268783537","0x000000000000000000000000000000000023ad36feadd91e50118f32e97a0204"] \ No newline at end of file diff --git a/tooling/nargo_cli/tests/execution_success/merkle_insert/Prover.toml b/tooling/nargo_cli/tests/execution_success/merkle_insert/Prover.toml index fca4a077df4..3f69ad1cffb 100644 --- a/tooling/nargo_cli/tests/execution_success/merkle_insert/Prover.toml +++ b/tooling/nargo_cli/tests/execution_success/merkle_insert/Prover.toml @@ -1,11 +1,11 @@ -old_root = "0x285785b10eca49cf456b935f1c9787ff571f306c1bc62549c31a9199a633f9f8" +old_root = "0x200fbe381993186866de8eb5a9cc33845de6b084be3ff67f6e34d35b8a786157" old_leaf = "0x1cdcf02431ba623767fe389337d011df1048dcc24b98ed81cec97627bab454a0" old_hash_path = [ "0x1cdcf02431ba623767fe389337d011df1048dcc24b98ed81cec97627bab454a0", "0x0b5e9666e7323ce925c28201a97ddf4144ac9d148448ed6f49f9008719c1b85b", "0x22ec636f8ad30ef78c42b7fe2be4a4cacf5a445cfb5948224539f59a11d70775", ] -new_root = "0x2d05c2650e6c2ef02c6dc7fae7f517b8ac191386666c0b5a68130a8c11092f5f" +new_root = "0x029ead881a6684995190589a67874f188f33a433211df82f56c1351c96530387" leaf = "0x085ca53be9c9d95b57e6e5fc91c5d531ad9e63e85dd71af7e35562991774b435" index = "0" -mimc_input = [12,45,78,41] +mimc_input = [12, 45, 78, 41] diff --git a/tooling/nargo_cli/tests/execution_success/pedersen_check/Prover.toml b/tooling/nargo_cli/tests/execution_success/pedersen_check/Prover.toml index 2fb3b1e1abf..db1ebdf6c51 100644 --- a/tooling/nargo_cli/tests/execution_success/pedersen_check/Prover.toml +++ b/tooling/nargo_cli/tests/execution_success/pedersen_check/Prover.toml @@ -2,5 +2,6 @@ x = "0" y = "1" salt = "42" -out_x = "0x0c5e1ddecd49de44ed5e5798d3f6fb7c71fe3d37f5bee8664cf88a445b5ba0af" -out_y = "0x230294a041e26fe80b827c2ef5cb8784642bbaa83842da2714d62b1f3c4f9752" \ No newline at end of file +out_x = "0x054aa86a73cb8a34525e5bbed6e43ba1198e860f5f3950268f71df4591bde402" +out_y = "0x209dcfbf2cfb57f9f6046f44d71ac6faf87254afc7407c04eb621a6287cac126" +out_hash = "0x0d98561fb02ca04d00801dfdc118b2a24cea0351963587712a28d368041370e1" diff --git a/tooling/nargo_cli/tests/execution_success/pedersen_check/src/main.nr b/tooling/nargo_cli/tests/execution_success/pedersen_check/src/main.nr index 0e5c6b2c5b4..8d3460de98f 100644 --- a/tooling/nargo_cli/tests/execution_success/pedersen_check/src/main.nr +++ b/tooling/nargo_cli/tests/execution_success/pedersen_check/src/main.nr @@ -1,9 +1,13 @@ use dep::std; -fn main(x: Field, y: Field, salt: Field, out_x: Field, out_y: Field ) { +fn main(x: Field, y: Field, salt: Field, out_x: Field, out_y: Field, out_hash: Field) { let res = std::hash::pedersen([x, y]); assert(res[0] == out_x); assert(res[1] == out_y); + let res_hash = std::hash::pedersen_hash_with_separator([x, y], 0); + assert_eq(res_hash, out_hash); + + assert(res_hash != res[0]); let raw_data = [x,y]; let mut state = 0; diff --git a/tooling/nargo_cli/tests/execution_success/references_aliasing/Nargo.toml b/tooling/nargo_cli/tests/execution_success/references_aliasing/Nargo.toml deleted file mode 100644 index b95c3998483..00000000000 --- a/tooling/nargo_cli/tests/execution_success/references_aliasing/Nargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "references_aliasing" -type = "bin" -authors = [""] -compiler_version = "0.5.1" - -[dependencies] diff --git a/tooling/nargo_cli/tests/execution_success/references_aliasing/src/main.nr b/tooling/nargo_cli/tests/execution_success/references_aliasing/src/main.nr deleted file mode 100644 index 02057732f35..00000000000 --- a/tooling/nargo_cli/tests/execution_success/references_aliasing/src/main.nr +++ /dev/null @@ -1,29 +0,0 @@ -fn main() { - let mut x = 100; - let mut xref = &mut x; - increment(xref); - assert(*xref == 101); - - regression_2445(); -} - -fn increment(mut r: &mut Field) { - *r = *r + 1; -} - -// If aliasing within arrays and constant folding within the mem2reg pass aren't -// handled, we'll fail to optimize out all the references in this function. -fn regression_2445() { - let mut var = 0; - let ref = &mut &mut var; - - let mut array = [ref, ref]; - - **array[0] = 1; - **array[1] = 2; - - assert(var == 2); - assert(**ref == 2); - assert(**array[0] == 2); - assert(**array[1] == 2); -} diff --git a/tooling/nargo_cli/tests/execution_success/schnorr/Prover.toml b/tooling/nargo_cli/tests/execution_success/schnorr/Prover.toml index 5fe6bd2546f..2faf2018e07 100644 --- a/tooling/nargo_cli/tests/execution_success/schnorr/Prover.toml +++ b/tooling/nargo_cli/tests/execution_success/schnorr/Prover.toml @@ -1,10 +1,70 @@ -message = [0,1,2,3,4,5,6,7,8,9] +message = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] message_field = "0x010203040506070809" -pub_key_x = "0x17cbd3ed3151ccfd170efe1d54280a6a4822640bf5c369908ad74ea21518a9c5" -pub_key_y = "0x0e0456e3795c1a31f20035b741cd6158929eeccd320d299cfcac962865a6bc74" +pub_key_x = "0x04b260954662e97f00cab9adb773a259097f7a274b83b113532bce27fa3fb96a" +pub_key_y = "0x2fd51571db6c08666b0edfbfbc57d432068bccd0110a39b166ab243da0037197" signature = [ - 5, 202, 31, 146, 81, 242, 246, 69, 43, 107, 249, 153, 198, 44, 14, 111, 191, 121, 137, 166, - 160, 103, 18, 181, 243, 233, 226, 95, 67, 16, 37, 128, 85, 76, 19, 253, 30, 77, 192, 53, 138, - 205, 69, 33, 236, 163, 83, 194, 84, 137, 184, 221, 176, 121, 179, 27, 63, 70, 54, 16, 176, - 250, 39, 239, -] \ No newline at end of file + 1, + 13, + 119, + 112, + 212, + 39, + 233, + 41, + 84, + 235, + 255, + 93, + 245, + 172, + 186, + 83, + 157, + 253, + 76, + 77, + 33, + 128, + 178, + 15, + 214, + 67, + 105, + 107, + 177, + 234, + 77, + 48, + 27, + 237, + 155, + 84, + 39, + 84, + 247, + 27, + 22, + 8, + 176, + 230, + 24, + 115, + 145, + 220, + 254, + 122, + 135, + 179, + 171, + 4, + 214, + 202, + 64, + 199, + 19, + 84, + 239, + 138, + 124, + 12, +] diff --git a/tooling/nargo_cli/tests/execution_success/simple_shield/Prover.toml b/tooling/nargo_cli/tests/execution_success/simple_shield/Prover.toml index 5a9b2f21b9b..55492a9bf6d 100644 --- a/tooling/nargo_cli/tests/execution_success/simple_shield/Prover.toml +++ b/tooling/nargo_cli/tests/execution_success/simple_shield/Prover.toml @@ -1,6 +1,6 @@ # Random test key priv_key = "0x000000000000000000000000000000000000000000000000000000616c696365" -note_root = "0x21386402d57460963f45f32577dc3902c38a6f6fab9ec7b1b708a92e48745de7" +note_root = "0x0f8cd7b45fbb4e08f63126f1673ce9e574cfbda70f36c2e5182f9e3dbe6524c0" index = "0" note_hash_path = [ "0x1cdcf02431ba623767fe389337d011df1048dcc24b98ed81cec97627bab454a0", diff --git a/tooling/nargo_cli/tests/execution_success/slices/src/main.nr b/tooling/nargo_cli/tests/execution_success/slices/src/main.nr index e027c0f5ea2..8d53e013f96 100644 --- a/tooling/nargo_cli/tests/execution_success/slices/src/main.nr +++ b/tooling/nargo_cli/tests/execution_success/slices/src/main.nr @@ -49,6 +49,7 @@ fn main(x : Field, y : pub Field) { regression_2083(); // The parameters to this function must come from witness values (inputs to main) regression_merge_slices(x, y); + regression_2370(); } // Ensure that slices of struct/tuple values work. @@ -301,3 +302,10 @@ fn merge_slices_remove_between_ifs(x: Field, y: Field) -> [Field] { slice } + +// Previously, we'd get a type error when trying to assign an array of a different size to +// an existing array variable. Now, we infer the variable must be a slice. +fn regression_2370() { + let mut slice = []; + slice = [1, 2, 3]; +} diff --git a/tooling/nargo_cli/tests/execution_success/trait_as_return_type/Nargo.toml b/tooling/nargo_cli/tests/execution_success/trait_as_return_type/Nargo.toml new file mode 100644 index 00000000000..1a7ef7ee8a2 --- /dev/null +++ b/tooling/nargo_cli/tests/execution_success/trait_as_return_type/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "trait_as_return_type" +type = "bin" +authors = [""] +compiler_version = "0.10.5" + +[dependencies] \ No newline at end of file diff --git a/tooling/nargo_cli/tests/execution_success/trait_as_return_type/Prover.toml b/tooling/nargo_cli/tests/execution_success/trait_as_return_type/Prover.toml new file mode 100644 index 00000000000..a0cd58138b6 --- /dev/null +++ b/tooling/nargo_cli/tests/execution_success/trait_as_return_type/Prover.toml @@ -0,0 +1 @@ +x = "5" \ No newline at end of file diff --git a/tooling/nargo_cli/tests/execution_success/trait_as_return_type/src/main.nr b/tooling/nargo_cli/tests/execution_success/trait_as_return_type/src/main.nr new file mode 100644 index 00000000000..e84fe15aba7 --- /dev/null +++ b/tooling/nargo_cli/tests/execution_success/trait_as_return_type/src/main.nr @@ -0,0 +1,55 @@ +trait SomeTrait { + fn magic_number(self) -> Field; +} + +struct A {} +struct B {} +struct C { + x: Field +} + + +impl SomeTrait for A { + fn magic_number(self) -> Field { + 2 + } +} + +impl SomeTrait for B { + fn magic_number(self) -> Field { + 4 + } +} + +impl SomeTrait for C { + fn magic_number(self) -> Field { + self.x + } +} + + + +fn factory_a() -> impl SomeTrait { + A {} +} + +fn factory_b() -> impl SomeTrait { + B {} +} + +fn factory_c(x: Field) -> impl SomeTrait { + C {x:x} +} + +// x = 15 +fn main(x: u32) { + let a = factory_a(); + let b = B {}; + let b2 = factory_b(); + assert(a.magic_number() == 2); + assert(b.magic_number() == 4); + assert(b2.magic_number() == 4); + let c = factory_c(10); + assert(c.magic_number() == 10); + assert(factory_c(13).magic_number() == 13); +} \ No newline at end of file diff --git a/tooling/nargo_cli/tests/execution_success/trait_multi_module_test/Prover.toml b/tooling/nargo_cli/tests/execution_success/trait_multi_module_test/Prover.toml deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/tooling/nargo_cli/tests/gates_report.sh b/tooling/nargo_cli/tests/gates_report.sh new file mode 100755 index 00000000000..e06e6812e9d --- /dev/null +++ b/tooling/nargo_cli/tests/gates_report.sh @@ -0,0 +1,36 @@ +#!/bin/bash +set -e + +# These tests are incompatible with gas reporting +excluded_dirs=("workspace" "workspace_default_member") + +# These tests cause failures in CI with a stack overflow for some reason. +ci_excluded_dirs=("eddsa") + +current_dir=$(pwd) +base_path="$current_dir/execution_success" +test_dirs=$(ls $base_path) + +# We generate a Noir workspace which contains all of the test cases +# This allows us to generate a gates report using `nargo info` for all of them at once. + +echo "[workspace]" > Nargo.toml +echo "members = [" >> Nargo.toml + +for dir in $test_dirs; do + if [[ " ${excluded_dirs[@]} " =~ " ${dir} " ]]; then + continue + fi + + if [[ ${CI-false} = "true" ]] && [[ " ${ci_excluded_dirs[@]} " =~ " ${dir} " ]]; then + continue + fi + + echo " \"execution_success/$dir\"," >> Nargo.toml +done + +echo "]" >> Nargo.toml + +nargo info --json > gates_report.json + +rm Nargo.toml diff --git a/tooling/nargo_fmt/src/config.rs b/tooling/nargo_fmt/src/config.rs index 7cb80a9f04d..dd57778da92 100644 --- a/tooling/nargo_fmt/src/config.rs +++ b/tooling/nargo_fmt/src/config.rs @@ -42,8 +42,12 @@ macro_rules! config { } config! { + max_width: usize, 100, "Maximum width of each line"; tab_spaces: usize, 4, "Number of spaces per tab"; remove_nested_parens: bool, true, "Remove nested parens"; + short_array_element_width_threshold: usize, 10, "Width threshold for an array element to be considered short"; + array_width: usize, 100, "Maximum width of an array literal before falling back to vertical formatting"; + single_line_if_else_max_width: usize, 100, "Maximum line length for single line if-else expressions"; } impl Config { diff --git a/tooling/nargo_fmt/src/lib.rs b/tooling/nargo_fmt/src/lib.rs index 9bc148ae304..3e8ee570c09 100644 --- a/tooling/nargo_fmt/src/lib.rs +++ b/tooling/nargo_fmt/src/lib.rs @@ -20,6 +20,7 @@ /// in both placement and content during the formatting process. mod config; pub mod errors; +mod utils; mod visitor; use noirc_frontend::ParsedModule; diff --git a/tooling/nargo_fmt/src/utils.rs b/tooling/nargo_fmt/src/utils.rs new file mode 100644 index 00000000000..5b2cf2f3c47 --- /dev/null +++ b/tooling/nargo_fmt/src/utils.rs @@ -0,0 +1,243 @@ +use crate::visitor::FmtVisitor; +use noirc_frontend::hir::resolution::errors::Span; +use noirc_frontend::lexer::Lexer; +use noirc_frontend::token::Token; +use noirc_frontend::{Expression, Ident}; + +pub(crate) fn recover_comment_removed(original: &str, new: String) -> String { + if changed_comment_content(original, &new) { + original.to_string() + } else { + new + } +} + +pub(crate) fn changed_comment_content(original: &str, new: &str) -> bool { + comments(original).ne(comments(new)) +} + +pub(crate) fn comments(source: &str) -> impl Iterator + '_ { + Lexer::new(source).skip_comments(false).flatten().filter_map(|spanned| { + if let Token::LineComment(content, _) | Token::BlockComment(content, _) = + spanned.into_token() + { + Some(content) + } else { + None + } + }) +} + +#[derive(Debug)] +pub(crate) struct Expr { + pub(crate) leading: String, + pub(crate) value: String, + pub(crate) trailing: String, + pub(crate) different_line: bool, +} + +impl Expr { + pub(crate) fn total_width(&self) -> usize { + comment_len(&self.leading) + self.value.chars().count() + comment_len(&self.trailing) + } + + pub(crate) fn is_multiline(&self) -> bool { + self.leading.contains('\n') || self.trailing.contains('\n') + } +} + +pub(crate) struct Exprs<'me, T> { + pub(crate) visitor: &'me FmtVisitor<'me>, + pub(crate) elements: std::iter::Peekable>, + pub(crate) last_position: u32, + pub(crate) end_position: u32, +} + +impl<'me, T: Item> Exprs<'me, T> { + pub(crate) fn new(visitor: &'me FmtVisitor<'me>, span: Span, elements: Vec) -> Self { + Self { + visitor, + last_position: span.start() + 1, /*(*/ + end_position: span.end() - 1, /*)*/ + elements: elements.into_iter().peekable(), + } + } +} + +impl Iterator for Exprs<'_, T> { + type Item = Expr; + + fn next(&mut self) -> Option { + let element = self.elements.next()?; + let element_span = element.span(); + + let start = self.last_position; + let end = element_span.start(); + + let is_last = self.elements.peek().is_none(); + let next_start = self.elements.peek().map_or(self.end_position, |expr| expr.start()); + + let (leading, different_line) = self.leading(start, end); + let expr = element.format(self.visitor); + let trailing = self.trailing(element_span.end(), next_start, is_last); + + Expr { leading, value: expr, trailing, different_line }.into() + } +} + +impl<'me, T> Exprs<'me, T> { + pub(crate) fn leading(&mut self, start: u32, end: u32) -> (String, bool) { + let mut different_line = false; + + let leading = self.visitor.slice(start..end); + let leading_trimmed = leading.trim(); + + let starts_with_block_comment = leading_trimmed.starts_with("/*"); + let ends_with_block_comment = leading_trimmed.ends_with("*/"); + let starts_with_single_line_comment = leading_trimmed.starts_with("//"); + + if ends_with_block_comment { + let comment_end = leading_trimmed.rfind(|c| c == '/').unwrap(); + + if leading[comment_end..].contains('\n') { + different_line = true; + } + } else if starts_with_single_line_comment || starts_with_block_comment { + different_line = true; + }; + + (leading_trimmed.to_string(), different_line) + } + + pub(crate) fn trailing(&mut self, start: u32, end: u32, is_last: bool) -> String { + let slice = self.visitor.slice(start..end); + let comment_end = find_comment_end(slice, is_last); + let trailing = slice[..comment_end].trim_matches(',').trim(); + self.last_position = start + (comment_end as u32); + trailing.to_string() + } +} + +pub(crate) trait FindToken { + fn find_token(&self, token: Token) -> Option; + fn find_token_with(&self, f: impl Fn(&Token) -> bool) -> Option; +} + +impl FindToken for str { + fn find_token(&self, token: Token) -> Option { + Lexer::new(self) + .flatten() + .find_map(|it| (it.token() == &token).then(|| it.to_span().start())) + } + + fn find_token_with(&self, f: impl Fn(&Token) -> bool) -> Option { + Lexer::new(self) + .skip_comments(false) + .flatten() + .into_iter() + .find_map(|spanned| f(spanned.token()).then(|| spanned.to_span().end())) + } +} + +pub(crate) fn find_comment_end(slice: &str, is_last: bool) -> usize { + fn find_comment_end(slice: &str) -> usize { + slice + .find_token_with(|token| { + matches!(token, Token::LineComment(_, _) | Token::BlockComment(_, _)) + }) + .map(|index| index as usize) + .unwrap_or(slice.len()) + } + + if is_last { + return slice.len(); + } + + let mut block_open_index = slice.find("/*"); + if let Some(index) = block_open_index { + match slice.find('/') { + Some(slash) if slash < index => block_open_index = None, + _ if slice[..index].ends_with('/') => block_open_index = None, + _ => (), + } + } + + let newline_index = slice.find('\n'); + if let Some(separator_index) = slice.find_token(Token::Comma).map(|index| index as usize) { + match (block_open_index, newline_index) { + (Some(block), None) if block > separator_index => separator_index + 1, + (Some(block), None) => { + let slice = &slice[block..]; + std::cmp::max(find_comment_end(slice) + block, separator_index + 1) + } + (Some(block), Some(newline)) if block < newline => { + let slice = &slice[block..]; + std::cmp::max(find_comment_end(slice) + block, separator_index + 1) + } + (_, Some(newline)) if newline > separator_index => newline + 1, + _ => slice.len(), + } + } else if let Some(newline_index) = newline_index { + newline_index + 1 + } else { + 0 + } +} + +fn comment_len(comment: &str) -> usize { + match comment { + "" => 0, + _ => { + let len = comment.trim().len(); + if len > 0 { + len + 6 + } else { + len + } + } + } +} + +pub(crate) trait Item { + fn span(&self) -> Span; + + fn format(self, visitor: &FmtVisitor) -> String; + + fn start(&self) -> u32 { + self.span().start() + } + + fn end(&self) -> u32 { + self.span().end() + } +} + +impl Item for Expression { + fn span(&self) -> Span { + self.span + } + + fn format(self, visitor: &FmtVisitor) -> String { + visitor.format_sub_expr(self) + } +} + +impl Item for (Ident, Expression) { + fn span(&self) -> Span { + let (name, value) = self; + (name.span().start()..value.span.end()).into() + } + + fn format(self, visitor: &FmtVisitor) -> String { + let (name, expr) = self; + + let name = name.0.contents; + let expr = visitor.format_sub_expr(expr); + + if name == expr { + name + } else { + format!("{name}: {expr}") + } + } +} diff --git a/tooling/nargo_fmt/src/visitor.rs b/tooling/nargo_fmt/src/visitor.rs index b0b897c4cd7..bc769e3f298 100644 --- a/tooling/nargo_fmt/src/visitor.rs +++ b/tooling/nargo_fmt/src/visitor.rs @@ -1,24 +1,19 @@ -/// A macro to create a slice from a given data source, helping to avoid borrow checker errors. -#[macro_export] -macro_rules! slice { - ($this:ident, $start:expr, $end:expr) => { - &$this.source[$start as usize..$end as usize] - }; -} - mod expr; mod item; mod stmt; -use noirc_frontend::hir::resolution::errors::Span; +use noirc_frontend::{hir::resolution::errors::Span, token::Token}; -use crate::config::Config; +use crate::{ + config::Config, + utils::{self, FindToken}, +}; pub(crate) struct FmtVisitor<'me> { config: &'me Config, buffer: String, - source: &'me str, - block_indent: Indent, + pub(crate) source: &'me str, + indent: Indent, last_position: u32, } @@ -29,17 +24,38 @@ impl<'me> FmtVisitor<'me> { config, source, last_position: 0, - block_indent: Indent { block_indent: 0 }, + indent: Indent { block_indent: 0 }, + } + } + + pub(crate) fn slice(&self, span: impl Into) -> &'me str { + let span = span.into(); + &self.source[span.start() as usize..span.end() as usize] + } + + fn span_before(&self, span: impl Into, token: Token) -> Span { + let span = span.into(); + + let slice = self.slice(span); + let offset = slice.find_token(token).unwrap(); + + (span.start() + offset..span.end()).into() + } + + fn shape(&self) -> Shape { + Shape { + width: self.config.max_width.saturating_sub(self.indent.width()), + indent: self.indent, } } pub(crate) fn fork(&self) -> Self { Self { - config: self.config, buffer: String::new(), + config: self.config, source: self.source, - block_indent: self.block_indent, last_position: self.last_position, + indent: self.indent, } } @@ -48,9 +64,9 @@ impl<'me> FmtVisitor<'me> { } fn with_indent(&mut self, f: impl FnOnce(&mut Self) -> T) -> T { - self.block_indent.block_indent(self.config); + self.indent.block_indent(self.config); let ret = f(self); - self.block_indent.block_unindent(self.config); + self.indent.block_unindent(self.config); ret } @@ -63,9 +79,10 @@ impl<'me> FmtVisitor<'me> { } #[track_caller] - fn push_rewrite(&mut self, s: String, span: Span) { + fn push_rewrite(&mut self, rewrite: String, span: Span) { + let rewrite = utils::recover_comment_removed(self.slice(span), rewrite); self.format_missing_indent(span.start(), true); - self.push_str(&s); + self.push_str(&rewrite); } fn format_missing(&mut self, end: u32) { @@ -82,7 +99,7 @@ impl<'me> FmtVisitor<'me> { } if should_indent { - let indent = this.block_indent.to_string(); + let indent = this.indent.to_string(); this.push_str(&indent); } }); @@ -103,7 +120,7 @@ impl<'me> FmtVisitor<'me> { return; } - let slice = slice!(self, start, end); + let slice = self.slice(start..end); self.last_position = end; if slice.trim().is_empty() && !self.at_start() { @@ -140,7 +157,7 @@ impl<'me> FmtVisitor<'me> { } pub(crate) fn format_comment(&self, span: Span) -> String { - let slice = slice!(self, span.start(), span.end()).trim(); + let slice = self.slice(span).trim(); let pos = slice.find('/'); if !slice.is_empty() && pos.is_some() { @@ -151,12 +168,16 @@ impl<'me> FmtVisitor<'me> { } } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug, Default)] struct Indent { block_indent: usize, } impl Indent { + fn width(&self) -> usize { + self.block_indent + } + fn block_indent(&mut self, config: &Config) { self.block_indent += config.tab_spaces; } @@ -174,3 +195,15 @@ impl Indent { " ".repeat(self.block_indent) } } + +#[derive(Clone, Copy, Debug)] +struct Shape { + width: usize, + indent: Indent, +} + +#[derive(PartialEq, Eq, Debug)] +pub(crate) enum ExpressionType { + Statement, + SubExpression, +} diff --git a/tooling/nargo_fmt/src/visitor/expr.rs b/tooling/nargo_fmt/src/visitor/expr.rs index c2d3b4f6632..8f855cd6157 100644 --- a/tooling/nargo_fmt/src/visitor/expr.rs +++ b/tooling/nargo_fmt/src/visitor/expr.rs @@ -1,22 +1,34 @@ use noirc_frontend::{ - hir::resolution::errors::Span, lexer::Lexer, token::Token, ArrayLiteral, BlockExpression, - Expression, ExpressionKind, Literal, Statement, UnaryOp, + hir::resolution::errors::Span, token::Token, ArrayLiteral, BlockExpression, + ConstructorExpression, Expression, ExpressionKind, IfExpression, Literal, Statement, + StatementKind, UnaryOp, }; -use super::FmtVisitor; +use super::{ExpressionType, FmtVisitor, Indent, Shape}; +use crate::{ + utils::{self, Expr, FindToken, Item}, + Config, +}; impl FmtVisitor<'_> { - pub(crate) fn visit_expr(&mut self, expr: Expression) { + pub(crate) fn visit_expr(&mut self, expr: Expression, expr_type: ExpressionType) { let span = expr.span; - let rewrite = self.format_expr(expr); - let rewrite = recover_comment_removed(slice!(self, span.start(), span.end()), rewrite); + let rewrite = self.format_expr(expr, expr_type); self.push_rewrite(rewrite, span); self.last_position = span.end(); } - fn format_expr(&self, Expression { kind, mut span }: Expression) -> String { + pub(crate) fn format_sub_expr(&self, expression: Expression) -> String { + self.format_expr(expression, ExpressionType::SubExpression) + } + + pub(crate) fn format_expr( + &self, + Expression { kind, mut span }: Expression, + expr_type: ExpressionType, + ) -> String { match kind { ExpressionKind::Block(block) => { let mut visitor = self.fork(); @@ -37,73 +49,70 @@ impl FmtVisitor<'_> { } }; - format!("{op}{}", self.format_expr(prefix.rhs)) + format!("{op}{}", self.format_sub_expr(prefix.rhs)) } ExpressionKind::Cast(cast) => { - format!("{} as {}", self.format_expr(cast.lhs), cast.r#type) + format!("{} as {}", self.format_sub_expr(cast.lhs), cast.r#type) } ExpressionKind::Infix(infix) => { format!( "{} {} {}", - self.format_expr(infix.lhs), + self.format_sub_expr(infix.lhs), infix.operator.contents.as_string(), - self.format_expr(infix.rhs) + self.format_sub_expr(infix.rhs) ) } ExpressionKind::Call(call_expr) => { - let formatted_func = self.format_expr(*call_expr.func); - let formatted_args = call_expr - .arguments - .into_iter() - .map(|arg| self.format_expr(arg)) - .collect::>() - .join(", "); - format!("{}({})", formatted_func, formatted_args) + let args_span = + self.span_before(call_expr.func.span.end()..span.end(), Token::LeftParen); + + let callee = self.format_sub_expr(*call_expr.func); + let args = format_parens(self.fork(), false, call_expr.arguments, args_span); + + format!("{callee}{args}") } ExpressionKind::MethodCall(method_call_expr) => { - let formatted_object = self.format_expr(method_call_expr.object).trim().to_string(); - let formatted_args = method_call_expr - .arguments - .iter() - .map(|arg| { - let arg_str = self.format_expr(arg.clone()).trim().to_string(); - if arg_str.contains('(') { - return arg_str - .replace(" ,", ",") - .replace("( ", "(") - .replace(" )", ")"); - } - arg_str - }) - .collect::>() - .join(", "); - format!("{}.{}({})", formatted_object, method_call_expr.method_name, formatted_args) + let args_span = self.span_before( + method_call_expr.method_name.span().end()..span.end(), + Token::LeftParen, + ); + + let object = self.format_sub_expr(method_call_expr.object); + let method = method_call_expr.method_name.to_string(); + let args = format_parens(self.fork(), false, method_call_expr.arguments, args_span); + + format!("{object}.{method}{args}") } ExpressionKind::MemberAccess(member_access_expr) => { - let lhs_str = self.format_expr(member_access_expr.lhs); + let lhs_str = self.format_sub_expr(member_access_expr.lhs); format!("{}.{}", lhs_str, member_access_expr.rhs) } ExpressionKind::Index(index_expr) => { - let formatted_collection = - self.format_expr(index_expr.collection).trim_end().to_string(); - let formatted_index = self.format_expr(index_expr.index); - format!("{}[{}]", formatted_collection, formatted_index) + let index_span = self + .span_before(index_expr.collection.span.end()..span.end(), Token::LeftBracket); + + let collection = self.format_sub_expr(index_expr.collection); + let index = format_brackets(self.fork(), false, vec![index_expr.index], index_span); + + format!("{collection}{index}") + } + ExpressionKind::Tuple(exprs) => { + format_parens(self.fork(), exprs.len() == 1, exprs, span) } ExpressionKind::Literal(literal) => match literal { - Literal::Integer(_) => slice!(self, span.start(), span.end()).to_string(), + Literal::Integer(_) | Literal::Bool(_) | Literal::Str(_) | Literal::FmtStr(_) => { + self.slice(span).to_string() + } Literal::Array(ArrayLiteral::Repeated { repeated_element, length }) => { - format!("[{}; {length}]", self.format_expr(*repeated_element)) + let repeated = self.format_sub_expr(*repeated_element); + let length = self.format_sub_expr(*length); + + format!("[{repeated}; {length}]") } - // TODO: Handle line breaks when array gets too long. Literal::Array(ArrayLiteral::Standard(exprs)) => { - let contents: Vec = - exprs.into_iter().map(|expr| self.format_expr(expr)).collect(); - format!("[{}]", contents.join(", ")) - } - - Literal::Bool(_) | Literal::Str(_) | Literal::FmtStr(_) | Literal::Unit => { - literal.to_string() + format_brackets(self.fork(), false, exprs, span) } + Literal::Unit => "()".to_string(), }, ExpressionKind::Parenthesized(mut sub_expr) => { let remove_nested_parens = self.config.remove_nested_parens; @@ -130,16 +139,16 @@ impl FmtVisitor<'_> { } if !leading.contains("//") && !trailing.contains("//") { - let sub_expr = self.format_expr(*sub_expr); + let sub_expr = self.format_sub_expr(*sub_expr); format!("({leading}{sub_expr}{trailing})") } else { let mut visitor = self.fork(); - let indent = visitor.block_indent.to_string_with_newline(); - visitor.block_indent.block_indent(self.config); - let nested_indent = visitor.block_indent.to_string_with_newline(); + let indent = visitor.indent.to_string_with_newline(); + visitor.indent.block_indent(self.config); + let nested_indent = visitor.indent.to_string_with_newline(); - let sub_expr = visitor.format_expr(*sub_expr); + let sub_expr = visitor.format_sub_expr(*sub_expr); let mut result = String::new(); result.push('('); @@ -163,11 +172,115 @@ impl FmtVisitor<'_> { result } } - // TODO: - _expr => slice!(self, span.start(), span.end()).to_string(), + ExpressionKind::Constructor(constructor) => { + let type_name = self.slice(span.start()..constructor.type_name.span().end()); + let fields_span = self + .span_before(constructor.type_name.span().end()..span.end(), Token::LeftBrace); + + self.format_struct_lit(type_name, fields_span, *constructor) + } + ExpressionKind::If(if_expr) => { + let allow_single_line = expr_type == ExpressionType::SubExpression; + + if allow_single_line { + let mut visitor = self.fork(); + visitor.indent = Indent::default(); + if let Some(line) = visitor.format_if_single_line(*if_expr.clone()) { + return line; + } + } + + self.format_if(*if_expr) + } + ExpressionKind::Variable(_) | ExpressionKind::Lambda(_) => self.slice(span).to_string(), + ExpressionKind::Error => unreachable!(), } } + fn format_if(&self, if_expr: IfExpression) -> String { + let condition_str = self.format_sub_expr(if_expr.condition); + let consequence_str = self.format_sub_expr(if_expr.consequence); + + let mut result = format!("if {condition_str} {consequence_str}"); + + if let Some(alternative) = if_expr.alternative { + let alternative = if let Some(ExpressionKind::If(if_expr)) = + extract_simple_expr(alternative.clone()).map(|expr| expr.kind) + { + self.format_if(*if_expr) + } else { + self.format_expr(alternative, ExpressionType::Statement) + }; + + result.push_str(" else "); + result.push_str(&alternative); + }; + + result + } + + fn format_if_single_line(&self, if_expr: IfExpression) -> Option { + let condition_str = self.format_sub_expr(if_expr.condition); + let consequence_str = self.format_sub_expr(extract_simple_expr(if_expr.consequence)?); + + let if_str = if let Some(alternative) = if_expr.alternative { + let alternative_str = if let Some(ExpressionKind::If(_)) = + extract_simple_expr(alternative.clone()).map(|expr| expr.kind) + { + return None; + } else { + self.format_expr(extract_simple_expr(alternative)?, ExpressionType::Statement) + }; + + format!("if {} {{ {} }} else {{ {} }}", condition_str, consequence_str, alternative_str) + } else { + format!("if {{{}}} {{{}}}", condition_str, consequence_str) + }; + + (if_str.len() <= self.config.single_line_if_else_max_width).then_some(if_str) + } + + fn format_struct_lit( + &self, + type_name: &str, + fields_span: Span, + constructor: ConstructorExpression, + ) -> String { + let fields = { + let mut visitor = self.fork(); + let is_unit_struct = constructor.fields.is_empty(); + + visitor.indent.block_indent(visitor.config); + + let nested_indent = visitor.shape(); + let exprs: Vec<_> = + utils::Exprs::new(&visitor, fields_span, constructor.fields).collect(); + let exprs = format_exprs( + visitor.config, + Tactic::HorizontalVertical, + false, + exprs, + nested_indent, + ); + + visitor.indent.block_unindent(visitor.config); + + if exprs.contains('\n') { + format!( + "{}{exprs}{}", + nested_indent.indent.to_string_with_newline(), + visitor.shape().indent.to_string_with_newline() + ) + } else if is_unit_struct { + exprs + } else { + format!(" {exprs} ") + } + }; + + format!("{type_name} {{{fields}}}") + } + pub(crate) fn visit_block( &mut self, block: BlockExpression, @@ -188,21 +301,21 @@ impl FmtVisitor<'_> { this.visit_stmts(block.0); }); - let slice = slice!(self, self.last_position, block_span.end() - 1).trim_end(); + let slice = self.slice(self.last_position..block_span.end() - 1).trim_end(); self.push_str(slice); self.last_position = block_span.end(); self.push_str("\n"); if should_indent { - self.push_str(&self.block_indent.to_string()); + self.push_str(&self.indent.to_string()); } self.push_str("}"); } fn trim_spaces_after_opening_brace(&mut self, block: &[Statement]) { if let Some(first_stmt) = block.first() { - let slice = slice!(self, self.last_position, first_stmt.span.start()); + let slice = self.slice(self.last_position..first_stmt.span.start()); let len = slice.chars().take_while(|ch| ch.is_whitespace()).collect::().rfind('\n'); self.last_position += len.unwrap_or(0) as u32; @@ -210,16 +323,15 @@ impl FmtVisitor<'_> { } fn visit_empty_block(&mut self, block_span: Span, should_indent: bool) { - let slice = slice!(self, block_span.start(), block_span.end()); + let slice = self.slice(block_span); let comment_str = slice[1..slice.len() - 1].trim(); let block_str = if comment_str.is_empty() { "{}".to_string() } else { - self.block_indent.block_indent(self.config); - let open_indent = self.block_indent.to_string(); - self.block_indent.block_unindent(self.config); - let close_indent = - if should_indent { self.block_indent.to_string() } else { String::new() }; + self.indent.block_indent(self.config); + let open_indent = self.indent.to_string(); + self.indent.block_unindent(self.config); + let close_indent = if should_indent { self.indent.to_string() } else { String::new() }; let ret = format!("{{\n{open_indent}{comment_str}\n{close_indent}}}"); ret @@ -229,29 +341,256 @@ impl FmtVisitor<'_> { } } -fn recover_comment_removed(original: &str, new: String) -> String { - if changed_comment_content(original, &new) { - original.to_string() +fn format_expr_seq( + prefix: &str, + suffix: &str, + mut visitor: FmtVisitor, + trailing_comma: bool, + exprs: Vec, + span: Span, + tactic: Tactic, +) -> String { + visitor.indent.block_indent(visitor.config); + + let nested_indent = visitor.shape(); + let exprs: Vec<_> = utils::Exprs::new(&visitor, span, exprs).collect(); + let exprs = format_exprs(visitor.config, tactic, trailing_comma, exprs, nested_indent); + + visitor.indent.block_unindent(visitor.config); + + wrap_exprs(prefix, suffix, exprs, nested_indent, visitor.shape()) +} + +fn format_brackets( + visitor: FmtVisitor, + trailing_comma: bool, + exprs: Vec, + span: Span, +) -> String { + let array_width = visitor.config.array_width; + format_expr_seq( + "[", + "]", + visitor, + trailing_comma, + exprs, + span, + Tactic::LimitedHorizontalVertical(array_width), + ) +} + +fn format_parens( + visitor: FmtVisitor, + trailing_comma: bool, + exprs: Vec, + span: Span, +) -> String { + format_expr_seq("(", ")", visitor, trailing_comma, exprs, span, Tactic::Horizontal) +} + +fn format_exprs( + config: &Config, + tactic: Tactic, + trailing_comma: bool, + exprs: Vec, + shape: Shape, +) -> String { + let mut result = String::new(); + let indent_str = shape.indent.to_string(); + + let tactic = tactic.definitive(&exprs, config.short_array_element_width_threshold); + let mut exprs = exprs.into_iter().enumerate().peekable(); + let mut line_len = 0; + let mut prev_expr_trailing_comment = false; + + while let Some((index, expr)) = exprs.next() { + let is_first = index == 0; + let separate = exprs.peek().is_some() || trailing_comma; + let separate_len = usize::from(separate); + + match tactic { + DefinitiveTactic::Vertical + if !is_first && !expr.value.is_empty() && !result.is_empty() => + { + result.push('\n'); + result.push_str(&indent_str); + } + DefinitiveTactic::Horizontal if !is_first => { + result.push(' '); + } + DefinitiveTactic::Mixed => { + let total_width = expr.total_width() + separate_len; + + if line_len > 0 && line_len + 1 + total_width > shape.width + || prev_expr_trailing_comment + { + result.push('\n'); + result.push_str(&indent_str); + line_len = 0; + } else if line_len > 0 { + result.push(' '); + line_len += 1; + } + + line_len += total_width; + } + _ => {} + } + + result.push_str(&expr.leading); + + if expr.different_line { + result.push('\n'); + result.push_str(&indent_str); + line_len = expr.value.chars().count(); + } else if !expr.leading.is_empty() { + result.push(' '); + } + + result.push_str(&expr.value); + + if tactic == DefinitiveTactic::Horizontal { + result.push_str(&expr.trailing); + } + + if separate && expr.trailing.find_token(Token::Comma).is_none() { + result.push(','); + } + + if tactic != DefinitiveTactic::Horizontal { + prev_expr_trailing_comment = !expr.trailing.is_empty(); + + if !expr.different_line && !expr.trailing.is_empty() { + result.push(' '); + } + + result.push_str(&expr.trailing); + } + } + + result +} + +fn wrap_exprs( + prefix: &str, + suffix: &str, + exprs: String, + nested_shape: Shape, + shape: Shape, +) -> String { + let first_line_width = exprs.lines().next().map_or(0, |line| line.chars().count()); + + if first_line_width <= shape.width { + let allow_trailing_newline = exprs + .lines() + .last() + .unwrap_or_default() + .find_token_with(|token| matches!(token, Token::LineComment(_, _))) + .is_some(); + + let trailing_newline = if allow_trailing_newline { + shape.indent.to_string_with_newline() + } else { + String::new() + }; + + format!("{prefix}{exprs}{trailing_newline}{suffix}") } else { - new + let nested_indent_str = nested_shape.indent.to_string_with_newline(); + let indent_str = shape.indent.to_string_with_newline(); + + format!("{prefix}{nested_indent_str}{exprs}{indent_str}{suffix}") } } -fn changed_comment_content(original: &str, new: &str) -> bool { - comments(original) != comments(new) +#[derive(PartialEq, Eq)] +enum Tactic { + Horizontal, + HorizontalVertical, + LimitedHorizontalVertical(usize), + Mixed, } -fn comments(source: &str) -> Vec { - Lexer::new(source) - .skip_comments(false) - .flatten() - .filter_map(|spanned| { - if let Token::LineComment(content) | Token::BlockComment(content) = spanned.into_token() - { - Some(content) +impl Tactic { + fn definitive( + self, + exprs: &[Expr], + short_array_element_width_threshold: usize, + ) -> DefinitiveTactic { + let tactic = || { + let has_single_line_comment = exprs.iter().any(|item| { + has_single_line_comment(&item.leading) || has_single_line_comment(&item.trailing) + }); + + let limit = match self { + _ if has_single_line_comment => return DefinitiveTactic::Vertical, + + Tactic::Horizontal => return DefinitiveTactic::Horizontal, + Tactic::LimitedHorizontalVertical(limit) => limit, + Tactic::HorizontalVertical | Tactic::Mixed => 100, + }; + + let (sep_count, total_width): (usize, usize) = exprs + .iter() + .map(|expr| expr.total_width()) + .fold((0, 0), |(sep_count, total_width), width| { + (sep_count + 1, total_width + width) + }); + + let total_sep_len = sep_count.saturating_sub(1); + let real_total = total_width + total_sep_len; + + if real_total <= limit && !exprs.iter().any(|expr| expr.is_multiline()) { + DefinitiveTactic::Horizontal + } else if self == Tactic::Mixed { + DefinitiveTactic::Mixed } else { - None + DefinitiveTactic::Vertical + } + }; + + tactic().reduce(exprs, short_array_element_width_threshold) + } +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +enum DefinitiveTactic { + Vertical, + Horizontal, + Mixed, +} + +impl DefinitiveTactic { + fn reduce(self, exprs: &[Expr], short_array_element_width_threshold: usize) -> Self { + match self { + DefinitiveTactic::Vertical + if no_long_exprs(exprs, short_array_element_width_threshold) => + { + DefinitiveTactic::Mixed } - }) - .collect() + DefinitiveTactic::Vertical | DefinitiveTactic::Horizontal | DefinitiveTactic::Mixed => { + self + } + } + } +} + +fn has_single_line_comment(slice: &str) -> bool { + slice.trim_start().starts_with("//") +} + +fn no_long_exprs(exprs: &[Expr], max_width: usize) -> bool { + exprs.iter().all(|expr| expr.value.len() <= max_width) +} + +fn extract_simple_expr(expr: Expression) -> Option { + if let ExpressionKind::Block(mut block) = expr.kind { + if block.len() == 1 { + if let StatementKind::Expression(expr) = block.pop().unwrap() { + return expr.into(); + } + } + } + + None } diff --git a/tooling/nargo_fmt/src/visitor/item.rs b/tooling/nargo_fmt/src/visitor/item.rs index 1e32ab22747..09031082fa3 100644 --- a/tooling/nargo_fmt/src/visitor/item.rs +++ b/tooling/nargo_fmt/src/visitor/item.rs @@ -5,7 +5,7 @@ use noirc_frontend::{ impl super::FmtVisitor<'_> { fn format_fn_before_block(&self, func: NoirFunction, start: u32) -> (String, bool) { - let slice = slice!(self, start, func.span().start()); + let slice = self.slice(start..func.span().start()); let force_brace_newline = slice.contains("//"); (slice.trim_end().to_string(), force_brace_newline) } diff --git a/tooling/nargo_fmt/src/visitor/stmt.rs b/tooling/nargo_fmt/src/visitor/stmt.rs index 973167fd19a..0a814ebd136 100644 --- a/tooling/nargo_fmt/src/visitor/stmt.rs +++ b/tooling/nargo_fmt/src/visitor/stmt.rs @@ -1,16 +1,62 @@ -use noirc_frontend::{Statement, StatementKind}; +use std::iter::zip; + +use noirc_frontend::{ConstrainKind, ConstrainStatement, ExpressionKind, Statement, StatementKind}; + +use super::ExpressionType; impl super::FmtVisitor<'_> { pub(crate) fn visit_stmts(&mut self, stmts: Vec) { - for Statement { kind, span } in stmts { + let len = stmts.len(); + + for (Statement { kind, span }, index) in zip(stmts, 1..) { + let is_last = index == len; + match kind { - StatementKind::Expression(expr) => self.visit_expr(expr), + StatementKind::Expression(expr) => self.visit_expr( + expr, + if is_last { ExpressionType::SubExpression } else { ExpressionType::Statement }, + ), StatementKind::Semi(expr) => { - self.visit_expr(expr); + self.visit_expr(expr, ExpressionType::Statement); self.push_str(";"); } + StatementKind::Let(let_stmt) => { + let let_str = + self.slice(span.start()..let_stmt.expression.span.start()).trim_end(); + let expr_str = + self.format_expr(let_stmt.expression, ExpressionType::SubExpression); + + self.push_rewrite(format!("{let_str} {expr_str};"), span); + } + StatementKind::Constrain(ConstrainStatement(expr, message, kind)) => { + let message = + message.map_or(String::new(), |message| format!(", \"{message}\"")); + let constrain = match kind { + ConstrainKind::Assert => { + let assertion = self.format_sub_expr(expr); + + format!("assert({assertion}{message});") + } + ConstrainKind::AssertEq => { + if let ExpressionKind::Infix(infix) = expr.kind { + let lhs = self.format_sub_expr(infix.lhs); + let rhs = self.format_sub_expr(infix.rhs); + + format!("assert_eq({lhs}, {rhs}{message});") + } else { + unreachable!() + } + } + ConstrainKind::Constrain => { + let expr = self.format_sub_expr(expr); + format!("constrain {expr};") + } + }; + + self.push_rewrite(constrain, span); + } + StatementKind::Assign(_) | StatementKind::For(_) => self.format_missing(span.end()), StatementKind::Error => unreachable!(), - _ => self.format_missing(span.end()), } self.last_position = span.end(); diff --git a/tooling/nargo_fmt/tests/expected/add.nr b/tooling/nargo_fmt/tests/expected/add.nr index 6f2892942c1..341ed06f3e6 100644 --- a/tooling/nargo_fmt/tests/expected/add.nr +++ b/tooling/nargo_fmt/tests/expected/add.nr @@ -3,5 +3,5 @@ fn main(mut x: u32, y: u32, z: u32) { assert(x == z); x *= 8; - assert(x>9); + assert(x > 9); } diff --git a/tooling/nargo_fmt/tests/expected/array.nr b/tooling/nargo_fmt/tests/expected/array.nr new file mode 100644 index 00000000000..fdf81d3595c --- /dev/null +++ b/tooling/nargo_fmt/tests/expected/array.nr @@ -0,0 +1,43 @@ +fn big_array() { + [1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, + 10000000000, + 100000000000, + 1000000000000, + 10000000000000, + 100000000000000, + 1000000000000000, + 10000000000000000, + 100000000000000000, + 1000000000000000000, + 10000000000000000000, + 100000000000000000000, + 1000000000000000000000, + 10000000000000000000000, + 100000000000000000000000, + 1000000000000000000000000]; + + [1, 10]; + + [// hello! + 1, 10]; + + [// hello! + 1, // asd + 10]; + + [// hello! + 1, // asd + 10// asdasd + ]; + + [[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]], [[13, 14, 15], [16, 17, 18]]]; +} diff --git a/tooling/nargo_fmt/tests/expected/call.nr b/tooling/nargo_fmt/tests/expected/call.nr index 105a69acedc..8f627ed1223 100644 --- a/tooling/nargo_fmt/tests/expected/call.nr +++ b/tooling/nargo_fmt/tests/expected/call.nr @@ -1,3 +1,31 @@ fn foo() { my_function(10, some_value, another_func(20, 30)); + + outer_function(some_function(), // Original inner function call + another_function() // Original inner function call + ); + + outer_function(some_function(), // Original inner function call + another_function() // Original inner function call + ); + + my_function(// Comment + some_value, + /* Multiline + Comment */ + another_func(20, 30)); + + my_function(some_function(10, "arg1", another_function()), another_func(20, some_function(), 30)); + + outer_function(some_function(), another_function(some_function(), some_value)); + + assert_eq(x, y); + + assert_eq(x, y, "message"); + + assert(x); + + assert(x, "message"); + + assert(x == y); } diff --git a/tooling/nargo_fmt/tests/expected/expr.nr b/tooling/nargo_fmt/tests/expected/expr.nr index 6d4fedba4b3..20eb6ad547d 100644 --- a/tooling/nargo_fmt/tests/expected/expr.nr +++ b/tooling/nargo_fmt/tests/expected/expr.nr @@ -79,3 +79,44 @@ fn parenthesized() { fn parenthesized() { (i as u8) + (j as u8) + (k as u8) + x + y + z } + +fn parenthesized() { + value + (/*test*/x as Field/*test*/) +} + +fn parenthesized() { + value + ( + // line + x as Field + ) +} + +fn constructor() { + Point { x: 5, y: 10 }; +} + +fn if_expr() { + if true { + println("Hello :D"); + } +} + +fn return_if_expr() { + if true { 42 } else { 40 + 2 } +} + +fn return_if_expr() { + if true { + 42 + }; + + if true { 42 } else { 40 + 2 } +} + +fn if_if() { + if cond { + some(); + } else { + none(); + }.bar().baz(); +} diff --git a/tooling/nargo_fmt/tests/expected/if.nr b/tooling/nargo_fmt/tests/expected/if.nr new file mode 100644 index 00000000000..9893239750c --- /dev/null +++ b/tooling/nargo_fmt/tests/expected/if.nr @@ -0,0 +1,40 @@ +fn main() { + if false { + (); + (); + } + + if false // lone if comment + { + (); + (); + } + + let a = if 0 > 1 { 0 } else { 0 }; + + if true { + (); + } else if false { + (); + (); + } else { + (); + (); + (); + } + + if true // else-if-chain if comment + { + (); + } + else if false // else-if-chain else-if comment + { + (); + (); + } else // else-if-chain else comment + { + (); + (); + (); + } +} diff --git a/tooling/nargo_fmt/tests/expected/index.nr b/tooling/nargo_fmt/tests/expected/index.nr index 79430e5c0e6..54f2ed2cf39 100644 --- a/tooling/nargo_fmt/tests/expected/index.nr +++ b/tooling/nargo_fmt/tests/expected/index.nr @@ -2,4 +2,8 @@ fn foo() { let arr = [10, 20, 30, 40]; arr[2]; arr[2]; + arr[/*test*/ 2]; + arr[2/*test*/]; + arr[// test + 2]; } diff --git a/tooling/nargo_fmt/tests/expected/let.nr b/tooling/nargo_fmt/tests/expected/let.nr new file mode 100644 index 00000000000..dccdb76328c --- /dev/null +++ b/tooling/nargo_fmt/tests/expected/let.nr @@ -0,0 +1,58 @@ +fn let_() { + let fn_call = my_function(some_function(10, "arg1", another_function()), another_func(20, some_function(), 30)); + let array = [[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]], [[13, 14, 15], [16, 17, 18]]]; + + let padded_sha256_hash: [u8; 259] = [// Padded hash + 209, 50, 135, 178, 4, 155, 190, 229, 228, 111, 61, 174, 8, 49, 48, 116, 90, 226, 77, 7, 111, + 27, 19, 113, 154, 48, 138, 136, 138, 15, 230, 132, 32, 4, 0, 5, 1, 2, 4, 3, 101, 1, 72, 134, + 96, 9, 6, 13, 48, 49, 48, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 1, 0, + // Rest is padded with 0s until max bytes + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0]; + + let a = BigUint56 { + limbs: [ + 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + ] + }; + + let person = Person { + first_name: "John", + last_name: "Doe", + home_address: Address { street: "123 Main St", city: "Exampleville", zip_code: "12345" } + }; + + let person = Person { + first_name: "John", + last_name: "Doe", + home_address: Address { + street: "123 Main St", + city: "Exampleville", + zip_code: "12345", + master: Person { + first_name: "John", + last_name: "Doe", + home_address: Address { street: "123 Main St", city: "Exampleville", zip_code: "12345" } + } + } + }; + + let expr = Expr { + // A boolean literal (true, false). + kind: ExprKind::Bool(true) + }; + + let expr = Expr { /*A boolean literal (true, false).*/ kind: ExprKind::Bool(true) }; + + let mut V = dep::crate2::MyStruct { Q: x }; + let mut V = dep::crate2::MyStruct {}; + let mut V = dep::crate2::MyStruct {/*test*/}; + let mut V = dep::crate2::MyStruct { + // sad + }; +} diff --git a/tooling/nargo_fmt/tests/expected/literals.nr b/tooling/nargo_fmt/tests/expected/literals.nr index 44a74a5db68..abe14c14965 100644 --- a/tooling/nargo_fmt/tests/expected/literals.nr +++ b/tooling/nargo_fmt/tests/expected/literals.nr @@ -5,9 +5,19 @@ fn main() { [0xff; 5]; + [0 as u8; MAX_BYTES]; + true; "hello world"; + "hell\0\"world"; + + f"i: {i}, j: {j}"; + + (); + + (/*test*/); + () } diff --git a/tooling/nargo_fmt/tests/expected/nested_if_else.nr b/tooling/nargo_fmt/tests/expected/nested_if_else.nr index 8aa120e3b18..dfd203189e8 100644 --- a/tooling/nargo_fmt/tests/expected/nested_if_else.nr +++ b/tooling/nargo_fmt/tests/expected/nested_if_else.nr @@ -1,3 +1,9 @@ fn nested_if_else() { - if false { 1 } else if false { 2 } else { 3 } + if false { + 1 + } else if false { + 2 + } else { + 3 + } } diff --git a/tooling/nargo_fmt/tests/expected/struct.nr b/tooling/nargo_fmt/tests/expected/struct.nr index 5e3530e8364..6734dec68a6 100644 --- a/tooling/nargo_fmt/tests/expected/struct.nr +++ b/tooling/nargo_fmt/tests/expected/struct.nr @@ -34,11 +34,7 @@ struct MyStruct { my_nest: Nested, } fn test_struct_in_tuple(a_bool : bool,x:Field, y:Field) -> (MyStruct, bool) { - let my_struct = MyStruct { - my_bool: a_bool, - my_int: 5, - my_nest: Nested{a:x,b:y}, - }; + let my_struct = MyStruct { my_bool: a_bool, my_int: 5, my_nest: Nested { a: x, b: y } }; (my_struct, a_bool) } @@ -53,7 +49,7 @@ fn get_dog() -> Animal { } fn main(x: Field, y: Field) { - let first = Foo::default(x,y); + let first = Foo::default(x, y); let p = Pair { first, second: 1 }; assert(p.bar() == x); @@ -61,7 +57,7 @@ fn main(x: Field, y: Field) { assert(p.first.array[0] != p.first.array[1]); // Nested structs - let (struct_from_tuple, a_bool) = test_struct_in_tuple(true,x,y); + let (struct_from_tuple, a_bool) = test_struct_in_tuple(true, x, y); assert(struct_from_tuple.my_bool == true); assert(a_bool == true); assert(struct_from_tuple.my_int == 5); diff --git a/tooling/nargo_fmt/tests/expected/tuple.nr b/tooling/nargo_fmt/tests/expected/tuple.nr new file mode 100644 index 00000000000..b190a5f7c55 --- /dev/null +++ b/tooling/nargo_fmt/tests/expected/tuple.nr @@ -0,0 +1,32 @@ +fn main() { + (1,); + (// hello + 1,); + (/*hello*/ 1,); + (1/*hello*/,); + (1,); + (/*test*/ 1,); + (/*a*/ 1/*b*/,); + (/*a*/ 1/*b*/, /*c*/ 2/*d*/, /*c*/ 2/*d*/); + (/*a*/ 1/*b*/, /*c*/ 2/*d*/, /*c*/ 2/*d*/, /*e*/ 3/*f*/); + + (1/*1*/, 2/* 2*/); + + (1/*test*/,); + + (// + 1,); + + (// 1 + 1, // 2, + 2); + + (/*1*/ 1, /*2*/ 2); + +// FIXME: + (((//2 + 1,),),); + (/*a*/ + 1/*b*/, +/*c*/ 2/*d*/, /*c*/ 2/*d*/, /*e*/ 3/*f*/); +} diff --git a/tooling/nargo_fmt/tests/input/array.nr b/tooling/nargo_fmt/tests/input/array.nr new file mode 100644 index 00000000000..73651ef76bd --- /dev/null +++ b/tooling/nargo_fmt/tests/input/array.nr @@ -0,0 +1,39 @@ +fn big_array() { + [ + 1,10,100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000, 100000000000, 1000000000000, 10000000000000, 100000000000000, 1000000000000000, 10000000000000000, 100000000000000000, 1000000000000000000, + 10000000000000000000, + 100000000000000000000, + 1000000000000000000000, + 10000000000000000000000, + 100000000000000000000000, + 1000000000000000000000000, + ]; + + [ + 1, + 10, + ]; + + [ +// hello! +1, +10, + ]; + + [ +// hello! +1, +// asd +10, + ]; + + [ +// hello! +1, +// asd +10, +// asdasd + ]; + + [[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]], [[13, 14, 15], [16, 17, 18]]]; +} diff --git a/tooling/nargo_fmt/tests/input/call.nr b/tooling/nargo_fmt/tests/input/call.nr index 93d2597a05c..24e61c806cc 100644 --- a/tooling/nargo_fmt/tests/input/call.nr +++ b/tooling/nargo_fmt/tests/input/call.nr @@ -1,3 +1,45 @@ fn foo() { my_function( 10,some_value,another_func( 20 , 30) ); + + outer_function(some_function(), // Original inner function call + another_function(), // Original inner function call + ); + + outer_function( + + + some_function(), // Original inner function call + another_function(), // Original inner function call + ); + + my_function( + // Comment + some_value, + /* Multiline + Comment */ + another_func( 20, 30 ) + ); + + my_function( + some_function( 10, "arg1", another_function() ), + another_func (20, some_function() , 30 ) + ); + + outer_function( + some_function(), + + + another_function( + some_function(), some_value) + ); + + assert_eq( x, y ); + + assert_eq( x, y, "message" ); + + assert( x ); + + assert( x, "message" ); + + assert( x == y ); } diff --git a/tooling/nargo_fmt/tests/input/expr.nr b/tooling/nargo_fmt/tests/input/expr.nr index 25602c640d3..28ba9cb0585 100644 --- a/tooling/nargo_fmt/tests/input/expr.nr +++ b/tooling/nargo_fmt/tests/input/expr.nr @@ -88,3 +88,48 @@ fn parenthesized() { fn parenthesized() { ( i as u8 ) + ( j as u8 ) + ( k as u8 ) + x + y + z } + +fn parenthesized() { + value + ( /*test*/x as Field /*test*/ ) +} + +fn parenthesized() { + value + ( +// line + x as Field + ) +} + +fn constructor() { + Point{x :5, + y: 10 }; +} + +fn if_expr() { + if true { println("Hello :D"); } +} + +fn return_if_expr() { + if true { +42 +} +else +{ 40 + 2 } +} + +fn return_if_expr() { + if true {42}; + + if true { + 42 + } + else { + 40 + + 2 } +} + +fn if_if() { +if cond { some(); } else { none(); } + .bar() + .baz(); +} \ No newline at end of file diff --git a/tooling/nargo_fmt/tests/input/if.nr b/tooling/nargo_fmt/tests/input/if.nr new file mode 100644 index 00000000000..0985928396d --- /dev/null +++ b/tooling/nargo_fmt/tests/input/if.nr @@ -0,0 +1,52 @@ +fn main() { + if false + { + (); + (); + } + + if false // lone if comment + { + (); + (); + } + + + let a = + if 0 > 1 { + 0 + } + else + { + 0 + }; + + + if true + { + (); + } else if false { + (); + (); + } + else { + (); + (); + (); + } + + if true // else-if-chain if comment + { + (); + } + else if false // else-if-chain else-if comment + { + (); + (); + } else // else-if-chain else comment + { + (); + (); + (); + } +} diff --git a/tooling/nargo_fmt/tests/input/index.nr b/tooling/nargo_fmt/tests/input/index.nr index e1c6fed02c1..7d10e897b8d 100644 --- a/tooling/nargo_fmt/tests/input/index.nr +++ b/tooling/nargo_fmt/tests/input/index.nr @@ -2,4 +2,9 @@ fn foo() { let arr = [10, 20, 30, 40]; arr [2]; arr [2]; + arr [/*test*/2]; + arr [2/*test*/]; + arr [ + // test + 2]; } \ No newline at end of file diff --git a/tooling/nargo_fmt/tests/input/let.nr b/tooling/nargo_fmt/tests/input/let.nr new file mode 100644 index 00000000000..ae23f0150d9 --- /dev/null +++ b/tooling/nargo_fmt/tests/input/let.nr @@ -0,0 +1,34 @@ +fn let_() { + let fn_call = my_function(some_function( 10, "arg1", another_function() ),another_func (20, some_function() , 30 )); + let array = [[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]], [[13, 14, 15], [16, 17, 18]]]; + + let padded_sha256_hash: [u8; 259] = [ + // Padded hash + 209, 50, 135, 178, 4, 155, 190, 229, 228, 111, 61, 174, 8, 49, 48, 116, 90, 226, 77, 7, 111, 27, 19, 113, 154, 48, 138, 136, 138, 15, 230, 132, 32, 4, 0, 5, 1, 2, 4, 3, 101, 1, 72, 134, 96, 9, 6, 13, 48, 49, + 48, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 1, 0, + // Rest is padded with 0s until max bytes + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + ]; + + let a = BigUint56 {limbs:[1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]}; + + let person = Person { first_name: "John", last_name: "Doe", home_address: Address { street: "123 Main St", city: "Exampleville", zip_code: "12345" } }; + + let person = Person { first_name: "John", last_name: "Doe", home_address: Address { street: "123 Main St", city: "Exampleville", zip_code: "12345", master: Person { first_name: "John", last_name: "Doe", home_address: Address { street: "123 Main St", city: "Exampleville", zip_code: "12345" } } } }; + + let expr = Expr {// A boolean literal (true, false). +kind: ExprKind::Bool(true), + }; + + let expr = Expr {/*A boolean literal (true, false).*/kind: ExprKind::Bool(true),}; + + let mut V = dep::crate2::MyStruct { Q: x }; + let mut V = dep::crate2::MyStruct {}; + let mut V = dep::crate2::MyStruct {/*test*/}; + let mut V = dep::crate2::MyStruct { + // sad + }; +} diff --git a/tooling/nargo_fmt/tests/input/literals.nr b/tooling/nargo_fmt/tests/input/literals.nr index 5ca6af41a13..3490c1e7d0d 100644 --- a/tooling/nargo_fmt/tests/input/literals.nr +++ b/tooling/nargo_fmt/tests/input/literals.nr @@ -7,9 +7,19 @@ fn main() { [0xff;5]; + [0 as u8; MAX_BYTES]; + true; "hello world"; + "hell\0\"world"; + + f"i: {i}, j: {j}"; + + ( ); + + (/*test*/); + () } diff --git a/tooling/nargo_fmt/tests/input/tuple.nr b/tooling/nargo_fmt/tests/input/tuple.nr new file mode 100644 index 00000000000..da3b6ed597b --- /dev/null +++ b/tooling/nargo_fmt/tests/input/tuple.nr @@ -0,0 +1,48 @@ +fn main() { +(1,); +( +// hello +1,); +(/*hello*/1,); +(1,/*hello*/); + ( 1, ); +( /*test*/1, ); +( /*a*/1/*b*/, ); +( /*a*/1/*b*/, /*c*/2/*d*/, /*c*/2/*d*/ ); +( /*a*/1/*b*/, /*c*/2/*d*/, /*c*/2/*d*/, /*e*/3/*f*/ ); + +( 1 /*1*/ , 2 /* 2*/ ); + + + + +( 1, /*test*/ ); + + ( +// +1, +); + +( +// 1 +1, +// 2, +2, +); + +(/*1*/1, /*2*/2); + +// FIXME: +((( +//2 +1,),),); +( + /*a*/ + 1 + /*b*/, +/*c*/ +2/*d*/, +/*c*/2/*d*/, +/*e*/3/*f*/ +); +} diff --git a/tooling/noir_js/package.json b/tooling/noir_js/package.json index 3f17a1a44b2..09dfac939d2 100644 --- a/tooling/noir_js/package.json +++ b/tooling/noir_js/package.json @@ -3,7 +3,7 @@ "collaborators": [ "The Noir Team " ], - "version": "0.16.0", + "version": "0.18.0", "packageManager": "yarn@3.5.1", "license": "(MIT OR Apache-2.0)", "type": "module", diff --git a/tooling/noir_js_backend_barretenberg/package.json b/tooling/noir_js_backend_barretenberg/package.json index afc0a75d19e..3dbfb52a7f8 100644 --- a/tooling/noir_js_backend_barretenberg/package.json +++ b/tooling/noir_js_backend_barretenberg/package.json @@ -3,7 +3,7 @@ "collaborators": [ "The Noir Team " ], - "version": "0.7.10", + "version": "0.18.0", "packageManager": "yarn@3.5.1", "license": "(MIT OR Apache-2.0)", "type": "module", @@ -32,7 +32,7 @@ "lint": "NODE_NO_WARNINGS=1 eslint . --ext .ts --ignore-path ./.eslintignore --max-warnings 0" }, "dependencies": { - "@aztec/bb.js": "0.8.10", + "@aztec/bb.js": "0.11.0", "@noir-lang/types": "workspace:*", "fflate": "^0.8.0" }, diff --git a/tooling/noir_js_types/package.json b/tooling/noir_js_types/package.json index 547a6f9faf4..06f7ce41d1f 100644 --- a/tooling/noir_js_types/package.json +++ b/tooling/noir_js_types/package.json @@ -4,7 +4,7 @@ "The Noir Team " ], "packageManager": "yarn@3.5.1", - "version": "0.16.0", + "version": "0.18.0", "license": "(MIT OR Apache-2.0)", "files": [ "lib", diff --git a/tooling/noirc_abi/src/lib.rs b/tooling/noirc_abi/src/lib.rs index d5c2314b3a6..9753dc21f14 100644 --- a/tooling/noirc_abi/src/lib.rs +++ b/tooling/noirc_abi/src/lib.rs @@ -158,6 +158,7 @@ impl AbiType { Type::Error => unreachable!(), Type::Unit => unreachable!(), Type::Constant(_) => unreachable!(), + Type::TraitAsType(_) => unreachable!(), Type::Struct(def, ref args) => { let struct_type = def.borrow(); let fields = struct_type.get_fields(args); diff --git a/tooling/noirc_abi_wasm/package.json b/tooling/noirc_abi_wasm/package.json index 7dc2858cd57..f98340f7131 100644 --- a/tooling/noirc_abi_wasm/package.json +++ b/tooling/noirc_abi_wasm/package.json @@ -3,7 +3,7 @@ "collaborators": [ "The Noir Team " ], - "version": "0.16.0", + "version": "0.18.0", "license": "(MIT OR Apache-2.0)", "files": [ "nodejs", diff --git a/yarn.lock b/yarn.lock index 71338f8f3a3..fa4a28d9988 100644 --- a/yarn.lock +++ b/yarn.lock @@ -221,9 +221,9 @@ __metadata: languageName: node linkType: hard -"@aztec/bb.js@npm:0.8.10": - version: 0.8.10 - resolution: "@aztec/bb.js@npm:0.8.10" +"@aztec/bb.js@npm:0.11.0": + version: 0.11.0 + resolution: "@aztec/bb.js@npm:0.11.0" dependencies: comlink: ^4.4.1 commander: ^10.0.1 @@ -231,7 +231,7 @@ __metadata: tslib: ^2.4.0 bin: bb.js: dest/node/main.js - checksum: c77f6e27f626edca1477e4d94794d43b373dfcb527f00579e20270fc92794f9e4bc5df2c25ebbce564700c114cdf69e0b213ddb0192c24af4fc4cdf468918702 + checksum: fff6813458dfa654210859dbf32abcb6c520ef8b3c4896535afa1bbc4a1a6dc77fd5626051fe0017de2f4b03d09bd9629fa1a144df2af3270a2e00faa779362d languageName: node linkType: hard @@ -3434,7 +3434,7 @@ __metadata: version: 0.0.0-use.local resolution: "@noir-lang/backend_barretenberg@workspace:tooling/noir_js_backend_barretenberg" dependencies: - "@aztec/bb.js": 0.8.10 + "@aztec/bb.js": 0.11.0 "@noir-lang/types": "workspace:*" "@types/node": ^20.6.2 "@types/prettier": ^3