diff --git a/avm-transpiler/Cargo.lock b/avm-transpiler/Cargo.lock index b571e5ffbd4..a6289ae924e 100644 --- a/avm-transpiler/Cargo.lock +++ b/avm-transpiler/Cargo.lock @@ -760,6 +760,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + [[package]] name = "flate2" version = "1.0.28" @@ -1086,6 +1092,7 @@ dependencies = [ "noirc_errors", "noirc_evaluator", "noirc_frontend", + "noirc_macros", "rust-embed", "serde", "tracing", @@ -1102,6 +1109,7 @@ dependencies = [ "codespan-reporting", "flate2", "fm", + "noirc_printable_type", "serde", "serde_json", "serde_with", @@ -1135,6 +1143,7 @@ dependencies = [ "iter-extended", "noirc_errors", "noirc_printable_type", + "petgraph", "regex", "rustc-hash", "serde", @@ -1145,6 +1154,14 @@ dependencies = [ "tracing", ] +[[package]] +name = "noirc_macros" +version = "0.23.0" +dependencies = [ + "iter-extended", + "noirc_frontend", +] + [[package]] name = "noirc_printable_type" version = "0.23.0" @@ -1211,6 +1228,16 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +[[package]] +name = "petgraph" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +dependencies = [ + "fixedbitset", + "indexmap 2.2.1", +] + [[package]] name = "pin-project-lite" version = "0.2.13" diff --git a/build-system/scripts/request_spot b/build-system/scripts/request_spot index 3d669fed1df..6c4e1d1bb2d 100755 --- a/build-system/scripts/request_spot +++ b/build-system/scripts/request_spot @@ -57,7 +57,7 @@ launch_spec=$(cat <> $GITHUB_ENV - name: Cache playwright binaries - uses: actions/cache@v3 + uses: actions/cache@v4 id: playwright-cache with: path: | diff --git a/noir/.github/actions/nix/action.yml b/noir/.github/actions/nix/action.yml deleted file mode 100644 index 9f008ad0f9d..00000000000 --- a/noir/.github/actions/nix/action.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: Setup Nix -description: Installs and setups Nix components - -inputs: - github-token: - description: 'Github Access Token' - required: true - nix-cache-name: - description: 'Name of the Cachix cache to use' - required: true - cachix-auth-token: - description: 'Cachix Auth Token' - required: true - - -runs: - using: composite - steps: - - uses: cachix/install-nix-action@v22 - with: - nix_path: nixpkgs=channel:nixos-23.05 - github_access_token: ${{ inputs.github-token }} - - - uses: cachix/cachix-action@v12 - with: - name: ${{ inputs.nix-cache-name }} - authToken: ${{ inputs.cachix-auth-token }} diff --git a/noir/.github/scripts/integration-test.sh b/noir/.github/scripts/integration-test-browser.sh similarity index 52% rename from noir/.github/scripts/integration-test.sh rename to noir/.github/scripts/integration-test-browser.sh index 4e1b52cedf9..2ace2723a20 100755 --- a/noir/.github/scripts/integration-test.sh +++ b/noir/.github/scripts/integration-test-browser.sh @@ -1,6 +1,5 @@ #!/bin/bash set -eu -apt-get install libc++-dev -y npx playwright install && npx playwright install-deps -yarn workspace integration-tests test \ No newline at end of file +yarn workspace integration-tests test diff --git a/noir/.github/scripts/integration-test-node.sh b/noir/.github/scripts/integration-test-node.sh new file mode 100755 index 00000000000..7260ca4bb0f --- /dev/null +++ b/noir/.github/scripts/integration-test-node.sh @@ -0,0 +1,5 @@ +#!/bin/bash +set -eu + +apt-get install libc++-dev -y +yarn workspace integration-tests test diff --git a/noir/.github/scripts/noir-js-test.sh b/noir/.github/scripts/noir-js-test.sh index b5fe34038fe..72458d8de6a 100755 --- a/noir/.github/scripts/noir-js-test.sh +++ b/noir/.github/scripts/noir-js-test.sh @@ -1,6 +1,4 @@ #!/bin/bash set -eu -./scripts/nargo_compile_noir_js_assert_lt.sh -rm -rf /usr/src/noir/tooling/noir_js/test/noir_compiled_examples/assert_lt/target/debug_assert_lt.json -yarn workspace @noir-lang/noir_js test \ No newline at end of file +yarn workspace @noir-lang/noir_js test diff --git a/noir/.github/workflows/docker-test-flow.yml b/noir/.github/workflows/docker-test-flow.yml index 4b4a2ac2add..f9f4815dd3d 100644 --- a/noir/.github/workflows/docker-test-flow.yml +++ b/noir/.github/workflows/docker-test-flow.yml @@ -720,7 +720,63 @@ jobs: - name: Test working-directory: /usr/src/noir run: | - ./.github/scripts/integration-test.sh + ./.github/scripts/integration-test-node.sh + + test-integration-browser: + name: Integration test browser + runs-on: ubuntu-latest + needs: [ + build-base-js, + build-noir-wasm, + build-noirc-abi, + build-acvm_js, + build-noir-js-types, + build-noir_js, + build-barretenberg-backend + ] + container: + image: ghcr.io/noir-lang/noir:${{ github.sha }}-js + credentials: + username: ${{ github.actor }} + password: ${{ secrets.github_token }} + steps: + - name: Download noir wasm + uses: actions/download-artifact@v4 + with: + name: noir_wasm + path: /usr/src/noir/compiler/wasm + - name: Download noirc abi + uses: actions/download-artifact@v4 + with: + name: noirc_abi_wasm + path: /usr/src/noir/tooling/noirc_abi_wasm + - name: Download acvm js + uses: actions/download-artifact@v4 + with: + name: acvm_js + path: /usr/src/noir/acvm-repo/acvm_js + - name: Download noir js types + uses: actions/download-artifact@v4 + with: + name: noir-js-types + path: | + /usr/src/noir/tooling/noir_js_types/lib + - name: Download noir js + uses: actions/download-artifact@v4 + with: + name: noir_js + path: + /usr/src/noir/tooling/noir_js/lib + - name: Download Barretenberg backend + uses: actions/download-artifact@v4 + with: + name: barretenberg-backend + path: + /usr/src/noir/tooling/noir_js_backend_barretenberg/lib + - name: Test + working-directory: /usr/src/noir + run: | + ./.github/scripts/integration-test-browser.sh tests-end: name: End @@ -733,6 +789,7 @@ jobs: - test-noir-wasm - test-noir-wasm-browser - test-integration + - test-integration-browser - test-noir_codegen - test-acvm_js - test-acvm_js-browser diff --git a/noir/.github/workflows/docs-pr.yml b/noir/.github/workflows/docs-pr.yml index 87bec37c438..3cdca177a20 100644 --- a/noir/.github/workflows/docs-pr.yml +++ b/noir/.github/workflows/docs-pr.yml @@ -53,6 +53,14 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 + + - name: Setup toolchain + uses: dtolnay/rust-toolchain@1.71.1 + + - uses: Swatinem/rust-cache@v2 + with: + key: x86_64-unknown-linux-gnu + save-if: false - name: Setup toolchain uses: dtolnay/rust-toolchain@1.71.1 @@ -80,7 +88,7 @@ jobs: yarn workspaces foreach -Rpt --from docs run build - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: docs path: ./docs/build/ @@ -98,7 +106,7 @@ jobs: uses: actions/checkout@v4 - name: Download built docs - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: docs path: ./docs/build diff --git a/noir/.github/workflows/gates_report.yml b/noir/.github/workflows/gates_report.yml index 8e3ef768828..39416e628a9 100644 --- a/noir/.github/workflows/gates_report.yml +++ b/noir/.github/workflows/gates_report.yml @@ -36,7 +36,7 @@ jobs: 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 + uses: actions/upload-artifact@v4 with: name: nargo path: ./dist/* @@ -53,7 +53,7 @@ jobs: - uses: actions/checkout@v4 - name: Download nargo binary - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: nargo path: ./nargo diff --git a/noir/.github/workflows/publish-es-packages.yml b/noir/.github/workflows/publish-es-packages.yml index 2c825ffd45f..231a6124785 100644 --- a/noir/.github/workflows/publish-es-packages.yml +++ b/noir/.github/workflows/publish-es-packages.yml @@ -18,31 +18,31 @@ jobs: build-noirc_abi_wasm: runs-on: ubuntu-latest steps: - - name: Checkout sources + - name: Checkout Noir repo uses: actions/checkout@v4 - with: - ref: ${{ inputs.noir-ref }} - - name: Setup Nix - uses: ./.github/actions/nix + - name: Setup toolchain + uses: dtolnay/rust-toolchain@1.71.1 + + - uses: Swatinem/rust-cache@v2 with: - github-token: ${{ secrets.GITHUB_TOKEN }} - nix-cache-name: "noir" - cachix-auth-token: ${{ secrets.CACHIXAUTHTOKEN }} + key: noirc-abi + save-if: false - - name: Build wasm package - run: | - nix build -L .#noirc_abi_wasm + - name: Install Yarn dependencies + uses: ./.github/actions/setup - - uses: actions/upload-artifact@v3 + - name: Build noirc_abi + run: ./.github/scripts/noirc-abi-build.sh + + - name: Upload artifact + uses: actions/upload-artifact@v4 with: name: noirc_abi_wasm - path: | - result/noirc_abi_wasm/nodejs - result/noirc_abi_wasm/web + path: ./tooling/noirc_abi_wasm/outputs/out/noirc_abi_wasm + retention-days: 10 build-noir_wasm: - needs: [build-noirc_abi_wasm] runs-on: ubuntu-latest steps: - name: Checkout sources @@ -58,20 +58,17 @@ jobs: key: noir-wasm save-if: false - - name: Download noirc_abi_wasm package artifact - uses: actions/download-artifact@v3 - with: - name: noirc_abi_wasm - path: ./tooling/noirc_abi_wasm - - name: Install Yarn dependencies uses: ./.github/actions/setup + - name: Build noir_js_types + run: yarn workspace @noir-lang/types build + - name: Build noir_wasm - run: yarn workspace @noir-lang/noir_wasm build + run: ./.github/scripts/noir-wasm-build.sh - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: noir_wasm path: | @@ -84,26 +81,27 @@ jobs: steps: - name: Checkout sources uses: actions/checkout@v4 - with: - ref: ${{ inputs.noir-ref }} - - name: Setup Nix - uses: ./.github/actions/nix + - name: Setup toolchain + uses: dtolnay/rust-toolchain@1.71.1 + + - uses: Swatinem/rust-cache@v2 with: - github-token: ${{ secrets.GITHUB_TOKEN }} - nix-cache-name: "noir" - cachix-auth-token: ${{ secrets.CACHIXAUTHTOKEN }} + key: acvm-js + save-if: false - - name: Build wasm package - run: | - nix build -L .#acvm_js + - name: Install Yarn dependencies + uses: ./.github/actions/setup + + - name: Build acvm_js + run: ./.github/scripts/acvm_js-build.sh - - uses: actions/upload-artifact@v3 + - name: Upload artifact + uses: actions/upload-artifact@v4 with: - name: acvm_js - path: | - result/acvm_js/nodejs - result/acvm_js/web + name: acvm-js + path: ./acvm-repo/acvm_js/outputs/out/acvm_js + retention-days: 3 publish-es-packages: runs-on: ubuntu-latest @@ -114,17 +112,17 @@ jobs: with: ref: ${{ inputs.noir-ref }} - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: acvm_js path: acvm-repo/acvm_js - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: noir_wasm path: compiler/wasm - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: noirc_abi_wasm path: tooling/noirc_abi_wasm diff --git a/noir/.github/workflows/publish-nargo.yml b/noir/.github/workflows/publish-nargo.yml index fc089008657..085ab013e4e 100644 --- a/noir/.github/workflows/publish-nargo.yml +++ b/noir/.github/workflows/publish-nargo.yml @@ -67,7 +67,7 @@ jobs: 7z a -ttar -so -an ./dist/* | 7z a -si ./nargo-${{ matrix.target }}.tar.gz - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: nargo-${{ matrix.target }} path: ./dist/* @@ -145,7 +145,7 @@ jobs: 7z a -ttar -so -an ./dist/* | 7z a -si ./nargo-${{ matrix.target }}.tar.gz - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: nargo-${{ matrix.target }} path: ./dist/* diff --git a/noir/.github/workflows/test-js-packages.yml b/noir/.github/workflows/test-js-packages.yml index addc9ce3d83..15ed303450f 100644 --- a/noir/.github/workflows/test-js-packages.yml +++ b/noir/.github/workflows/test-js-packages.yml @@ -40,19 +40,18 @@ jobs: 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 + uses: actions/upload-artifact@v4 with: name: nargo path: ./dist/* retention-days: 3 - build-noir-wasm: - needs: [build-noirc-abi] + build-noirc-abi: runs-on: ubuntu-latest timeout-minutes: 30 steps: - - name: Checkout sources + - name: Checkout Noir repo uses: actions/checkout@v4 - name: Setup toolchain @@ -60,32 +59,25 @@ jobs: - uses: Swatinem/rust-cache@v2 with: - key: noir-wasm + key: noirc-abi cache-on-failure: true save-if: ${{ github.event_name != 'merge_group' }} - - name: Download noirc_abi_wasm package artifact - uses: actions/download-artifact@v3 - with: - name: noirc_abi_wasm - path: ./tooling/noirc_abi_wasm - - name: Install Yarn dependencies uses: ./.github/actions/setup - - name: Build noir_wasm - run: yarn workspace @noir-lang/noir_wasm build + - name: Build noirc_abi + run: ./.github/scripts/noirc-abi-build.sh - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: noir_wasm - path: | - ./compiler/wasm/dist - ./compiler/wasm/build - retention-days: 3 + name: noirc_abi_wasm + path: ./tooling/noirc_abi_wasm/outputs/out/noirc_abi_wasm + retention-days: 10 - build-acvm-js: + + build-noir-wasm: runs-on: ubuntu-latest timeout-minutes: 30 @@ -93,55 +85,62 @@ jobs: - name: Checkout sources uses: actions/checkout@v4 - - name: Setup Nix - uses: ./.github/actions/nix + - name: Setup toolchain + uses: dtolnay/rust-toolchain@1.71.1 + + - uses: Swatinem/rust-cache@v2 with: - github-token: ${{ secrets.GITHUB_TOKEN }} - nix-cache-name: "noir" - cachix-auth-token: ${{ secrets.CACHIXAUTHTOKEN }} + key: noir-wasm + cache-on-failure: true + save-if: ${{ github.event_name != 'merge_group' }} - - name: Build acvm-js - run: | - nix build -L .#acvm_js + - name: Install Yarn dependencies + uses: ./.github/actions/setup - - name: Dereference symlink - run: echo "UPLOAD_PATH=$(readlink -f result/acvm_js)" >> $GITHUB_ENV + - name: Build noir_js_types + run: yarn workspace @noir-lang/types build + + - name: Build noir_wasm + run: ./.github/scripts/noir-wasm-build.sh - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: acvm-js - path: ${{ env.UPLOAD_PATH }} + name: noir_wasm + path: | + ./compiler/wasm/dist + ./compiler/wasm/build retention-days: 3 - build-noirc-abi: + build-acvm-js: runs-on: ubuntu-latest timeout-minutes: 30 steps: - name: Checkout sources - uses: actions/checkout@v3 + uses: actions/checkout@v4 - - name: Setup Nix - uses: ./.github/actions/nix + - name: Setup toolchain + uses: dtolnay/rust-toolchain@1.71.1 + + - uses: Swatinem/rust-cache@v2 with: - github-token: ${{ secrets.GITHUB_TOKEN }} - nix-cache-name: "noir" - cachix-auth-token: ${{ secrets.CACHIXAUTHTOKEN }} + key: acvm-js + cache-on-failure: true + save-if: ${{ github.event_name != 'merge_group' }} - - name: Build noirc_abi_wasm - run: | - nix build -L .#noirc_abi_wasm + - name: Install Yarn dependencies + uses: ./.github/actions/setup - - name: Dereference symlink - run: echo "UPLOAD_PATH=$(readlink -f ./result/noirc_abi_wasm)" >> $GITHUB_ENV + - name: Build acvm_js + run: ./.github/scripts/acvm_js-build.sh - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: noirc_abi_wasm - path: ${{ env.UPLOAD_PATH }} - retention-days: 10 + name: acvm-js + path: ./acvm-repo/acvm_js/outputs/out/acvm_js + retention-days: 3 test-acvm_js-node: needs: [build-acvm-js] @@ -154,7 +153,7 @@ jobs: uses: actions/checkout@v4 - name: Download artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: acvm-js path: ./acvm-repo/acvm_js @@ -176,7 +175,7 @@ jobs: uses: actions/checkout@v4 - name: Download artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: acvm-js path: ./acvm-repo/acvm_js @@ -200,10 +199,10 @@ jobs: steps: - name: Checkout sources - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Download wasm package artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: noirc_abi_wasm path: ./tooling/noirc_abi_wasm @@ -231,7 +230,7 @@ jobs: uses: actions/checkout@v4 - name: Download wasm package artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: noirc_abi_wasm path: ./tooling/noirc_abi_wasm @@ -247,7 +246,7 @@ jobs: yarn workspace @noir-lang/backend_barretenberg test test-noir-js: - needs: [build-acvm-js, build-noirc-abi] + needs: [build-nargo, build-acvm-js, build-noirc-abi] name: Noir JS runs-on: ubuntu-latest timeout-minutes: 30 @@ -256,18 +255,32 @@ jobs: - name: Checkout uses: actions/checkout@v4 + - name: Download nargo binary + uses: actions/download-artifact@v4 + with: + name: nargo + path: ./nargo + - name: Download artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: acvm-js path: ./acvm-repo/acvm_js - name: Download wasm package artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: noirc_abi_wasm path: ./tooling/noirc_abi_wasm + - 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: Install Yarn dependencies uses: ./.github/actions/setup @@ -293,7 +306,7 @@ jobs: uses: actions/checkout@v4 - name: Download wasm package artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: noir_wasm path: ./compiler/wasm @@ -302,7 +315,7 @@ jobs: uses: ./.github/actions/setup - name: Download nargo binary - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: nargo path: ./nargo @@ -337,19 +350,19 @@ jobs: uses: actions/checkout@v4 - name: Download nargo binary - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: nargo path: ./nargo - name: Download acvm_js package artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: acvm-js path: ./acvm-repo/acvm_js - name: Download noirc_abi package artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: noirc_abi_wasm path: ./tooling/noirc_abi_wasm @@ -374,8 +387,8 @@ jobs: - name: Run noir_codegen tests run: yarn workspace @noir-lang/noir_codegen test - test-integration: - name: Integration Tests + test-integration-node: + name: Integration Tests (Node) runs-on: ubuntu-latest needs: [build-acvm-js, build-noir-wasm, build-nargo, build-noirc-abi] timeout-minutes: 30 @@ -385,25 +398,25 @@ jobs: uses: actions/checkout@v4 - name: Download nargo binary - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: nargo path: ./nargo - name: Download acvm_js package artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: acvm-js path: ./acvm-repo/acvm_js - name: Download noir_wasm package artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: noir_wasm path: ./compiler/wasm - name: Download noirc_abi package artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: noirc_abi_wasm path: ./tooling/noirc_abi_wasm @@ -419,6 +432,48 @@ jobs: - name: Install Yarn dependencies uses: ./.github/actions/setup + - name: Setup `integration-tests` + run: | + # Note the lack of spaces between package names. + PACKAGES_TO_BUILD="@noir-lang/types,@noir-lang/backend_barretenberg,@noir-lang/noir_js" + yarn workspaces foreach -vtp --from "{$PACKAGES_TO_BUILD}" run build + + - name: Run `integration-tests` + working-directory: ./compiler/integration-tests + run: | + yarn test:node + + test-integration-browser: + name: Integration Tests (Browser) + runs-on: ubuntu-latest + needs: [build-acvm-js, build-noir-wasm, build-nargo, build-noirc-abi] + timeout-minutes: 30 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Download acvm_js package artifact + uses: actions/download-artifact@v4 + with: + name: acvm-js + path: ./acvm-repo/acvm_js + + - name: Download noir_wasm package artifact + uses: actions/download-artifact@v4 + with: + name: noir_wasm + path: ./compiler/wasm + + - name: Download noirc_abi package artifact + uses: actions/download-artifact@v4 + with: + name: noirc_abi_wasm + path: ./tooling/noirc_abi_wasm + + - name: Install Yarn dependencies + uses: ./.github/actions/setup + - name: Install Playwright uses: ./.github/actions/install-playwright @@ -429,8 +484,9 @@ jobs: yarn workspaces foreach -vtp --from "{$PACKAGES_TO_BUILD}" run build - name: Run `integration-tests` + working-directory: ./compiler/integration-tests run: | - yarn test:integration + yarn test:browser # This is a job which depends on all test jobs and reports the overall status. # This allows us to add/remove test jobs without having to update the required workflows. @@ -447,7 +503,8 @@ jobs: - test-noir-js - test-noir-wasm - test-noir-codegen - - test-integration + - test-integration-node + - test-integration-browser steps: - name: Report overall success diff --git a/noir/.github/workflows/test-rust-workspace.yml b/noir/.github/workflows/test-rust-workspace.yml index eccd7585fcf..be6e587dc15 100644 --- a/noir/.github/workflows/test-rust-workspace.yml +++ b/noir/.github/workflows/test-rust-workspace.yml @@ -13,19 +13,11 @@ concurrency: cancel-in-progress: true jobs: - test: - name: Test on ${{ matrix.os }} - runs-on: ${{ matrix.runner }} + build-test-artifacts: + name: Build test artifacts + runs-on: ubuntu-latest timeout-minutes: 30 - strategy: - fail-fast: false - matrix: - include: - - os: ubuntu - runner: ubuntu-latest - target: x86_64-unknown-linux-gnu - steps: - name: Checkout uses: actions/checkout@v4 @@ -33,13 +25,75 @@ jobs: - name: Setup toolchain uses: dtolnay/rust-toolchain@1.71.1 with: - targets: ${{ matrix.target }} + targets: x86_64-unknown-linux-gnu - uses: Swatinem/rust-cache@v2 with: - key: ${{ matrix.target }} + key: x86_64-unknown-linux-gnu cache-on-failure: true save-if: ${{ github.event_name != 'merge_group' }} + - name: Install nextest + uses: taiki-e/install-action@v2 + with: + tool: nextest@0.9.67 + + - name: Build and archive tests + run: cargo nextest archive --workspace --release --archive-file nextest-archive.tar.zst + + - name: Upload archive to workflow + uses: actions/upload-artifact@v4 + with: + name: nextest-archive + path: nextest-archive.tar.zst + + run-tests: + name: "Run tests (partition ${{matrix.partition}})" + runs-on: ubuntu-latest + needs: [build-test-artifacts] + strategy: + matrix: + partition: [1, 2, 3, 4] + steps: + - uses: actions/checkout@v4 + + - name: Setup toolchain + uses: dtolnay/rust-toolchain@1.71.1 + with: + targets: x86_64-unknown-linux-gnu + + - name: Install nextest + uses: taiki-e/install-action@v2 + with: + tool: nextest@0.9.67 + + - name: Download archive + uses: actions/download-artifact@v4 + with: + name: nextest-archive - name: Run tests - run: cargo test --workspace --locked --release + run: | + cargo nextest run --archive-file nextest-archive.tar.zst \ + --partition count:${{ matrix.partition }}/4 + + # This is a job which depends on all test jobs and reports the overall status. + # This allows us to add/remove test jobs without having to update the required workflows. + tests-end: + name: Rust End + runs-on: ubuntu-latest + # We want this job to always run (even if the dependant jobs fail) as we want this job to fail rather than skipping. + if: ${{ always() }} + needs: + - run-tests + + steps: + - name: Report overall success + run: | + if [[ $FAIL == true ]]; then + exit 1 + else + exit 0 + fi + env: + # We treat any skipped or failing jobs as a failure for the workflow as a whole. + FAIL: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'skipped') }} diff --git a/noir/.gitrepo b/noir/.gitrepo index f725a01b89b..f8b66efc119 100644 --- a/noir/.gitrepo +++ b/noir/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/noir-lang/noir branch = aztec-packages - commit = f1b91511124df89bbe9e059b87536901bdf0d6f3 - parent = f5be1f17beeded5ab1ac59331bd520787b3778a1 + commit = 6ff518af281afe601edb8574d425b07d9d2f9c5d + parent = 2082fedfb03d4882a269881f51c5337263bc539b method = merge cmdver = 0.4.6 diff --git a/noir/Cargo.lock b/noir/Cargo.lock index 291ac30336c..5677c7daad8 100644 --- a/noir/Cargo.lock +++ b/noir/Cargo.lock @@ -589,8 +589,8 @@ dependencies = [ "ark-ff", "flate2", "getrandom 0.2.10", - "grumpkin", "js-sys", + "noir_grumpkin", "num-bigint", "pkg-config", "reqwest", @@ -826,6 +826,14 @@ dependencies = [ "clap_derive", ] +[[package]] +name = "clap-markdown" +version = "0.1.3" +source = "git+https://github.com/noir-lang/clap-markdown?rev=450d759532c88f0dba70891ceecdbc9ff8f25d2b#450d759532c88f0dba70891ceecdbc9ff8f25d2b" +dependencies = [ + "clap", +] + [[package]] name = "clap_builder" version = "4.4.7" @@ -1672,6 +1680,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + [[package]] name = "flate2" version = "1.0.28" @@ -1942,17 +1956,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "grumpkin" -version = "0.1.0" -source = "git+https://github.com/noir-lang/grumpkin?rev=56d99799381f79e42148aaef0de2b0cf9a4b9a5d#56d99799381f79e42148aaef0de2b0cf9a4b9a5d" -dependencies = [ - "ark-bn254", - "ark-ec", - "ark-ff", - "ark-std", -] - [[package]] name = "h2" version = "0.3.24" @@ -2678,7 +2681,6 @@ dependencies = [ "rayon", "rustc_version", "serde", - "serial_test", "tempfile", "thiserror", "tracing", @@ -2696,6 +2698,7 @@ dependencies = [ "bn254_blackbox_solver", "build-data", "clap", + "clap-markdown", "color-eyre", "const_format", "criterion", @@ -2834,15 +2837,27 @@ dependencies = [ "nargo", "noirc_driver", "noirc_errors", + "noirc_frontend", "noirc_printable_type", "owo-colors", "rexpect", "serde_json", "tempfile", - "test-binary", "thiserror", ] +[[package]] +name = "noir_grumpkin" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7d49a4b14b13c0dc730b05780b385828ab88f4148daaad7db080ecdce07350" +dependencies = [ + "ark-bn254", + "ark-ec", + "ark-ff", + "ark-std", +] + [[package]] name = "noir_lsp" version = "0.23.0" @@ -2941,6 +2956,7 @@ dependencies = [ "noirc_errors", "noirc_evaluator", "noirc_frontend", + "noirc_macros", "rust-embed", "serde", "tracing", @@ -2957,6 +2973,7 @@ dependencies = [ "codespan-reporting", "flate2", "fm", + "noirc_printable_type", "serde", "serde_json", "serde_with", @@ -2990,6 +3007,7 @@ dependencies = [ "iter-extended", "noirc_errors", "noirc_printable_type", + "petgraph", "regex", "rustc-hash", "serde", @@ -3003,6 +3021,14 @@ dependencies = [ "tracing", ] +[[package]] +name = "noirc_macros" +version = "0.23.0" +dependencies = [ + "iter-extended", + "noirc_frontend", +] + [[package]] name = "noirc_printable_type" version = "0.23.0" @@ -3193,6 +3219,16 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +[[package]] +name = "petgraph" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +dependencies = [ + "fixedbitset", + "indexmap 2.0.0", +] + [[package]] name = "phf" version = "0.10.1" @@ -4242,31 +4278,6 @@ dependencies = [ "syn 2.0.32", ] -[[package]] -name = "serial_test" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e56dd856803e253c8f298af3f4d7eb0ae5e23a737252cd90bb4f3b435033b2d" -dependencies = [ - "dashmap", - "futures 0.3.28", - "lazy_static", - "log", - "parking_lot 0.12.1", - "serial_test_derive", -] - -[[package]] -name = "serial_test_derive" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.32", -] - [[package]] name = "sha2" version = "0.10.7" diff --git a/noir/Cargo.toml b/noir/Cargo.toml index 5dfff3dbb5d..2ba97e906b1 100644 --- a/noir/Cargo.toml +++ b/noir/Cargo.toml @@ -1,7 +1,10 @@ [workspace] members = [ + # Macros crates for metaprogramming "aztec_macros", + "noirc_macros", + # Compiler crates "compiler/noirc_evaluator", "compiler/noirc_frontend", "compiler/noirc_errors", diff --git a/noir/acvm-repo/acir/codegen/acir.cpp b/noir/acvm-repo/acir/codegen/acir.cpp index 3ce63ecfa94..0fc84d47a0f 100644 --- a/noir/acvm-repo/acir/codegen/acir.cpp +++ b/noir/acvm-repo/acir/codegen/acir.cpp @@ -983,18 +983,7 @@ namespace Circuit { static ToLeRadix bincodeDeserialize(std::vector); }; - struct PermutationSort { - std::vector> inputs; - uint32_t tuple; - std::vector bits; - std::vector sort_by; - - friend bool operator==(const PermutationSort&, const PermutationSort&); - std::vector bincodeSerialize() const; - static PermutationSort bincodeDeserialize(std::vector); - }; - - std::variant value; + std::variant value; friend bool operator==(const Directive&, const Directive&); std::vector bincodeSerialize() const; @@ -5200,53 +5189,6 @@ Circuit::Directive::ToLeRadix serde::Deserializable Directive::PermutationSort::bincodeSerialize() const { - auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); - return std::move(serializer).bytes(); - } - - inline Directive::PermutationSort Directive::PermutationSort::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::Directive::PermutationSort &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.inputs, serializer); - serde::Serializable::serialize(obj.tuple, serializer); - serde::Serializable::serialize(obj.bits, serializer); - serde::Serializable::serialize(obj.sort_by, serializer); -} - -template <> -template -Circuit::Directive::PermutationSort serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::Directive::PermutationSort obj; - obj.inputs = serde::Deserializable::deserialize(deserializer); - obj.tuple = serde::Deserializable::deserialize(deserializer); - obj.bits = serde::Deserializable::deserialize(deserializer); - obj.sort_by = serde::Deserializable::deserialize(deserializer); - return obj; -} - namespace Circuit { inline bool operator==(const Expression &lhs, const Expression &rhs) { diff --git a/noir/acvm-repo/acir/src/circuit/directives.rs b/noir/acvm-repo/acir/src/circuit/directives.rs index 2486f4cfb83..099d0634399 100644 --- a/noir/acvm-repo/acir/src/circuit/directives.rs +++ b/noir/acvm-repo/acir/src/circuit/directives.rs @@ -7,18 +7,5 @@ use serde::{Deserialize, Serialize}; /// In the future, this can be replaced with asm non-determinism blocks pub enum Directive { //decomposition of a: a=\sum b[i]*radix^i where b is an array of witnesses < radix in little endian form - ToLeRadix { - a: Expression, - b: Vec, - radix: u32, - }, - - // Sort directive, using a sorting network - // This directive is used to generate the values of the control bits for the sorting network such that its outputs are properly sorted according to sort_by - PermutationSort { - inputs: Vec>, // Array of tuples to sort - tuple: u32, // tuple size; if 1 then inputs is a single array [a0,a1,..], if 2 then inputs=[(a0,b0),..] is [a0,b0,a1,b1,..], etc.. - bits: Vec, // control bits of the network which permutes the inputs into its sorted version - sort_by: Vec, // specify primary index to sort by, then the secondary,... For instance, if tuple is 2 and sort_by is [1,0], then a=[(a0,b0),..] is sorted by bi and then ai. - }, + ToLeRadix { a: Expression, b: Vec, radix: u32 }, } diff --git a/noir/acvm-repo/acir/src/circuit/mod.rs b/noir/acvm-repo/acir/src/circuit/mod.rs index 9cbacdc2ab0..7e6cbf23803 100644 --- a/noir/acvm-repo/acir/src/circuit/mod.rs +++ b/noir/acvm-repo/acir/src/circuit/mod.rs @@ -56,6 +56,10 @@ pub struct Circuit { // Note: This should be a BTreeMap, but serde-reflect is creating invalid // c++ code at the moment when it is, due to OpcodeLocation needing a comparison // implementation which is never generated. + // + // TODO: These are only used for constraints that are explicitly created during code generation (such as index out of bounds on slices) + // TODO: We should move towards having all the checks being evaluated in the same manner + // TODO: as runtime assert messages specified by the user. This will also be a breaking change as the `Circuit` structure will change. pub assert_messages: Vec<(OpcodeLocation, String)>, /// States whether the backend should use a SNARK recursion friendly prover. diff --git a/noir/acvm-repo/acir/src/circuit/opcodes.rs b/noir/acvm-repo/acir/src/circuit/opcodes.rs index 5aab9d4d472..f725ba8c32a 100644 --- a/noir/acvm-repo/acir/src/circuit/opcodes.rs +++ b/noir/acvm-repo/acir/src/circuit/opcodes.rs @@ -8,6 +8,7 @@ mod memory_operation; pub use black_box_function_call::{BlackBoxFuncCall, FunctionInput}; pub use memory_operation::{BlockId, MemOp}; +#[allow(clippy::large_enum_variant)] #[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum Opcode { AssertZero(Expression), @@ -59,20 +60,6 @@ impl std::fmt::Display for Opcode { b.last().unwrap().witness_index(), ) } - Opcode::Directive(Directive::PermutationSort { inputs: a, tuple, bits, sort_by }) => { - write!(f, "DIR::PERMUTATIONSORT ")?; - write!( - f, - "(permutation size: {} {}-tuples, sort_by: {:#?}, bits: [_{}..._{}]))", - a.len(), - tuple, - sort_by, - // (Note): the bits do not have contiguous index but there are too many for display - bits.first().unwrap().witness_index(), - bits.last().unwrap().witness_index(), - ) - } - Opcode::Brillig(brillig) => { write!(f, "BRILLIG: ")?; writeln!(f, "inputs: {:?}", brillig.inputs)?; diff --git a/noir/acvm-repo/acir_field/src/generic_ark.rs b/noir/acvm-repo/acir_field/src/generic_ark.rs index 542e291982b..dc54d271beb 100644 --- a/noir/acvm-repo/acir_field/src/generic_ark.rs +++ b/noir/acvm-repo/acir_field/src/generic_ark.rs @@ -175,6 +175,10 @@ impl FieldElement { self == &Self::one() } + pub fn is_negative(&self) -> bool { + self.neg().num_bits() < self.num_bits() + } + pub fn pow(&self, exponent: &Self) -> Self { FieldElement(self.0.pow(exponent.0.into_bigint())) } @@ -240,6 +244,12 @@ impl FieldElement { self.fits_in_u128().then(|| self.to_u128()) } + pub fn to_i128(self) -> i128 { + let is_negative = self.is_negative(); + let bytes = if is_negative { self.neg() } else { self }.to_be_bytes(); + i128::from_be_bytes(bytes[16..32].try_into().unwrap()) * if is_negative { -1 } else { 1 } + } + pub fn try_to_u64(&self) -> Option { (self.num_bits() <= 64).then(|| self.to_u128() as u64) } diff --git a/noir/acvm-repo/acvm/src/compiler/transformers/mod.rs b/noir/acvm-repo/acvm/src/compiler/transformers/mod.rs index 4be2eb7029e..214243d9360 100644 --- a/noir/acvm-repo/acvm/src/compiler/transformers/mod.rs +++ b/noir/acvm-repo/acvm/src/compiler/transformers/mod.rs @@ -111,11 +111,6 @@ pub(super) fn transform_internal( transformer.mark_solvable(*witness); } } - Directive::PermutationSort { bits, .. } => { - for witness in bits { - transformer.mark_solvable(*witness); - } - } } new_acir_opcode_positions.push(acir_opcode_positions[index]); transformed_opcodes.push(opcode); diff --git a/noir/acvm-repo/acvm/src/pwg/brillig.rs b/noir/acvm-repo/acvm/src/pwg/brillig.rs index c5a98aaf01c..b0fb7469fd9 100644 --- a/noir/acvm-repo/acvm/src/pwg/brillig.rs +++ b/noir/acvm-repo/acvm/src/pwg/brillig.rs @@ -130,6 +130,10 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { self.vm.write_memory_at(ptr, value); } + pub fn get_call_stack(&self) -> Vec { + self.vm.get_call_stack() + } + pub(super) fn solve(&mut self) -> Result { let status = self.vm.process_opcodes(); self.handle_vm_status(status) diff --git a/noir/acvm-repo/acvm/src/pwg/directives/mod.rs b/noir/acvm-repo/acvm/src/pwg/directives/mod.rs index 4605168d98b..07226c85b27 100644 --- a/noir/acvm-repo/acvm/src/pwg/directives/mod.rs +++ b/noir/acvm-repo/acvm/src/pwg/directives/mod.rs @@ -1,5 +1,3 @@ -use std::cmp::Ordering; - use acir::{circuit::directives::Directive, native_types::WitnessMap, FieldElement}; use num_bigint::BigUint; @@ -7,8 +5,6 @@ use crate::OpcodeResolutionError; use super::{get_value, insert_value, ErrorLocation}; -mod sorting; - /// Attempts to solve the [`Directive`] opcode `directive`. /// If successful, `initial_witness` will be mutated to contain the new witness assignment. /// @@ -48,38 +44,5 @@ pub(super) fn solve_directives( Ok(()) } - Directive::PermutationSort { inputs: a, tuple, bits, sort_by } => { - let mut val_a = Vec::new(); - let mut base = Vec::new(); - for (i, element) in a.iter().enumerate() { - assert_eq!(element.len(), *tuple as usize); - let mut element_val = Vec::with_capacity(*tuple as usize + 1); - for e in element { - element_val.push(get_value(e, initial_witness)?); - } - let field_i = FieldElement::from(i as i128); - element_val.push(field_i); - base.push(field_i); - val_a.push(element_val); - } - val_a.sort_by(|a, b| { - for i in sort_by { - let int_a = BigUint::from_bytes_be(&a[*i as usize].to_be_bytes()); - let int_b = BigUint::from_bytes_be(&b[*i as usize].to_be_bytes()); - let cmp = int_a.cmp(&int_b); - if cmp != Ordering::Equal { - return cmp; - } - } - Ordering::Equal - }); - let b = val_a.iter().map(|a| *a.last().unwrap()).collect(); - let control = sorting::route(base, b); - for (w, value) in bits.iter().zip(control) { - let value = if value { FieldElement::one() } else { FieldElement::zero() }; - insert_value(w, value, initial_witness)?; - } - Ok(()) - } } } diff --git a/noir/acvm-repo/acvm/src/pwg/directives/sorting.rs b/noir/acvm-repo/acvm/src/pwg/directives/sorting.rs deleted file mode 100644 index 2749e88b023..00000000000 --- a/noir/acvm-repo/acvm/src/pwg/directives/sorting.rs +++ /dev/null @@ -1,396 +0,0 @@ -use std::collections::{BTreeMap, BTreeSet}; - -use acir::FieldElement; - -// A sorting network is a graph of connected switches -// It is defined recursively so here we only keep track of the outer layer of switches -struct SortingNetwork { - n: usize, // size of the network - x_inputs: Vec, // inputs of the network - y_inputs: Vec, // outputs of the network - x_values: BTreeMap, // map for matching a y value with a x value - y_values: BTreeMap, // map for matching a x value with a y value - inner_x: Vec, // positions after the switch_x - inner_y: Vec, // positions after the sub-networks, and before the switch_y - switch_x: Vec, // outer switches for the inputs - switch_y: Vec, // outer switches for the outputs - free: BTreeSet, // outer switches available for looping -} - -impl SortingNetwork { - fn new(n: usize) -> SortingNetwork { - let free_len = (n - 1) / 2; - let mut free = BTreeSet::new(); - for i in 0..free_len { - free.insert(i); - } - SortingNetwork { - n, - x_inputs: Vec::with_capacity(n), - y_inputs: Vec::with_capacity(n), - x_values: BTreeMap::new(), - y_values: BTreeMap::new(), - inner_x: Vec::with_capacity(n), - inner_y: Vec::with_capacity(n), - switch_x: Vec::with_capacity(n / 2), - switch_y: Vec::with_capacity(free_len), - free, - } - } - - fn init(&mut self, inputs: Vec, outputs: Vec) { - let n = self.n; - assert_eq!(inputs.len(), outputs.len()); - assert_eq!(inputs.len(), n); - - self.x_inputs = inputs; - self.y_inputs = outputs; - for i in 0..self.n { - self.x_values.insert(self.x_inputs[i], i); - self.y_values.insert(self.y_inputs[i], i); - } - self.switch_x = vec![false; n / 2]; - self.switch_y = vec![false; (n - 1) / 2]; - self.inner_x = vec![FieldElement::zero(); n]; - self.inner_y = vec![FieldElement::zero(); n]; - - //Route the single wires so we do not need to handle this case later on - self.inner_y[n - 1] = self.y_inputs[n - 1]; - if n % 2 == 0 { - self.inner_y[n / 2 - 1] = self.y_inputs[n - 2]; - } else { - self.inner_x[n - 1] = self.x_inputs[n - 1]; - } - } - - //route a wire from outputs to its value in the inputs - fn route_out_wire(&mut self, y: usize, sub: bool) -> usize { - // sub <- y - if self.is_single_y(y) { - assert!(sub); - } else { - let port = y % 2 != 0; - let s1 = sub ^ port; - let inner = self.compute_inner(y, s1); - self.configure_y(y, s1, inner); - } - // x <- sub - let x = self.x_values.remove(&self.y_inputs[y]).unwrap(); - if !self.is_single_x(x) { - let port2 = x % 2 != 0; - let s2 = sub ^ port2; - let inner = self.compute_inner(x, s2); - self.configure_x(x, s2, inner); - } - x - } - - //route a wire from inputs to its value in the outputs - fn route_in_wire(&mut self, x: usize, sub: bool) -> usize { - // x -> sub - assert!(!self.is_single_x(x)); - let port = x % 2 != 0; - let s1 = sub ^ port; - let inner = self.compute_inner(x, s1); - self.configure_x(x, s1, inner); - - // sub -> y - let y = self.y_values.remove(&self.x_inputs[x]).unwrap(); - if !self.is_single_y(y) { - let port = y % 2 != 0; - let s2 = sub ^ port; - let inner = self.compute_inner(y, s2); - self.configure_y(y, s2, inner); - } - y - } - - //update the computed switch and inner values for an input wire - fn configure_x(&mut self, x: usize, switch: bool, inner: usize) { - self.inner_x[inner] = self.x_inputs[x]; - self.switch_x[x / 2] = switch; - } - - //update the computed switch and inner values for an output wire - fn configure_y(&mut self, y: usize, switch: bool, inner: usize) { - self.inner_y[inner] = self.y_inputs[y]; - self.switch_y[y / 2] = switch; - } - - // returns the other wire belonging to the same switch - fn sibling(index: usize) -> usize { - index + 1 - 2 * (index % 2) - } - - // returns a free switch - fn take(&mut self) -> Option { - self.free.first().copied() - } - - fn is_single_x(&self, a: usize) -> bool { - let n = self.x_inputs.len(); - n % 2 == 1 && a == n - 1 - } - - fn is_single_y(&mut self, a: usize) -> bool { - let n = self.x_inputs.len(); - a >= n - 2 + n % 2 - } - - // compute the inner position of idx through its switch - fn compute_inner(&self, idx: usize, switch: bool) -> usize { - if switch ^ (idx % 2 == 1) { - idx / 2 + self.n / 2 - } else { - idx / 2 - } - } - - fn new_start(&mut self) -> (Option, usize) { - let next = self.take(); - if let Some(switch) = next { - (next, 2 * switch) - } else { - (None, 0) - } - } -} - -// Computes the control bits of the sorting network which transform inputs into outputs -// implementation is based on https://www.mdpi.com/2227-7080/10/1/16 -pub(super) fn route(inputs: Vec, outputs: Vec) -> Vec { - assert_eq!(inputs.len(), outputs.len()); - match inputs.len() { - 0 => Vec::new(), - 1 => { - assert_eq!(inputs[0], outputs[0]); - Vec::new() - } - 2 => { - if inputs[0] == outputs[0] { - assert_eq!(inputs[1], outputs[1]); - vec![false] - } else { - assert_eq!(inputs[1], outputs[0]); - assert_eq!(inputs[0], outputs[1]); - vec![true] - } - } - _ => { - let n = inputs.len(); - - let mut result; - let n1 = n / 2; - let in_sub1; - let out_sub1; - let in_sub2; - let out_sub2; - - // process the outer layer in a code block so that the intermediate data is cleared before recursion - { - let mut network = SortingNetwork::new(n); - network.init(inputs, outputs); - - //We start with the last single wire - let mut out_idx = n - 1; - let mut start_sub = true; //it is connected to the lower inner network - let mut switch = None; - let mut start = None; - - while !network.free.is_empty() { - // the processed switch is no more available - if let Some(free_switch) = switch { - network.free.remove(&free_switch); - } - - // connect the output wire to its matching input - let in_idx = network.route_out_wire(out_idx, start_sub); - if network.is_single_x(in_idx) { - start_sub = !start_sub; //We need to restart, but did not complete the loop so we switch the sub network - (start, out_idx) = network.new_start(); - switch = start; - continue; - } - - // loop from the sibling - let next = SortingNetwork::sibling(in_idx); - // connect the input wire to its matching output, using the other sub-network - out_idx = network.route_in_wire(next, !start_sub); - switch = Some(out_idx / 2); - if start == switch || network.is_single_y(out_idx) { - //loop is complete, need a fresh start - (start, out_idx) = network.new_start(); - switch = start; - } else { - // we loop back from the sibling - out_idx = SortingNetwork::sibling(out_idx); - } - } - //All the wires are connected, we can now route the sub-networks - result = network.switch_x; - result.extend(network.switch_y); - in_sub1 = network.inner_x[0..n1].to_vec(); - in_sub2 = network.inner_x[n1..].to_vec(); - out_sub1 = network.inner_y[0..n1].to_vec(); - out_sub2 = network.inner_y[n1..].to_vec(); - } - let s1 = route(in_sub1, out_sub1); - result.extend(s1); - let s2 = route(in_sub2, out_sub2); - result.extend(s2); - result - } - } -} - -#[cfg(test)] -mod tests { - // Silence `unused_crate_dependencies` warning - use paste as _; - use proptest as _; - - use super::route; - use acir::FieldElement; - use rand::prelude::*; - - fn execute_network(config: Vec, inputs: Vec) -> Vec { - let n = inputs.len(); - if n == 1 { - return inputs; - } - let mut in1 = Vec::new(); - let mut in2 = Vec::new(); - //layer 1: - for i in 0..n / 2 { - if config[i] { - in1.push(inputs[2 * i + 1]); - in2.push(inputs[2 * i]); - } else { - in1.push(inputs[2 * i]); - in2.push(inputs[2 * i + 1]); - } - } - if n % 2 == 1 { - in2.push(*inputs.last().unwrap()); - } - let n2 = n / 2 + (n - 1) / 2; - let n3 = n2 + switch_nb(n / 2); - let mut result = Vec::new(); - let out1 = execute_network(config[n2..n3].to_vec(), in1); - let out2 = execute_network(config[n3..].to_vec(), in2); - //last layer: - for i in 0..(n - 1) / 2 { - if config[n / 2 + i] { - result.push(out2[i]); - result.push(out1[i]); - } else { - result.push(out1[i]); - result.push(out2[i]); - } - } - if n % 2 == 0 { - result.push(*out1.last().unwrap()); - result.push(*out2.last().unwrap()); - } else { - result.push(*out2.last().unwrap()); - } - result - } - - // returns the number of switches in the network - fn switch_nb(n: usize) -> usize { - let mut s = 0; - for i in 0..n { - s += f64::from((i + 1) as u32).log2().ceil() as usize; - } - s - } - - #[test] - fn test_route() { - //basic tests - let a = vec![ - FieldElement::from(1_i128), - FieldElement::from(2_i128), - FieldElement::from(3_i128), - ]; - let b = vec![ - FieldElement::from(1_i128), - FieldElement::from(2_i128), - FieldElement::from(3_i128), - ]; - let c = route(a, b); - assert_eq!(c, vec![false, false, false]); - - let a = vec![ - FieldElement::from(1_i128), - FieldElement::from(2_i128), - FieldElement::from(3_i128), - ]; - let b = vec![ - FieldElement::from(1_i128), - FieldElement::from(3_i128), - FieldElement::from(2_i128), - ]; - let c = route(a, b); - assert_eq!(c, vec![false, false, true]); - - let a = vec![ - FieldElement::from(1_i128), - FieldElement::from(2_i128), - FieldElement::from(3_i128), - ]; - let b = vec![ - FieldElement::from(3_i128), - FieldElement::from(2_i128), - FieldElement::from(1_i128), - ]; - let c = route(a, b); - assert_eq!(c, vec![true, true, true]); - - let a = vec![ - FieldElement::from(0_i128), - FieldElement::from(1_i128), - FieldElement::from(2_i128), - FieldElement::from(3_i128), - ]; - let b = vec![ - FieldElement::from(2_i128), - FieldElement::from(3_i128), - FieldElement::from(0_i128), - FieldElement::from(1_i128), - ]; - let c = route(a, b); - assert_eq!(c, vec![false, true, true, true, true]); - - let a = vec![ - FieldElement::from(0_i128), - FieldElement::from(1_i128), - FieldElement::from(2_i128), - FieldElement::from(3_i128), - FieldElement::from(4_i128), - ]; - let b = vec![ - FieldElement::from(0_i128), - FieldElement::from(3_i128), - FieldElement::from(4_i128), - FieldElement::from(2_i128), - FieldElement::from(1_i128), - ]; - let c = route(a, b); - assert_eq!(c, vec![false, false, false, true, false, true, false, true]); - - // random tests - for i in 2..50 { - let mut a = vec![FieldElement::zero()]; - for j in 0..i - 1 { - a.push(a[j] + FieldElement::one()); - } - let mut rng = rand::thread_rng(); - let mut b = a.clone(); - b.shuffle(&mut rng); - let c = route(a.clone(), b.clone()); - assert_eq!(b, execute_network(c, a)); - } - } -} diff --git a/noir/acvm-repo/bn254_blackbox_solver/Cargo.toml b/noir/acvm-repo/bn254_blackbox_solver/Cargo.toml index a73aded231f..ef80e2c1c0f 100644 --- a/noir/acvm-repo/bn254_blackbox_solver/Cargo.toml +++ b/noir/acvm-repo/bn254_blackbox_solver/Cargo.toml @@ -23,8 +23,9 @@ rust-embed = { version = "6.6.0", features = [ "include-exclude", ] } -# BN254 fixed base scalar multiplication solver -grumpkin = { git = "https://github.com/noir-lang/grumpkin", rev = "56d99799381f79e42148aaef0de2b0cf9a4b9a5d", features = ["std"] } +grumpkin = { version = "0.1.0", package = "noir_grumpkin", features = [ + "std", +] } # BN254 fixed base scalar multiplication solver ark-ec = { version = "^0.4.0", default-features = false } ark-ff = { version = "^0.4.0", default-features = false } num-bigint.workspace = true diff --git a/noir/acvm-repo/brillig/src/foreign_call.rs b/noir/acvm-repo/brillig/src/foreign_call.rs index 1359d7d604d..3f124a9a0a7 100644 --- a/noir/acvm-repo/brillig/src/foreign_call.rs +++ b/noir/acvm-repo/brillig/src/foreign_call.rs @@ -37,7 +37,7 @@ impl ForeignCallParam { } /// Represents the full output of a [foreign call][crate::Opcode::ForeignCall]. -#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)] +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, Default)] pub struct ForeignCallResult { /// Resolved output values of the foreign call. pub values: Vec, diff --git a/noir/acvm-repo/brillig_vm/src/lib.rs b/noir/acvm-repo/brillig_vm/src/lib.rs index 081ecd33cb6..13accbeacb3 100644 --- a/noir/acvm-repo/brillig_vm/src/lib.rs +++ b/noir/acvm-repo/brillig_vm/src/lib.rs @@ -167,6 +167,16 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { self.memory.write(MemoryAddress(ptr), value); } + /// Returns the VM's current call stack, including the actual program + /// counter in the last position of the returned vector. + pub fn get_call_stack(&self) -> Vec { + self.call_stack + .iter() + .map(|program_counter| program_counter.to_usize()) + .chain(std::iter::once(self.program_counter)) + .collect() + } + /// Process a single opcode and modify the program counter. pub fn process_opcode(&mut self) -> VMStatus { let opcode = &self.bytecode[self.program_counter]; diff --git a/noir/aztec_macros/src/lib.rs b/noir/aztec_macros/src/lib.rs index 2143fbf6e3d..7ca4b79eed8 100644 --- a/noir/aztec_macros/src/lib.rs +++ b/noir/aztec_macros/src/lib.rs @@ -150,7 +150,7 @@ fn pattern(name: &str) -> Pattern { } fn mutable(name: &str) -> Pattern { - Pattern::Mutable(Box::new(pattern(name)), Span::default()) + Pattern::Mutable(Box::new(pattern(name)), Span::default(), true) } fn mutable_assignment(name: &str, assigned_to: Expression) -> Statement { @@ -184,7 +184,7 @@ fn member_access(lhs: &str, rhs: &str) -> Expression { } fn return_type(path: Path) -> FunctionReturnType { - let ty = make_type(UnresolvedTypeData::Named(path, vec![])); + let ty = make_type(UnresolvedTypeData::Named(path, vec![], true)); FunctionReturnType::Ty(ty) } @@ -330,7 +330,7 @@ fn check_for_storage_definition(module: &SortedModule) -> bool { // Check to see if the user has defined a storage struct fn check_for_storage_implementation(module: &SortedModule) -> bool { module.impls.iter().any(|r#impl| match &r#impl.object_type.typ { - UnresolvedTypeData::Named(path, _) => { + UnresolvedTypeData::Named(path, _, _) => { path.segments.last().is_some_and(|segment| segment.0.contents == "Storage") } _ => false, @@ -343,7 +343,7 @@ fn check_for_compute_note_hash_and_nullifier_definition(module: &SortedModule) - func.def.name.0.contents == "compute_note_hash_and_nullifier" && func.def.parameters.len() == 4 && match &func.def.parameters[0].typ.typ { - UnresolvedTypeData::Named(path, _) => path.segments.last().unwrap().0.contents == "AztecAddress", + UnresolvedTypeData::Named(path, _, _) => path.segments.last().unwrap().0.contents == "AztecAddress", _ => false, } && func.def.parameters[1].typ.typ == UnresolvedTypeData::FieldElement @@ -470,7 +470,7 @@ fn generate_storage_field_constructor( ) -> Result { let typ = &unresolved_type.typ; match typ { - UnresolvedTypeData::Named(path, generics) => { + UnresolvedTypeData::Named(path, generics, _) => { let mut new_path = path.clone().to_owned(); new_path.segments.push(ident("new")); match path.segments.last().unwrap().0.contents.as_str() { @@ -486,6 +486,7 @@ fn generate_storage_field_constructor( make_type(UnresolvedTypeData::Named( chained_path!("aztec", "context", "Context"), vec![], + true, )), ), ( @@ -569,6 +570,7 @@ fn generate_storage_implementation(module: &mut SortedModule) -> Result<(), Azte make_type(UnresolvedTypeData::Named( chained_path!("aztec", "context", "Context"), vec![], + true, )), )], &BlockExpression(vec![storage_constructor_statement]), @@ -578,12 +580,12 @@ fn generate_storage_implementation(module: &mut SortedModule) -> Result<(), Azte let storage_impl = TypeImpl { object_type: UnresolvedType { - typ: UnresolvedTypeData::Named(chained_path!("Storage"), vec![]), + typ: UnresolvedTypeData::Named(chained_path!("Storage"), vec![], true), span: Some(Span::default()), }, type_span: Span::default(), generics: vec![], - methods: vec![init], + methods: vec![(init, Span::default())], }; module.impls.push(storage_impl); @@ -994,7 +996,8 @@ const SIGNATURE_PLACEHOLDER: &str = "SIGNATURE_PLACEHOLDER"; /// The signature cannot be known at this point since types are not resolved yet, so we use a signature placeholder. /// It'll get resolved after by transforming the HIR. fn generate_selector_impl(structure: &NoirStruct) -> TypeImpl { - let struct_type = make_type(UnresolvedTypeData::Named(path(structure.name.clone()), vec![])); + let struct_type = + make_type(UnresolvedTypeData::Named(path(structure.name.clone()), vec![], true)); let selector_path = chained_path!("aztec", "protocol_types", "abis", "function_selector", "FunctionSelector"); @@ -1008,7 +1011,7 @@ fn generate_selector_impl(structure: &NoirStruct) -> TypeImpl { // Define `FunctionSelector` return type let return_type = - FunctionReturnType::Ty(make_type(UnresolvedTypeData::Named(selector_path, vec![]))); + FunctionReturnType::Ty(make_type(UnresolvedTypeData::Named(selector_path, vec![], true))); let mut selector_fn_def = FunctionDefinition::normal( &ident("selector"), @@ -1028,7 +1031,7 @@ fn generate_selector_impl(structure: &NoirStruct) -> TypeImpl { object_type: struct_type, type_span: structure.span, generics: vec![], - methods: vec![NoirFunction::normal(selector_fn_def)], + methods: vec![(NoirFunction::normal(selector_fn_def), Span::default())], } } @@ -1054,7 +1057,7 @@ fn create_inputs(ty: &str) -> Param { let path_snippet = ty.to_case(Case::Snake); // e.g. private_context_inputs let type_path = chained_path!("aztec", "context", "inputs", &path_snippet, ty); - let context_type = make_type(UnresolvedTypeData::Named(type_path, vec![])); + let context_type = make_type(UnresolvedTypeData::Named(type_path, vec![], true)); let visibility = Visibility::Private; Param { pattern: context_pattern, typ: context_type, visibility, span: Span::default() } diff --git a/noir/compiler/integration-tests/package.json b/noir/compiler/integration-tests/package.json index c4e424df480..a89e37dc64f 100644 --- a/noir/compiler/integration-tests/package.json +++ b/noir/compiler/integration-tests/package.json @@ -5,8 +5,8 @@ "private": true, "scripts": { "build": "echo Integration Test build step", - "test": "bash ./scripts/codegen-verifiers.sh && yarn test:browser && yarn test:node", - "test:node": "hardhat test test/node/**/*", + "test": "yarn test:browser && yarn test:node", + "test:node": "bash ./scripts/codegen-verifiers.sh && hardhat test test/node/**/*", "test:browser": "web-test-runner", "test:integration:browser": "web-test-runner test/browser/**/*.test.ts", "test:integration:browser:watch": "web-test-runner test/browser/**/*.test.ts --watch", diff --git a/noir/compiler/noirc_driver/Cargo.toml b/noir/compiler/noirc_driver/Cargo.toml index eb9650e8aec..d9b240101d8 100644 --- a/noir/compiler/noirc_driver/Cargo.toml +++ b/noir/compiler/noirc_driver/Cargo.toml @@ -25,3 +25,4 @@ rust-embed.workspace = true tracing.workspace = true aztec_macros = { path = "../../aztec_macros" } +noirc_macros = { path = "../../noirc_macros" } diff --git a/noir/compiler/noirc_driver/src/lib.rs b/noir/compiler/noirc_driver/src/lib.rs index cded514f28c..8b0fc5dc97a 100644 --- a/noir/compiler/noirc_driver/src/lib.rs +++ b/noir/compiler/noirc_driver/src/lib.rs @@ -11,11 +11,12 @@ use noirc_abi::{AbiParameter, AbiType, ContractEvent}; use noirc_errors::{CustomDiagnostic, FileDiagnostic}; use noirc_evaluator::create_circuit; use noirc_evaluator::errors::RuntimeError; +use noirc_frontend::debug::build_debug_crate_file; use noirc_frontend::graph::{CrateId, CrateName}; use noirc_frontend::hir::def_map::{Contract, CrateDefMap}; use noirc_frontend::hir::Context; use noirc_frontend::macros_api::MacroProcessor; -use noirc_frontend::monomorphization::monomorphize; +use noirc_frontend::monomorphization::{monomorphize, monomorphize_debug}; use noirc_frontend::node_interner::FuncId; use std::path::Path; use tracing::info; @@ -33,6 +34,7 @@ pub use debug::DebugFile; pub use program::CompiledProgram; const STD_CRATE_NAME: &str = "std"; +const DEBUG_CRATE_NAME: &str = "__debug"; pub const GIT_COMMIT: &str = env!("GIT_COMMIT"); pub const GIT_DIRTY: &str = env!("GIT_DIRTY"); @@ -76,13 +78,21 @@ pub struct CompileOptions { #[arg(long, hide = true)] pub only_acir: bool, - /// Disables the builtin macros being used in the compiler + /// Disables the builtin Aztec macros being used in the compiler #[arg(long, hide = true)] pub disable_macros: bool, /// Outputs the monomorphized IR to stdout for debugging #[arg(long, hide = true)] pub show_monomorphized: bool, + + /// Insert debug symbols to inspect variables + #[arg(long, hide = true)] + pub instrument_debug: bool, + + /// Force Brillig output (for step debugging) + #[arg(long, hide = true)] + pub force_brillig: bool, } fn parse_expression_width(input: &str) -> Result { @@ -115,6 +125,7 @@ pub fn file_manager_with_stdlib(root: &Path) -> FileManager { let mut file_manager = FileManager::new(root); add_stdlib_source_to_file_manager(&mut file_manager); + add_debug_source_to_file_manager(&mut file_manager); file_manager } @@ -131,6 +142,15 @@ fn add_stdlib_source_to_file_manager(file_manager: &mut FileManager) { } } +/// Adds the source code of the debug crate needed to support instrumentation to +/// track variables values +fn add_debug_source_to_file_manager(file_manager: &mut FileManager) { + // Adds the synthetic debug module for instrumentation into the file manager + let path_to_debug_lib_file = Path::new(DEBUG_CRATE_NAME).join("lib.nr"); + file_manager + .add_file_with_source_canonical_path(&path_to_debug_lib_file, build_debug_crate_file()); +} + /// Adds the file from the file system at `Path` to the crate graph as a root file /// /// Note: This methods adds the stdlib as a dependency to the crate. @@ -152,6 +172,12 @@ pub fn prepare_crate(context: &mut Context, file_name: &Path) -> CrateId { root_crate_id } +pub fn link_to_debug_crate(context: &mut Context, root_crate_id: CrateId) { + let path_to_debug_lib_file = Path::new(DEBUG_CRATE_NAME).join("lib.nr"); + let debug_crate_id = prepare_dependency(context, &path_to_debug_lib_file); + add_dep(context, root_crate_id, debug_crate_id, DEBUG_CRATE_NAME.parse().unwrap()); +} + // Adds the file from the file system at `Path` to the crate graph pub fn prepare_dependency(context: &mut Context, file_name: &Path) -> CrateId { let root_file_id = context @@ -193,9 +219,12 @@ pub fn check_crate( disable_macros: bool, ) -> CompilationResult<()> { let macros: Vec<&dyn MacroProcessor> = if disable_macros { - vec![] + vec![&noirc_macros::AssertMessageMacro as &dyn MacroProcessor] } else { - vec![&aztec_macros::AztecMacro as &dyn MacroProcessor] + vec![ + &aztec_macros::AztecMacro as &dyn MacroProcessor, + &noirc_macros::AssertMessageMacro as &dyn MacroProcessor, + ] }; let mut errors = vec![]; @@ -246,6 +275,7 @@ pub fn compile_main( let compiled_program = compile_no_check(context, options, main, cached_program, options.force_compile) .map_err(FileDiagnostic::from)?; + let compilation_warnings = vecmap(compiled_program.warnings.clone(), FileDiagnostic::from); if options.deny_warnings && !compilation_warnings.is_empty() { return Err(compilation_warnings); @@ -325,7 +355,7 @@ fn has_errors(errors: &[FileDiagnostic], deny_warnings: bool) -> bool { /// Compile all of the functions associated with a Noir contract. fn compile_contract_inner( - context: &Context, + context: &mut Context, contract: Contract, options: &CompileOptions, ) -> Result { @@ -401,13 +431,17 @@ fn compile_contract_inner( /// This function assumes [`check_crate`] is called beforehand. #[tracing::instrument(level = "trace", skip_all, fields(function_name = context.function_name(&main_function)))] pub fn compile_no_check( - context: &Context, + context: &mut Context, options: &CompileOptions, main_function: FuncId, cached_program: Option, force_compile: bool, ) -> Result { - let program = monomorphize(main_function, &context.def_interner); + let program = if options.instrument_debug { + monomorphize_debug(main_function, &mut context.def_interner, &context.debug_instrumenter) + } else { + monomorphize(main_function, &mut context.def_interner) + }; let hash = fxhash::hash64(&program); let hashes_match = cached_program.as_ref().map_or(false, |program| program.hash == hash); @@ -426,7 +460,7 @@ pub fn compile_no_check( } let visibility = program.return_visibility; let (circuit, debug, input_witnesses, return_witnesses, warnings) = - create_circuit(program, options.show_ssa, options.show_brillig)?; + create_circuit(program, options.show_ssa, options.show_brillig, options.force_brillig)?; let abi = abi_gen::gen_abi(context, &main_function, input_witnesses, return_witnesses, visibility); diff --git a/noir/compiler/noirc_errors/Cargo.toml b/noir/compiler/noirc_errors/Cargo.toml index 935137ba2fc..da18399971e 100644 --- a/noir/compiler/noirc_errors/Cargo.toml +++ b/noir/compiler/noirc_errors/Cargo.toml @@ -13,6 +13,7 @@ codespan-reporting.workspace = true codespan.workspace = true fm.workspace = true chumsky.workspace = true +noirc_printable_type.workspace = true serde.workspace = true serde_with = "3.2.0" tracing.workspace = true diff --git a/noir/compiler/noirc_errors/src/debug_info.rs b/noir/compiler/noirc_errors/src/debug_info.rs index ffca8fbf2e1..25722aac57f 100644 --- a/noir/compiler/noirc_errors/src/debug_info.rs +++ b/noir/compiler/noirc_errors/src/debug_info.rs @@ -16,10 +16,26 @@ use std::io::Write; use std::mem; use crate::Location; +use noirc_printable_type::PrintableType; use serde::{ de::Error as DeserializationError, ser::Error as SerializationError, Deserialize, Serialize, }; +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, Deserialize, Serialize)] +pub struct DebugVarId(pub u32); + +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, Deserialize, Serialize)] +pub struct DebugTypeId(pub u32); + +#[derive(Debug, Clone, Hash, Deserialize, Serialize)] +pub struct DebugVariable { + pub name: String, + pub debug_type_id: DebugTypeId, +} + +pub type DebugVariables = BTreeMap; +pub type DebugTypes = BTreeMap; + #[serde_as] #[derive(Default, Debug, Clone, Deserialize, Serialize)] pub struct DebugInfo { @@ -28,6 +44,8 @@ pub struct DebugInfo { /// that they should be serialized to/from strings. #[serde_as(as = "BTreeMap")] pub locations: BTreeMap>, + pub variables: DebugVariables, + pub types: DebugTypes, } /// Holds OpCodes Counts for Acir and Brillig Opcodes @@ -39,8 +57,12 @@ pub struct OpCodesCount { } impl DebugInfo { - pub fn new(locations: BTreeMap>) -> Self { - DebugInfo { locations } + pub fn new( + locations: BTreeMap>, + variables: DebugVariables, + types: DebugTypes, + ) -> Self { + Self { locations, variables, types } } /// Updates the locations map when the [`Circuit`][acvm::acir::circuit::Circuit] is modified. diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs b/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs index e0630655253..65b593b77f5 100644 --- a/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs +++ b/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs @@ -5,6 +5,7 @@ use crate::brillig::brillig_ir::{ BrilligBinaryOp, BrilligContext, BRILLIG_INTEGER_ARITHMETIC_BIT_SIZE, }; use crate::ssa::ir::dfg::CallStack; +use crate::ssa::ir::instruction::ConstrainError; use crate::ssa::ir::{ basic_block::{BasicBlock, BasicBlockId}, dfg::DataFlowGraph, @@ -257,7 +258,30 @@ impl<'block> BrilligBlock<'block> { condition, ); - self.brillig_context.constrain_instruction(condition, assert_message.clone()); + let assert_message = if let Some(error) = assert_message { + match error.as_ref() { + ConstrainError::Static(string) => Some(string.clone()), + ConstrainError::Dynamic(call_instruction) => { + let Instruction::Call { func, arguments } = call_instruction else { + unreachable!("expected a call instruction") + }; + + let Value::Function(func_id) = &dfg[*func] else { + unreachable!("expected a function value") + }; + + self.convert_ssa_function_call(*func_id, arguments, dfg, &[]); + + // Dynamic assert messages are handled in the generated function call. + // We then don't need to attach one to the constrain instruction. + None + } + } + } else { + None + }; + + self.brillig_context.constrain_instruction(condition, assert_message); self.brillig_context.deallocate_register(condition); } Instruction::Allocate => { @@ -368,7 +392,8 @@ impl<'block> BrilligBlock<'block> { } } Value::Function(func_id) => { - self.convert_ssa_function_call(*func_id, arguments, dfg, instruction_id); + let result_ids = dfg.instruction_results(instruction_id); + self.convert_ssa_function_call(*func_id, arguments, dfg, result_ids); } Value::Intrinsic(Intrinsic::BlackBox(bb_func)) => { // Slices are represented as a tuple of (length, slice contents). @@ -640,7 +665,7 @@ impl<'block> BrilligBlock<'block> { func_id: FunctionId, arguments: &[ValueId], dfg: &DataFlowGraph, - instruction_id: InstructionId, + result_ids: &[ValueId], ) { // Convert the arguments to registers casting those to the types of the receiving function let argument_registers: Vec = arguments @@ -648,8 +673,6 @@ impl<'block> BrilligBlock<'block> { .flat_map(|argument_id| self.convert_ssa_value(*argument_id, dfg).extract_registers()) .collect(); - let result_ids = dfg.instruction_results(instruction_id); - // Create label for the function that will be called let label_of_function_to_call = FunctionContext::function_id_to_function_label(func_id); @@ -1233,7 +1256,23 @@ impl<'block> BrilligBlock<'block> { new_variable } } - Value::Function(_) | Value::Intrinsic(_) | Value::ForeignFunction(_) => { + Value::Function(_) => { + // For the debugger instrumentation we want to allow passing + // around values representing function pointers, even though + // there is no interaction with the function possible given that + // value. + let new_variable = + self.variables.allocate_constant(self.brillig_context, value_id, dfg); + let register_index = new_variable.extract_register(); + + self.brillig_context.const_instruction( + register_index, + value_id.to_usize().into(), + 32, + ); + new_variable + } + Value::Intrinsic(_) | Value::ForeignFunction(_) => { todo!("ICE: Cannot convert value {value:?}") } } @@ -1419,6 +1458,8 @@ pub(crate) fn convert_ssa_binary_op_to_brillig_binary_op( BinaryOp::And => BinaryIntOp::And, BinaryOp::Or => BinaryIntOp::Or, BinaryOp::Xor => BinaryIntOp::Xor, + BinaryOp::Shl => BinaryIntOp::Shl, + BinaryOp::Shr => BinaryIntOp::Shr, }; BrilligBinaryOp::Integer { op: operation, bit_size } diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs b/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs index 49d40ca3697..cbb3049a904 100644 --- a/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs +++ b/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs @@ -173,7 +173,10 @@ pub(crate) fn allocate_value( let typ = dfg.type_of_value(value_id); match typ { - Type::Numeric(_) | Type::Reference(_) => { + Type::Numeric(_) | Type::Reference(_) | Type::Function => { + // NB. function references are converted to a constant when + // translating from SSA to Brillig (to allow for debugger + // instrumentation to work properly) let register = brillig_context.allocate_register(); BrilligVariable::Simple(register) } @@ -199,8 +202,5 @@ pub(crate) fn allocate_value( rc: rc_register, }) } - Type::Function => { - unreachable!("ICE: Function values should have been removed from the SSA") - } } } diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_ir.rs b/noir/compiler/noirc_evaluator/src/brillig/brillig_ir.rs index a0e5ca080bd..963b602e7bf 100644 --- a/noir/compiler/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/noir/compiler/noirc_evaluator/src/brillig/brillig_ir.rs @@ -927,8 +927,11 @@ impl BrilligContext { // // This means that the arguments will be in the first `n` registers after // the number of reserved registers. - let (sources, destinations) = + let (sources, destinations): (Vec<_>, Vec<_>) = arguments.iter().enumerate().map(|(i, argument)| (*argument, self.register(i))).unzip(); + destinations + .iter() + .for_each(|destination| self.registers.ensure_register_is_allocated(*destination)); self.mov_registers_to_registers_instruction(sources, destinations); saved_registers } diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs b/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs index 6ee2e0c0b9f..dd57f0c4426 100644 --- a/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs +++ b/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs @@ -74,9 +74,8 @@ impl DebugToString for BinaryIntOp { BinaryIntOp::And => "&&".into(), BinaryIntOp::Or => "||".into(), BinaryIntOp::Xor => "^".into(), - BinaryIntOp::Shl | BinaryIntOp::Shr => { - unreachable!("bit shift should have been replaced") - } + BinaryIntOp::Shl => "<<".into(), + BinaryIntOp::Shr => ">>".into(), } } } diff --git a/noir/compiler/noirc_evaluator/src/errors.rs b/noir/compiler/noirc_evaluator/src/errors.rs index 73b6e671bd5..ed94adac28e 100644 --- a/noir/compiler/noirc_evaluator/src/errors.rs +++ b/noir/compiler/noirc_evaluator/src/errors.rs @@ -46,6 +46,8 @@ pub enum RuntimeError { NestedSlice { call_stack: CallStack }, #[error("Big Integer modulus do no match")] BigIntModulus { call_stack: CallStack }, + #[error("Slices cannot be returned from an unconstrained runtime to a constrained runtime")] + UnconstrainedSliceReturnToConstrained { call_stack: CallStack }, } // We avoid showing the actual lhs and rhs since most of the time they are just 0 @@ -135,7 +137,8 @@ impl RuntimeError { | RuntimeError::IntegerOutOfBounds { call_stack, .. } | RuntimeError::UnsupportedIntegerSize { call_stack, .. } | RuntimeError::NestedSlice { call_stack, .. } - | RuntimeError::BigIntModulus { call_stack, .. } => call_stack, + | RuntimeError::BigIntModulus { call_stack, .. } + | RuntimeError::UnconstrainedSliceReturnToConstrained { call_stack } => call_stack, } } } @@ -160,10 +163,21 @@ impl RuntimeError { noirc_errors::Span::inclusive(0, 0) ) } + RuntimeError::UnknownLoopBound { .. } => { + let primary_message = self.to_string(); + let location = + self.call_stack().back().expect("Expected RuntimeError to have a location"); + + Diagnostic::simple_error( + primary_message, + "If attempting to fetch the length of a slice, try converting to an array. Slices only use dynamic lengths.".to_string(), + location.span, + ) + } _ => { let message = self.to_string(); let location = - self.call_stack().back().expect("Expected RuntimeError to have a location"); + self.call_stack().back().unwrap_or_else(|| panic!("Expected RuntimeError to have a location. Error message: {message}")); Diagnostic::simple_error(message, String::new(), location.span) } diff --git a/noir/compiler/noirc_evaluator/src/ssa.rs b/noir/compiler/noirc_evaluator/src/ssa.rs index e1a2e0d3564..d19c4467235 100644 --- a/noir/compiler/noirc_evaluator/src/ssa.rs +++ b/noir/compiler/noirc_evaluator/src/ssa.rs @@ -40,12 +40,13 @@ pub(crate) fn optimize_into_acir( program: Program, print_ssa_passes: bool, print_brillig_trace: bool, + force_brillig_output: bool, ) -> Result { let abi_distinctness = program.return_distinctness; let ssa_gen_span = span!(Level::TRACE, "ssa_generation"); let ssa_gen_span_guard = ssa_gen_span.enter(); - let ssa = SsaBuilder::new(program, print_ssa_passes)? + let ssa = SsaBuilder::new(program, print_ssa_passes, force_brillig_output)? .run_pass(Ssa::defunctionalize, "After Defunctionalization:") .run_pass(Ssa::inline_functions, "After Inlining:") // Run mem2reg with the CFG separated into blocks @@ -59,9 +60,14 @@ pub(crate) fn optimize_into_acir( // and this pass is missed, slice merging will fail inside of flattening. .run_pass(Ssa::mem2reg, "After Mem2Reg:") .run_pass(Ssa::flatten_cfg, "After Flattening:") + .run_pass(Ssa::remove_bit_shifts, "After Removing Bit Shifts:") // Run mem2reg once more with the flattened CFG to catch any remaining loads/stores .run_pass(Ssa::mem2reg, "After Mem2Reg:") .run_pass(Ssa::fold_constants, "After Constant Folding:") + .run_pass( + Ssa::fold_constants_using_constraints, + "After Constant Folding With Constraint Info:", + ) .run_pass(Ssa::dead_instruction_elimination, "After Dead Instruction Elimination:") .finish(); @@ -83,11 +89,18 @@ pub fn create_circuit( program: Program, enable_ssa_logging: bool, enable_brillig_logging: bool, + force_brillig_output: bool, ) -> Result<(Circuit, DebugInfo, Vec, Vec, Vec), RuntimeError> { + let debug_variables = program.debug_variables.clone(); + let debug_types = program.debug_types.clone(); let func_sig = program.main_function_signature.clone(); let recursive = program.recursive; - let mut generated_acir = - optimize_into_acir(program, enable_ssa_logging, enable_brillig_logging)?; + let mut generated_acir = optimize_into_acir( + program, + enable_ssa_logging, + enable_brillig_logging, + force_brillig_output, + )?; let opcodes = generated_acir.take_opcodes(); let current_witness_index = generated_acir.current_witness_index().0; let GeneratedAcir { @@ -122,7 +135,7 @@ pub fn create_circuit( .map(|(index, locations)| (index, locations.into_iter().collect())) .collect(); - let mut debug_info = DebugInfo::new(locations); + let mut debug_info = DebugInfo::new(locations, debug_variables, debug_types); // Perform any ACIR-level optimizations let (optimized_circuit, transformation_map) = acvm::compiler::optimize(circuit); @@ -172,8 +185,12 @@ struct SsaBuilder { } impl SsaBuilder { - fn new(program: Program, print_ssa_passes: bool) -> Result { - let ssa = ssa_gen::generate_ssa(program)?; + fn new( + program: Program, + print_ssa_passes: bool, + force_brillig_runtime: bool, + ) -> Result { + let ssa = ssa_gen::generate_ssa(program, force_brillig_runtime)?; Ok(SsaBuilder { print_ssa_passes, ssa }.print("Initial SSA:")) } diff --git a/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir.rs b/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir.rs index 1ddbae0f339..090d5bb0a83 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir.rs @@ -1,4 +1,3 @@ pub(crate) mod acir_variable; pub(crate) mod big_int; pub(crate) mod generated_acir; -pub(crate) mod sort; diff --git a/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs b/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs index 94e62e76746..912447721cd 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs @@ -319,6 +319,7 @@ impl AcirContext { vec![AcirValue::Var(var, AcirType::field())], vec![AcirType::field()], true, + false, )?; let inverted_var = Self::expect_one_var(results); @@ -631,18 +632,22 @@ impl AcirContext { bit_size: u32, predicate: AcirVar, ) -> Result<(AcirVar, AcirVar), RuntimeError> { - // 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)); - } + let one = self.add_constant(FieldElement::one()); + + let lhs_expr = self.var_to_expression(lhs)?; + let rhs_expr = self.var_to_expression(rhs)?; + let predicate_expr = self.var_to_expression(predicate)?; + + match (lhs_expr.to_const(), rhs_expr.to_const(), predicate_expr.to_const()) { + // If predicate is zero, `quotient_var` and `remainder_var` will be 0. + (_, _, Some(predicate_const)) if predicate_const.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() => { + (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(); @@ -652,36 +657,29 @@ impl AcirContext { } // If `rhs` is one then the division is a noop. - (_, Some(rhs_const)) if rhs_const == FieldElement::one() => { + (_, 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()); + // After this point, we cannot perform the division at compile-time. + // + // We need to check that the rhs is not zero, otherwise when executing the brillig quotient, + // we may attempt to divide by zero and cause a VM panic. + // + // When the predicate is 0, the division always succeeds (as it is skipped). + // When the predicate is 1, the rhs must not be 0. - let rhs_expr = self.var_to_expression(rhs)?; - 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)?; - } + // If the predicate is known to be active, we simply assert that an inverse must exist. + // This implies that `rhs != 0`. + (_, _, Some(predicate_const)) if predicate_const.is_one() => { + let _inverse = self.inv_var(rhs, one)?; + } - _ => { - // 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)?; - } + // Otherwise we must handle both potential cases. + _ => { + let rhs_is_zero = self.eq_var(rhs, zero)?; + let rhs_is_zero_and_predicate_active = self.mul_var(rhs_is_zero, predicate)?; + self.assert_eq_var(rhs_is_zero_and_predicate_active, zero, None)?; } } @@ -689,7 +687,7 @@ impl AcirContext { 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() { + if let Some(rhs_const) = rhs_expr.to_const() { max_rhs_bits = rhs_const.num_bits(); if max_rhs_bits != 0 { if max_rhs_bits > bit_size { @@ -699,18 +697,6 @@ impl AcirContext { } } - // 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, @@ -721,6 +707,7 @@ impl AcirContext { ], vec![AcirType::unsigned(max_q_bits), AcirType::unsigned(max_rhs_bits)], true, + false, )? .try_into() .expect("quotient only returns two values"); @@ -761,7 +748,19 @@ impl AcirContext { 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() { + // 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_expr.is_const() { + avoid_overflow = true; + } else { + // we do not support unbounded division + unreachable!("overflow in unbounded division"); + } + } + + if let Some(rhs_const) = rhs_expr.to_const() { if avoid_overflow { // we compute q0 = p/rhs let rhs_big = BigUint::from_bytes_be(&rhs_const.to_be_bytes()); @@ -1442,6 +1441,7 @@ impl AcirContext { inputs: Vec, outputs: Vec, attempt_execution: bool, + unsafe_return_values: bool, ) -> Result, RuntimeError> { let b_inputs = try_vecmap(inputs, |i| -> Result<_, InternalError> { match i { @@ -1514,10 +1514,13 @@ impl AcirContext { Ok(()) } - for output_var in &outputs_var { - range_constraint_value(self, output_var)?; + // This is a hack to ensure that if we're compiling a brillig entrypoint function then + // we don't also add a number of range constraints. + if !unsafe_return_values { + for output_var in &outputs_var { + range_constraint_value(self, output_var)?; + } } - Ok(outputs_var) } @@ -1634,50 +1637,6 @@ impl AcirContext { AcirValue::Array(array_values) } - /// Generate output variables that are constrained to be the sorted inputs - /// The outputs are the sorted inputs iff - /// outputs are sorted and - /// outputs are a permutation of the inputs - pub(crate) fn sort( - &mut self, - inputs: Vec, - bit_size: u32, - predicate: AcirVar, - ) -> Result, RuntimeError> { - let len = inputs.len(); - // Convert the inputs into expressions - let inputs_expr = try_vecmap(inputs, |input| self.var_to_expression(input))?; - // Generate output witnesses - let outputs_witness = vecmap(0..len, |_| self.acir_ir.next_witness_index()); - let output_expr = - vecmap(&outputs_witness, |witness_index| Expression::from(*witness_index)); - let outputs_var = vecmap(&outputs_witness, |witness_index| { - self.add_data(AcirVarData::Witness(*witness_index)) - }); - - // Enforce the outputs to be a permutation of the inputs - self.acir_ir.permutation(&inputs_expr, &output_expr)?; - - // Enforce the outputs to be sorted - for i in 0..(outputs_var.len() - 1) { - self.less_than_constrain(outputs_var[i], outputs_var[i + 1], bit_size, predicate)?; - } - - Ok(outputs_var) - } - - /// Constrain lhs to be less than rhs - fn less_than_constrain( - &mut self, - lhs: AcirVar, - rhs: AcirVar, - bit_size: u32, - predicate: AcirVar, - ) -> Result<(), RuntimeError> { - let lhs_less_than_rhs = self.more_than_eq_var(rhs, lhs, bit_size)?; - self.maybe_eq_predicate(lhs_less_than_rhs, predicate) - } - /// Returns a Variable that is constrained to be the result of reading /// from the memory `block_id` at the given `index`. pub(crate) fn read_from_memory( diff --git a/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs b/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs index 4d88a449e1c..1d05e998b13 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs @@ -74,6 +74,10 @@ impl GeneratedAcir { } } + pub(crate) fn opcodes(&self) -> &[AcirOpcode] { + &self.opcodes + } + pub(crate) fn take_opcodes(&mut self) -> Vec { std::mem::take(&mut self.opcodes) } @@ -563,40 +567,6 @@ impl GeneratedAcir { } } - /// Generate gates and control bits witnesses which ensure that out_expr is a permutation of in_expr - /// Add the control bits of the sorting network used to generate the constrains - /// into the PermutationSort directive for solving in ACVM. - /// The directive is solving the control bits so that the outputs are sorted in increasing order. - /// - /// n.b. A sorting network is a predetermined set of switches, - /// the control bits indicate the configuration of each switch: false for pass-through and true for cross-over - pub(crate) fn permutation( - &mut self, - in_expr: &[Expression], - out_expr: &[Expression], - ) -> Result<(), RuntimeError> { - let mut bits_len = 0; - for i in 0..in_expr.len() { - bits_len += ((i + 1) as f32).log2().ceil() as u32; - } - - let bits = vecmap(0..bits_len, |_| self.next_witness_index()); - let inputs = in_expr.iter().map(|a| vec![a.clone()]).collect(); - self.push_opcode(AcirOpcode::Directive(Directive::PermutationSort { - inputs, - tuple: 1, - bits: bits.clone(), - sort_by: vec![0], - })); - let (_, b) = self.permutation_layer(in_expr, &bits, false)?; - - // Constrain the network output to out_expr - for (b, o) in b.iter().zip(out_expr) { - self.push_opcode(AcirOpcode::AssertZero(b - o)); - } - Ok(()) - } - pub(crate) fn last_acir_opcode_location(&self) -> OpcodeLocation { OpcodeLocation::Acir(self.opcodes.len() - 1) } diff --git a/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/sort.rs b/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/sort.rs deleted file mode 100644 index 52640d32337..00000000000 --- a/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/sort.rs +++ /dev/null @@ -1,88 +0,0 @@ -use crate::errors::InternalError; - -use super::generated_acir::GeneratedAcir; -use acvm::acir::native_types::{Expression, Witness}; - -impl GeneratedAcir { - // Generates gates for a sorting network - // returns witness corresponding to the network configuration and the expressions corresponding to the network output - // in_expr: inputs of the sorting network - // if generate_witness is false, it uses the witness provided in bits instead of generating them - // in both cases it returns the witness of the network configuration - // if generate_witness is true, bits is ignored - pub(crate) fn permutation_layer( - &mut self, - in_expr: &[Expression], - bits: &[Witness], - generate_witness: bool, - ) -> Result<(Vec, Vec), InternalError> { - let n = in_expr.len(); - if n == 1 { - return Ok((Vec::new(), in_expr.to_vec())); - } - let n1 = n / 2; - - // witness for the input switches - let mut conf = iter_extended::vecmap(0..n1, |i| { - if generate_witness { - self.next_witness_index() - } else { - bits[i] - } - }); - - // compute expressions after the input switches - // If inputs are a1,a2, and the switch value is c, then we compute expressions b1,b2 where - // b1 = a1+q, b2 = a2-q, q = c(a2-a1) - let mut in_sub1 = Vec::new(); - let mut in_sub2 = Vec::new(); - for i in 0..n1 { - //q = c*(a2-a1); - let intermediate = self.mul_with_witness( - &Expression::from(conf[i]), - &(&in_expr[2 * i + 1] - &in_expr[2 * i]), - ); - //b1=a1+q - in_sub1.push(&intermediate + &in_expr[2 * i]); - //b2=a2-q - in_sub2.push(&in_expr[2 * i + 1] - &intermediate); - } - if n % 2 == 1 { - in_sub2.push(match in_expr.last() { - Some(in_expr) => in_expr.clone(), - None => { - return Err(InternalError::EmptyArray { call_stack: self.call_stack.clone() }) - } - }); - } - let mut out_expr = Vec::new(); - // compute results for the sub networks - let bits1 = if generate_witness { bits } else { &bits[n1 + (n - 1) / 2..] }; - let (w1, b1) = self.permutation_layer(&in_sub1, bits1, generate_witness)?; - let bits2 = if generate_witness { bits } else { &bits[n1 + (n - 1) / 2 + w1.len()..] }; - let (w2, b2) = self.permutation_layer(&in_sub2, bits2, generate_witness)?; - // apply the output switches - for i in 0..(n - 1) / 2 { - let c = if generate_witness { self.next_witness_index() } else { bits[n1 + i] }; - conf.push(c); - let intermediate = self.mul_with_witness(&Expression::from(c), &(&b2[i] - &b1[i])); - out_expr.push(&intermediate + &b1[i]); - out_expr.push(&b2[i] - &intermediate); - } - if n % 2 == 0 { - out_expr.push(match b1.last() { - Some(b1) => b1.clone(), - None => { - return Err(InternalError::EmptyArray { call_stack: self.call_stack.clone() }) - } - }); - } - out_expr.push(match b2.last() { - Some(b2) => b2.clone(), - None => return Err(InternalError::EmptyArray { call_stack: self.call_stack.clone() }), - }); - conf.extend(w1); - conf.extend(w2); - Ok((conf, out_expr)) - } -} diff --git a/noir/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs b/noir/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs index 120c5bf25df..9603377a107 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs @@ -7,6 +7,7 @@ use std::fmt::Debug; use self::acir_ir::acir_variable::{AcirContext, AcirType, AcirVar}; use super::function_builder::data_bus::DataBus; use super::ir::dfg::CallStack; +use super::ir::instruction::ConstrainError; use super::{ ir::{ dfg::DataFlowGraph, @@ -269,6 +270,7 @@ impl Context { inputs, outputs, false, + true, )?; let output_vars: Vec<_> = output_values .iter() @@ -279,7 +281,16 @@ impl Context { for acir_var in output_vars { self.acir_context.return_var(acir_var)?; } - Ok(self.acir_context.finish(witness_inputs, Vec::new())) + + let generated_acir = self.acir_context.finish(witness_inputs, Vec::new()); + + assert_eq!( + generated_acir.opcodes().len(), + 1, + "Unconstrained programs should only generate a single opcode but multiple were emitted" + ); + + Ok(generated_acir) } /// Adds and binds `AcirVar`s for each numeric block parameter or block parameter array element. @@ -413,15 +424,94 @@ impl Context { let lhs = self.convert_numeric_value(*lhs, dfg)?; let rhs = self.convert_numeric_value(*rhs, dfg)?; - self.acir_context.assert_eq_var(lhs, rhs, assert_message.clone())?; + let assert_message = if let Some(error) = assert_message { + match error.as_ref() { + ConstrainError::Static(string) => Some(string.clone()), + ConstrainError::Dynamic(call_instruction) => { + self.convert_ssa_call(call_instruction, dfg, ssa, brillig, &[])?; + None + } + } + } else { + None + }; + + self.acir_context.assert_eq_var(lhs, rhs, assert_message)?; } Instruction::Cast(value_id, _) => { let acir_var = self.convert_numeric_value(*value_id, dfg)?; self.define_result_var(dfg, instruction_id, acir_var); } - Instruction::Call { func, arguments } => { + Instruction::Call { .. } => { let result_ids = dfg.instruction_results(instruction_id); - match &dfg[*func] { + warnings.extend(self.convert_ssa_call( + instruction, + dfg, + ssa, + brillig, + result_ids, + )?); + } + Instruction::Not(value_id) => { + let (acir_var, typ) = match self.convert_value(*value_id, dfg) { + AcirValue::Var(acir_var, typ) => (acir_var, typ), + _ => unreachable!("NOT is only applied to numerics"), + }; + let result_acir_var = self.acir_context.not_var(acir_var, typ)?; + self.define_result_var(dfg, instruction_id, result_acir_var); + } + Instruction::Truncate { value, bit_size, max_bit_size } => { + let result_acir_var = + self.convert_ssa_truncate(*value, *bit_size, *max_bit_size, dfg)?; + self.define_result_var(dfg, instruction_id, result_acir_var); + } + Instruction::EnableSideEffects { condition } => { + let acir_var = self.convert_numeric_value(*condition, dfg)?; + self.current_side_effects_enabled_var = acir_var; + } + Instruction::ArrayGet { .. } | Instruction::ArraySet { .. } => { + self.handle_array_operation(instruction_id, dfg, last_array_uses)?; + } + Instruction::Allocate => { + unreachable!("Expected all allocate instructions to be removed before acir_gen") + } + Instruction::Store { .. } => { + unreachable!("Expected all store instructions to be removed before acir_gen") + } + Instruction::Load { .. } => { + unreachable!("Expected all load instructions to be removed before acir_gen") + } + Instruction::IncrementRc { .. } => { + // Do nothing. Only Brillig needs to worry about reference counted arrays + } + Instruction::RangeCheck { value, max_bit_size, assert_message } => { + let acir_var = self.convert_numeric_value(*value, dfg)?; + self.acir_context.range_constrain_var( + acir_var, + &NumericType::Unsigned { bit_size: *max_bit_size }, + assert_message.clone(), + )?; + } + } + + self.acir_context.set_call_stack(CallStack::new()); + Ok(warnings) + } + + fn convert_ssa_call( + &mut self, + instruction: &Instruction, + dfg: &DataFlowGraph, + ssa: &Ssa, + brillig: &Brillig, + result_ids: &[ValueId], + ) -> Result, RuntimeError> { + let mut warnings = Vec::new(); + + match instruction { + Instruction::Call { func, arguments } => { + let function_value = &dfg[*func]; + match function_value { Value::Function(id) => { let func = &ssa.functions[id]; match func.runtime() { @@ -429,13 +519,21 @@ impl Context { "expected an intrinsic/brillig call, but found {func:?}. All ACIR methods should be inlined" ), RuntimeType::Brillig => { + // Check that we are not attempting to return a slice from + // an unconstrained runtime to a constrained runtime + for result_id in result_ids { + if dfg.type_of_value(*result_id).contains_slice_element() { + return Err(RuntimeError::UnconstrainedSliceReturnToConstrained { call_stack: self.acir_context.get_call_stack() }) + } + } + let inputs = vecmap(arguments, |arg| self.convert_value(*arg, dfg)); let code = self.gen_brillig_for(func, brillig)?; let outputs: Vec = vecmap(result_ids, |result_id| dfg.type_of_value(*result_id).into()); - let output_values = self.acir_context.brillig(self.current_side_effects_enabled_var, code, inputs, outputs, true)?; + let output_values = self.acir_context.brillig(self.current_side_effects_enabled_var, code, inputs, outputs, true, false)?; // Compiler sanity check assert_eq!(result_ids.len(), output_values.len(), "ICE: The number of Brillig output values should match the result ids in SSA"); @@ -495,51 +593,11 @@ impl Context { Value::ForeignFunction(_) => unreachable!( "All `oracle` methods should be wrapped in an unconstrained fn" ), - _ => unreachable!("expected calling a function"), + _ => unreachable!("expected calling a function but got {function_value:?}"), } } - Instruction::Not(value_id) => { - let (acir_var, typ) = match self.convert_value(*value_id, dfg) { - AcirValue::Var(acir_var, typ) => (acir_var, typ), - _ => unreachable!("NOT is only applied to numerics"), - }; - let result_acir_var = self.acir_context.not_var(acir_var, typ)?; - self.define_result_var(dfg, instruction_id, result_acir_var); - } - Instruction::Truncate { value, bit_size, max_bit_size } => { - let result_acir_var = - self.convert_ssa_truncate(*value, *bit_size, *max_bit_size, dfg)?; - self.define_result_var(dfg, instruction_id, result_acir_var); - } - Instruction::EnableSideEffects { condition } => { - let acir_var = self.convert_numeric_value(*condition, dfg)?; - self.current_side_effects_enabled_var = acir_var; - } - Instruction::ArrayGet { .. } | Instruction::ArraySet { .. } => { - self.handle_array_operation(instruction_id, dfg, last_array_uses)?; - } - Instruction::Allocate => { - unreachable!("Expected all allocate instructions to be removed before acir_gen") - } - Instruction::Store { .. } => { - unreachable!("Expected all store instructions to be removed before acir_gen") - } - Instruction::Load { .. } => { - unreachable!("Expected all load instructions to be removed before acir_gen") - } - Instruction::IncrementRc { .. } => { - // Do nothing. Only Brillig needs to worry about reference counted arrays - } - Instruction::RangeCheck { value, max_bit_size, assert_message } => { - let acir_var = self.convert_numeric_value(*value, dfg)?; - self.acir_context.range_constrain_var( - acir_var, - &NumericType::Unsigned { bit_size: *max_bit_size }, - assert_message.clone(), - )?; - } + _ => unreachable!("expected calling a call instruction"), } - self.acir_context.set_call_stack(CallStack::new()); Ok(warnings) } @@ -621,11 +679,11 @@ impl Context { instruction: InstructionId, dfg: &DataFlowGraph, index: ValueId, - array: ValueId, + array_id: ValueId, store_value: Option, ) -> Result { let index_const = dfg.get_numeric_constant(index); - let value_type = dfg.type_of_value(array); + let value_type = dfg.type_of_value(array_id); // Compiler sanity checks assert!( !value_type.is_nested_slice(), @@ -635,7 +693,7 @@ impl Context { unreachable!("ICE: expected array or slice type"); }; - match self.convert_value(array, dfg) { + match self.convert_value(array_id, dfg) { AcirValue::Var(acir_var, _) => { return Err(RuntimeError::InternalError(InternalError::Unexpected { expected: "an array value".to_string(), @@ -1328,7 +1386,13 @@ impl Context { AcirValue::Array(elements.collect()) } Value::Intrinsic(..) => todo!(), - Value::Function(..) => unreachable!("ICE: All functions should have been inlined"), + Value::Function(function_id) => { + // This conversion is for debugging support only, to allow the + // debugging instrumentation code to work. Taking the reference + // of a function in ACIR is useless. + let id = self.acir_context.add_constant(function_id.to_usize()); + AcirValue::Var(id, AcirType::field()) + } Value::ForeignFunction(_) => unimplemented!( "Oracle calls directly in constrained functions are not yet available." ), @@ -1419,6 +1483,9 @@ impl Context { bit_count, self.current_side_effects_enabled_var, ), + BinaryOp::Shl | BinaryOp::Shr => unreachable!( + "ICE - bit shift operators do not exist in ACIR and should have been replaced" + ), } } @@ -1563,33 +1630,6 @@ impl Context { self.acir_context.bit_decompose(endian, field, bit_size, result_type) } - Intrinsic::Sort => { - let inputs = vecmap(arguments, |arg| self.convert_value(*arg, dfg)); - // We flatten the inputs and retrieve the bit_size of the elements - let mut input_vars = Vec::new(); - let mut bit_size = 0; - for input in inputs { - for (var, typ) in input.flatten() { - input_vars.push(var); - if bit_size == 0 { - bit_size = typ.bit_size(); - } else { - assert_eq!( - bit_size, - typ.bit_size(), - "cannot sort element of different bit size" - ); - } - } - } - // Generate the sorted output variables - let out_vars = self - .acir_context - .sort(input_vars, bit_size, self.current_side_effects_enabled_var) - .expect("Could not sort"); - - Ok(self.convert_vars_to_values(out_vars, dfg, result_ids)) - } Intrinsic::ArrayLen => { let len = match self.convert_value(arguments[0], dfg) { AcirValue::Var(_, _) => unreachable!("Non-array passed to array.len() method"), diff --git a/noir/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs b/noir/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs index 44be423be10..9e17595a033 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs @@ -18,8 +18,7 @@ use super::{ basic_block::BasicBlock, dfg::{CallStack, InsertInstructionResult}, function::RuntimeType, - instruction::{Endian, InstructionId, Intrinsic}, - types::NumericType, + instruction::{ConstrainError, InstructionId, Intrinsic}, }, ssa_gen::Ssa, }; @@ -250,7 +249,7 @@ impl FunctionBuilder { &mut self, lhs: ValueId, rhs: ValueId, - assert_message: Option, + assert_message: Option>, ) { self.insert_instruction(Instruction::Constrain(lhs, rhs, assert_message), None); } @@ -279,108 +278,6 @@ impl FunctionBuilder { self.insert_instruction(Instruction::Call { func, arguments }, Some(result_types)).results() } - /// Insert ssa instructions which computes lhs << rhs by doing lhs*2^rhs - /// and truncate the result to bit_size - pub(crate) fn insert_wrapping_shift_left( - &mut self, - lhs: ValueId, - rhs: ValueId, - bit_size: u32, - ) -> ValueId { - let base = self.field_constant(FieldElement::from(2_u128)); - let typ = self.current_function.dfg.type_of_value(lhs); - let (max_bit, pow) = - if let Some(rhs_constant) = self.current_function.dfg.get_numeric_constant(rhs) { - // Happy case is that we know precisely by how many bits the the integer will - // increase: lhs_bit_size + rhs - let bit_shift_size = rhs_constant.to_u128() as u32; - - let (rhs_bit_size_pow_2, overflows) = 2_u128.overflowing_pow(bit_shift_size); - if overflows { - assert!(bit_size < 128, "ICE - shift left with big integers are not supported"); - if bit_size < 128 { - let zero = self.numeric_constant(FieldElement::zero(), typ); - return InsertInstructionResult::SimplifiedTo(zero).first(); - } - } - let pow = self.numeric_constant(FieldElement::from(rhs_bit_size_pow_2), typ); - - let max_lhs_bits = self.current_function.dfg.get_value_max_num_bits(lhs); - - (max_lhs_bits + bit_shift_size, pow) - } else { - // we use a predicate to nullify the result in case of overflow - let bit_size_var = - self.numeric_constant(FieldElement::from(bit_size as u128), typ.clone()); - let overflow = self.insert_binary(rhs, BinaryOp::Lt, bit_size_var); - let predicate = self.insert_cast(overflow, typ.clone()); - // we can safely cast to unsigned because overflow_checks prevent bit-shift with a negative value - let rhs_unsigned = self.insert_cast(rhs, Type::unsigned(bit_size)); - let pow = self.pow(base, rhs_unsigned); - let pow = self.insert_cast(pow, typ); - (FieldElement::max_num_bits(), self.insert_binary(predicate, BinaryOp::Mul, pow)) - }; - - if max_bit <= bit_size { - self.insert_binary(lhs, BinaryOp::Mul, pow) - } else { - let result = self.insert_binary(lhs, BinaryOp::Mul, pow); - self.insert_truncate(result, bit_size, max_bit) - } - } - - /// Insert ssa instructions which computes lhs >> rhs by doing lhs/2^rhs - pub(crate) fn insert_shift_right( - &mut self, - lhs: ValueId, - rhs: ValueId, - bit_size: u32, - ) -> ValueId { - let base = self.field_constant(FieldElement::from(2_u128)); - // we can safely cast to unsigned because overflow_checks prevent bit-shift with a negative value - let rhs_unsigned = self.insert_cast(rhs, Type::unsigned(bit_size)); - let pow = self.pow(base, rhs_unsigned); - self.insert_binary(lhs, BinaryOp::Div, pow) - } - - /// Computes lhs^rhs via square&multiply, using the bits decomposition of rhs - /// Pseudo-code of the computation: - /// let mut r = 1; - /// let rhs_bits = to_bits(rhs); - /// for i in 1 .. bit_size + 1 { - /// let r_squared = r * r; - /// let b = rhs_bits[bit_size - i]; - /// r = (r_squared * lhs * b) + (1 - b) * r_squared; - /// } - pub(crate) fn pow(&mut self, lhs: ValueId, rhs: ValueId) -> ValueId { - let typ = self.current_function.dfg.type_of_value(rhs); - if let Type::Numeric(NumericType::Unsigned { bit_size }) = typ { - let to_bits = self.import_intrinsic_id(Intrinsic::ToBits(Endian::Little)); - let length = self.field_constant(FieldElement::from(bit_size as i128)); - let result_types = - vec![Type::field(), Type::Array(Rc::new(vec![Type::bool()]), bit_size as usize)]; - let rhs_bits = self.insert_call(to_bits, vec![rhs, length], result_types); - let rhs_bits = rhs_bits[1]; - let one = self.field_constant(FieldElement::one()); - let mut r = one; - for i in 1..bit_size + 1 { - let r_squared = self.insert_binary(r, BinaryOp::Mul, r); - let a = self.insert_binary(r_squared, BinaryOp::Mul, lhs); - let idx = self.field_constant(FieldElement::from((bit_size - i) as i128)); - let b = self.insert_array_get(rhs_bits, idx, Type::bool()); - let not_b = self.insert_not(b); - let b = self.insert_cast(b, Type::field()); - let not_b = self.insert_cast(not_b, Type::field()); - let r1 = self.insert_binary(a, BinaryOp::Mul, b); - let r2 = self.insert_binary(r_squared, BinaryOp::Mul, not_b); - r = self.insert_binary(r1, BinaryOp::Add, r2); - } - r - } else { - unreachable!("Value must be unsigned in power operation"); - } - } - /// Insert an instruction to extract an element from an array pub(crate) fn insert_array_get( &mut self, diff --git a/noir/compiler/noirc_evaluator/src/ssa/ir/instruction.rs b/noir/compiler/noirc_evaluator/src/ssa/ir/instruction.rs index 331a02a6974..0b6c7074e45 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/ir/instruction.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/ir/instruction.rs @@ -36,7 +36,6 @@ pub(crate) type InstructionId = Id; /// of this is println. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub(crate) enum Intrinsic { - Sort, ArrayLen, AssertConstant, SlicePushBack, @@ -57,7 +56,6 @@ pub(crate) enum Intrinsic { impl std::fmt::Display for Intrinsic { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Intrinsic::Sort => write!(f, "arraysort"), Intrinsic::ArrayLen => write!(f, "array_len"), Intrinsic::AssertConstant => write!(f, "assert_constant"), Intrinsic::SlicePushBack => write!(f, "slice_push_back"), @@ -90,8 +88,7 @@ impl Intrinsic { // These apply a constraint that the input must fit into a specified number of limbs. Intrinsic::ToBits(_) | Intrinsic::ToRadix(_) => true, - Intrinsic::Sort - | Intrinsic::ArrayLen + Intrinsic::ArrayLen | Intrinsic::SlicePushBack | Intrinsic::SlicePushFront | Intrinsic::SlicePopBack @@ -111,7 +108,6 @@ impl Intrinsic { /// If there is no such intrinsic by that name, None is returned. pub(crate) fn lookup(name: &str) -> Option { match name { - "arraysort" => Some(Intrinsic::Sort), "array_len" => Some(Intrinsic::ArrayLen), "assert_constant" => Some(Intrinsic::AssertConstant), "apply_range_constraint" => Some(Intrinsic::ApplyRangeConstraint), @@ -157,7 +153,7 @@ pub(crate) enum Instruction { Truncate { value: ValueId, bit_size: u32, max_bit_size: u32 }, /// Constrains two values to be equal to one another. - Constrain(ValueId, ValueId, Option), + Constrain(ValueId, ValueId, Option>), /// Range constrain `value` to `max_bit_size` RangeCheck { value: ValueId, max_bit_size: u32, assert_message: Option }, @@ -326,7 +322,17 @@ impl Instruction { max_bit_size: *max_bit_size, }, Instruction::Constrain(lhs, rhs, assert_message) => { - Instruction::Constrain(f(*lhs), f(*rhs), assert_message.clone()) + // Must map the `lhs` and `rhs` first as the value `f` is moved with the closure + let lhs = f(*lhs); + let rhs = f(*rhs); + let assert_message = assert_message.as_ref().map(|error| match error.as_ref() { + ConstrainError::Dynamic(call_instr) => { + let new_instr = call_instr.map_values(f); + Box::new(ConstrainError::Dynamic(new_instr)) + } + _ => error.clone(), + }); + Instruction::Constrain(lhs, rhs, assert_message) } Instruction::Call { func, arguments } => Instruction::Call { func: f(*func), @@ -376,9 +382,14 @@ impl Instruction { | Instruction::Load { address: value } => { f(*value); } - Instruction::Constrain(lhs, rhs, _) => { + Instruction::Constrain(lhs, rhs, assert_error) => { f(*lhs); f(*rhs); + if let Some(error) = assert_error.as_ref() { + if let ConstrainError::Dynamic(call_instr) = error.as_ref() { + call_instr.for_each_value(f); + } + } } Instruction::Store { address, value } => { @@ -425,9 +436,10 @@ impl Instruction { // Limit optimizing ! on constants to only booleans. If we tried it on fields, // there is no Not on FieldElement, so we'd need to convert between u128. This // would be incorrect however since the extra bits on the field would not be flipped. - Value::NumericConstant { constant, typ } if *typ == Type::bool() => { - let value = constant.is_zero() as u128; - SimplifiedTo(dfg.make_constant(value.into(), Type::bool())) + Value::NumericConstant { constant, typ } if typ.is_unsigned() => { + // As we're casting to a `u128`, we need to clear out any upper bits that the NOT fills. + let value = !constant.to_u128() % (1 << typ.bit_size()); + SimplifiedTo(dfg.make_constant(value.into(), typ.clone())) } Value::Instruction { instruction, .. } => { // !!v => v @@ -441,7 +453,7 @@ impl Instruction { } } Instruction::Constrain(lhs, rhs, msg) => { - let constraints = decompose_constrain(*lhs, *rhs, msg.clone(), dfg); + let constraints = decompose_constrain(*lhs, *rhs, msg, dfg); if constraints.is_empty() { Remove } else { @@ -475,6 +487,9 @@ impl Instruction { None } Instruction::Truncate { value, bit_size, max_bit_size } => { + if bit_size == max_bit_size { + return SimplifiedTo(*value); + } if let Some((numeric_constant, typ)) = dfg.get_numeric_constant_with_type(*value) { let integer_modulus = 2_u128.pow(*bit_size); let truncated = numeric_constant.to_u128() % integer_modulus; @@ -551,6 +566,28 @@ impl Instruction { } } +#[derive(Debug, PartialEq, Eq, Hash, Clone)] +pub(crate) enum ConstrainError { + // These are errors which have been hardcoded during SSA gen + Static(String), + // These are errors which come from runtime expressions specified by a Noir program + // We store an `Instruction` as we want this Instruction to be atomic in SSA with + // a constrain instruction, and leave codegen of this instruction to lower level passes. + Dynamic(Instruction), +} + +impl From for ConstrainError { + fn from(value: String) -> Self { + ConstrainError::Static(value) + } +} + +impl From for Box { + fn from(value: String) -> Self { + Box::new(value.into()) + } +} + /// The possible return values for Instruction::return_types pub(crate) enum InstructionResultType { /// The result type of this instruction matches that of this operand diff --git a/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/binary.rs b/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/binary.rs index 1cb32d94148..552be9420d9 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/binary.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/binary.rs @@ -38,6 +38,10 @@ pub(crate) enum BinaryOp { Or, /// Bitwise xor (^) Xor, + /// Bitshift left (<<) + Shl, + /// Bitshift right (>>) + Shr, } impl std::fmt::Display for BinaryOp { @@ -53,6 +57,8 @@ impl std::fmt::Display for BinaryOp { BinaryOp::And => write!(f, "and"), BinaryOp::Or => write!(f, "or"), BinaryOp::Xor => write!(f, "xor"), + BinaryOp::Shl => write!(f, "shl"), + BinaryOp::Shr => write!(f, "shr"), } } } @@ -215,7 +221,27 @@ impl Binary { return SimplifyResult::SimplifiedTo(zero); } } - } + BinaryOp::Shl => return SimplifyResult::None, + BinaryOp::Shr => { + // Bit shifts by constants can be treated as divisions. + if let Some(rhs_const) = rhs { + if rhs_const >= FieldElement::from(operand_type.bit_size() as u128) { + // Shifting by the full width of the operand type, any `lhs` goes to zero. + let zero = dfg.make_constant(FieldElement::zero(), operand_type); + return SimplifyResult::SimplifiedTo(zero); + } + + // `two_pow_rhs` is limited to be at most `2 ^ {operand_bitsize - 1}` so it fits in `operand_type`. + let two_pow_rhs = FieldElement::from(2u128).pow(&rhs_const); + let two_pow_rhs = dfg.make_constant(two_pow_rhs, operand_type); + return SimplifyResult::SimplifiedToInstruction(Instruction::binary( + BinaryOp::Div, + self.lhs, + two_pow_rhs, + )); + } + } + }; SimplifyResult::None } } @@ -314,6 +340,8 @@ impl BinaryOp { BinaryOp::And => None, BinaryOp::Or => None, BinaryOp::Xor => None, + BinaryOp::Shl => None, + BinaryOp::Shr => None, } } @@ -329,6 +357,8 @@ impl BinaryOp { BinaryOp::Xor => |x, y| Some(x ^ y), BinaryOp::Eq => |x, y| Some((x == y) as u128), BinaryOp::Lt => |x, y| Some((x < y) as u128), + BinaryOp::Shl => |x, y| Some(x << y), + BinaryOp::Shr => |x, y| Some(x >> y), } } @@ -344,6 +374,8 @@ impl BinaryOp { BinaryOp::Xor => |x, y| Some(x ^ y), BinaryOp::Eq => |x, y| Some((x == y) as i128), BinaryOp::Lt => |x, y| Some((x < y) as i128), + BinaryOp::Shl => |x, y| Some(x << y), + BinaryOp::Shr => |x, y| Some(x >> y), } } } diff --git a/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs b/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs index 64f81e05f77..4217a3d4710 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs @@ -1,3 +1,4 @@ +use fxhash::FxHashMap as HashMap; use std::{collections::VecDeque, rc::Rc}; use acvm::{acir::BlackBoxFunc, BlackBoxResolutionError, FieldElement}; @@ -238,7 +239,6 @@ pub(super) fn simplify_call( } } Intrinsic::BlackBox(bb_func) => simplify_black_box_func(bb_func, arguments, dfg), - Intrinsic::Sort => simplify_sort(dfg, arguments), Intrinsic::AsField => { let instruction = Instruction::Cast( arguments[0], @@ -319,6 +319,8 @@ fn simplify_slice_push_back( for elem in &arguments[2..] { slice.push_back(*elem); } + let slice_size = slice.len(); + let element_size = element_type.element_size(); let new_slice = dfg.make_array(slice, element_type); let set_last_slice_value_instr = @@ -327,7 +329,11 @@ fn simplify_slice_push_back( .insert_instruction_and_results(set_last_slice_value_instr, block, None, call_stack) .first(); - let mut value_merger = ValueMerger::new(dfg, block, None, None); + let mut slice_sizes = HashMap::default(); + slice_sizes.insert(set_last_slice_value, slice_size / element_size); + slice_sizes.insert(new_slice, slice_size / element_size); + + let mut value_merger = ValueMerger::new(dfg, block, &mut slice_sizes); let new_slice = value_merger.merge_values( len_not_equals_capacity, len_equals_capacity, @@ -584,20 +590,3 @@ fn simplify_signature( _ => SimplifyResult::None, } } - -fn simplify_sort(dfg: &mut DataFlowGraph, arguments: &[ValueId]) -> SimplifyResult { - match dfg.get_array_constant(arguments[0]) { - Some((input, _)) => { - let inputs: Option> = - input.iter().map(|id| dfg.get_numeric_constant(*id)).collect(); - - let Some(mut sorted_inputs) = inputs else { return SimplifyResult::None }; - sorted_inputs.sort_unstable(); - - let (_, element_type) = dfg.get_numeric_constant_with_type(input[0]).unwrap(); - let result_array = make_constant_array(dfg, sorted_inputs, element_type); - SimplifyResult::SimplifiedTo(result_array) - } - _ => SimplifyResult::None, - } -} diff --git a/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/constrain.rs b/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/constrain.rs index 7fb0970c834..b4198e2cfec 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/constrain.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/constrain.rs @@ -1,13 +1,13 @@ use acvm::FieldElement; -use super::{Binary, BinaryOp, DataFlowGraph, Instruction, Type, Value, ValueId}; +use super::{Binary, BinaryOp, ConstrainError, DataFlowGraph, Instruction, Type, Value, ValueId}; /// Try to decompose this constrain instruction. This constraint will be broken down such that it instead constrains /// all the values which are used to compute the values which were being constrained. pub(super) fn decompose_constrain( lhs: ValueId, rhs: ValueId, - msg: Option, + msg: &Option>, dfg: &mut DataFlowGraph, ) -> Vec { let lhs = dfg.resolve(lhs); @@ -39,7 +39,7 @@ pub(super) fn decompose_constrain( // Note that this doesn't remove the value `v2` as it may be used in other instructions, but it // will likely be removed through dead instruction elimination. - vec![Instruction::Constrain(lhs, rhs, msg)] + vec![Instruction::Constrain(lhs, rhs, msg.clone())] } Instruction::Binary(Binary { lhs, rhs, operator: BinaryOp::Mul }) @@ -64,7 +64,7 @@ pub(super) fn decompose_constrain( let one = dfg.make_constant(one, Type::bool()); [ - decompose_constrain(lhs, one, msg.clone(), dfg), + decompose_constrain(lhs, one, msg, dfg), decompose_constrain(rhs, one, msg, dfg), ] .concat() @@ -92,7 +92,7 @@ pub(super) fn decompose_constrain( let zero = dfg.make_constant(zero, dfg.type_of_value(lhs)); [ - decompose_constrain(lhs, zero, msg.clone(), dfg), + decompose_constrain(lhs, zero, msg, dfg), decompose_constrain(rhs, zero, msg, dfg), ] .concat() @@ -116,11 +116,28 @@ pub(super) fn decompose_constrain( decompose_constrain(value, reversed_constant, msg, dfg) } - _ => vec![Instruction::Constrain(lhs, rhs, msg)], + _ => vec![Instruction::Constrain(lhs, rhs, msg.clone())], } } - _ => vec![Instruction::Constrain(lhs, rhs, msg)], + ( + Value::Instruction { instruction: instruction_lhs, .. }, + Value::Instruction { instruction: instruction_rhs, .. }, + ) => { + match (&dfg[*instruction_lhs], &dfg[*instruction_rhs]) { + // Casting two values just to enforce an equality on them. + // + // This is equivalent to enforcing equality on the original values. + (Instruction::Cast(original_lhs, _), Instruction::Cast(original_rhs, _)) + if dfg.type_of_value(*original_lhs) == dfg.type_of_value(*original_rhs) => + { + vec![Instruction::Constrain(*original_lhs, *original_rhs, msg.clone())] + } + + _ => vec![Instruction::Constrain(lhs, rhs, msg.clone())], + } + } + _ => vec![Instruction::Constrain(lhs, rhs, msg.clone())], } } } diff --git a/noir/compiler/noirc_evaluator/src/ssa/ir/printer.rs b/noir/compiler/noirc_evaluator/src/ssa/ir/printer.rs index 2899b987c1d..9bd43fab1ff 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/ir/printer.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/ir/printer.rs @@ -9,7 +9,7 @@ use iter_extended::vecmap; use super::{ basic_block::BasicBlockId, function::Function, - instruction::{Instruction, InstructionId, TerminatorInstruction}, + instruction::{ConstrainError, Instruction, InstructionId, TerminatorInstruction}, value::ValueId, }; @@ -133,9 +133,17 @@ pub(crate) fn display_instruction( write!(f, "{} = ", value_list(function, results))?; } + display_instruction_inner(function, &function.dfg[instruction], f) +} + +fn display_instruction_inner( + function: &Function, + instruction: &Instruction, + f: &mut Formatter, +) -> Result { let show = |id| value(function, id); - match &function.dfg[instruction] { + match instruction { Instruction::Binary(binary) => { writeln!(f, "{} {}, {}", binary.operator, show(binary.lhs), show(binary.rhs)) } @@ -145,10 +153,15 @@ pub(crate) fn display_instruction( let value = show(*value); writeln!(f, "truncate {value} to {bit_size} bits, max_bit_size: {max_bit_size}",) } - Instruction::Constrain(lhs, rhs, message) => match message { - Some(message) => writeln!(f, "constrain {} == {} '{message}'", show(*lhs), show(*rhs)), - None => writeln!(f, "constrain {} == {}", show(*lhs), show(*rhs)), - }, + Instruction::Constrain(lhs, rhs, error) => { + write!(f, "constrain {} == {}", show(*lhs), show(*rhs))?; + if let Some(error) = error { + write!(f, " ")?; + display_constrain_error(function, error, f) + } else { + writeln!(f) + } + } Instruction::Call { func, arguments } => { writeln!(f, "call {}({})", show(*func), value_list(function, arguments)) } @@ -180,3 +193,18 @@ pub(crate) fn display_instruction( } } } + +fn display_constrain_error( + function: &Function, + error: &ConstrainError, + f: &mut Formatter, +) -> Result { + match error { + ConstrainError::Static(assert_message_string) => { + writeln!(f, "{assert_message_string:?}") + } + ConstrainError::Dynamic(assert_message_call) => { + display_instruction_inner(function, assert_message_call, f) + } + } +} diff --git a/noir/compiler/noirc_evaluator/src/ssa/ir/types.rs b/noir/compiler/noirc_evaluator/src/ssa/ir/types.rs index f412def1e76..8dc9e67db79 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/ir/types.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/ir/types.rs @@ -120,7 +120,7 @@ impl Type { } Type::Slice(_) => true, Type::Numeric(_) => false, - Type::Reference(_) => false, + Type::Reference(element) => element.contains_slice_element(), Type::Function => false, } } diff --git a/noir/compiler/noirc_evaluator/src/ssa/opt/bubble_up_constrains.rs b/noir/compiler/noirc_evaluator/src/ssa/opt/bubble_up_constrains.rs index 8a903cbd87b..b737c51d145 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/opt/bubble_up_constrains.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/opt/bubble_up_constrains.rs @@ -109,11 +109,11 @@ mod test { let v1 = builder.insert_binary(v0, BinaryOp::Add, one); let v2 = builder.insert_binary(v1, BinaryOp::Add, one); - builder.insert_constrain(v0, one, Some("With message".to_string())); + builder.insert_constrain(v0, one, Some("With message".to_string().into())); builder.insert_constrain(v2, three, None); builder.insert_constrain(v0, one, None); builder.insert_constrain(v1, two, None); - builder.insert_constrain(v1, two, Some("With message".to_string())); + builder.insert_constrain(v1, two, Some("With message".to_string().into())); builder.terminate_with_return(vec![]); let ssa = builder.finish(); @@ -137,11 +137,11 @@ mod test { assert_eq!(block.instructions().len(), 7); let expected_instructions = vec![ - Instruction::Constrain(v0, one, Some("With message".to_string())), + Instruction::Constrain(v0, one, Some("With message".to_string().into())), Instruction::Constrain(v0, one, None), Instruction::Binary(Binary { lhs: v0, rhs: one, operator: BinaryOp::Add }), Instruction::Constrain(v1, two, None), - Instruction::Constrain(v1, two, Some("With message".to_string())), + Instruction::Constrain(v1, two, Some("With message".to_string().into())), Instruction::Binary(Binary { lhs: v1, rhs: one, operator: BinaryOp::Add }), Instruction::Constrain(v2, three, None), ]; diff --git a/noir/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs b/noir/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs index addaee3ba8d..06ae4bf5202 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs @@ -22,6 +22,7 @@ //! different blocks are merged, i.e. after the [`flatten_cfg`][super::flatten_cfg] pass. use std::collections::HashSet; +use acvm::FieldElement; use iter_extended::vecmap; use crate::ssa::{ @@ -30,7 +31,8 @@ use crate::ssa::{ dfg::{DataFlowGraph, InsertInstructionResult}, function::Function, instruction::{Instruction, InstructionId}, - value::ValueId, + types::Type, + value::{Value, ValueId}, }, ssa_gen::Ssa, }; @@ -43,7 +45,20 @@ impl Ssa { #[tracing::instrument(level = "trace", skip(self))] pub(crate) fn fold_constants(mut self) -> Ssa { for function in self.functions.values_mut() { - constant_fold(function); + constant_fold(function, false); + } + self + } + + /// Performs constant folding on each instruction. + /// + /// Also uses constraint information to inform more optimizations. + /// + /// See [`constant_folding`][self] module for more information. + #[tracing::instrument(level = "trace", skip(self))] + pub(crate) fn fold_constants_using_constraints(mut self) -> Ssa { + for function in self.functions.values_mut() { + constant_fold(function, true); } self } @@ -51,8 +66,8 @@ impl Ssa { /// The structure of this pass is simple: /// Go through each block and re-insert all instructions. -fn constant_fold(function: &mut Function) { - let mut context = Context::default(); +fn constant_fold(function: &mut Function, use_constraint_info: bool) { + let mut context = Context { use_constraint_info, ..Default::default() }; context.block_queue.push(function.entry_block()); while let Some(block) = context.block_queue.pop() { @@ -67,6 +82,7 @@ fn constant_fold(function: &mut Function) { #[derive(Default)] struct Context { + use_constraint_info: bool, /// Maps pre-folded ValueIds to the new ValueIds obtained by re-inserting the instruction. visited_blocks: HashSet, block_queue: Vec, @@ -79,24 +95,43 @@ impl Context { // Cache of instructions without any side-effects along with their outputs. let mut cached_instruction_results: HashMap> = HashMap::default(); + // Contains sets of values which are constrained to be equivalent to each other. + // + // The mapping's structure is `side_effects_enabled_var => (constrained_value => simplified_value)`. + // + // We partition the maps of constrained values according to the side-effects flag at the point + // at which the values are constrained. This prevents constraints which are only sometimes enforced + // being used to modify the rest of the program. + let mut constraint_simplification_mappings: HashMap> = + HashMap::default(); + let mut side_effects_enabled_var = + function.dfg.make_constant(FieldElement::one(), Type::bool()); + for instruction_id in instructions { - Self::fold_constants_into_instruction( + self.fold_constants_into_instruction( &mut function.dfg, block, instruction_id, &mut cached_instruction_results, + &mut constraint_simplification_mappings, + &mut side_effects_enabled_var, ); } self.block_queue.extend(function.dfg[block].successors()); } fn fold_constants_into_instruction( + &self, dfg: &mut DataFlowGraph, block: BasicBlockId, id: InstructionId, instruction_result_cache: &mut HashMap>, + constraint_simplification_mappings: &mut HashMap>, + side_effects_enabled_var: &mut ValueId, ) { - let instruction = Self::resolve_instruction(id, dfg); + let constraint_simplification_mapping = + constraint_simplification_mappings.entry(*side_effects_enabled_var).or_default(); + let instruction = Self::resolve_instruction(id, dfg, constraint_simplification_mapping); let old_results = dfg.instruction_results(id).to_vec(); // If a copy of this instruction exists earlier in the block, then reuse the previous results. @@ -110,15 +145,49 @@ impl Context { Self::replace_result_ids(dfg, &old_results, &new_results); - Self::cache_instruction(instruction, new_results, dfg, instruction_result_cache); + self.cache_instruction( + instruction.clone(), + new_results, + dfg, + instruction_result_cache, + constraint_simplification_mapping, + ); + + // If we just inserted an `Instruction::EnableSideEffects`, we need to update `side_effects_enabled_var` + // so that we use the correct set of constrained values in future. + if let Instruction::EnableSideEffects { condition } = instruction { + *side_effects_enabled_var = condition; + }; } /// Fetches an [`Instruction`] by its [`InstructionId`] and fully resolves its inputs. - fn resolve_instruction(instruction_id: InstructionId, dfg: &DataFlowGraph) -> Instruction { + fn resolve_instruction( + instruction_id: InstructionId, + dfg: &DataFlowGraph, + constraint_simplification_mapping: &HashMap, + ) -> Instruction { let instruction = dfg[instruction_id].clone(); + // Alternate between resolving `value_id` in the `dfg` and checking to see if the resolved value + // has been constrained to be equal to some simpler value in the current block. + // + // This allows us to reach a stable final `ValueId` for each instruction input as we add more + // constraints to the cache. + fn resolve_cache( + dfg: &DataFlowGraph, + cache: &HashMap, + value_id: ValueId, + ) -> ValueId { + let resolved_id = dfg.resolve(value_id); + match cache.get(&resolved_id) { + Some(cached_value) => resolve_cache(dfg, cache, *cached_value), + None => resolved_id, + } + } + // Resolve any inputs to ensure that we're comparing like-for-like instructions. - instruction.map_values(|value_id| dfg.resolve(value_id)) + instruction + .map_values(|value_id| resolve_cache(dfg, constraint_simplification_mapping, value_id)) } /// Pushes a new [`Instruction`] into the [`DataFlowGraph`] which applies any optimizations @@ -152,11 +221,42 @@ impl Context { } fn cache_instruction( + &self, instruction: Instruction, instruction_results: Vec, dfg: &DataFlowGraph, instruction_result_cache: &mut HashMap>, + constraint_simplification_mapping: &mut HashMap, ) { + if self.use_constraint_info { + // If the instruction was a constraint, then create a link between the two `ValueId`s + // to map from the more complex to the simpler value. + if let Instruction::Constrain(lhs, rhs, _) = instruction { + // These `ValueId`s should be fully resolved now. + match (&dfg[lhs], &dfg[rhs]) { + // Ignore trivial constraints + (Value::NumericConstant { .. }, Value::NumericConstant { .. }) => (), + + // Prefer replacing with constants where possible. + (Value::NumericConstant { .. }, _) => { + constraint_simplification_mapping.insert(rhs, lhs); + } + (_, Value::NumericConstant { .. }) => { + constraint_simplification_mapping.insert(lhs, rhs); + } + // Otherwise prefer block parameters over instruction results. + // This is as block parameters are more likely to be a single witness rather than a full expression. + (Value::Param { .. }, Value::Instruction { .. }) => { + constraint_simplification_mapping.insert(rhs, lhs); + } + (Value::Instruction { .. }, Value::Param { .. }) => { + constraint_simplification_mapping.insert(lhs, rhs); + } + (_, _) => (), + } + } + } + // If the instruction doesn't have side-effects, cache the results so we can reuse them if // the same instruction appears again later in the block. if instruction.is_pure(dfg) { @@ -336,9 +436,9 @@ mod test { // // fn main f0 { // b0(v0: u16, Field 255: Field): - // v5 = div v0, Field 255 - // v6 = truncate v5 to 8 bits, max_bit_size: 16 - // return v6 + // v6 = div v0, Field 255 + // v7 = truncate v6 to 8 bits, max_bit_size: 16 + // return v7 // } main.dfg.set_value_from_id(v1, constant); @@ -354,7 +454,7 @@ mod test { ); assert_eq!( &main.dfg[instructions[1]], - &Instruction::Truncate { value: ValueId::test_new(5), bit_size: 8, max_bit_size: 16 } + &Instruction::Truncate { value: ValueId::test_new(6), bit_size: 8, max_bit_size: 16 } ); } diff --git a/noir/compiler/noirc_evaluator/src/ssa/opt/defunctionalize.rs b/noir/compiler/noirc_evaluator/src/ssa/opt/defunctionalize.rs index b7f154397a6..1f09a132132 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/opt/defunctionalize.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/opt/defunctionalize.rs @@ -14,7 +14,7 @@ use crate::ssa::{ ir::{ basic_block::BasicBlockId, function::{Function, FunctionId, RuntimeType, Signature}, - instruction::{BinaryOp, Instruction}, + instruction::{BinaryOp, ConstrainError, Instruction}, types::{NumericType, Type}, value::{Value, ValueId}, }, @@ -86,9 +86,22 @@ impl DefunctionalizationContext { let instruction = func.dfg[instruction_id].clone(); let mut replacement_instruction = None; // Operate on call instructions - let (target_func_id, mut arguments) = match instruction { + let (target_func_id, arguments) = match &instruction { Instruction::Call { func: target_func_id, arguments } => { - (target_func_id, arguments) + (*target_func_id, arguments) + } + // Constrain instruction potentially hold a call instruction themselves + // thus we need to account for them. + Instruction::Constrain(_, _, Some(constrain_error)) => { + if let ConstrainError::Dynamic(Instruction::Call { + func: target_func_id, + arguments, + }) = constrain_error.as_ref() + { + (*target_func_id, arguments) + } else { + continue; + } } _ => continue, }; @@ -96,6 +109,7 @@ impl DefunctionalizationContext { match func.dfg[target_func_id] { // If the target is a function used as value Value::Param { .. } | Value::Instruction { .. } => { + let mut arguments = arguments.clone(); let results = func.dfg.instruction_results(instruction_id); let signature = Signature { params: vecmap(&arguments, |param| func.dfg.type_of_value(*param)), @@ -120,7 +134,20 @@ impl DefunctionalizationContext { } _ => {} } - if let Some(new_instruction) = replacement_instruction { + if let Some(mut new_instruction) = replacement_instruction { + if let Instruction::Constrain(lhs, rhs, constrain_error_call) = instruction { + let new_error_call = if let Some(error) = constrain_error_call { + match error.as_ref() { + ConstrainError::Dynamic(_) => { + Some(Box::new(ConstrainError::Dynamic(new_instruction))) + } + _ => None, + } + } else { + None + }; + new_instruction = Instruction::Constrain(lhs, rhs, new_error_call); + } func.dfg[instruction_id] = new_instruction; } } diff --git a/noir/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs b/noir/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs index 1059994b9be..943a57c1bc0 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs @@ -152,8 +152,10 @@ use crate::ssa::{ }; mod branch_analysis; +mod capacity_tracker; pub(crate) mod value_merger; +use capacity_tracker::SliceCapacityTracker; use value_merger::ValueMerger; impl Ssa { @@ -184,17 +186,6 @@ struct Context<'f> { /// between inlining of branches. store_values: HashMap, - /// Maps an address to the old and new value of the element at that address - /// The difference between this map and store_values is that this stores - /// the old and new value of an element from the outer block whose jmpif - /// terminator is being flattened. - /// - /// This map persists throughout the flattening process, where addresses - /// are overwritten as new stores are found. This overwriting is the desired behavior, - /// as we want the most update to date value to be stored at a given address as - /// we walk through blocks to flatten. - outer_block_stores: HashMap, - /// Stores all allocations local to the current branch. /// Since these branches are local to the current branch (ie. only defined within one branch of /// an if expression), they should not be merged with their previous value or stored value in @@ -209,6 +200,10 @@ struct Context<'f> { /// condition. If we are under multiple conditions (a nested if), the topmost condition is /// the most recent condition combined with all previous conditions via `And` instructions. conditions: Vec<(BasicBlockId, ValueId)>, + + /// Maps SSA array values with a slice type to their size. + /// This is maintained by appropriate calls to the `SliceCapacityTracker` and is used by the `ValueMerger`. + slice_sizes: HashMap, } pub(crate) struct Store { @@ -239,7 +234,7 @@ fn flatten_function_cfg(function: &mut Function) { local_allocations: HashSet::new(), branch_ends, conditions: Vec::new(), - outer_block_stores: HashMap::default(), + slice_sizes: HashMap::default(), }; context.flatten(); } @@ -262,21 +257,18 @@ impl<'f> Context<'f> { /// Returns the last block to be inlined. This is either the return block of the function or, /// if self.conditions is not empty, the end block of the most recent condition. fn handle_terminator(&mut self, block: BasicBlockId) -> BasicBlockId { - if let TerminatorInstruction::JmpIf { .. } = - self.inserter.function.dfg[block].unwrap_terminator() - { - // Find stores in the outer block and insert into the `outer_block_stores` map. - // Not using this map can lead to issues when attempting to merge slices. - // When inlining a branch end, only the then branch and the else branch are checked for stores. - // However, there are cases where we want to load a value that comes from the outer block - // that we are handling the terminator for here. - let instructions = self.inserter.function.dfg[block].instructions().to_vec(); - for instruction in instructions { - let (instruction, _) = self.inserter.map_instruction(instruction); - if let Instruction::Store { address, value } = instruction { - self.outer_block_stores.insert(address, value); - } - } + // As we recursively flatten inner blocks, we need to track the slice information + // for the outer block before we start recursively inlining + let outer_block_instructions = self.inserter.function.dfg[block].instructions(); + let mut capacity_tracker = SliceCapacityTracker::new(&self.inserter.function.dfg); + for instruction in outer_block_instructions { + let results = self.inserter.function.dfg.instruction_results(*instruction); + let instruction = &self.inserter.function.dfg[*instruction]; + capacity_tracker.collect_slice_information( + instruction, + &mut self.slice_sizes, + results.to_vec(), + ); } match self.inserter.function.dfg[block].unwrap_terminator() { @@ -494,12 +486,16 @@ impl<'f> Context<'f> { }); let block = self.inserter.function.entry_block(); - let mut value_merger = ValueMerger::new( - &mut self.inserter.function.dfg, - block, - Some(&self.store_values), - Some(&self.outer_block_stores), - ); + + // Make sure we have tracked the slice capacities of any block arguments + let capacity_tracker = SliceCapacityTracker::new(&self.inserter.function.dfg); + for (then_arg, else_arg) in args.iter() { + capacity_tracker.compute_slice_capacity(*then_arg, &mut self.slice_sizes); + capacity_tracker.compute_slice_capacity(*else_arg, &mut self.slice_sizes); + } + + let mut value_merger = + ValueMerger::new(&mut self.inserter.function.dfg, block, &mut self.slice_sizes); // Cannot include this in the previous vecmap since it requires exclusive access to self let args = vecmap(args, |(then_arg, else_arg)| { @@ -538,18 +534,22 @@ impl<'f> Context<'f> { } } + // Most slice information is collected when instructions are inlined. + // We need to collect information on slice values here as we may possibly merge stores + // before any inlining occurs. + let capacity_tracker = SliceCapacityTracker::new(&self.inserter.function.dfg); + for (then_case, else_case, _) in new_map.values() { + capacity_tracker.compute_slice_capacity(*then_case, &mut self.slice_sizes); + capacity_tracker.compute_slice_capacity(*else_case, &mut self.slice_sizes); + } + let then_condition = then_branch.condition; let else_condition = else_branch.condition; let block = self.inserter.function.entry_block(); - let mut value_merger = ValueMerger::new( - &mut self.inserter.function.dfg, - block, - Some(&self.store_values), - Some(&self.outer_block_stores), - ); - + let mut value_merger = + ValueMerger::new(&mut self.inserter.function.dfg, block, &mut self.slice_sizes); // Merging must occur in a separate loop as we cannot borrow `self` as mutable while `value_merger` does let mut new_values = HashMap::default(); for (address, (then_case, else_case, _)) in &new_map { @@ -571,6 +571,16 @@ impl<'f> Context<'f> { .insert(address, Store { old_value: *old_value, new_value: value }); } } + + // Collect any potential slice information on the stores we are merging + for (address, (_, _, _)) in &new_map { + let value = new_values[address]; + let address = *address; + let instruction = Instruction::Store { address, value }; + + let mut capacity_tracker = SliceCapacityTracker::new(&self.inserter.function.dfg); + capacity_tracker.collect_slice_information(&instruction, &mut self.slice_sizes, vec![]); + } } fn remember_store(&mut self, address: ValueId, new_value: ValueId) { @@ -579,8 +589,18 @@ impl<'f> Context<'f> { store_value.new_value = new_value; } else { let load = Instruction::Load { address }; + let load_type = Some(vec![self.inserter.function.dfg.type_of_value(new_value)]); - let old_value = self.insert_instruction_with_typevars(load, load_type).first(); + let old_value = + self.insert_instruction_with_typevars(load.clone(), load_type).first(); + + // Need this or else we will be missing a the previous value of a slice that we wish to merge + let mut capacity_tracker = SliceCapacityTracker::new(&self.inserter.function.dfg); + capacity_tracker.collect_slice_information( + &load, + &mut self.slice_sizes, + vec![old_value], + ); self.store_values.insert(address, Store { old_value, new_value }); } @@ -602,8 +622,15 @@ impl<'f> Context<'f> { // unnecessary, when removing it actually causes an aliasing/mutability error. let instructions = self.inserter.function.dfg[destination].instructions().to_vec(); - for instruction in instructions { - self.push_instruction(instruction); + for instruction in instructions.iter() { + let results = self.push_instruction(*instruction); + let (instruction, _) = self.inserter.map_instruction(*instruction); + let mut capacity_tracker = SliceCapacityTracker::new(&self.inserter.function.dfg); + capacity_tracker.collect_slice_information( + &instruction, + &mut self.slice_sizes, + results, + ); } self.handle_terminator(destination) @@ -615,7 +642,7 @@ impl<'f> Context<'f> { /// As a result, the instruction that will be pushed will actually be a new instruction /// with a different InstructionId from the original. The results of the given instruction /// will also be mapped to the results of the new instruction. - fn push_instruction(&mut self, id: InstructionId) { + fn push_instruction(&mut self, id: InstructionId) -> Vec { let (instruction, call_stack) = self.inserter.map_instruction(id); let instruction = self.handle_instruction_side_effects(instruction, call_stack.clone()); let is_allocate = matches!(instruction, Instruction::Allocate); @@ -628,6 +655,8 @@ impl<'f> Context<'f> { if is_allocate { self.local_allocations.insert(results.first()); } + + results.results().into_owned() } /// If we are currently in a branch, we need to modify constrain instructions diff --git a/noir/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs b/noir/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs new file mode 100644 index 00000000000..7cd0fe3084e --- /dev/null +++ b/noir/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs @@ -0,0 +1,150 @@ +use crate::ssa::ir::{ + dfg::DataFlowGraph, + instruction::{Instruction, Intrinsic}, + types::Type, + value::{Value, ValueId}, +}; + +use fxhash::FxHashMap as HashMap; + +pub(crate) struct SliceCapacityTracker<'a> { + dfg: &'a DataFlowGraph, +} + +impl<'a> SliceCapacityTracker<'a> { + pub(crate) fn new(dfg: &'a DataFlowGraph) -> Self { + SliceCapacityTracker { dfg } + } + + /// Determine how the slice sizes map needs to be updated according to the provided instruction. + pub(crate) fn collect_slice_information( + &mut self, + instruction: &Instruction, + slice_sizes: &mut HashMap, + results: Vec, + ) { + match instruction { + Instruction::ArrayGet { array, .. } => { + let array_typ = self.dfg.type_of_value(*array); + let array_value = &self.dfg[*array]; + if matches!(array_value, Value::Array { .. }) && array_typ.contains_slice_element() + { + // Initial insertion into the slice sizes map + // Any other insertions should only occur if the value is already + // a part of the map. + self.compute_slice_capacity(*array, slice_sizes); + } + } + Instruction::ArraySet { array, value, .. } => { + let array_typ = self.dfg.type_of_value(*array); + let array_value = &self.dfg[*array]; + if matches!(array_value, Value::Array { .. }) && array_typ.contains_slice_element() + { + // Initial insertion into the slice sizes map + // Any other insertions should only occur if the value is already + // a part of the map. + self.compute_slice_capacity(*array, slice_sizes); + } + + let value_typ = self.dfg.type_of_value(*value); + // Compiler sanity check + assert!(!value_typ.contains_slice_element(), "ICE: Nested slices are not allowed and should not have reached the flattening pass of SSA"); + + if let Some(capacity) = slice_sizes.get(array) { + slice_sizes.insert(results[0], *capacity); + } + } + Instruction::Call { func, arguments } => { + let func = &self.dfg[*func]; + if let Value::Intrinsic(intrinsic) = func { + let (argument_index, result_index) = match intrinsic { + Intrinsic::SlicePushBack + | Intrinsic::SlicePushFront + | Intrinsic::SlicePopBack + | Intrinsic::SliceInsert + | Intrinsic::SliceRemove => (1, 1), + // `pop_front` returns the popped element, and then the respective slice. + // This means in the case of a slice with structs, the result index of the popped slice + // will change depending on the number of elements in the struct. + // For example, a slice with four elements will look as such in SSA: + // v3, v4, v5, v6, v7, v8 = call slice_pop_front(v1, v2) + // where v7 is the slice length and v8 is the popped slice itself. + Intrinsic::SlicePopFront => (1, results.len() - 1), + _ => return, + }; + let slice_contents = arguments[argument_index]; + match intrinsic { + Intrinsic::SlicePushBack + | Intrinsic::SlicePushFront + | Intrinsic::SliceInsert => { + for arg in &arguments[(argument_index + 1)..] { + let element_typ = self.dfg.type_of_value(*arg); + if element_typ.contains_slice_element() { + self.compute_slice_capacity(*arg, slice_sizes); + } + } + if let Some(contents_capacity) = slice_sizes.get(&slice_contents) { + let new_capacity = *contents_capacity + 1; + slice_sizes.insert(results[result_index], new_capacity); + } + } + Intrinsic::SlicePopBack + | Intrinsic::SliceRemove + | Intrinsic::SlicePopFront => { + // We do not decrement the size on intrinsics that could remove values from a slice. + // This is because we could potentially go back to the smaller slice and not fill in dummies. + // This pass should be tracking the potential max that a slice ***could be*** + if let Some(contents_capacity) = slice_sizes.get(&slice_contents) { + let new_capacity = *contents_capacity - 1; + slice_sizes.insert(results[result_index], new_capacity); + } + } + _ => {} + } + } + } + Instruction::Store { address, value } => { + let value_typ = self.dfg.type_of_value(*value); + if value_typ.contains_slice_element() { + self.compute_slice_capacity(*value, slice_sizes); + + let value_capacity = slice_sizes.get(value).unwrap_or_else(|| { + panic!("ICE: should have slice capacity set for value {value} being stored at {address}") + }); + + slice_sizes.insert(*address, *value_capacity); + } + } + Instruction::Load { address } => { + let load_typ = self.dfg.type_of_value(*address); + if load_typ.contains_slice_element() { + let result = results[0]; + + let address_capacity = slice_sizes.get(address).unwrap_or_else(|| { + panic!("ICE: should have slice capacity set at address {address} being loaded into {result}") + }); + + slice_sizes.insert(result, *address_capacity); + } + } + _ => {} + } + } + + /// Computes the starting capacity of a slice which is still a `Value::Array` + pub(crate) fn compute_slice_capacity( + &self, + array_id: ValueId, + slice_sizes: &mut HashMap, + ) { + if let Value::Array { array, typ } = &self.dfg[array_id] { + // Compiler sanity check + assert!(!typ.is_nested_slice(), "ICE: Nested slices are not allowed and should not have reached the flattening pass of SSA"); + if let Type::Slice(_) = typ { + let element_size = typ.element_size(); + let len = array.len() / element_size; + slice_sizes.insert(array_id, len); + } + } + } +} diff --git a/noir/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs b/noir/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs index 446560f45f1..6b923a2e42d 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs @@ -4,35 +4,26 @@ use fxhash::FxHashMap as HashMap; use crate::ssa::ir::{ basic_block::BasicBlockId, dfg::{CallStack, DataFlowGraph}, - instruction::{BinaryOp, Instruction, Intrinsic}, + instruction::{BinaryOp, Instruction}, types::Type, - value::{Value, ValueId}, + value::ValueId, }; -use crate::ssa::opt::flatten_cfg::Store; - pub(crate) struct ValueMerger<'a> { dfg: &'a mut DataFlowGraph, block: BasicBlockId, - store_values: Option<&'a HashMap>, - outer_block_stores: Option<&'a HashMap>, - slice_sizes: HashMap, + // Maps SSA array values with a slice type to their size. + // This must be computed before merging values. + slice_sizes: &'a mut HashMap, } impl<'a> ValueMerger<'a> { pub(crate) fn new( dfg: &'a mut DataFlowGraph, block: BasicBlockId, - store_values: Option<&'a HashMap>, - outer_block_stores: Option<&'a HashMap>, + slice_sizes: &'a mut HashMap, ) -> Self { - ValueMerger { - dfg, - block, - store_values, - outer_block_stores, - slice_sizes: HashMap::default(), - } + ValueMerger { dfg, block, slice_sizes } } /// Merge two values a and b from separate basic blocks to a single value. @@ -184,11 +175,13 @@ impl<'a> ValueMerger<'a> { _ => panic!("Expected slice type"), }; - let then_len = self.get_slice_length(then_value_id); - self.slice_sizes.insert(then_value_id, then_len); + let then_len = *self.slice_sizes.get(&then_value_id).unwrap_or_else(|| { + panic!("ICE: Merging values during flattening encountered slice {then_value_id} without a preset size"); + }); - let else_len = self.get_slice_length(else_value_id); - self.slice_sizes.insert(else_value_id, else_len); + let else_len = *self.slice_sizes.get(&else_value_id).unwrap_or_else(|| { + panic!("ICE: Merging values during flattening encountered slice {else_value_id} without a preset size"); + }); let len = then_len.max(else_len); @@ -218,8 +211,10 @@ impl<'a> ValueMerger<'a> { } }; - let then_element = get_element(then_value_id, typevars.clone(), then_len); - let else_element = get_element(else_value_id, typevars, else_len); + let then_element = + get_element(then_value_id, typevars.clone(), then_len * element_types.len()); + let else_element = + get_element(else_value_id, typevars, else_len * element_types.len()); merged.push_back(self.merge_values( then_condition, @@ -233,82 +228,6 @@ impl<'a> ValueMerger<'a> { self.dfg.make_array(merged, typ) } - fn get_slice_length(&mut self, value_id: ValueId) -> usize { - let value = &self.dfg[value_id]; - match value { - Value::Array { array, .. } => array.len(), - Value::Instruction { instruction: instruction_id, .. } => { - let instruction = &self.dfg[*instruction_id]; - match instruction { - // TODO(#3188): A slice can be the result of an ArrayGet when it is the - // fetched from a slice of slices or as a struct field. - // However, we need to incorporate nested slice support in flattening - // in order for this to be valid - // Instruction::ArrayGet { array, .. } => {} - Instruction::ArraySet { array, .. } => { - let array = *array; - let len = self.get_slice_length(array); - self.slice_sizes.insert(array, len); - len - } - Instruction::Load { address } => { - let outer_block_stores = self.outer_block_stores.expect("ICE: A map of previous stores is required in order to resolve a slice load"); - let store_values = self.store_values.expect("ICE: A map of previous stores is required in order to resolve a slice load"); - let store_value = outer_block_stores - .get(address) - .expect("ICE: load in merger should have store from outer block"); - - if let Some(len) = self.slice_sizes.get(store_value) { - return *len; - } - - let store_value = if let Some(store) = store_values.get(address) { - if let Some(len) = self.slice_sizes.get(&store.new_value) { - return *len; - } - - store.new_value - } else { - *store_value - }; - - self.get_slice_length(store_value) - } - Instruction::Call { func, arguments } => { - let slice_contents = arguments[1]; - let func = &self.dfg[*func]; - match func { - Value::Intrinsic(intrinsic) => match intrinsic { - Intrinsic::SlicePushBack - | Intrinsic::SlicePushFront - | Intrinsic::SliceInsert => { - // `get_slice_length` needs to be called here as it is borrows self as mutable - let initial_len = self.get_slice_length(slice_contents); - self.slice_sizes.insert(slice_contents, initial_len); - initial_len + 1 - } - Intrinsic::SlicePopBack - | Intrinsic::SlicePopFront - | Intrinsic::SliceRemove => { - // `get_slice_length` needs to be called here as it is borrows self as mutable - let initial_len = self.get_slice_length(slice_contents); - self.slice_sizes.insert(slice_contents, initial_len); - initial_len - 1 - } - _ => { - unreachable!("ICE: Intrinsic not supported, got {intrinsic:?}") - } - }, - _ => unreachable!("ICE: Expected intrinsic value but got {func:?}"), - } - } - _ => unreachable!("ICE: Got unexpected instruction: {instruction:?}"), - } - } - _ => unreachable!("ICE: Got unexpected value when resolving slice length {value:?}"), - } - } - /// Construct a dummy value to be attached to the smaller of two slices being merged. /// We need to make sure we follow the internal element type structure of the slice type /// even for dummy data to ensure that we do not have errors later in the compiler, diff --git a/noir/compiler/noirc_evaluator/src/ssa/opt/mod.rs b/noir/compiler/noirc_evaluator/src/ssa/opt/mod.rs index 71725422a7a..a315695f7db 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/opt/mod.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/opt/mod.rs @@ -12,5 +12,6 @@ mod die; pub(crate) mod flatten_cfg; mod inlining; mod mem2reg; +mod remove_bit_shifts; mod simplify_cfg; mod unrolling; diff --git a/noir/compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs b/noir/compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs new file mode 100644 index 00000000000..a71a42d5757 --- /dev/null +++ b/noir/compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs @@ -0,0 +1,285 @@ +use std::{borrow::Cow, rc::Rc}; + +use acvm::FieldElement; + +use crate::ssa::{ + ir::{ + basic_block::BasicBlockId, + dfg::{CallStack, InsertInstructionResult}, + function::{Function, RuntimeType}, + instruction::{Binary, BinaryOp, Endian, Instruction, InstructionId, Intrinsic}, + types::{NumericType, Type}, + value::ValueId, + }, + ssa_gen::Ssa, +}; + +impl Ssa { + /// Performs constant folding on each instruction. + /// + /// See [`constant_folding`][self] module for more information. + #[tracing::instrument(level = "trace", skip(self))] + pub(crate) fn remove_bit_shifts(mut self) -> Ssa { + remove_bit_shifts(self.main_mut()); + self + } +} + +/// The structure of this pass is simple: +/// Go through each block and re-insert all instructions. +fn remove_bit_shifts(function: &mut Function) { + if let RuntimeType::Brillig = function.runtime() { + return; + } + + let block = function.entry_block(); + let mut context = + Context { function, new_instructions: Vec::new(), block, call_stack: CallStack::default() }; + + context.remove_bit_shifts(); +} + +struct Context<'f> { + function: &'f mut Function, + new_instructions: Vec, + + block: BasicBlockId, + call_stack: CallStack, +} + +impl Context<'_> { + fn remove_bit_shifts(&mut self) { + let instructions = self.function.dfg[self.block].take_instructions(); + + for instruction_id in instructions { + match self.function.dfg[instruction_id] { + Instruction::Binary(Binary { lhs, rhs, operator }) + if matches!(operator, BinaryOp::Shl | BinaryOp::Shr) => + { + self.call_stack = self.function.dfg.get_call_stack(instruction_id).clone(); + let old_result = + *self.function.dfg.instruction_results(instruction_id).first().unwrap(); + + let bit_size = match self.function.dfg.type_of_value(lhs) { + Type::Numeric(NumericType::Signed { bit_size }) + | Type::Numeric(NumericType::Unsigned { bit_size }) => bit_size, + _ => unreachable!("ICE: right-shift attempted on non-integer"), + }; + let new_result = if operator == BinaryOp::Shl { + self.insert_wrapping_shift_left(lhs, rhs, bit_size) + } else { + self.insert_shift_right(lhs, rhs, bit_size) + }; + + self.function.dfg.set_value_from_id(old_result, new_result); + } + _ => { + self.new_instructions.push(instruction_id); + } + }; + } + + *self.function.dfg[self.block].instructions_mut() = + std::mem::take(&mut self.new_instructions); + } + + /// Insert ssa instructions which computes lhs << rhs by doing lhs*2^rhs + /// and truncate the result to bit_size + pub(crate) fn insert_wrapping_shift_left( + &mut self, + lhs: ValueId, + rhs: ValueId, + bit_size: u32, + ) -> ValueId { + let base = self.field_constant(FieldElement::from(2_u128)); + let typ = self.function.dfg.type_of_value(lhs); + let (max_bit, pow) = if let Some(rhs_constant) = self.function.dfg.get_numeric_constant(rhs) + { + // Happy case is that we know precisely by how many bits the the integer will + // increase: lhs_bit_size + rhs + let bit_shift_size = rhs_constant.to_u128() as u32; + + let (rhs_bit_size_pow_2, overflows) = 2_u128.overflowing_pow(bit_shift_size); + if overflows { + assert!(bit_size < 128, "ICE - shift left with big integers are not supported"); + if bit_size < 128 { + let zero = self.numeric_constant(FieldElement::zero(), typ); + return InsertInstructionResult::SimplifiedTo(zero).first(); + } + } + let pow = self.numeric_constant(FieldElement::from(rhs_bit_size_pow_2), typ); + + let max_lhs_bits = self.function.dfg.get_value_max_num_bits(lhs); + + (max_lhs_bits + bit_shift_size, pow) + } else { + // we use a predicate to nullify the result in case of overflow + let bit_size_var = + self.numeric_constant(FieldElement::from(bit_size as u128), typ.clone()); + let overflow = self.insert_binary(rhs, BinaryOp::Lt, bit_size_var); + let predicate = self.insert_cast(overflow, typ.clone()); + // we can safely cast to unsigned because overflow_checks prevent bit-shift with a negative value + let rhs_unsigned = self.insert_cast(rhs, Type::unsigned(bit_size)); + let pow = self.pow(base, rhs_unsigned); + let pow = self.insert_cast(pow, typ); + (FieldElement::max_num_bits(), self.insert_binary(predicate, BinaryOp::Mul, pow)) + }; + + if max_bit <= bit_size { + self.insert_binary(lhs, BinaryOp::Mul, pow) + } else { + let result = self.insert_binary(lhs, BinaryOp::Mul, pow); + self.insert_truncate(result, bit_size, max_bit) + } + } + + /// Insert ssa instructions which computes lhs >> rhs by doing lhs/2^rhs + pub(crate) fn insert_shift_right( + &mut self, + lhs: ValueId, + rhs: ValueId, + bit_size: u32, + ) -> ValueId { + let lhs_typ = self.function.dfg.type_of_value(lhs); + let base = self.field_constant(FieldElement::from(2_u128)); + // we can safely cast to unsigned because overflow_checks prevent bit-shift with a negative value + let rhs_unsigned = self.insert_cast(rhs, Type::unsigned(bit_size)); + let pow = self.pow(base, rhs_unsigned); + // We need at least one more bit for the case where rhs == bit_size + let div_type = Type::unsigned(bit_size + 1); + let casted_lhs = self.insert_cast(lhs, div_type.clone()); + let casted_pow = self.insert_cast(pow, div_type); + let div_result = self.insert_binary(casted_lhs, BinaryOp::Div, casted_pow); + // We have to cast back to the original type + self.insert_cast(div_result, lhs_typ) + } + + /// Computes lhs^rhs via square&multiply, using the bits decomposition of rhs + /// Pseudo-code of the computation: + /// let mut r = 1; + /// let rhs_bits = to_bits(rhs); + /// for i in 1 .. bit_size + 1 { + /// let r_squared = r * r; + /// let b = rhs_bits[bit_size - i]; + /// r = (r_squared * lhs * b) + (1 - b) * r_squared; + /// } + fn pow(&mut self, lhs: ValueId, rhs: ValueId) -> ValueId { + let typ = self.function.dfg.type_of_value(rhs); + if let Type::Numeric(NumericType::Unsigned { bit_size }) = typ { + let to_bits = self.function.dfg.import_intrinsic(Intrinsic::ToBits(Endian::Little)); + let length = self.field_constant(FieldElement::from(bit_size as i128)); + let result_types = + vec![Type::field(), Type::Array(Rc::new(vec![Type::bool()]), bit_size as usize)]; + let rhs_bits = self.insert_call(to_bits, vec![rhs, length], result_types); + + let rhs_bits = rhs_bits[1]; + let one = self.field_constant(FieldElement::one()); + let mut r = one; + for i in 1..bit_size + 1 { + let r_squared = self.insert_binary(r, BinaryOp::Mul, r); + let a = self.insert_binary(r_squared, BinaryOp::Mul, lhs); + let idx = self.field_constant(FieldElement::from((bit_size - i) as i128)); + let b = self.insert_array_get(rhs_bits, idx, Type::bool()); + let not_b = self.insert_not(b); + let b = self.insert_cast(b, Type::field()); + let not_b = self.insert_cast(not_b, Type::field()); + let r1 = self.insert_binary(a, BinaryOp::Mul, b); + let r2 = self.insert_binary(r_squared, BinaryOp::Mul, not_b); + r = self.insert_binary(r1, BinaryOp::Add, r2); + } + r + } else { + unreachable!("Value must be unsigned in power operation"); + } + } + + pub(crate) fn field_constant(&mut self, constant: FieldElement) -> ValueId { + self.function.dfg.make_constant(constant, Type::field()) + } + + /// Insert a numeric constant into the current function + pub(crate) fn numeric_constant( + &mut self, + value: impl Into, + typ: Type, + ) -> ValueId { + self.function.dfg.make_constant(value.into(), typ) + } + + /// Insert a binary instruction at the end of the current block. + /// Returns the result of the binary instruction. + pub(crate) fn insert_binary( + &mut self, + lhs: ValueId, + operator: BinaryOp, + rhs: ValueId, + ) -> ValueId { + let instruction = Instruction::Binary(Binary { lhs, rhs, operator }); + self.insert_instruction(instruction, None).first() + } + + /// Insert a not instruction at the end of the current block. + /// Returns the result of the instruction. + pub(crate) fn insert_not(&mut self, rhs: ValueId) -> ValueId { + self.insert_instruction(Instruction::Not(rhs), None).first() + } + + /// Insert a truncate instruction at the end of the current block. + /// Returns the result of the truncate instruction. + pub(crate) fn insert_truncate( + &mut self, + value: ValueId, + bit_size: u32, + max_bit_size: u32, + ) -> ValueId { + self.insert_instruction(Instruction::Truncate { value, bit_size, max_bit_size }, None) + .first() + } + + /// Insert a cast instruction at the end of the current block. + /// Returns the result of the cast instruction. + pub(crate) fn insert_cast(&mut self, value: ValueId, typ: Type) -> ValueId { + self.insert_instruction(Instruction::Cast(value, typ), None).first() + } + + /// Insert a call instruction at the end of the current block and return + /// the results of the call. + pub(crate) fn insert_call( + &mut self, + func: ValueId, + arguments: Vec, + result_types: Vec, + ) -> Cow<[ValueId]> { + self.insert_instruction(Instruction::Call { func, arguments }, Some(result_types)).results() + } + + /// Insert an instruction to extract an element from an array + pub(crate) fn insert_array_get( + &mut self, + array: ValueId, + index: ValueId, + element_type: Type, + ) -> ValueId { + let element_type = Some(vec![element_type]); + self.insert_instruction(Instruction::ArrayGet { array, index }, element_type).first() + } + + pub(crate) fn insert_instruction( + &mut self, + instruction: Instruction, + ctrl_typevars: Option>, + ) -> InsertInstructionResult { + let result = self.function.dfg.insert_instruction_and_results( + instruction, + self.block, + ctrl_typevars, + self.call_stack.clone(), + ); + + if let InsertInstructionResult::Results(instruction_id, _) = result { + self.new_instructions.push(instruction_id); + } + + result + } +} diff --git a/noir/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs b/noir/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs index 0e155776545..6ee7f312660 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs @@ -435,7 +435,7 @@ impl<'a> FunctionContext<'a> { self.builder.set_location(location).insert_constrain( sign, one, - Some("attempt to bit-shift with overflow".to_string()), + Some("attempt to bit-shift with overflow".to_owned().into()), ); } @@ -446,7 +446,7 @@ impl<'a> FunctionContext<'a> { self.builder.set_location(location).insert_constrain( overflow, one, - Some("attempt to bit-shift with overflow".to_owned()), + Some("attempt to bit-shift with overflow".to_owned().into()), ); self.builder.insert_truncate(result, bit_size, bit_size + 1) } @@ -498,8 +498,11 @@ impl<'a> FunctionContext<'a> { let sign_diff = self.builder.insert_binary(result_sign, BinaryOp::Eq, lhs_sign); let sign_diff_with_predicate = self.builder.insert_binary(sign_diff, BinaryOp::Mul, same_sign); - let overflow_check = - Instruction::Constrain(sign_diff_with_predicate, same_sign, Some(message)); + let overflow_check = Instruction::Constrain( + sign_diff_with_predicate, + same_sign, + Some(message.into()), + ); self.builder.set_location(location).insert_instruction(overflow_check, None); } BinaryOpKind::Multiply => { @@ -509,11 +512,10 @@ impl<'a> FunctionContext<'a> { let rhs_abs = self.absolute_value_helper(rhs, rhs_sign, bit_size); let product_field = self.builder.insert_binary(lhs_abs, BinaryOp::Mul, rhs_abs); // It must not already overflow the bit_size - let message = "attempt to multiply with overflow".to_string(); self.builder.set_location(location).insert_range_check( product_field, bit_size, - Some(message.clone()), + Some("attempt to multiply with overflow".to_string()), ); let product = self.builder.insert_cast(product_field, Type::unsigned(bit_size)); @@ -530,7 +532,7 @@ impl<'a> FunctionContext<'a> { self.builder.set_location(location).insert_constrain( product_overflow_check, one, - Some(message), + Some(message.into()), ); } _ => unreachable!("operator {} should not overflow", operator), @@ -550,22 +552,6 @@ impl<'a> FunctionContext<'a> { ) -> Values { let result_type = self.builder.type_of_value(lhs); let mut result = match operator { - BinaryOpKind::ShiftLeft => { - let bit_size = match result_type { - Type::Numeric(NumericType::Signed { bit_size }) - | Type::Numeric(NumericType::Unsigned { bit_size }) => bit_size, - _ => unreachable!("ICE: left-shift attempted on non-integer"), - }; - self.builder.insert_wrapping_shift_left(lhs, rhs, bit_size) - } - BinaryOpKind::ShiftRight => { - let bit_size = match result_type { - Type::Numeric(NumericType::Signed { bit_size }) - | Type::Numeric(NumericType::Unsigned { bit_size }) => bit_size, - _ => unreachable!("ICE: right-shift attempted on non-integer"), - }; - self.builder.insert_shift_right(lhs, rhs, bit_size) - } BinaryOpKind::Equal | BinaryOpKind::NotEqual if matches!(result_type, Type::Array(..)) => { @@ -738,12 +724,17 @@ impl<'a> FunctionContext<'a> { /// Create a const offset of an address for an array load or store pub(super) fn make_offset(&mut self, mut address: ValueId, offset: u128) -> ValueId { if offset != 0 { - let offset = self.builder.field_constant(offset); + let offset = self.builder.numeric_constant(offset, self.builder.type_of_value(address)); address = self.builder.insert_binary(address, BinaryOp::Add, offset); } address } + /// Array indexes are u64s. This function casts values used as indexes to u64. + pub(super) fn make_array_index(&mut self, index: ValueId) -> ValueId { + self.builder.insert_cast(index, Type::unsigned(64)) + } + /// Define a local variable to be some Values that can later be retrieved /// by calling self.lookup(id) pub(super) fn define(&mut self, id: LocalId, value: Values) { @@ -987,12 +978,14 @@ impl<'a> FunctionContext<'a> { index: ValueId, location: Location, ) -> ValueId { - let element_size = self.builder.field_constant(self.element_size(array)); + let index = self.make_array_index(index); + let element_size = + self.builder.numeric_constant(self.element_size(array), Type::unsigned(64)); // The actual base index is the user's index * the array element type's size let mut index = self.builder.set_location(location).insert_binary(index, BinaryOp::Mul, element_size); - let one = self.builder.field_constant(FieldElement::one()); + let one = self.builder.numeric_constant(FieldElement::one(), Type::unsigned(64)); new_value.for_each(|value| { let value = value.eval(self); @@ -1132,9 +1125,8 @@ fn convert_operator(op: noirc_frontend::BinaryOpKind) -> BinaryOp { BinaryOpKind::And => BinaryOp::And, BinaryOpKind::Or => BinaryOp::Or, BinaryOpKind::Xor => BinaryOp::Xor, - BinaryOpKind::ShiftRight | BinaryOpKind::ShiftLeft => unreachable!( - "ICE - bit shift operators do not exist in SSA and should have been replaced" - ), + BinaryOpKind::ShiftLeft => BinaryOp::Shl, + BinaryOpKind::ShiftRight => BinaryOp::Shr, } } diff --git a/noir/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs b/noir/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs index 9d9635fed34..ecc8bf87597 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs @@ -13,11 +13,8 @@ use noirc_frontend::{ }; use crate::{ - errors::RuntimeError, - ssa::{ - function_builder::data_bus::DataBusBuilder, - ir::{instruction::Intrinsic, types::NumericType}, - }, + errors::{InternalError, RuntimeError}, + ssa::{function_builder::data_bus::DataBusBuilder, ir::instruction::Intrinsic}, }; use self::{ @@ -29,7 +26,7 @@ use super::{ function_builder::data_bus::DataBus, ir::{ function::RuntimeType, - instruction::{BinaryOp, TerminatorInstruction}, + instruction::{BinaryOp, ConstrainError, Instruction, TerminatorInstruction}, types::Type, value::ValueId, }, @@ -38,7 +35,10 @@ use super::{ /// 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) -> Result { +pub(crate) fn generate_ssa( + program: Program, + force_brillig_runtime: bool, +) -> Result { // see which parameter has call_data/return_data attribute let is_databus = DataBusBuilder::is_databus(&program.main_function_signature); @@ -56,7 +56,11 @@ pub(crate) fn generate_ssa(program: Program) -> Result { let mut function_context = FunctionContext::new( main.name.clone(), &main.parameters, - if main.unconstrained { RuntimeType::Brillig } else { RuntimeType::Acir }, + if force_brillig_runtime || main.unconstrained { + RuntimeType::Brillig + } else { + RuntimeType::Acir + }, &context, ); @@ -141,7 +145,7 @@ impl<'a> FunctionContext<'a> { Expression::Call(call) => self.codegen_call(call), Expression::Let(let_expr) => self.codegen_let(let_expr), Expression::Constrain(expr, location, assert_message) => { - self.codegen_constrain(expr, *location, assert_message.clone()) + self.codegen_constrain(expr, *location, assert_message) } Expression::Assign(assign) => self.codegen_assign(assign), Expression::Semi(semi) => self.codegen_semi(semi), @@ -383,8 +387,9 @@ impl<'a> FunctionContext<'a> { length: Option, ) -> Result { // base_index = index * type_size + let index = self.make_array_index(index); let type_size = Self::convert_type(element_type).size_of_type(); - let type_size = self.builder.field_constant(type_size as u128); + let type_size = self.builder.numeric_constant(type_size as u128, Type::unsigned(64)); let base_index = self.builder.set_location(location).insert_binary(index, BinaryOp::Mul, type_size); @@ -421,27 +426,18 @@ impl<'a> FunctionContext<'a> { index: super::ir::value::ValueId, length: Option, ) { - let array_len = length.expect("ICE: a length must be supplied for indexing slices"); - // Check the type of the index value for valid comparisons - let array_len = match self.builder.type_of_value(index) { - Type::Numeric(numeric_type) => match numeric_type { - // If the index itself is an integer, keep the array length as a Field - NumericType::Unsigned { .. } | NumericType::Signed { .. } => array_len, - // If the index and the array length are both Fields we will not be able to perform a less than comparison on them. - // Thus, we cast the array length to a u64 before performing the less than comparison - NumericType::NativeField => self - .builder - .insert_cast(array_len, Type::Numeric(NumericType::Unsigned { bit_size: 64 })), - }, - _ => unreachable!("ICE: array index must be a numeric type"), - }; + let index = self.make_array_index(index); + // We convert the length as an array index type for comparison + let array_len = self + .make_array_index(length.expect("ICE: a length must be supplied for indexing slices")); let is_offset_out_of_bounds = self.builder.insert_binary(index, BinaryOp::Lt, array_len); let true_const = self.builder.numeric_constant(true, Type::bool()); + self.builder.insert_constrain( is_offset_out_of_bounds, true_const, - Some("Index out of bounds".to_owned()), + Some(Box::new("Index out of bounds".to_owned().into())), ); } @@ -665,15 +661,65 @@ impl<'a> FunctionContext<'a> { &mut self, expr: &Expression, location: Location, - assert_message: Option, + assert_message: &Option>, ) -> Result { 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, true_literal, assert_message); + + // Set the location here for any errors that may occur when we codegen the assert message + self.builder.set_location(location); + + let assert_message = self.codegen_constrain_error(assert_message)?; + + self.builder.insert_constrain(expr, true_literal, assert_message); Ok(Self::unit_value()) } + // This method does not necessary codegen the full assert message expression, thus it does not + // return a `Values` object. Instead we check the internals of the expression to make sure + // we have an `Expression::Call` as expected. An `Instruction::Call` is then constructed but not + // inserted to the SSA as we want that instruction to be atomic in SSA with a constrain instruction. + fn codegen_constrain_error( + &mut self, + assert_message: &Option>, + ) -> Result>, RuntimeError> { + let Some(assert_message_expr) = assert_message else { + return Ok(None) + }; + + if let ast::Expression::Literal(ast::Literal::Str(assert_message)) = + assert_message_expr.as_ref() + { + return Ok(Some(Box::new(ConstrainError::Static(assert_message.to_string())))); + } + + let ast::Expression::Call(call) = assert_message_expr.as_ref() else { + return Err(InternalError::Unexpected { + expected: "Expected a call expression".to_owned(), + found: "Instead found {expr:?}".to_owned(), + call_stack: self.builder.get_call_stack(), + } + .into()); + }; + + let func = 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); + } + + // If an array is passed as an argument we increase its reference count + for argument in &arguments { + self.builder.increment_array_reference_count(*argument); + } + + let instr = Instruction::Call { func, arguments }; + Ok(Some(Box::new(ConstrainError::Dynamic(instr)))) + } + fn codegen_assign(&mut self, assign: &ast::Assign) -> Result { let lhs = self.extract_current_value(&assign.lvalue)?; let rhs = self.codegen_expression(&assign.expression)?; diff --git a/noir/compiler/noirc_frontend/Cargo.toml b/noir/compiler/noirc_frontend/Cargo.toml index 80d767f7f2c..a3a8d460572 100644 --- a/noir/compiler/noirc_frontend/Cargo.toml +++ b/noir/compiler/noirc_frontend/Cargo.toml @@ -23,6 +23,7 @@ rustc-hash = "1.1.0" small-ord-set = "0.1.3" regex = "1.9.1" tracing.workspace = true +petgraph = "0.6" [dev-dependencies] strum = "0.24" diff --git a/noir/compiler/noirc_frontend/src/ast/mod.rs b/noir/compiler/noirc_frontend/src/ast/mod.rs index d9af5893024..1223f822af3 100644 --- a/noir/compiler/noirc_frontend/src/ast/mod.rs +++ b/noir/compiler/noirc_frontend/src/ast/mod.rs @@ -45,7 +45,7 @@ pub enum UnresolvedTypeData { Parenthesized(Box), /// A Named UnresolvedType can be a struct type or a type variable - Named(Path, Vec), + Named(Path, Vec, /*is_synthesized*/ bool), /// A Trait as return type or parameter of function, including its generics TraitAsType(Path, Vec), @@ -110,7 +110,7 @@ impl std::fmt::Display for UnresolvedTypeData { Signedness::Signed => write!(f, "i{num_bits}"), Signedness::Unsigned => write!(f, "u{num_bits}"), }, - Named(s, args) => { + Named(s, args, _) => { let args = vecmap(args, |arg| ToString::to_string(&arg.typ)); if args.is_empty() { write!(f, "{s}") @@ -179,6 +179,14 @@ impl std::fmt::Display for UnresolvedTypeExpression { } impl UnresolvedType { + pub fn is_synthesized(&self) -> bool { + match &self.typ { + UnresolvedTypeData::MutableReference(ty) => ty.is_synthesized(), + UnresolvedTypeData::Named(_, _, synthesized) => *synthesized, + _ => false, + } + } + pub fn without_span(typ: UnresolvedTypeData) -> UnresolvedType { UnresolvedType { typ, span: None } } diff --git a/noir/compiler/noirc_frontend/src/ast/statement.rs b/noir/compiler/noirc_frontend/src/ast/statement.rs index 73b1f68778d..f39b71405d3 100644 --- a/noir/compiler/noirc_frontend/src/ast/statement.rs +++ b/noir/compiler/noirc_frontend/src/ast/statement.rs @@ -416,7 +416,7 @@ pub enum LValue { } #[derive(Debug, PartialEq, Eq, Clone)] -pub struct ConstrainStatement(pub Expression, pub Option, pub ConstrainKind); +pub struct ConstrainStatement(pub Expression, pub Option, pub ConstrainKind); #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum ConstrainKind { @@ -428,18 +428,22 @@ pub enum ConstrainKind { #[derive(Debug, PartialEq, Eq, Clone)] pub enum Pattern { Identifier(Ident), - Mutable(Box, Span), + Mutable(Box, Span, /*is_synthesized*/ bool), Tuple(Vec, Span), Struct(Path, Vec<(Ident, Pattern)>, Span), } impl Pattern { + pub fn is_synthesized(&self) -> bool { + matches!(self, Pattern::Mutable(_, _, true)) + } + pub fn span(&self) -> Span { match self { Pattern::Identifier(ident) => ident.span(), - Pattern::Mutable(_, span) | Pattern::Tuple(_, span) | Pattern::Struct(_, _, span) => { - *span - } + Pattern::Mutable(_, span, _) + | Pattern::Tuple(_, span) + | Pattern::Struct(_, _, span) => *span, } } pub fn name_ident(&self) -> &Ident { @@ -452,7 +456,7 @@ impl Pattern { pub(crate) fn into_ident(self) -> Ident { match self { Pattern::Identifier(ident) => ident, - Pattern::Mutable(pattern, _) => pattern.into_ident(), + Pattern::Mutable(pattern, _, _) => pattern.into_ident(), other => panic!("Pattern::into_ident called on {other} pattern with no identifier"), } } @@ -688,7 +692,7 @@ impl Display for Pattern { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Pattern::Identifier(name) => name.fmt(f), - Pattern::Mutable(name, _) => write!(f, "mut {name}"), + Pattern::Mutable(name, _, _) => write!(f, "mut {name}"), Pattern::Tuple(fields, _) => { let fields = vecmap(fields, ToString::to_string); write!(f, "({})", fields.join(", ")) diff --git a/noir/compiler/noirc_frontend/src/ast/traits.rs b/noir/compiler/noirc_frontend/src/ast/traits.rs index feb627df60b..775f0a5f2b4 100644 --- a/noir/compiler/noirc_frontend/src/ast/traits.rs +++ b/noir/compiler/noirc_frontend/src/ast/traits.rs @@ -48,7 +48,7 @@ pub struct TypeImpl { pub object_type: UnresolvedType, pub type_span: Span, pub generics: UnresolvedGenerics, - pub methods: Vec, + pub methods: Vec<(NoirFunction, Span)>, } /// Ast node for an implementation of a trait for a particular type @@ -101,7 +101,7 @@ impl Display for TypeImpl { writeln!(f, "impl{} {} {{", generics, self.object_type)?; - for method in self.methods.iter() { + for (method, _) in self.methods.iter() { let method = method.to_string(); for line in method.lines() { writeln!(f, " {line}")?; diff --git a/noir/compiler/noirc_frontend/src/debug/mod.rs b/noir/compiler/noirc_frontend/src/debug/mod.rs new file mode 100644 index 00000000000..8335867c819 --- /dev/null +++ b/noir/compiler/noirc_frontend/src/debug/mod.rs @@ -0,0 +1,611 @@ +use crate::parser::{parse_program, ParsedModule}; +use crate::{ + ast, + ast::{Path, PathKind}, + parser::{Item, ItemKind}, +}; +use noirc_errors::{Span, Spanned}; +use std::collections::HashMap; +use std::collections::VecDeque; + +const MAX_MEMBER_ASSIGN_DEPTH: usize = 8; + +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +pub struct SourceVarId(pub u32); + +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +pub struct SourceFieldId(pub u32); + +/// This structure is used to collect information about variables to track +/// for debugging during the instrumentation injection phase. +#[derive(Debug, Clone)] +pub struct DebugInstrumenter { + // all collected variable names while instrumenting the source for variable tracking + pub variables: HashMap, + + // all field names referenced when assigning to a member of a variable + pub field_names: HashMap, + + next_var_id: u32, + next_field_name_id: u32, + + // last seen variable names and their IDs grouped by scope + scope: Vec>, +} + +impl Default for DebugInstrumenter { + fn default() -> Self { + Self { + variables: HashMap::default(), + field_names: HashMap::default(), + scope: vec![], + next_var_id: 0, + next_field_name_id: 1, + } + } +} + +impl DebugInstrumenter { + pub fn instrument_module(&mut self, module: &mut ParsedModule) { + module.items.iter_mut().for_each(|item| { + if let Item { kind: ItemKind::Function(f), .. } = item { + self.walk_fn(&mut f.def); + } + }); + // this part absolutely must happen after ast traversal above + // so that oracle functions don't get wrapped, resulting in infinite recursion: + self.insert_state_set_oracle(module, 8); + } + + fn insert_var(&mut self, var_name: &str) -> SourceVarId { + let var_id = SourceVarId(self.next_var_id); + self.next_var_id += 1; + self.variables.insert(var_id, var_name.to_string()); + self.scope.last_mut().unwrap().insert(var_name.to_string(), var_id); + var_id + } + + fn lookup_var(&self, var_name: &str) -> Option { + self.scope.iter().rev().find_map(|vars| vars.get(var_name).copied()) + } + + fn insert_field_name(&mut self, field_name: &str) -> SourceFieldId { + let field_name_id = SourceFieldId(self.next_field_name_id); + self.next_field_name_id += 1; + self.field_names.insert(field_name_id, field_name.to_string()); + field_name_id + } + + fn walk_fn(&mut self, func: &mut ast::FunctionDefinition) { + self.scope.push(HashMap::default()); + + let set_fn_params = func + .parameters + .iter() + .flat_map(|param| { + pattern_vars(¶m.pattern) + .iter() + .map(|(id, _is_mut)| { + let var_id = self.insert_var(&id.0.contents); + build_assign_var_stmt(var_id, id_expr(id)) + }) + .collect::>() + }) + .collect(); + + self.walk_scope(&mut func.body.0, func.span); + + // prepend fn params: + func.body.0 = vec![set_fn_params, func.body.0.clone()].concat(); + } + + // Modify a vector of statements in-place, adding instrumentation for sets and drops. + // This function will consume a scope level. + fn walk_scope(&mut self, statements: &mut Vec, span: Span) { + statements.iter_mut().for_each(|stmt| self.walk_statement(stmt)); + + // extract and save the return value from the scope if there is one + let ret_stmt = statements.pop(); + let has_ret_expr = match ret_stmt { + None => false, + Some(ast::Statement { kind: ast::StatementKind::Expression(ret_expr), .. }) => { + let save_ret_expr = ast::Statement { + kind: ast::StatementKind::Let(ast::LetStatement { + pattern: ast::Pattern::Identifier(ident("__debug_expr", ret_expr.span)), + r#type: ast::UnresolvedType::unspecified(), + expression: ret_expr.clone(), + }), + span: ret_expr.span, + }; + statements.push(save_ret_expr); + true + } + Some(ret_stmt) => { + // not an expression, so leave it untouched + statements.push(ret_stmt); + false + } + }; + + let span = Span::empty(span.end()); + + // drop scope variables + let scope_vars = self.scope.pop().unwrap_or(HashMap::default()); + let drop_vars_stmts = scope_vars.values().map(|var_id| build_drop_var_stmt(*var_id, span)); + statements.extend(drop_vars_stmts); + + // return the saved value in __debug_expr, or unit otherwise + let last_stmt = if has_ret_expr { + ast::Statement { + kind: ast::StatementKind::Expression(ast::Expression { + kind: ast::ExpressionKind::Variable(ast::Path { + segments: vec![ident("__debug_expr", span)], + kind: PathKind::Plain, + span, + }), + span, + }), + span, + } + } else { + ast::Statement { + kind: ast::StatementKind::Expression(ast::Expression { + kind: ast::ExpressionKind::Literal(ast::Literal::Unit), + span, + }), + span, + } + }; + statements.push(last_stmt); + } + + fn walk_let_statement(&mut self, let_stmt: &ast::LetStatement, span: &Span) -> ast::Statement { + // rewrites let statements written like this: + // let (((a,b,c),D { d }),e,f) = x; + // + // into statements like this: + // + // let (a,b,c,d,e,f,g) = { + // let (((a,b,c),D { d }),e,f) = x; + // wrap(1, a); + // wrap(2, b); + // ... + // wrap(6, f); + // (a,b,c,d,e,f,g) + // }; + + // a.b.c[3].x[i*4+1].z + + let vars = pattern_vars(&let_stmt.pattern); + let vars_pattern: Vec = vars + .iter() + .map(|(id, is_mut)| { + if *is_mut { + ast::Pattern::Mutable( + Box::new(ast::Pattern::Identifier(id.clone())), + id.span(), + true, + ) + } else { + ast::Pattern::Identifier(id.clone()) + } + }) + .collect(); + let vars_exprs: Vec = vars.iter().map(|(id, _)| id_expr(id)).collect(); + + let mut block_stmts = + vec![ast::Statement { kind: ast::StatementKind::Let(let_stmt.clone()), span: *span }]; + block_stmts.extend(vars.iter().map(|(id, _)| { + let var_id = self.insert_var(&id.0.contents); + build_assign_var_stmt(var_id, id_expr(id)) + })); + block_stmts.push(ast::Statement { + kind: ast::StatementKind::Expression(ast::Expression { + kind: ast::ExpressionKind::Tuple(vars_exprs), + span: let_stmt.pattern.span(), + }), + span: let_stmt.pattern.span(), + }); + + ast::Statement { + kind: ast::StatementKind::Let(ast::LetStatement { + pattern: ast::Pattern::Tuple(vars_pattern, let_stmt.pattern.span()), + r#type: ast::UnresolvedType::unspecified(), + expression: ast::Expression { + kind: ast::ExpressionKind::Block(ast::BlockExpression(block_stmts)), + span: let_stmt.expression.span, + }, + }), + span: *span, + } + } + + fn walk_assign_statement( + &mut self, + assign_stmt: &ast::AssignStatement, + span: &Span, + ) -> ast::Statement { + // X = Y becomes: + // X = { + // let __debug_expr = Y; + // + // __debug_var_assign(17, __debug_expr); + // // or: + // __debug_member_assign_{arity}(17, __debug_expr, _v0, _v1..., _v{arity}); + // + // __debug_expr + // }; + + let let_kind = ast::StatementKind::Let(ast::LetStatement { + pattern: ast::Pattern::Identifier(ident("__debug_expr", assign_stmt.expression.span)), + r#type: ast::UnresolvedType::unspecified(), + expression: assign_stmt.expression.clone(), + }); + let expression_span = assign_stmt.expression.span; + let new_assign_stmt = match &assign_stmt.lvalue { + ast::LValue::Ident(id) => { + let var_id = self + .lookup_var(&id.0.contents) + .unwrap_or_else(|| panic!("var lookup failed for var_name={}", &id.0.contents)); + build_assign_var_stmt(var_id, id_expr(&ident("__debug_expr", id.span()))) + } + ast::LValue::Dereference(_lv) => { + // TODO: this is a dummy statement for now, but we should + // somehow track the derefence and update the pointed to + // variable + ast::Statement { + kind: ast::StatementKind::Expression(uint_expr(0, *span)), + span: *span, + } + } + _ => { + let mut indexes = vec![]; + let mut cursor = &assign_stmt.lvalue; + let var_id; + loop { + match cursor { + ast::LValue::Ident(id) => { + var_id = self.lookup_var(&id.0.contents).unwrap_or_else(|| { + panic!("var lookup failed for var_name={}", &id.0.contents) + }); + break; + } + ast::LValue::MemberAccess { object, field_name } => { + cursor = object; + let field_name_id = self.insert_field_name(&field_name.0.contents); + indexes.push(sint_expr(-(field_name_id.0 as i128), expression_span)); + } + ast::LValue::Index { index, array } => { + cursor = array; + indexes.push(index.clone()); + } + ast::LValue::Dereference(_ref) => { + unimplemented![] + } + } + } + build_assign_member_stmt( + var_id, + &indexes, + &id_expr(&ident("__debug_expr", expression_span)), + ) + } + }; + let ret_kind = + ast::StatementKind::Expression(id_expr(&ident("__debug_expr", expression_span))); + + ast::Statement { + kind: ast::StatementKind::Assign(ast::AssignStatement { + lvalue: assign_stmt.lvalue.clone(), + expression: ast::Expression { + kind: ast::ExpressionKind::Block(ast::BlockExpression(vec![ + ast::Statement { kind: let_kind, span: expression_span }, + new_assign_stmt, + ast::Statement { kind: ret_kind, span: expression_span }, + ])), + span: expression_span, + }, + }), + span: *span, + } + } + + fn walk_expr(&mut self, expr: &mut ast::Expression) { + match &mut expr.kind { + ast::ExpressionKind::Block(ast::BlockExpression(ref mut statements)) => { + self.scope.push(HashMap::default()); + self.walk_scope(statements, expr.span); + } + ast::ExpressionKind::Prefix(prefix_expr) => { + self.walk_expr(&mut prefix_expr.rhs); + } + ast::ExpressionKind::Index(index_expr) => { + self.walk_expr(&mut index_expr.collection); + self.walk_expr(&mut index_expr.index); + } + ast::ExpressionKind::Call(call_expr) => { + // TODO: push a stack frame or something here? + self.walk_expr(&mut call_expr.func); + call_expr.arguments.iter_mut().for_each(|ref mut expr| { + self.walk_expr(expr); + }); + } + ast::ExpressionKind::MethodCall(mc_expr) => { + // TODO: also push a stack frame here + self.walk_expr(&mut mc_expr.object); + mc_expr.arguments.iter_mut().for_each(|ref mut expr| { + self.walk_expr(expr); + }); + } + ast::ExpressionKind::Constructor(c_expr) => { + c_expr.fields.iter_mut().for_each(|(_id, ref mut expr)| { + self.walk_expr(expr); + }); + } + ast::ExpressionKind::MemberAccess(ma_expr) => { + self.walk_expr(&mut ma_expr.lhs); + } + ast::ExpressionKind::Cast(cast_expr) => { + self.walk_expr(&mut cast_expr.lhs); + } + ast::ExpressionKind::Infix(infix_expr) => { + self.walk_expr(&mut infix_expr.lhs); + self.walk_expr(&mut infix_expr.rhs); + } + ast::ExpressionKind::If(if_expr) => { + self.walk_expr(&mut if_expr.condition); + self.walk_expr(&mut if_expr.consequence); + if let Some(ref mut alt) = if_expr.alternative { + self.walk_expr(alt); + } + } + ast::ExpressionKind::Tuple(exprs) => { + exprs.iter_mut().for_each(|ref mut expr| { + self.walk_expr(expr); + }); + } + ast::ExpressionKind::Lambda(lambda) => { + self.walk_expr(&mut lambda.body); + } + ast::ExpressionKind::Parenthesized(expr) => { + self.walk_expr(expr); + } + _ => {} + } + } + + fn walk_for(&mut self, for_stmt: &mut ast::ForLoopStatement) { + let var_name = &for_stmt.identifier.0.contents; + let var_id = self.insert_var(var_name); + + let set_stmt = build_assign_var_stmt(var_id, id_expr(&for_stmt.identifier)); + let drop_stmt = build_drop_var_stmt(var_id, Span::empty(for_stmt.span.end())); + + self.walk_expr(&mut for_stmt.block); + for_stmt.block = ast::Expression { + kind: ast::ExpressionKind::Block(ast::BlockExpression(vec![ + set_stmt, + ast::Statement { + kind: ast::StatementKind::Semi(for_stmt.block.clone()), + span: for_stmt.block.span, + }, + drop_stmt, + ])), + span: for_stmt.span, + }; + } + + fn walk_statement(&mut self, stmt: &mut ast::Statement) { + match &mut stmt.kind { + ast::StatementKind::Let(let_stmt) => { + *stmt = self.walk_let_statement(let_stmt, &stmt.span); + } + ast::StatementKind::Assign(assign_stmt) => { + *stmt = self.walk_assign_statement(assign_stmt, &stmt.span); + } + ast::StatementKind::Expression(expr) => { + self.walk_expr(expr); + } + ast::StatementKind::Semi(expr) => { + self.walk_expr(expr); + } + ast::StatementKind::For(ref mut for_stmt) => { + self.walk_for(for_stmt); + } + _ => {} // Constrain, Error + } + } + + fn insert_state_set_oracle(&self, module: &mut ParsedModule, n: u32) { + let member_assigns = (1..=n) + .map(|i| format!["__debug_member_assign_{i}"]) + .collect::>() + .join(",\n"); + let (program, errors) = parse_program(&format!( + r#" + use dep::__debug::{{ + __debug_var_assign, + __debug_var_drop, + __debug_dereference_assign, + {member_assigns}, + }};"# + )); + if !errors.is_empty() { + panic!("errors parsing internal oracle definitions: {errors:?}") + } + module.items.extend(program.items); + } +} + +pub fn build_debug_crate_file() -> String { + [ + r#" + #[oracle(__debug_var_assign)] + unconstrained fn __debug_var_assign_oracle(_var_id: u32, _value: T) {} + unconstrained fn __debug_var_assign_inner(var_id: u32, value: T) { + __debug_var_assign_oracle(var_id, value); + } + pub fn __debug_var_assign(var_id: u32, value: T) { + __debug_var_assign_inner(var_id, value); + } + + #[oracle(__debug_var_drop)] + unconstrained fn __debug_var_drop_oracle(_var_id: u32) {} + unconstrained fn __debug_var_drop_inner(var_id: u32) { + __debug_var_drop_oracle(var_id); + } + pub fn __debug_var_drop(var_id: u32) { + __debug_var_drop_inner(var_id); + } + + #[oracle(__debug_dereference_assign)] + unconstrained fn __debug_dereference_assign_oracle(_var_id: u32, _value: T) {} + unconstrained fn __debug_dereference_assign_inner(var_id: u32, value: T) { + __debug_dereference_assign_oracle(var_id, value); + } + pub fn __debug_dereference_assign(var_id: u32, value: T) { + __debug_dereference_assign_inner(var_id, value); + } + "# + .to_string(), + (1..=MAX_MEMBER_ASSIGN_DEPTH) + .map(|n| { + let var_sig = + (0..n).map(|i| format!["_v{i}: Field"]).collect::>().join(", "); + let vars = (0..n).map(|i| format!["_v{i}"]).collect::>().join(", "); + format!( + r#" + #[oracle(__debug_member_assign_{n})] + unconstrained fn __debug_oracle_member_assign_{n}( + _var_id: u32, _value: T, {var_sig} + ) {{}} + unconstrained fn __debug_inner_member_assign_{n}( + var_id: u32, value: T, {var_sig} + ) {{ + __debug_oracle_member_assign_{n}(var_id, value, {vars}); + }} + pub fn __debug_member_assign_{n}(var_id: u32, value: T, {var_sig}) {{ + __debug_inner_member_assign_{n}(var_id, value, {vars}); + }} + + "# + ) + }) + .collect::>() + .join("\n"), + ] + .join("\n") +} + +fn build_assign_var_stmt(var_id: SourceVarId, expr: ast::Expression) -> ast::Statement { + let span = expr.span; + let kind = ast::ExpressionKind::Call(Box::new(ast::CallExpression { + func: Box::new(ast::Expression { + kind: ast::ExpressionKind::Variable(ast::Path { + segments: vec![ident("__debug_var_assign", span)], + kind: PathKind::Plain, + span, + }), + span, + }), + arguments: vec![uint_expr(var_id.0 as u128, span), expr], + })); + ast::Statement { kind: ast::StatementKind::Semi(ast::Expression { kind, span }), span } +} + +fn build_drop_var_stmt(var_id: SourceVarId, span: Span) -> ast::Statement { + let kind = ast::ExpressionKind::Call(Box::new(ast::CallExpression { + func: Box::new(ast::Expression { + kind: ast::ExpressionKind::Variable(ast::Path { + segments: vec![ident("__debug_var_drop", span)], + kind: PathKind::Plain, + span, + }), + span, + }), + arguments: vec![uint_expr(var_id.0 as u128, span)], + })); + ast::Statement { kind: ast::StatementKind::Semi(ast::Expression { kind, span }), span } +} + +fn build_assign_member_stmt( + var_id: SourceVarId, + indexes: &[ast::Expression], + expr: &ast::Expression, +) -> ast::Statement { + let arity = indexes.len(); + if arity > MAX_MEMBER_ASSIGN_DEPTH { + unreachable!("Assignment to member exceeds maximum depth for debugging"); + } + let span = expr.span; + let kind = ast::ExpressionKind::Call(Box::new(ast::CallExpression { + func: Box::new(ast::Expression { + kind: ast::ExpressionKind::Variable(ast::Path { + segments: vec![ident(&format!["__debug_member_assign_{arity}"], span)], + kind: PathKind::Plain, + span, + }), + span, + }), + arguments: [ + vec![uint_expr(var_id.0 as u128, span)], + vec![expr.clone()], + indexes.iter().rev().cloned().collect(), + ] + .concat(), + })); + ast::Statement { kind: ast::StatementKind::Semi(ast::Expression { kind, span }), span } +} + +fn pattern_vars(pattern: &ast::Pattern) -> Vec<(ast::Ident, bool)> { + let mut vars = vec![]; + let mut stack = VecDeque::from([(pattern, false)]); + while stack.front().is_some() { + let (pattern, is_mut) = stack.pop_front().unwrap(); + match pattern { + ast::Pattern::Identifier(id) => { + vars.push((id.clone(), is_mut)); + } + ast::Pattern::Mutable(pattern, _, _) => { + stack.push_back((pattern, true)); + } + ast::Pattern::Tuple(patterns, _) => { + stack.extend(patterns.iter().map(|pattern| (pattern, false))); + } + ast::Pattern::Struct(_, pids, _) => { + stack.extend(pids.iter().map(|(_, pattern)| (pattern, is_mut))); + vars.extend(pids.iter().map(|(id, _)| (id.clone(), false))); + } + } + } + vars +} + +fn ident(s: &str, span: Span) -> ast::Ident { + ast::Ident(Spanned::from(span, s.to_string())) +} + +fn id_expr(id: &ast::Ident) -> ast::Expression { + ast::Expression { + kind: ast::ExpressionKind::Variable(Path { + segments: vec![id.clone()], + kind: PathKind::Plain, + span: id.span(), + }), + span: id.span(), + } +} + +fn uint_expr(x: u128, span: Span) -> ast::Expression { + ast::Expression { + kind: ast::ExpressionKind::Literal(ast::Literal::Integer(x.into(), false)), + span, + } +} + +fn sint_expr(x: i128, span: Span) -> ast::Expression { + ast::Expression { + kind: ast::ExpressionKind::Literal(ast::Literal::Integer(x.abs().into(), x < 0)), + span, + } +} diff --git a/noir/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs b/noir/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs index f7441750fc8..0d1dd1b4337 100644 --- a/noir/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/noir/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -15,7 +15,7 @@ use crate::hir::type_check::{type_check_func, TypeCheckError, TypeChecker}; use crate::hir::Context; use crate::macros_api::{MacroError, MacroProcessor}; -use crate::node_interner::{FuncId, NodeInterner, StmtId, StructId, TraitId, TypeAliasId}; +use crate::node_interner::{FuncId, GlobalId, NodeInterner, StructId, TraitId, TypeAliasId}; use crate::parser::{ParserError, SortedModule}; use crate::{ @@ -109,7 +109,7 @@ pub struct UnresolvedTypeAlias { pub struct UnresolvedGlobal { pub file_id: FileId, pub module_id: LocalModuleId, - pub stmt_id: StmtId, + pub global_id: GlobalId, pub stmt_def: LetStatement, } @@ -317,9 +317,10 @@ impl DefCollector { // Must resolve structs before we resolve globals. errors.extend(resolve_structs(context, def_collector.collected_types, crate_id)); - // We must wait to resolve non-integer globals until after we resolve structs since structs + // We must wait to resolve non-integer globals until after we resolve structs since struct // globals will need to reference the struct type they're initialized to to ensure they are valid. resolved_globals.extend(resolve_globals(context, other_globals, crate_id)); + errors.extend(resolved_globals.errors); // Bind trait impls to their trait. Collect trait functions, that have a // default implementation, which hasn't been overridden. @@ -338,31 +339,31 @@ impl DefCollector { // over trait methods if there are name conflicts. errors.extend(collect_impls(context, crate_id, &def_collector.collected_impls)); - // Lower each function in the crate. This is now possible since imports have been resolved - let file_func_ids = resolve_free_functions( + // Resolve each function in the crate. This is now possible since imports have been resolved + let mut functions = Vec::new(); + functions.extend(resolve_free_functions( &mut context.def_interner, crate_id, &context.def_maps, def_collector.collected_functions, None, &mut errors, - ); + )); - let file_method_ids = resolve_impls( + functions.extend(resolve_impls( &mut context.def_interner, crate_id, &context.def_maps, def_collector.collected_impls, &mut errors, - ); - let file_trait_impls_ids = resolve_trait_impls( + )); + + functions.extend(resolve_trait_impls( context, def_collector.collected_traits_impls, crate_id, &mut errors, - ); - - errors.extend(resolved_globals.errors); + )); for macro_processor in macro_processors { macro_processor.process_typed_ast(&crate_id, context).unwrap_or_else( @@ -371,12 +372,11 @@ impl DefCollector { }, ); } - errors.extend(type_check_globals(&mut context.def_interner, resolved_globals.globals)); - // Type check all of the functions in the crate - errors.extend(type_check_functions(&mut context.def_interner, file_func_ids)); - errors.extend(type_check_functions(&mut context.def_interner, file_method_ids)); - errors.extend(type_check_functions(&mut context.def_interner, file_trait_impls_ids)); + errors.extend(context.def_interner.check_for_dependency_cycles()); + + errors.extend(type_check_globals(&mut context.def_interner, resolved_globals.globals)); + errors.extend(type_check_functions(&mut context.def_interner, functions)); errors } } @@ -436,15 +436,15 @@ fn filter_literal_globals( fn type_check_globals( interner: &mut NodeInterner, - global_ids: Vec<(FileId, StmtId)>, + global_ids: Vec<(FileId, GlobalId)>, ) -> Vec<(CompilationError, fm::FileId)> { global_ids - .iter() - .flat_map(|(file_id, stmt_id)| { - TypeChecker::check_global(stmt_id, interner) + .into_iter() + .flat_map(|(file_id, global_id)| { + TypeChecker::check_global(global_id, interner) .iter() .cloned() - .map(|e| (e.into(), *file_id)) + .map(|e| (e.into(), file_id)) .collect::>() }) .collect() @@ -455,12 +455,12 @@ fn type_check_functions( file_func_ids: Vec<(FileId, FuncId)>, ) -> Vec<(CompilationError, fm::FileId)> { file_func_ids - .iter() + .into_iter() .flat_map(|(file, func)| { - type_check_func(interner, *func) + type_check_func(interner, func) .iter() .cloned() - .map(|e| (e.into(), *file)) + .map(|e| (e.into(), file)) .collect::>() }) .collect() diff --git a/noir/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs b/noir/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs index 3cd60c33b8b..77224cc311c 100644 --- a/noir/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs +++ b/noir/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs @@ -89,13 +89,12 @@ impl<'a> ModCollector<'a> { for global in globals { let name = global.pattern.name_ident().clone(); - // First create dummy function in the DefInterner - // So that we can get a StmtId - let stmt_id = context.def_interner.push_empty_global(); + let global_id = + context.def_interner.push_empty_global(name.clone(), self.module_id, self.file_id); // Add the statement to the scope so its path can be looked up later - let result = - self.def_collector.def_map.modules[self.module_id.0].declare_global(name, stmt_id); + let result = self.def_collector.def_map.modules[self.module_id.0] + .declare_global(name, global_id); if let Err((first_def, second_def)) = result { let err = DefCollectorErrorKind::Duplicate { @@ -109,7 +108,7 @@ impl<'a> ModCollector<'a> { self.def_collector.collected_globals.push(UnresolvedGlobal { file_id: self.file_id, module_id: self.module_id, - stmt_id, + global_id, stmt_def: global, }); } @@ -126,7 +125,7 @@ impl<'a> ModCollector<'a> { trait_id: None, }; - for method in r#impl.methods { + for (method, _) in r#impl.methods { let func_id = context.def_interner.push_empty_fn(); let location = Location::new(method.span(), self.file_id); context.def_interner.push_function(func_id, &method.def, module_id, location); @@ -440,11 +439,15 @@ impl<'a> ModCollector<'a> { } } TraitItem::Constant { name, .. } => { - let stmt_id = context.def_interner.push_empty_global(); + let global_id = context.def_interner.push_empty_global( + name.clone(), + trait_id.0.local_id, + self.file_id, + ); if let Err((first_def, second_def)) = self.def_collector.def_map.modules [trait_id.0.local_id.0] - .declare_global(name.clone(), stmt_id) + .declare_global(name.clone(), global_id) { let error = DefCollectorErrorKind::Duplicate { typ: DuplicateType::TraitAssociatedConst, diff --git a/noir/compiler/noirc_frontend/src/hir/def_map/module_data.rs b/noir/compiler/noirc_frontend/src/hir/def_map/module_data.rs index fbb5e5cf741..309618dd011 100644 --- a/noir/compiler/noirc_frontend/src/hir/def_map/module_data.rs +++ b/noir/compiler/noirc_frontend/src/hir/def_map/module_data.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; use noirc_errors::Location; use crate::{ - node_interner::{FuncId, StmtId, StructId, TraitId, TypeAliasId}, + node_interner::{FuncId, GlobalId, StructId, TraitId, TypeAliasId}, Ident, }; @@ -76,7 +76,7 @@ impl ModuleData { self.definitions.remove_definition(name); } - pub fn declare_global(&mut self, name: Ident, id: StmtId) -> Result<(), (Ident, Ident)> { + pub fn declare_global(&mut self, name: Ident, id: GlobalId) -> Result<(), (Ident, Ident)> { self.declare(name, id.into(), None) } diff --git a/noir/compiler/noirc_frontend/src/hir/def_map/module_def.rs b/noir/compiler/noirc_frontend/src/hir/def_map/module_def.rs index 3e5629639fa..54d092f9515 100644 --- a/noir/compiler/noirc_frontend/src/hir/def_map/module_def.rs +++ b/noir/compiler/noirc_frontend/src/hir/def_map/module_def.rs @@ -1,4 +1,4 @@ -use crate::node_interner::{FuncId, StmtId, StructId, TraitId, TypeAliasId}; +use crate::node_interner::{FuncId, GlobalId, StructId, TraitId, TypeAliasId}; use super::ModuleId; @@ -10,7 +10,7 @@ pub enum ModuleDefId { TypeId(StructId), TypeAliasId(TypeAliasId), TraitId(TraitId), - GlobalId(StmtId), + GlobalId(GlobalId), } impl ModuleDefId { @@ -42,9 +42,9 @@ impl ModuleDefId { } } - pub fn as_global(&self) -> Option { + pub fn as_global(&self) -> Option { match self { - ModuleDefId::GlobalId(stmt_id) => Some(*stmt_id), + ModuleDefId::GlobalId(global_id) => Some(*global_id), _ => None, } } @@ -88,9 +88,9 @@ impl From for ModuleDefId { } } -impl From for ModuleDefId { - fn from(stmt_id: StmtId) -> Self { - ModuleDefId::GlobalId(stmt_id) +impl From for ModuleDefId { + fn from(global_id: GlobalId) -> Self { + ModuleDefId::GlobalId(global_id) } } @@ -162,13 +162,13 @@ impl TryFromModuleDefId for TraitId { } } -impl TryFromModuleDefId for StmtId { +impl TryFromModuleDefId for GlobalId { fn try_from(id: ModuleDefId) -> Option { id.as_global() } fn dummy_id() -> Self { - StmtId::dummy_id() + GlobalId::dummy_id() } fn description() -> String { diff --git a/noir/compiler/noirc_frontend/src/hir/mod.rs b/noir/compiler/noirc_frontend/src/hir/mod.rs index 2124b5281f4..4d3800f1a50 100644 --- a/noir/compiler/noirc_frontend/src/hir/mod.rs +++ b/noir/compiler/noirc_frontend/src/hir/mod.rs @@ -4,6 +4,7 @@ pub mod resolution; pub mod scope; pub mod type_check; +use crate::debug::DebugInstrumenter; use crate::graph::{CrateGraph, CrateId}; use crate::hir_def::function::FuncMeta; use crate::node_interner::{FuncId, NodeInterner, StructId}; @@ -31,6 +32,8 @@ pub struct Context<'file_manager, 'parsed_files> { // is read-only however, once it has been passed to the Context. pub file_manager: Cow<'file_manager, FileManager>, + pub debug_instrumenter: DebugInstrumenter, + /// A map of each file that already has been visited from a prior `mod foo;` declaration. /// This is used to issue an error if a second `mod foo;` is declared to the same file. pub visited_files: BTreeMap, @@ -56,6 +59,7 @@ impl Context<'_, '_> { visited_files: BTreeMap::new(), crate_graph: CrateGraph::default(), file_manager: Cow::Owned(file_manager), + debug_instrumenter: DebugInstrumenter::default(), parsed_files: Cow::Owned(parsed_files), } } @@ -70,6 +74,7 @@ impl Context<'_, '_> { visited_files: BTreeMap::new(), crate_graph: CrateGraph::default(), file_manager: Cow::Borrowed(file_manager), + debug_instrumenter: DebugInstrumenter::default(), parsed_files: Cow::Borrowed(parsed_files), } } diff --git a/noir/compiler/noirc_frontend/src/hir/resolution/errors.rs b/noir/compiler/noirc_frontend/src/hir/resolution/errors.rs index 0752838c82e..d2fe67da38c 100644 --- a/noir/compiler/noirc_frontend/src/hir/resolution/errors.rs +++ b/noir/compiler/noirc_frontend/src/hir/resolution/errors.rs @@ -88,6 +88,8 @@ pub enum ResolverError { MisplacedRecursiveAttribute { ident: Ident }, #[error("Usage of the `#[foreign]` or `#[builtin]` function attributes are not allowed outside of the Noir standard library")] LowLevelFunctionOutsideOfStdlib { ident: Ident }, + #[error("Dependency cycle found, '{item}' recursively depends on itself: {cycle} ")] + DependencyCycle { span: Span, item: String, cycle: String }, } impl ResolverError { @@ -142,33 +144,33 @@ impl From for Diagnostic { field.span(), ), ResolverError::NoSuchField { field, struct_definition } => { - let mut error = Diagnostic::simple_error( + Diagnostic::simple_error( format!("no such field {field} defined in struct {struct_definition}"), String::new(), field.span(), - ); - - error.add_secondary( - format!("{struct_definition} defined here with no {field} field"), - struct_definition.span(), - ); - error + ) } - ResolverError::MissingFields { span, missing_fields, struct_definition } => { + ResolverError::MissingFields { span, mut missing_fields, struct_definition } => { let plural = if missing_fields.len() != 1 { "s" } else { "" }; - let missing_fields = missing_fields.join(", "); + let remaining_fields_names = match &missing_fields[..] { + [field1] => field1.clone(), + [field1, field2] => format!("{field1} and {field2}"), + [field1, field2, field3] => format!("{field1}, {field2} and {field3}"), + _ => { + let len = missing_fields.len() - 3; + let len_plural = if len != 1 {"s"} else {""}; - let mut error = Diagnostic::simple_error( - format!("missing field{plural}: {missing_fields}"), + let truncated_fields = format!(" and {len} other field{len_plural}"); + missing_fields.truncate(3); + format!("{}{truncated_fields}", missing_fields.join(", ")) + } + }; + + Diagnostic::simple_error( + format!("missing field{plural} {remaining_fields_names} in struct {struct_definition}"), String::new(), span, - ); - - error.add_secondary( - format!("{struct_definition} defined here"), - struct_definition.span(), - ); - error + ) } ResolverError::UnnecessaryMut { first_mut, second_mut } => { let mut error = Diagnostic::simple_error( @@ -332,6 +334,13 @@ impl From for Diagnostic { "Usage of the `#[foreign]` or `#[builtin]` function attributes are not allowed outside of the Noir standard library".into(), ident.span(), ), + ResolverError::DependencyCycle { span, item, cycle } => { + Diagnostic::simple_error( + "Dependency cycle found".into(), + format!("'{item}' recursively depends on itself: {cycle}"), + span, + ) + }, } } } diff --git a/noir/compiler/noirc_frontend/src/hir/resolution/globals.rs b/noir/compiler/noirc_frontend/src/hir/resolution/globals.rs index b5aec212dbf..9fb31271727 100644 --- a/noir/compiler/noirc_frontend/src/hir/resolution/globals.rs +++ b/noir/compiler/noirc_frontend/src/hir/resolution/globals.rs @@ -6,13 +6,13 @@ use crate::{ def_map::ModuleId, Context, }, - node_interner::StmtId, + node_interner::GlobalId, }; use fm::FileId; use iter_extended::vecmap; pub(crate) struct ResolvedGlobals { - pub(crate) globals: Vec<(FileId, StmtId)>, + pub(crate) globals: Vec<(FileId, GlobalId)>, pub(crate) errors: Vec<(CompilationError, FileId)>, } @@ -40,16 +40,13 @@ pub(crate) fn resolve_globals( global.file_id, ); - let name = global.stmt_def.pattern.name_ident().clone(); - - let hir_stmt = resolver.resolve_global_let(global.stmt_def); + let hir_stmt = resolver.resolve_global_let(global.stmt_def, global.global_id); errors.extend(take_errors(global.file_id, resolver)); - context.def_interner.update_global(global.stmt_id, hir_stmt); - - context.def_interner.push_global(global.stmt_id, name, global.module_id); + let statement_id = context.def_interner.get_global(global.global_id).let_statement; + context.def_interner.replace_statement(statement_id, hir_stmt); - (global.file_id, global.stmt_id) + (global.file_id, global.global_id) }); ResolvedGlobals { globals, errors } } diff --git a/noir/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/noir/compiler/noirc_frontend/src/hir/resolution/resolver.rs index f025f817b09..bef5e113428 100644 --- a/noir/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/noir/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -28,8 +28,8 @@ use crate::graph::CrateId; use crate::hir::def_map::{LocalModuleId, ModuleDefId, TryFromModuleDefId, MAIN_FUNCTION}; use crate::hir_def::stmt::{HirAssignStatement, HirForStatement, HirLValue, HirPattern}; use crate::node_interner::{ - DefinitionId, DefinitionKind, ExprId, FuncId, NodeInterner, StmtId, StructId, TraitId, - TraitImplId, TraitMethodId, + DefinitionId, DefinitionKind, DependencyId, ExprId, FuncId, GlobalId, NodeInterner, StmtId, + StructId, TraitId, TraitImplId, TraitMethodId, }; use crate::{ hir::{def_map::CrateDefMap, resolution::path_resolver::PathResolver}, @@ -93,6 +93,10 @@ pub struct Resolver<'a> { /// to the corresponding trait impl ID. current_trait_impl: Option, + /// The current dependency item we're resolving. + /// Used to link items to their dependencies in the dependency graph + current_item: Option, + /// True if the current module is a contract. /// This is usually determined by self.path_resolver.module_id(), but it can /// be overridden for impls. Impls are an odd case since the methods within resolve @@ -148,6 +152,7 @@ impl<'a> Resolver<'a> { errors: Vec::new(), lambda_stack: Vec::new(), current_trait_impl: None, + current_item: None, file, in_contract, } @@ -184,6 +189,7 @@ impl<'a> Resolver<'a> { func_id: FuncId, ) -> (HirFunction, FuncMeta, Vec) { self.scopes.start_function(); + self.current_item = Some(DependencyId::Function(func_id)); // Check whether the function has globals in the local module and add them to the scope self.resolve_local_globals(); @@ -338,21 +344,22 @@ impl<'a> Resolver<'a> { // This check is necessary to maintain the same definition ids in the interner. Currently, each function uses a new resolver that has its own ScopeForest and thus global scope. // We must first check whether an existing definition ID has been inserted as otherwise there will be multiple definitions for the same global statement. // This leads to an error in evaluation where the wrong definition ID is selected when evaluating a statement using the global. The check below prevents this error. - let mut stmt_id = None; + let mut global_id = None; let global = self.interner.get_all_globals(); - for (global_stmt_id, global_info) in global { + for global_info in global { if global_info.ident == name && global_info.local_id == self.path_resolver.local_module_id() { - stmt_id = Some(global_stmt_id); + global_id = Some(global_info.id); } } - let (ident, resolver_meta) = if let Some(id) = stmt_id { - let hir_let_stmt = self.interner.let_statement(&id); - let ident = hir_let_stmt.ident(); + let (ident, resolver_meta) = if let Some(id) = global_id { + let global = self.interner.get_global(id); + let hir_ident = HirIdent::non_trait_method(global.definition_id, global.location); + let ident = hir_ident.clone(); let resolver_meta = ResolverMeta { num_times_used: 0, ident, warn_if_unused: true }; - (hir_let_stmt.ident(), resolver_meta) + (hir_ident, resolver_meta) } else { let location = Location::new(name.span(), self.file); let id = @@ -483,7 +490,7 @@ impl<'a> Resolver<'a> { Unit => Type::Unit, Unspecified => Type::Error, Error => Type::Error, - Named(path, args) => self.resolve_named_type(path, args, new_variables), + 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) => { @@ -599,6 +606,11 @@ impl<'a> Resolver<'a> { struct_type.borrow().to_string() }); + if let Some(current_item) = self.current_item { + let dependency_id = struct_type.borrow().id; + self.interner.add_type_dependency(current_item, dependency_id); + } + Type::Struct(struct_type, args) } None => Type::Error, @@ -651,7 +663,10 @@ impl<'a> Resolver<'a> { // If we cannot find a local generic of the same name, try to look up a global match self.path_resolver.resolve(self.def_maps, path.clone()) { Ok(ModuleDefId::GlobalId(id)) => { - Some(Type::Constant(self.eval_global_as_array_length(id))) + if let Some(current_item) = self.current_item { + self.interner.add_global_dependency(current_item, id); + } + Some(Type::Constant(self.eval_global_as_array_length(id, path))) } _ => None, } @@ -830,23 +845,27 @@ impl<'a> Resolver<'a> { pub fn resolve_struct_fields( mut self, unresolved: NoirStruct, + struct_id: StructId, ) -> (Generics, Vec<(Ident, Type)>, Vec) { let generics = self.add_generics(&unresolved.generics); // Check whether the struct definition has globals in the local module and add them to the scope self.resolve_local_globals(); + self.current_item = Some(DependencyId::Struct(struct_id)); let fields = vecmap(unresolved.fields, |(ident, typ)| (ident, self.resolve_type(typ))); (generics, fields, self.errors) } fn resolve_local_globals(&mut self) { - for (stmt_id, global_info) in self.interner.get_all_globals() { - if global_info.local_id == self.path_resolver.local_module_id() { - let global_stmt = self.interner.let_statement(&stmt_id); - let definition = DefinitionKind::Global(global_stmt.expression); - self.add_global_variable_decl(global_info.ident, definition); + let globals = vecmap(self.interner.get_all_globals(), |global| { + (global.id, global.local_id, global.ident.clone()) + }); + for (id, local_module_id, name) in globals { + if local_module_id == self.path_resolver.local_module_id() { + let definition = DefinitionKind::Global(id); + self.add_global_variable_decl(name, definition); } } } @@ -1116,9 +1135,15 @@ impl<'a> Resolver<'a> { } } - pub fn resolve_global_let(&mut self, let_stmt: crate::LetStatement) -> HirStatement { + pub fn resolve_global_let( + &mut self, + let_stmt: crate::LetStatement, + global_id: GlobalId, + ) -> HirStatement { + self.current_item = Some(DependencyId::Global(global_id)); let expression = self.resolve_expression(let_stmt.expression); - let definition = DefinitionKind::Global(expression); + let global_id = self.interner.next_global_id(); + let definition = DefinitionKind::Global(global_id); HirStatement::Let(HirLetStatement { pattern: self.resolve_pattern(let_stmt.pattern, definition), @@ -1139,9 +1164,16 @@ impl<'a> Resolver<'a> { }) } StatementKind::Constrain(constrain_stmt) => { + let span = constrain_stmt.0.span; + let assert_msg_call_expr_id = + self.resolve_assert_message(constrain_stmt.1, span, constrain_stmt.0.clone()); let expr_id = self.resolve_expression(constrain_stmt.0); - let assert_message = constrain_stmt.1; - HirStatement::Constrain(HirConstrainStatement(expr_id, self.file, assert_message)) + + HirStatement::Constrain(HirConstrainStatement( + expr_id, + self.file, + assert_msg_call_expr_id, + )) } StatementKind::Expression(expr) => { HirStatement::Expression(self.resolve_expression(expr)) @@ -1190,6 +1222,44 @@ impl<'a> Resolver<'a> { } } + fn resolve_assert_message( + &mut self, + assert_message_expr: Option, + span: Span, + condition: Expression, + ) -> Option { + let assert_message_expr = assert_message_expr?; + + if matches!( + assert_message_expr, + Expression { kind: ExpressionKind::Literal(Literal::Str(..)), .. } + ) { + return Some(self.resolve_expression(assert_message_expr)); + } + + let is_in_stdlib = self.path_resolver.module_id().krate.is_stdlib(); + let assert_msg_call_path = if is_in_stdlib { + ExpressionKind::Variable(Path { + segments: vec![Ident::from("resolve_assert_message")], + kind: PathKind::Crate, + span, + }) + } else { + ExpressionKind::Variable(Path { + segments: vec![Ident::from("std"), Ident::from("resolve_assert_message")], + kind: PathKind::Dep, + span, + }) + }; + let assert_msg_call_args = vec![assert_message_expr.clone(), condition]; + let assert_msg_call_expr = Expression::call( + Expression { kind: assert_msg_call_path, span }, + assert_msg_call_args, + span, + ); + Some(self.resolve_expression(assert_msg_call_expr)) + } + pub fn intern_stmt(&mut self, stmt: StatementKind) -> StmtId { let hir_stmt = self.resolve_stmt(stmt); self.interner.push_stmt(hir_stmt) @@ -1352,6 +1422,10 @@ impl<'a> Resolver<'a> { if hir_ident.id != DefinitionId::dummy_id() { match self.interner.definition(hir_ident.id).kind { DefinitionKind::Function(id) => { + if let Some(current_item) = self.current_item { + self.interner.add_function_dependency(current_item, id); + } + if self.interner.function_visibility(id) != FunctionVisibility::Public { @@ -1363,7 +1437,11 @@ impl<'a> Resolver<'a> { ); } } - DefinitionKind::Global(_) => {} + DefinitionKind::Global(global_id) => { + if let Some(current_item) = self.current_item { + self.interner.add_global_dependency(current_item, global_id); + } + } DefinitionKind::GenericType(_) => { // Initialize numeric generics to a polymorphic integer type in case // they're used in expressions. We must do this here since the type @@ -1535,19 +1613,21 @@ impl<'a> Resolver<'a> { let id = self.add_variable_decl(name, mutable.is_some(), true, definition); HirPattern::Identifier(id) } - Pattern::Mutable(pattern, span) => { + Pattern::Mutable(pattern, span, _) => { if let Some(first_mut) = mutable { self.push_err(ResolverError::UnnecessaryMut { first_mut, second_mut: span }); } let pattern = self.resolve_pattern_mutable(*pattern, Some(span), definition); - HirPattern::Mutable(Box::new(pattern), span) + let location = Location::new(span, self.file); + HirPattern::Mutable(Box::new(pattern), location) } Pattern::Tuple(fields, span) => { let fields = vecmap(fields, |field| { self.resolve_pattern_mutable(field, mutable, definition.clone()) }); - HirPattern::Tuple(fields, span) + let location = Location::new(span, self.file); + HirPattern::Tuple(fields, location) } Pattern::Struct(name, fields, span) => { let error_identifier = |this: &mut Self| { @@ -1576,7 +1656,8 @@ impl<'a> Resolver<'a> { let fields = self.resolve_constructor_fields(typ, fields, span, resolve_field); let typ = Type::Struct(struct_type, generics); - HirPattern::Struct(typ, fields, span) + let location = Location::new(span, self.file); + HirPattern::Struct(typ, fields, location) } } } @@ -1656,8 +1737,8 @@ impl<'a> Resolver<'a> { } if let Some(global) = TryFromModuleDefId::try_from(id) { - let let_stmt = self.interner.let_statement(&global); - return Ok(let_stmt.ident().id); + let global = self.interner.get_global(global); + return Ok(global.definition_id); } let expected = "global variable".into(); @@ -1781,7 +1862,7 @@ impl<'a> Resolver<'a> { } for UnresolvedTraitConstraint { typ, trait_bound } in self.trait_bounds.clone() { - if let UnresolvedTypeData::Named(constraint_path, _) = &typ.typ { + if let UnresolvedTypeData::Named(constraint_path, _, _) = &typ.typ { // if `path` is `T::method_name`, we're looking for constraint of the form `T: SomeTrait` if constraint_path.segments.len() == 1 && path.segments[0] != constraint_path.last_segment() @@ -1839,10 +1920,11 @@ impl<'a> Resolver<'a> { self.interner.push_expr(hir_block) } - fn eval_global_as_array_length(&mut self, global: StmtId) -> u64 { - let stmt = match self.interner.statement(&global) { - HirStatement::Let(let_expr) => let_expr, - _ => return 0, + fn eval_global_as_array_length(&mut self, global: GlobalId, path: &Path) -> u64 { + let Some(stmt) = self.interner.get_global_let_statement(global) else { + let path = path.clone(); + self.push_err(ResolverError::NoSuchNumericTypeVariable { path }); + return 0; }; let length = stmt.expression; @@ -1942,7 +2024,7 @@ impl<'a> Resolver<'a> { self.push_err(ResolverError::InvalidTypeForEntryPoint { span }); } } - UnresolvedTypeData::Named(path, generics) => { + 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 diff --git a/noir/compiler/noirc_frontend/src/hir/resolution/structs.rs b/noir/compiler/noirc_frontend/src/hir/resolution/structs.rs index cf3e3436c88..ed7aa86e718 100644 --- a/noir/compiler/noirc_frontend/src/hir/resolution/structs.rs +++ b/noir/compiler/noirc_frontend/src/hir/resolution/structs.rs @@ -32,7 +32,8 @@ pub(crate) fn resolve_structs( // Each struct should already be present in the NodeInterner after def collection. for (type_id, typ) in structs { let file_id = typ.file_id; - let (generics, fields, resolver_errors) = resolve_struct_fields(context, crate_id, typ); + let (generics, fields, resolver_errors) = + resolve_struct_fields(context, crate_id, type_id, typ); errors.extend(vecmap(resolver_errors, |err| (err.into(), file_id))); context.def_interner.update_struct(type_id, |struct_def| { struct_def.set_fields(fields); @@ -67,6 +68,7 @@ pub(crate) fn resolve_structs( fn resolve_struct_fields( context: &mut Context, krate: CrateId, + type_id: StructId, unresolved: UnresolvedStruct, ) -> (Generics, Vec<(Ident, Type)>, Vec) { let path_resolver = @@ -74,7 +76,7 @@ fn resolve_struct_fields( let file_id = unresolved.file_id; let (generics, fields, errors) = Resolver::new(&mut context.def_interner, &path_resolver, &context.def_maps, file_id) - .resolve_struct_fields(unresolved.struct_def); + .resolve_struct_fields(unresolved.struct_def, type_id); (generics, fields, errors) } diff --git a/noir/compiler/noirc_frontend/src/hir/type_check/errors.rs b/noir/compiler/noirc_frontend/src/hir/type_check/errors.rs index 267dbd6b5be..3967d7642f7 100644 --- a/noir/compiler/noirc_frontend/src/hir/type_check/errors.rs +++ b/noir/compiler/noirc_frontend/src/hir/type_check/errors.rs @@ -115,6 +115,12 @@ pub enum TypeCheckError { NoMatchingImplFound { constraints: Vec<(Type, String)>, span: Span }, #[error("Constraint for `{typ}: {trait_name}` is not needed, another matching impl is already in scope")] UnneededTraitConstraint { trait_name: String, typ: Type, span: Span }, + #[error( + "Cannot pass a mutable reference from a constrained runtime to an unconstrained runtime" + )] + ConstrainedReferenceToUnconstrained { span: Span }, + #[error("Slices cannot be returned from an unconstrained runtime to a constrained runtime")] + UnconstrainedSliceReturnToConstrained { span: Span }, } impl TypeCheckError { @@ -202,7 +208,9 @@ impl From for Diagnostic { | TypeCheckError::AmbiguousBitWidth { span, .. } | TypeCheckError::IntegerAndFieldBinaryOperation { span } | TypeCheckError::OverflowingAssignment { span, .. } - | TypeCheckError::FieldModulo { span } => { + | TypeCheckError::FieldModulo { span } + | TypeCheckError::ConstrainedReferenceToUnconstrained { span } + | TypeCheckError::UnconstrainedSliceReturnToConstrained { span } => { Diagnostic::simple_error(error.to_string(), String::new(), span) } TypeCheckError::PublicReturnType { typ, span } => Diagnostic::simple_error( diff --git a/noir/compiler/noirc_frontend/src/hir/type_check/expr.rs b/noir/compiler/noirc_frontend/src/hir/type_check/expr.rs index 5885707a9b7..b3180e0dd20 100644 --- a/noir/compiler/noirc_frontend/src/hir/type_check/expr.rs +++ b/noir/compiler/noirc_frontend/src/hir/type_check/expr.rs @@ -36,6 +36,18 @@ impl<'interner> TypeChecker<'interner> { } } + fn is_unconstrained_call(&self, expr: &ExprId) -> bool { + if let HirExpression::Ident(expr::HirIdent { id, .. }) = self.interner.expression(expr) { + if let Some(DefinitionKind::Function(func_id)) = + self.interner.try_definition(id).map(|def| &def.kind) + { + let modifiers = self.interner.function_modifiers(func_id); + return modifiers.is_unconstrained; + } + } + false + } + /// 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. @@ -139,6 +151,14 @@ impl<'interner> TypeChecker<'interner> { } HirExpression::Index(index_expr) => self.check_index_expression(expr_id, index_expr), HirExpression::Call(call_expr) => { + // Need to setup these flags here as `self` is borrowed mutably to type check the rest of the call expression + // These flags are later used to type check calls to unconstrained functions from constrained functions + let current_func = self.current_function; + let func_mod = current_func.map(|func| self.interner.function_modifiers(&func)); + let is_current_func_constrained = + func_mod.map_or(true, |func_mod| !func_mod.is_unconstrained); + let is_unconstrained_call = self.is_unconstrained_call(&call_expr.func); + self.check_if_deprecated(&call_expr.func); let function = self.check_expression(&call_expr.func); @@ -147,8 +167,34 @@ impl<'interner> TypeChecker<'interner> { let typ = self.check_expression(arg); (typ, *arg, self.interner.expr_span(arg)) }); + + // Check that we are not passing a mutable reference from a constrained runtime to an unconstrained runtime + if is_current_func_constrained && is_unconstrained_call { + for (typ, _, _) in args.iter() { + if matches!(&typ.follow_bindings(), Type::MutableReference(_)) { + self.errors.push(TypeCheckError::ConstrainedReferenceToUnconstrained { + span: self.interner.expr_span(expr_id), + }); + return Type::Error; + } + } + } + let span = self.interner.expr_span(expr_id); - self.bind_function_type(function, args, span) + let return_type = self.bind_function_type(function, args, span); + + // Check that we are not passing a slice from an unconstrained runtime to a constrained runtime + if is_current_func_constrained + && is_unconstrained_call + && return_type.contains_slice() + { + self.errors.push(TypeCheckError::UnconstrainedSliceReturnToConstrained { + span: self.interner.expr_span(expr_id), + }); + return Type::Error; + } + + return_type } HirExpression::MethodCall(mut method_call) => { let mut object_type = self.check_expression(&method_call.object).follow_bindings(); diff --git a/noir/compiler/noirc_frontend/src/hir/type_check/mod.rs b/noir/compiler/noirc_frontend/src/hir/type_check/mod.rs index 3c2a970ee84..8952ba83586 100644 --- a/noir/compiler/noirc_frontend/src/hir/type_check/mod.rs +++ b/noir/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, traits::TraitConstraint}, - node_interner::{ExprId, FuncId, NodeInterner, StmtId}, + node_interner::{ExprId, FuncId, GlobalId, NodeInterner}, Type, }; @@ -193,7 +193,10 @@ impl<'interner> TypeChecker<'interner> { (body_type, std::mem::take(&mut self.delayed_type_checks)) } - pub fn check_global(id: &StmtId, interner: &'interner mut NodeInterner) -> Vec { + pub fn check_global( + id: GlobalId, + interner: &'interner mut NodeInterner, + ) -> Vec { let mut this = Self { delayed_type_checks: Vec::new(), interner, @@ -201,7 +204,8 @@ impl<'interner> TypeChecker<'interner> { trait_constraints: Vec::new(), current_function: None, }; - this.check_statement(id); + let statement = this.interner.get_global(id).let_statement; + this.check_statement(&statement); this.errors } diff --git a/noir/compiler/noirc_frontend/src/hir/type_check/stmt.rs b/noir/compiler/noirc_frontend/src/hir/type_check/stmt.rs index fd8ae62d34e..1bd6c16277b 100644 --- a/noir/compiler/noirc_frontend/src/hir/type_check/stmt.rs +++ b/noir/compiler/noirc_frontend/src/hir/type_check/stmt.rs @@ -8,6 +8,7 @@ use crate::hir_def::stmt::{ }; use crate::hir_def::types::Type; use crate::node_interner::{DefinitionId, ExprId, StmtId}; +use crate::UnaryOp; use super::errors::{Source, TypeCheckError}; use super::TypeChecker; @@ -92,7 +93,7 @@ impl<'interner> TypeChecker<'interner> { match pattern { HirPattern::Identifier(ident) => self.interner.push_definition_type(ident.id, typ), HirPattern::Mutable(pattern, _) => self.bind_pattern(pattern, typ), - HirPattern::Tuple(fields, span) => match typ { + HirPattern::Tuple(fields, location) => match typ { Type::Tuple(field_types) if field_types.len() == fields.len() => { for (field, field_type) in fields.iter().zip(field_types) { self.bind_pattern(field, field_type); @@ -106,16 +107,16 @@ impl<'interner> TypeChecker<'interner> { self.errors.push(TypeCheckError::TypeMismatchWithSource { expected, actual: other, - span: *span, + span: location.span, source: Source::Assignment, }); } }, - HirPattern::Struct(struct_type, fields, span) => { + HirPattern::Struct(struct_type, fields, location) => { self.unify(struct_type, &typ, || TypeCheckError::TypeMismatchWithSource { expected: struct_type.clone(), actual: typ.clone(), - span: *span, + span: location.span, source: Source::Assignment, }); @@ -303,6 +304,9 @@ impl<'interner> TypeChecker<'interner> { let expr_type = self.check_expression(&stmt.0); let expr_span = self.interner.expr_span(&stmt.0); + // Must type check the assertion message expression so that we instantiate bindings + stmt.2.map(|assert_msg_expr| self.check_expression(&assert_msg_expr)); + self.unify(&expr_type, &Type::Bool, || TypeCheckError::TypeMismatch { expr_typ: expr_type.to_string(), expected_typ: Type::Bool.to_string(), @@ -358,9 +362,15 @@ impl<'interner> TypeChecker<'interner> { }; }; } - HirExpression::Prefix(_) => self - .errors - .push(TypeCheckError::InvalidUnaryOp { kind: annotated_type.to_string(), span }), + HirExpression::Prefix(expr) => { + self.lint_overflowing_uint(&expr.rhs, annotated_type); + if matches!(expr.operator, UnaryOp::Minus) { + self.errors.push(TypeCheckError::InvalidUnaryOp { + kind: "annotated_type".to_string(), + span, + }); + } + } HirExpression::Infix(expr) => { self.lint_overflowing_uint(&expr.lhs, annotated_type); self.lint_overflowing_uint(&expr.rhs, annotated_type); diff --git a/noir/compiler/noirc_frontend/src/hir_def/function.rs b/noir/compiler/noirc_frontend/src/hir_def/function.rs index 78f44696b72..d3ab2a9393b 100644 --- a/noir/compiler/noirc_frontend/src/hir_def/function.rs +++ b/noir/compiler/noirc_frontend/src/hir_def/function.rs @@ -43,12 +43,7 @@ pub struct Parameters(pub Vec); impl Parameters { pub fn span(&self) -> Span { assert!(!self.is_empty()); - let mut spans = vecmap(&self.0, |param| match ¶m.0 { - HirPattern::Identifier(ident) => ident.location.span, - HirPattern::Mutable(_, span) => *span, - HirPattern::Tuple(_, span) => *span, - HirPattern::Struct(_, _, span) => *span, - }); + let mut spans = vecmap(&self.0, |param| param.0.span()); let merged_span = spans.pop().unwrap(); for span in spans { diff --git a/noir/compiler/noirc_frontend/src/hir_def/stmt.rs b/noir/compiler/noirc_frontend/src/hir_def/stmt.rs index 34c9302c251..b910be1fdda 100644 --- a/noir/compiler/noirc_frontend/src/hir_def/stmt.rs +++ b/noir/compiler/noirc_frontend/src/hir_def/stmt.rs @@ -2,7 +2,7 @@ use super::expr::HirIdent; use crate::node_interner::ExprId; use crate::{Ident, Type}; use fm::FileId; -use noirc_errors::Span; +use noirc_errors::{Location, Span}; /// A HirStatement is the result of performing name resolution on /// the Statement AST node. Unlike the AST node, any nested nodes @@ -55,14 +55,14 @@ pub struct HirAssignStatement { /// originates from. This is used later in the SSA pass to issue /// an error if a constrain is found to be always false. #[derive(Debug, Clone)] -pub struct HirConstrainStatement(pub ExprId, pub FileId, pub Option); +pub struct HirConstrainStatement(pub ExprId, pub FileId, pub Option); #[derive(Debug, Clone, Hash)] pub enum HirPattern { Identifier(HirIdent), - Mutable(Box, Span), - Tuple(Vec, Span), - Struct(Type, Vec<(Ident, HirPattern)>, Span), + Mutable(Box, Location), + Tuple(Vec, Location), + Struct(Type, Vec<(Ident, HirPattern)>, Location), } impl HirPattern { @@ -92,9 +92,9 @@ impl HirPattern { pub fn span(&self) -> Span { match self { HirPattern::Identifier(ident) => ident.location.span, - HirPattern::Mutable(_, span) - | HirPattern::Tuple(_, span) - | HirPattern::Struct(_, _, span) => *span, + HirPattern::Mutable(_, location) + | HirPattern::Tuple(_, location) + | HirPattern::Struct(_, _, location) => location.span, } } } diff --git a/noir/compiler/noirc_frontend/src/hir_def/types.rs b/noir/compiler/noirc_frontend/src/hir_def/types.rs index 0ba4cb2da65..00e24de279b 100644 --- a/noir/compiler/noirc_frontend/src/hir_def/types.rs +++ b/noir/compiler/noirc_frontend/src/hir_def/types.rs @@ -157,7 +157,7 @@ impl Type { } } - fn contains_slice(&self) -> bool { + pub(crate) fn contains_slice(&self) -> bool { match self { Type::Array(size, _) => matches!(size.as_ref(), Type::NotConstant), Type::Struct(struct_typ, generics) => { diff --git a/noir/compiler/noirc_frontend/src/lib.rs b/noir/compiler/noirc_frontend/src/lib.rs index b6d4c568334..eb00a61adf6 100644 --- a/noir/compiler/noirc_frontend/src/lib.rs +++ b/noir/compiler/noirc_frontend/src/lib.rs @@ -11,6 +11,7 @@ #![warn(clippy::semicolon_if_nothing_returned)] pub mod ast; +pub mod debug; pub mod graph; pub mod lexer; pub mod monomorphization; @@ -48,7 +49,7 @@ pub mod macros_api { pub use crate::hir_def::expr::{HirExpression, HirLiteral}; pub use crate::hir_def::stmt::HirStatement; pub use crate::node_interner::{NodeInterner, StructId}; - pub use crate::parser::SortedModule; + pub use crate::parser::{parse_program, SortedModule}; pub use crate::token::SecondaryAttribute; pub use crate::hir::def_map::ModuleDefId; diff --git a/noir/compiler/noirc_frontend/src/monomorphization/ast.rs b/noir/compiler/noirc_frontend/src/monomorphization/ast.rs index 515d9710882..73e7ef372ab 100644 --- a/noir/compiler/noirc_frontend/src/monomorphization/ast.rs +++ b/noir/compiler/noirc_frontend/src/monomorphization/ast.rs @@ -1,6 +1,9 @@ use acvm::FieldElement; use iter_extended::vecmap; -use noirc_errors::Location; +use noirc_errors::{ + debug_info::{DebugTypes, DebugVariables}, + Location, +}; use crate::{ hir_def::function::FunctionSignature, BinaryOpKind, Distinctness, Signedness, Visibility, @@ -31,7 +34,7 @@ pub enum Expression { ExtractTupleField(Box, usize), Call(Call), Let(Let), - Constrain(Box, Location, Option), + Constrain(Box, Location, Option>), Assign(Assign), Semi(Box), } @@ -248,9 +251,12 @@ pub struct Program { pub return_visibility: Visibility, /// Indicates to a backend whether a SNARK-friendly prover should be used. pub recursive: bool, + pub debug_variables: DebugVariables, + pub debug_types: DebugTypes, } impl Program { + #[allow(clippy::too_many_arguments)] pub fn new( functions: Vec, main_function_signature: FunctionSignature, @@ -258,6 +264,8 @@ impl Program { return_location: Option, return_visibility: Visibility, recursive: bool, + debug_variables: DebugVariables, + debug_types: DebugTypes, ) -> Program { Program { functions, @@ -266,6 +274,8 @@ impl Program { return_location, return_visibility, recursive, + debug_variables, + debug_types, } } diff --git a/noir/compiler/noirc_frontend/src/monomorphization/debug.rs b/noir/compiler/noirc_frontend/src/monomorphization/debug.rs new file mode 100644 index 00000000000..d36816e3d37 --- /dev/null +++ b/noir/compiler/noirc_frontend/src/monomorphization/debug.rs @@ -0,0 +1,190 @@ +use iter_extended::vecmap; +use noirc_errors::debug_info::DebugVarId; +use noirc_errors::Location; +use noirc_printable_type::PrintableType; + +use crate::debug::{SourceFieldId, SourceVarId}; +use crate::hir_def::expr::*; +use crate::node_interner::ExprId; + +use super::ast::{Expression, Ident}; +use super::Monomorphizer; + +const DEBUG_MEMBER_ASSIGN_PREFIX: &str = "__debug_member_assign_"; +const DEBUG_VAR_ID_ARG_SLOT: usize = 0; +const DEBUG_VALUE_ARG_SLOT: usize = 1; +const DEBUG_MEMBER_FIELD_INDEX_ARG_SLOT: usize = 2; + +impl From for SourceVarId { + fn from(var_id: u128) -> Self { + Self(var_id as u32) + } +} + +impl From for SourceFieldId { + fn from(field_id: u128) -> Self { + Self(field_id as u32) + } +} + +impl<'interner> Monomorphizer<'interner> { + /// Patch instrumentation calls inserted for debugging. This will record + /// tracked variables and their types, and assign them an ID to use at + /// runtime. This ID is different from the source ID assigned at + /// instrumentation time because at that point we haven't fully resolved the + /// types for generic functions. So a single generic function may be + /// instantiated multiple times with its tracked variables being of + /// different types for each instance at runtime. + pub(super) fn patch_debug_instrumentation_call( + &mut self, + call: &HirCallExpression, + arguments: &mut [Expression], + ) { + let original_func = Box::new(self.expr(call.func)); + if let Expression::Ident(Ident { name, .. }) = original_func.as_ref() { + if name == "__debug_var_assign" { + self.patch_debug_var_assign(call, arguments); + } else if name == "__debug_var_drop" { + self.patch_debug_var_drop(call, arguments); + } else if let Some(arity) = name.strip_prefix(DEBUG_MEMBER_ASSIGN_PREFIX) { + let arity = arity.parse::().expect("failed to parse member assign arity"); + self.patch_debug_member_assign(call, arguments, arity); + } + } + } + + /// Update instrumentation code inserted on variable assignment. We need to + /// register the variable instance, its type and replace the source_var_id + /// with the ID of the registration. Multiple registrations of the same + /// variable are possible if using generic functions, hence the temporary ID + /// created when injecting the instrumentation code can map to multiple IDs + /// at runtime. + fn patch_debug_var_assign(&mut self, call: &HirCallExpression, arguments: &mut [Expression]) { + let hir_arguments = vecmap(&call.arguments, |id| self.interner.expression(id)); + let var_id_arg = hir_arguments.get(DEBUG_VAR_ID_ARG_SLOT); + let Some(HirExpression::Literal(HirLiteral::Integer(source_var_id, _))) = var_id_arg else { + unreachable!("Missing source_var_id in __debug_var_assign call"); + }; + + // instantiate tracked variable for the value type and associate it with + // the ID used by the injected instrumentation code + let var_type = self.interner.id_type(call.arguments[DEBUG_VALUE_ARG_SLOT]); + let source_var_id = source_var_id.to_u128().into(); + // then update the ID used for tracking at runtime + let var_id = self.debug_type_tracker.insert_var(source_var_id, var_type); + let interned_var_id = self.intern_var_id(var_id, &call.location); + arguments[DEBUG_VAR_ID_ARG_SLOT] = self.expr(interned_var_id); + } + + /// Update instrumentation code for a variable being dropped out of scope. + /// Given the source_var_id we search for the last assigned debug var_id and + /// replace it instead. + fn patch_debug_var_drop(&mut self, call: &HirCallExpression, arguments: &mut [Expression]) { + let hir_arguments = vecmap(&call.arguments, |id| self.interner.expression(id)); + let var_id_arg = hir_arguments.get(DEBUG_VAR_ID_ARG_SLOT); + let Some(HirExpression::Literal(HirLiteral::Integer(source_var_id, _))) = var_id_arg else { + unreachable!("Missing source_var_id in __debug_var_drop call"); + }; + // update variable ID for tracked drops (ie. when the var goes out of scope) + let source_var_id = source_var_id.to_u128().into(); + let var_id = self + .debug_type_tracker + .get_var_id(source_var_id) + .unwrap_or_else(|| unreachable!("failed to find debug variable")); + let interned_var_id = self.intern_var_id(var_id, &call.location); + arguments[DEBUG_VAR_ID_ARG_SLOT] = self.expr(interned_var_id); + } + + /// Update instrumentation code inserted when assigning to a member of an + /// existing variable. Same as above for replacing the source_var_id, but also + /// we need to resolve the path and the type of the member being assigned. + /// For this last part, we need to resolve the mapping from field names in + /// structs to positions in the runtime tuple, since all structs are + /// replaced by tuples during compilation. + fn patch_debug_member_assign( + &mut self, + call: &HirCallExpression, + arguments: &mut [Expression], + arity: usize, + ) { + let hir_arguments = vecmap(&call.arguments, |id| self.interner.expression(id)); + let var_id_arg = hir_arguments.get(DEBUG_VAR_ID_ARG_SLOT); + let Some(HirExpression::Literal(HirLiteral::Integer(source_var_id, _))) = var_id_arg else { + unreachable!("Missing source_var_id in __debug_member_assign call"); + }; + // update variable member assignments + let source_var_id = source_var_id.to_u128().into(); + + let var_type = self + .debug_type_tracker + .get_type(source_var_id) + .unwrap_or_else(|| panic!("type not found for {source_var_id:?}")) + .clone(); + let mut cursor_type = &var_type; + for i in 0..arity { + if let Some(HirExpression::Literal(HirLiteral::Integer(fe_i, i_neg))) = + hir_arguments.get(DEBUG_MEMBER_FIELD_INDEX_ARG_SLOT + i) + { + let index = fe_i.to_i128().unsigned_abs(); + if *i_neg { + // We use negative indices at instrumentation time to indicate + // and reference member accesses by name which cannot be + // resolved until we have a type. This strategy is also used + // for tuple member access because syntactically they are + // the same as named field accesses. + let field_index = self + .debug_type_tracker + .resolve_field_index(index.into(), cursor_type) + .unwrap_or_else(|| { + unreachable!("failed to resolve {i}-th member indirection on type {cursor_type:?}") + }); + + cursor_type = element_type_at_index(cursor_type, field_index); + let index_id = self.interner.push_expr(HirExpression::Literal( + HirLiteral::Integer(field_index.into(), false), + )); + self.interner.push_expr_type(&index_id, crate::Type::FieldElement); + self.interner.push_expr_location( + index_id, + call.location.span, + call.location.file, + ); + arguments[DEBUG_MEMBER_FIELD_INDEX_ARG_SLOT + i] = self.expr(index_id); + } else { + // array/string element using constant index + cursor_type = element_type_at_index(cursor_type, index as usize); + } + } else { + // array element using non-constant index + cursor_type = element_type_at_index(cursor_type, 0); + } + } + + let var_id = self + .debug_type_tracker + .get_var_id(source_var_id) + .unwrap_or_else(|| unreachable!("failed to find debug variable")); + let interned_var_id = self.intern_var_id(var_id, &call.location); + arguments[DEBUG_VAR_ID_ARG_SLOT] = self.expr(interned_var_id); + } + + fn intern_var_id(&mut self, var_id: DebugVarId, location: &Location) -> ExprId { + let var_id_literal = HirLiteral::Integer((var_id.0 as u128).into(), false); + let expr_id = self.interner.push_expr(HirExpression::Literal(var_id_literal)); + self.interner.push_expr_type(&expr_id, crate::Type::FieldElement); + self.interner.push_expr_location(expr_id, location.span, location.file); + expr_id + } +} + +fn element_type_at_index(ptype: &PrintableType, i: usize) -> &PrintableType { + match ptype { + PrintableType::Array { length: _length, typ } => typ.as_ref(), + PrintableType::Tuple { types } => &types[i], + PrintableType::Struct { name: _name, fields } => &fields[i].1, + PrintableType::String { length: _length } => &PrintableType::UnsignedInteger { width: 8 }, + _ => { + panic!["expected type with sub-fields, found terminal type"] + } + } +} diff --git a/noir/compiler/noirc_frontend/src/monomorphization/debug_types.rs b/noir/compiler/noirc_frontend/src/monomorphization/debug_types.rs new file mode 100644 index 00000000000..fea073d394f --- /dev/null +++ b/noir/compiler/noirc_frontend/src/monomorphization/debug_types.rs @@ -0,0 +1,137 @@ +use crate::{ + debug::{DebugInstrumenter, SourceFieldId, SourceVarId}, + hir_def::types::Type, +}; +use noirc_errors::debug_info::{ + DebugTypeId, DebugTypes, DebugVarId, DebugVariable, DebugVariables, +}; +use noirc_printable_type::PrintableType; +use std::collections::HashMap; + +/// We keep a collection of the debug variables and their types in this +/// structure. The source_var_id refers to the ID given by the debug +/// instrumenter. This variable does not have a type yet and hence it +/// can be instantiated for multiple types if it's in the context of a generic +/// variable. The var_id refers to the ID of the instantiated variable which +/// will have a valid type. +#[derive(Debug, Clone, Default)] +pub struct DebugTypeTracker { + // Variable names collected during instrumentation injection + source_variables: HashMap, + + // Field names used for member access collected during instrumentation injection + source_field_names: HashMap, + + // Current instances of tracked variables from the ID given during + // instrumentation. The tracked var_id will change for each source_var_id + // when compiling generic functions. + source_to_debug_vars: HashMap, + + // All instances of tracked variables + variables: HashMap, + + // Types of tracked variables + types: HashMap, + types_reverse: HashMap, + + next_var_id: u32, + next_type_id: u32, +} + +impl DebugTypeTracker { + pub fn build_from_debug_instrumenter(instrumenter: &DebugInstrumenter) -> Self { + DebugTypeTracker { + source_variables: instrumenter.variables.clone(), + source_field_names: instrumenter.field_names.clone(), + ..DebugTypeTracker::default() + } + } + + pub fn extract_vars_and_types(&self) -> (DebugVariables, DebugTypes) { + let debug_variables = self + .variables + .clone() + .into_iter() + .map(|(var_id, (source_var_id, type_id))| { + ( + var_id, + DebugVariable { + name: self.source_variables.get(&source_var_id).cloned().unwrap_or_else( + || { + unreachable!( + "failed to retrieve variable name for {source_var_id:?}" + ); + }, + ), + debug_type_id: type_id, + }, + ) + }) + .collect(); + let debug_types = self.types.clone().into_iter().collect(); + + (debug_variables, debug_types) + } + + pub fn resolve_field_index( + &self, + field_id: SourceFieldId, + cursor_type: &PrintableType, + ) -> Option { + self.source_field_names + .get(&field_id) + .and_then(|field_name| get_field(cursor_type, field_name)) + } + + pub fn insert_var(&mut self, source_var_id: SourceVarId, var_type: Type) -> DebugVarId { + if !self.source_variables.contains_key(&source_var_id) { + unreachable!("cannot find source debug variable {source_var_id:?}"); + } + + let ptype: PrintableType = var_type.follow_bindings().into(); + let type_id = self.types_reverse.get(&ptype).copied().unwrap_or_else(|| { + let type_id = DebugTypeId(self.next_type_id); + self.next_type_id += 1; + self.types_reverse.insert(ptype.clone(), type_id); + self.types.insert(type_id, ptype); + type_id + }); + // check if we need to instantiate the var with a new type + let existing_var_id = self.source_to_debug_vars.get(&source_var_id).and_then(|var_id| { + let (_, existing_type_id) = self.variables.get(var_id).unwrap(); + (*existing_type_id == type_id).then_some(var_id) + }); + if let Some(var_id) = existing_var_id { + *var_id + } else { + let var_id = DebugVarId(self.next_var_id); + self.next_var_id += 1; + self.variables.insert(var_id, (source_var_id, type_id)); + self.source_to_debug_vars.insert(source_var_id, var_id); + var_id + } + } + + pub fn get_var_id(&self, source_var_id: SourceVarId) -> Option { + self.source_to_debug_vars.get(&source_var_id).copied() + } + + pub fn get_type(&self, source_var_id: SourceVarId) -> Option<&PrintableType> { + self.source_to_debug_vars + .get(&source_var_id) + .and_then(|var_id| self.variables.get(var_id)) + .and_then(|(_, type_id)| self.types.get(type_id)) + } +} + +fn get_field(ptype: &PrintableType, field_name: &str) -> Option { + match ptype { + PrintableType::Struct { fields, .. } => { + fields.iter().position(|(name, _)| name == field_name) + } + PrintableType::Tuple { .. } | PrintableType::Array { .. } => { + field_name.parse::().ok() + } + _ => None, + } +} diff --git a/noir/compiler/noirc_frontend/src/monomorphization/mod.rs b/noir/compiler/noirc_frontend/src/monomorphization/mod.rs index 0334e01af5d..21c095eb877 100644 --- a/noir/compiler/noirc_frontend/src/monomorphization/mod.rs +++ b/noir/compiler/noirc_frontend/src/monomorphization/mod.rs @@ -18,9 +18,10 @@ use std::{ }; use crate::{ + debug::DebugInstrumenter, hir_def::{ expr::*, - function::{FunctionSignature, Parameters}, + function::{FuncMeta, FunctionSignature, Parameters}, stmt::{HirAssignStatement, HirLValue, HirLetStatement, HirPattern, HirStatement}, types, }, @@ -31,8 +32,11 @@ use crate::{ }; use self::ast::{Definition, FuncId, Function, LocalId, Program}; +use self::debug_types::DebugTypeTracker; pub mod ast; +mod debug; +pub mod debug_types; pub mod printer; struct LambdaContext { @@ -67,7 +71,7 @@ struct Monomorphizer<'interner> { finished_functions: BTreeMap, /// Used to reference existing definitions in the HIR - interner: &'interner NodeInterner, + interner: &'interner mut NodeInterner, lambda_envs_stack: Vec, @@ -77,6 +81,8 @@ struct Monomorphizer<'interner> { is_range_loop: bool, return_location: Option, + + debug_type_tracker: DebugTypeTracker, } type HirType = crate::Type; @@ -93,8 +99,17 @@ type HirType = crate::Type; /// this function. Typically, this is the function named "main" in the source project, /// but it can also be, for example, an arbitrary test function for running `nargo test`. #[tracing::instrument(level = "trace", skip(main, interner))] -pub fn monomorphize(main: node_interner::FuncId, interner: &NodeInterner) -> Program { - let mut monomorphizer = Monomorphizer::new(interner); +pub fn monomorphize(main: node_interner::FuncId, interner: &mut NodeInterner) -> Program { + monomorphize_debug(main, interner, &DebugInstrumenter::default()) +} + +pub fn monomorphize_debug( + main: node_interner::FuncId, + interner: &mut NodeInterner, + debug_instrumenter: &DebugInstrumenter, +) -> Program { + let debug_type_tracker = DebugTypeTracker::build_from_debug_instrumenter(debug_instrumenter); + let mut monomorphizer = Monomorphizer::new(interner, debug_type_tracker); let function_sig = monomorphizer.compile_main(main); while !monomorphizer.queue.is_empty() { @@ -109,20 +124,24 @@ pub fn monomorphize(main: node_interner::FuncId, interner: &NodeInterner) -> Pro } let functions = vecmap(monomorphizer.finished_functions, |(_, f)| f); - let meta = interner.function_meta(&main); + let FuncMeta { return_distinctness, return_visibility, kind, .. } = + monomorphizer.interner.function_meta(&main); + let (debug_variables, debug_types) = monomorphizer.debug_type_tracker.extract_vars_and_types(); Program::new( functions, function_sig, - meta.return_distinctness, + *return_distinctness, monomorphizer.return_location, - meta.return_visibility, - meta.kind == FunctionKind::Recursive, + *return_visibility, + *kind == FunctionKind::Recursive, + debug_variables, + debug_types, ) } impl<'interner> Monomorphizer<'interner> { - fn new(interner: &'interner NodeInterner) -> Self { + fn new(interner: &'interner mut NodeInterner, debug_type_tracker: DebugTypeTracker) -> Self { Monomorphizer { globals: HashMap::new(), locals: HashMap::new(), @@ -134,6 +153,7 @@ impl<'interner> Monomorphizer<'interner> { lambda_envs_stack: Vec::new(), is_range_loop: false, return_location: None, + debug_type_tracker, } } @@ -234,7 +254,7 @@ impl<'interner> Monomorphizer<'interner> { the_trait.self_type_typevar.force_bind(self_type); } - let meta = self.interner.function_meta(&f); + let meta = self.interner.function_meta(&f).clone(); let modifiers = self.interner.function_modifiers(&f); let name = self.interner.function_name(&f).to_owned(); @@ -244,14 +264,13 @@ impl<'interner> Monomorphizer<'interner> { Type::TraitAsType(..) => &body_return_type, _ => meta.return_type(), }); - - let parameters = self.parameters(&meta.parameters); - - let body = self.expr(body_expr_id); let unconstrained = modifiers.is_unconstrained || matches!(modifiers.contract_function_type, Some(ContractFunctionType::Open)); + let parameters = self.parameters(&meta.parameters); + let body = self.expr(body_expr_id); let function = ast::Function { id, name, parameters, body, return_type, unconstrained }; + self.push_function(id, function); } @@ -370,7 +389,6 @@ impl<'interner> Monomorphizer<'interner> { let rhs = self.expr(infix.rhs); let operator = infix.operator.kind; let location = self.interner.expr_location(&expr); - if self.interner.get_selected_impl_for_expression(expr).is_some() { // If an impl was selected for this infix operator, replace it // with a method call to the appropriate trait impl method. @@ -483,7 +501,9 @@ impl<'interner> Monomorphizer<'interner> { HirStatement::Constrain(constrain) => { let expr = self.expr(constrain.0); let location = self.interner.expr_location(&constrain.0); - ast::Expression::Constrain(Box::new(expr), location, constrain.2) + let assert_message = + constrain.2.map(|assert_msg_expr| Box::new(self.expr(assert_msg_expr))); + ast::Expression::Constrain(Box::new(expr), location, assert_message) } HirStatement::Assign(assign) => self.assign(assign), HirStatement::For(for_loop) => { @@ -710,7 +730,12 @@ impl<'interner> Monomorphizer<'interner> { ident_expression } } - DefinitionKind::Global(expr_id) => self.expr(*expr_id), + DefinitionKind::Global(global_id) => { + let Some(let_) = self.interner.get_global_let_statement(*global_id) else { + unreachable!("Globals should have a corresponding let statement by monomorphization") + }; + self.expr(let_.expression) + } DefinitionKind::Local(_) => self.lookup_captured_expr(ident.id).unwrap_or_else(|| { let ident = self.local_ident(&ident).unwrap(); ast::Expression::Ident(ident) @@ -921,6 +946,9 @@ impl<'interner> Monomorphizer<'interner> { let original_func = Box::new(self.expr(call.func)); let mut arguments = vecmap(&call.arguments, |id| self.expr(*id)); let hir_arguments = vecmap(&call.arguments, |id| self.interner.expression(id)); + + self.patch_debug_instrumentation_call(&call, &mut arguments); + let return_type = self.interner.id_type(id); let return_type = self.convert_type(&return_type); @@ -933,6 +961,9 @@ impl<'interner> Monomorphizer<'interner> { // The first argument to the `print` oracle is a bool, indicating a newline to be inserted at the end of the input // The second argument is expected to always be an ident self.append_printable_type_info(&hir_arguments[1], &mut arguments); + } else if name.as_str() == "assert_message" { + // The first argument to the `assert_message` oracle is the expression passed as a mesage to an `assert` or `assert_eq` statement + self.append_printable_type_info(&hir_arguments[0], &mut arguments); } } } @@ -1028,7 +1059,7 @@ impl<'interner> Monomorphizer<'interner> { // The caller needs information as to whether it is handling a format string or a single type arguments.push(ast::Expression::Literal(ast::Literal::Bool(is_fmt_str))); } - _ => unreachable!("logging expr {:?} is not supported", arguments[0]), + _ => unreachable!("logging expr {:?} is not supported", hir_argument), } } @@ -1037,10 +1068,10 @@ impl<'interner> Monomorphizer<'interner> { // since they cannot be passed from ACIR into Brillig if let HirType::Array(size, _) = typ { if let HirType::NotConstant = **size { - unreachable!("println does not support slices. Convert the slice to an array before passing it to println"); + unreachable!("println and format strings do not support slices. Convert the slice to an array before passing it to println"); } } else if matches!(typ, HirType::MutableReference(_)) { - unreachable!("println does not support mutable references."); + unreachable!("println and format strings do not support mutable references."); } let printable_type: PrintableType = typ.into(); diff --git a/noir/compiler/noirc_frontend/src/node_interner.rs b/noir/compiler/noirc_frontend/src/node_interner.rs index 11ef12ef83e..0051c1b4f5f 100644 --- a/noir/compiler/noirc_frontend/src/node_interner.rs +++ b/noir/compiler/noirc_frontend/src/node_interner.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::collections::HashMap; use std::ops::Deref; @@ -5,12 +6,17 @@ use arena::{Arena, Index}; use fm::FileId; use iter_extended::vecmap; use noirc_errors::{Location, Span, Spanned}; +use petgraph::algo::tarjan_scc; +use petgraph::prelude::DiGraph; +use petgraph::prelude::NodeIndex as PetGraphIndex; use crate::ast::Ident; use crate::graph::CrateId; +use crate::hir::def_collector::dc_crate::CompilationError; use crate::hir::def_collector::dc_crate::{UnresolvedStruct, UnresolvedTrait, UnresolvedTypeAlias}; use crate::hir::def_map::{LocalModuleId, ModuleId}; +use crate::hir::resolution::errors::ResolverError; use crate::hir_def::stmt::HirLetStatement; use crate::hir_def::traits::TraitImpl; use crate::hir_def::traits::{Trait, TraitConstraint}; @@ -42,6 +48,7 @@ type StructAttributes = Vec; pub struct NodeInterner { pub(crate) nodes: Arena, pub(crate) func_meta: HashMap, + function_definition_ids: HashMap, // For a given function ID, this gives the function's modifiers which includes @@ -52,6 +59,14 @@ pub struct NodeInterner { // Contains the source module each function was defined in function_modules: HashMap, + /// This graph tracks dependencies between different global definitions. + /// This is used to ensure the absense of dependency cycles for globals and types. + dependency_graph: DiGraph, + + /// To keep track of where each DependencyId is in `dependency_graph`, we need + /// this separate graph to map between the ids and indices. + dependency_graph_indices: HashMap, + // Map each `Index` to it's own location pub(crate) id_to_location: HashMap, @@ -126,7 +141,9 @@ pub struct NodeInterner { /// checking. field_indices: HashMap, - globals: HashMap, // NOTE: currently only used for checking repeat globals and restricting their scope to a module + // Maps GlobalId -> GlobalInfo + // NOTE: currently only used for checking repeat globals and restricting their scope to a module + globals: Vec, next_type_variable_id: std::cell::Cell, @@ -152,6 +169,24 @@ pub struct NodeInterner { pub(crate) type_ref_locations: Vec<(Type, Location)>, } +/// A dependency in the dependency graph may be a type or a definition. +/// Types can depend on definitions too. E.g. `Foo` depends on `COUNT` in: +/// +/// ```struct +/// global COUNT = 3; +/// +/// struct Foo { +/// array: [Field; COUNT], +/// } +/// ``` +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum DependencyId { + Struct(StructId), + Global(GlobalId), + Function(FuncId), + Alias(TypeAliasId), +} + /// A trait implementation is either a normal implementation that is present in the source /// program via an `impl` block, or it is assumed to exist from a `where` clause or similar. #[derive(Debug, Clone)] @@ -247,6 +282,17 @@ impl From for Index { } } +/// An ID for a global value +#[derive(Debug, Eq, PartialEq, Hash, Clone, Copy)] +pub struct GlobalId(usize); + +impl GlobalId { + // Dummy id for error reporting + pub fn dummy_id() -> Self { + GlobalId(std::usize::MAX) + } +} + #[derive(Debug, Eq, PartialEq, Hash, Clone, Copy)] pub struct StmtId(Index); @@ -397,7 +443,7 @@ impl DefinitionInfo { pub enum DefinitionKind { Function(FuncId), - Global(ExprId), + Global(GlobalId), /// Locals may be defined in let statements or parameters, /// in which case they will not have an associated ExprId @@ -418,7 +464,7 @@ impl DefinitionKind { pub fn get_rhs(&self) -> Option { match self { DefinitionKind::Function(_) => None, - DefinitionKind::Global(id) => Some(*id), + DefinitionKind::Global(_) => None, DefinitionKind::Local(id) => *id, DefinitionKind::GenericType(_) => None, } @@ -427,8 +473,12 @@ impl DefinitionKind { #[derive(Debug, Clone)] pub struct GlobalInfo { + pub id: GlobalId, + pub definition_id: DefinitionId, pub ident: Ident, pub local_id: LocalModuleId, + pub location: Location, + pub let_statement: StmtId, } impl Default for NodeInterner { @@ -440,6 +490,8 @@ impl Default for NodeInterner { function_modifiers: HashMap::new(), function_modules: HashMap::new(), func_id_to_trait: HashMap::new(), + dependency_graph: petgraph::graph::DiGraph::new(), + dependency_graph_indices: HashMap::new(), id_to_location: HashMap::new(), definitions: vec![], id_to_type: HashMap::new(), @@ -455,7 +507,7 @@ impl Default for NodeInterner { instantiation_bindings: HashMap::new(), field_indices: HashMap::new(), next_type_variable_id: std::cell::Cell::new(0), - globals: HashMap::new(), + globals: Vec::new(), struct_methods: HashMap::new(), primitive_methods: HashMap::new(), type_alias_ref: Vec::new(), @@ -617,26 +669,41 @@ impl NodeInterner { self.type_ref_locations.push((typ, location)); } - pub fn push_global(&mut self, stmt_id: StmtId, ident: Ident, local_id: LocalModuleId) { - self.globals.insert(stmt_id, GlobalInfo { ident, local_id }); + fn push_global( + &mut self, + ident: Ident, + local_id: LocalModuleId, + let_statement: StmtId, + file: FileId, + ) -> GlobalId { + let id = GlobalId(self.globals.len()); + let location = Location::new(ident.span(), file); + let name = ident.to_string(); + let definition_id = self.push_definition(name, false, DefinitionKind::Global(id), location); + self.globals.push(GlobalInfo { + id, + definition_id, + ident, + local_id, + let_statement, + location, + }); + id } - /// Intern an empty global stmt. Used for collecting globals - pub fn push_empty_global(&mut self) -> StmtId { - self.push_stmt(HirStatement::Error) + pub fn next_global_id(&mut self) -> GlobalId { + GlobalId(self.globals.len()) } - pub fn update_global(&mut self, stmt_id: StmtId, hir_stmt: HirStatement) { - let def = - self.nodes.get_mut(stmt_id.0).expect("ice: all function ids should have definitions"); - - let stmt = match def { - Node::Statement(stmt) => stmt, - _ => { - panic!("ice: all global ids should correspond to a statement in the interner") - } - }; - *stmt = hir_stmt; + /// Intern an empty global. Used for collecting globals before they're defined + pub fn push_empty_global( + &mut self, + name: Ident, + local_id: LocalModuleId, + file: FileId, + ) -> GlobalId { + let statement = self.push_stmt(HirStatement::Error); + self.push_global(name, local_id, statement, file) } /// Intern an empty function. @@ -816,19 +883,19 @@ impl NodeInterner { } } - /// Returns the interned let statement corresponding to `stmt_id` - pub fn let_statement(&self, stmt_id: &StmtId) -> HirLetStatement { - let def = - self.nodes.get(stmt_id.0).expect("ice: all statement ids should have definitions"); + /// Try to get the `HirLetStatement` which defines a given global value + pub fn get_global_let_statement(&self, global: GlobalId) -> Option { + let global = self.get_global(global); + let def = self.nodes.get(global.let_statement.0)?; match def { - Node::Statement(hir_stmt) => { - match hir_stmt { - HirStatement::Let(let_stmt) => let_stmt.clone(), - _ => panic!("ice: all let statement ids should correspond to a let statement in the interner"), + Node::Statement(hir_stmt) => match hir_stmt { + HirStatement::Let(let_stmt) => Some(let_stmt.clone()), + _ => { + panic!("ice: all globals should correspond to a let statement in the interner") } }, - _ => panic!("ice: all statement ids should correspond to a statement in the interner"), + _ => panic!("ice: all globals should correspond to a statement in the interner"), } } @@ -894,12 +961,17 @@ impl NodeInterner { &self.type_aliases[id.0] } - pub fn get_global(&self, stmt_id: &StmtId) -> Option { - self.globals.get(stmt_id).cloned() + pub fn get_global(&self, global_id: GlobalId) -> &GlobalInfo { + &self.globals[global_id.0] + } + + pub fn get_global_definition(&self, global_id: GlobalId) -> &DefinitionInfo { + let global = self.get_global(global_id); + self.definition(global.definition_id) } - pub fn get_all_globals(&self) -> HashMap { - self.globals.clone() + pub fn get_all_globals(&self) -> &[GlobalInfo] { + &self.globals } /// Returns the type of an item stored in the Interner or Error if it was not found. @@ -935,6 +1007,12 @@ impl NodeInterner { *old = Node::Expression(new); } + /// Replaces the HirStatement at the given StmtId with a new HirStatement + pub fn replace_statement(&mut self, stmt_id: StmtId, hir_stmt: HirStatement) { + let old = self.nodes.get_mut(stmt_id.0).unwrap(); + *old = Node::Statement(hir_stmt); + } + pub fn next_type_variable_id(&self) -> TypeVariableId { let id = self.next_type_variable_id.get(); self.next_type_variable_id.set(id + 1); @@ -1446,6 +1524,105 @@ impl NodeInterner { pub(crate) fn ordering_type(&self) -> Type { self.ordering_type.clone().expect("Expected ordering_type to be set in the NodeInterner") } + + /// Register that `dependent` depends on `dependency`. + /// This is usually because `dependent` refers to `dependency` in one of its struct fields. + pub fn add_type_dependency(&mut self, dependent: DependencyId, dependency: StructId) { + self.add_dependency(dependent, DependencyId::Struct(dependency)); + } + + pub fn add_global_dependency(&mut self, dependent: DependencyId, dependency: GlobalId) { + self.add_dependency(dependent, DependencyId::Global(dependency)); + } + + pub fn add_function_dependency(&mut self, dependent: DependencyId, dependency: FuncId) { + self.add_dependency(dependent, DependencyId::Function(dependency)); + } + + fn add_dependency(&mut self, dependent: DependencyId, dependency: DependencyId) { + let dependent_index = self.get_or_insert_dependency(dependent); + let dependency_index = self.get_or_insert_dependency(dependency); + self.dependency_graph.update_edge(dependent_index, dependency_index, ()); + } + + fn get_or_insert_dependency(&mut self, id: DependencyId) -> PetGraphIndex { + if let Some(index) = self.dependency_graph_indices.get(&id) { + return *index; + } + + let index = self.dependency_graph.add_node(id); + self.dependency_graph_indices.insert(id, index); + index + } + + pub(crate) fn check_for_dependency_cycles(&self) -> Vec<(CompilationError, FileId)> { + let strongly_connected_components = tarjan_scc(&self.dependency_graph); + let mut errors = Vec::new(); + + let mut push_error = |item: String, scc: &[_], i, location: Location| { + let cycle = self.get_cycle_error_string(scc, i); + let span = location.span; + let error = ResolverError::DependencyCycle { item, cycle, span }; + errors.push((error.into(), location.file)); + }; + + for scc in strongly_connected_components { + if scc.len() > 1 { + // If a SCC contains a type, type alias, or global, it must be the only element in the SCC + for (i, index) in scc.iter().enumerate() { + match self.dependency_graph[*index] { + DependencyId::Struct(struct_id) => { + let struct_type = self.get_struct(struct_id); + let struct_type = struct_type.borrow(); + push_error(struct_type.name.to_string(), &scc, i, struct_type.location); + break; + } + DependencyId::Global(global_id) => { + let global = self.get_global(global_id); + let name = global.ident.to_string(); + push_error(name, &scc, i, global.location); + break; + } + DependencyId::Alias(alias_id) => { + let alias = self.get_type_alias(alias_id); + push_error(alias.name.to_string(), &scc, i, alias.location); + break; + } + // Mutually recursive functions are allowed + DependencyId::Function(_) => (), + } + } + } + } + + errors + } + + /// Build up a string starting from the given item containing each item in the dependency + /// cycle. The final result will resemble `foo -> bar -> baz -> foo`, always going back to the + /// element at the given start index. + fn get_cycle_error_string(&self, scc: &[PetGraphIndex], start_index: usize) -> String { + let index_to_string = |index: PetGraphIndex| match self.dependency_graph[index] { + DependencyId::Struct(id) => Cow::Owned(self.get_struct(id).borrow().name.to_string()), + DependencyId::Function(id) => Cow::Borrowed(self.function_name(&id)), + DependencyId::Alias(id) => { + Cow::Borrowed(self.get_type_alias(id).name.0.contents.as_ref()) + } + DependencyId::Global(id) => { + Cow::Borrowed(self.get_global(id).ident.0.contents.as_ref()) + } + }; + + let mut cycle = index_to_string(scc[start_index]).to_string(); + + // Reversing the dependencies here matches the order users would expect for the error message + for i in (0..scc.len()).rev() { + cycle += " -> "; + cycle += &index_to_string(scc[(start_index + i) % scc.len()]); + } + + cycle + } } impl Methods { diff --git a/noir/compiler/noirc_frontend/src/parser/errors.rs b/noir/compiler/noirc_frontend/src/parser/errors.rs index 5c869ff4719..9158c68db72 100644 --- a/noir/compiler/noirc_frontend/src/parser/errors.rs +++ b/noir/compiler/noirc_frontend/src/parser/errors.rs @@ -40,6 +40,8 @@ pub enum ParserErrorReason { NoFunctionAttributesAllowedOnStruct, #[error("Assert statements can only accept string literals")] AssertMessageNotString, + #[error("Integer bit size {0} won't be supported")] + DeprecatedBitSize(u32), #[error("{0}")] Lexer(LexerErrorKind), } @@ -130,6 +132,8 @@ impl std::fmt::Display for ParserError { } } +pub(crate) static ALLOWED_INTEGER_BIT_SIZES: &[u32] = &[1, 8, 32, 64]; + impl From for Diagnostic { fn from(error: ParserError) -> Diagnostic { match error.reason { @@ -145,6 +149,11 @@ impl From for Diagnostic { "The 'comptime' keyword has been deprecated. It can be removed without affecting your program".into(), error.span, ), + ParserErrorReason::DeprecatedBitSize(bit_size) => Diagnostic::simple_warning( + format!("Use of deprecated bit size {}", bit_size), + format!("Bit sizes for integers will be restricted to {}", ALLOWED_INTEGER_BIT_SIZES.iter().map(|n| n.to_string()).collect::>().join(", ")), + error.span, + ), ParserErrorReason::ExperimentalFeature(_) => Diagnostic::simple_warning( reason.to_string(), "".into(), diff --git a/noir/compiler/noirc_frontend/src/parser/parser.rs b/noir/compiler/noirc_frontend/src/parser/parser.rs index f82ce95c718..b1ec18f5ec5 100644 --- a/noir/compiler/noirc_frontend/src/parser/parser.rs +++ b/noir/compiler/noirc_frontend/src/parser/parser.rs @@ -23,6 +23,7 @@ //! prevent other parsers from being tried afterward since there is no longer an error. Thus, they should //! be limited to cases like the above `fn` example where it is clear we shouldn't back out of the //! current parser to try alternative parsers in a `choice` expression. +use super::errors::ALLOWED_INTEGER_BIT_SIZES; use super::{ foldl_with_span, labels::ParsingRuleLabel, parameter_name_recovery, parameter_recovery, parenthesized, then_commit, then_commit_ignore, top_level_statement_recovery, ExprParser, @@ -35,7 +36,7 @@ use crate::ast::{ }; use crate::lexer::Lexer; use crate::parser::{force, ignore_then_commit, statement_recovery}; -use crate::token::{Attribute, Attributes, Keyword, SecondaryAttribute, Token, TokenKind}; +use crate::token::{Attribute, Attributes, IntType, Keyword, SecondaryAttribute, Token, TokenKind}; use crate::{ BinaryOp, BinaryOpKind, BlockExpression, ConstrainKind, ConstrainStatement, Distinctness, ForLoopStatement, ForRange, FunctionDefinition, FunctionReturnType, FunctionVisibility, Ident, @@ -132,7 +133,7 @@ fn global_declaration() -> impl NoirParser { ); let p = then_commit(p, optional_type_annotation()); let p = then_commit_ignore(p, just(Token::Assign)); - let p = then_commit(p, literal_or_collection(expression()).map_with_span(Expression::new)); + let p = then_commit(p, expression()); p.map(LetStatement::new_let).map(TopLevelStatement::Global) } @@ -380,24 +381,24 @@ fn self_parameter() -> impl NoirParser { Token::Ident(ref word) if word == "self" => Ok(span), _ => Err(ParserError::expected_label(ParsingRuleLabel::Parameter, found, span)), })) - .map(|(pattern_keyword, span)| { - let ident = Ident::new("self".to_string(), span); - let path = Path::from_single("Self".to_owned(), span); - let mut self_type = UnresolvedTypeData::Named(path, vec![]).with_span(span); + .map(|(pattern_keyword, ident_span)| { + let ident = Ident::new("self".to_string(), ident_span); + let path = Path::from_single("Self".to_owned(), ident_span); + let mut self_type = UnresolvedTypeData::Named(path, vec![], true).with_span(ident_span); let mut pattern = Pattern::Identifier(ident); match pattern_keyword { Some((Token::Ampersand, _)) => { - self_type = - UnresolvedTypeData::MutableReference(Box::new(self_type)).with_span(span); + self_type = UnresolvedTypeData::MutableReference(Box::new(self_type)) + .with_span(ident_span); } Some((Token::Keyword(_), span)) => { - pattern = Pattern::Mutable(Box::new(pattern), span); + pattern = Pattern::Mutable(Box::new(pattern), span.merge(ident_span), true); } _ => (), } - Param { pattern, typ: self_type, visibility: Visibility::Private, span } + Param { span: pattern.span(), pattern, typ: self_type, visibility: Visibility::Private } }) } @@ -557,7 +558,7 @@ fn implementation() -> impl NoirParser { .ignore_then(generics()) .then(parse_type().map_with_span(|typ, span| (typ, span))) .then_ignore(just(Token::LeftBrace)) - .then(function_definition(true).repeated()) + .then(spanned(function_definition(true)).repeated()) .then_ignore(just(Token::RightBrace)) .map(|((generics, (object_type, type_span)), methods)| { TopLevelStatement::Impl(TypeImpl { generics, object_type, type_span, methods }) @@ -832,23 +833,10 @@ where ignore_then_commit(keyword(Keyword::Assert), parenthesized(argument_parser)) .labelled(ParsingRuleLabel::Statement) - .validate(|expressions, span, emit| { + .validate(|expressions, span, _| { let condition = expressions.get(0).unwrap_or(&Expression::error(span)).clone(); - let mut message_str = None; - - if let Some(message) = expressions.get(1) { - if let ExpressionKind::Literal(Literal::Str(message)) = &message.kind { - message_str = Some(message.clone()); - } else { - emit(ParserError::with_reason(ParserErrorReason::AssertMessageNotString, span)); - } - } - - StatementKind::Constrain(ConstrainStatement( - condition, - message_str, - ConstrainKind::Assert, - )) + let message = expressions.get(1).cloned(); + StatementKind::Constrain(ConstrainStatement(condition, message, ConstrainKind::Assert)) }) } @@ -861,7 +849,7 @@ where ignore_then_commit(keyword(Keyword::AssertEq), parenthesized(argument_parser)) .labelled(ParsingRuleLabel::Statement) - .validate(|exprs: Vec, span, emit| { + .validate(|exprs: Vec, span, _| { let predicate = Expression::new( ExpressionKind::Infix(Box::new(InfixExpression { lhs: exprs.get(0).unwrap_or(&Expression::error(span)).clone(), @@ -870,18 +858,10 @@ where })), span, ); - let mut message_str = None; - - if let Some(message) = exprs.get(2) { - if let ExpressionKind::Literal(Literal::Str(message)) = &message.kind { - message_str = Some(message.clone()); - } else { - emit(ParserError::with_reason(ParserErrorReason::AssertMessageNotString, span)); - } - } + let message = exprs.get(2).cloned(); StatementKind::Constrain(ConstrainStatement( predicate, - message_str, + message, ConstrainKind::AssertEq, )) }) @@ -914,7 +894,7 @@ fn pattern() -> impl NoirParser { let mut_pattern = keyword(Keyword::Mut) .ignore_then(pattern.clone()) - .map_with_span(|inner, span| Pattern::Mutable(Box::new(inner), span)); + .map_with_span(|inner, span| Pattern::Mutable(Box::new(inner), span, false)); let short_field = ident().map(|name| (name.clone(), Pattern::Identifier(name))); let long_field = ident().then_ignore(just(Token::Colon)).then(pattern.clone()); @@ -1113,13 +1093,25 @@ fn int_type() -> impl NoirParser { Err(ParserError::expected_label(ParsingRuleLabel::IntegerType, unexpected, span)) } })) + .validate(|int_type, span, emit| { + let bit_size = match int_type.1 { + IntType::Signed(bit_size) | IntType::Unsigned(bit_size) => bit_size, + }; + if !ALLOWED_INTEGER_BIT_SIZES.contains(&bit_size) { + emit(ParserError::with_reason( + ParserErrorReason::DeprecatedBitSize(bit_size), + span, + )); + } + int_type + }) .map_with_span(|(_, token), span| UnresolvedTypeData::from_int_token(token).with_span(span)) } fn named_type(type_parser: impl NoirParser) -> impl NoirParser { - path() - .then(generic_type_args(type_parser)) - .map_with_span(|(path, args), span| UnresolvedTypeData::Named(path, args).with_span(span)) + path().then(generic_type_args(type_parser)).map_with_span(|(path, args), span| { + UnresolvedTypeData::Named(path, args, false).with_span(span) + }) } fn named_trait(type_parser: impl NoirParser) -> impl NoirParser { @@ -1684,24 +1676,6 @@ fn literal() -> impl NoirParser { }) } -fn literal_with_sign() -> impl NoirParser { - choice(( - literal(), - just(Token::Minus).then(literal()).map(|(_, exp)| match exp { - ExpressionKind::Literal(Literal::Integer(value, sign)) => { - ExpressionKind::Literal(Literal::Integer(value, !sign)) - } - _ => unreachable!(), - }), - )) -} - -fn literal_or_collection<'a>( - expr_parser: impl ExprParser + 'a, -) -> impl NoirParser + 'a { - choice((literal_with_sign(), constructor(expr_parser.clone()), array_expr(expr_parser))) -} - #[cfg(test)] mod test { use noirc_errors::CustomDiagnostic; @@ -2092,7 +2066,13 @@ mod test { match parse_with(assertion(expression()), "assert(x == y, \"assertion message\")").unwrap() { StatementKind::Constrain(ConstrainStatement(_, message, _)) => { - assert_eq!(message, Some("assertion message".to_owned())); + let message = message.unwrap(); + match message.kind { + ExpressionKind::Literal(Literal::Str(message_string)) => { + assert_eq!(message_string, "assertion message".to_owned()); + } + _ => unreachable!(), + } } _ => unreachable!(), } @@ -2116,7 +2096,13 @@ mod test { .unwrap() { StatementKind::Constrain(ConstrainStatement(_, message, _)) => { - assert_eq!(message, Some("assertion message".to_owned())); + let message = message.unwrap(); + match message.kind { + ExpressionKind::Literal(Literal::Str(message_string)) => { + assert_eq!(message_string, "assertion message".to_owned()); + } + _ => unreachable!(), + } } _ => unreachable!(), } @@ -2483,7 +2469,7 @@ mod test { Case { source: "assert(x == x, x)", expect: "constrain (plain::x == plain::x)", - errors: 1, + errors: 0, }, Case { source: "assert_eq(x,)", expect: "constrain (Error == Error)", errors: 1 }, Case { @@ -2494,7 +2480,7 @@ mod test { Case { source: "assert_eq(x, x, x)", expect: "constrain (plain::x == plain::x)", - errors: 1, + errors: 0, }, ]; diff --git a/noir/compiler/noirc_frontend/src/tests.rs b/noir/compiler/noirc_frontend/src/tests.rs index a4246a9fe7d..1deff446d7e 100644 --- a/noir/compiler/noirc_frontend/src/tests.rs +++ b/noir/compiler/noirc_frontend/src/tests.rs @@ -1128,9 +1128,9 @@ mod test { } fn check_rewrite(src: &str, expected: &str) { - let (_program, context, _errors) = get_program(src); + let (_program, mut context, _errors) = get_program(src); let main_func_id = context.def_interner.find_function("main").unwrap(); - let program = monomorphize(main_func_id, &context.def_interner); + let program = monomorphize(main_func_id, &mut context.def_interner); assert!(format!("{}", program) == expected); } @@ -1164,4 +1164,24 @@ fn lambda$f1(mut env$l1: (Field)) -> Field { "#; check_rewrite(src, expected_rewrite); } + + #[test] + fn deny_cyclic_structs() { + let src = r#" + struct Foo { bar: Bar } + struct Bar { foo: Foo } + fn main() {} + "#; + assert_eq!(get_program_errors(src).len(), 1); + } + + #[test] + fn deny_cyclic_globals() { + let src = r#" + global A = B; + global B = A; + fn main() {} + "#; + assert_eq!(get_program_errors(src).len(), 1); + } } diff --git a/noir/compiler/noirc_printable_type/src/lib.rs b/noir/compiler/noirc_printable_type/src/lib.rs index 18f2fe0a873..24f4f275a14 100644 --- a/noir/compiler/noirc_printable_type/src/lib.rs +++ b/noir/compiler/noirc_printable_type/src/lib.rs @@ -6,7 +6,7 @@ use regex::{Captures, Regex}; use serde::{Deserialize, Serialize}; use thiserror::Error; -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(tag = "kind", rename_all = "lowercase")] pub enum PrintableType { Field, @@ -50,6 +50,7 @@ pub enum PrintableValue { String(String), Vec(Vec), Struct(BTreeMap), + Other, } /// In order to display a `PrintableValue` we need a `PrintableType` to accurately @@ -69,6 +70,9 @@ pub enum ForeignCallError { #[error("Failed calling external resolver. {0}")] ExternalResolverError(#[from] jsonrpc::Error), + + #[error("Assert message resolved after an unsatisified constrain. {0}")] + ResolvedAssertMessage(String), } impl TryFrom<&[ForeignCallParam]> for PrintableValueDisplay { @@ -293,7 +297,7 @@ fn format_field_string(field: FieldElement) -> String { } /// Assumes that `field_iterator` contains enough [FieldElement] in order to decode the [PrintableType] -fn decode_value( +pub fn decode_value( field_iterator: &mut impl Iterator, typ: &PrintableType, ) -> PrintableValue { diff --git a/noir/compiler/wasm/README.md b/noir/compiler/wasm/README.md index 0b2d92b0815..52f7e83e19e 100644 --- a/noir/compiler/wasm/README.md +++ b/noir/compiler/wasm/README.md @@ -1,9 +1,32 @@ # Noir Lang WASM JavaScript Package -This JavaScript package enables users to compile a Noir program, i.e. generating its artifacts. +This JavaScript package enables users to compile a Noir program, i.e. generating its artifacts, both in Node.JS environments and the browser. The package also handles dependency management like how Nargo (Noir's CLI tool) operates, but the package is used just for compilation, not proving, verifying and simulating functions. +## Usage + +```typescript +// Node.js + +import { compile, createFileManager } from '@noir-lang/noir_wasm'; + +const fm = createFileManager(myProjectPath); +const myCompiledCode = await compile(fm); +``` + +```typescript +// Browser + +import { compile, createFileManager } from '@noir-lang/noir_wasm'; + +const fm = createFileManager('/'); +for (const path of files) { + await fm.writeFile(path, await getFileAsStream(path)); +} +const myCompiledCode = await compile(fm); +``` + ## Building from source Outside of the [noir repo](https://github.com/noir-lang/noir), this package can be built using the command below: diff --git a/noir/compiler/wasm/package.json b/noir/compiler/wasm/package.json index 2aaf4a494df..74dfd27de3e 100644 --- a/noir/compiler/wasm/package.json +++ b/noir/compiler/wasm/package.json @@ -80,6 +80,7 @@ "webpack-cli": "^4.7.2" }, "dependencies": { + "@noir-lang/types": "workspace:*", "pako": "^2.1.0" } } diff --git a/noir/compiler/wasm/src/index.cts b/noir/compiler/wasm/src/index.cts index 14687e615df..7c707e662d8 100644 --- a/noir/compiler/wasm/src/index.cts +++ b/noir/compiler/wasm/src/index.cts @@ -5,6 +5,36 @@ import { LogData, LogFn } from './utils'; import { CompilationResult } from './types/noir_artifact'; import { inflateDebugSymbols } from './noir/debug'; +/** + * Compiles a Noir project + * + * @param fileManager - The file manager to use + * @param projectPath - The path to the project inside the file manager. Defaults to the root of the file manager + * @param logFn - A logging function. If not provided, console.log will be used + * @param debugLogFn - A debug logging function. If not provided, logFn will be used + * + * @example + * ```typescript + * // Node.js + * + * import { compile, createFileManager } from '@noir-lang/noir_wasm'; + * + * const fm = createFileManager(myProjectPath); + * const myCompiledCode = await compile(fm); + * ``` + * + * ```typescript + * // Browser + * + * import { compile, createFileManager } from '@noir-lang/noir_wasm'; + * + * const fm = createFileManager('/'); + * for (const path of files) { + * await fm.writeFile(path, await getFileAsStream(path)); + * } + * const myCompiledCode = await compile(fm); + * ``` + */ async function compile( fileManager: FileManager, projectPath?: string, diff --git a/noir/compiler/wasm/src/index.mts b/noir/compiler/wasm/src/index.mts index 8774a7857ef..d4ed0beccfc 100644 --- a/noir/compiler/wasm/src/index.mts +++ b/noir/compiler/wasm/src/index.mts @@ -5,6 +5,36 @@ import { LogData, LogFn } from './utils'; import { CompilationResult } from './types/noir_artifact'; import { inflateDebugSymbols } from './noir/debug'; +/** + * Compiles a Noir project + * + * @param fileManager - The file manager to use + * @param projectPath - The path to the project inside the file manager. Defaults to the root of the file manager + * @param logFn - A logging function. If not provided, console.log will be used + * @param debugLogFn - A debug logging function. If not provided, logFn will be used + * + * @example + * ```typescript + * // Node.js + * + * import { compile, createFileManager } from '@noir-lang/noir_wasm'; + * + * const fm = createFileManager(myProjectPath); + * const myCompiledCode = await compile(fm); + * ``` + * + * ```typescript + * // Browser + * + * import { compile, createFileManager } from '@noir-lang/noir_wasm'; + * + * const fm = createFileManager('/'); + * for (const path of files) { + * await fm.writeFile(path, await getFileAsStream(path)); + * } + * const myCompiledCode = await compile(fm); + * ``` + */ async function compile( fileManager: FileManager, projectPath?: string, diff --git a/noir/compiler/wasm/src/noir/debug.ts b/noir/compiler/wasm/src/noir/debug.ts index 7a65f4b68c2..1a4ccfe95ec 100644 --- a/noir/compiler/wasm/src/noir/debug.ts +++ b/noir/compiler/wasm/src/noir/debug.ts @@ -1,6 +1,9 @@ import { inflate } from 'pako'; -/** Decompresses and decodes the debug symbols */ +/** + * Decompresses and decodes the debug symbols + * @param debugSymbols - The base64 encoded debug symbols + */ export function inflateDebugSymbols(debugSymbols: string) { return JSON.parse(inflate(Buffer.from(debugSymbols, 'base64'), { to: 'string', raw: true })); } diff --git a/noir/compiler/wasm/src/noir/file-manager/nodejs-file-manager.ts b/noir/compiler/wasm/src/noir/file-manager/nodejs-file-manager.ts index 1a8250f49cc..195eea8a70d 100644 --- a/noir/compiler/wasm/src/noir/file-manager/nodejs-file-manager.ts +++ b/noir/compiler/wasm/src/noir/file-manager/nodejs-file-manager.ts @@ -18,8 +18,9 @@ export async function readdirRecursive(dir: string): Promise { } /** - * Creates a new FileManager instance based on nodejs fs - * @param dataDir - where to store files + * Creates a new FileManager instance based on fs in node and memfs in the browser (via webpack alias) + * + * @param dataDir - root of the file system */ export function createNodejsFileManager(dataDir: string): FileManager { return new FileManager( diff --git a/noir/compiler/wasm/src/types/noir_artifact.ts b/noir/compiler/wasm/src/types/noir_artifact.ts index 715877e335f..350a4053a9a 100644 --- a/noir/compiler/wasm/src/types/noir_artifact.ts +++ b/noir/compiler/wasm/src/types/noir_artifact.ts @@ -1,4 +1,4 @@ -import { Abi, AbiType } from '@noir-lang/noirc_abi'; +import { Abi, AbiType } from '@noir-lang/types'; /** * A named type. diff --git a/noir/cspell.json b/noir/cspell.json index 12b1e3f63d3..34424647616 100644 --- a/noir/cspell.json +++ b/noir/cspell.json @@ -13,7 +13,6 @@ "arithmetization", "arity", "arkworks", - "arraysort", "barebones", "barretenberg", "bincode", @@ -157,6 +156,7 @@ "subshell", "subtyping", "swcurve", + "Taiko", "tecurve", "tempdir", "tempfile", diff --git a/noir/deny.toml b/noir/deny.toml index 5edce08fb70..a3e506984c9 100644 --- a/noir/deny.toml +++ b/noir/deny.toml @@ -57,7 +57,7 @@ allow = [ # bitmaps 2.1.0, generational-arena 0.2.9,im 15.1.0 "MPL-2.0", # Boost Software License - "BSL-1.0" + "BSL-1.0", ] # Allow 1 or more licenses on a per-crate basis, so that particular licenses @@ -93,7 +93,12 @@ unknown-registry = "warn" # Lint level for what to happen when a crate from a git repository that is not # in the allow list is encountered unknown-git = "deny" + +# DON'T YOU DARE ADD ANYTHING TO THIS IF YOU WANT TO PUBLISH ANYTHING NOIR RELATED TO CRATES.IO +# +# crates.io rejects git dependencies so anything depending on these is unpublishable and you'll ruin my day +# when I find out. allow-git = [ - "https://github.com/noir-lang/grumpkin", - "https://github.com/jfecher/chumsky" + "https://github.com/jfecher/chumsky", + "https://github.com/noir-lang/clap-markdown", ] diff --git a/noir/docs/docs/getting_started/installation/other_install_methods.md b/noir/docs/docs/getting_started/installation/other_install_methods.md index a532f83750e..489f1eda802 100644 --- a/noir/docs/docs/getting_started/installation/other_install_methods.md +++ b/noir/docs/docs/getting_started/installation/other_install_methods.md @@ -1,38 +1,102 @@ --- title: Alternative Install Methods -description: - There are different ways to install Nargo, the one-stop shop and command-line tool for developing Noir programs. This guide explains other methods that don't rely on noirup, such as compiling from source, installing from binaries, and using WSL for windows +description: There are different ways to install Nargo, the one-stop shop and command-line tool for developing Noir programs. This guide explains other methods that don't rely on noirup, such as compiling from source, installing from binaries, and using WSL for windows keywords: [ - Installation - Nargo - Noirup - Binaries - Compiling from Source - WSL for Windows - macOS - Linux - Nix - Direnv - Shell & editor experience - Building and testing - Uninstalling Nargo - Noir vs code extension -] + Installation + Nargo + Noirup + Binaries + Compiling from Source + WSL for Windows + macOS + Linux + Nix + Direnv + Shell & editor experience + Building and testing + Uninstalling Nargo + Noir vs code extension, + ] sidebar_position: 1 --- +## Encouraged Installation Method: Noirup -## Installation +Noirup is the endorsed method for installing Nargo, streamlining the process of fetching binaries or compiling from source. It supports a range of options to cater to your specific needs, from nightly builds and specific versions to compiling from various sources. -The most common method of installing Nargo is through [Noirup](./index.md) +### Installing Noirup + +First, ensure you have `noirup` installed: + +```sh +curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash +``` + +### Fetching Binaries + +With `noirup`, you can easily switch between different Nargo versions, including nightly builds: + +- **Nightly Version**: Install the latest nightly build. + + ```sh + noirup --version nightly + ``` + +- **Specific Version**: Install a specific version of Nargo. + ```sh + noirup --version + ``` + +### Compiling from Source + +`noirup` also enables compiling Nargo from various sources: + +- **From a Specific Branch**: Install from the latest commit on a branch. + + ```sh + noirup --branch + ``` + +- **From a Fork**: Install from the main branch of a fork. + + ```sh + noirup --repo + ``` + +- **From a Specific Branch in a Fork**: Install from a specific branch in a fork. + + ```sh + noirup --repo --branch + ``` + +- **From a Specific Pull Request**: Install from a specific PR. + + ```sh + noirup --pr + ``` + +- **From a Specific Commit**: Install from a specific commit. + + ```sh + noirup -C + ``` + +- **From Local Source**: Compile and install from a local directory. + ```sh + noirup --path ./path/to/local/source + ``` + +## Alternate Installation Methods (No Longer Recommended) + +While the following methods are available, they are no longer recommended. We advise using noirup for a more efficient and flexible installation experience. However, there are other methods for installing Nargo: -- [Binaries](#binaries) -- [Compiling from Source](#compile-from-source) -- [WSL for Windows](#wsl-for-windows) +- [Binaries](#option-1-installing-from-binaries) +- [Compiling from Source](#option-2-compile-from-source) +- [WSL for Windows](#option-3-wsl-for-windows) -### Binaries +### Option 1: Installing from Binaries See [GitHub Releases](https://github.com/noir-lang/noir/releases) for the latest and previous platform specific binaries. @@ -81,7 +145,7 @@ Check if the installation was successful by running `nargo --version`. You shoul > **macOS:** If you are prompted with an OS alert, right-click and open the _nargo_ executable from > Finder. Close the new terminal popped up and `nargo` should now be accessible. -### Option 3: Compile from Source +### Option 2: Compile from Source Due to the large number of native dependencies, Noir projects uses [Nix](https://nixos.org/) and [direnv](https://direnv.net/) to streamline the development experience. It helps mitigating issues commonly associated with dependency management, such as conflicts between required package versions for different projects (often referred to as "dependency hell"). @@ -161,19 +225,19 @@ If you have hesitations with using direnv, you can launch a subshell with `nix d Advanced: If you aren't using direnv nor launching your editor within the subshell, you can try to install Barretenberg and other global dependencies the package needs. This is an advanced workflow and likely won't receive support! -### Option 4: WSL (for Windows) +### Option 3: WSL (for Windows) The default backend for Noir (Barretenberg) doesn't provide Windows binaries at this time. For that reason, Noir cannot be installed natively. However, it is available by using Windows Subsystem for Linux (WSL). Step 1: Follow the instructions [here](https://learn.microsoft.com/en-us/windows/wsl/install) to install and run WSL. -step 2: Follow the [Noirup instructions](./index.md). +step 2: Follow the [Noirup instructions](#encouraged-installation-method-noirup). ## Uninstalling Nargo ### Noirup -If you installed Noir with `noirup`, you can uninstall Noir by removing the files in `~/.nargo`, `~/nargo` and `~/noir_cache`. +If you installed Nargo with `noirup` or through directly downloading binaries, you can uninstall Nargo by removing the files in `~/.nargo`, `~/nargo`, and `~/noir_cache`. This ensures that all installed binaries, configurations, and cache related to Nargo are fully removed from your system. ```bash rm -r ~/.nargo @@ -183,7 +247,7 @@ rm -r ~/noir_cache ### Nix -If you installed Noir with Nix or from source, you can remove the binary located at `~/.nix-profile/bin/nargo`. +If you installed Nargo with Nix or compiled it from source, you can remove the binary located at `~/.nix-profile/bin/nargo`. ```bash rm ~/.nix-profile/bin/nargo diff --git a/noir/docs/docs/how_to/how-to-recursion.md b/noir/docs/docs/how_to/how-to-recursion.md index f34647a99d5..4c45bb87ae2 100644 --- a/noir/docs/docs/how_to/how-to-recursion.md +++ b/noir/docs/docs/how_to/how-to-recursion.md @@ -42,9 +42,9 @@ In short: ::: -In a standard recursive app, you're also dealing with at least two circuits. For the purpose of this guide, we will assume these two: +In a standard recursive app, you're also dealing with at least two circuits. For the purpose of this guide, we will assume the following: -- `main`: a circuit of type `assert(x != y)` +- `main`: a circuit of type `assert(x != y)`, where `main` is marked with a `#[recursive]` attribute. This attribute states that the backend should generate proofs that are friendly for verification within another circuit. - `recursive`: a circuit that verifies `main` For a full example on how recursive proofs work, please refer to the [noir-examples](https://github.com/noir-lang/noir-examples) repository. We will *not* be using it as a reference for this guide. @@ -77,7 +77,7 @@ const { witness } = noir.execute(input) With this witness, you are now able to generate the intermediate proof for the main circuit: ```js -const { proof, publicInputs } = await backend.generateIntermediateProof(witness) +const { proof, publicInputs } = await backend.generateProof(witness) ``` :::warning @@ -95,13 +95,13 @@ With this in mind, it becomes clear that our intermediate proof is the one *mean Optionally, you are able to verify the intermediate proof: ```js -const verified = await backend.verifyIntermediateProof({ proof, publicInputs }) +const verified = await backend.verifyProof({ proof, publicInputs }) ``` -This can be useful to make sure our intermediate proof was correctly generated. But the real goal is to do it within another circuit. For that, we need to generate the intermediate artifacts: +This can be useful to make sure our intermediate proof was correctly generated. But the real goal is to do it within another circuit. For that, we need to generate recursive proof artifacts that will be passed to the circuit that is verifying the proof we just generated. Instead of passing the proof and verification key as a byte array, we pass them as fields which makes it cheaper to verify in a circuit: ```js -const { proofAsFields, vkAsFields, vkHash } = await backend.generateIntermediateProofArtifacts( { publicInputs, proof }, publicInputsCount) +const { proofAsFields, vkAsFields, vkHash } = await backend.generateRecursiveProofArtifacts( { publicInputs, proof }, publicInputsCount) ``` This call takes the public inputs and the proof, but also the public inputs count. While this is easily retrievable by simply counting the `publicInputs` length, the backend interface doesn't currently abstract it away. @@ -135,8 +135,8 @@ const recursiveInputs = { } const { witness, returnValue } = noir.execute(recursiveInputs) // we're executing the recursive circuit now! -const { proof, publicInputs } = backend.generateFinalProof(witness) -const verified = backend.verifyFinalProof({ proof, publicInputs }) +const { proof, publicInputs } = backend.generateProof(witness) +const verified = backend.verifyProof({ proof, publicInputs }) ``` You can obviously chain this proof into another proof. In fact, if you're using recursive proofs, you're probably interested of using them this way! @@ -165,15 +165,15 @@ This allows you to neatly call exactly the method you want without conflicting n ```js // Alice runs this 👇 const { witness: mainWitness } = await noir_programs.main.execute(input) -const proof = await backends.main.generateIntermediateProof(mainWitness) +const proof = await backends.main.generateProof(mainWitness) // Bob runs this 👇 -const verified = await backends.main.verifyIntermediateProof(proof) -const { proofAsFields, vkAsFields, vkHash } = await backends.main.generateIntermediateProofArtifacts( +const verified = await backends.main.verifyProof(proof) +const { proofAsFields, vkAsFields, vkHash } = await backends.main.generateRecursiveProofArtifacts( proof, numPublicInputs, ); -const recursiveProof = await noir_programs.recursive.generateFinalProof(recursiveInputs) +const recursiveProof = await noir_programs.recursive.generateProof(recursiveInputs) ``` ::: diff --git a/noir/docs/docs/noir/concepts/assert.md b/noir/docs/docs/noir/concepts/assert.md index c5f9aff139c..bcff613a695 100644 --- a/noir/docs/docs/noir/concepts/assert.md +++ b/noir/docs/docs/noir/concepts/assert.md @@ -18,10 +18,28 @@ fn main(x : Field, y : Field) { } ``` +> Assertions only work for predicate operations, such as `==`. If there's any ambiguity on the operation, the program will fail to compile. For example, it is unclear if `assert(x + y)` would check for `x + y == 0` or simply would return `true`. + You can optionally provide a message to be logged when the assertion fails: ```rust assert(x == y, "x and y are not equal"); ``` -> Assertions only work for predicate operations, such as `==`. If there's any ambiguity on the operation, the program will fail to compile. For example, it is unclear if `assert(x + y)` would check for `x + y == 0` or simply would return `true`. +Aside string literals, the optional message can be a format string or any other type supported as input for Noir's [print](../standard_library/logging.md) functions. This feature lets you incorporate runtime variables into your failed assertion logs: + +```rust +assert(x == y, f"Expected x == y, but got {x} == {y}"); +``` + +Using a variable as an assertion message directly: + +```rust +struct myStruct { + myField: Field +} + +let s = myStruct { myField: y }; +assert(s.myField == x, s); +``` + diff --git a/noir/docs/docs/noir/concepts/data_types/fields.md b/noir/docs/docs/noir/concepts/data_types/fields.md index 7870c98c858..99b4aa63549 100644 --- a/noir/docs/docs/noir/concepts/data_types/fields.md +++ b/noir/docs/docs/noir/concepts/data_types/fields.md @@ -181,3 +181,12 @@ Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x ∈ \{0, ..., p-1\} ```rust fn sgn0(self) -> u1 ``` + + +### lt + +Returns true if the field is less than the other field + +```rust +pub fn lt(self, another: Field) -> bool +``` diff --git a/noir/docs/docs/noir/concepts/data_types/integers.md b/noir/docs/docs/noir/concepts/data_types/integers.md index 7d1e83cf4e9..30135d76e4a 100644 --- a/noir/docs/docs/noir/concepts/data_types/integers.md +++ b/noir/docs/docs/noir/concepts/data_types/integers.md @@ -51,6 +51,55 @@ If you are using the default proving backend with Noir, both even (e.g. _u2_, _i ::: + +## 128 bits Unsigned Integers + +The built-in structure `U128` allows you to use 128-bit unsigned integers almost like a native integer type. However, there are some differences to keep in mind: +- You cannot cast between a native integer and `U128` +- There is a higher performance cost when using `U128`, compared to a native type. + +Conversion between unsigned integer types and U128 are done through the use of `from_integer` and `to_integer` functions. + +```rust +fn main() { + let x = U128::from_integer(23); + let y = U128::from_hex("0x7"); + let z = x + y; + assert(z.to_integer() == 30); +} +``` + +`U128` is implemented with two 64 bits limbs, representing the low and high bits, which explains the performance cost. You should expect `U128` to be twice more costly for addition and four times more costly for multiplication. +You can construct a U128 from its limbs: +```rust +fn main(x: u64, y: u64) { + let x = U128::from_u64s_be(x,y); + assert(z.hi == x as Field); + assert(z.lo == y as Field); +} +``` + +Note that the limbs are stored as Field elements in order to avoid unnecessary conversions. +Apart from this, most operations will work as usual: + +```rust +fn main(x: U128, y: U128) { + // multiplication + let c = x * y; + // addition and subtraction + let c = c - x + y; + // division + let c = x / y; + // bit operation; + let c = x & y | y; + // bit shift + let c = x << y; + // comparisons; + let c = x < y; + let c = x == y; +} +``` + ## Overflows Computations that exceed the type boundaries will result in overflow errors. This happens with both signed and unsigned integers. For example, attempting to prove: @@ -108,6 +157,6 @@ Example of how it is used: use dep::std; fn main(x: u8, y: u8) -> pub u8 { - std::wrapping_add(x + y) + std::wrapping_add(x, y) } ``` diff --git a/noir/docs/docs/noir/concepts/globals.md b/noir/docs/docs/noir/concepts/globals.md new file mode 100644 index 00000000000..063a3d89248 --- /dev/null +++ b/noir/docs/docs/noir/concepts/globals.md @@ -0,0 +1,72 @@ +--- +title: Global Variables +description: + Learn about global variables in Noir. Discover how + to declare, modify, and use them in your programs. +keywords: [noir programming language, globals, global variables, constants] +sidebar_position: 8 +--- + +## Globals + + +Noir supports global variables. The global's type can be inferred by the compiler entirely: + +```rust +global N = 5; // Same as `global N: Field = 5` + +global TUPLE = (3, 2); + +fn main() { + assert(N == 5); + assert(N == TUPLE.0 + TUPLE.1); +} +``` + +:::info + +Globals can be defined as any expression, so long as they don't depend on themselves - otherwise there would be a dependency cycle! For example: + +```rust +global T = foo(T); // dependency error +``` + +::: + + +If they are initialized to a literal integer, globals can be used to specify an array's length: + +```rust +global N: Field = 2; + +fn main(y : [Field; N]) { + assert(y[0] == y[1]) +} +``` + +A global from another module can be imported or referenced externally like any other name: + +```rust +global N = 20; + +fn main() { + assert(my_submodule::N != N); +} + +mod my_submodule { + global N: Field = 10; +} +``` + +When a global is used, Noir replaces the name with its definition on each occurrence. +This means globals defined using function calls will repeat the call each time they're used: + +```rust +global RESULT = foo(); + +fn foo() -> [Field; 100] { ... } +``` + +This is usually fine since Noir will generally optimize any function call that does not +refer to a program input into a constant. It should be kept in mind however, if the called +function performs side-effects like `println`, as these will still occur on each use. diff --git a/noir/docs/docs/noir/concepts/mutability.md b/noir/docs/docs/noir/concepts/mutability.md index 9cc10429cb4..fdeef6a87c5 100644 --- a/noir/docs/docs/noir/concepts/mutability.md +++ b/noir/docs/docs/noir/concepts/mutability.md @@ -1,9 +1,9 @@ --- title: Mutability description: - Learn about mutable variables, constants, and globals in Noir programming language. Discover how + Learn about mutable variables in Noir. Discover how to declare, modify, and use them in your programs. -keywords: [noir programming language, mutability in noir, mutable variables, constants, globals] +keywords: [noir programming language, mutability in noir, mutable variables] sidebar_position: 8 --- @@ -49,45 +49,73 @@ fn helper(mut x: i32) { } ``` -## Comptime Values +## Non-local mutability -:::warning +Non-local mutability can be achieved through the mutable reference type `&mut T`: -The 'comptime' keyword was removed in version 0.10. The comptime keyword and syntax are currently still kept and parsed for backwards compatibility, but are now deprecated and will issue a warning when used. `comptime` has been removed because it is no longer needed for accessing arrays. - -::: +```rust +fn set_to_zero(x: &mut Field) { + *x = 0; +} -## Globals +fn main() { + let mut y = 42; + set_to_zero(&mut y); + assert(*y == 0); +} +``` -Noir also supports global variables. However, they must be known at compile-time. The global type can also be inferred by the compiler entirely. Globals can also be used to specify array -annotations for function parameters and can be imported from submodules. +When creating a mutable reference, the original variable being referred to (`y` in this +example) must also be mutable. Since mutable references are a reference type, they must +be explicitly dereferenced via `*` to retrieve the underlying value. Note that this yields +a copy of the value, so mutating this copy will not change the original value behind the +reference: ```rust -global N: Field = 5; // Same as `global N: Field = 5` +fn main() { + let mut x = 1; + let x_ref = &mut x; + + let mut y = *x_ref; + let y_ref = &mut y; -fn main(x : Field, y : [Field; N]) { - let res = x * N; + x = 2; + *x_ref = 3; - assert(res == y[0]); + y = 4; + *y_ref = 5; - let res2 = x * my_submodule::N; - assert(res != res2); + assert(x == 3); + assert(*x_ref == 3); + assert(y == 5); + assert(*y_ref == 5); } +``` -mod my_submodule { - use dep::std; +Note that types in Noir are actually deeply immutable so the copy that occurs when +dereferencing is only a conceptual copy - no additional constraints will occur. - global N: Field = 10; +Mutable references can also be stored within structs. Note that there is also +no lifetime parameter on these unlike rust. This is because the allocated memory +always lasts the entire program - as if it were an array of one element. - fn my_helper() -> Field { - let x = N; - x +```rust +struct Foo { + x: &mut Field +} + +impl Foo { + fn incr(mut self) { + *self.x += 1; } } -``` -## Why only local mutability? +fn main() { + let foo = Foo { x: &mut 0 }; + foo.incr(); + assert(*foo.x == 1); +} +``` -Witnesses in a proving system are immutable in nature. Noir aims to _closely_ mirror this setting -without applying additional overhead to the user. Modeling a mutable reference is not as -straightforward as on conventional architectures and would incur some possibly unexpected overhead. +In general, you should avoid non-local & shared mutability unless it is needed. Sticking +to only local mutability will improve readability and potentially improve compiler optimizations as well. diff --git a/noir/docs/docs/noir/concepts/unconstrained.md b/noir/docs/docs/noir/concepts/unconstrained.md index 6b3424f7993..89d12c1c971 100644 --- a/noir/docs/docs/noir/concepts/unconstrained.md +++ b/noir/docs/docs/noir/concepts/unconstrained.md @@ -40,7 +40,7 @@ Total ACIR opcodes generated for language PLONKCSat { width: 3 }: 91 Backend circuit size: 3619 ``` -A lot of the operations in this function are optimized away by the compiler (all the bit-shifts turn into divisions by constants). However we can save a bunch of gates by casting to u8 a bit earlier. This automatically truncates the bit-shifted value to fit in a u8 which allows us to remove the XOR against 0xff. This saves us ~480 gates in total. +A lot of the operations in this function are optimized away by the compiler (all the bit-shifts turn into divisions by constants). However we can save a bunch of gates by casting to u8 a bit earlier. This automatically truncates the bit-shifted value to fit in a u8 which allows us to remove the AND against 0xff. This saves us ~480 gates in total. ```rust fn main(num: u72) -> pub [u8; 8] { diff --git a/noir/docs/docs/noir/standard_library/black_box_fns.md b/noir/docs/docs/noir/standard_library/black_box_fns.md index 6b22d0e7466..eae8744abf0 100644 --- a/noir/docs/docs/noir/standard_library/black_box_fns.md +++ b/noir/docs/docs/noir/standard_library/black_box_fns.md @@ -15,7 +15,7 @@ Here is a list of the current black box functions: - [SHA256](./cryptographic_primitives/hashes#sha256) - [Schnorr signature verification](./cryptographic_primitives/schnorr) - [Blake2s](./cryptographic_primitives/hashes#blake2s) -- [Blake3](./cryptographic_primitives/hashes#blake2s) +- [Blake3](./cryptographic_primitives/hashes#blake3) - [Pedersen Hash](./cryptographic_primitives/hashes#pedersen_hash) - [Pedersen Commitment](./cryptographic_primitives/hashes#pedersen_commitment) - [ECDSA signature verification](./cryptographic_primitives/ecdsa_sig_verification) diff --git a/noir/docs/docs/noir/standard_library/bn254.md b/noir/docs/docs/noir/standard_library/bn254.md new file mode 100644 index 00000000000..3294f005dbb --- /dev/null +++ b/noir/docs/docs/noir/standard_library/bn254.md @@ -0,0 +1,46 @@ +--- +title: Bn254 Field Library +--- + +Noir provides a module in standard library with some optimized functions for bn254 Fr in `std::field::bn254`. + +## decompose + +```rust +fn decompose(x: Field) -> (Field, Field) {} +``` + +Decomposes a single field into two fields, low and high. The low field contains the lower 16 bytes of the input field and the high field contains the upper 16 bytes of the input field. Both field results are range checked to 128 bits. + + +## assert_gt + +```rust +fn assert_gt(a: Field, b: Field) {} +``` + +Asserts that a > b. This will generate less constraints than using `assert(gt(a, b))`. + +## assert_lt + +```rust +fn assert_lt(a: Field, b: Field) {} +``` + +Asserts that a < b. This will generate less constraints than using `assert(lt(a, b))`. + +## gt + +```rust +fn gt(a: Field, b: Field) -> bool {} +``` + +Returns true if a > b. + +## lt + +```rust +fn lt(a: Field, b: Field) -> bool {} +``` + +Returns true if a < b. \ No newline at end of file diff --git a/noir/docs/docs/noir/standard_library/options.md b/noir/docs/docs/noir/standard_library/options.md index 970c9cfbf11..a1bd4e1de5f 100644 --- a/noir/docs/docs/noir/standard_library/options.md +++ b/noir/docs/docs/noir/standard_library/options.md @@ -56,6 +56,10 @@ Returns the wrapped value if `self.is_some()`. Otherwise, returns the given defa Returns the wrapped value if `self.is_some()`. Otherwise, calls the given function to return a default value. +### expect + +Asserts `self.is_some()` with a provided custom message and returns the contained `Some` value. The custom message is expected to be a format string. + ### map If self is `Some(x)`, this returns `Some(f(x))`. Otherwise, this returns `None`. diff --git a/noir/docs/docs/reference/nargo_commands.md b/noir/docs/docs/reference/nargo_commands.md deleted file mode 100644 index fc2671b2bfc..00000000000 --- a/noir/docs/docs/reference/nargo_commands.md +++ /dev/null @@ -1,253 +0,0 @@ ---- -title: Nargo -description: - Noir CLI Commands for Noir Prover and Verifier to create, execute, prove and verify programs, - generate Solidity verifier smart contract and compile into JSON file containing ACIR - representation and ABI of circuit. -keywords: - [ - Nargo, - Noir CLI, - Noir Prover, - Noir Verifier, - generate Solidity verifier, - compile JSON file, - ACIR representation, - ABI of circuit, - TypeScript, - ] -sidebar_position: 0 ---- - -## General options - -| 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]` - -Prints the list of available commands or specific information of a subcommand. - -_Arguments_ - -| Argument | Description | -| -------------- | -------------------------------------------- | -| `` | The subcommand whose help message to display | - -## `nargo backend` - -Installs and selects custom backends used to generate and verify proofs. - -### Commands - -| 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 - -| Option | Description | -| ------------ | ----------- | -| `-h, --help` | Print help | - -## `nargo check` - -Generate the `Prover.toml` and `Verifier.toml` files for specifying prover and verifier in/output -values of the Noir program respectively. - -### Options - -| 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` - -Generate a Solidity verifier smart contract for the program. - -### Options - -| 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` - -Compile the program into a JSON build artifact file containing the ACIR representation and the ABI -of the circuit. This build artifact can then be used to generate and verify proofs. - -You can also use "build" as an alias for compile (e.g. `nargo build`). - -### Options - -| Option | Description | -| --------------------- | ------------------------------------------------------------ | -| `--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 ` - -Creates a new Noir project in a new folder. - -**Arguments** - -| Argument | Description | -| -------- | -------------------------------- | -| `` | The path to save the new project | - -### Options - -| 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` - -Creates a new Noir project in the current directory. - -### Options - -| 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]` - -Runs the Noir program and prints its return value. - -**Arguments** - -| Argument | Description | -| ---------------- | ----------------------------------------- | -| `[WITNESS_NAME]` | Write the execution witness to named file | - -### Options - -| 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 | -| `--oracle-resolver` | JSON RPC url to solve oracle calls | -| `-h, --help` | Print help | - -_Usage_ - -The inputs to the circuit are read from the `Prover.toml` file generated by `nargo check`, which -must be filled in. - -To save the witness to file, run the command with a value for the `WITNESS_NAME` argument. A -`.tr` file will then be saved in the `./target` folder. - -## `nargo prove` - -Creates a proof for the program. - -### Options - -| 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 | -| `--oracle-resolver` | JSON RPC url to solve oracle calls | -| `-h, --help` | Print help | - -## `nargo verify` - -Given a proof and a program, verify whether the proof is valid. - -### Options - -| 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]` - -Nargo will automatically compile and run any functions which have the decorator `#[test]` on them if -you run `nargo test`. To print `println` statements in tests, use the `--show-output` flag. - -Takes an optional `--exact` flag which allows you to select tests based on an exact name. - -See an example on the [testing page](../getting_started/tooling/testing.md). - -### Options - -| 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 | -| `--oracle-resolver` | JSON RPC url to solve oracle calls | -| `-h, --help` | Print help | - -## `nargo info` - -Prints a table containing the information of the package. - -Currently the table provide - -1. The number of ACIR opcodes -2. The final number gates in the circuit used by a backend - -If the file contains a contract the table will provide the -above information about each function of the contract. - -## `nargo lsp` - -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/noir/docs/docs/tutorials/noirjs_app.md b/noir/docs/docs/tutorials/noirjs_app.md index 23534795dde..ad76dd255cc 100644 --- a/noir/docs/docs/tutorials/noirjs_app.md +++ b/noir/docs/docs/tutorials/noirjs_app.md @@ -101,7 +101,7 @@ At this point in the tutorial, your folder structure should look like this: `npx create vite` is amazing but it creates a bunch of files we don't really need for our simple example. Actually, let's just delete everything except for `index.html`, `main.js` and `package.json`. I feel lighter already. -![my heart is ready for you, noir.js](../../static/img/memes/titanic.jpeg) +![my heart is ready for you, noir.js](@site/static/img/memes/titanic.jpeg) ## HTML @@ -270,7 +270,7 @@ if (verification) display('logs', 'Verifying proof... ✅'); You have successfully generated a client-side Noir web app! -![coded app without math knowledge](../../static/img/memes/flextape.jpeg) +![coded app without math knowledge](@site/static/img/memes/flextape.jpeg) ## Further Reading diff --git a/noir/docs/docusaurus.config.ts b/noir/docs/docusaurus.config.ts index d1d344ba635..e041d0a32a4 100644 --- a/noir/docs/docusaurus.config.ts +++ b/noir/docs/docusaurus.config.ts @@ -26,7 +26,7 @@ export default { '@docusaurus/preset-classic', { docs: { - path: "processed-docs", + path: 'processed-docs', sidebarPath: './sidebars.js', routeBasePath: '/docs', remarkPlugins: [math], @@ -210,6 +210,37 @@ export default { membersWithOwnFile: ['Interface', 'Class', 'TypeAlias'], }, ], + [ + 'docusaurus-plugin-typedoc', + { + id: 'noir_wasm', + entryPoints: ['../compiler/wasm/src/index.cts'], + tsconfig: '../compiler/wasm/tsconfig.json', + entryPointStrategy: 'resolve', + out: 'processed-docs/reference/NoirJS/noir_wasm', + plugin: ['typedoc-plugin-markdown'], + name: 'noir_wasm', + disableSources: true, + excludePrivate: true, + skipErrorChecking: true, + sidebar: { + filteredIds: ['reference/noir_wasm/index'], + }, + readme: 'none', + hidePageHeader: true, + hideBreadcrumbs: true, + hideInPageTOC: true, + useCodeBlocks: true, + typeDeclarationFormat: 'table', + propertiesFormat: 'table', + parametersFormat: 'table', + enumMembersFormat: 'table', + indexFormat: 'table', + outputFileStrategy: 'members', + memberPageTitle: '{name}', + membersWithOwnFile: ['Function', 'TypeAlias'], + }, + ], ], markdown: { format: 'detect', diff --git a/noir/docs/package.json b/noir/docs/package.json index 71b624ff565..146c2a9800c 100644 --- a/noir/docs/package.json +++ b/noir/docs/package.json @@ -3,7 +3,7 @@ "version": "0.0.0", "private": true, "scripts": { - "preprocess": "yarn node ./scripts/preprocess/index.js", + "preprocess": "./scripts/codegen_nargo_reference.sh && yarn node ./scripts/preprocess/index.js", "start": "yarn preprocess && docusaurus start", "build": "yarn preprocess && yarn version::stables && docusaurus build", "version::stables": "ts-node ./scripts/setStable.ts", @@ -18,7 +18,6 @@ "@noir-lang/noir_js": "workspace:*", "@noir-lang/noirc_abi": "workspace:*", "@noir-lang/types": "workspace:*", - "@signorecello/noir_playground": "^0.7.0", "axios": "^1.4.0", "clsx": "^1.2.1", "hast-util-is-element": "^1.1.0", diff --git a/noir/docs/scripts/codegen_nargo_reference.sh b/noir/docs/scripts/codegen_nargo_reference.sh new file mode 100755 index 00000000000..4ff7d43d142 --- /dev/null +++ b/noir/docs/scripts/codegen_nargo_reference.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +set -eu + +cd $(dirname "$0")/.. + +REFERENCE_DIR="./processed-docs/reference" +NARGO_REFERENCE="$REFERENCE_DIR/nargo_commands.md" +rm -f $NARGO_REFERENCE +mkdir -p $REFERENCE_DIR + +echo "--- +title: Nargo +description: + Noir CLI Commands for Noir Prover and Verifier to create, execute, prove and verify programs, + generate Solidity verifier smart contract and compile into JSON file containing ACIR + representation and ABI of circuit. +keywords: + [ + Nargo, + Noir CLI, + Noir Prover, + Noir Verifier, + generate Solidity verifier, + compile JSON file, + ACIR representation, + ABI of circuit, + TypeScript, + ] +sidebar_position: 0 +--- +" > $NARGO_REFERENCE + +cargo run -F codegen-docs -- info >> $NARGO_REFERENCE diff --git a/noir/docs/src/css/custom.css b/noir/docs/src/css/custom.css index 5a526ec5bfd..b08766fbc3b 100644 --- a/noir/docs/src/css/custom.css +++ b/noir/docs/src/css/custom.css @@ -209,3 +209,8 @@ html[data-theme='dark'] { border-width: 0; border-style: solid; } + +input#docsearch-input { + background-color: transparent; +} + diff --git a/noir/docs/src/pages/index.jsx b/noir/docs/src/pages/index.jsx index 6b52628a5ff..b372871e7b4 100644 --- a/noir/docs/src/pages/index.jsx +++ b/noir/docs/src/pages/index.jsx @@ -5,19 +5,7 @@ import Link from '@docusaurus/Link'; import headerPic from '@site/static/img/homepage_header_pic.png'; import { BeatLoader } from 'react-spinners'; -const NoirEditor = lazy(() => import('@signorecello/noir_playground')); - -const Spinner = () => { - return ( -
- -
- ); -}; - export default function Landing() { - const [tryIt, setTryIt] = React.useState(false); - return (
@@ -41,65 +29,46 @@ export default function Landing() { compatible proving system. Its design choices are influenced heavily by Rust and focuses on a simple, familiar syntax.

- {!tryIt && ( -
-
- - - - - - -
-
- )} - {tryIt && ( - }> + +
+
- - - )} +
+
- {!tryIt && ( -
-
-

Learn

- - - - - - -
-
-

Coming from...

- - - - - - -
-
-

New to Everything

- - - - - - -
+
+
+

Learn

+ + + + + + +
+
+

Coming from...

+ + + + + + +
+
+

New to Everything

+ + + + + +
- )} +
diff --git a/noir/docs/versioned_docs/version-v0.22.0/how_to/solidity_verifier.md b/noir/docs/versioned_docs/version-v0.22.0/how_to/solidity_verifier.md index 8022b0e5f20..6aaad542ee0 100644 --- a/noir/docs/versioned_docs/version-v0.22.0/how_to/solidity_verifier.md +++ b/noir/docs/versioned_docs/version-v0.22.0/how_to/solidity_verifier.md @@ -120,6 +120,7 @@ You can currently deploy the Solidity verifier contracts to most EVM compatible - Polygon PoS - Scroll - Celo +- Taiko Other EVM chains should work, but have not been tested directly by our team. If you test any other chains, please open a PR on this page to update the list. See [this doc](https://github.com/noir-lang/noir-starter/tree/main/with-foundry#testing-on-chain) for more info about testing verifier contracts on different EVM chains. diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/fields.md b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/fields.md index a1c67945d66..99b4aa63549 100644 --- a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/fields.md +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/fields.md @@ -157,6 +157,23 @@ fn main() { } ``` +### assert_max_bit_size + +Adds a constraint to specify that the field can be represented with `bit_size` number of bits + +```rust +fn assert_max_bit_size(self, bit_size: u32) +``` + +example: + +```rust +fn main() { + let field = 2 + field.assert_max_bit_size(32); +} +``` + ### sgn0 Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x ∈ \{0, ..., p-1\} is even, otherwise sgn0(x mod p) = 1. @@ -164,3 +181,12 @@ Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x ∈ \{0, ..., p-1\} ```rust fn sgn0(self) -> u1 ``` + + +### lt + +Returns true if the field is less than the other field + +```rust +pub fn lt(self, another: Field) -> bool +``` diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/integers.md b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/integers.md index 7d1e83cf4e9..30135d76e4a 100644 --- a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/integers.md +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/integers.md @@ -51,6 +51,55 @@ If you are using the default proving backend with Noir, both even (e.g. _u2_, _i ::: + +## 128 bits Unsigned Integers + +The built-in structure `U128` allows you to use 128-bit unsigned integers almost like a native integer type. However, there are some differences to keep in mind: +- You cannot cast between a native integer and `U128` +- There is a higher performance cost when using `U128`, compared to a native type. + +Conversion between unsigned integer types and U128 are done through the use of `from_integer` and `to_integer` functions. + +```rust +fn main() { + let x = U128::from_integer(23); + let y = U128::from_hex("0x7"); + let z = x + y; + assert(z.to_integer() == 30); +} +``` + +`U128` is implemented with two 64 bits limbs, representing the low and high bits, which explains the performance cost. You should expect `U128` to be twice more costly for addition and four times more costly for multiplication. +You can construct a U128 from its limbs: +```rust +fn main(x: u64, y: u64) { + let x = U128::from_u64s_be(x,y); + assert(z.hi == x as Field); + assert(z.lo == y as Field); +} +``` + +Note that the limbs are stored as Field elements in order to avoid unnecessary conversions. +Apart from this, most operations will work as usual: + +```rust +fn main(x: U128, y: U128) { + // multiplication + let c = x * y; + // addition and subtraction + let c = c - x + y; + // division + let c = x / y; + // bit operation; + let c = x & y | y; + // bit shift + let c = x << y; + // comparisons; + let c = x < y; + let c = x == y; +} +``` + ## Overflows Computations that exceed the type boundaries will result in overflow errors. This happens with both signed and unsigned integers. For example, attempting to prove: @@ -108,6 +157,6 @@ Example of how it is used: use dep::std; fn main(x: u8, y: u8) -> pub u8 { - std::wrapping_add(x + y) + std::wrapping_add(x, y) } ``` diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/black_box_fns.md b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/black_box_fns.md index 4b1efbd17de..eae8744abf0 100644 --- a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/black_box_fns.md +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/black_box_fns.md @@ -6,40 +6,26 @@ keywords: [noir, black box functions] Black box functions are functions in Noir that rely on backends implementing support for specialized constraints. This makes certain zk-snark unfriendly computations cheaper than if they were implemented in Noir. -:::warning - -It is likely that not all backends will support a particular black box function. - -::: - -Because it is not guaranteed that all backends will support black box functions, it is possible that certain Noir programs won't compile against a particular backend if they use an unsupported black box function. It is possible to fallback to less efficient implementations written in Noir/ACIR in some cases. - -Black box functions are specified with the `#[foreign(black_box_fn)]` attribute. For example, the SHA256 function in the Noir [source code](https://github.com/noir-lang/noir/blob/v0.5.1/noir_stdlib/src/hash.nr) looks like: - -```rust -#[foreign(sha256)] -fn sha256(_input : [u8; N]) -> [u8; 32] {} -``` +The ACVM spec defines a set of blackbox functions which backends will be expected to implement. This allows backends to use optimized implementations of these constraints if they have them, however they may also fallback to less efficient naive implementations if not. ## Function list -Here is a list of the current black box functions that are supported by UltraPlonk: +Here is a list of the current black box functions: -- AES - [SHA256](./cryptographic_primitives/hashes#sha256) - [Schnorr signature verification](./cryptographic_primitives/schnorr) - [Blake2s](./cryptographic_primitives/hashes#blake2s) +- [Blake3](./cryptographic_primitives/hashes#blake3) - [Pedersen Hash](./cryptographic_primitives/hashes#pedersen_hash) - [Pedersen Commitment](./cryptographic_primitives/hashes#pedersen_commitment) - [ECDSA signature verification](./cryptographic_primitives/ecdsa_sig_verification) - [Fixed base scalar multiplication](./cryptographic_primitives/scalar) -- [Compute merkle root](./merkle_trees#compute_merkle_root) - AND - XOR - RANGE - [Keccak256](./cryptographic_primitives/hashes#keccak256) - [Recursive proof verification](./recursion) -Most black box functions are included as part of the Noir standard library, however `AND`, `XOR` and `RANGE` are used as part of the Noir language syntax. For instance, using the bitwise operator `&` will invoke the `AND` black box function. To ensure compatibility across backends, the ACVM has fallback implementations of `AND`, `XOR` and `RANGE` defined in its standard library which it can seamlessly fallback to if the backend doesn't support them. +Most black box functions are included as part of the Noir standard library, however `AND`, `XOR` and `RANGE` are used as part of the Noir language syntax. For instance, using the bitwise operator `&` will invoke the `AND` black box function. You can view the black box functions defined in the ACVM code [here](https://github.com/noir-lang/noir/blob/master/acvm-repo/acir/src/circuit/black_box_functions.rs). diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/bn254.md b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/bn254.md new file mode 100644 index 00000000000..3294f005dbb --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/bn254.md @@ -0,0 +1,46 @@ +--- +title: Bn254 Field Library +--- + +Noir provides a module in standard library with some optimized functions for bn254 Fr in `std::field::bn254`. + +## decompose + +```rust +fn decompose(x: Field) -> (Field, Field) {} +``` + +Decomposes a single field into two fields, low and high. The low field contains the lower 16 bytes of the input field and the high field contains the upper 16 bytes of the input field. Both field results are range checked to 128 bits. + + +## assert_gt + +```rust +fn assert_gt(a: Field, b: Field) {} +``` + +Asserts that a > b. This will generate less constraints than using `assert(gt(a, b))`. + +## assert_lt + +```rust +fn assert_lt(a: Field, b: Field) {} +``` + +Asserts that a < b. This will generate less constraints than using `assert(lt(a, b))`. + +## gt + +```rust +fn gt(a: Field, b: Field) -> bool {} +``` + +Returns true if a > b. + +## lt + +```rust +fn lt(a: Field, b: Field) -> bool {} +``` + +Returns true if a < b. \ No newline at end of file diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx index 1376c51dfde..4bf09cef178 100644 --- a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx @@ -13,9 +13,16 @@ Noir supports ECDSA signatures verification over the secp256k1 and secp256r1 cur Verifier for ECDSA Secp256k1 signatures -```rust -fn verify_signature(_public_key_x : [u8; 32], _public_key_y : [u8; 32], _signature: [u8; 64], _message: [u8]) -> bool +```rust title="ecdsa_secp256k1" showLineNumbers +pub fn verify_signature( + public_key_x: [u8; 32], + public_key_y: [u8; 32], + signature: [u8; 64], + message_hash: [u8; N] +) -> bool ``` +> Source code: noir_stdlib/src/ecdsa_secp256k1.nr#L2-L9 + example: @@ -30,9 +37,16 @@ fn main(hashed_message : [u8;32], pub_key_x : [u8;32], pub_key_y : [u8;32], sign Verifier for ECDSA Secp256r1 signatures -```rust -fn verify_signature(_public_key_x : [u8; 32], _public_key_y : [u8; 32], _signature: [u8; 64], _message: [u8]) -> bool +```rust title="ecdsa_secp256r1" showLineNumbers +pub fn verify_signature( + public_key_x: [u8; 32], + public_key_y: [u8; 32], + signature: [u8; 64], + message_hash: [u8; N] +) -> bool ``` +> Source code: noir_stdlib/src/ecdsa_secp256r1.nr#L2-L9 + example: diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/hashes.mdx b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/hashes.mdx index 3c5f7f79603..730b6d4117f 100644 --- a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/hashes.mdx +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/hashes.mdx @@ -14,9 +14,11 @@ import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; Given an array of bytes, returns the resulting sha256 hash. -```rust -fn sha256(_input : [u8]) -> [u8; 32] +```rust title="sha256" showLineNumbers +pub fn sha256(input: [u8; N]) -> [u8; 32] ``` +> Source code: noir_stdlib/src/hash.nr#L5-L7 + example: @@ -33,9 +35,11 @@ fn main() { Given an array of bytes, returns an array with the Blake2 hash -```rust -fn blake2s(_input : [u8]) -> [u8; 32] +```rust title="blake2s" showLineNumbers +pub fn blake2s(input: [u8; N]) -> [u8; 32] ``` +> Source code: noir_stdlib/src/hash.nr#L11-L13 + example: @@ -48,43 +52,81 @@ fn main() { -## pedersen_hash +## blake3 -Given an array of Fields, returns the Pedersen hash. +Given an array of bytes, returns an array with the Blake3 hash -```rust -fn pedersen_hash(_input : [Field]) -> Field +```rust title="blake3" showLineNumbers +pub fn blake3(input: [u8; N]) -> [u8; 32] ``` +> Source code: noir_stdlib/src/hash.nr#L17-L19 + example: ```rust fn main() { let x = [163, 117, 178, 149]; // some random bytes - let hash = std::hash::pedersen_hash(x); + let hash = std::hash::blake3(x); } ``` +## pedersen_hash + +Given an array of Fields, returns the Pedersen hash. + +```rust title="pedersen_hash" showLineNumbers +pub fn pedersen_hash(input: [Field; N]) -> Field +``` +> Source code: noir_stdlib/src/hash.nr#L42-L44 + + +example: + +```rust title="pedersen-hash" showLineNumbers +use dep::std; + +fn main(x: Field, y: Field, expected_hash: Field) { + let hash = std::hash::pedersen_hash([x, y]); + assert_eq(hash, expected_hash); +} +``` +> Source code: test_programs/execution_success/pedersen_hash/src/main.nr#L1-L8 + + + ## pedersen_commitment Given an array of Fields, returns the Pedersen commitment. -```rust -fn pedersen_commitment(_input : [Field]) -> [Field; 2] +```rust title="pedersen_commitment" showLineNumbers +struct PedersenPoint { + x : Field, + y : Field, +} + +pub fn pedersen_commitment(input: [Field; N]) -> PedersenPoint ``` +> Source code: noir_stdlib/src/hash.nr#L22-L29 + example: -```rust -fn main() { - let x = [163, 117, 178, 149]; // some random bytes - let commitment = std::hash::pedersen_commitment(x); +```rust title="pedersen-commitment" showLineNumbers +use dep::std; + +fn main(x: Field, y: Field, expected_commitment: std::hash::PedersenPoint) { + let commitment = std::hash::pedersen_commitment([x, y]); + assert_eq(commitment.x, expected_commitment.x); + assert_eq(commitment.y, expected_commitment.y); } ``` +> Source code: test_programs/execution_success/pedersen_commitment/src/main.nr#L1-L9 + @@ -94,19 +136,38 @@ Given an array of bytes (`u8`), returns the resulting keccak hash as an array of (`[u8; 32]`). Specify a message_size to hash only the first `message_size` bytes of the input. -```rust -fn keccak256(_input : [u8; N], _message_size: u32) -> [u8; 32] +```rust title="keccak256" showLineNumbers +pub fn keccak256(input: [u8; N], message_size: u32) -> [u8; 32] ``` +> Source code: noir_stdlib/src/hash.nr#L67-L69 + example: -```rust -fn main() { - let x = [163, 117, 178, 149]; // some random bytes +```rust title="keccak256" showLineNumbers +use dep::std; + +fn main(x: Field, result: [u8; 32]) { + // We use the `as` keyword here to denote the fact that we want to take just the first byte from the x Field + // The padding is taken care of by the program + let digest = std::hash::keccak256([x as u8], 1); + assert(digest == result); + + //#1399: variable message size let message_size = 4; - let hash = std::hash::keccak256(x, message_size); + let hash_a = std::hash::keccak256([1, 2, 3, 4], message_size); + let hash_b = std::hash::keccak256([1, 2, 3, 4, 0, 0, 0, 0], message_size); + + assert(hash_a == hash_b); + + let message_size_big = 8; + let hash_c = std::hash::keccak256([1, 2, 3, 4, 0, 0, 0, 0], message_size_big); + + assert(hash_a != hash_c); } ``` +> Source code: test_programs/execution_success/keccak256/src/main.nr#L1-L22 + @@ -122,13 +183,19 @@ fn hash_1(input: [Field; 1]) -> Field example: -```rust -fn main() -{ - let hash_2 = std::hash::poseidon::bn254::hash_2([1, 2]); - assert(hash2 == 0x115cc0f5e7d690413df64c6b9662e9cf2a3617f2743245519e19607a4417189a); +```rust title="poseidon" showLineNumbers +use dep::std::hash::poseidon; + +fn main(x1: [Field; 2], y1: pub Field, x2: [Field; 4], y2: pub Field) { + let hash1 = poseidon::bn254::hash_2(x1); + assert(hash1 == y1); + + let hash2 = poseidon::bn254::hash_4(x2); + assert(hash2 == y2); } ``` +> Source code: test_programs/execution_success/poseidon_bn254_hash/src/main.nr#L1-L11 + ## mimc_bn254 and mimc diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/scalar.mdx b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/scalar.mdx index aa4fb8cbaed..df411ca5443 100644 --- a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/scalar.mdx +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/scalar.mdx @@ -12,9 +12,14 @@ import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; Performs scalar multiplication over the embedded curve whose coordinates are defined by the configured noir field. For the BN254 scalar field, this is BabyJubJub or Grumpkin. -```rust -fn fixed_base_embedded_curve(_input : Field) -> [Field; 2] +```rust title="fixed_base_embedded_curve" showLineNumbers +pub fn fixed_base_embedded_curve( + low: Field, + high: Field +) -> [Field; 2] ``` +> Source code: noir_stdlib/src/scalar_mul.nr#L27-L32 + example diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/schnorr.mdx b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/schnorr.mdx index 7a2c9c20226..ae12e6c12dc 100644 --- a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/schnorr.mdx +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/schnorr.mdx @@ -11,9 +11,16 @@ import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; Verifier for Schnorr signatures over the embedded curve (for BN254 it is Grumpkin). -```rust -fn verify_signature(_public_key_x: Field, _public_key_y: Field, _signature: [u8; 64], _message: [u8]) -> bool +```rust title="schnorr_verify" showLineNumbers +pub fn verify_signature( + public_key_x: Field, + public_key_y: Field, + signature: [u8; 64], + message: [u8; N] +) -> bool ``` +> Source code: noir_stdlib/src/schnorr.nr#L2-L9 + where `_signature` can be generated like so using the npm package [@noir-lang/barretenberg](https://www.npmjs.com/package/@noir-lang/barretenberg) diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/.nojekyll b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/.nojekyll new file mode 100644 index 00000000000..e2ac6616add --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/.nojekyll @@ -0,0 +1 @@ +TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. \ No newline at end of file diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/compile.md b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/compile.md new file mode 100644 index 00000000000..33eb434c3db --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/compile.md @@ -0,0 +1,51 @@ +# compile() + +```ts +compile( + fileManager, + projectPath?, + logFn?, +debugLogFn?): Promise +``` + +Compiles a Noir project + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `fileManager` | `FileManager` | The file manager to use | +| `projectPath`? | `string` | The path to the project inside the file manager. Defaults to the root of the file manager | +| `logFn`? | `LogFn` | A logging function. If not provided, console.log will be used | +| `debugLogFn`? | `LogFn` | A debug logging function. If not provided, logFn will be used | + +## Returns + +`Promise`\<[`CompilationResult`](../type-aliases/CompilationResult.md)\> + +## Example + +```typescript +// Node.js + +import { compile, createFileManager } from '@noir-lang/noir_wasm'; + +const fm = createFileManager(myProjectPath); +const myCompiledCode = await compile(fm); +``` + +```typescript +// Browser + +import { compile, createFileManager } from '@noir-lang/noir_wasm'; + +const fm = createFileManager('/'); +for (const path of files) { + await fm.writeFile(path, await getFileAsStream(path)); +} +const myCompiledCode = await compile(fm); +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/createFileManager.md b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/createFileManager.md new file mode 100644 index 00000000000..7e65c1d69c7 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/createFileManager.md @@ -0,0 +1,21 @@ +# createFileManager() + +```ts +createFileManager(dataDir): FileManager +``` + +Creates a new FileManager instance based on fs in node and memfs in the browser (via webpack alias) + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `dataDir` | `string` | root of the file system | + +## Returns + +`FileManager` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/inflateDebugSymbols.md b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/inflateDebugSymbols.md new file mode 100644 index 00000000000..fcea9275341 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/inflateDebugSymbols.md @@ -0,0 +1,21 @@ +# inflateDebugSymbols() + +```ts +inflateDebugSymbols(debugSymbols): any +``` + +Decompresses and decodes the debug symbols + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `debugSymbols` | `string` | The base64 encoded debug symbols | + +## Returns + +`any` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/index.md b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/index.md new file mode 100644 index 00000000000..939f2481687 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/index.md @@ -0,0 +1,21 @@ +# noir_wasm + +## Exports + +### Type Aliases + +| Type alias | Description | +| :------ | :------ | +| [CompilationResult](type-aliases/CompilationResult.md) | output of Noir Wasm compilation, can be for a contract or lib/binary | + +### Functions + +| Function | Description | +| :------ | :------ | +| [compile](functions/compile.md) | Compiles a Noir project | +| [createFileManager](functions/createFileManager.md) | Creates a new FileManager instance based on fs in node and memfs in the browser (via webpack alias) | +| [inflateDebugSymbols](functions/inflateDebugSymbols.md) | Decompresses and decodes the debug symbols | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/type-aliases/CompilationResult.md b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/type-aliases/CompilationResult.md new file mode 100644 index 00000000000..23cfbe6025d --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/type-aliases/CompilationResult.md @@ -0,0 +1,11 @@ +# CompilationResult + +```ts +type CompilationResult: ContractCompilationArtifacts | ProgramCompilationArtifacts; +``` + +output of Noir Wasm compilation, can be for a contract or lib/binary + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/typedoc-sidebar.cjs b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/typedoc-sidebar.cjs new file mode 100644 index 00000000000..d7eba0db813 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/typedoc-sidebar.cjs @@ -0,0 +1,4 @@ +// @ts-check +/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ +const typedocSidebar = { items: [{"type":"doc","id":"reference/NoirJS/noir_wasm/index","label":"API"},{"type":"category","label":"Type Aliases","items":[{"type":"doc","id":"reference/NoirJS/noir_wasm/type-aliases/CompilationResult","label":"CompilationResult"}]},{"type":"category","label":"Functions","items":[{"type":"doc","id":"reference/NoirJS/noir_wasm/functions/compile","label":"compile"},{"type":"doc","id":"reference/NoirJS/noir_wasm/functions/createFileManager","label":"createFileManager"},{"type":"doc","id":"reference/NoirJS/noir_wasm/functions/inflateDebugSymbols","label":"inflateDebugSymbols"}]}]}; +module.exports = typedocSidebar.items; \ No newline at end of file diff --git a/noir/docs/versioned_docs/version-v0.23.0/tutorials/noirjs_app.md b/noir/docs/versioned_docs/version-v0.23.0/tutorials/noirjs_app.md index 23534795dde..ad76dd255cc 100644 --- a/noir/docs/versioned_docs/version-v0.23.0/tutorials/noirjs_app.md +++ b/noir/docs/versioned_docs/version-v0.23.0/tutorials/noirjs_app.md @@ -101,7 +101,7 @@ At this point in the tutorial, your folder structure should look like this: `npx create vite` is amazing but it creates a bunch of files we don't really need for our simple example. Actually, let's just delete everything except for `index.html`, `main.js` and `package.json`. I feel lighter already. -![my heart is ready for you, noir.js](../../static/img/memes/titanic.jpeg) +![my heart is ready for you, noir.js](@site/static/img/memes/titanic.jpeg) ## HTML @@ -270,7 +270,7 @@ if (verification) display('logs', 'Verifying proof... ✅'); You have successfully generated a client-side Noir web app! -![coded app without math knowledge](../../static/img/memes/flextape.jpeg) +![coded app without math knowledge](@site/static/img/memes/flextape.jpeg) ## Further Reading diff --git a/noir/noir_stdlib/src/array.nr b/noir/noir_stdlib/src/array.nr index 87cf4167dac..995af6c4c6f 100644 --- a/noir/noir_stdlib/src/array.nr +++ b/noir/noir_stdlib/src/array.nr @@ -1,3 +1,4 @@ +use crate::cmp::{Ord}; // TODO: Once we fully move to the new SSA pass this module can be removed and replaced // by the methods in the `slice` module @@ -5,23 +6,53 @@ impl [T; N] { #[builtin(array_len)] pub fn len(self) -> Field {} - #[builtin(arraysort)] - pub fn sort(self) -> Self {} + pub fn sort(self) -> Self where T: Ord { + self.sort_via(|a, b| a <= b) + } + + pub fn sort_via(self, ordering: fn[Env](T, T) -> bool) -> Self { + let sorted_index = self.get_sorting_index(ordering); + let mut result = self; + // Ensure the indexes are correct + for i in 0..N { + let pos = find_index(sorted_index, i); + assert(sorted_index[pos] == i); + } + // Sort the array using the indexes + for i in 0..N { + result[i] = self[sorted_index[i]]; + } + // Ensure the array is sorted + for i in 0..N-1 { + assert(ordering(result[i], result[i+1])); + } + + result + } - // Sort with a custom sorting function. - pub fn sort_via(mut a: Self, ordering: fn[Env](T, T) -> bool) -> Self { - for i in 1 .. a.len() { + /// Returns the index of the elements in the array that would sort it, using the provided custom sorting function. + unconstrained fn get_sorting_index(self, ordering: fn[Env](T, T) -> bool) -> [Field; N] { + let mut result = [0;N]; + let mut a = self; + for i in 0..N { + result[i] = i; + } + for i in 1 .. N { for j in 0..i { if ordering(a[i], a[j]) { let old_a_j = a[j]; a[j] = a[i]; a[i] = old_a_j; + let old_j = result[j]; + result[j] = result[i]; + result[i] = old_j; } } } - a + result } + // Converts an array into a slice. pub fn as_slice(self) -> [T] { let mut slice = []; @@ -83,3 +114,15 @@ impl [T; N] { ret } } + +// helper function used to look up the position of a value in an array of Field +// Note that function returns 0 if the value is not found +unconstrained fn find_index(a: [Field;N], find: Field) -> Field { + let mut result = 0; + for i in 0..a.len() { + if a[i] == find { + result = i; + } + } + result +} \ No newline at end of file diff --git a/noir/noir_stdlib/src/cmp.nr b/noir/noir_stdlib/src/cmp.nr index b3de3e2658e..38316e5d6a8 100644 --- a/noir/noir_stdlib/src/cmp.nr +++ b/noir/noir_stdlib/src/cmp.nr @@ -8,12 +8,10 @@ impl Eq for Field { fn eq(self, other: Field) -> bool { self == other } } impl Eq for u1 { fn eq(self, other: u1) -> bool { self == other } } impl Eq for u8 { fn eq(self, other: u8) -> bool { self == other } } -impl Eq for u16 { fn eq(self, other: u16) -> bool { self == other } } impl Eq for u32 { fn eq(self, other: u32) -> bool { self == other } } impl Eq for u64 { fn eq(self, other: u64) -> bool { self == other } } impl Eq for i8 { fn eq(self, other: i8) -> bool { self == other } } -impl Eq for i16 { fn eq(self, other: i16) -> bool { self == other } } impl Eq for i32 { fn eq(self, other: i32) -> bool { self == other } } impl Eq for i64 { fn eq(self, other: i64) -> bool { self == other } } @@ -111,18 +109,6 @@ impl Ord for u8 { } } -impl Ord for u16 { - fn cmp(self, other: u16) -> Ordering { - if self < other { - Ordering::less() - } else if self > other { - Ordering::greater() - } else { - Ordering::equal() - } - } -} - impl Ord for u32 { fn cmp(self, other: u32) -> Ordering { if self < other { @@ -159,18 +145,6 @@ impl Ord for i8 { } } -impl Ord for i16 { - fn cmp(self, other: i16) -> Ordering { - if self < other { - Ordering::less() - } else if self > other { - Ordering::greater() - } else { - Ordering::equal() - } - } -} - impl Ord for i32 { fn cmp(self, other: i32) -> Ordering { if self < other { diff --git a/noir/noir_stdlib/src/convert.nr b/noir/noir_stdlib/src/convert.nr index 814f63f1cde..00ac0a0fd8c 100644 --- a/noir/noir_stdlib/src/convert.nr +++ b/noir/noir_stdlib/src/convert.nr @@ -24,37 +24,28 @@ impl Into for U where T: From { // docs:start:from-impls // Unsigned integers -impl From for u16 { fn from(value: u8) -> u16 { value as u16 } } impl From for u32 { fn from(value: u8) -> u32 { value as u32 } } -impl From for u32 { fn from(value: u16) -> u32 { value as u32 } } impl From for u64 { fn from(value: u8) -> u64 { value as u64 } } -impl From for u64 { fn from(value: u16) -> u64 { value as u64 } } impl From for u64 { fn from(value: u32) -> u64 { value as u64 } } impl From for Field { fn from(value: u8) -> Field { value as Field } } -impl From for Field { fn from(value: u16) -> Field { value as Field } } impl From for Field { fn from(value: u32) -> Field { value as Field } } impl From for Field { fn from(value: u64) -> Field { value as Field } } // Signed integers -impl From for i16 { fn from(value: i8) -> i16 { value as i16 } } impl From for i32 { fn from(value: i8) -> i32 { value as i32 } } -impl From for i32 { fn from(value: i16) -> i32 { value as i32 } } impl From for i64 { fn from(value: i8) -> i64 { value as i64 } } -impl From for i64 { fn from(value: i16) -> i64 { value as i64 } } impl From for i64 { fn from(value: i32) -> i64 { value as i64 } } // Booleans impl From for u8 { fn from(value: bool) -> u8 { value as u8 } } -impl From for u16 { fn from(value: bool) -> u16 { value as u16 } } impl From for u32 { fn from(value: bool) -> u32 { value as u32 } } impl From for u64 { fn from(value: bool) -> u64 { value as u64 } } impl From for i8 { fn from(value: bool) -> i8 { value as i8 } } -impl From for i16 { fn from(value: bool) -> i16 { value as i16 } } impl From for i32 { fn from(value: bool) -> i32 { value as i32 } } impl From for i64 { fn from(value: bool) -> i64 { value as i64 } } impl From for Field { fn from(value: bool) -> Field { value as Field } } diff --git a/noir/noir_stdlib/src/default.nr b/noir/noir_stdlib/src/default.nr index ba6412a834f..32c4f3f3b48 100644 --- a/noir/noir_stdlib/src/default.nr +++ b/noir/noir_stdlib/src/default.nr @@ -7,12 +7,10 @@ trait Default { impl Default for Field { fn default() -> Field { 0 } } impl Default for u8 { fn default() -> u8 { 0 } } -impl Default for u16 { fn default() -> u16 { 0 } } impl Default for u32 { fn default() -> u32 { 0 } } impl Default for u64 { fn default() -> u64 { 0 } } impl Default for i8 { fn default() -> i8 { 0 } } -impl Default for i16 { fn default() -> i16 { 0 } } impl Default for i32 { fn default() -> i32 { 0 } } impl Default for i64 { fn default() -> i64 { 0 } } diff --git a/noir/noir_stdlib/src/field/bn254.nr b/noir/noir_stdlib/src/field/bn254.nr index f6e23f8db0c..9e1445fd3ba 100644 --- a/noir/noir_stdlib/src/field/bn254.nr +++ b/noir/noir_stdlib/src/field/bn254.nr @@ -1,7 +1,10 @@ +// The low and high decomposition of the field modulus global PLO: Field = 53438638232309528389504892708671455233; global PHI: Field = 64323764613183177041862057485226039389; + global TWO_POW_128: Field = 0x100000000000000000000000000000000; +/// A hint for decomposing a single field into two 16 byte fields. unconstrained fn decompose_unsafe(x: Field) -> (Field, Field) { let x_bytes = x.to_le_bytes(32); @@ -18,14 +21,20 @@ unconstrained fn decompose_unsafe(x: Field) -> (Field, Field) { (low, high) } +/// Decompose a single field into two 16 byte fields. pub fn decompose(x: Field) -> (Field, Field) { + // Take hints of the decomposition let (xlo, xhi) = decompose_unsafe(x); let borrow = lt_unsafe(PLO, xlo, 16); + // Range check the limbs xlo.assert_max_bit_size(128); xhi.assert_max_bit_size(128); + // Check that the decomposition is correct assert_eq(x, xlo + TWO_POW_128 * xhi); + + // Check that (xlo < plo && xhi <= phi) || (xlo >= plo && xhi < phi) let rlo = PLO - xlo + (borrow as Field) * TWO_POW_128; let rhi = PHI - xhi - (borrow as Field); @@ -59,11 +68,13 @@ unconstrained fn lte_unsafe(x: Field, y: Field, num_bytes: u32) -> bool { } pub fn assert_gt(a: Field, b: Field) { + // Decompose a and b let (alo, ahi) = decompose(a); let (blo, bhi) = decompose(b); let borrow = lte_unsafe(alo, blo, 16); + // Assert that (alo > blo && ahi >= bhi) || (alo <= blo && ahi > bhi) let rlo = alo - blo - 1 + (borrow as Field) * TWO_POW_128; let rhi = ahi - bhi - (borrow as Field); diff --git a/noir/noir_stdlib/src/ops.nr b/noir/noir_stdlib/src/ops.nr index 50386290b8e..e561265629e 100644 --- a/noir/noir_stdlib/src/ops.nr +++ b/noir/noir_stdlib/src/ops.nr @@ -7,12 +7,10 @@ trait Add { impl Add for Field { fn add(self, other: Field) -> Field { self + other } } impl Add for u8 { fn add(self, other: u8) -> u8 { self + other } } -impl Add for u16 { fn add(self, other: u16) -> u16 { self + other } } impl Add for u32 { fn add(self, other: u32) -> u32 { self + other } } impl Add for u64 { fn add(self, other: u64) -> u64 { self + other } } impl Add for i8 { fn add(self, other: i8) -> i8 { self + other } } -impl Add for i16 { fn add(self, other: i16) -> i16 { self + other } } impl Add for i32 { fn add(self, other: i32) -> i32 { self + other } } impl Add for i64 { fn add(self, other: i64) -> i64 { self + other } } @@ -25,12 +23,10 @@ trait Sub { impl Sub for Field { fn sub(self, other: Field) -> Field { self - other } } impl Sub for u8 { fn sub(self, other: u8) -> u8 { self - other } } -impl Sub for u16 { fn sub(self, other: u16) -> u16 { self - other } } impl Sub for u32 { fn sub(self, other: u32) -> u32 { self - other } } impl Sub for u64 { fn sub(self, other: u64) -> u64 { self - other } } impl Sub for i8 { fn sub(self, other: i8) -> i8 { self - other } } -impl Sub for i16 { fn sub(self, other: i16) -> i16 { self - other } } impl Sub for i32 { fn sub(self, other: i32) -> i32 { self - other } } impl Sub for i64 { fn sub(self, other: i64) -> i64 { self - other } } @@ -43,12 +39,10 @@ trait Mul { impl Mul for Field { fn mul(self, other: Field) -> Field { self * other } } impl Mul for u8 { fn mul(self, other: u8) -> u8 { self * other } } -impl Mul for u16 { fn mul(self, other: u16) -> u16 { self * other } } impl Mul for u32 { fn mul(self, other: u32) -> u32 { self * other } } impl Mul for u64 { fn mul(self, other: u64) -> u64 { self * other } } impl Mul for i8 { fn mul(self, other: i8) -> i8 { self * other } } -impl Mul for i16 { fn mul(self, other: i16) -> i16 { self * other } } impl Mul for i32 { fn mul(self, other: i32) -> i32 { self * other } } impl Mul for i64 { fn mul(self, other: i64) -> i64 { self * other } } @@ -61,12 +55,10 @@ trait Div { impl Div for Field { fn div(self, other: Field) -> Field { self / other } } impl Div for u8 { fn div(self, other: u8) -> u8 { self / other } } -impl Div for u16 { fn div(self, other: u16) -> u16 { self / other } } impl Div for u32 { fn div(self, other: u32) -> u32 { self / other } } impl Div for u64 { fn div(self, other: u64) -> u64 { self / other } } impl Div for i8 { fn div(self, other: i8) -> i8 { self / other } } -impl Div for i16 { fn div(self, other: i16) -> i16 { self / other } } impl Div for i32 { fn div(self, other: i32) -> i32 { self / other } } impl Div for i64 { fn div(self, other: i64) -> i64 { self / other } } @@ -77,12 +69,10 @@ trait Rem{ // docs:end:rem-trait impl Rem for u8 { fn rem(self, other: u8) -> u8 { self % other } } -impl Rem for u16 { fn rem(self, other: u16) -> u16 { self % other } } impl Rem for u32 { fn rem(self, other: u32) -> u32 { self % other } } impl Rem for u64 { fn rem(self, other: u64) -> u64 { self % other } } impl Rem for i8 { fn rem(self, other: i8) -> i8 { self % other } } -impl Rem for i16 { fn rem(self, other: i16) -> i16 { self % other } } impl Rem for i32 { fn rem(self, other: i32) -> i32 { self % other } } impl Rem for i64 { fn rem(self, other: i64) -> i64 { self % other } } @@ -95,12 +85,10 @@ trait BitOr { impl BitOr for bool { fn bitor(self, other: bool) -> bool { self | other } } impl BitOr for u8 { fn bitor(self, other: u8) -> u8 { self | other } } -impl BitOr for u16 { fn bitor(self, other: u16) -> u16 { self | other } } impl BitOr for u32 { fn bitor(self, other: u32) -> u32 { self | other } } impl BitOr for u64 { fn bitor(self, other: u64) -> u64 { self | other } } impl BitOr for i8 { fn bitor(self, other: i8) -> i8 { self | other } } -impl BitOr for i16 { fn bitor(self, other: i16) -> i16 { self | other } } impl BitOr for i32 { fn bitor(self, other: i32) -> i32 { self | other } } impl BitOr for i64 { fn bitor(self, other: i64) -> i64 { self | other } } @@ -113,12 +101,10 @@ trait BitAnd { impl BitAnd for bool { fn bitand(self, other: bool) -> bool { self & other } } impl BitAnd for u8 { fn bitand(self, other: u8) -> u8 { self & other } } -impl BitAnd for u16 { fn bitand(self, other: u16) -> u16 { self & other } } impl BitAnd for u32 { fn bitand(self, other: u32) -> u32 { self & other } } impl BitAnd for u64 { fn bitand(self, other: u64) -> u64 { self & other } } impl BitAnd for i8 { fn bitand(self, other: i8) -> i8 { self & other } } -impl BitAnd for i16 { fn bitand(self, other: i16) -> i16 { self & other } } impl BitAnd for i32 { fn bitand(self, other: i32) -> i32 { self & other } } impl BitAnd for i64 { fn bitand(self, other: i64) -> i64 { self & other } } @@ -131,12 +117,10 @@ trait BitXor { impl BitXor for bool { fn bitxor(self, other: bool) -> bool { self ^ other } } impl BitXor for u8 { fn bitxor(self, other: u8) -> u8 { self ^ other } } -impl BitXor for u16 { fn bitxor(self, other: u16) -> u16 { self ^ other } } impl BitXor for u32 { fn bitxor(self, other: u32) -> u32 { self ^ other } } impl BitXor for u64 { fn bitxor(self, other: u64) -> u64 { self ^ other } } impl BitXor for i8 { fn bitxor(self, other: i8) -> i8 { self ^ other } } -impl BitXor for i16 { fn bitxor(self, other: i16) -> i16 { self ^ other } } impl BitXor for i32 { fn bitxor(self, other: i32) -> i32 { self ^ other } } impl BitXor for i64 { fn bitxor(self, other: i64) -> i64 { self ^ other } } @@ -147,13 +131,11 @@ trait Shl { // docs:end:shl-trait impl Shl for u8 { fn shl(self, other: u8) -> u8 { self << other } } -impl Shl for u16 { fn shl(self, other: u16) -> u16 { self << other } } impl Shl for u32 { fn shl(self, other: u32) -> u32 { self << other } } impl Shl for u64 { fn shl(self, other: u64) -> u64 { self << other } } // Bit shifting is not currently supported for signed integer types // impl Shl for i8 { fn shl(self, other: i8) -> i8 { self << other } } -// impl Shl for i16 { fn shl(self, other: i16) -> i16 { self << other } } // impl Shl for i32 { fn shl(self, other: i32) -> i32 { self << other } } // impl Shl for i64 { fn shl(self, other: i64) -> i64 { self << other } } @@ -164,12 +146,10 @@ trait Shr { // docs:end:shr-trait impl Shr for u8 { fn shr(self, other: u8) -> u8 { self >> other } } -impl Shr for u16 { fn shr(self, other: u16) -> u16 { self >> other } } impl Shr for u32 { fn shr(self, other: u32) -> u32 { self >> other } } impl Shr for u64 { fn shr(self, other: u64) -> u64 { self >> other } } // Bit shifting is not currently supported for signed integer types // impl Shr for i8 { fn shr(self, other: i8) -> i8 { self >> other } } -// impl Shr for i16 { fn shr(self, other: i16) -> i16 { self >> other } } // impl Shr for i32 { fn shr(self, other: i32) -> i32 { self >> other } } // impl Shr for i64 { fn shr(self, other: i64) -> i64 { self >> other } } diff --git a/noir/noir_stdlib/src/option.nr b/noir/noir_stdlib/src/option.nr index 137d57f33db..cab95731d05 100644 --- a/noir/noir_stdlib/src/option.nr +++ b/noir/noir_stdlib/src/option.nr @@ -56,6 +56,12 @@ impl Option { } } + /// Asserts `self.is_some()` with a provided custom message and returns the contained `Some` value + fn expect(self, message: fmtstr) -> T { + assert(self.is_some(), message); + self._value + } + /// If self is `Some(x)`, this returns `Some(f(x))`. Otherwise, this returns `None`. pub fn map(self, f: fn[Env](T) -> U) -> Option { if self._is_some { diff --git a/noir/noirc_macros/Cargo.toml b/noir/noirc_macros/Cargo.toml new file mode 100644 index 00000000000..699e6b01cae --- /dev/null +++ b/noir/noirc_macros/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "noirc_macros" +version.workspace = true +authors.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +repository.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +noirc_frontend.workspace = true +iter-extended.workspace = true \ No newline at end of file diff --git a/noir/noirc_macros/src/lib.rs b/noir/noirc_macros/src/lib.rs new file mode 100644 index 00000000000..4337214d69f --- /dev/null +++ b/noir/noirc_macros/src/lib.rs @@ -0,0 +1,61 @@ +use noirc_frontend::macros_api::parse_program; +use noirc_frontend::macros_api::HirContext; +use noirc_frontend::macros_api::SortedModule; +use noirc_frontend::macros_api::{CrateId, FileId}; +use noirc_frontend::macros_api::{MacroError, MacroProcessor}; + +pub struct AssertMessageMacro; + +impl MacroProcessor for AssertMessageMacro { + fn process_untyped_ast( + &self, + ast: SortedModule, + crate_id: &CrateId, + _context: &HirContext, + ) -> Result { + transform(ast, crate_id) + } + + // This macro does not need to process any information after name resolution + fn process_typed_ast( + &self, + _crate_id: &CrateId, + _context: &mut HirContext, + ) -> Result<(), (MacroError, FileId)> { + Ok(()) + } +} + +fn transform(ast: SortedModule, crate_id: &CrateId) -> Result { + let ast = add_resolve_assert_message_funcs(ast, crate_id)?; + + Ok(ast) +} + +fn add_resolve_assert_message_funcs( + mut ast: SortedModule, + crate_id: &CrateId, +) -> Result { + if !crate_id.is_stdlib() { + return Ok(ast); + } + let assert_message_oracles = " + #[oracle(assert_message)] + unconstrained fn assert_message_oracle(_input: T) {} + unconstrained pub fn resolve_assert_message(input: T, condition: bool) { + if !condition { + assert_message_oracle(input); + } + }"; + + let (assert_msg_funcs_ast, errors) = parse_program(assert_message_oracles); + assert_eq!(errors.len(), 0, "Failed to parse Noir macro code. This is either a bug in the compiler or the Noir macro code"); + + let assert_msg_funcs_ast = assert_msg_funcs_ast.into_sorted(); + + for func in assert_msg_funcs_ast.functions { + ast.functions.push(func) + } + + Ok(ast) +} diff --git a/noir/scripts/nargo_compile_noir_js_assert_lt.sh b/noir/scripts/nargo_compile_noir_js_assert_lt.sh deleted file mode 100755 index 636ae59b996..00000000000 --- a/noir/scripts/nargo_compile_noir_js_assert_lt.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -cd ./tooling/noir_js/test/noir_compiled_examples/assert_lt -nargo compile \ No newline at end of file diff --git a/noir/test_programs/compile_failure/assert_msg_runtime/Nargo.toml b/noir/test_programs/compile_failure/assert_msg_runtime/Nargo.toml new file mode 100644 index 00000000000..765f632ff74 --- /dev/null +++ b/noir/test_programs/compile_failure/assert_msg_runtime/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "assert_msg_runtime" +type = "bin" +authors = [""] +compiler_version = ">=0.23.0" + +[dependencies] \ No newline at end of file diff --git a/noir/test_programs/compile_failure/assert_msg_runtime/Prover.toml b/noir/test_programs/compile_failure/assert_msg_runtime/Prover.toml new file mode 100644 index 00000000000..f28f2f8cc48 --- /dev/null +++ b/noir/test_programs/compile_failure/assert_msg_runtime/Prover.toml @@ -0,0 +1,2 @@ +x = "5" +y = "10" diff --git a/noir/test_programs/compile_failure/assert_msg_runtime/src/main.nr b/noir/test_programs/compile_failure/assert_msg_runtime/src/main.nr new file mode 100644 index 00000000000..bec3082550a --- /dev/null +++ b/noir/test_programs/compile_failure/assert_msg_runtime/src/main.nr @@ -0,0 +1,7 @@ +fn main(x: Field, y: pub Field) { + assert(x != y, f"Expected x != y, but got both equal {x}"); + assert(x != y); + let z = x + y; + assert(z != y, f"Expected z != y, but got both equal {z}"); + assert_eq(x, y, f"Expected x == y, but x is {x} and y is {y}"); +} \ No newline at end of file diff --git a/noir/test_programs/compile_failure/brillig_assert_msg_runtime/Nargo.toml b/noir/test_programs/compile_failure/brillig_assert_msg_runtime/Nargo.toml new file mode 100644 index 00000000000..00f97b7273a --- /dev/null +++ b/noir/test_programs/compile_failure/brillig_assert_msg_runtime/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "brillig_assert_msg_runtime" +type = "bin" +authors = [""] +compiler_version = ">=0.23.0" + +[dependencies] \ No newline at end of file diff --git a/noir/test_programs/compile_failure/brillig_assert_msg_runtime/Prover.toml b/noir/test_programs/compile_failure/brillig_assert_msg_runtime/Prover.toml new file mode 100644 index 00000000000..0e5dfd5638d --- /dev/null +++ b/noir/test_programs/compile_failure/brillig_assert_msg_runtime/Prover.toml @@ -0,0 +1 @@ +x = "5" diff --git a/noir/test_programs/compile_failure/brillig_assert_msg_runtime/src/main.nr b/noir/test_programs/compile_failure/brillig_assert_msg_runtime/src/main.nr new file mode 100644 index 00000000000..428b2006363 --- /dev/null +++ b/noir/test_programs/compile_failure/brillig_assert_msg_runtime/src/main.nr @@ -0,0 +1,10 @@ +fn main(x: Field) { + assert(1 == conditional(x)); +} + +unconstrained fn conditional(x: Field) -> Field { + let z = x as u8 + 20; + assert_eq(z, 25, f"Expected 25 but got {z}"); + assert(x == 10, f"Expected x to equal 10, but got {x}"); + 1 +} \ No newline at end of file diff --git a/noir/test_programs/compile_failure/brillig_mut_ref_from_acir/Nargo.toml b/noir/test_programs/compile_failure/brillig_mut_ref_from_acir/Nargo.toml new file mode 100644 index 00000000000..a20ee09714c --- /dev/null +++ b/noir/test_programs/compile_failure/brillig_mut_ref_from_acir/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "brillig_mut_ref_from_acir" +type = "bin" +authors = [""] +compiler_version = ">=0.23.0" + +[dependencies] \ No newline at end of file diff --git a/noir/test_programs/compile_failure/brillig_mut_ref_from_acir/src/main.nr b/noir/test_programs/compile_failure/brillig_mut_ref_from_acir/src/main.nr new file mode 100644 index 00000000000..cf3279cac0d --- /dev/null +++ b/noir/test_programs/compile_failure/brillig_mut_ref_from_acir/src/main.nr @@ -0,0 +1,8 @@ +unconstrained fn mut_ref_identity(value: &mut Field) -> Field { + *value +} + +fn main(mut x: Field, y: pub Field) { + let returned_x = mut_ref_identity(&mut x); + assert(returned_x == x); +} \ No newline at end of file diff --git a/noir/test_programs/compile_failure/brillig_slice_to_acir/Nargo.toml b/noir/test_programs/compile_failure/brillig_slice_to_acir/Nargo.toml new file mode 100644 index 00000000000..c3e51561cc7 --- /dev/null +++ b/noir/test_programs/compile_failure/brillig_slice_to_acir/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "brillig_slice_to_acir" +type = "bin" +authors = [""] +compiler_version = ">=0.23.0" + +[dependencies] \ No newline at end of file diff --git a/noir/test_programs/compile_failure/brillig_slice_to_acir/src/main.nr b/noir/test_programs/compile_failure/brillig_slice_to_acir/src/main.nr new file mode 100644 index 00000000000..dcf23aac5f5 --- /dev/null +++ b/noir/test_programs/compile_failure/brillig_slice_to_acir/src/main.nr @@ -0,0 +1,14 @@ +global DEPTH: Field = 40000; + +fn main(x: [u32; DEPTH], y: u32) { + let mut new_x = []; + new_x = clear(x, y); +} + +unconstrained fn clear(x: [u32; DEPTH], y: u32) -> [u32] { + let mut a = []; + for i in 0..y { + a = a.push_back(x[i]); + } + a +} diff --git a/noir/test_programs/compile_failure/brillig_vec_to_acir/Nargo.toml b/noir/test_programs/compile_failure/brillig_vec_to_acir/Nargo.toml new file mode 100644 index 00000000000..c09fc417b55 --- /dev/null +++ b/noir/test_programs/compile_failure/brillig_vec_to_acir/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "brillig_vec_to_acir" +type = "bin" +authors = [""] +compiler_version = ">=0.23.0" + +[dependencies] \ No newline at end of file diff --git a/noir/test_programs/compile_failure/brillig_vec_to_acir/src/main.nr b/noir/test_programs/compile_failure/brillig_vec_to_acir/src/main.nr new file mode 100644 index 00000000000..8f872f1b903 --- /dev/null +++ b/noir/test_programs/compile_failure/brillig_vec_to_acir/src/main.nr @@ -0,0 +1,14 @@ +global DEPTH: Field = 40000; + +fn main(x: [u32; DEPTH], y: u32) { + let mut new_x = Vec::new(); + new_x = clear(x, y); +} + +unconstrained fn clear(x: [u32; DEPTH], y: u32) -> Vec { + let mut a = Vec::new(); + for i in 0..y { + a.push(x[i]); + } + a +} diff --git a/noir/test_programs/compile_failure/option_expect/Nargo.toml b/noir/test_programs/compile_failure/option_expect/Nargo.toml new file mode 100644 index 00000000000..1ee1215ff71 --- /dev/null +++ b/noir/test_programs/compile_failure/option_expect/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "option_expect" +type = "bin" +authors = [""] +compiler_version = ">=0.23.0" + +[dependencies] \ No newline at end of file diff --git a/noir/test_programs/compile_failure/option_expect/src/main.nr b/noir/test_programs/compile_failure/option_expect/src/main.nr new file mode 100644 index 00000000000..439ce4f386e --- /dev/null +++ b/noir/test_programs/compile_failure/option_expect/src/main.nr @@ -0,0 +1,8 @@ +fn main() { + let inner_value = 3; + let none = Option::none(); + let some = Option::some(inner_value); + + assert(some.expect(f"Should have the value {inner_value}") == 3); + assert(none.expect(f"Should have the value {inner_value}") == 3); +} diff --git a/noir/test_programs/compile_failure/option_expect_bad_input/Nargo.toml b/noir/test_programs/compile_failure/option_expect_bad_input/Nargo.toml new file mode 100644 index 00000000000..0555681e188 --- /dev/null +++ b/noir/test_programs/compile_failure/option_expect_bad_input/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "option_expect_bad_input" +type = "bin" +authors = [""] +compiler_version = ">=0.23.0" + +[dependencies] \ No newline at end of file diff --git a/noir/test_programs/compile_failure/option_expect_bad_input/src/main.nr b/noir/test_programs/compile_failure/option_expect_bad_input/src/main.nr new file mode 100644 index 00000000000..cc93e767975 --- /dev/null +++ b/noir/test_programs/compile_failure/option_expect_bad_input/src/main.nr @@ -0,0 +1,6 @@ +fn main() { + let inner_value = 3; + let some = Option::some(inner_value); + + assert(some.expect("Should have the value {inner_value}") == 3); +} diff --git a/noir/test_programs/compile_success_empty/brillig_cast/src/main.nr b/noir/test_programs/compile_success_empty/brillig_cast/src/main.nr index 3ba29b52982..ecb832468ba 100644 --- a/noir/test_programs/compile_success_empty/brillig_cast/src/main.nr +++ b/noir/test_programs/compile_success_empty/brillig_cast/src/main.nr @@ -17,33 +17,25 @@ unconstrained fn bool_casts() { unconstrained fn field_casts() { assert(5 as u8 as Field == 5); - assert(16 as u4 as Field == 0); + assert(256 as u8 as Field == 0); } unconstrained fn uint_casts() { - let x: u32 = 100; - assert(x as u2 == 0); - assert(x as u4 == 4); - assert(x as u6 == 36); - assert(x as u8 == 100); - assert(x as u64 == 100); - assert(x as u126 == 100); + let x: u32 = 300; + assert(x as u8 == 44); + assert(x as u32 == 300); + assert(x as u64 == 300); } unconstrained fn int_casts() { - let x: i32 = 100; - assert(x as i2 == 0); - assert(x as i4 == 4); - assert(x as i6 == -28 as i6); - assert(x as i8 == 100); - assert(x as i8 == 100); - assert(x as i8 == 100); + let x: i32 = 456; + assert(x as i8 == -56 as i8); + assert(x as i64 == 456); } unconstrained fn mixed_casts() { assert(100 as u32 as i32 as u32 == 100); - assert(13 as u4 as i2 as u32 == 1); - assert(15 as u4 as i2 as u32 == 3); + assert(257 as u8 as u32 == 1); assert(1 as u8 as bool == true); assert(true as i8 == 1); } diff --git a/noir/test_programs/compile_success_empty/brillig_modulo/src/main.nr b/noir/test_programs/compile_success_empty/brillig_modulo/src/main.nr index ed0353b101a..195ed31fb08 100644 --- a/noir/test_programs/compile_success_empty/brillig_modulo/src/main.nr +++ b/noir/test_programs/compile_success_empty/brillig_modulo/src/main.nr @@ -7,9 +7,9 @@ fn main() { assert(signed_modulo(5, 3) == 2); assert(signed_modulo(2, 3) == 2); - let minus_two: i4 = -2; // 14 - let minus_three: i4 = -3; // 13 - let minus_five: i4 = -5; // 11 + let minus_two: i8 = -2; // 254 + let minus_three: i8 = -3; // 253 + let minus_five: i8 = -5; // 251 // (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 @@ -22,6 +22,6 @@ unconstrained fn modulo(x: u32, y: u32) -> u32 { x % y } -unconstrained fn signed_modulo(x: i4, y: i4) -> i4 { +unconstrained fn signed_modulo(x: i8, y: i8) -> i8 { x % y } diff --git a/noir/test_programs/compile_success_empty/comptime_sort/src/main.nr b/noir/test_programs/compile_success_empty/comptime_sort/src/main.nr deleted file mode 100644 index a24a6ebaba6..00000000000 --- a/noir/test_programs/compile_success_empty/comptime_sort/src/main.nr +++ /dev/null @@ -1,7 +0,0 @@ -fn main() { - let unsorted: [u8; 3] = [3, 1, 2]; - let sorted = unsorted.sort(); - assert(sorted[0] == 1); - assert(sorted[1] == 2); - assert(sorted[2] == 3); -} diff --git a/noir/test_programs/compile_success_empty/literal_not_simplification/Nargo.toml b/noir/test_programs/compile_success_empty/literal_not_simplification/Nargo.toml new file mode 100644 index 00000000000..63d73ed3c0a --- /dev/null +++ b/noir/test_programs/compile_success_empty/literal_not_simplification/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "literal_not_simplification" +type = "bin" +authors = [""] +compiler_version = ">=0.23.0" + +[dependencies] diff --git a/noir/test_programs/compile_success_empty/literal_not_simplification/src/main.nr b/noir/test_programs/compile_success_empty/literal_not_simplification/src/main.nr new file mode 100644 index 00000000000..33198a326c9 --- /dev/null +++ b/noir/test_programs/compile_success_empty/literal_not_simplification/src/main.nr @@ -0,0 +1,8 @@ +fn main() { + let four: u8 = 4; + let not_four: u8 = !four; + + let five: u8 = 5; + let not_five: u8 = !five; + assert(not_four != not_five); +} diff --git a/noir/test_programs/compile_success_empty/method_call_regression/Nargo.toml b/noir/test_programs/compile_success_empty/method_call_regression/Nargo.toml index 92c9b942008..09f95590aad 100644 --- a/noir/test_programs/compile_success_empty/method_call_regression/Nargo.toml +++ b/noir/test_programs/compile_success_empty/method_call_regression/Nargo.toml @@ -1,5 +1,5 @@ [package] -name = "short" +name = "method_call_regression" type = "bin" authors = [""] compiler_version = ">=0.19.4" diff --git a/noir/test_programs/compile_success_empty/option/src/main.nr b/noir/test_programs/compile_success_empty/option/src/main.nr index 1f879bd375f..989c8f65bf4 100644 --- a/noir/test_programs/compile_success_empty/option/src/main.nr +++ b/noir/test_programs/compile_success_empty/option/src/main.nr @@ -1,5 +1,3 @@ -use dep::std::option::Option; - fn main() { let ten = 10; // giving this a name, to ensure that the Option functions work with closures let none = Option::none(); @@ -22,6 +20,8 @@ fn main() { assert(some.map(|x| x * 2).unwrap() == 6); assert(some.map(|x| x * ten).unwrap() == 30); + assert(some.expect(f"Should have a value") == 3); + assert(none.map_or(0, |x| x * 2) == 0); assert(some.map_or(0, |x| x * 2) == 6); assert(none.map_or(0, |x| x * ten) == 0); diff --git a/noir/test_programs/compile_success_empty/trait_static_methods/Nargo.toml b/noir/test_programs/compile_success_empty/trait_static_methods/Nargo.toml index 71c541ccd4f..ea30031b9a5 100644 --- a/noir/test_programs/compile_success_empty/trait_static_methods/Nargo.toml +++ b/noir/test_programs/compile_success_empty/trait_static_methods/Nargo.toml @@ -1,5 +1,5 @@ [package] -name = "trait_self" +name = "trait_static_methods" type = "bin" authors = [""] diff --git a/noir/test_programs/execution_success/5_over/src/main.nr b/noir/test_programs/execution_success/5_over/src/main.nr index f24ff06cb2a..313d580a8d1 100644 --- a/noir/test_programs/execution_success/5_over/src/main.nr +++ b/noir/test_programs/execution_success/5_over/src/main.nr @@ -5,6 +5,6 @@ fn main(mut x: u32, y: u32) { x = std::wrapping_mul(x,x); assert(y == x); - let c: u3 = 2; - assert(c > x as u3); + let c: u1 = 0; + assert(x as u1 > c); } diff --git a/noir/test_programs/execution_success/bit_not/Nargo.toml b/noir/test_programs/execution_success/bit_not/Nargo.toml new file mode 100644 index 00000000000..e89a338595b --- /dev/null +++ b/noir/test_programs/execution_success/bit_not/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "bit_not" +type = "bin" +authors = [""] +compiler_version = ">=0.23.0" + +[dependencies] diff --git a/noir/test_programs/execution_success/bit_not/Prover.toml b/noir/test_programs/execution_success/bit_not/Prover.toml new file mode 100644 index 00000000000..b4bcbcec177 --- /dev/null +++ b/noir/test_programs/execution_success/bit_not/Prover.toml @@ -0,0 +1 @@ +four_as_u32 = 4 diff --git a/noir/test_programs/execution_success/bit_not/src/main.nr b/noir/test_programs/execution_success/bit_not/src/main.nr new file mode 100644 index 00000000000..30b78d330ce --- /dev/null +++ b/noir/test_programs/execution_success/bit_not/src/main.nr @@ -0,0 +1,8 @@ +fn main(four_as_u32: u32) { + let four_as_u8: u8 = 4; + let not_four_as_u8: u8 = !four_as_u8; + assert_eq(not_four_as_u8, 251); + + let not_four_as_u32: u32 = !four_as_u32; + assert_eq(not_four_as_u32, 4294967291); +} diff --git a/noir/test_programs/execution_success/bit_shifts_comptime/src/main.nr b/noir/test_programs/execution_success/bit_shifts_comptime/src/main.nr index 9bb1028173d..9184b5bd5e6 100644 --- a/noir/test_programs/execution_success/bit_shifts_comptime/src/main.nr +++ b/noir/test_programs/execution_success/bit_shifts_comptime/src/main.nr @@ -14,7 +14,7 @@ fn main(x: u64) { //regression for 3481 assert(x << 63 == 0); - assert_eq((1 as u56) << (32 as u56), 0x0100000000); + assert_eq((1 as u64) << (32 as u64), 0x0100000000); } fn regression_2250() { diff --git a/noir/test_programs/execution_success/bit_shifts_runtime/src/main.nr b/noir/test_programs/execution_success/bit_shifts_runtime/src/main.nr index 33d68765598..28b3ef656c1 100644 --- a/noir/test_programs/execution_success/bit_shifts_runtime/src/main.nr +++ b/noir/test_programs/execution_success/bit_shifts_runtime/src/main.nr @@ -16,4 +16,5 @@ fn main(x: u64, y: u64) { assert(a << 7 == -128); assert(a << -a == -2); + assert(x >> x == 0); } diff --git a/noir/test_programs/execution_success/brillig_assert/src/main.nr b/noir/test_programs/execution_success/brillig_assert/src/main.nr index 91e4cebd9d3..16fe7b29061 100644 --- a/noir/test_programs/execution_success/brillig_assert/src/main.nr +++ b/noir/test_programs/execution_success/brillig_assert/src/main.nr @@ -6,7 +6,7 @@ fn main(x: Field) { } unconstrained fn conditional(x: bool) -> Field { - assert(x, "x is false"); - assert_eq(x, true, "x is false"); + assert(x, f"Expected x to be false but got {x}"); + assert_eq(x, true, f"Expected x to be false but got {x}"); 1 } diff --git a/noir/test_programs/execution_success/brillig_bit_shifts_runtime/Nargo.toml b/noir/test_programs/execution_success/brillig_bit_shifts_runtime/Nargo.toml new file mode 100644 index 00000000000..ed8200d8a95 --- /dev/null +++ b/noir/test_programs/execution_success/brillig_bit_shifts_runtime/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "brillig_bit_shifts_runtime" +type = "bin" +authors = [""] + +[dependencies] diff --git a/noir/test_programs/execution_success/brillig_bit_shifts_runtime/Prover.toml b/noir/test_programs/execution_success/brillig_bit_shifts_runtime/Prover.toml new file mode 100644 index 00000000000..98d8630792e --- /dev/null +++ b/noir/test_programs/execution_success/brillig_bit_shifts_runtime/Prover.toml @@ -0,0 +1,2 @@ +x = 64 +y = 1 \ No newline at end of file diff --git a/noir/test_programs/execution_success/brillig_bit_shifts_runtime/src/main.nr b/noir/test_programs/execution_success/brillig_bit_shifts_runtime/src/main.nr new file mode 100644 index 00000000000..f22166b5993 --- /dev/null +++ b/noir/test_programs/execution_success/brillig_bit_shifts_runtime/src/main.nr @@ -0,0 +1,20 @@ +unconstrained fn main(x: u64, y: u64) { + // runtime shifts on compile-time known values + assert(64 << y == 128); + assert(64 >> y == 32); + // runtime shifts on runtime values + assert(x << y == 128); + assert(x >> y == 32); + + // Bit-shift with signed integers + let mut a :i8 = y as i8; + let mut b: i8 = x as i8; + assert(b << 1 == -128); + assert(b >> 2 == 16); + assert(b >> a == 32); + a = -a; + assert(a << 7 == -128); + assert(a << -a == -2); + + assert(x >> x == 0); +} diff --git a/noir/test_programs/compile_success_empty/comptime_sort/Nargo.toml b/noir/test_programs/execution_success/brillig_cow_regression/Nargo.toml similarity index 61% rename from noir/test_programs/compile_success_empty/comptime_sort/Nargo.toml rename to noir/test_programs/execution_success/brillig_cow_regression/Nargo.toml index 7d215a22496..c5bf60a1e78 100644 --- a/noir/test_programs/compile_success_empty/comptime_sort/Nargo.toml +++ b/noir/test_programs/execution_success/brillig_cow_regression/Nargo.toml @@ -1,5 +1,6 @@ [package] -name = "comptime_sort" +name = "brillig_cow_regression" type = "bin" authors = [""] + [dependencies] diff --git a/noir/test_programs/execution_success/brillig_cow_regression/Prover.toml b/noir/test_programs/execution_success/brillig_cow_regression/Prover.toml new file mode 100644 index 00000000000..f0a4dc2485d --- /dev/null +++ b/noir/test_programs/execution_success/brillig_cow_regression/Prover.toml @@ -0,0 +1,229 @@ +[kernel_data] +encrypted_logs_hash = [ + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", +] +new_commitments = [ + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", +] +new_l2_to_l1_msgs = [ + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", +] +new_nullifiers = [ + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", +] +unencrypted_logs_hash = [ + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", +] + +[[kernel_data.new_contracts]] +contract_address = "0x0000000000000000000000000000000000000000000000000000000000000000" +portal_contract_address = "0x0000000000000000000000000000000000000000000000000000000000000000" + +[[kernel_data.public_data_update_requests]] +leaf_slot = "0x0000000000000000000000000000000000000000000000000000000000000000" +new_value = "0x0000000000000000000000000000000000000000000000000000000000000000" +old_value = "0x0000000000000000000000000000000000000000000000000000000000000000" + +[[kernel_data.public_data_update_requests]] +leaf_slot = "0x0000000000000000000000000000000000000000000000000000000000000000" +new_value = "0x0000000000000000000000000000000000000000000000000000000000000000" +old_value = "0x0000000000000000000000000000000000000000000000000000000000000000" + +[[kernel_data.public_data_update_requests]] +leaf_slot = "0x0000000000000000000000000000000000000000000000000000000000000000" +new_value = "0x0000000000000000000000000000000000000000000000000000000000000000" +old_value = "0x0000000000000000000000000000000000000000000000000000000000000000" + +[[kernel_data.public_data_update_requests]] +leaf_slot = "0x0000000000000000000000000000000000000000000000000000000000000000" +new_value = "0x0000000000000000000000000000000000000000000000000000000000000000" +old_value = "0x0000000000000000000000000000000000000000000000000000000000000000" + +[[kernel_data.public_data_update_requests]] +leaf_slot = "0x0000000000000000000000000000000000000000000000000000000000000000" +new_value = "0x0000000000000000000000000000000000000000000000000000000000000000" +old_value = "0x0000000000000000000000000000000000000000000000000000000000000000" + +[[kernel_data.public_data_update_requests]] +leaf_slot = "0x0000000000000000000000000000000000000000000000000000000000000000" +new_value = "0x0000000000000000000000000000000000000000000000000000000000000000" +old_value = "0x0000000000000000000000000000000000000000000000000000000000000000" + +[[kernel_data.public_data_update_requests]] +leaf_slot = "0x0000000000000000000000000000000000000000000000000000000000000000" +new_value = "0x0000000000000000000000000000000000000000000000000000000000000000" +old_value = "0x0000000000000000000000000000000000000000000000000000000000000000" + +[[kernel_data.public_data_update_requests]] +leaf_slot = "0x0000000000000000000000000000000000000000000000000000000000000000" +new_value = "0x0000000000000000000000000000000000000000000000000000000000000000" +old_value = "0x0000000000000000000000000000000000000000000000000000000000000000" + +[[kernel_data.public_data_update_requests]] +leaf_slot = "0x0000000000000000000000000000000000000000000000000000000000000000" +new_value = "0x0000000000000000000000000000000000000000000000000000000000000000" +old_value = "0x0000000000000000000000000000000000000000000000000000000000000000" + +[[kernel_data.public_data_update_requests]] +leaf_slot = "0x0000000000000000000000000000000000000000000000000000000000000000" +new_value = "0x0000000000000000000000000000000000000000000000000000000000000000" +old_value = "0x0000000000000000000000000000000000000000000000000000000000000000" + +[[kernel_data.public_data_update_requests]] +leaf_slot = "0x0000000000000000000000000000000000000000000000000000000000000000" +new_value = "0x0000000000000000000000000000000000000000000000000000000000000000" +old_value = "0x0000000000000000000000000000000000000000000000000000000000000000" + +[[kernel_data.public_data_update_requests]] +leaf_slot = "0x0000000000000000000000000000000000000000000000000000000000000000" +new_value = "0x0000000000000000000000000000000000000000000000000000000000000000" +old_value = "0x0000000000000000000000000000000000000000000000000000000000000000" + +[[kernel_data.public_data_update_requests]] +leaf_slot = "0x0000000000000000000000000000000000000000000000000000000000000000" +new_value = "0x0000000000000000000000000000000000000000000000000000000000000000" +old_value = "0x0000000000000000000000000000000000000000000000000000000000000000" + +[[kernel_data.public_data_update_requests]] +leaf_slot = "0x0000000000000000000000000000000000000000000000000000000000000000" +new_value = "0x0000000000000000000000000000000000000000000000000000000000000000" +old_value = "0x0000000000000000000000000000000000000000000000000000000000000000" + +[[kernel_data.public_data_update_requests]] +leaf_slot = "0x0000000000000000000000000000000000000000000000000000000000000000" +new_value = "0x0000000000000000000000000000000000000000000000000000000000000000" +old_value = "0x0000000000000000000000000000000000000000000000000000000000000000" + +[[kernel_data.public_data_update_requests]] +leaf_slot = "0x0000000000000000000000000000000000000000000000000000000000000000" +new_value = "0x0000000000000000000000000000000000000000000000000000000000000000" +old_value = "0x0000000000000000000000000000000000000000000000000000000000000000" diff --git a/noir/test_programs/execution_success/brillig_cow_regression/src/main.nr b/noir/test_programs/execution_success/brillig_cow_regression/src/main.nr new file mode 100644 index 00000000000..974c17dfbc9 --- /dev/null +++ b/noir/test_programs/execution_success/brillig_cow_regression/src/main.nr @@ -0,0 +1,178 @@ +// Tests a performance regression found in aztec-packages with brillig cow optimization + +global MAX_NEW_COMMITMENTS_PER_TX: Field = 64; +global MAX_NEW_NULLIFIERS_PER_TX: Field = 64; +global MAX_NEW_L2_TO_L1_MSGS_PER_TX: Field = 2; +global MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX: Field = 16; +global MAX_NEW_CONTRACTS_PER_TX: Field = 1; +global NUM_ENCRYPTED_LOGS_HASHES_PER_TX: Field = 1; +global NUM_UNENCRYPTED_LOGS_HASHES_PER_TX: Field = 1; +global NUM_FIELDS_PER_SHA256 = 2; +global CALLDATA_HASH_INPUT_SIZE = 169; +global CALL_DATA_HASH_LOG_FIELDS = 4; +global CALL_DATA_HASH_FULL_FIELDS = 165; + +struct PublicDataUpdateRequest { + leaf_slot : Field, + old_value : Field, + new_value : Field +} + +struct NewContractData { + contract_address: Field, + portal_contract_address: Field, +} + +impl NewContractData { + fn hash(self) -> Field { + dep::std::hash::pedersen_hash([self.contract_address, self.portal_contract_address]) + } +} + +struct DataToHash { + new_commitments: [Field; MAX_NEW_COMMITMENTS_PER_TX], + new_nullifiers: [Field; MAX_NEW_NULLIFIERS_PER_TX], + public_data_update_requests: [PublicDataUpdateRequest; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], + new_l2_to_l1_msgs: [Field; MAX_NEW_L2_TO_L1_MSGS_PER_TX], + encrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], + unencrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], + new_contracts: [NewContractData; MAX_NEW_CONTRACTS_PER_TX], +} + +struct U256 { + // This is in big-endian order, typically because + // sha256 is usually in big endian order. + // Note: this means that inner[0] has the most significant 64 bits. + inner : [u64; 4] +} + +impl U256 { + pub fn from_bytes32(bytes : [u8;32]) -> U256 { + // We use addition rather than a bitwise OR as the bitshifts ensure that none of the bytes overlap each other. + let high_0 = ((bytes[0] as u64) << 56) + + ((bytes[1] as u64) << 48) + + ((bytes[2] as u64) << 40) + + ((bytes[3] as u64) << 32) + + ((bytes[4] as u64) << 24) + + ((bytes[5] as u64) << 16) + + ((bytes[6] as u64) << 8) + + (bytes[7] as u64); + + let high_1 = ((bytes[8] as u64) << 56) + + ((bytes[9] as u64) << 48) + + ((bytes[10] as u64) << 40) + + ((bytes[11] as u64) << 32) + + ((bytes[12] as u64) << 24) + + ((bytes[13] as u64) << 16) + + ((bytes[14] as u64) << 8) + + (bytes[15] as u64); + + let low_0 = ((bytes[16] as u64) << 56) + + ((bytes[17] as u64) << 48) + + ((bytes[18] as u64) << 40) + + ((bytes[19] as u64) << 32) + + ((bytes[20] as u64) << 24) + + ((bytes[21] as u64) << 16) + + ((bytes[22] as u64) << 8) + + (bytes[23] as u64); + + let low_1 = ((bytes[24] as u64) << 56) + + ((bytes[25] as u64) << 48) + + ((bytes[26] as u64) << 40) + + ((bytes[27] as u64) << 32) + + ((bytes[28] as u64) << 24) + + ((bytes[29] as u64) << 16) + + ((bytes[30] as u64) << 8) + + (bytes[31] as u64); + + U256{inner : [high_0, high_1, low_0, low_1]} + } + + pub fn to_u128_limbs(self) -> [Field;2] { + let two_pow_64 = 2.pow_32(64); + + let high = (self.inner[0] as Field) * two_pow_64 + self.inner[1] as Field; + let low = (self.inner[2] as Field) * two_pow_64 + self.inner[3] as Field; + + [high,low] + } +} + +unconstrained fn main(kernel_data: DataToHash) -> pub [Field; NUM_FIELDS_PER_SHA256] { + let mut calldata_hash_inputs = [0; CALLDATA_HASH_INPUT_SIZE]; + + let new_commitments = kernel_data.new_commitments; + let new_nullifiers = kernel_data.new_nullifiers; + let public_data_update_requests = kernel_data.public_data_update_requests; + let newL2ToL1msgs = kernel_data.new_l2_to_l1_msgs; + let encryptedLogsHash = kernel_data.encrypted_logs_hash; + let unencryptedLogsHash = kernel_data.unencrypted_logs_hash; + + let mut offset = 0; + + for j in 0..MAX_NEW_COMMITMENTS_PER_TX { + calldata_hash_inputs[offset + j] = new_commitments[j]; + } + offset += MAX_NEW_COMMITMENTS_PER_TX ; + + for j in 0..MAX_NEW_NULLIFIERS_PER_TX { + calldata_hash_inputs[offset + j] = new_nullifiers[j]; + } + offset += MAX_NEW_NULLIFIERS_PER_TX ; + + for j in 0..MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX { + calldata_hash_inputs[offset + j * 2] = + public_data_update_requests[j].leaf_slot; + calldata_hash_inputs[offset + j * 2 + 1] = + public_data_update_requests[j].new_value; + } + offset += MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * 2; + + for j in 0..MAX_NEW_L2_TO_L1_MSGS_PER_TX { + calldata_hash_inputs[offset + j] = newL2ToL1msgs[j]; + } + offset += MAX_NEW_L2_TO_L1_MSGS_PER_TX; + + let contract_leaf = kernel_data.new_contracts[0]; + calldata_hash_inputs[offset] = contract_leaf.hash(); + + offset += MAX_NEW_CONTRACTS_PER_TX; + + let new_contracts = kernel_data.new_contracts; + calldata_hash_inputs[offset] = new_contracts[0].contract_address; + + calldata_hash_inputs[offset + 1] = new_contracts[0].portal_contract_address; + + offset += MAX_NEW_CONTRACTS_PER_TX * 2; + + for j in 0..NUM_FIELDS_PER_SHA256 { + calldata_hash_inputs[offset + j] = encryptedLogsHash[j]; + } + + offset += NUM_ENCRYPTED_LOGS_HASHES_PER_TX * NUM_FIELDS_PER_SHA256; + + for j in 0..NUM_FIELDS_PER_SHA256 { + calldata_hash_inputs[offset + j] = unencryptedLogsHash[j]; + } + + offset += NUM_UNENCRYPTED_LOGS_HASHES_PER_TX * NUM_FIELDS_PER_SHA256; + assert_eq(offset, CALLDATA_HASH_INPUT_SIZE); // Sanity check + + let mut hash_input_flattened = [0; CALL_DATA_HASH_FULL_FIELDS * 32 + CALL_DATA_HASH_LOG_FIELDS * 16]; + for offset in 0..CALL_DATA_HASH_FULL_FIELDS { + let input_as_bytes = calldata_hash_inputs[offset].to_be_bytes(32); + for byte_index in 0..32 { + hash_input_flattened[offset * 32 + byte_index] = input_as_bytes[byte_index]; + } + } + + for log_field_index in 0..CALL_DATA_HASH_LOG_FIELDS { + let input_as_bytes = calldata_hash_inputs[CALL_DATA_HASH_FULL_FIELDS + log_field_index].to_be_bytes(16); + for byte_index in 0..16 { + hash_input_flattened[CALL_DATA_HASH_FULL_FIELDS * 32 + log_field_index * 16 + byte_index] = input_as_bytes[byte_index]; + } + } + + let sha_digest = dep::std::hash::sha256(hash_input_flattened); + U256::from_bytes32(sha_digest).to_u128_limbs() +} diff --git a/noir/test_programs/execution_success/conditional_regression_underflow/src/main.nr b/noir/test_programs/execution_success/conditional_regression_underflow/src/main.nr index a101af32505..aaf3754a20f 100644 --- a/noir/test_programs/execution_success/conditional_regression_underflow/src/main.nr +++ b/noir/test_programs/execution_success/conditional_regression_underflow/src/main.nr @@ -1,12 +1,12 @@ // Regression test for https://github.com/noir-lang/noir/issues/3493 -fn main(x: u4) { +fn main(x: u8) { if x == 10 { - x + 15; + x + 255; } if x == 9 { - x << 3; + x << 7; } - if x == 8 { + if x == 128 { x * 3; } if x == 7 { diff --git a/noir/test_programs/execution_success/debug_logs/src/main.nr b/noir/test_programs/execution_success/debug_logs/src/main.nr index cbce6f15286..49e0041594a 100644 --- a/noir/test_programs/execution_success/debug_logs/src/main.nr +++ b/noir/test_programs/execution_success/debug_logs/src/main.nr @@ -3,8 +3,15 @@ use dep::std; fn main(x: Field, y: pub Field) { let string = "i: {i}, j: {j}"; std::println(string); + + // TODO: fmtstr cannot be printed + // let fmt_str: fmtstr<14, (Field, Field)> = f"i: {x}, j: {y}"; + // let fmt_fmt_str = f"fmtstr: {fmt_str}, i: {x}"; + // std::println(fmt_fmt_str); + // A `fmtstr` lets you easily perform string interpolation. let fmt_str: fmtstr<14, (Field, Field)> = f"i: {x}, j: {y}"; + let fmt_str = string_identity(fmt_str); std::println(fmt_str); diff --git a/noir/test_programs/execution_success/global_consts/src/main.nr b/noir/test_programs/execution_success/global_consts/src/main.nr index 70c7a745a22..25cc0e4dd36 100644 --- a/noir/test_programs/execution_success/global_consts/src/main.nr +++ b/noir/test_programs/execution_success/global_consts/src/main.nr @@ -5,7 +5,10 @@ global M: Field = 32; global L: Field = 10; // Unused globals currently allowed global N: Field = 5; global T_LEN = 2; // Type inference is allowed on globals -//global N: Field = 5; // Uncomment to see duplicate globals error + +// Globals can reference other globals +global DERIVED = M + L; + struct Dummy { x: [Field; N], y: [Field; foo::MAGIC_NUMBER] @@ -17,6 +20,13 @@ struct Test { global VALS: [Test; 1] = [Test { v: 100 }]; global NESTED = [VALS, VALS]; +unconstrained fn calculate_global_value() -> Field { + 42 +} + +// Regression test for https://github.com/noir-lang/noir/issues/4318 +global CALCULATED_GLOBAL: Field = calculate_global_value(); + fn main( a: [Field; M + N - N], b: [Field; 30 + N / 2], @@ -70,6 +80,9 @@ fn main( foo::from_foo(d); baz::from_baz(c); + assert(DERIVED == M + L); + + assert(CALCULATED_GLOBAL == 42); } fn multiplyByM(x: Field) -> Field { diff --git a/noir/test_programs/execution_success/missing_closure_env/Nargo.toml b/noir/test_programs/execution_success/missing_closure_env/Nargo.toml new file mode 100644 index 00000000000..284e61b1144 --- /dev/null +++ b/noir/test_programs/execution_success/missing_closure_env/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "missing_closure_env" +type = "bin" +authors = [""] +compiler_version = ">=0.23.0" + +[dependencies] \ No newline at end of file diff --git a/noir/test_programs/execution_success/missing_closure_env/Prover.toml b/noir/test_programs/execution_success/missing_closure_env/Prover.toml new file mode 100644 index 00000000000..2d76abaa89f --- /dev/null +++ b/noir/test_programs/execution_success/missing_closure_env/Prover.toml @@ -0,0 +1 @@ +x = 42 diff --git a/noir/test_programs/execution_success/missing_closure_env/src/main.nr b/noir/test_programs/execution_success/missing_closure_env/src/main.nr new file mode 100644 index 00000000000..0bc99b0671c --- /dev/null +++ b/noir/test_programs/execution_success/missing_closure_env/src/main.nr @@ -0,0 +1,16 @@ +fn main(x: Field) { + let x1 = &mut 42; + let set_x1 = |y| { *x1 = y; }; + + assert(*x1 == 42); + set_x1(44); + assert(*x1 == 44); + set_x1(*x1); + assert(*x1 == 44); + assert(x == 42); +} + +#[test] +fn test_main() { + main(42); +} diff --git a/noir/test_programs/execution_success/regression/src/main.nr b/noir/test_programs/execution_success/regression/src/main.nr index 08112d4c616..c70e2e75fa8 100644 --- a/noir/test_programs/execution_success/regression/src/main.nr +++ b/noir/test_programs/execution_success/regression/src/main.nr @@ -1,29 +1,49 @@ global NIBBLE_LENGTH: Field = 16; -fn compact_decode(input: [u8; N], length: Field) -> ([u4; NIBBLE_LENGTH], Field) { +struct U4 { + inner: u8, +} + +impl U4 { + fn zero() -> U4 { + U4 { inner: 0 } + } + + fn from_u8(x: u8) -> U4 { + U4 { inner: x % 16 } + } +} + +impl Eq for U4 { + fn eq(self, other: Self) -> bool { + self.inner == other.inner + } +} + +fn compact_decode(input: [u8; N], length: Field) -> ([U4; NIBBLE_LENGTH], Field) { assert(2 * input.len() as u64 <= NIBBLE_LENGTH as u64); assert(length as u64 <= input.len() as u64); - let mut nibble = [0 as u4; NIBBLE_LENGTH]; + let mut nibble = [U4::zero(); NIBBLE_LENGTH]; - let first_nibble = (input[0] >> 4) as u4; - let parity = first_nibble as u1; + let first_nibble = U4::from_u8(input[0] >> 4); + let parity = first_nibble.inner as u1; if parity == 1 { - nibble[0] = (input[0] & 0x0f) as u4; + nibble[0] = U4::from_u8(input[0] & 0x0f); for i in 1..input.len() { if i as u64 < length as u64 { let x = input[i]; - nibble[2*i - 1] = (x >> 4) as u4; - nibble[2*i] = (x & 0x0f) as u4; + nibble[2*i - 1] = U4::from_u8(x >> 4); + nibble[2*i] = U4::from_u8(x & 0x0f); } } } else { for i in 0..2 { if (i as u64) < length as u64 - 1 { let x = input[i + 1]; - nibble[2*i] = (x >> 4) as u4; - nibble[2*i + 1] = (x & 0x0f) as u4; + nibble[2*i] = U4::from_u8(x >> 4); + nibble[2*i + 1] = U4::from_u8(x & 0x0f); } } } @@ -78,7 +98,10 @@ fn main(x: [u8; 5], z: Field) { //Issue 1144 let (nib, len) = compact_decode(x, z); assert(len == 5); - assert([nib[0], nib[1], nib[2], nib[3], nib[4]] == [15, 1, 12, 11, 8]); + assert( + [nib[0], nib[1], nib[2], nib[3], nib[4]] + == [U4::from_u8(15), U4::from_u8(1), U4::from_u8(12), U4::from_u8(11), U4::from_u8(8)] + ); // Issue 1169 let val1 = [ 0xb8, 0x8f, 0x61, 0xe6, 0xfb, 0xda, 0x83, 0xfb, 0xff, 0xfa, 0xbe, 0x36, 0x41, 0x12, 0x13, diff --git a/noir/test_programs/execution_success/regression_4202/Nargo.toml b/noir/test_programs/execution_success/regression_4202/Nargo.toml new file mode 100644 index 00000000000..acfba12dd4f --- /dev/null +++ b/noir/test_programs/execution_success/regression_4202/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "regression_4202" +type = "bin" +authors = [""] +compiler_version = ">=0.23.0" + +[dependencies] \ No newline at end of file diff --git a/noir/test_programs/execution_success/regression_4202/Prover.toml b/noir/test_programs/execution_success/regression_4202/Prover.toml new file mode 100644 index 00000000000..e9319802dfd --- /dev/null +++ b/noir/test_programs/execution_success/regression_4202/Prover.toml @@ -0,0 +1 @@ +input = [1, 2, 3, 4] diff --git a/noir/test_programs/execution_success/regression_4202/src/main.nr b/noir/test_programs/execution_success/regression_4202/src/main.nr new file mode 100644 index 00000000000..37d2ee4578d --- /dev/null +++ b/noir/test_programs/execution_success/regression_4202/src/main.nr @@ -0,0 +1,14 @@ +fn main(input: [u32; 4]) { + let mut slice1: [u32] = [1, 2, 3, 4]; + if slice1[0] == 3 { + slice1[1] = 4; + } + + if slice1[1] == 5 { + slice1[3] = 6; + } + + for i in 0..4 { + assert(slice1[i] == input[i]); + } +} diff --git a/noir/test_programs/execution_success/u128/src/main.nr b/noir/test_programs/execution_success/u128/src/main.nr index 4c734f3a8f9..dc586408795 100644 --- a/noir/test_programs/execution_success/u128/src/main.nr +++ b/noir/test_programs/execution_success/u128/src/main.nr @@ -39,6 +39,6 @@ fn main(mut x: u32, y: u32, z: u32, big_int: U128, hexa: str<7>) { assert(shift >> small_int == small_int); assert(shift >> U128::from_integer(127) == U128::from_integer(0)); assert(shift << U128::from_integer(127) == U128::from_integer(0)); - + assert(U128::from_integer(3).to_integer() == 3); } diff --git a/noir/tooling/backend_interface/src/download.rs b/noir/tooling/backend_interface/src/download.rs index 27aab7ef351..60ecb14e642 100644 --- a/noir/tooling/backend_interface/src/download.rs +++ b/noir/tooling/backend_interface/src/download.rs @@ -17,8 +17,12 @@ pub fn download_backend(backend_url: &str, destination_path: &Path) -> std::io:: use tempfile::tempdir; // Download sources - let compressed_file: Cursor> = download_binary_from_url(backend_url) - .map_err(|_| std::io::Error::from(ErrorKind::Other))?; + let compressed_file: Cursor> = download_binary_from_url(backend_url).map_err(|_| { + std::io::Error::new( + ErrorKind::Other, + format!("Could not download backend from install url: {backend_url}"), + ) + })?; // Unpack the tarball let gz_decoder = GzDecoder::new(compressed_file); diff --git a/noir/tooling/bb_abstraction_leaks/build.rs b/noir/tooling/bb_abstraction_leaks/build.rs index 6197f52cb4b..24603186c87 100644 --- a/noir/tooling/bb_abstraction_leaks/build.rs +++ b/noir/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.21.0"; +const VERSION: &str = "0.23.0"; const TAG: &str = formatcp!("aztec-packages-v{}", VERSION); const API_URL: &str = diff --git a/noir/tooling/debugger/Cargo.toml b/noir/tooling/debugger/Cargo.toml index 4d240c61f90..30d11db8cf3 100644 --- a/noir/tooling/debugger/Cargo.toml +++ b/noir/tooling/debugger/Cargo.toml @@ -11,11 +11,12 @@ build-data.workspace = true [dependencies] acvm.workspace = true +fm.workspace = true nargo.workspace = true +noirc_frontend.workspace = true noirc_printable_type.workspace = true noirc_errors.workspace = true noirc_driver.workspace = true -fm.workspace = true thiserror.workspace = true codespan-reporting.workspace = true dap.workspace = true @@ -26,5 +27,4 @@ serde_json.workspace = true [dev-dependencies] assert_cmd = "2.0.12" rexpect = "0.5.0" -test-binary = "3.0.1" tempfile.workspace = true diff --git a/noir/tooling/debugger/build.rs b/noir/tooling/debugger/build.rs index cedeebcae86..26a8bc64b0e 100644 --- a/noir/tooling/debugger/build.rs +++ b/noir/tooling/debugger/build.rs @@ -1,3 +1,4 @@ +use std::collections::HashSet; use std::fs::File; use std::io::Write; use std::path::{Path, PathBuf}; @@ -6,9 +7,6 @@ use std::{env, fs}; 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() { @@ -29,6 +27,11 @@ fn main() { }; let test_dir = root_dir.join("test_programs"); + // Rebuild if the tests have changed + println!("cargo:rerun-if-changed=tests"); + println!("cargo:rerun-if-changed=ignored-tests.txt"); + println!("cargo:rerun-if-changed={}", test_dir.as_os_str().to_str().unwrap()); + generate_debugger_tests(&mut test_file, &test_dir); } @@ -38,10 +41,13 @@ fn generate_debugger_tests(test_file: &mut File, test_data_dir: &Path) { let test_case_dirs = fs::read_dir(test_data_dir).unwrap().flatten().filter(|c| c.path().is_dir()); + let ignored_tests_contents = fs::read_to_string("ignored-tests.txt").unwrap(); + let ignored_tests = ignored_tests_contents.lines().collect::>(); for test_dir in test_case_dirs { let test_name = test_dir.file_name().into_string().expect("Directory can't be converted to string"); + let ignored = ignored_tests.contains(test_name.as_str()); if test_name.contains('-') { panic!( "Invalid test directory: {test_name}. Cannot include `-`, please convert to `_`" @@ -53,11 +59,13 @@ fn generate_debugger_tests(test_file: &mut File, test_data_dir: &Path) { test_file, r#" #[test] +{ignored} fn debug_{test_name}() {{ debugger_execution_success("{test_dir}"); }} "#, test_dir = test_dir.display(), + ignored = if ignored { "#[ignore]" } else { "" }, ) .expect("Could not write templated test file."); } diff --git a/noir/tooling/debugger/ignored-tests.txt b/noir/tooling/debugger/ignored-tests.txt new file mode 100644 index 00000000000..94bf0f91b57 --- /dev/null +++ b/noir/tooling/debugger/ignored-tests.txt @@ -0,0 +1,19 @@ +array_sort +assign_ex +bit_shifts_comptime +brillig_cow +brillig_nested_arrays +brillig_references +brillig_to_bytes_integration +debug_logs +double_verify_proof +modulus +nested_array_dynamic +nested_array_in_slice +nested_arrays_from_brillig +references +scalar_mul +signed_comparison +simple_2d_array +to_bytes_integration +bigint \ No newline at end of file diff --git a/noir/tooling/debugger/src/context.rs b/noir/tooling/debugger/src/context.rs index 9c12794d5dd..5ab2c63c365 100644 --- a/noir/tooling/debugger/src/context.rs +++ b/noir/tooling/debugger/src/context.rs @@ -1,5 +1,7 @@ +use crate::foreign_calls::DebugForeignCallExecutor; use acvm::acir::circuit::{Circuit, Opcode, OpcodeLocation}; use acvm::acir::native_types::{Witness, WitnessMap}; +use acvm::brillig_vm::brillig::ForeignCallResult; use acvm::brillig_vm::brillig::Value; use acvm::pwg::{ ACVMStatus, BrilligSolver, BrilligSolverStatus, ForeignCallWaitInfo, StepResult, ACVM, @@ -8,8 +10,8 @@ use acvm::{BlackBoxFunctionSolver, FieldElement}; use nargo::artifacts::debug::DebugArtifact; use nargo::errors::{ExecutionError, Location}; -use nargo::ops::ForeignCallExecutor; use nargo::NargoError; +use noirc_printable_type::{PrintableType, PrintableValue}; use std::collections::{hash_set::Iter, HashSet}; @@ -24,7 +26,7 @@ pub(super) enum DebugCommandResult { pub(super) struct DebugContext<'a, B: BlackBoxFunctionSolver> { acvm: ACVM<'a, B>, brillig_solver: Option>, - foreign_call_executor: Box, + foreign_call_executor: Box, debug_artifact: &'a DebugArtifact, breakpoints: HashSet, } @@ -35,7 +37,7 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> { circuit: &'a Circuit, debug_artifact: &'a DebugArtifact, initial_witness: WitnessMap, - foreign_call_executor: Box, + foreign_call_executor: Box, ) -> Self { Self { acvm: ACVM::new(blackbox_solver, &circuit.opcodes, initial_witness), @@ -76,15 +78,82 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> { } } + pub(super) fn get_call_stack(&self) -> Vec { + let instruction_pointer = self.acvm.instruction_pointer(); + if instruction_pointer >= self.get_opcodes().len() { + vec![] + } else if let Some(ref solver) = self.brillig_solver { + solver + .get_call_stack() + .iter() + .map(|program_counter| OpcodeLocation::Brillig { + acir_index: instruction_pointer, + brillig_index: *program_counter, + }) + .collect() + } else { + vec![OpcodeLocation::Acir(instruction_pointer)] + } + } + + pub(super) fn is_source_location_in_debug_module(&self, location: &Location) -> bool { + self.debug_artifact + .file_map + .get(&location.file) + .map(|file| file.path.starts_with("__debug/")) + .unwrap_or(false) + } + /// Returns the callstack in source code locations for the currently /// executing opcode. This can be `None` if the execution finished (and /// `get_current_opcode_location()` returns `None`) or if the opcode is not /// mapped to a specific source location in the debug artifact (which can - /// happen for certain opcodes inserted synthetically by the compiler) + /// happen for certain opcodes inserted synthetically by the compiler). + /// This function also filters source locations that are determined to be in + /// the internal debug module. pub(super) fn get_current_source_location(&self) -> Option> { self.get_current_opcode_location() .as_ref() - .and_then(|location| self.debug_artifact.debug_symbols[0].opcode_location(location)) + .map(|opcode_location| self.get_source_location_for_opcode_location(opcode_location)) + .filter(|v: &Vec| !v.is_empty()) + } + + /// Returns the (possible) stack of source locations corresponding to the + /// given opcode location. Due to compiler inlining it's possible for this + /// function to return multiple source locations. An empty vector means that + /// the given opcode location cannot be mapped back to a source location + /// (eg. it may be pure debug instrumentation code or other synthetically + /// produced opcode by the compiler) + pub(super) fn get_source_location_for_opcode_location( + &self, + opcode_location: &OpcodeLocation, + ) -> Vec { + self.debug_artifact.debug_symbols[0] + .opcode_location(opcode_location) + .map(|source_locations| { + source_locations + .into_iter() + .filter(|source_location| { + !self.is_source_location_in_debug_module(source_location) + }) + .collect() + }) + .unwrap_or(vec![]) + } + + /// Returns the current call stack with expanded source locations. In + /// general, the matching between opcode location and source location is 1 + /// to 1, but due to the compiler inlining functions a single opcode + /// location may expand to multiple source locations. + pub(super) fn get_source_call_stack(&self) -> Vec<(OpcodeLocation, Location)> { + self.get_call_stack() + .iter() + .flat_map(|opcode_location| { + self.get_source_location_for_opcode_location(opcode_location) + .into_iter() + .map(|source_location| (*opcode_location, source_location)) + }) + .collect() } fn get_opcodes_sizes(&self) -> Vec { @@ -224,6 +293,9 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> { let foreign_call_result = self.foreign_call_executor.execute(&foreign_call); match foreign_call_result { Ok(foreign_call_result) => { + let foreign_call_result = foreign_call_result + .get_brillig_output() + .unwrap_or(ForeignCallResult::default()); if let Some(mut solver) = self.brillig_solver.take() { solver.resolve_pending_foreign_call(foreign_call_result); self.brillig_solver = Some(solver); @@ -323,7 +395,8 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> { } } - pub(super) fn next(&mut self) -> DebugCommandResult { + /// Steps debugging execution until the next source location + pub(super) fn next_into(&mut self) -> DebugCommandResult { let start_location = self.get_current_source_location(); loop { let result = self.step_into_opcode(); @@ -337,6 +410,38 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> { } } + /// Steps debugging execution until the next source location at the same (or + /// less) call stack depth (eg. don't dive into function calls) + pub(super) fn next_over(&mut self) -> DebugCommandResult { + let start_call_stack = self.get_source_call_stack(); + loop { + let result = self.next_into(); + if !matches!(result, DebugCommandResult::Ok) { + return result; + } + let new_call_stack = self.get_source_call_stack(); + if new_call_stack.len() <= start_call_stack.len() { + return DebugCommandResult::Ok; + } + } + } + + /// Steps debugging execution until the next source location with a smaller + /// call stack depth (eg. returning from the current function) + pub(super) fn next_out(&mut self) -> DebugCommandResult { + let start_call_stack = self.get_source_call_stack(); + loop { + let result = self.next_into(); + if !matches!(result, DebugCommandResult::Ok) { + return result; + } + let new_call_stack = self.get_source_call_stack(); + if new_call_stack.len() < start_call_stack.len() { + return DebugCommandResult::Ok; + } + } + } + pub(super) fn cont(&mut self) -> DebugCommandResult { loop { let result = self.step_into_opcode(); @@ -362,6 +467,10 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> { } } + pub(super) fn get_variables(&self) -> Vec<(&str, &PrintableValue, &PrintableType)> { + return self.foreign_call_executor.get_variables(); + } + fn breakpoint_reached(&self) -> bool { if let Some(location) = self.get_current_opcode_location() { self.breakpoints.contains(&location) @@ -422,6 +531,7 @@ mod tests { use super::*; use crate::context::{DebugCommandResult, DebugContext}; + use crate::foreign_calls::DefaultDebugForeignCallExecutor; use acvm::{ acir::{ circuit::{ @@ -435,7 +545,7 @@ mod tests { BinaryFieldOp, HeapValueType, MemoryAddress, Opcode as BrilligOpcode, ValueOrArray, }, }; - use nargo::{artifacts::debug::DebugArtifact, ops::DefaultForeignCallExecutor}; + use nargo::artifacts::debug::DebugArtifact; use std::collections::BTreeMap; #[test] @@ -483,12 +593,14 @@ mod tests { let initial_witness = BTreeMap::from([(Witness(1), fe_1)]).into(); + let foreign_call_executor = + Box::new(DefaultDebugForeignCallExecutor::from_artifact(true, debug_artifact)); let mut context = DebugContext::new( &StubbedBlackBoxSolver, circuit, debug_artifact, initial_witness, - Box::new(DefaultForeignCallExecutor::new(true, None)), + foreign_call_executor, ); assert_eq!(context.get_current_opcode_location(), Some(OpcodeLocation::Acir(0))); @@ -588,12 +700,14 @@ mod tests { let initial_witness = BTreeMap::from([(Witness(1), fe_1), (Witness(2), fe_1)]).into(); + let foreign_call_executor = + Box::new(DefaultDebugForeignCallExecutor::from_artifact(true, debug_artifact)); let mut context = DebugContext::new( &StubbedBlackBoxSolver, circuit, debug_artifact, initial_witness, - Box::new(DefaultForeignCallExecutor::new(true, None)), + foreign_call_executor, ); // set breakpoint @@ -650,7 +764,7 @@ mod tests { &circuit, &debug_artifact, WitnessMap::new(), - Box::new(DefaultForeignCallExecutor::new(true, None)), + Box::new(DefaultDebugForeignCallExecutor::new(true)), ); assert_eq!(context.offset_opcode_location(&None, 0), (None, 0)); diff --git a/noir/tooling/debugger/src/dap.rs b/noir/tooling/debugger/src/dap.rs index 803f9f108db..dd9a30d50da 100644 --- a/noir/tooling/debugger/src/dap.rs +++ b/noir/tooling/debugger/src/dap.rs @@ -9,6 +9,7 @@ use codespan_reporting::files::{Files, SimpleFile}; use crate::context::DebugCommandResult; use crate::context::DebugContext; +use crate::foreign_calls::DefaultDebugForeignCallExecutor; use dap::errors::ServerError; use dap::events::StoppedEventBody; @@ -17,15 +18,14 @@ use dap::requests::{Command, Request, SetBreakpointsArguments}; use dap::responses::{ ContinueResponse, DisassembleResponse, ResponseBody, ScopesResponse, SetBreakpointsResponse, SetExceptionBreakpointsResponse, SetInstructionBreakpointsResponse, StackTraceResponse, - ThreadsResponse, + ThreadsResponse, VariablesResponse, }; use dap::server::Server; use dap::types::{ - Breakpoint, DisassembledInstruction, Source, StackFrame, SteppingGranularity, - StoppedEventReason, Thread, + Breakpoint, DisassembledInstruction, Scope, Source, StackFrame, SteppingGranularity, + StoppedEventReason, Thread, Variable, }; use nargo::artifacts::debug::DebugArtifact; -use nargo::ops::DefaultForeignCallExecutor; use fm::FileId; use noirc_driver::CompiledProgram; @@ -41,6 +41,22 @@ pub struct DapSession<'a, R: Read, W: Write, B: BlackBoxFunctionSolver> { source_breakpoints: BTreeMap>, } +enum ScopeReferences { + Locals = 1, + WitnessMap = 2, + InvalidScope = 0, +} + +impl From for ScopeReferences { + fn from(value: i64) -> Self { + match value { + 1 => Self::Locals, + 2 => Self::WitnessMap, + _ => Self::InvalidScope, + } + } +} + // BTreeMap impl<'a, R: Read, W: Write, B: BlackBoxFunctionSolver> DapSession<'a, R, W, B> { @@ -57,7 +73,7 @@ impl<'a, R: Read, W: Write, B: BlackBoxFunctionSolver> DapSession<'a, R, W, B> { circuit, debug_artifact, initial_witness, - Box::new(DefaultForeignCallExecutor::new(true, None)), + Box::new(DefaultDebugForeignCallExecutor::from_artifact(true, debug_artifact)), ); Self { server, @@ -125,14 +141,14 @@ impl<'a, R: Read, W: Write, B: BlackBoxFunctionSolver> DapSession<'a, R, W, B> { } pub fn run_loop(&mut self) -> Result<(), ServerError> { - self.running = true; + self.running = self.context.get_current_opcode_location().is_some(); - if matches!(self.context.get_current_source_location(), None) { + if self.running && matches!(self.context.get_current_source_location(), None) { // TODO: remove this? This is to ensure that the tool has a proper // source location to show when first starting the debugger, but // maybe the default behavior should be to start executing until the // first breakpoint set. - _ = self.context.next(); + _ = self.context.next_into(); } self.server.send_event(Event::Initialized)?; @@ -176,7 +192,7 @@ impl<'a, R: Read, W: Write, B: BlackBoxFunctionSolver> DapSession<'a, R, W, B> { args.granularity.as_ref().unwrap_or(&SteppingGranularity::Statement); match granularity { SteppingGranularity::Instruction => self.handle_step(req)?, - _ => self.handle_next(req)?, + _ => self.handle_next_into(req)?, } } Command::StepOut(ref args) => { @@ -184,7 +200,7 @@ impl<'a, R: Read, W: Write, B: BlackBoxFunctionSolver> DapSession<'a, R, W, B> { args.granularity.as_ref().unwrap_or(&SteppingGranularity::Statement); match granularity { SteppingGranularity::Instruction => self.handle_step(req)?, - _ => self.handle_next(req)?, + _ => self.handle_next_out(req)?, } } Command::Next(ref args) => { @@ -192,18 +208,17 @@ impl<'a, R: Read, W: Write, B: BlackBoxFunctionSolver> DapSession<'a, R, W, B> { args.granularity.as_ref().unwrap_or(&SteppingGranularity::Statement); match granularity { SteppingGranularity::Instruction => self.handle_step(req)?, - _ => self.handle_next(req)?, + _ => self.handle_next_over(req)?, } } Command::Continue(_) => { self.handle_continue(req)?; } Command::Scopes(_) => { - // FIXME: this needs a proper implementation when we can - // show the parameters and variables - self.server.respond( - req.success(ResponseBody::Scopes(ScopesResponse { scopes: vec![] })), - )?; + self.handle_scopes(req)?; + } + Command::Variables(ref _args) => { + self.handle_variables(req)?; } _ => { eprintln!("ERROR: unhandled command: {:?}", req.command); @@ -213,37 +228,38 @@ impl<'a, R: Read, W: Write, B: BlackBoxFunctionSolver> DapSession<'a, R, W, B> { Ok(()) } + fn build_stack_trace(&self) -> Vec { + self.context + .get_source_call_stack() + .iter() + .enumerate() + .map(|(index, (opcode_location, source_location))| { + let line_number = + self.debug_artifact.location_line_number(*source_location).unwrap(); + let column_number = + self.debug_artifact.location_column_number(*source_location).unwrap(); + StackFrame { + id: index as i64, + name: format!("frame #{index}"), + source: Some(Source { + path: self.debug_artifact.file_map[&source_location.file] + .path + .to_str() + .map(String::from), + ..Source::default() + }), + line: line_number as i64, + column: column_number as i64, + instruction_pointer_reference: Some(opcode_location.to_string()), + ..StackFrame::default() + } + }) + .rev() + .collect() + } + fn handle_stack_trace(&mut self, req: Request) -> Result<(), ServerError> { - let opcode_location = self.context.get_current_opcode_location(); - let source_location = self.context.get_current_source_location(); - let frames = match source_location { - None => vec![], - Some(locations) => locations - .iter() - .enumerate() - .map(|(index, location)| { - let line_number = self.debug_artifact.location_line_number(*location).unwrap(); - let column_number = - self.debug_artifact.location_column_number(*location).unwrap(); - let ip_reference = opcode_location.map(|location| location.to_string()); - StackFrame { - id: index as i64, - name: format!("frame #{index}"), - source: Some(Source { - path: self.debug_artifact.file_map[&location.file] - .path - .to_str() - .map(String::from), - ..Source::default() - }), - line: line_number as i64, - column: column_number as i64, - instruction_pointer_reference: ip_reference, - ..StackFrame::default() - } - }) - .collect(), - }; + let frames = self.build_stack_trace(); let total_frames = Some(frames.len() as i64); self.server.respond(req.success(ResponseBody::StackTrace(StackTraceResponse { stack_frames: frames, @@ -315,9 +331,23 @@ impl<'a, R: Read, W: Write, B: BlackBoxFunctionSolver> DapSession<'a, R, W, B> { self.handle_execution_result(result) } - fn handle_next(&mut self, req: Request) -> Result<(), ServerError> { - let result = self.context.next(); - eprintln!("INFO: stepped by statement with result {result:?}"); + fn handle_next_into(&mut self, req: Request) -> Result<(), ServerError> { + let result = self.context.next_into(); + eprintln!("INFO: stepped into by statement with result {result:?}"); + self.server.respond(req.ack()?)?; + self.handle_execution_result(result) + } + + fn handle_next_out(&mut self, req: Request) -> Result<(), ServerError> { + let result = self.context.next_out(); + eprintln!("INFO: stepped out by statement with result {result:?}"); + self.server.respond(req.ack()?)?; + self.handle_execution_result(result) + } + + fn handle_next_over(&mut self, req: Request) -> Result<(), ServerError> { + let result = self.context.next_over(); + eprintln!("INFO: stepped over by statement with result {result:?}"); self.server.respond(req.ack()?)?; self.handle_execution_result(result) } @@ -548,6 +578,73 @@ impl<'a, R: Read, W: Write, B: BlackBoxFunctionSolver> DapSession<'a, R, W, B> { )?; Ok(()) } + + fn handle_scopes(&mut self, req: Request) -> Result<(), ServerError> { + self.server.respond(req.success(ResponseBody::Scopes(ScopesResponse { + scopes: vec![ + Scope { + name: String::from("Locals"), + variables_reference: ScopeReferences::Locals as i64, + ..Scope::default() + }, + Scope { + name: String::from("Witness Map"), + variables_reference: ScopeReferences::WitnessMap as i64, + ..Scope::default() + }, + ], + })))?; + Ok(()) + } + + fn build_local_variables(&self) -> Vec { + let mut variables: Vec<_> = self + .context + .get_variables() + .iter() + .map(|(name, value, _var_type)| Variable { + name: String::from(*name), + value: format!("{:?}", *value), + ..Variable::default() + }) + .collect(); + variables.sort_by(|a, b| a.name.partial_cmp(&b.name).unwrap()); + variables + } + + fn build_witness_map(&self) -> Vec { + self.context + .get_witness_map() + .clone() + .into_iter() + .map(|(witness, value)| Variable { + name: format!("_{}", witness.witness_index()), + value: format!("{value:?}"), + ..Variable::default() + }) + .collect() + } + + fn handle_variables(&mut self, req: Request) -> Result<(), ServerError> { + let Command::Variables(ref args) = req.command else { + unreachable!("handle_variables called on a different request"); + }; + let scope: ScopeReferences = args.variables_reference.into(); + let variables: Vec<_> = match scope { + ScopeReferences::Locals => self.build_local_variables(), + ScopeReferences::WitnessMap => self.build_witness_map(), + _ => { + eprintln!( + "handle_variables with an unknown variables_reference {}", + args.variables_reference + ); + vec![] + } + }; + self.server + .respond(req.success(ResponseBody::Variables(VariablesResponse { variables })))?; + Ok(()) + } } pub fn run_session( diff --git a/noir/tooling/debugger/src/foreign_calls.rs b/noir/tooling/debugger/src/foreign_calls.rs new file mode 100644 index 00000000000..01676adfef3 --- /dev/null +++ b/noir/tooling/debugger/src/foreign_calls.rs @@ -0,0 +1,138 @@ +use acvm::{ + acir::brillig::{ForeignCallParam, ForeignCallResult, Value}, + pwg::ForeignCallWaitInfo, +}; +use nargo::{ + artifacts::debug::{DebugArtifact, DebugVars}, + ops::{DefaultForeignCallExecutor, ForeignCallExecutor, NargoForeignCallResult}, +}; +use noirc_errors::debug_info::DebugVarId; +use noirc_printable_type::{ForeignCallError, PrintableType, PrintableValue}; + +pub(crate) enum DebugForeignCall { + VarAssign, + VarDrop, + MemberAssign(u32), + DerefAssign, +} + +impl DebugForeignCall { + pub(crate) fn lookup(op_name: &str) -> Option { + let member_pre = "__debug_member_assign_"; + if let Some(op_suffix) = op_name.strip_prefix(member_pre) { + let arity = + op_suffix.parse::().expect("failed to parse debug_member_assign arity"); + return Some(DebugForeignCall::MemberAssign(arity)); + } + match op_name { + "__debug_var_assign" => Some(DebugForeignCall::VarAssign), + "__debug_var_drop" => Some(DebugForeignCall::VarDrop), + "__debug_deref_assign" => Some(DebugForeignCall::DerefAssign), + _ => None, + } + } +} + +pub trait DebugForeignCallExecutor: ForeignCallExecutor { + fn get_variables(&self) -> Vec<(&str, &PrintableValue, &PrintableType)>; +} + +pub struct DefaultDebugForeignCallExecutor { + executor: DefaultForeignCallExecutor, + pub debug_vars: DebugVars, +} + +impl DefaultDebugForeignCallExecutor { + pub fn new(show_output: bool) -> Self { + Self { + executor: DefaultForeignCallExecutor::new(show_output, None), + debug_vars: DebugVars::default(), + } + } + + pub fn from_artifact(show_output: bool, artifact: &DebugArtifact) -> Self { + let mut ex = Self::new(show_output); + ex.load_artifact(artifact); + ex + } + + pub fn load_artifact(&mut self, artifact: &DebugArtifact) { + artifact.debug_symbols.iter().for_each(|info| { + self.debug_vars.insert_variables(&info.variables); + self.debug_vars.insert_types(&info.types); + }); + } +} + +impl DebugForeignCallExecutor for DefaultDebugForeignCallExecutor { + fn get_variables(&self) -> Vec<(&str, &PrintableValue, &PrintableType)> { + self.debug_vars.get_variables() + } +} + +fn debug_var_id(value: &Value) -> DebugVarId { + DebugVarId(value.to_u128() as u32) +} + +impl ForeignCallExecutor for DefaultDebugForeignCallExecutor { + fn execute( + &mut self, + foreign_call: &ForeignCallWaitInfo, + ) -> Result { + let foreign_call_name = foreign_call.function.as_str(); + match DebugForeignCall::lookup(foreign_call_name) { + Some(DebugForeignCall::VarAssign) => { + let fcp_var_id = &foreign_call.inputs[0]; + if let ForeignCallParam::Single(var_id_value) = fcp_var_id { + let var_id = debug_var_id(var_id_value); + let values: Vec = + foreign_call.inputs[1..].iter().flat_map(|x| x.values()).collect(); + self.debug_vars.assign_var(var_id, &values); + } + Ok(ForeignCallResult::default().into()) + } + Some(DebugForeignCall::VarDrop) => { + let fcp_var_id = &foreign_call.inputs[0]; + if let ForeignCallParam::Single(var_id_value) = fcp_var_id { + let var_id = debug_var_id(var_id_value); + self.debug_vars.drop_var(var_id); + } + Ok(ForeignCallResult::default().into()) + } + Some(DebugForeignCall::MemberAssign(arity)) => { + if let Some(ForeignCallParam::Single(var_id_value)) = foreign_call.inputs.get(0) { + let arity = arity as usize; + let var_id = debug_var_id(var_id_value); + let n = foreign_call.inputs.len(); + let indexes: Vec = foreign_call.inputs[(n - arity)..n] + .iter() + .map(|fcp_v| { + if let ForeignCallParam::Single(v) = fcp_v { + v.to_u128() as u32 + } else { + panic!("expected ForeignCallParam::Single(v)"); + } + }) + .collect(); + let values: Vec = (0..n - 1 - arity) + .flat_map(|i| { + foreign_call.inputs.get(1 + i).map(|fci| fci.values()).unwrap_or(vec![]) + }) + .collect(); + self.debug_vars.assign_field(var_id, indexes, &values); + } + Ok(ForeignCallResult::default().into()) + } + Some(DebugForeignCall::DerefAssign) => { + let fcp_var_id = &foreign_call.inputs[0]; + let fcp_value = &foreign_call.inputs[1]; + if let ForeignCallParam::Single(var_id_value) = fcp_var_id { + let var_id = debug_var_id(var_id_value); + self.debug_vars.assign_deref(var_id, &fcp_value.values()); + } + Ok(ForeignCallResult::default().into()) + } + None => self.executor.execute(foreign_call), + } + } +} diff --git a/noir/tooling/debugger/src/lib.rs b/noir/tooling/debugger/src/lib.rs index 21834e44f93..35014f9a8c8 100644 --- a/noir/tooling/debugger/src/lib.rs +++ b/noir/tooling/debugger/src/lib.rs @@ -1,5 +1,6 @@ mod context; mod dap; +mod foreign_calls; mod repl; mod source_code_printer; diff --git a/noir/tooling/debugger/src/repl.rs b/noir/tooling/debugger/src/repl.rs index 92224ab785a..8441dbde9be 100644 --- a/noir/tooling/debugger/src/repl.rs +++ b/noir/tooling/debugger/src/repl.rs @@ -4,9 +4,11 @@ use acvm::acir::circuit::{Circuit, Opcode, OpcodeLocation}; use acvm::acir::native_types::{Witness, WitnessMap}; use acvm::{BlackBoxFunctionSolver, FieldElement}; -use nargo::{artifacts::debug::DebugArtifact, ops::DefaultForeignCallExecutor, NargoError}; +use crate::foreign_calls::DefaultDebugForeignCallExecutor; +use nargo::{artifacts::debug::DebugArtifact, NargoError}; use easy_repl::{command, CommandStatus, Repl}; +use noirc_printable_type::PrintableValueDisplay; use std::cell::RefCell; use crate::source_code_printer::print_source_code_location; @@ -27,21 +29,22 @@ impl<'a, B: BlackBoxFunctionSolver> ReplDebugger<'a, B> { debug_artifact: &'a DebugArtifact, initial_witness: WitnessMap, ) -> Self { + let foreign_call_executor = + Box::new(DefaultDebugForeignCallExecutor::from_artifact(true, debug_artifact)); let context = DebugContext::new( blackbox_solver, circuit, debug_artifact, initial_witness.clone(), - Box::new(DefaultForeignCallExecutor::new(true, None)), + foreign_call_executor, ); - Self { - context, - blackbox_solver, - circuit, - debug_artifact, - initial_witness, - last_result: DebugCommandResult::Ok, - } + let last_result = if context.get_current_opcode_location().is_none() { + // handle circuit with no opcodes + DebugCommandResult::Done + } else { + DebugCommandResult::Ok + }; + Self { context, blackbox_solver, circuit, debug_artifact, initial_witness, last_result } } pub fn show_current_vm_status(&self) { @@ -73,10 +76,45 @@ impl<'a, B: BlackBoxFunctionSolver> ReplDebugger<'a, B> { ); } } + let locations = self.context.get_source_location_for_opcode_location(&location); + print_source_code_location(self.debug_artifact, &locations); + } + } + } - print_source_code_location(self.debug_artifact, &location); + fn show_stack_frame(&self, index: usize, location: &OpcodeLocation) { + let opcodes = self.context.get_opcodes(); + match location { + OpcodeLocation::Acir(instruction_pointer) => { + println!( + "Frame #{index}, opcode {}: {}", + instruction_pointer, opcodes[*instruction_pointer] + ) + } + OpcodeLocation::Brillig { acir_index, brillig_index } => { + let Opcode::Brillig(ref brillig) = opcodes[*acir_index] else { + unreachable!("Brillig location does not contain a Brillig block"); + }; + println!( + "Frame #{index}, opcode {}.{}: {:?}", + acir_index, brillig_index, brillig.bytecode[*brillig_index] + ); } } + let locations = self.context.get_source_location_for_opcode_location(location); + print_source_code_location(self.debug_artifact, &locations); + } + + pub fn show_current_call_stack(&self) { + let call_stack = self.context.get_call_stack(); + if call_stack.is_empty() { + println!("Finished execution. Call stack empty."); + return; + } + + for (i, frame_location) in call_stack.iter().enumerate() { + self.show_stack_frame(i, frame_location); + } } fn display_opcodes(&self) { @@ -193,9 +231,23 @@ impl<'a, B: BlackBoxFunctionSolver> ReplDebugger<'a, B> { } } - fn next(&mut self) { + fn next_into(&mut self) { + if self.validate_in_progress() { + let result = self.context.next_into(); + self.handle_debug_command_result(result); + } + } + + fn next_over(&mut self) { if self.validate_in_progress() { - let result = self.context.next(); + let result = self.context.next_over(); + self.handle_debug_command_result(result); + } + } + + fn next_out(&mut self) { + if self.validate_in_progress() { + let result = self.context.next_out(); self.handle_debug_command_result(result); } } @@ -211,12 +263,14 @@ impl<'a, B: BlackBoxFunctionSolver> ReplDebugger<'a, B> { fn restart_session(&mut self) { let breakpoints: Vec = self.context.iterate_breakpoints().copied().collect(); + let foreign_call_executor = + Box::new(DefaultDebugForeignCallExecutor::from_artifact(true, self.debug_artifact)); self.context = DebugContext::new( self.blackbox_solver, self.circuit, self.debug_artifact, self.initial_witness.clone(), - Box::new(DefaultForeignCallExecutor::new(true, None)), + foreign_call_executor, ); for opcode_location in breakpoints { self.context.add_breakpoint(opcode_location); @@ -282,6 +336,15 @@ impl<'a, B: BlackBoxFunctionSolver> ReplDebugger<'a, B> { self.context.write_brillig_memory(index, field_value); } + pub fn show_vars(&self) { + let vars = self.context.get_variables(); + for (var_name, value, var_type) in vars.iter() { + let printable_value = + PrintableValueDisplay::Plain((*value).clone(), (*var_type).clone()); + println!("{var_name}:{var_type:?} = {}", printable_value); + } + } + fn is_solved(&self) -> bool { self.context.is_solved() } @@ -329,11 +392,31 @@ pub fn run( command! { "step until a new source location is reached", () => || { - ref_context.borrow_mut().next(); + ref_context.borrow_mut().next_into(); Ok(CommandStatus::Done) } }, ) + .add( + "over", + command! { + "step until a new source location is reached without diving into function calls", + () => || { + ref_context.borrow_mut().next_over(); + Ok(CommandStatus::Done) + } + } + ) + .add( + "out", + command! { + "step until a new source location is reached and the current stack frame is finished", + () => || { + ref_context.borrow_mut().next_out(); + Ok(CommandStatus::Done) + } + } + ) .add( "continue", command! { @@ -434,6 +517,26 @@ pub fn run( } }, ) + .add( + "stacktrace", + command! { + "display the current stack trace", + () => || { + ref_context.borrow().show_current_call_stack(); + Ok(CommandStatus::Done) + } + }, + ) + .add( + "vars", + command! { + "show variable values available at this point in execution", + () => || { + ref_context.borrow_mut().show_vars(); + Ok(CommandStatus::Done) + } + }, + ) .build() .expect("Failed to initialize debugger repl"); diff --git a/noir/tooling/debugger/src/source_code_printer.rs b/noir/tooling/debugger/src/source_code_printer.rs index 1707f9066b7..b5ffdb12d01 100644 --- a/noir/tooling/debugger/src/source_code_printer.rs +++ b/noir/tooling/debugger/src/source_code_printer.rs @@ -1,4 +1,3 @@ -use acvm::acir::circuit::OpcodeLocation; use codespan_reporting::files::Files; use nargo::artifacts::debug::DebugArtifact; use noirc_errors::Location; @@ -31,13 +30,7 @@ struct LocationPrintContext { // Given a DebugArtifact and an OpcodeLocation, prints all the source code // locations the OpcodeLocation maps to, with some surrounding context and // visual aids to highlight the location itself. -pub(crate) fn print_source_code_location( - debug_artifact: &DebugArtifact, - location: &OpcodeLocation, -) { - let locations = debug_artifact.debug_symbols[0].opcode_location(location); - let Some(locations) = locations else { return; }; - +pub(crate) fn print_source_code_location(debug_artifact: &DebugArtifact, locations: &[Location]) { let locations = locations.iter(); for loc in locations { @@ -276,7 +269,8 @@ mod tests { let mut opcode_locations = BTreeMap::>::new(); opcode_locations.insert(OpcodeLocation::Acir(42), vec![loc]); - let debug_symbols = vec![DebugInfo::new(opcode_locations)]; + let debug_symbols = + vec![DebugInfo::new(opcode_locations, BTreeMap::default(), BTreeMap::default())]; let debug_artifact = DebugArtifact::new(debug_symbols, &fm); let location_rendered: Vec<_> = render_location(&debug_artifact, &loc).collect(); diff --git a/noir/tooling/debugger/tests/debug.rs b/noir/tooling/debugger/tests/debug.rs index e8b17b8a7af..4cb678192b8 100644 --- a/noir/tooling/debugger/tests/debug.rs +++ b/noir/tooling/debugger/tests/debug.rs @@ -5,8 +5,6 @@ mod tests { use rexpect::spawn_bash; - test_binary::build_test_binary_once!(mock_backend, "../backend_interface/test-binaries"); - // include tests generated by `build.rs` include!(concat!(env!("OUT_DIR"), "/debug.rs")); @@ -14,20 +12,20 @@ mod tests { let nargo_bin = cargo_bin("nargo").into_os_string().into_string().expect("Cannot parse nargo path"); - let mock_backend_path = - path_to_mock_backend().into_string().expect("Cannot parse mock_backend path"); - let mut dbg_session = spawn_bash(Some(10000)).expect("Could not start bash session"); + // Set backend to `/dev/null` to force an error if nargo tries to speak to a backend. dbg_session - .send_line(&format!("export NARGO_BACKEND_PATH={}", mock_backend_path)) + .send_line("export NARGO_BACKEND_PATH=/dev/null") .expect("Could not export NARGO_BACKEND_PATH."); dbg_session.wait_for_prompt().expect("Could not export NARGO_BACKEND_PATH."); // Start debugger and test that it loads for the given program. dbg_session .execute( - &format!("{} debug --program-dir {}", nargo_bin, test_program_dir), + &format!( + "{nargo_bin} debug --program-dir {test_program_dir} --force-brillig --expression-width 3" + ), ".*\\Starting debugger.*", ) .expect("Could not start debugger"); diff --git a/noir/tooling/lsp/src/requests/test_run.rs b/noir/tooling/lsp/src/requests/test_run.rs index 135090d7ed9..0b88d814265 100644 --- a/noir/tooling/lsp/src/requests/test_run.rs +++ b/noir/tooling/lsp/src/requests/test_run.rs @@ -83,7 +83,7 @@ fn on_test_run_request_inner( let test_result = run_test( &state.solver, - &context, + &mut context, test_function, false, None, diff --git a/noir/tooling/nargo/Cargo.toml b/noir/tooling/nargo/Cargo.toml index cd97980b9e0..efd38a182e0 100644 --- a/noir/tooling/nargo/Cargo.toml +++ b/noir/tooling/nargo/Cargo.toml @@ -36,4 +36,3 @@ jsonrpc-http-server = "18.0" jsonrpc-core-client = "18.0" jsonrpc-derive = "18.0" jsonrpc-core = "18.0" -serial_test = "2.0" diff --git a/noir/tooling/nargo/src/artifacts/debug.rs b/noir/tooling/nargo/src/artifacts/debug.rs index 2e2d98f279e..a249ecb03ad 100644 --- a/noir/tooling/nargo/src/artifacts/debug.rs +++ b/noir/tooling/nargo/src/artifacts/debug.rs @@ -8,6 +8,7 @@ use std::{ ops::Range, }; +pub use super::debug_vars::DebugVars; use fm::{FileId, FileManager, PathString}; /// A Debug Artifact stores, for a given program, the debug info for every function @@ -86,7 +87,8 @@ impl DebugArtifact { let line_index = self.line_index(location.file, location_start)?; let line_span = self.line_range(location.file, line_index)?; - let line_length = line_span.end - (line_span.start + 1); + let line_length = + if line_span.end > line_span.start { line_span.end - (line_span.start + 1) } else { 0 }; let start_in_line = location_start - line_span.start; // The location might continue beyond the line, @@ -229,7 +231,8 @@ mod tests { let mut opcode_locations = BTreeMap::>::new(); opcode_locations.insert(OpcodeLocation::Acir(42), vec![loc]); - let debug_symbols = vec![DebugInfo::new(opcode_locations)]; + let debug_symbols = + vec![DebugInfo::new(opcode_locations, BTreeMap::default(), BTreeMap::default())]; let debug_artifact = DebugArtifact::new(debug_symbols, &fm); let location_in_line = debug_artifact.location_in_line(loc).expect("Expected a range"); diff --git a/noir/tooling/nargo/src/artifacts/debug_vars.rs b/noir/tooling/nargo/src/artifacts/debug_vars.rs new file mode 100644 index 00000000000..b5559ca53c8 --- /dev/null +++ b/noir/tooling/nargo/src/artifacts/debug_vars.rs @@ -0,0 +1,117 @@ +use acvm::brillig_vm::brillig::Value; +use noirc_errors::debug_info::{ + DebugTypeId, DebugTypes, DebugVarId, DebugVariable, DebugVariables, +}; +use noirc_printable_type::{decode_value, PrintableType, PrintableValue}; +use std::collections::{HashMap, HashSet}; + +#[derive(Debug, Default, Clone)] +pub struct DebugVars { + variables: HashMap, + types: HashMap, + active: HashSet, + values: HashMap, +} + +impl DebugVars { + pub fn get_variables(&self) -> Vec<(&str, &PrintableValue, &PrintableType)> { + self.active + .iter() + .filter_map(|var_id| { + self.variables + .get(var_id) + .and_then(|debug_var| { + let Some(value) = self.values.get(var_id) else { return None; }; + let Some(ptype) = self.types.get(&debug_var.debug_type_id) else { return None; }; + Some((debug_var.name.as_str(), value, ptype)) + }) + }) + .collect() + } + + pub fn insert_variables(&mut self, vars: &DebugVariables) { + self.variables.extend(vars.clone().into_iter()); + } + + pub fn insert_types(&mut self, types: &DebugTypes) { + self.types.extend(types.clone().into_iter()); + } + + pub fn assign_var(&mut self, var_id: DebugVarId, values: &[Value]) { + self.active.insert(var_id); + let type_id = &self.variables.get(&var_id).unwrap().debug_type_id; + let ptype = self.types.get(type_id).unwrap(); + self.values.insert(var_id, decode_value(&mut values.iter().map(|v| v.to_field()), ptype)); + } + + pub fn assign_field(&mut self, var_id: DebugVarId, indexes: Vec, values: &[Value]) { + let mut cursor: &mut PrintableValue = self + .values + .get_mut(&var_id) + .unwrap_or_else(|| panic!("value unavailable for var_id {var_id:?}")); + let cursor_type_id = &self + .variables + .get(&var_id) + .unwrap_or_else(|| panic!("variable {var_id:?} not found")) + .debug_type_id; + let mut cursor_type = self + .types + .get(cursor_type_id) + .unwrap_or_else(|| panic!("type unavailable for type id {cursor_type_id:?}")); + for index in indexes.iter() { + (cursor, cursor_type) = match (cursor, cursor_type) { + (PrintableValue::Vec(array), PrintableType::Array { length, typ }) => { + if let Some(len) = length { + if *index as u64 >= *len { + panic!("unexpected field index past array length") + } + if *len != array.len() as u64 { + panic!("type/array length mismatch") + } + } + (array.get_mut(*index as usize).unwrap(), &*Box::leak(typ.clone())) + } + ( + PrintableValue::Struct(field_map), + PrintableType::Struct { name: _name, fields }, + ) => { + if *index as usize >= fields.len() { + panic!("unexpected field index past struct field length") + } + let (key, typ) = fields.get(*index as usize).unwrap(); + (field_map.get_mut(key).unwrap(), typ) + } + (PrintableValue::Vec(array), PrintableType::Tuple { types }) => { + if *index >= types.len() as u32 { + panic!( + "unexpected field index ({index}) past tuple length ({})", + types.len() + ); + } + if types.len() != array.len() { + panic!("type/array length mismatch") + } + let typ = types.get(*index as usize).unwrap(); + (array.get_mut(*index as usize).unwrap(), typ) + } + _ => { + panic!("unexpected assign field of {cursor_type:?} type"); + } + }; + } + *cursor = decode_value(&mut values.iter().map(|v| v.to_field()), cursor_type); + self.active.insert(var_id); + } + + pub fn assign_deref(&mut self, _var_id: DebugVarId, _values: &[Value]) { + unimplemented![] + } + + pub fn get_type(&self, var_id: DebugVarId) -> Option<&PrintableType> { + self.variables.get(&var_id).and_then(|debug_var| self.types.get(&debug_var.debug_type_id)) + } + + pub fn drop_var(&mut self, var_id: DebugVarId) { + self.active.remove(&var_id); + } +} diff --git a/noir/tooling/nargo/src/artifacts/mod.rs b/noir/tooling/nargo/src/artifacts/mod.rs index 180a900fd81..c7b3736f90b 100644 --- a/noir/tooling/nargo/src/artifacts/mod.rs +++ b/noir/tooling/nargo/src/artifacts/mod.rs @@ -5,4 +5,5 @@ //! to generate them using these artifacts as a starting point. pub mod contract; pub mod debug; +mod debug_vars; pub mod program; diff --git a/noir/tooling/nargo/src/ops/compile.rs b/noir/tooling/nargo/src/ops/compile.rs index dccd2cedbf5..bd1850649c4 100644 --- a/noir/tooling/nargo/src/ops/compile.rs +++ b/noir/tooling/nargo/src/ops/compile.rs @@ -1,5 +1,8 @@ use fm::FileManager; -use noirc_driver::{CompilationResult, CompileOptions, CompiledContract, CompiledProgram}; +use noirc_driver::{ + link_to_debug_crate, CompilationResult, CompileOptions, CompiledContract, CompiledProgram, +}; +use noirc_frontend::debug::DebugInstrumenter; use noirc_frontend::hir::ParsedFiles; use crate::errors::CompileError; @@ -68,8 +71,29 @@ pub fn compile_program( package: &Package, compile_options: &CompileOptions, cached_program: Option, +) -> CompilationResult { + compile_program_with_debug_instrumenter( + file_manager, + parsed_files, + package, + compile_options, + cached_program, + DebugInstrumenter::default(), + ) +} + +pub fn compile_program_with_debug_instrumenter( + file_manager: &FileManager, + parsed_files: &ParsedFiles, + package: &Package, + compile_options: &CompileOptions, + cached_program: Option, + debug_instrumenter: DebugInstrumenter, ) -> CompilationResult { let (mut context, crate_id) = prepare_package(file_manager, parsed_files, package); + link_to_debug_crate(&mut context, crate_id); + context.debug_instrumenter = debug_instrumenter; + noirc_driver::compile_main(&mut context, crate_id, compile_options, cached_program) } diff --git a/noir/tooling/nargo/src/ops/execute.rs b/noir/tooling/nargo/src/ops/execute.rs index 4fc7f7b599f..370393fea09 100644 --- a/noir/tooling/nargo/src/ops/execute.rs +++ b/noir/tooling/nargo/src/ops/execute.rs @@ -1,3 +1,4 @@ +use acvm::brillig_vm::brillig::ForeignCallResult; use acvm::pwg::{ACVMStatus, ErrorLocation, OpcodeResolutionError, ACVM}; use acvm::BlackBoxFunctionSolver; use acvm::{acir::circuit::Circuit, acir::native_types::WitnessMap}; @@ -5,7 +6,7 @@ use acvm::{acir::circuit::Circuit, acir::native_types::WitnessMap}; use crate::errors::ExecutionError; use crate::NargoError; -use super::foreign_calls::ForeignCallExecutor; +use super::foreign_calls::{ForeignCallExecutor, NargoForeignCallResult}; #[tracing::instrument(level = "trace", skip_all)] pub fn execute_circuit( @@ -16,6 +17,8 @@ pub fn execute_circuit( ) -> Result { let mut acvm = ACVM::new(blackbox_solver, &circuit.opcodes, initial_witness); + // This message should be resolved by a nargo foreign call only when we have an unsatisfied assertion. + let mut assert_message: Option = None; loop { let solver_status = acvm.solve(); @@ -37,7 +40,13 @@ pub fn execute_circuit( return Err(NargoError::ExecutionError(match call_stack { Some(call_stack) => { - if let Some(assert_message) = circuit.get_assert_message( + // First check whether we have a runtime assertion message that should be resolved on an ACVM failure + // If we do not have a runtime assertion message, we should check whether the circuit has any hardcoded + // messages associated with a specific `OpcodeLocation`. + // Otherwise return the provided opcode resolution error. + if let Some(assert_message) = assert_message { + ExecutionError::AssertionFailed(assert_message.to_owned(), call_stack) + } else if let Some(assert_message) = circuit.get_assert_message( *call_stack.last().expect("Call stacks should not be empty"), ) { ExecutionError::AssertionFailed(assert_message.to_owned(), call_stack) @@ -50,7 +59,19 @@ pub fn execute_circuit( } ACVMStatus::RequiresForeignCall(foreign_call) => { let foreign_call_result = foreign_call_executor.execute(&foreign_call)?; - acvm.resolve_pending_foreign_call(foreign_call_result); + match foreign_call_result { + NargoForeignCallResult::BrilligOutput(foreign_call_result) => { + acvm.resolve_pending_foreign_call(foreign_call_result); + } + NargoForeignCallResult::ResolvedAssertMessage(message) => { + if assert_message.is_some() { + unreachable!("Resolving an assert message should happen only once as the VM should have failed"); + } + assert_message = Some(message); + + acvm.resolve_pending_foreign_call(ForeignCallResult::default()); + } + } } } } diff --git a/noir/tooling/nargo/src/ops/foreign_calls.rs b/noir/tooling/nargo/src/ops/foreign_calls.rs index e3a3174f8dc..f7f36c65c90 100644 --- a/noir/tooling/nargo/src/ops/foreign_calls.rs +++ b/noir/tooling/nargo/src/ops/foreign_calls.rs @@ -9,13 +9,69 @@ pub trait ForeignCallExecutor { fn execute( &mut self, foreign_call: &ForeignCallWaitInfo, - ) -> Result; + ) -> Result; +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum NargoForeignCallResult { + BrilligOutput(ForeignCallResult), + ResolvedAssertMessage(String), +} + +impl NargoForeignCallResult { + pub fn get_assert_message(self) -> Option { + match self { + Self::ResolvedAssertMessage(msg) => Some(msg), + _ => None, + } + } + + pub fn get_brillig_output(self) -> Option { + match self { + Self::BrilligOutput(foreign_call_result) => Some(foreign_call_result), + _ => None, + } + } +} + +impl From for NargoForeignCallResult { + fn from(value: ForeignCallResult) -> Self { + Self::BrilligOutput(value) + } +} + +impl From for NargoForeignCallResult { + fn from(value: String) -> Self { + Self::ResolvedAssertMessage(value) + } +} + +impl From for NargoForeignCallResult { + fn from(value: Value) -> Self { + let foreign_call_result: ForeignCallResult = value.into(); + foreign_call_result.into() + } +} + +impl From> for NargoForeignCallResult { + fn from(values: Vec) -> Self { + let foreign_call_result: ForeignCallResult = values.into(); + foreign_call_result.into() + } +} + +impl From> for NargoForeignCallResult { + fn from(values: Vec) -> Self { + let foreign_call_result: ForeignCallResult = values.into(); + foreign_call_result.into() + } } /// This enumeration represents the Brillig foreign calls that are natively supported by nargo. /// After resolution of a foreign call, nargo will restart execution of the ACVM -pub(crate) enum ForeignCall { +pub enum ForeignCall { Print, + AssertMessage, CreateMock, SetMockParams, SetMockReturns, @@ -33,6 +89,7 @@ impl ForeignCall { pub(crate) fn name(&self) -> &'static str { match self { ForeignCall::Print => "print", + ForeignCall::AssertMessage => "assert_message", ForeignCall::CreateMock => "create_mock", ForeignCall::SetMockParams => "set_mock_params", ForeignCall::SetMockReturns => "set_mock_returns", @@ -44,6 +101,7 @@ impl ForeignCall { pub(crate) fn lookup(op_name: &str) -> Option { match op_name { "print" => Some(ForeignCall::Print), + "assert_message" => Some(ForeignCall::AssertMessage), "create_mock" => Some(ForeignCall::CreateMock), "set_mock_params" => Some(ForeignCall::SetMockParams), "set_mock_returns" => Some(ForeignCall::SetMockReturns), @@ -134,29 +192,49 @@ impl DefaultForeignCallExecutor { fn execute_print(foreign_call_inputs: &[ForeignCallParam]) -> Result<(), ForeignCallError> { let skip_newline = foreign_call_inputs[0].unwrap_value().is_zero(); - let display_values: PrintableValueDisplay = foreign_call_inputs - .split_first() - .ok_or(ForeignCallError::MissingForeignCallInputs)? - .1 - .try_into()?; - print!("{display_values}{}", if skip_newline { "" } else { "\n" }); + + let foreign_call_inputs = + foreign_call_inputs.split_first().ok_or(ForeignCallError::MissingForeignCallInputs)?.1; + let display_string = Self::format_printable_value(foreign_call_inputs, skip_newline)?; + + print!("{display_string}"); + Ok(()) } + + fn execute_assert_message( + foreign_call_inputs: &[ForeignCallParam], + ) -> Result { + let display_string = Self::format_printable_value(foreign_call_inputs, true)?; + Ok(display_string.into()) + } + + fn format_printable_value( + foreign_call_inputs: &[ForeignCallParam], + skip_newline: bool, + ) -> Result { + let display_values: PrintableValueDisplay = foreign_call_inputs.try_into()?; + + let result = format!("{display_values}{}", if skip_newline { "" } else { "\n" }); + + Ok(result) + } } impl ForeignCallExecutor for DefaultForeignCallExecutor { fn execute( &mut self, foreign_call: &ForeignCallWaitInfo, - ) -> Result { + ) -> Result { let foreign_call_name = foreign_call.function.as_str(); match ForeignCall::lookup(foreign_call_name) { Some(ForeignCall::Print) => { if self.show_output { Self::execute_print(&foreign_call.inputs)?; } - Ok(ForeignCallResult { values: vec![] }) + Ok(ForeignCallResult::default().into()) } + Some(ForeignCall::AssertMessage) => Self::execute_assert_message(&foreign_call.inputs), Some(ForeignCall::CreateMock) => { let mock_oracle_name = Self::parse_string(&foreign_call.inputs[0]); assert!(ForeignCall::lookup(&mock_oracle_name).is_none()); @@ -164,7 +242,7 @@ impl ForeignCallExecutor for DefaultForeignCallExecutor { self.mocked_responses.push(MockedCall::new(id, mock_oracle_name)); self.last_mock_id += 1; - Ok(ForeignCallResult { values: vec![Value::from(id).into()] }) + Ok(Value::from(id).into()) } Some(ForeignCall::SetMockParams) => { let (id, params) = Self::extract_mock_id(&foreign_call.inputs)?; @@ -172,7 +250,7 @@ impl ForeignCallExecutor for DefaultForeignCallExecutor { .unwrap_or_else(|| panic!("Unknown mock id {}", id)) .params = Some(params.to_vec()); - Ok(ForeignCallResult { values: vec![] }) + Ok(ForeignCallResult::default().into()) } Some(ForeignCall::SetMockReturns) => { let (id, params) = Self::extract_mock_id(&foreign_call.inputs)?; @@ -180,7 +258,7 @@ impl ForeignCallExecutor for DefaultForeignCallExecutor { .unwrap_or_else(|| panic!("Unknown mock id {}", id)) .result = ForeignCallResult { values: params.to_vec() }; - Ok(ForeignCallResult { values: vec![] }) + Ok(ForeignCallResult::default().into()) } Some(ForeignCall::SetMockTimes) => { let (id, params) = Self::extract_mock_id(&foreign_call.inputs)?; @@ -194,12 +272,12 @@ impl ForeignCallExecutor for DefaultForeignCallExecutor { .unwrap_or_else(|| panic!("Unknown mock id {}", id)) .times_left = Some(times); - Ok(ForeignCallResult { values: vec![] }) + Ok(ForeignCallResult::default().into()) } Some(ForeignCall::ClearMock) => { let (id, _) = Self::extract_mock_id(&foreign_call.inputs)?; self.mocked_responses.retain(|response| response.id != id); - Ok(ForeignCallResult { values: vec![] }) + Ok(ForeignCallResult::default().into()) } None => { let mock_response_position = self @@ -222,7 +300,7 @@ impl ForeignCallExecutor for DefaultForeignCallExecutor { } } - Ok(ForeignCallResult { values: result }) + Ok(result.into()) } (None, Some(external_resolver)) => { let encoded_params: Vec<_> = @@ -235,7 +313,7 @@ impl ForeignCallExecutor for DefaultForeignCallExecutor { let parsed_response: ForeignCallResult = response.result()?; - Ok(parsed_response) + Ok(parsed_response.into()) } (None, None) => panic!("Unknown foreign call {}", foreign_call_name), } @@ -255,7 +333,6 @@ mod tests { use jsonrpc_core::Result as RpcResult; use jsonrpc_derive::rpc; use jsonrpc_http_server::{Server, ServerBuilder}; - use serial_test::serial; use crate::ops::{DefaultForeignCallExecutor, ForeignCallExecutor}; @@ -291,15 +368,15 @@ mod tests { let mut io = jsonrpc_core::IoHandler::new(); io.extend_with(OracleResolverImpl.to_delegate()); + // Choosing port 0 results in a random port being assigned. let server = ServerBuilder::new(io) - .start_http(&"127.0.0.1:5555".parse().expect("Invalid address")) + .start_http(&"127.0.0.1:0".parse().expect("Invalid address")) .expect("Could not start server"); let url = format!("http://{}", server.address()); (server, url) } - #[serial] #[test] fn test_oracle_resolver_echo() { let (server, url) = build_oracle_server(); @@ -312,12 +389,11 @@ mod tests { }; let result = executor.execute(&foreign_call); - assert_eq!(result.unwrap(), ForeignCallResult { values: foreign_call.inputs }); + assert_eq!(result.unwrap(), ForeignCallResult { values: foreign_call.inputs }.into()); server.close(); } - #[serial] #[test] fn test_oracle_resolver_sum() { let (server, url) = build_oracle_server(); diff --git a/noir/tooling/nargo/src/ops/mod.rs b/noir/tooling/nargo/src/ops/mod.rs index 4f92faa73a4..23dd0db15b9 100644 --- a/noir/tooling/nargo/src/ops/mod.rs +++ b/noir/tooling/nargo/src/ops/mod.rs @@ -1,6 +1,10 @@ -pub use self::compile::{compile_contract, compile_program, compile_workspace}; +pub use self::compile::{ + compile_contract, compile_program, compile_program_with_debug_instrumenter, compile_workspace, +}; pub use self::execute::execute_circuit; -pub use self::foreign_calls::{DefaultForeignCallExecutor, ForeignCallExecutor}; +pub use self::foreign_calls::{ + DefaultForeignCallExecutor, ForeignCall, ForeignCallExecutor, NargoForeignCallResult, +}; pub use self::optimize::{optimize_contract, optimize_program}; pub use self::transform::{transform_contract, transform_program}; diff --git a/noir/tooling/nargo/src/ops/test.rs b/noir/tooling/nargo/src/ops/test.rs index f38dcad0c2f..0929739a6ab 100644 --- a/noir/tooling/nargo/src/ops/test.rs +++ b/noir/tooling/nargo/src/ops/test.rs @@ -16,7 +16,7 @@ pub enum TestStatus { pub fn run_test( blackbox_solver: &B, - context: &Context, + context: &mut Context, test_function: TestFunction, show_output: bool, foreign_call_resolver_url: Option<&str>, diff --git a/noir/tooling/nargo_cli/Cargo.toml b/noir/tooling/nargo_cli/Cargo.toml index 6e022f090f0..57edbf5ae04 100644 --- a/noir/tooling/nargo_cli/Cargo.toml +++ b/noir/tooling/nargo_cli/Cargo.toml @@ -48,6 +48,7 @@ termcolor = "1.1.2" color-eyre = "0.6.2" tokio = { version = "1.0", features = ["io-std"] } dap.workspace = true +clap-markdown = { git = "https://github.com/noir-lang/clap-markdown", rev = "450d759532c88f0dba70891ceecdbc9ff8f25d2b", optional = true } # Backends backend-interface = { path = "../backend_interface" } @@ -83,3 +84,6 @@ harness = false [[bench]] name = "iai" harness = false + +[features] +codegen-docs = ["dep:clap-markdown"] \ No newline at end of file diff --git a/noir/tooling/nargo_cli/src/cli/dap_cmd.rs b/noir/tooling/nargo_cli/src/cli/dap_cmd.rs index f25d0ac212b..7c7e6056901 100644 --- a/noir/tooling/nargo_cli/src/cli/dap_cmd.rs +++ b/noir/tooling/nargo_cli/src/cli/dap_cmd.rs @@ -3,7 +3,7 @@ use acvm::acir::native_types::WitnessMap; use backend_interface::Backend; use clap::Args; use nargo::constants::PROVER_INPUT_FILE; -use nargo::ops::compile_program; +use nargo::ops::compile_program_with_debug_instrumenter; use nargo::workspace::Workspace; use nargo::{insert_all_files_for_workspace_into_file_manager, parse_all}; use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelection}; @@ -24,6 +24,7 @@ use dap::types::Capabilities; use serde_json::Value; use super::compile_cmd::report_errors; +use super::debug_cmd::instrument_package_files; use super::fs::inputs::read_inputs_from_file; use crate::errors::CliError; @@ -87,11 +88,21 @@ fn load_and_compile_project( let mut workspace_file_manager = file_manager_with_stdlib(std::path::Path::new("")); insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager); - let parsed_files = parse_all(&workspace_file_manager); + let mut parsed_files = parse_all(&workspace_file_manager); - let compile_options = CompileOptions::default(); - let compilation_result = - compile_program(&workspace_file_manager, &parsed_files, package, &compile_options, None); + let compile_options = + CompileOptions { instrument_debug: true, force_brillig: true, ..CompileOptions::default() }; + + let debug_state = instrument_package_files(&mut parsed_files, &workspace_file_manager, package); + + let compilation_result = compile_program_with_debug_instrumenter( + &workspace_file_manager, + &parsed_files, + package, + &compile_options, + None, + debug_state, + ); let compiled_program = report_errors( compilation_result, diff --git a/noir/tooling/nargo_cli/src/cli/debug_cmd.rs b/noir/tooling/nargo_cli/src/cli/debug_cmd.rs index a0bac3bdac1..b3ee9137530 100644 --- a/noir/tooling/nargo_cli/src/cli/debug_cmd.rs +++ b/noir/tooling/nargo_cli/src/cli/debug_cmd.rs @@ -4,9 +4,10 @@ use acvm::acir::native_types::WitnessMap; use bn254_blackbox_solver::Bn254BlackBoxSolver; use clap::Args; +use fm::FileManager; use nargo::artifacts::debug::DebugArtifact; use nargo::constants::PROVER_INPUT_FILE; -use nargo::ops::compile_program; +use nargo::ops::compile_program_with_debug_instrumenter; use nargo::package::Package; use nargo::{insert_all_files_for_workspace_into_file_manager, parse_all}; use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelection}; @@ -15,7 +16,9 @@ use noirc_abi::InputMap; use noirc_driver::{ file_manager_with_stdlib, CompileOptions, CompiledProgram, NOIR_ARTIFACT_VERSION_STRING, }; +use noirc_frontend::debug::DebugInstrumenter; use noirc_frontend::graph::CrateName; +use noirc_frontend::hir::ParsedFiles; use super::compile_cmd::report_errors; use super::fs::{inputs::read_inputs_from_file, witness::save_witness_to_dir}; @@ -46,6 +49,10 @@ pub(crate) fn run( args: DebugCommand, config: NargoConfig, ) -> Result<(), CliError> { + // Override clap default for compiler option flag + let mut args = args.clone(); + args.compile_options.instrument_debug = true; + let toml_path = get_package_manifest(&config.program_dir)?; let selection = args.package.map_or(PackageSelection::DefaultOrAll, PackageSelection::Selected); let workspace = resolve_workspace_from_toml( @@ -61,7 +68,7 @@ pub(crate) fn run( let mut workspace_file_manager = file_manager_with_stdlib(std::path::Path::new("")); insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager); - let parsed_files = parse_all(&workspace_file_manager); + let mut parsed_files = parse_all(&workspace_file_manager); let Some(package) = workspace.into_iter().find(|p| p.is_binary()) else { println!( @@ -70,12 +77,16 @@ pub(crate) fn run( return Ok(()); }; - let compilation_result = compile_program( + let debug_instrumenter = + instrument_package_files(&mut parsed_files, &workspace_file_manager, package); + + let compilation_result = compile_program_with_debug_instrumenter( &workspace_file_manager, &parsed_files, package, &args.compile_options, None, + debug_instrumenter, ); let compiled_program = report_errors( @@ -90,6 +101,36 @@ pub(crate) fn run( run_async(package, compiled_program, &args.prover_name, &args.witness_name, target_dir) } +/// Add debugging instrumentation to all parsed files belonging to the package +/// being compiled +pub(crate) fn instrument_package_files( + parsed_files: &mut ParsedFiles, + file_manager: &FileManager, + package: &Package, +) -> DebugInstrumenter { + // Start off at the entry path and read all files in the parent directory. + let entry_path_parent = package + .entry_path + .parent() + .unwrap_or_else(|| panic!("The entry path is expected to be a single file within a directory and so should have a parent {:?}", package.entry_path)) + .clone(); + + let mut debug_instrumenter = DebugInstrumenter::default(); + + for (file_id, parsed_file) in parsed_files.iter_mut() { + let file_path = + file_manager.path(*file_id).expect("Parsed file ID not found in file manager"); + for ancestor in file_path.ancestors() { + if ancestor == entry_path_parent { + // file is in package + debug_instrumenter.instrument_module(&mut parsed_file.0); + } + } + } + + debug_instrumenter +} + fn run_async( package: &Package, program: CompiledProgram, diff --git a/noir/tooling/nargo_cli/src/cli/export_cmd.rs b/noir/tooling/nargo_cli/src/cli/export_cmd.rs index feaa55857e5..96b24796a2b 100644 --- a/noir/tooling/nargo_cli/src/cli/export_cmd.rs +++ b/noir/tooling/nargo_cli/src/cli/export_cmd.rs @@ -102,7 +102,7 @@ fn compile_exported_functions( exported_functions, |(function_name, function_id)| -> Result<(String, CompiledProgram), CompileError> { // TODO: We should to refactor how to deal with compilation errors to avoid this. - let program = compile_no_check(&context, compile_options, function_id, None, false) + let program = compile_no_check(&mut context, compile_options, function_id, None, false) .map_err(|error| vec![FileDiagnostic::from(error)]); let program = report_errors( diff --git a/noir/tooling/nargo_cli/src/cli/mod.rs b/noir/tooling/nargo_cli/src/cli/mod.rs index 01adbe9da98..c080061d44f 100644 --- a/noir/tooling/nargo_cli/src/cli/mod.rs +++ b/noir/tooling/nargo_cli/src/cli/mod.rs @@ -83,6 +83,9 @@ enum NargoCommand { } pub(crate) fn start_cli() -> eyre::Result<()> { + #[cfg(feature = "codegen-docs")] + return codegen_docs(); + let NargoCli { command, mut config } = NargoCli::parse(); // If the provided `program_dir` is relative, make it absolute by joining it to the current directory. @@ -126,3 +129,10 @@ pub(crate) fn start_cli() -> eyre::Result<()> { Ok(()) } + +#[cfg(feature = "codegen-docs")] +fn codegen_docs() -> eyre::Result<()> { + let markdown: String = clap_markdown::help_markdown::(); + println!("{markdown}"); + Ok(()) +} diff --git a/noir/tooling/nargo_cli/src/cli/test_cmd.rs b/noir/tooling/nargo_cli/src/cli/test_cmd.rs index 9fee27b9172..503fd5afdd4 100644 --- a/noir/tooling/nargo_cli/src/cli/test_cmd.rs +++ b/noir/tooling/nargo_cli/src/cli/test_cmd.rs @@ -160,7 +160,7 @@ fn run_tests( let test_status = run_test( blackbox_solver, - &context, + &mut context, test_function, show_output, foreign_call_resolver_url, diff --git a/noir/tooling/nargo_fmt/src/items.rs b/noir/tooling/nargo_fmt/src/items.rs new file mode 100644 index 00000000000..7f998f45b59 --- /dev/null +++ b/noir/tooling/nargo_fmt/src/items.rs @@ -0,0 +1,117 @@ +use noirc_frontend::macros_api::Span; + +use crate::{ + utils::{comment_len, find_comment_end}, + visitor::{FmtVisitor, Shape}, +}; + +#[derive(Debug)] +pub(crate) struct Item { + pub(crate) leading: String, + pub(crate) value: String, + pub(crate) trailing: String, + pub(crate) different_line: bool, +} + +impl Item { + 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 Items<'me, T> { + visitor: &'me FmtVisitor<'me>, + shape: Shape, + elements: std::iter::Peekable>, + last_position: u32, + end_position: u32, +} + +impl<'me, T: HasItem> Items<'me, T> { + pub(crate) fn new( + visitor: &'me FmtVisitor<'me>, + shape: Shape, + span: Span, + elements: Vec, + ) -> Self { + Self { + visitor, + shape, + last_position: span.start() + 1, + end_position: span.end() - 1, + elements: elements.into_iter().peekable(), + } + } +} + +impl Iterator for Items<'_, T> { + type Item = Item; + + 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, self.shape); + let trailing = self.trailing(element_span.end(), next_start, is_last); + + Item { leading, value: expr, trailing, different_line }.into() + } +} + +impl<'me, T> Items<'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 HasItem { + fn span(&self) -> Span; + + fn format(self, visitor: &FmtVisitor, shape: Shape) -> String; + + fn start(&self) -> u32 { + self.span().start() + } + + fn end(&self) -> u32 { + self.span().end() + } +} diff --git a/noir/tooling/nargo_fmt/src/lib.rs b/noir/tooling/nargo_fmt/src/lib.rs index d731934c3c3..0a7903f0ce1 100644 --- a/noir/tooling/nargo_fmt/src/lib.rs +++ b/noir/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 items; mod rewrite; mod utils; mod visitor; diff --git a/noir/tooling/nargo_fmt/src/rewrite.rs b/noir/tooling/nargo_fmt/src/rewrite.rs index 6a95eba8759..61792c7a7fa 100644 --- a/noir/tooling/nargo_fmt/src/rewrite.rs +++ b/noir/tooling/nargo_fmt/src/rewrite.rs @@ -1,11 +1,13 @@ mod array; mod expr; +mod imports; mod infix; mod parenthesized; mod typ; pub(crate) use array::rewrite as array; pub(crate) use expr::{rewrite as expr, rewrite_sub_expr as sub_expr}; +pub(crate) use imports::UseTree; pub(crate) use infix::rewrite as infix; pub(crate) use parenthesized::rewrite as parenthesized; pub(crate) use typ::rewrite as typ; diff --git a/noir/tooling/nargo_fmt/src/rewrite/array.rs b/noir/tooling/nargo_fmt/src/rewrite/array.rs index fc5b240f83e..77e5e756f19 100644 --- a/noir/tooling/nargo_fmt/src/rewrite/array.rs +++ b/noir/tooling/nargo_fmt/src/rewrite/array.rs @@ -1,7 +1,8 @@ use noirc_frontend::{hir::resolution::errors::Span, token::Token, Expression}; use crate::{ - utils::{Expr, FindToken}, + items::Item, + utils::FindToken, visitor::{expr::NewlineMode, FmtVisitor}, }; @@ -39,12 +40,12 @@ pub(crate) fn rewrite(mut visitor: FmtVisitor, array: Vec, array_spa let (leading, _) = visitor.format_comment_in_block(leading); let (trailing, _) = visitor.format_comment_in_block(trailing); - result.push(Expr { leading, value: item, trailing, different_line: false }); + result.push(Item { leading, value: item, trailing, different_line: false }); } let slice = visitor.slice(last_position..end_position); let (comment, _) = visitor.format_comment_in_block(slice); - result.push(Expr { + result.push(Item { leading: "".into(), value: "".into(), trailing: comment, diff --git a/noir/tooling/nargo_fmt/src/rewrite/imports.rs b/noir/tooling/nargo_fmt/src/rewrite/imports.rs new file mode 100644 index 00000000000..2788f778140 --- /dev/null +++ b/noir/tooling/nargo_fmt/src/rewrite/imports.rs @@ -0,0 +1,115 @@ +use noirc_frontend::{PathKind, UseTreeKind}; + +use crate::{ + items::Item, + visitor::{ + expr::{format_exprs, Tactic}, + FmtVisitor, Shape, + }, +}; + +#[derive(Debug)] +pub(crate) enum UseSegment { + Ident(String, Option), + List(Vec), + Dep, + Crate, +} + +impl UseSegment { + fn rewrite(&self, visitor: &FmtVisitor, shape: Shape) -> String { + match self { + UseSegment::Ident(ident, None) => ident.clone(), + UseSegment::Ident(ident, Some(rename)) => format!("{ident} as {rename}"), + UseSegment::List(use_tree_list) => { + let mut nested_shape = shape; + nested_shape.indent.block_indent(visitor.config); + + let items: Vec<_> = use_tree_list + .iter() + .map(|item| Item { + leading: String::new(), + value: item.rewrite(visitor, shape).clone(), + trailing: String::new(), + different_line: false, + }) + .collect(); + + let list_str = + format_exprs(visitor.config, Tactic::Mixed, false, items, nested_shape, true); + + if list_str.contains('\n') { + format!( + "{{\n{}{list_str}\n{}}}", + nested_shape.indent.to_string(), + shape.indent.to_string() + ) + } else { + format!("{{{list_str}}}") + } + } + UseSegment::Dep => "dep".into(), + UseSegment::Crate => "crate".into(), + } + } +} + +#[derive(Debug)] +pub(crate) struct UseTree { + path: Vec, +} + +impl UseTree { + pub(crate) fn from_ast(use_tree: noirc_frontend::UseTree) -> Self { + let mut result = UseTree { path: vec![] }; + + match use_tree.prefix.kind { + PathKind::Crate => result.path.push(UseSegment::Crate), + PathKind::Dep => result.path.push(UseSegment::Dep), + PathKind::Plain => {} + }; + + result.path.extend( + use_tree + .prefix + .segments + .into_iter() + .map(|segment| UseSegment::Ident(segment.to_string(), None)), + ); + + match use_tree.kind { + UseTreeKind::Path(name, alias) => { + result.path.push(UseSegment::Ident( + name.to_string(), + alias.map(|rename| rename.to_string()), + )); + } + UseTreeKind::List(list) => { + let segment = UseSegment::List(list.into_iter().map(UseTree::from_ast).collect()); + result.path.push(segment); + } + } + + result + } + + pub(crate) fn rewrite_top_level(&self, visitor: &FmtVisitor, shape: Shape) -> String { + format!("use {};", self.rewrite(visitor, shape)) + } + + fn rewrite(&self, visitor: &FmtVisitor, shape: Shape) -> String { + let mut result = String::new(); + + let mut iter = self.path.iter().peekable(); + while let Some(segment) = iter.next() { + let segment_str = segment.rewrite(visitor, shape); + result.push_str(&segment_str); + + if iter.peek().is_some() { + result.push_str("::"); + } + } + + result + } +} diff --git a/noir/tooling/nargo_fmt/src/rewrite/typ.rs b/noir/tooling/nargo_fmt/src/rewrite/typ.rs index 4c6411e92b8..aaa77b0bea5 100644 --- a/noir/tooling/nargo_fmt/src/rewrite/typ.rs +++ b/noir/tooling/nargo_fmt/src/rewrite/typ.rs @@ -59,7 +59,7 @@ pub(crate) fn rewrite(visitor: &FmtVisitor, _shape: Shape, typ: UnresolvedType) UnresolvedTypeData::FieldElement | UnresolvedTypeData::Integer(_, _) | UnresolvedTypeData::Bool - | UnresolvedTypeData::Named(_, _) + | UnresolvedTypeData::Named(_, _, _) | UnresolvedTypeData::Unit | UnresolvedTypeData::Expression(_) | UnresolvedTypeData::String(_) diff --git a/noir/tooling/nargo_fmt/src/utils.rs b/noir/tooling/nargo_fmt/src/utils.rs index 1160f01972f..5874ebdebbc 100644 --- a/noir/tooling/nargo_fmt/src/utils.rs +++ b/noir/tooling/nargo_fmt/src/utils.rs @@ -1,3 +1,4 @@ +use crate::items::HasItem; use crate::rewrite; use crate::visitor::{FmtVisitor, Shape}; use noirc_frontend::hir::resolution::errors::Span; @@ -21,103 +22,6 @@ pub(crate) fn comments(source: &str) -> impl Iterator + '_ { }) } -#[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>, - shape: Shape, - 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>, - shape: Shape, - span: Span, - elements: Vec, - ) -> Self { - Self { - visitor, - shape, - 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, self.shape); - 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; @@ -183,7 +87,7 @@ pub(crate) fn find_comment_end(slice: &str, is_last: bool) -> usize { } } -fn comment_len(comment: &str) -> usize { +pub(crate) fn comment_len(comment: &str) -> usize { match comment { "" => 0, _ => { @@ -201,21 +105,7 @@ pub(crate) fn count_newlines(slice: &str) -> usize { bytecount::count(slice.as_bytes(), b'\n') } -pub(crate) trait Item { - fn span(&self) -> Span; - - fn format(self, visitor: &FmtVisitor, shape: Shape) -> String; - - fn start(&self) -> u32 { - self.span().start() - } - - fn end(&self) -> u32 { - self.span().end() - } -} - -impl Item for Expression { +impl HasItem for Expression { fn span(&self) -> Span { self.span } @@ -225,7 +115,7 @@ impl Item for Expression { } } -impl Item for (Ident, Expression) { +impl HasItem for (Ident, Expression) { fn span(&self) -> Span { let (name, value) = self; (name.span().start()..value.span.end()).into() @@ -245,25 +135,29 @@ impl Item for (Ident, Expression) { } } -impl Item for Param { +impl HasItem for Param { fn span(&self) -> Span { self.span } fn format(self, visitor: &FmtVisitor, shape: Shape) -> String { + let pattern = visitor.slice(self.pattern.span()); let visibility = match self.visibility { Visibility::Public => "pub ", Visibility::Private => "", Visibility::DataBus => "call_data", }; - let pattern = visitor.slice(self.pattern.span()); - let ty = rewrite::typ(visitor, shape, self.typ); - format!("{pattern}: {visibility}{ty}") + if self.pattern.is_synthesized() || self.typ.is_synthesized() { + pattern.to_string() + } else { + let ty = rewrite::typ(visitor, shape, self.typ); + format!("{pattern}: {visibility}{ty}") + } } } -impl Item for Ident { +impl HasItem for Ident { fn span(&self) -> Span { self.span() } diff --git a/noir/tooling/nargo_fmt/src/visitor.rs b/noir/tooling/nargo_fmt/src/visitor.rs index 85989db79d8..db084e5a49d 100644 --- a/noir/tooling/nargo_fmt/src/visitor.rs +++ b/noir/tooling/nargo_fmt/src/visitor.rs @@ -277,7 +277,7 @@ impl Indent { } } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, Default)] pub(crate) struct Shape { pub(crate) width: usize, pub(crate) indent: Indent, diff --git a/noir/tooling/nargo_fmt/src/visitor/expr.rs b/noir/tooling/nargo_fmt/src/visitor/expr.rs index 586d9583e32..9b36911b1af 100644 --- a/noir/tooling/nargo_fmt/src/visitor/expr.rs +++ b/noir/tooling/nargo_fmt/src/visitor/expr.rs @@ -5,8 +5,9 @@ use noirc_frontend::{ use super::{ExpressionType, FmtVisitor, Shape}; use crate::{ + items::{HasItem, Item, Items}, rewrite, - utils::{self, first_line_width, Expr, FindToken, Item}, + utils::{first_line_width, FindToken}, Config, }; @@ -81,8 +82,7 @@ impl FmtVisitor<'_> { let nested_indent = visitor.shape(); let exprs: Vec<_> = - utils::Exprs::new(&visitor, nested_indent, fields_span, constructor.fields) - .collect(); + Items::new(&visitor, nested_indent, fields_span, constructor.fields).collect(); let exprs = format_exprs( visitor.config, Tactic::HorizontalVertical, @@ -189,7 +189,7 @@ impl FmtVisitor<'_> { // TODO: fixme #[allow(clippy::too_many_arguments)] -pub(crate) fn format_seq( +pub(crate) fn format_seq( shape: Shape, prefix: &str, suffix: &str, @@ -206,7 +206,7 @@ pub(crate) fn format_seq( nested_indent.indent.block_indent(visitor.config); - let exprs: Vec<_> = utils::Exprs::new(&visitor, nested_indent, span, exprs).collect(); + let exprs: Vec<_> = Items::new(&visitor, nested_indent, span, exprs).collect(); let exprs = format_exprs(visitor.config, tactic, trailing_comma, exprs, nested_indent, reduce); wrap_exprs(prefix, suffix, exprs, nested_indent, shape, mode) @@ -249,11 +249,11 @@ pub(crate) fn format_parens( format_seq(shape, "(", ")", visitor, trailing_comma, exprs, span, tactic, mode, reduce) } -fn format_exprs( +pub(crate) fn format_exprs( config: &Config, tactic: Tactic, trailing_comma: bool, - exprs: Vec, + exprs: Vec, shape: Shape, reduce: bool, ) -> String { @@ -396,7 +396,7 @@ pub(crate) enum Tactic { impl Tactic { fn definitive( self, - exprs: &[Expr], + exprs: &[Item], short_width_threshold: usize, reduce: bool, ) -> DefinitiveTactic { @@ -449,7 +449,7 @@ enum DefinitiveTactic { } impl DefinitiveTactic { - fn reduce(self, exprs: &[Expr], short_array_element_width_threshold: usize) -> Self { + fn reduce(self, exprs: &[Item], short_array_element_width_threshold: usize) -> Self { match self { DefinitiveTactic::Vertical if no_long_exprs(exprs, short_array_element_width_threshold) => @@ -467,7 +467,7 @@ fn has_single_line_comment(slice: &str) -> bool { slice.trim_start().starts_with("//") } -fn no_long_exprs(exprs: &[Expr], max_width: usize) -> bool { +fn no_long_exprs(exprs: &[Item], max_width: usize) -> bool { exprs.iter().all(|expr| expr.value.len() <= max_width) } diff --git a/noir/tooling/nargo_fmt/src/visitor/item.rs b/noir/tooling/nargo_fmt/src/visitor/item.rs index eb2086168ba..1825a6e05b0 100644 --- a/noir/tooling/nargo_fmt/src/visitor/item.rs +++ b/noir/tooling/nargo_fmt/src/visitor/item.rs @@ -6,7 +6,7 @@ use noirc_frontend::{ }; use crate::{ - rewrite, + rewrite::{self, UseTree}, utils::{last_line_contains_single_line_comment, last_line_used_width, FindToken}, visitor::expr::{format_seq, NewlineMode}, }; @@ -146,6 +146,9 @@ impl super::FmtVisitor<'_> { for Item { kind, span } in module.items { match kind { ItemKind::Function(func) => { + self.visit_function(span, func); + } + ItemKind::Submodules(module) => { self.format_missing_indent(span.start(), true); if std::mem::take(&mut self.ignore_next_node) { @@ -154,15 +157,27 @@ impl super::FmtVisitor<'_> { continue; } - let (fn_before_block, force_brace_newline) = - self.format_fn_before_block(func.clone(), span.start()); + let name = module.name; + let after_brace = self.span_after(span, Token::LeftBrace).start(); + self.last_position = after_brace; + + let keyword = if module.is_contract { "contract" } else { "mod" }; + + self.push_str(&format!("{keyword} {name} ")); - self.push_str(&fn_before_block); - self.push_str(if force_brace_newline { "\n" } else { " " }); + if module.contents.items.is_empty() { + self.visit_empty_block((after_brace - 1..span.end()).into()); + continue; + } else { + self.push_str("{"); + self.indent.block_indent(self.config); + self.visit_module(module.contents); + } - self.visit_block(func.def.body, func.def.span); + self.close_block((self.last_position..span.end() - 1).into()); + self.last_position = span.end(); } - ItemKind::Submodules(module) => { + ItemKind::Impl(impl_) => { self.format_missing_indent(span.start(), true); if std::mem::take(&mut self.ignore_next_node) { @@ -171,31 +186,37 @@ impl super::FmtVisitor<'_> { continue; } - let name = module.name; + let slice = + self.slice(self.last_position..impl_.object_type.span.unwrap().end()); let after_brace = self.span_after(span, Token::LeftBrace).start(); self.last_position = after_brace; - let keyword = if module.is_contract { "contract" } else { "mod" }; + self.push_str(&format!("{slice} ")); - self.push_str(&format!("{keyword} {name} ")); - - if module.contents.items.is_empty() { + if impl_.methods.is_empty() { self.visit_empty_block((after_brace - 1..span.end()).into()); continue; } else { self.push_str("{"); self.indent.block_indent(self.config); - self.visit_module(module.contents); - } - self.close_block((self.last_position..span.end() - 1).into()); + for (method, span) in impl_.methods { + self.visit_function(span, method); + } + + self.close_block((self.last_position..span.end() - 1).into()); + self.last_position = span.end(); + } + } + ItemKind::Import(use_tree) => { + let use_tree = + UseTree::from_ast(use_tree).rewrite_top_level(self, self.shape()); + self.push_rewrite(use_tree, span); self.last_position = span.end(); } - ItemKind::Import(_) - | ItemKind::Struct(_) + ItemKind::Struct(_) | ItemKind::Trait(_) | ItemKind::TraitImpl(_) - | ItemKind::Impl(_) | ItemKind::TypeAlias(_) | ItemKind::Global(_) | ItemKind::ModuleDecl(_) => { @@ -205,4 +226,18 @@ impl super::FmtVisitor<'_> { } } } + + fn visit_function(&mut self, span: Span, func: NoirFunction) { + self.format_missing_indent(span.start(), true); + if std::mem::take(&mut self.ignore_next_node) { + self.push_str(self.slice(span)); + self.last_position = span.end(); + return; + } + let (fn_before_block, force_brace_newline) = + self.format_fn_before_block(func.clone(), span.start()); + self.push_str(&fn_before_block); + self.push_str(if force_brace_newline { "\n" } else { " " }); + self.visit_block(func.def.body, func.def.span); + } } diff --git a/noir/tooling/nargo_fmt/src/visitor/stmt.rs b/noir/tooling/nargo_fmt/src/visitor/stmt.rs index 800a8656ef3..44c5dad6b5d 100644 --- a/noir/tooling/nargo_fmt/src/visitor/stmt.rs +++ b/noir/tooling/nargo_fmt/src/visitor/stmt.rs @@ -38,11 +38,13 @@ impl super::FmtVisitor<'_> { nested_shape.indent.block_indent(self.config); - let message = - message.map_or(String::new(), |message| format!(", \"{message}\"")); + let message = message.map_or(String::new(), |message| { + let message = rewrite::sub_expr(self, nested_shape, message); + format!(", {message}") + }); let (callee, args) = match kind { - ConstrainKind::Assert => { + ConstrainKind::Assert | ConstrainKind::Constrain => { let assertion = rewrite::sub_expr(self, nested_shape, expr); let args = format!("{assertion}{message}"); @@ -60,12 +62,6 @@ impl super::FmtVisitor<'_> { unreachable!() } } - ConstrainKind::Constrain => { - let expr = rewrite::sub_expr(self, self.shape(), expr); - let constrain = format!("constrain {expr};"); - self.push_rewrite(constrain, span); - return; - } }; let args = wrap_exprs( diff --git a/noir/tooling/nargo_fmt/tests/expected/assert.nr b/noir/tooling/nargo_fmt/tests/expected/assert.nr new file mode 100644 index 00000000000..805e069c9a7 --- /dev/null +++ b/noir/tooling/nargo_fmt/tests/expected/assert.nr @@ -0,0 +1,5 @@ +fn main(x: Field) { + assert(x == 0, "with a message"); + assert_eq(x, 1); + assert(x, message); +} diff --git a/noir/tooling/nargo_fmt/tests/expected/contract.nr b/noir/tooling/nargo_fmt/tests/expected/contract.nr index 2e3f4d7c8c4..ed828289d22 100644 --- a/noir/tooling/nargo_fmt/tests/expected/contract.nr +++ b/noir/tooling/nargo_fmt/tests/expected/contract.nr @@ -5,18 +5,14 @@ contract Benchmarking { use dep::aztec::protocol_types::abis::function_selector::FunctionSelector; - use dep::value_note::{ - utils::{increment, decrement}, - value_note::{VALUE_NOTE_LEN, ValueNote, ValueNoteMethods}, - }; + use dep::value_note::{utils::{increment, decrement}, value_note::{VALUE_NOTE_LEN, ValueNote, ValueNoteMethods}}; use dep::aztec::{ context::{Context}, note::{utils as note_utils, note_getter_options::NoteGetterOptions, note_header::NoteHeader}, - log::emit_unencrypted_log, - state_vars::{map::Map, public_state::PublicState, set::Set}, + log::emit_unencrypted_log, state_vars::{map::Map, public_state::PublicState, set::Set}, types::type_serialization::field_serialization::{FieldSerializationMethods, FIELD_SERIALIZED_LEN}, - types::address::{AztecAddress}, + types::address::{AztecAddress} }; struct Storage { @@ -27,8 +23,16 @@ contract Benchmarking { impl Storage { fn init(context: Context) -> pub Self { Storage { - notes: Map::new(context, 1, |context, slot| { Set::new(context, slot, ValueNoteMethods) }), - balances: Map::new(context, 2, |context, slot| { PublicState::new(context, slot, FieldSerializationMethods) }), + notes: Map::new( + context, + 1, + |context, slot| { Set::new(context, slot, ValueNoteMethods) } + ), + balances: Map::new( + context, + 2, + |context, slot| { PublicState::new(context, slot, FieldSerializationMethods) } + ) } } } diff --git a/noir/tooling/nargo_fmt/tests/expected/impl.nr b/noir/tooling/nargo_fmt/tests/expected/impl.nr new file mode 100644 index 00000000000..1c0d4564b5e --- /dev/null +++ b/noir/tooling/nargo_fmt/tests/expected/impl.nr @@ -0,0 +1,21 @@ +impl Type {} + +impl Type {} + +impl Type {} + +impl Type { + fn method(self) {} + + fn method(mut self) {} + + fn method(&mut self) {} +} + +impl Type { + fn method(self) {} +} + +impl Type { + fn method(self) {} +} diff --git a/noir/tooling/nargo_fmt/tests/expected/struct.nr b/noir/tooling/nargo_fmt/tests/expected/struct.nr index cf1795892d2..8fc642f7cd5 100644 --- a/noir/tooling/nargo_fmt/tests/expected/struct.nr +++ b/noir/tooling/nargo_fmt/tests/expected/struct.nr @@ -9,8 +9,8 @@ struct Pair { } impl Foo { - fn default(x: Field,y: Field) -> Self { - Self { bar: 0, array: [x,y] } + fn default(x: Field, y: Field) -> Self { + Self { bar: 0, array: [x, y] } } } diff --git a/noir/tooling/nargo_fmt/tests/expected/vec.nr b/noir/tooling/nargo_fmt/tests/expected/vec.nr index 1c9a791961e..466c9844e74 100644 --- a/noir/tooling/nargo_fmt/tests/expected/vec.nr +++ b/noir/tooling/nargo_fmt/tests/expected/vec.nr @@ -20,12 +20,12 @@ impl Vec { /// points beyond the end of the vector. pub fn get(self, index: Field) -> T { self.slice[index] - } + } /// Push a new element to the end of the vector, returning a /// new vector with a length one greater than the /// original unmodified vector. - pub fn push(&mut self, elem: T) { + pub fn push(&mut self, elem: T) { self.slice = self.slice.push_back(elem); } @@ -33,7 +33,7 @@ impl Vec { /// a new vector with a length of one less than the given vector, /// as well as the popped element. /// Panics if the given vector's length is zero. - pub fn pop(&mut self) -> T { + pub fn pop(&mut self) -> T { let (popped_slice, last_elem) = self.slice.pop_back(); self.slice = popped_slice; last_elem @@ -43,7 +43,7 @@ impl Vec { /// after it to the right pub fn insert(&mut self, index: Field, elem: T) { self.slice = self.slice.insert(index, elem); - } + } /// Remove an element at a specified index, shifting all elements /// after it to the left, returning the removed element diff --git a/noir/tooling/nargo_fmt/tests/input/assert.nr b/noir/tooling/nargo_fmt/tests/input/assert.nr new file mode 100644 index 00000000000..d0259da0e24 --- /dev/null +++ b/noir/tooling/nargo_fmt/tests/input/assert.nr @@ -0,0 +1,8 @@ +fn main(x: Field) { + assert(x == 0, "with a message"); + assert_eq( + x, + 1 + ); + assert( x, message ); +} diff --git a/noir/tooling/nargo_fmt/tests/input/impl.nr b/noir/tooling/nargo_fmt/tests/input/impl.nr new file mode 100644 index 00000000000..1f111371a43 --- /dev/null +++ b/noir/tooling/nargo_fmt/tests/input/impl.nr @@ -0,0 +1,21 @@ +impl Type {} + +impl Type {} + +impl Type {} + +impl Type { + fn method(self) {} + + fn method(mut self) {} + + fn method(&mut self) {} +} + +impl Type { +fn method(self) {} +} + +impl Type { + fn method(self) {} +} \ No newline at end of file diff --git a/noir/tooling/noir_js/.gitignore b/noir/tooling/noir_js/.gitignore index 5b57ba1708d..a55d1794141 100644 --- a/noir/tooling/noir_js/.gitignore +++ b/noir/tooling/noir_js/.gitignore @@ -1,3 +1 @@ crs - -!test/noir_compiled_examples/*/target diff --git a/noir/tooling/noir_js/package.json b/noir/tooling/noir_js/package.json index 356909a1e35..5f83a03019b 100644 --- a/noir/tooling/noir_js/package.json +++ b/noir/tooling/noir_js/package.json @@ -37,7 +37,8 @@ "scripts": { "dev": "tsc-multi --watch", "build": "tsc-multi", - "test": "yarn test:node:esm && yarn test:node:cjs", + "test": "yarn test:compile_program && yarn test:node:esm && yarn test:node:cjs", + "test:compile_program": "./scripts/compile_test_programs.sh", "test:node:esm": "mocha --timeout 25000 --exit --config ./.mocharc.json", "test:node:cjs": "mocha --timeout 25000 --exit --config ./.mocharc.cjs.json", "prettier": "prettier 'src/**/*.ts'", diff --git a/noir/tooling/noir_js/scripts/compile_test_programs.sh b/noir/tooling/noir_js/scripts/compile_test_programs.sh new file mode 100755 index 00000000000..5257aaae696 --- /dev/null +++ b/noir/tooling/noir_js/scripts/compile_test_programs.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +rm -rf ./test/noir_compiled_examples/**/target +nargo --program-dir ./test/noir_compiled_examples/assert_lt compile --force +nargo --program-dir ./test/noir_compiled_examples/assert_msg_runtime compile --force diff --git a/noir/tooling/noir_js/src/witness_generation.ts b/noir/tooling/noir_js/src/witness_generation.ts index 1f233422061..cef1d817d9b 100644 --- a/noir/tooling/noir_js/src/witness_generation.ts +++ b/noir/tooling/noir_js/src/witness_generation.ts @@ -26,6 +26,12 @@ const defaultForeignCallHandler: ForeignCallHandler = async (name: string, args: // // If a user needs to print values then they should provide a custom foreign call handler. return []; + } else if (name == 'assert_message') { + // By default we do not do anything for `assert_message` foreign calls due to a need for formatting, + // however we provide an empty response in order to not halt execution. + // + // If a user needs to use dynamic assertion messages then they should provide a custom foreign call handler. + return []; } throw Error(`Unexpected oracle during execution: ${name}(${args.join(', ')})`); }; diff --git a/noir/tooling/noir_js/test/node/execute.test.ts b/noir/tooling/noir_js/test/node/execute.test.ts index bfaf80882ab..491bcb0dfc4 100644 --- a/noir/tooling/noir_js/test/node/execute.test.ts +++ b/noir/tooling/noir_js/test/node/execute.test.ts @@ -1,9 +1,11 @@ import assert_lt_json from '../noir_compiled_examples/assert_lt/target/assert_lt.json' assert { type: 'json' }; +import assert_msg_json from '../noir_compiled_examples/assert_msg_runtime/target/assert_msg_runtime.json' assert { type: 'json' }; import { Noir } from '@noir-lang/noir_js'; import { CompiledCircuit } from '@noir-lang/types'; import { expect } from 'chai'; const assert_lt_program = assert_lt_json as CompiledCircuit; +const assert_msg_runtime = assert_msg_json as CompiledCircuit; it('returns the return value of the circuit', async () => { const inputs = { @@ -14,3 +16,16 @@ it('returns the return value of the circuit', async () => { expect(returnValue).to.be.eq('0x05'); }); + +it('circuit with a dynamic assert message should fail on an assert failure not the foreign call handler', async () => { + const inputs = { + x: '10', + y: '5', + }; + try { + await new Noir(assert_msg_runtime).execute(inputs); + } catch (error) { + const knownError = error as Error; + expect(knownError.message).to.equal('Circuit execution failed: Error: Cannot satisfy constraint'); + } +}); diff --git a/noir/tooling/noir_js/test/noir_compiled_examples/assert_lt/src/main.nr b/noir/tooling/noir_js/test/noir_compiled_examples/assert_lt/src/main.nr index 693e7285736..a9aaae5f2f7 100644 --- a/noir/tooling/noir_js/test/noir_compiled_examples/assert_lt/src/main.nr +++ b/noir/tooling/noir_js/test/noir_compiled_examples/assert_lt/src/main.nr @@ -4,6 +4,10 @@ fn main(x: u64, y: pub u64) -> pub u64 { // We include a println statement to show that noirJS will ignore this and continue execution std::println("foo"); + // A dynamic assertion message is used to show that noirJS will ignore the call and continue execution + // The assertion passes and thus the foreign call for resolving an assertion message should not be called. + assert(x < y, f"Expected x < y but got {x} < {y}"); + assert(x < y); x + y } diff --git a/noir/tooling/noir_js/test/noir_compiled_examples/assert_lt/target/assert_lt.json b/noir/tooling/noir_js/test/noir_compiled_examples/assert_lt/target/assert_lt.json deleted file mode 100644 index 5b511cdc140..00000000000 --- a/noir/tooling/noir_js/test/noir_compiled_examples/assert_lt/target/assert_lt.json +++ /dev/null @@ -1 +0,0 @@ -{"noir_version":"0.20.0+010fdb69616f47fc0a9f252a65a903316d3cbe80","hash":17538653710107541030,"backend":"acvm-backend-barretenberg","abi":{"parameters":[{"name":"x","type":{"kind":"integer","sign":"unsigned","width":64},"visibility":"private"},{"name":"y","type":{"kind":"integer","sign":"unsigned","width":64},"visibility":"public"}],"param_witnesses":{"x":[{"start":1,"end":2}],"y":[{"start":2,"end":3}]},"return_type":{"abi_type":{"kind":"integer","sign":"unsigned","width":64},"visibility":"public"},"return_witnesses":[5]},"bytecode":"H4sIAAAAAAAA/9Wa627aMBiGHcKhBBLOR+0Hl+Ak5PQP9U6gBK3SNqoqWm9kFzzMYu2DujhbPjvFEkrsJu/7vJ+TFDAtQkiH/GnG6VXLtxvQr+V9Mx/jx5pE3Db5lpZqYahI96Ba91e+bee1g60J6objS90mehbqN8nfuUbSpLAeNVAjXg++bZxeD/m+k9esjlyz6+t3A/p1MFfYvkyzharpPrXzmsFmXPU3YL8F8jUV5HvA1aRMs42qGe2YhgVqwuvH2Tvg721QLwu5Xgbw5Lq8bynz9Tye8Vb+joCjozF/R5lveJ7/riR/V8DR1Zi/q8w3TJiGLclvCzhsjfltZb5hyjQcSX5HwOFozO8o8w3XTKMnyd8TcPQ05od8RVmtilnxff0t0+hL8vcFHH2N+SFfUVarYlZ838hnGgNJ/oGAY6Ax/0CZb3R+rgwl+YcCjqHG/ENlvtH5fdVIkn8k4BhpzA/5irJ274jVrpgV3zeMmMZYkn8s4BhrzA/5irJaFbPi+3pPTGMiyT8RcEw05od8RVmtilnxfcPzXE0l+acCjqnG/FNlvmHANGaS/DMBx0xjfshXlNW+I9bRHbEOKmbF9w1jpjGX5J8LOOYa80O+oqzWHbH2KmbF9/XPnwUXkvwLAcdCY/6FMt9ozzSWkvxLAcdSY/4l8MVet3gAmV9en39kHKAOYPg+X2xlzQRjXOALOIeDtsj7hR60qpnk/eolAWNYPgbQ8k/fTK7TyEtd391SL9nFAV0HuzB2YzeIg70X+34ar+Mo2SURTdy1n7qHIPEPuVjt/7nc6wFBdDRtWFe46tgAE18D44/geLgCb4A5eQTniI4xPtBpgzF+vkMUXljQHEvTJJc/T+C6ZS8oE4+R8kmtk8vlWELwfxKg6qYqq9VErOet+v0jJ73idE3EzHXEeS1Rv5sPuM9839yaZ1quXdwntFxzMe+TBsF/7nDNj/6B8P0GuXz4848R/B3INsvS7y/ZKjuutvv96u05+7o6/kxfD9+Ob78Bhjydn08mAAA="} \ No newline at end of file diff --git a/noir/tooling/noir_js/test/noir_compiled_examples/assert_msg_runtime/Nargo.toml b/noir/tooling/noir_js/test/noir_compiled_examples/assert_msg_runtime/Nargo.toml new file mode 100644 index 00000000000..765f632ff74 --- /dev/null +++ b/noir/tooling/noir_js/test/noir_compiled_examples/assert_msg_runtime/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "assert_msg_runtime" +type = "bin" +authors = [""] +compiler_version = ">=0.23.0" + +[dependencies] \ No newline at end of file diff --git a/noir/tooling/noir_js/test/noir_compiled_examples/assert_msg_runtime/src/main.nr b/noir/tooling/noir_js/test/noir_compiled_examples/assert_msg_runtime/src/main.nr new file mode 100644 index 00000000000..40e447cad02 --- /dev/null +++ b/noir/tooling/noir_js/test/noir_compiled_examples/assert_msg_runtime/src/main.nr @@ -0,0 +1,6 @@ +fn main(x: u64, y: pub u64) { + // A dynamic assertion message is used to show that noirJS will ignore the call and continue execution + // We need this assertion to fail as the `assert_message` oracle in Noir is only called + // upon a failing condition in an assert. + assert(x < y, f"Expected x < y but got {x} < {y}"); +} diff --git a/noir/tooling/noir_js_backend_barretenberg/package.json b/noir/tooling/noir_js_backend_barretenberg/package.json index a0123883efd..b8ab24a73bd 100644 --- a/noir/tooling/noir_js_backend_barretenberg/package.json +++ b/noir/tooling/noir_js_backend_barretenberg/package.json @@ -42,7 +42,7 @@ "lint": "NODE_NO_WARNINGS=1 eslint . --ext .ts --ignore-path ./.eslintignore --max-warnings 0" }, "dependencies": { - "@aztec/bb.js": "0.21.0", + "@aztec/bb.js": "0.23.0", "@noir-lang/types": "workspace:*", "fflate": "^0.8.0" }, diff --git a/noir/tooling/noir_js_backend_barretenberg/src/index.ts b/noir/tooling/noir_js_backend_barretenberg/src/index.ts index 4d5b6389404..d79b487c3cf 100644 --- a/noir/tooling/noir_js_backend_barretenberg/src/index.ts +++ b/noir/tooling/noir_js_backend_barretenberg/src/index.ts @@ -55,7 +55,6 @@ export class BarretenbergBackend implements Backend { this.acirComposer, this.acirUncompressedBytecode, gunzip(compressedWitness), - false, ); const splitIndex = proofWithPublicInputs.length - numBytesInProofWithoutPublicInputs; @@ -117,7 +116,7 @@ export class BarretenbergBackend implements Backend { await this.instantiate(); await this.api.acirInitVerificationKey(this.acirComposer); // TODO: Change once `@aztec/bb.js` version is updated to use methods without isRecursive flag - return await this.api.acirVerifyProof(this.acirComposer, proof, false); + return await this.api.acirVerifyProof(this.acirComposer, proof); } async destroy(): Promise { diff --git a/noir/tooling/noir_js_types/package.json b/noir/tooling/noir_js_types/package.json index ef75f3d2fb3..6ec0e772f67 100644 --- a/noir/tooling/noir_js_types/package.json +++ b/noir/tooling/noir_js_types/package.json @@ -38,9 +38,6 @@ "types": "./lib/esm/types.d.ts" } }, - "dependencies": { - "@noir-lang/noirc_abi": "workspace:*" - }, "devDependencies": { "@types/prettier": "^3", "eslint": "^8.50.0", diff --git a/noir/tooling/noir_js_types/src/types.ts b/noir/tooling/noir_js_types/src/types.ts index 84148c5d855..3a62d79a807 100644 --- a/noir/tooling/noir_js_types/src/types.ts +++ b/noir/tooling/noir_js_types/src/types.ts @@ -1,6 +1,33 @@ -import { Abi } from '@noir-lang/noirc_abi'; +export type Field = string | number | boolean; +export type InputValue = Field | InputMap | (Field | InputMap)[]; +export type InputMap = { [key: string]: InputValue }; -export { Abi, WitnessMap } from '@noir-lang/noirc_abi'; +export type Visibility = 'public' | 'private' | 'databus'; +export type Sign = 'unsigned' | 'signed'; +export type AbiType = + | { kind: 'field' } + | { kind: 'boolean' } + | { kind: 'string'; length: number } + | { kind: 'integer'; sign: Sign; width: number } + | { kind: 'array'; length: number; type: AbiType } + | { kind: 'tuple'; fields: AbiType[] } + | { kind: 'struct'; path: string; fields: { name: string; type: AbiType }[] }; + +export type AbiParameter = { + name: string; + type: AbiType; + visibility: Visibility; +}; + +// Map from witness index to hex string value of witness. +export type WitnessMap = Map; + +export type Abi = { + parameters: AbiParameter[]; + param_witnesses: Record; + return_type: { abi_type: AbiType; visibility: Visibility } | null; + return_witnesses: number[]; +}; export interface Backend { /** diff --git a/noir/tooling/noirc_abi_wasm/package.json b/noir/tooling/noirc_abi_wasm/package.json index db0f6c29153..f829543b9aa 100644 --- a/noir/tooling/noirc_abi_wasm/package.json +++ b/noir/tooling/noirc_abi_wasm/package.json @@ -37,6 +37,9 @@ "build:nix": "nix build -L .#noirc_abi_wasm", "install:from:nix": "yarn clean && yarn build:nix && cp -rL ./result/noirc_abi_wasm/nodejs ./ && cp -rL ./result/noirc_abi_wasm/web ./" }, + "dependencies": { + "@noir-lang/types": "workspace:*" + }, "devDependencies": { "@esm-bundle/chai": "^4.3.4-fix.0", "@web/dev-server-esbuild": "^0.3.6", diff --git a/noir/tooling/noirc_abi_wasm/src/js_witness_map.rs b/noir/tooling/noirc_abi_wasm/src/js_witness_map.rs index fcc6e75f18c..293c5c089f8 100644 --- a/noir/tooling/noirc_abi_wasm/src/js_witness_map.rs +++ b/noir/tooling/noirc_abi_wasm/src/js_witness_map.rs @@ -7,12 +7,6 @@ use acvm::{ use js_sys::{JsString, Map}; use wasm_bindgen::prelude::{wasm_bindgen, JsValue}; -#[wasm_bindgen(typescript_custom_section)] -const WITNESS_MAP: &'static str = r#" -// Map from witness index to hex string value of witness. -export type WitnessMap = Map; -"#; - // WitnessMap #[wasm_bindgen] extern "C" { diff --git a/noir/tooling/noirc_abi_wasm/src/lib.rs b/noir/tooling/noirc_abi_wasm/src/lib.rs index 5557cc917bf..ce15f6d502e 100644 --- a/noir/tooling/noirc_abi_wasm/src/lib.rs +++ b/noir/tooling/noirc_abi_wasm/src/lib.rs @@ -26,9 +26,8 @@ use js_witness_map::JsWitnessMap; #[wasm_bindgen(typescript_custom_section)] const INPUT_MAP: &'static str = r#" -export type Field = string | number | boolean; -export type InputValue = Field | InputMap | (Field | InputMap)[]; -export type InputMap = { [key: string]: InputValue }; +import { Field, InputValue, InputMap, Visibility, Sign, AbiType, AbiParameter, Abi, WitnessMap } from "@noir-lang/types"; +export { Field, InputValue, InputMap, Visibility, Sign, AbiType, AbiParameter, Abi, WitnessMap } from "@noir-lang/types"; "#; #[wasm_bindgen] @@ -36,44 +35,11 @@ extern "C" { #[wasm_bindgen(extends = js_sys::Object, js_name = "InputMap", typescript_type = "InputMap")] #[derive(Clone, Debug, PartialEq, Eq)] pub type JsInputMap; -} -#[wasm_bindgen] -extern "C" { #[wasm_bindgen(extends = js_sys::Object, js_name = "InputValue", typescript_type = "InputValue")] #[derive(Clone, Debug, PartialEq, Eq)] pub type JsInputValue; -} -#[wasm_bindgen(typescript_custom_section)] -const ABI: &'static str = r#" -export type Visibility = "public" | "private" | "databus"; -export type Sign = "unsigned" | "signed"; -export type AbiType = - { kind: "field" } | - { kind: "boolean" } | - { kind: "string", length: number } | - { kind: "integer", sign: Sign, width: number } | - { kind: "array", length: number, type: AbiType } | - { kind: "tuple", fields: AbiType[] } | - { kind: "struct", path: string, fields: { name: string, type: AbiType }[] }; - -export type AbiParameter = { - name: string, - type: AbiType, - visibility: Visibility, -}; - -export type Abi = { - parameters: AbiParameter[], - param_witnesses: Record, - return_type: {abi_type: AbiType, visibility: Visibility} | null, - return_witnesses: number[], -} -"#; - -#[wasm_bindgen] -extern "C" { #[wasm_bindgen(extends = js_sys::Object, js_name = "Abi", typescript_type = "Abi")] #[derive(Clone, Debug, PartialEq, Eq)] pub type JsAbi; diff --git a/noir/yarn.lock b/noir/yarn.lock index 743068f1907..a83bc234e1d 100644 --- a/noir/yarn.lock +++ b/noir/yarn.lock @@ -221,23 +221,9 @@ __metadata: languageName: node linkType: hard -"@aztec/bb.js@npm:0.16.0": - version: 0.16.0 - resolution: "@aztec/bb.js@npm:0.16.0" - dependencies: - comlink: ^4.4.1 - commander: ^10.0.1 - debug: ^4.3.4 - tslib: ^2.4.0 - bin: - bb.js: dest/node/main.js - checksum: 5f68b4ad16284a3a871e0ad21fea05aed670383bc639c9d07ab3bf9b7a9d15cc8a4e5cda404a9290775ad5023924739543a8aac37d602892dd1fb5087521970b - languageName: node - linkType: hard - -"@aztec/bb.js@npm:0.21.0": - version: 0.21.0 - resolution: "@aztec/bb.js@npm:0.21.0" +"@aztec/bb.js@npm:0.23.0": + version: 0.23.0 + resolution: "@aztec/bb.js@npm:0.23.0" dependencies: comlink: ^4.4.1 commander: ^10.0.1 @@ -245,7 +231,7 @@ __metadata: tslib: ^2.4.0 bin: bb.js: dest/node/main.js - checksum: a0fb97476f52025f3c31b7a5e890966ac375ed47c5cfd3434f5c3e4265af3c7566a162f37d6c56f394f44bfe4ba67e5002b7c5998ecc4f6abe70e04f5b8abe34 + checksum: e7bd32a20575a2834fa8a0500becdfae88a8f4a031c0f1796713d64a8ec90e516e16360f19031efeec59d51ede78c50422982ee08911c062bfa3142819af01fc languageName: node linkType: hard @@ -4175,30 +4161,6 @@ __metadata: languageName: node linkType: hard -"@monaco-editor/loader@npm:^1.4.0": - version: 1.4.0 - resolution: "@monaco-editor/loader@npm:1.4.0" - dependencies: - state-local: ^1.0.6 - peerDependencies: - monaco-editor: ">= 0.21.0 < 1" - checksum: 374ec0ea872ee15b33310e105a43217148161480d3955c5cece87d0f801754cd2c45a3f6c539a75da18a066c1615756fb87eaf1003f1df6a64a0cbce5d2c3749 - languageName: node - linkType: hard - -"@monaco-editor/react@npm:4.6.0": - version: 4.6.0 - resolution: "@monaco-editor/react@npm:4.6.0" - dependencies: - "@monaco-editor/loader": ^1.4.0 - peerDependencies: - monaco-editor: ">= 0.25.0 < 1" - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 9d44e76c5baad6db5f84c90a5540fbd3c9af691b97d76cf2a99b3c8273004d0efe44c2572d80e9d975c9af10022c21e4a66923924950a5201e82017c8b20428c - languageName: node - linkType: hard - "@noble/curves@npm:1.2.0": version: 1.2.0 resolution: "@noble/curves@npm:1.2.0" @@ -4395,13 +4357,6 @@ __metadata: languageName: node linkType: hard -"@noir-lang/acvm_js@npm:0.38.0": - version: 0.38.0 - resolution: "@noir-lang/acvm_js@npm:0.38.0" - checksum: 42a5bba45135d1df0d0eb3f7b65439733e016580bad610e859e140638d42200d6b856ff11c4b30417b74ce011da7c39861aafb1c5b8c7211de2172aea449c635 - languageName: node - linkType: hard - "@noir-lang/acvm_js@workspace:*, @noir-lang/acvm_js@workspace:acvm-repo/acvm_js": version: 0.0.0-use.local resolution: "@noir-lang/acvm_js@workspace:acvm-repo/acvm_js" @@ -4420,22 +4375,11 @@ __metadata: languageName: unknown linkType: soft -"@noir-lang/backend_barretenberg@npm:^0.22.0": - version: 0.22.0 - resolution: "@noir-lang/backend_barretenberg@npm:0.22.0" - dependencies: - "@aztec/bb.js": 0.16.0 - "@noir-lang/types": 0.22.0 - fflate: ^0.8.0 - checksum: ead456218ba61d925e0fc5b47d1b94272e980b44a220f1262fb6cdc73cff7cd4232ddc69dd67bb21e50f0b43e7696d4a96fde15e3eadc0bf223ec6d59e014e23 - languageName: node - linkType: hard - "@noir-lang/backend_barretenberg@workspace:*, @noir-lang/backend_barretenberg@workspace:tooling/noir_js_backend_barretenberg": version: 0.0.0-use.local resolution: "@noir-lang/backend_barretenberg@workspace:tooling/noir_js_backend_barretenberg" dependencies: - "@aztec/bb.js": 0.21.0 + "@aztec/bb.js": 0.23.0 "@noir-lang/types": "workspace:*" "@types/node": ^20.6.2 "@types/prettier": ^3 @@ -4475,17 +4419,6 @@ __metadata: languageName: unknown linkType: soft -"@noir-lang/noir_js@npm:^0.22.0": - version: 0.22.0 - resolution: "@noir-lang/noir_js@npm:0.22.0" - dependencies: - "@noir-lang/acvm_js": 0.38.0 - "@noir-lang/noirc_abi": 0.22.0 - "@noir-lang/types": 0.22.0 - checksum: 3b0873ad87521415af11208bebe5690191d03fa06dcd515789f0a63f7641146cdcb01d292b208452856ea3967e196c8332cb2618e013f9e7e5ce7d6e09de043d - languageName: node - linkType: hard - "@noir-lang/noir_js@workspace:*, @noir-lang/noir_js@workspace:tooling/noir_js": version: 0.0.0-use.local resolution: "@noir-lang/noir_js@workspace:tooling/noir_js" @@ -4509,13 +4442,6 @@ __metadata: languageName: unknown linkType: soft -"@noir-lang/noir_wasm@npm:^0.22.0": - version: 0.22.0 - resolution: "@noir-lang/noir_wasm@npm:0.22.0" - checksum: 7ac0ca170bf312df761d7ccfd32a67a27f88f15ad4eed1807864295d761d3b2176ffb82f4c6931e1bc06b225d6f738519962c79ffbce9a33d5ef8a6a2bdea82c - languageName: node - linkType: hard - "@noir-lang/noir_wasm@workspace:*, @noir-lang/noir_wasm@workspace:compiler/wasm": version: 0.0.0-use.local resolution: "@noir-lang/noir_wasm@workspace:compiler/wasm" @@ -4523,6 +4449,7 @@ __metadata: "@esm-bundle/chai": ^4.3.4-fix.0 "@ltd/j-toml": ^1.38.0 "@noir-lang/noirc_abi": "workspace:*" + "@noir-lang/types": "workspace:*" "@types/adm-zip": ^0.5.0 "@types/chai": ^4 "@types/mocha": ^10.0.6 @@ -4560,18 +4487,12 @@ __metadata: languageName: unknown linkType: soft -"@noir-lang/noirc_abi@npm:0.22.0": - version: 0.22.0 - resolution: "@noir-lang/noirc_abi@npm:0.22.0" - checksum: a250c6cc5ca37fcf02663f8d6b027776f0e58920fb8f8a84efcf74f079f235bb11bbad682ba332211d9b9a79b6a3eb7faede7701cd88582b682971a41ca6212d - languageName: node - linkType: hard - "@noir-lang/noirc_abi@workspace:*, @noir-lang/noirc_abi@workspace:tooling/noirc_abi_wasm": version: 0.0.0-use.local resolution: "@noir-lang/noirc_abi@workspace:tooling/noirc_abi_wasm" dependencies: "@esm-bundle/chai": ^4.3.4-fix.0 + "@noir-lang/types": "workspace:*" "@web/dev-server-esbuild": ^0.3.6 "@web/test-runner": ^0.15.3 "@web/test-runner-playwright": ^0.10.0 @@ -4597,20 +4518,10 @@ __metadata: languageName: unknown linkType: soft -"@noir-lang/types@npm:0.22.0, @noir-lang/types@npm:^0.22.0": - version: 0.22.0 - resolution: "@noir-lang/types@npm:0.22.0" - dependencies: - "@noir-lang/noirc_abi": 0.22.0 - checksum: 5dd1badf0449c518e755172de1d2f2c1b95bfaf7b7328b7de00b8ce9ba68bd447ca65e827185da7d737e7e88dcaf296b29687ffe2e1f5b4d5cc31ce3e3b4f208 - languageName: node - linkType: hard - "@noir-lang/types@workspace:*, @noir-lang/types@workspace:tooling/noir_js_types": version: 0.0.0-use.local resolution: "@noir-lang/types@workspace:tooling/noir_js_types" dependencies: - "@noir-lang/noirc_abi": "workspace:*" "@types/prettier": ^3 eslint: ^8.50.0 eslint-plugin-prettier: ^5.0.0 @@ -5326,26 +5237,6 @@ __metadata: languageName: node linkType: hard -"@signorecello/noir_playground@npm:^0.7.0": - version: 0.7.0 - resolution: "@signorecello/noir_playground@npm:0.7.0" - dependencies: - "@monaco-editor/react": 4.6.0 - "@noir-lang/backend_barretenberg": ^0.22.0 - "@noir-lang/noir_js": ^0.22.0 - "@noir-lang/noir_wasm": ^0.22.0 - "@noir-lang/types": ^0.22.0 - fflate: ^0.8.1 - js-base64: ^3.7.5 - monaco-editor: ^0.44.0 - monaco-editor-textmate: ^4.0.0 - monaco-textmate: ^3.0.1 - onigasm: ^2.2.5 - react-toastify: ^9.1.3 - checksum: 360bd1dbc8964a6ab8a6e8d0eb0cd11d7446cc23bf63c253083b18b5d6d5ccf2ec6ca847614106cd93490bb815aac651a6e4584ac63ea0fda182cdb1aadf3f45 - languageName: node - linkType: hard - "@sinclair/typebox@npm:^0.27.8": version: 0.27.8 resolution: "@sinclair/typebox@npm:0.27.8" @@ -10337,7 +10228,6 @@ __metadata: "@noir-lang/noir_js": "workspace:*" "@noir-lang/noirc_abi": "workspace:*" "@noir-lang/types": "workspace:*" - "@signorecello/noir_playground": ^0.7.0 "@types/prettier": ^3 axios: ^1.4.0 clsx: ^1.2.1 @@ -11499,13 +11389,6 @@ __metadata: languageName: node linkType: hard -"fast-plist@npm:^0.1.2": - version: 0.1.3 - resolution: "fast-plist@npm:0.1.3" - checksum: e879f548db3a1fc89c654c476e9c9846f4335fdcd2283ec99e5f234c897f5616cee2a0a4201bf4b64ab6269e75c09daafc3933bd4a038c85af943fac0f113caa - languageName: node - linkType: hard - "fast-url-parser@npm:1.1.3": version: 1.1.3 resolution: "fast-url-parser@npm:1.1.3" @@ -11567,7 +11450,7 @@ __metadata: languageName: node linkType: hard -"fflate@npm:^0.8.0, fflate@npm:^0.8.1": +"fflate@npm:^0.8.0": version: 0.8.1 resolution: "fflate@npm:0.8.1" checksum: 7207e2d333243724485d2488095256b776184bd4545aa9967b655feaee5dc18e9525ed9b6d75f94cfd71d98fb285336f4902641683472f1d0c19a99137084cec @@ -14077,13 +13960,6 @@ __metadata: languageName: node linkType: hard -"js-base64@npm:^3.7.5": - version: 3.7.5 - resolution: "js-base64@npm:3.7.5" - checksum: 67a78c8b1c47b73f1c6fba1957e9fe6fd9dc78ac93ac46cc2e43472dcb9cf150d126fb0e593192e88e0497354fa634d17d255add7cc6ee3c7b4d29870faa8e18 - languageName: node - linkType: hard - "js-sdsl@npm:^4.1.4": version: 4.4.2 resolution: "js-sdsl@npm:4.4.2" @@ -16249,34 +16125,6 @@ __metadata: languageName: node linkType: hard -"monaco-editor-textmate@npm:^4.0.0": - version: 4.0.0 - resolution: "monaco-editor-textmate@npm:4.0.0" - peerDependencies: - monaco-editor: 0.x.x - monaco-textmate: ^3.0.0 - checksum: 9d3f5f24982f928c5f4b7c5c5170a549cb19eb1471eb157aa07bd97cf15cd75dd941585eeb6924b05c54109a55d48adc45191eda9db5d2793b1d8c462181c100 - languageName: node - linkType: hard - -"monaco-editor@npm:^0.44.0": - version: 0.44.0 - resolution: "monaco-editor@npm:0.44.0" - checksum: 6e561b23e5e9090cbdbb820dae5895a8bf9d537acc09281756a8c428960da0481461c72f387cc9a2e14bff69ab4359186c98df2dd29d6d109f1ab7189b573a35 - languageName: node - linkType: hard - -"monaco-textmate@npm:^3.0.1": - version: 3.0.1 - resolution: "monaco-textmate@npm:3.0.1" - dependencies: - fast-plist: ^0.1.2 - peerDependencies: - onigasm: ^2.0.0 - checksum: 0f2ec07ee3e9a37bb880e2aaef802f82cb666660b40fc3c7c3e35553d740aed34ae94399b06296fddf1f96efdaf27eaf347b39cb14bc08ccfb65162c52771d56 - languageName: node - linkType: hard - "mrmime@npm:^1.0.0": version: 1.0.1 resolution: "mrmime@npm:1.0.1" @@ -16708,15 +16556,6 @@ __metadata: languageName: node linkType: hard -"onigasm@npm:^2.2.5": - version: 2.2.5 - resolution: "onigasm@npm:2.2.5" - dependencies: - lru-cache: ^5.1.1 - checksum: 97aedde610ef561f05853609d6a5b720ec1e123f867bdac1b38b5aeb3bc90ed60209678c75a5f0f9821aa793c720b6d17aabfb956e26ab115ee9b81d6e56bdf7 - languageName: node - linkType: hard - "only@npm:~0.0.2": version: 0.0.2 resolution: "only@npm:0.0.2" @@ -18335,18 +18174,6 @@ __metadata: languageName: node linkType: hard -"react-toastify@npm:^9.1.3": - version: 9.1.3 - resolution: "react-toastify@npm:9.1.3" - dependencies: - clsx: ^1.1.1 - peerDependencies: - react: ">=16" - react-dom: ">=16" - checksum: e8bd92c5cbf831b43a042644ab9bc69abe6ceb3ce91ba71f5cd2d8b6a2c9885ca52770e1f1ba64c5632607f6df962db344a26c7fba57606faf5aa0e7bfc8535f - languageName: node - linkType: hard - "react@npm:^18.2.0": version: 18.2.0 resolution: "react@npm:18.2.0" @@ -19869,13 +19696,6 @@ __metadata: languageName: node linkType: hard -"state-local@npm:^1.0.6": - version: 1.0.7 - resolution: "state-local@npm:1.0.7" - checksum: d1afcf1429e7e6eb08685b3a94be8797db847369316d4776fd51f3962b15b984dacc7f8e401ad20968e5798c9565b4b377afedf4e4c4d60fe7495e1cbe14a251 - languageName: node - linkType: hard - "state-toggle@npm:^1.0.0": version: 1.0.3 resolution: "state-toggle@npm:1.0.3" diff --git a/yarn-project/aztec-nr/address-note/src/address_note.nr b/yarn-project/aztec-nr/address-note/src/address_note.nr index e644b55ba13..2ce95fe79d6 100644 --- a/yarn-project/aztec-nr/address-note/src/address_note.nr +++ b/yarn-project/aztec-nr/address-note/src/address_note.nr @@ -2,22 +2,10 @@ use dep::aztec::log::emit_encrypted_log; // docs:end:encrypted_import use dep::aztec::{ - protocol_types::{ - address::AztecAddress, - traits::Empty - }, - note::{ - note_header::NoteHeader, - note_interface::NoteInterface, - utils::compute_note_hash_for_consumption, - }, - oracle::{ - rand::rand, - nullifier_key::get_nullifier_secret_key, - get_public_key::get_public_key, - }, - hash::pedersen_hash, - context::PrivateContext + protocol_types::{address::AztecAddress, traits::Empty}, + note::{note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_consumption}, + oracle::{rand::rand, nullifier_key::get_nullifier_secret_key, get_public_key::get_public_key}, + hash::pedersen_hash, context::PrivateContext }; global ADDRESS_NOTE_LEN: Field = 3; @@ -98,12 +86,7 @@ impl NoteInterface for AddressNote { impl AddressNote { pub fn new(address: AztecAddress, owner: AztecAddress) -> Self { let randomness = rand(); - AddressNote { - address, - owner, - randomness, - header: NoteHeader::empty(), - } + AddressNote { address, owner, randomness, header: NoteHeader::empty() } } -// docs:end:address_note_def + // docs:end:address_note_def } diff --git a/yarn-project/aztec-nr/authwit/src/account.nr b/yarn-project/aztec-nr/authwit/src/account.nr index 790aee2b662..8823b14c5ec 100644 --- a/yarn-project/aztec-nr/authwit/src/account.nr +++ b/yarn-project/aztec-nr/authwit/src/account.nr @@ -11,57 +11,73 @@ struct AccountActions { } impl AccountActions { - pub fn init(context: Context, approved_action_storage_slot: Field, is_valid_impl: fn(&mut PrivateContext, Field) -> bool) -> Self { - AccountActions { - context: context, - is_valid_impl: is_valid_impl, - approved_action: Map::new( - context, - approved_action_storage_slot, - |context, slot| { + pub fn init( + context: Context, + approved_action_storage_slot: Field, + is_valid_impl: fn(&mut PrivateContext, Field) -> bool + ) -> Self { + AccountActions { + context, + is_valid_impl, + approved_action: Map::new( + context, + approved_action_storage_slot, + |context, slot| { PublicState::new(context, slot) - }, - ), + } + ) + } } - } - pub fn private(context: &mut PrivateContext, approved_action_storage_slot: Field, is_valid_impl: fn(&mut PrivateContext, Field) -> bool) -> Self { - AccountActions::init(Context::private(context), approved_action_storage_slot, is_valid_impl) - } + pub fn private( + context: &mut PrivateContext, + approved_action_storage_slot: Field, + is_valid_impl: fn(&mut PrivateContext, Field) -> bool + ) -> Self { + AccountActions::init( + Context::private(context), + approved_action_storage_slot, + is_valid_impl + ) + } - pub fn public(context: &mut PublicContext, approved_action_storage_slot: Field, is_valid_impl: fn(&mut PrivateContext, Field) -> bool) -> Self { - AccountActions::init(Context::public(context), approved_action_storage_slot, is_valid_impl) - } - - // docs:start:entrypoint - pub fn entrypoint(self, payload: EntrypointPayload) { - let message_hash = payload.hash(); - let valid_fn = self.is_valid_impl; - let private_context = self.context.private.unwrap(); - assert(valid_fn(private_context, message_hash)); - payload.execute_calls(private_context); - } - // docs:end:entrypoint + pub fn public( + context: &mut PublicContext, + approved_action_storage_slot: Field, + is_valid_impl: fn(&mut PrivateContext, Field) -> bool + ) -> Self { + AccountActions::init( + Context::public(context), + approved_action_storage_slot, + is_valid_impl + ) + } - pub fn is_valid(self, message_hash: Field) -> Field { - let valid_fn = self.is_valid_impl; - if (valid_fn(self.context.private.unwrap(), message_hash)) { - IS_VALID_SELECTOR - } else { - 0 + // docs:start:entrypoint + pub fn entrypoint(self, payload: EntrypointPayload) { + let message_hash = payload.hash(); + let valid_fn = self.is_valid_impl; + let private_context = self.context.private.unwrap(); + assert(valid_fn(private_context, message_hash)); + payload.execute_calls(private_context); } - } + // docs:end:entrypoint - pub fn is_valid_public(self, message_hash: Field) -> Field { - let value = self.approved_action.at(message_hash).read(); - if (value){ - IS_VALID_SELECTOR - } else { - 0 + pub fn is_valid(self, message_hash: Field) -> Field { + let valid_fn = self.is_valid_impl; + if (valid_fn(self.context.private.unwrap(), message_hash)) { + IS_VALID_SELECTOR + } else { + 0 + } } - } - pub fn internal_set_is_valid_storage(self, message_hash: Field, value: bool) { - self.approved_action.at(message_hash).write(value); - } + pub fn is_valid_public(self, message_hash: Field) -> Field { + let value = self.approved_action.at(message_hash).read(); + if (value) { IS_VALID_SELECTOR } else { 0 } + } + + pub fn internal_set_is_valid_storage(self, message_hash: Field, value: bool) { + self.approved_action.at(message_hash).write(value); + } } diff --git a/yarn-project/aztec-nr/authwit/src/auth.nr b/yarn-project/aztec-nr/authwit/src/auth.nr index d9dababda41..99b07bf11a8 100644 --- a/yarn-project/aztec-nr/authwit/src/auth.nr +++ b/yarn-project/aztec-nr/authwit/src/auth.nr @@ -1,19 +1,8 @@ use dep::aztec::protocol_types::{ - abis::function_selector::FunctionSelector, - address::AztecAddress, - constants::{ - GENERATOR_INDEX__SIGNATURE_PAYLOAD, - }, - hash::{ - hash_args, - pedersen_hash, - }, -}; -use dep::aztec::context::{ - PrivateContext, - PublicContext, - Context, + abis::function_selector::FunctionSelector, address::AztecAddress, + constants::{GENERATOR_INDEX__SIGNATURE_PAYLOAD}, hash::{hash_args, pedersen_hash} }; +use dep::aztec::context::{PrivateContext, PublicContext, Context}; global IS_VALID_SELECTOR = 0xe86ab4ff; global IS_VALID_PUBLIC_SELECTOR = 0xf3661153; diff --git a/yarn-project/aztec-nr/authwit/src/entrypoint.nr b/yarn-project/aztec-nr/authwit/src/entrypoint.nr index 13407a40ecc..4113c42533c 100644 --- a/yarn-project/aztec-nr/authwit/src/entrypoint.nr +++ b/yarn-project/aztec-nr/authwit/src/entrypoint.nr @@ -1,10 +1,7 @@ use dep::aztec::context::PrivateContext; use dep::aztec::protocol_types::{ - abis::function_selector::FunctionSelector, - address::AztecAddress, - constants::GENERATOR_INDEX__SIGNATURE_PAYLOAD, - hash::pedersen_hash, - traits::{Hash, Serialize} + abis::function_selector::FunctionSelector, address::AztecAddress, + constants::GENERATOR_INDEX__SIGNATURE_PAYLOAD, hash::pedersen_hash, traits::{Hash, Serialize} }; global ACCOUNT_MAX_CALLS: Field = 4; @@ -27,17 +24,23 @@ impl Serialize for FunctionCall { } impl FunctionCall { - fn to_be_bytes(self) -> [u8; FUNCTION_CALL_SIZE_IN_BYTES] { - let mut bytes: [u8; FUNCTION_CALL_SIZE_IN_BYTES] = [0; FUNCTION_CALL_SIZE_IN_BYTES]; - let args_hash_bytes = self.args_hash.to_be_bytes(32); - for i in 0..32 { bytes[i] = args_hash_bytes[i]; } - let function_selector_bytes = self.function_selector.to_field().to_be_bytes(32); - for i in 0..32 { bytes[i + 32] = function_selector_bytes[i]; } - let target_address_bytes = self.target_address.to_field().to_be_bytes(32); - for i in 0..32 { bytes[i + 64] = target_address_bytes[i]; } - bytes[96] = self.is_public as u8; - bytes - } + fn to_be_bytes(self) -> [u8; FUNCTION_CALL_SIZE_IN_BYTES] { + let mut bytes: [u8; FUNCTION_CALL_SIZE_IN_BYTES] = [0; FUNCTION_CALL_SIZE_IN_BYTES]; + let args_hash_bytes = self.args_hash.to_be_bytes(32); + for i in 0..32 { + bytes[i] = args_hash_bytes[i]; + } + let function_selector_bytes = self.function_selector.to_field().to_be_bytes(32); + for i in 0..32 { + bytes[i + 32] = function_selector_bytes[i]; + } + let target_address_bytes = self.target_address.to_field().to_be_bytes(32); + for i in 0..32 { + bytes[i + 64] = target_address_bytes[i]; + } + bytes[96] = self.is_public as u8; + bytes + } } // FUNCTION_CALL_SIZE * ACCOUNT_MAX_CALLS + 1 @@ -75,42 +78,38 @@ impl Hash for EntrypointPayload { } impl EntrypointPayload { - // Serializes the payload as an array of bytes. Useful for hashing with sha256. - fn to_be_bytes(self) -> [u8; ENTRYPOINT_PAYLOAD_SIZE_IN_BYTES] { - let mut bytes: [u8; ENTRYPOINT_PAYLOAD_SIZE_IN_BYTES] = [0; ENTRYPOINT_PAYLOAD_SIZE_IN_BYTES]; + // Serializes the payload as an array of bytes. Useful for hashing with sha256. + fn to_be_bytes(self) -> [u8; ENTRYPOINT_PAYLOAD_SIZE_IN_BYTES] { + let mut bytes: [u8; ENTRYPOINT_PAYLOAD_SIZE_IN_BYTES] = [0; ENTRYPOINT_PAYLOAD_SIZE_IN_BYTES]; - for i in 0..ACCOUNT_MAX_CALLS { - let item_bytes = self.function_calls[i].to_be_bytes(); - for j in 0..FUNCTION_CALL_SIZE_IN_BYTES { - bytes[i * FUNCTION_CALL_SIZE_IN_BYTES + j] = item_bytes[j]; - } - } + for i in 0..ACCOUNT_MAX_CALLS { + let item_bytes = self.function_calls[i].to_be_bytes(); + for j in 0..FUNCTION_CALL_SIZE_IN_BYTES { + bytes[i * FUNCTION_CALL_SIZE_IN_BYTES + j] = item_bytes[j]; + } + } + + let nonce_bytes = self.nonce.to_be_bytes(32); + let nonce_offset = FUNCTION_CALL_SIZE_IN_BYTES * ACCOUNT_MAX_CALLS; + for j in 0..32 { + bytes[nonce_offset + j] = nonce_bytes[j]; + } - let nonce_bytes = self.nonce.to_be_bytes(32); - let nonce_offset = FUNCTION_CALL_SIZE_IN_BYTES * ACCOUNT_MAX_CALLS; - for j in 0..32 { - bytes[nonce_offset + j] = nonce_bytes[j]; + bytes } - - bytes - } - // Executes all private and public calls - // docs:start:entrypoint-execute-calls - fn execute_calls(self, context: &mut PrivateContext) { - for call in self.function_calls { - if !call.target_address.is_zero() { - if call.is_public { - context.call_public_function_with_packed_args( - call.target_address, call.function_selector, call.args_hash - ); - } else { - let _result = context.call_private_function_with_packed_args( - call.target_address, call.function_selector, call.args_hash - ); + // Executes all private and public calls + // docs:start:entrypoint-execute-calls + fn execute_calls(self, context: &mut PrivateContext) { + for call in self.function_calls { + if !call.target_address.is_zero() { + if call.is_public { + context.call_public_function_with_packed_args(call.target_address, call.function_selector, call.args_hash); + } else { + let _result = context.call_private_function_with_packed_args(call.target_address, call.function_selector, call.args_hash); + } + } } - } } - } - // docs:end:entrypoint-execute-calls + // docs:end:entrypoint-execute-calls } diff --git a/yarn-project/aztec-nr/aztec/src/avm/context.nr b/yarn-project/aztec-nr/aztec/src/avm/context.nr index 4e6d3f56f21..e247f60db89 100644 --- a/yarn-project/aztec-nr/aztec/src/avm/context.nr +++ b/yarn-project/aztec-nr/aztec/src/avm/context.nr @@ -1,7 +1,4 @@ -use dep::protocol_types::address::{ - AztecAddress, - EthAddress, -}; +use dep::protocol_types::address::{AztecAddress, EthAddress}; // Getters that will be converted by the transpiler into their // own opcodes @@ -44,7 +41,6 @@ impl AvmContext { #[oracle(timestamp)] pub fn timestamp() -> Field {} - // #[oracle(contractCallDepth)] // pub fn contract_call_depth() -> Field {} } diff --git a/yarn-project/aztec-nr/aztec/src/context.nr b/yarn-project/aztec-nr/aztec/src/context.nr index 8cc2c2a22c2..37eb6bb45fa 100644 --- a/yarn-project/aztec-nr/aztec/src/context.nr +++ b/yarn-project/aztec-nr/aztec/src/context.nr @@ -16,23 +16,14 @@ struct Context { impl Context { pub fn private(context: &mut PrivateContext) -> Context { - Context { - private: Option::some(context), - public: Option::none() - } + Context { private: Option::some(context), public: Option::none() } } pub fn public(context: &mut PublicContext) -> Context { - Context { - public: Option::some(context), - private: Option::none() - } + Context { public: Option::some(context), private: Option::none() } } pub fn none() -> Context { - Context { - public: Option::none(), - private: Option::none() - } + Context { public: Option::none(), private: Option::none() } } } diff --git a/yarn-project/aztec-nr/aztec/src/context/avm.nr b/yarn-project/aztec-nr/aztec/src/context/avm.nr index 98c578e59db..26634b84c34 100644 --- a/yarn-project/aztec-nr/aztec/src/context/avm.nr +++ b/yarn-project/aztec-nr/aztec/src/context/avm.nr @@ -1,7 +1,4 @@ -use dep::protocol_types::address::{ - AztecAddress, - EthAddress, -}; +use dep::protocol_types::address::{AztecAddress, EthAddress}; // Getters that will be converted by the transpiler into their // own opcodes @@ -48,7 +45,6 @@ impl AVMContext { #[oracle(timestamp)] pub fn timestamp(self) -> Field {} - // #[oracle(contractCallDepth)] // pub fn contract_call_depth(self) -> Field {} } diff --git a/yarn-project/aztec-nr/aztec/src/context/inputs/private_context_inputs.nr b/yarn-project/aztec-nr/aztec/src/context/inputs/private_context_inputs.nr index b96f62e6e50..c2ed873541a 100644 --- a/yarn-project/aztec-nr/aztec/src/context/inputs/private_context_inputs.nr +++ b/yarn-project/aztec-nr/aztec/src/context/inputs/private_context_inputs.nr @@ -1,8 +1,4 @@ -use dep::protocol_types::{ - abis::call_context::CallContext, - contrakt::deployment_data::ContractDeploymentData, - header::Header, -}; +use dep::protocol_types::{abis::call_context::CallContext, contrakt::deployment_data::ContractDeploymentData, header::Header}; use crate::context::globals::private_global_variables::PrivateGlobalVariables; // PrivateContextInputs are expected to be provided to each private function diff --git a/yarn-project/aztec-nr/aztec/src/context/inputs/public_context_inputs.nr b/yarn-project/aztec-nr/aztec/src/context/inputs/public_context_inputs.nr index 6fefcfed3b7..6b8aefbbcd4 100644 --- a/yarn-project/aztec-nr/aztec/src/context/inputs/public_context_inputs.nr +++ b/yarn-project/aztec-nr/aztec/src/context/inputs/public_context_inputs.nr @@ -1,9 +1,6 @@ use crate::context::globals::public_global_variables::PublicGlobalVariables; -use dep::protocol_types::{ - abis::call_context::CallContext, - header::Header, -}; +use dep::protocol_types::{abis::call_context::CallContext, header::Header}; // PublicContextInputs are expected to be provided to each public function // docs:start:public-context-inputs diff --git a/yarn-project/aztec-nr/aztec/src/context/private_context.nr b/yarn-project/aztec-nr/aztec/src/context/private_context.nr index 388a1fe99c1..1bb45553eb0 100644 --- a/yarn-project/aztec-nr/aztec/src/context/private_context.nr +++ b/yarn-project/aztec-nr/aztec/src/context/private_context.nr @@ -1,53 +1,32 @@ use crate::{ - context::inputs::PrivateContextInputs, - key::nullifier_key::validate_nullifier_key_against_address, + context::inputs::PrivateContextInputs, key::nullifier_key::validate_nullifier_key_against_address, messaging::process_l1_to_l2_message, oracle::{ - arguments, - call_private_function::call_private_function_internal, - enqueue_public_function_call::enqueue_public_function_call_internal, - context::get_portal_address, - header::get_header_at, - nullifier_key::{get_nullifier_key_pair, NullifierKeyPair}, - }, + arguments, call_private_function::call_private_function_internal, + enqueue_public_function_call::enqueue_public_function_call_internal, context::get_portal_address, + header::get_header_at, nullifier_key::{get_nullifier_key_pair, NullifierKeyPair} +} }; use dep::protocol_types::{ abis::{ - call_context::CallContext, - function_data::FunctionData, - function_selector::FunctionSelector, - nullifier_key_validation_request::NullifierKeyValidationRequest, - private_call_stack_item::PrivateCallStackItem, - private_circuit_public_inputs::PrivateCircuitPublicInputs, - public_call_stack_item::PublicCallStackItem, - public_circuit_public_inputs::PublicCircuitPublicInputs, - side_effect::{SideEffect, SideEffectLinkedToNoteHash}, - }, - address::{ - AztecAddress, - EthAddress, - }, + call_context::CallContext, function_data::FunctionData, function_selector::FunctionSelector, + nullifier_key_validation_request::NullifierKeyValidationRequest, + private_call_stack_item::PrivateCallStackItem, + private_circuit_public_inputs::PrivateCircuitPublicInputs, + public_call_stack_item::PublicCallStackItem, + public_circuit_public_inputs::PublicCircuitPublicInputs, + side_effect::{SideEffect, SideEffectLinkedToNoteHash} +}, + address::{AztecAddress, EthAddress}, constants::{ - MAX_NEW_COMMITMENTS_PER_CALL, - MAX_NEW_L2_TO_L1_MSGS_PER_CALL, - MAX_NEW_NULLIFIERS_PER_CALL, - MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, - MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, - MAX_PUBLIC_DATA_READS_PER_CALL, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, - MAX_READ_REQUESTS_PER_CALL, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, - NUM_FIELDS_PER_SHA256, - RETURN_VALUES_LENGTH, - }, - contrakt::{ - storage_read::StorageRead, - storage_update_request::StorageUpdateRequest, - }, - grumpkin_private_key::GrumpkinPrivateKey, - hash::hash_args, - header::Header, - utils::reader::Reader, + MAX_NEW_COMMITMENTS_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, + MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, + MAX_PUBLIC_DATA_READS_PER_CALL, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, + MAX_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, NUM_FIELDS_PER_SHA256, + RETURN_VALUES_LENGTH +}, + contrakt::{storage_read::StorageRead, storage_update_request::StorageUpdateRequest}, + grumpkin_private_key::GrumpkinPrivateKey, hash::hash_args, header::Header, utils::reader::Reader }; use dep::std::option::Option; @@ -89,30 +68,23 @@ struct PrivateContext { impl PrivateContext { pub fn new(inputs: PrivateContextInputs, args_hash: Field) -> PrivateContext { PrivateContext { - inputs: inputs, + inputs, side_effect_counter: inputs.call_context.start_side_effect_counter, max_non_revertible_side_effect_counter: 0, - - args_hash: args_hash, + args_hash, return_values: BoundedVec::new(0), - read_requests: BoundedVec::new(SideEffect::empty()), nullifier_key_validation_requests: BoundedVec::new(NullifierKeyValidationRequest::empty()), - new_commitments: BoundedVec::new(SideEffect::empty()), new_nullifiers: BoundedVec::new(SideEffectLinkedToNoteHash::empty()), - historical_header: inputs.historical_header, - private_call_stack_hashes: BoundedVec::new(0), public_call_stack_hashes: BoundedVec::new(0), new_l2_to_l1_msgs: BoundedVec::new(0), - // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) // encrypted_logs_preimages: Vec::new(), // unencrypted_logs_preimages: Vec::new(), - - nullifier_key: Option::none(), + nullifier_key: Option::none() } } @@ -172,42 +144,32 @@ impl PrivateContext { public_call_stack_hashes: self.public_call_stack_hashes.storage, new_l2_to_l1_msgs: self.new_l2_to_l1_msgs.storage, end_side_effect_counter: self.side_effect_counter, - encrypted_logs_hash: encrypted_logs_hash, - unencrypted_logs_hash: unencrypted_logs_hash, - encrypted_log_preimages_length: encrypted_log_preimages_length, - unencrypted_log_preimages_length: unencrypted_log_preimages_length, + encrypted_logs_hash, + unencrypted_logs_hash, + encrypted_log_preimages_length, + unencrypted_log_preimages_length, historical_header: self.historical_header, contract_deployment_data: self.inputs.contract_deployment_data, chain_id: self.inputs.private_global_variables.chain_id, - version: self.inputs.private_global_variables.version, + version: self.inputs.private_global_variables.version }; priv_circuit_pub_inputs } pub fn push_read_request(&mut self, read_request: Field) { - let side_effect = SideEffect { - value: read_request, - counter: self.side_effect_counter, - }; + let side_effect = SideEffect { value: read_request, counter: self.side_effect_counter }; self.read_requests.push(side_effect); self.side_effect_counter = self.side_effect_counter + 1; } pub fn push_new_note_hash(&mut self, note_hash: Field) { - let side_effect = SideEffect { - value: note_hash, - counter: self.side_effect_counter, - }; + let side_effect = SideEffect { value: note_hash, counter: self.side_effect_counter }; self.new_commitments.push(side_effect); self.side_effect_counter = self.side_effect_counter + 1; } pub fn push_new_nullifier(&mut self, nullifier: Field, nullified_commitment: Field) { - let side_effect = SideEffectLinkedToNoteHash { - value: nullifier, - note_hash: nullified_commitment, - counter: self.side_effect_counter, - }; + let side_effect = SideEffectLinkedToNoteHash { value: nullifier, note_hash: nullified_commitment, counter: self.side_effect_counter }; self.new_nullifiers.push(side_effect); self.side_effect_counter = self.side_effect_counter + 1; } @@ -224,16 +186,17 @@ impl PrivateContext { let key_pair = self.nullifier_key.unwrap_unchecked(); // If MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL is larger than 1, need to update the way the key pair is cached. assert(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL == 1); - assert(key_pair.account == account, "Cannot query nullifier key for more than one account per call"); + assert( + key_pair.account == account, "Cannot query nullifier key for more than one account per call" + ); key_pair }; key_pair.secret_key } // docs:start:context_message_portal - pub fn message_portal(&mut self, content: Field) - // docs:end:context_message_portal - { + pub fn message_portal(&mut self, content: Field) { + // docs:end:context_message_portal self.new_l2_to_l1_msgs.push(content); } @@ -241,15 +204,18 @@ impl PrivateContext { // Note this returns self to get around an issue where mutable structs do not maintain mutations unless reassigned // docs:start:context_consume_l1_to_l2_message // docs:start:consume_l1_to_l2_message - pub fn consume_l1_to_l2_message( - &mut self, - msg_key: Field, - content: Field, - secret: Field - ) - // docs:end:context_consume_l1_to_l2_message - { - let nullifier = process_l1_to_l2_message(self.historical_header.state.l1_to_l2_message_tree.root, self.this_address(), self.this_portal_address(), self.chain_id(), self.version(), msg_key, content, secret); + pub fn consume_l1_to_l2_message(&mut self, msg_key: Field, content: Field, secret: Field) { + // docs:end:context_consume_l1_to_l2_message + let nullifier = process_l1_to_l2_message( + self.historical_header.state.l1_to_l2_message_tree.root, + self.this_address(), + self.this_portal_address(), + self.chain_id(), + self.version(), + msg_key, + content, + secret + ); // Push nullifier (and the "commitment" corresponding to this can be "empty") self.push_new_nullifier(nullifier, 0) @@ -282,7 +248,7 @@ impl PrivateContext { pub fn call_private_function_no_args( &mut self, contract_address: AztecAddress, - function_selector: FunctionSelector, + function_selector: FunctionSelector ) -> [Field; RETURN_VALUES_LENGTH] { self.call_private_function_with_packed_args(contract_address, function_selector, 0) } @@ -297,7 +263,7 @@ impl PrivateContext { contract_address, function_selector, args_hash, - self.side_effect_counter, + self.side_effect_counter ); assert_eq(item.public_inputs.call_context.start_side_effect_counter, self.side_effect_counter); @@ -315,7 +281,9 @@ impl PrivateContext { assert(item.public_inputs.call_context.is_delegate_call == false); assert(item.public_inputs.call_context.is_static_call == false); assert(item.public_inputs.call_context.is_contract_deployment == false); - assert(item.public_inputs.call_context.msg_sender.eq(self.inputs.call_context.storage_contract_address)); + assert( + item.public_inputs.call_context.msg_sender.eq(self.inputs.call_context.storage_contract_address) + ); assert(item.public_inputs.call_context.storage_contract_address.eq(contract_address)); self.private_call_stack_hashes.push(item.hash()); @@ -337,7 +305,7 @@ impl PrivateContext { pub fn call_public_function_no_args( &mut self, contract_address: AztecAddress, - function_selector: FunctionSelector, + function_selector: FunctionSelector ) { self.call_public_function_with_packed_args(contract_address, function_selector, 0) } @@ -360,7 +328,7 @@ impl PrivateContext { // Note: Not using PublicCirclePublicInputs::deserialize here, because everything below args_hash is 0 and // there is no more data in fields because there is only ENQUEUE_PUBLIC_FUNCTION_CALL_RETURN_SIZE fields! let item = PublicCallStackItem { - contract_address: AztecAddress::from_field(reader.read()), + contract_address: AztecAddress::from_field(reader.read()), function_data: reader.read_struct(FunctionData::deserialize), public_inputs: PublicCircuitPublicInputs { call_context: reader.read_struct(CallContext::deserialize), @@ -371,13 +339,13 @@ impl PrivateContext { public_call_stack_hashes: [0; MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL], new_commitments: [SideEffect::empty(); MAX_NEW_COMMITMENTS_PER_CALL], new_nullifiers: [SideEffectLinkedToNoteHash::empty(); MAX_NEW_NULLIFIERS_PER_CALL], - new_l2_to_l1_msgs:[0; MAX_NEW_L2_TO_L1_MSGS_PER_CALL], - unencrypted_logs_hash:[0; NUM_FIELDS_PER_SHA256], + new_l2_to_l1_msgs: [0; MAX_NEW_L2_TO_L1_MSGS_PER_CALL], + unencrypted_logs_hash: [0; NUM_FIELDS_PER_SHA256], unencrypted_log_preimages_length: 0, historical_header: Header::empty(), - prover_address: AztecAddress::zero(), + prover_address: AztecAddress::zero() }, - is_execution_request: true, + is_execution_request: true }; reader.finish(); @@ -397,7 +365,9 @@ impl PrivateContext { assert(item.public_inputs.call_context.is_delegate_call == false); assert(item.public_inputs.call_context.is_static_call == false); assert(item.public_inputs.call_context.is_contract_deployment == false); - assert(item.public_inputs.call_context.msg_sender.eq(self.inputs.call_context.storage_contract_address)); + assert( + item.public_inputs.call_context.msg_sender.eq(self.inputs.call_context.storage_contract_address) + ); assert(item.public_inputs.call_context.storage_contract_address.eq(contract_address)); self.public_call_stack_hashes.push(item.hash()); diff --git a/yarn-project/aztec-nr/aztec/src/context/public_context.nr b/yarn-project/aztec-nr/aztec/src/context/public_context.nr index 2309a906d22..aec62abe430 100644 --- a/yarn-project/aztec-nr/aztec/src/context/public_context.nr +++ b/yarn-project/aztec-nr/aztec/src/context/public_context.nr @@ -1,42 +1,24 @@ use crate::{ - context::inputs::PublicContextInputs, - messaging::process_l1_to_l2_message, - oracle::{ - arguments, - public_call::call_public_function_internal, - }, + context::inputs::PublicContextInputs, messaging::process_l1_to_l2_message, + oracle::{arguments, public_call::call_public_function_internal} }; use dep::protocol_types::{ abis::{ - global_variables::GlobalVariables, - function_selector::FunctionSelector, - private_circuit_public_inputs::PrivateCircuitPublicInputs, - public_call_stack_item::PublicCallStackItem, - public_circuit_public_inputs::PublicCircuitPublicInputs, - side_effect::{SideEffect, SideEffectLinkedToNoteHash}, - }, - address::{ - AztecAddress, - EthAddress, - }, + global_variables::GlobalVariables, function_selector::FunctionSelector, + private_circuit_public_inputs::PrivateCircuitPublicInputs, + public_call_stack_item::PublicCallStackItem, + public_circuit_public_inputs::PublicCircuitPublicInputs, + side_effect::{SideEffect, SideEffectLinkedToNoteHash} +}, + address::{AztecAddress, EthAddress}, constants::{ - MAX_NEW_COMMITMENTS_PER_CALL, - MAX_NEW_L2_TO_L1_MSGS_PER_CALL, - MAX_NEW_NULLIFIERS_PER_CALL, - MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, - MAX_PUBLIC_DATA_READS_PER_CALL, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, - MAX_READ_REQUESTS_PER_CALL, - NUM_FIELDS_PER_SHA256, - RETURN_VALUES_LENGTH, - }, - contrakt::{ - storage_read::StorageRead, - storage_update_request::StorageUpdateRequest, - }, - hash::hash_args, - header::Header, - utils::reader::Reader, + MAX_NEW_COMMITMENTS_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_DATA_READS_PER_CALL, + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, MAX_READ_REQUESTS_PER_CALL, NUM_FIELDS_PER_SHA256, + RETURN_VALUES_LENGTH +}, + contrakt::{storage_read::StorageRead, storage_update_request::StorageUpdateRequest}, + hash::hash_args, header::Header, utils::reader::Reader }; struct PublicContext { @@ -69,29 +51,20 @@ impl PublicContext { let empty_storage_read = StorageRead::empty(); let empty_storage_update = StorageUpdateRequest::empty(); PublicContext { - inputs: inputs, + inputs, side_effect_counter: inputs.call_context.start_side_effect_counter, - - args_hash: args_hash, + args_hash, return_values: BoundedVec::new(0), - contract_storage_update_requests: BoundedVec::new(empty_storage_update), contract_storage_reads: BoundedVec::new(empty_storage_read), public_call_stack_hashes: BoundedVec::new(0), - new_commitments: BoundedVec::new(SideEffect::empty()), new_nullifiers: BoundedVec::new(SideEffectLinkedToNoteHash::empty()), - new_l2_to_l1_msgs: BoundedVec::new(0), - - unencrypted_logs_hash: BoundedVec::new(0), unencrypted_logs_preimages_length: 0, - historical_header: inputs.historical_header, - prover_address: AztecAddress::zero(), - - // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) + prover_address: AztecAddress::zero() // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) // encrypted_logs_preimages: Vec::new(), // unencrypted_logs_preimages: Vec::new(), } @@ -142,7 +115,6 @@ impl PublicContext { let unencrypted_logs_hash = [0; NUM_FIELDS_PER_SHA256]; let unencrypted_log_preimages_length = 0; - // Compute the public call stack hashes let pub_circuit_pub_inputs = PublicCircuitPublicInputs { call_context: self.inputs.call_context, // Done @@ -154,19 +126,16 @@ impl PublicContext { new_nullifiers: self.new_nullifiers.storage, public_call_stack_hashes: self.public_call_stack_hashes.storage, new_l2_to_l1_msgs: self.new_l2_to_l1_msgs.storage, - unencrypted_logs_hash: unencrypted_logs_hash, - unencrypted_log_preimages_length: unencrypted_log_preimages_length, + unencrypted_logs_hash, + unencrypted_log_preimages_length, historical_header: self.inputs.historical_header, - prover_address: self.prover_address, + prover_address: self.prover_address }; pub_circuit_pub_inputs } pub fn push_new_note_hash(&mut self, note_hash: Field) { - let side_effect = SideEffect { - value: note_hash, - counter: self.side_effect_counter - }; + let side_effect = SideEffect { value: note_hash, counter: self.side_effect_counter }; self.new_commitments.push(side_effect); self.side_effect_counter = self.side_effect_counter + 1; } @@ -189,7 +158,16 @@ impl PublicContext { // Note this returns self to get around an issue where mutable structs do not maintain mutations unless reassigned pub fn consume_l1_to_l2_message(&mut self, msg_key: Field, content: Field, secret: Field) { let this = (*self).this_address(); - let nullifier = process_l1_to_l2_message(self.historical_header.state.l1_to_l2_message_tree.root, this, self.this_portal_address(), self.chain_id(), self.version(), msg_key, content, secret); + let nullifier = process_l1_to_l2_message( + self.historical_header.state.l1_to_l2_message_tree.root, + this, + self.this_portal_address(), + self.chain_id(), + self.version(), + msg_key, + content, + secret + ); // Push nullifier (and the "commitment" corresponding to this can be "empty") self.push_new_nullifier(nullifier, 0) @@ -211,27 +189,18 @@ impl PublicContext { _self: Self, contract_address: AztecAddress, function_selector: FunctionSelector, - args: [Field; ARGS_COUNT], + args: [Field; ARGS_COUNT] ) -> [Field; RETURN_VALUES_LENGTH] { let args_hash = hash_args(args); assert(args_hash == arguments::pack_arguments(args)); - call_public_function_internal( - contract_address, - function_selector, - args_hash, - ) + call_public_function_internal(contract_address, function_selector, args_hash) } pub fn call_public_function_no_args( _self: Self, contract_address: AztecAddress, - function_selector: FunctionSelector, + function_selector: FunctionSelector ) -> [Field; RETURN_VALUES_LENGTH] { - call_public_function_internal( - contract_address, - function_selector, - 0, - ) + call_public_function_internal(contract_address, function_selector, 0) } - } diff --git a/yarn-project/aztec-nr/aztec/src/hash.nr b/yarn-project/aztec-nr/aztec/src/hash.nr index 03689083fb8..d59bdd9a7c3 100644 --- a/yarn-project/aztec-nr/aztec/src/hash.nr +++ b/yarn-project/aztec-nr/aztec/src/hash.nr @@ -1,7 +1,4 @@ -use dep::protocol_types::{ - constants::GENERATOR_INDEX__L1_TO_L2_MESSAGE_SECRET, - hash::pedersen_hash, -}; +use dep::protocol_types::{constants::GENERATOR_INDEX__L1_TO_L2_MESSAGE_SECRET, hash::pedersen_hash}; pub fn compute_secret_hash(secret: Field) -> Field { // TODO(#1205) This is probably not the right index to use diff --git a/yarn-project/aztec-nr/aztec/src/hasher.nr b/yarn-project/aztec-nr/aztec/src/hasher.nr index fcfd27a74ac..b1f1544112b 100644 --- a/yarn-project/aztec-nr/aztec/src/hasher.nr +++ b/yarn-project/aztec-nr/aztec/src/hasher.nr @@ -1,7 +1,4 @@ -use dep::protocol_types::{ - hash::hash_args, - traits::Hash, -}; +use dep::protocol_types::{hash::hash_args, traits::Hash}; struct Hasher { fields: [Field], @@ -14,7 +11,7 @@ impl Hash for Hasher { } impl Hasher { - pub fn new()-> Self { + pub fn new() -> Self { Self { fields: [] } } diff --git a/yarn-project/aztec-nr/aztec/src/history/contract_inclusion.nr b/yarn-project/aztec-nr/aztec/src/history/contract_inclusion.nr index 5b4469b20f5..21137cc7e5a 100644 --- a/yarn-project/aztec-nr/aztec/src/history/contract_inclusion.nr +++ b/yarn-project/aztec-nr/aztec/src/history/contract_inclusion.nr @@ -1,17 +1,10 @@ use dep::protocol_types::{ - abis::{ - new_contract_data::NewContractData as ContractLeafPreimage, - }, - address::{AztecAddress, EthAddress}, - contract_class::ContractClassId, - grumpkin_point::GrumpkinPoint, + abis::{new_contract_data::NewContractData as ContractLeafPreimage}, + address::{AztecAddress, EthAddress}, contract_class::ContractClassId, grumpkin_point::GrumpkinPoint }; use dep::std::merkle::compute_merkle_root; -use crate::{ - context::PrivateContext, - oracle::get_membership_witness::get_contract_membership_witness, -}; +use crate::{context::PrivateContext, oracle::get_membership_witness::get_contract_membership_witness}; // Proves that a contract exists at block `block_number` and returns its address. // Note: This can be used to approximate a factory pattern --> a factory contract could perform this proof and that diff --git a/yarn-project/aztec-nr/aztec/src/history/note_inclusion.nr b/yarn-project/aztec-nr/aztec/src/history/note_inclusion.nr index b4170fde8c9..0d47e4d84f4 100644 --- a/yarn-project/aztec-nr/aztec/src/history/note_inclusion.nr +++ b/yarn-project/aztec-nr/aztec/src/history/note_inclusion.nr @@ -3,11 +3,8 @@ use dep::protocol_types::header::Header; use crate::{ context::PrivateContext, - note::{ - utils::compute_note_hash_for_consumption, - note_interface::NoteInterface, - }, - oracle::get_membership_witness::get_note_hash_membership_witness, + note::{utils::compute_note_hash_for_consumption, note_interface::NoteInterface}, + oracle::get_membership_witness::get_note_hash_membership_witness }; pub fn _note_inclusion(note: Note, header: Header) where Note: NoteInterface { diff --git a/yarn-project/aztec-nr/aztec/src/history/note_validity.nr b/yarn-project/aztec-nr/aztec/src/history/note_validity.nr index 916e6ff16ef..c929f15eca9 100644 --- a/yarn-project/aztec-nr/aztec/src/history/note_validity.nr +++ b/yarn-project/aztec-nr/aztec/src/history/note_validity.nr @@ -1,15 +1,10 @@ use crate::{ context::PrivateContext, history::{ - note_inclusion::prove_note_inclusion, - note_inclusion::_note_inclusion, - nullifier_non_inclusion::prove_note_not_nullified, - nullifier_non_inclusion::_nullifier_non_inclusion, - }, - note::{ - utils::compute_siloed_nullifier, - note_interface::NoteInterface, - }, + note_inclusion::prove_note_inclusion, note_inclusion::_note_inclusion, + nullifier_non_inclusion::prove_note_not_nullified, nullifier_non_inclusion::_nullifier_non_inclusion +}, + note::{utils::compute_siloed_nullifier, note_interface::NoteInterface} }; pub fn prove_note_validity(note: Note, context: &mut PrivateContext) where Note: NoteInterface { diff --git a/yarn-project/aztec-nr/aztec/src/history/nullifier_inclusion.nr b/yarn-project/aztec-nr/aztec/src/history/nullifier_inclusion.nr index 6a1a28d6ac5..1a7de2c97b6 100644 --- a/yarn-project/aztec-nr/aztec/src/history/nullifier_inclusion.nr +++ b/yarn-project/aztec-nr/aztec/src/history/nullifier_inclusion.nr @@ -2,12 +2,8 @@ use dep::std::merkle::compute_merkle_root; use dep::protocol_types::header::Header; use crate::{ - context::PrivateContext, - oracle::get_nullifier_membership_witness::get_nullifier_membership_witness, - note::{ - utils::compute_siloed_nullifier, - note_interface::NoteInterface, - }, + context::PrivateContext, oracle::get_nullifier_membership_witness::get_nullifier_membership_witness, + note::{utils::compute_siloed_nullifier, note_interface::NoteInterface} }; fn _nullifier_inclusion(nullifier: Field, header: Header) { diff --git a/yarn-project/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr b/yarn-project/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr index d202ac3a290..1d17e2d96d8 100644 --- a/yarn-project/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr +++ b/yarn-project/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr @@ -1,18 +1,8 @@ use dep::std::merkle::compute_merkle_root; -use dep::protocol_types::{ - header::Header, - utils::field::{ - full_field_less_than, - full_field_greater_than, - }, -}; +use dep::protocol_types::{header::Header, utils::field::{full_field_less_than, full_field_greater_than}}; use crate::{ - context::PrivateContext, - note::{ - utils::compute_siloed_nullifier, - note_interface::NoteInterface, - }, - oracle::get_nullifier_membership_witness::get_low_nullifier_membership_witness, + context::PrivateContext, note::{utils::compute_siloed_nullifier, note_interface::NoteInterface}, + oracle::get_nullifier_membership_witness::get_low_nullifier_membership_witness }; pub fn _nullifier_non_inclusion(nullifier: Field, header: Header) { diff --git a/yarn-project/aztec-nr/aztec/src/history/public_value_inclusion.nr b/yarn-project/aztec-nr/aztec/src/history/public_value_inclusion.nr index 5a5f7f13dc5..47dbae54b6d 100644 --- a/yarn-project/aztec-nr/aztec/src/history/public_value_inclusion.nr +++ b/yarn-project/aztec-nr/aztec/src/history/public_value_inclusion.nr @@ -1,20 +1,10 @@ use dep::protocol_types::{ - constants::GENERATOR_INDEX__PUBLIC_LEAF_INDEX, - hash::pedersen_hash, - address::{ - AztecAddress - }, - header::Header, - utils::field::full_field_less_than, + constants::GENERATOR_INDEX__PUBLIC_LEAF_INDEX, hash::pedersen_hash, address::{AztecAddress}, + header::Header, utils::field::full_field_less_than }; use dep::std::merkle::compute_merkle_root; -use crate::{ - context::PrivateContext, - oracle::get_public_data_witness::{ - get_public_data_witness, - }, -}; +use crate::{context::PrivateContext, oracle::get_public_data_witness::{get_public_data_witness}}; fn _public_value_inclusion( value: Field, diff --git a/yarn-project/aztec-nr/aztec/src/key/nullifier_key.nr b/yarn-project/aztec-nr/aztec/src/key/nullifier_key.nr index 0b93dc87b77..7154a1917d8 100644 --- a/yarn-project/aztec-nr/aztec/src/key/nullifier_key.nr +++ b/yarn-project/aztec-nr/aztec/src/key/nullifier_key.nr @@ -1,8 +1,8 @@ -use dep::protocol_types::{ - address::AztecAddress, - grumpkin_point::GrumpkinPoint, -}; +use dep::protocol_types::{address::AztecAddress, grumpkin_point::GrumpkinPoint}; -pub fn validate_nullifier_key_against_address(_address: AztecAddress, _nullifier_public_key: GrumpkinPoint) { +pub fn validate_nullifier_key_against_address( + _address: AztecAddress, + _nullifier_public_key: GrumpkinPoint +) { // TODO: Nullifier public key should be part of the address. } diff --git a/yarn-project/aztec-nr/aztec/src/log.nr b/yarn-project/aztec-nr/aztec/src/log.nr index bc9141debdb..b70c199f5aa 100644 --- a/yarn-project/aztec-nr/aztec/src/log.nr +++ b/yarn-project/aztec-nr/aztec/src/log.nr @@ -1,9 +1,6 @@ use crate::context::{PrivateContext, PublicContext}; use crate::oracle; -use dep::protocol_types::{ - address::AztecAddress, - grumpkin_point::GrumpkinPoint, -}; +use dep::protocol_types::{address::AztecAddress, grumpkin_point::GrumpkinPoint}; pub fn emit_encrypted_log( context: &mut PrivateContext, diff --git a/yarn-project/aztec-nr/aztec/src/messaging.nr b/yarn-project/aztec-nr/aztec/src/messaging.nr index c75febd0a0e..caf26c3c0ca 100644 --- a/yarn-project/aztec-nr/aztec/src/messaging.nr +++ b/yarn-project/aztec-nr/aztec/src/messaging.nr @@ -7,10 +7,7 @@ use crate::oracle::get_l1_to_l2_message::get_l1_to_l2_message_call; use dep::std::merkle::compute_merkle_root; -use dep::protocol_types::address::{ - AztecAddress, - EthAddress, -}; +use dep::protocol_types::address::{AztecAddress, EthAddress}; // Returns the nullifier for the message pub fn process_l1_to_l2_message( diff --git a/yarn-project/aztec-nr/aztec/src/messaging/l1_to_l2_message.nr b/yarn-project/aztec-nr/aztec/src/messaging/l1_to_l2_message.nr index a4dfcfa4e52..a8f86a4ddf1 100644 --- a/yarn-project/aztec-nr/aztec/src/messaging/l1_to_l2_message.nr +++ b/yarn-project/aztec-nr/aztec/src/messaging/l1_to_l2_message.nr @@ -1,17 +1,7 @@ use dep::protocol_types::{ - address::{ - AztecAddress, - EthAddress, - }, - constants::{ - L1_TO_L2_MESSAGE_LENGTH, - GENERATOR_INDEX__NULLIFIER, - GENERATOR_INDEX__L1_TO_L2_MESSAGE_SECRET, - }, - hash::{ - pedersen_hash, - sha256_to_field, - }, + address::{AztecAddress, EthAddress}, + constants::{L1_TO_L2_MESSAGE_LENGTH, GENERATOR_INDEX__NULLIFIER, GENERATOR_INDEX__L1_TO_L2_MESSAGE_SECRET}, + hash::{pedersen_hash, sha256_to_field} }; struct L1ToL2Message { @@ -39,11 +29,11 @@ impl L1ToL2Message { recipient: AztecAddress::from_field(fields[2]), version: fields[3], content: fields[4], - secret: secret, + secret, secret_hash: fields[5], deadline: fields[6] as u32, fee: fields[7] as u64, - tree_index: tree_index + tree_index } } @@ -75,14 +65,17 @@ impl L1ToL2Message { } let message_hash = sha256_to_field(hash_bytes); - message_hash + message_hash } // The nullifier of a l1 to l2 message is the hash of the message salted with the secret and tree index // docs:start:l1_to_l2_message_compute_nullifier pub fn compute_nullifier(self: Self) -> Field { let message_hash = self.hash(); - pedersen_hash([message_hash, self.secret, self.tree_index], GENERATOR_INDEX__NULLIFIER) + pedersen_hash( + [message_hash, self.secret, self.tree_index], + GENERATOR_INDEX__NULLIFIER + ) } // docs:end:l1_to_l2_message_compute_nullifier } diff --git a/yarn-project/aztec-nr/aztec/src/messaging/l1_to_l2_message_getter_data.nr b/yarn-project/aztec-nr/aztec/src/messaging/l1_to_l2_message_getter_data.nr index 0f7254710c4..ae710e30e1b 100644 --- a/yarn-project/aztec-nr/aztec/src/messaging/l1_to_l2_message_getter_data.nr +++ b/yarn-project/aztec-nr/aztec/src/messaging/l1_to_l2_message_getter_data.nr @@ -1,11 +1,5 @@ use crate::messaging::l1_to_l2_message::L1ToL2Message; -use dep::protocol_types::{ - constants::{ - L1_TO_L2_MSG_TREE_HEIGHT, - L1_TO_L2_MESSAGE_LENGTH, - }, - utils::arr_copy_slice, -}; +use dep::protocol_types::{constants::{L1_TO_L2_MSG_TREE_HEIGHT, L1_TO_L2_MESSAGE_LENGTH}, utils::arr_copy_slice}; struct L1ToL2MessageGetterData { message: L1ToL2Message, diff --git a/yarn-project/aztec-nr/aztec/src/note/lifecycle.nr b/yarn-project/aztec-nr/aztec/src/note/lifecycle.nr index 84326f9ace6..0596ac66ea1 100644 --- a/yarn-project/aztec-nr/aztec/src/note/lifecycle.nr +++ b/yarn-project/aztec-nr/aztec/src/note/lifecycle.nr @@ -1,11 +1,7 @@ -use crate::context::{ - PrivateContext, - PublicContext, -}; +use crate::context::{PrivateContext, PublicContext}; use crate::note::{ - note_header::NoteHeader, - note_interface::NoteInterface, - utils::{compute_note_hash_for_insertion, compute_note_hash_for_consumption}, + note_header::NoteHeader, note_interface::NoteInterface, + utils::{compute_note_hash_for_insertion, compute_note_hash_for_consumption} }; use crate::oracle::notes::{notify_created_note, notify_nullified_note}; @@ -34,7 +30,11 @@ pub fn create_note( } } -pub fn create_note_hash_from_public(context: &mut PublicContext, storage_slot: Field, note: &mut Note) where Note: NoteInterface { +pub fn create_note_hash_from_public( + context: &mut PublicContext, + storage_slot: Field, + note: &mut Note +) where Note: NoteInterface { let contract_address = (*context).this_address(); let header = NoteHeader { contract_address, storage_slot, nonce: 0, is_transient: true }; diff --git a/yarn-project/aztec-nr/aztec/src/note/utils.nr b/yarn-project/aztec-nr/aztec/src/note/utils.nr index 81f2f2c17ce..8aa346dc16a 100644 --- a/yarn-project/aztec-nr/aztec/src/note/utils.nr +++ b/yarn-project/aztec-nr/aztec/src/note/utils.nr @@ -1,20 +1,12 @@ -use crate::{ - context::PrivateContext, - note::{ - note_header::NoteHeader, - note_interface::NoteInterface, - }, -}; +use crate::{context::PrivateContext, note::{note_header::NoteHeader, note_interface::NoteInterface}}; use dep::protocol_types::{ address::AztecAddress, constants::{ - GENERATOR_INDEX__OUTER_NULLIFIER, - GENERATOR_INDEX__UNIQUE_COMMITMENT, - GENERATOR_INDEX__SILOED_COMMITMENT, - }, - hash::pedersen_hash, - utils::arr_copy_slice, + GENERATOR_INDEX__OUTER_NULLIFIER, GENERATOR_INDEX__UNIQUE_COMMITMENT, + GENERATOR_INDEX__SILOED_COMMITMENT +}, + hash::pedersen_hash, utils::arr_copy_slice }; fn compute_siloed_hash(contract_address: AztecAddress, inner_note_hash: Field) -> Field { diff --git a/yarn-project/aztec-nr/aztec/src/oracle/call_private_function.nr b/yarn-project/aztec-nr/aztec/src/oracle/call_private_function.nr index 489fd383082..069247c9ea3 100644 --- a/yarn-project/aztec-nr/aztec/src/oracle/call_private_function.nr +++ b/yarn-project/aztec-nr/aztec/src/oracle/call_private_function.nr @@ -1,10 +1,6 @@ use dep::protocol_types::{ - abis::{ - function_selector::FunctionSelector, - private_call_stack_item::PrivateCallStackItem, - }, - address::AztecAddress, - constants::PRIVATE_CALL_STACK_ITEM_LENGTH, + abis::{function_selector::FunctionSelector, private_call_stack_item::PrivateCallStackItem}, + address::AztecAddress, constants::PRIVATE_CALL_STACK_ITEM_LENGTH }; #[oracle(callPrivateFunction)] diff --git a/yarn-project/aztec-nr/aztec/src/oracle/context.nr b/yarn-project/aztec-nr/aztec/src/oracle/context.nr index f5fae3b451a..56e1b229549 100644 --- a/yarn-project/aztec-nr/aztec/src/oracle/context.nr +++ b/yarn-project/aztec-nr/aztec/src/oracle/context.nr @@ -1,7 +1,4 @@ -use dep::protocol_types::address::{ - AztecAddress, - EthAddress, -}; +use dep::protocol_types::address::{AztecAddress, EthAddress}; #[oracle(getPortalContractAddress)] fn _get_portal_address(_contract_address: AztecAddress) -> EthAddress {} diff --git a/yarn-project/aztec-nr/aztec/src/oracle/enqueue_public_function_call.nr b/yarn-project/aztec-nr/aztec/src/oracle/enqueue_public_function_call.nr index d48f6b2ab63..d5bafbc28cc 100644 --- a/yarn-project/aztec-nr/aztec/src/oracle/enqueue_public_function_call.nr +++ b/yarn-project/aztec-nr/aztec/src/oracle/enqueue_public_function_call.nr @@ -1,7 +1,4 @@ -use dep::protocol_types::{ - abis::function_selector::FunctionSelector, - address::AztecAddress, -}; +use dep::protocol_types::{abis::function_selector::FunctionSelector, address::AztecAddress}; // contract_address + // args_hash + diff --git a/yarn-project/aztec-nr/aztec/src/oracle/get_membership_witness.nr b/yarn-project/aztec-nr/aztec/src/oracle/get_membership_witness.nr index 14d5b9e20ff..1e82b12c91e 100644 --- a/yarn-project/aztec-nr/aztec/src/oracle/get_membership_witness.nr +++ b/yarn-project/aztec-nr/aztec/src/oracle/get_membership_witness.nr @@ -1,11 +1,4 @@ -use dep::protocol_types::{ - constants::{ - ARCHIVE_HEIGHT, - CONTRACT_TREE_HEIGHT, - NOTE_HASH_TREE_HEIGHT, - }, - utils::arr_copy_slice, -}; +use dep::protocol_types::{constants::{ARCHIVE_HEIGHT, CONTRACT_TREE_HEIGHT, NOTE_HASH_TREE_HEIGHT}, utils::arr_copy_slice}; global CONTRACT_TREE_ID = 0; global NOTE_HASH_TREE_ID = 2; @@ -24,9 +17,17 @@ struct MembershipWitness { } #[oracle(getMembershipWitness)] -fn get_membership_witness_oracle(_block_number: u32, _tree_id: Field, _leaf_value: Field) -> [Field; M] {} +fn get_membership_witness_oracle( + _block_number: u32, + _tree_id: Field, + _leaf_value: Field +) -> [Field; M] {} -unconstrained pub fn get_membership_witness(block_number: u32, tree_id: Field, leaf_value: Field) -> MembershipWitness { +unconstrained pub fn get_membership_witness( + block_number: u32, + tree_id: Field, + leaf_value: Field +) -> MembershipWitness { let fields: [Field; M] = get_membership_witness_oracle(block_number, tree_id, leaf_value); MembershipWitness { index: fields[0], path: arr_copy_slice(fields, [0; N], 1) } } diff --git a/yarn-project/aztec-nr/aztec/src/oracle/get_nullifier_membership_witness.nr b/yarn-project/aztec-nr/aztec/src/oracle/get_nullifier_membership_witness.nr index 3cf667ce715..22d97991fda 100644 --- a/yarn-project/aztec-nr/aztec/src/oracle/get_nullifier_membership_witness.nr +++ b/yarn-project/aztec-nr/aztec/src/oracle/get_nullifier_membership_witness.nr @@ -1,11 +1,6 @@ use dep::protocol_types::{ - abis::nullifier_leaf_preimage::{ - NullifierLeafPreimage, - NULLIFIER_LEAF_PREIMAGE_LENGTH, - }, - constants::NULLIFIER_TREE_HEIGHT, - hash::pedersen_hash, - utils::arr_copy_slice, + abis::nullifier_leaf_preimage::{NullifierLeafPreimage, NULLIFIER_LEAF_PREIMAGE_LENGTH}, + constants::NULLIFIER_TREE_HEIGHT, hash::pedersen_hash, utils::arr_copy_slice }; // INDEX_LENGTH + NULLIFIER_LEAF_PREIMAGE_LENGTH + NULLIFIER_TREE_HEIGHT @@ -23,7 +18,11 @@ impl NullifierMembershipWitness { Self { index: fields[0], leaf_preimage: NullifierLeafPreimage::deserialize(leaf_preimage_fields), - path: arr_copy_slice(fields, [0; NULLIFIER_TREE_HEIGHT], 1 + NULLIFIER_LEAF_PREIMAGE_LENGTH) + path: arr_copy_slice( + fields, + [0; NULLIFIER_TREE_HEIGHT], + 1 + NULLIFIER_LEAF_PREIMAGE_LENGTH + ) } } } @@ -42,7 +41,10 @@ unconstrained pub fn get_low_nullifier_membership_witness(block_number: u32, nul } #[oracle(getNullifierMembershipWitness)] -fn get_nullifier_membership_witness_oracle(_block_number: u32, _nullifier: Field) -> [Field; NULLIFIER_MEMBERSHIP_WITNESS] {} +fn get_nullifier_membership_witness_oracle( + _block_number: u32, + _nullifier: Field +) -> [Field; NULLIFIER_MEMBERSHIP_WITNESS] {} // Nullifier here refers to the nullifier we are looking to get non-inclusion proof for (by proving that a lower // nullifier's next_value is bigger than the nullifier) diff --git a/yarn-project/aztec-nr/aztec/src/oracle/get_public_data_witness.nr b/yarn-project/aztec-nr/aztec/src/oracle/get_public_data_witness.nr index 1e843f79408..c7a8f537e97 100644 --- a/yarn-project/aztec-nr/aztec/src/oracle/get_public_data_witness.nr +++ b/yarn-project/aztec-nr/aztec/src/oracle/get_public_data_witness.nr @@ -1,12 +1,7 @@ use dep::protocol_types::{ - constants::PUBLIC_DATA_TREE_HEIGHT, - hash::pedersen_hash, - public_data_tree_leaf_preimage::PublicDataTreeLeafPreimage, - traits::{ - Hash, - Serialize, - }, - utils::arr_copy_slice, + constants::PUBLIC_DATA_TREE_HEIGHT, hash::pedersen_hash, + public_data_tree_leaf_preimage::PublicDataTreeLeafPreimage, traits::{Hash, Serialize}, + utils::arr_copy_slice }; global LEAF_PREIMAGE_LENGTH: Field = 4; @@ -19,7 +14,10 @@ struct PublicDataWitness { } #[oracle(getPublicDataTreeWitness)] -fn get_public_data_witness_oracle(_block_number: u32, _leaf_slot: Field) -> [Field; PUBLIC_DATA_WITNESS] {} +fn get_public_data_witness_oracle( + _block_number: u32, + _leaf_slot: Field +) -> [Field; PUBLIC_DATA_WITNESS] {} unconstrained pub fn get_public_data_witness(block_number: u32, leaf_slot: Field) -> PublicDataWitness { let fields = get_public_data_witness_oracle(block_number, leaf_slot); diff --git a/yarn-project/aztec-nr/aztec/src/oracle/get_public_key.nr b/yarn-project/aztec-nr/aztec/src/oracle/get_public_key.nr index 5aea4515160..abb7167dee9 100644 --- a/yarn-project/aztec-nr/aztec/src/oracle/get_public_key.nr +++ b/yarn-project/aztec-nr/aztec/src/oracle/get_public_key.nr @@ -1,11 +1,4 @@ -use dep::protocol_types::{ - address::{ - AztecAddress, - PartialAddress, - PublicKeysHash, - }, - grumpkin_point::GrumpkinPoint, -}; +use dep::protocol_types::{address::{AztecAddress, PartialAddress, PublicKeysHash}, grumpkin_point::GrumpkinPoint}; #[oracle(getPublicKeyAndPartialAddress)] fn get_public_key_and_partial_address_oracle(_address: AztecAddress) -> [Field; 3] {} diff --git a/yarn-project/aztec-nr/aztec/src/oracle/header.nr b/yarn-project/aztec-nr/aztec/src/oracle/header.nr index bcb7027d2d6..14e6eb63c5e 100644 --- a/yarn-project/aztec-nr/aztec/src/oracle/header.nr +++ b/yarn-project/aztec-nr/aztec/src/oracle/header.nr @@ -1,13 +1,7 @@ use dep::std::merkle::compute_merkle_root; -use dep::protocol_types::{ - constants::HEADER_LENGTH, - header::Header, -}; - -use crate::{ - context::PrivateContext, - oracle::get_membership_witness::get_archive_membership_witness, -}; +use dep::protocol_types::{constants::HEADER_LENGTH, header::Header}; + +use crate::{context::PrivateContext, oracle::get_membership_witness::get_archive_membership_witness}; #[oracle(getHeader)] fn get_header_at_oracle(_block_number: u32) -> [Field; HEADER_LENGTH] {} diff --git a/yarn-project/aztec-nr/aztec/src/oracle/logs.nr b/yarn-project/aztec-nr/aztec/src/oracle/logs.nr index eefed0a547d..04979ab54c8 100644 --- a/yarn-project/aztec-nr/aztec/src/oracle/logs.nr +++ b/yarn-project/aztec-nr/aztec/src/oracle/logs.nr @@ -1,8 +1,4 @@ -use dep::protocol_types::{ - address::AztecAddress, - constants::NUM_FIELDS_PER_SHA256, - grumpkin_point::GrumpkinPoint, -}; +use dep::protocol_types::{address::AztecAddress, constants::NUM_FIELDS_PER_SHA256, grumpkin_point::GrumpkinPoint}; // TODO: Should take encrypted data. #[oracle(emitEncryptedLog)] @@ -23,7 +19,11 @@ unconstrained pub fn emit_encrypted_log( } #[oracle(emitUnencryptedLog)] -fn emit_unencrypted_log_oracle(_contract_address: AztecAddress, _event_selector: Field, _message: T) -> Field {} +fn emit_unencrypted_log_oracle( + _contract_address: AztecAddress, + _event_selector: Field, + _message: T +) -> Field {} unconstrained pub fn emit_unencrypted_log( contract_address: AztecAddress, diff --git a/yarn-project/aztec-nr/aztec/src/oracle/nullifier_key.nr b/yarn-project/aztec-nr/aztec/src/oracle/nullifier_key.nr index a99b946752f..c3429d4f811 100644 --- a/yarn-project/aztec-nr/aztec/src/oracle/nullifier_key.nr +++ b/yarn-project/aztec-nr/aztec/src/oracle/nullifier_key.nr @@ -1,8 +1,4 @@ -use dep::protocol_types::{ - address::AztecAddress, - grumpkin_point::GrumpkinPoint, - grumpkin_private_key::GrumpkinPrivateKey, -}; +use dep::protocol_types::{address::AztecAddress, grumpkin_point::GrumpkinPoint, grumpkin_private_key::GrumpkinPrivateKey}; struct NullifierKeyPair { account: AztecAddress, diff --git a/yarn-project/aztec-nr/aztec/src/oracle/public_call.nr b/yarn-project/aztec-nr/aztec/src/oracle/public_call.nr index 0bc81973675..26b29d95bfe 100644 --- a/yarn-project/aztec-nr/aztec/src/oracle/public_call.nr +++ b/yarn-project/aztec-nr/aztec/src/oracle/public_call.nr @@ -1,8 +1,4 @@ -use dep::protocol_types::{ - abis::function_selector::FunctionSelector, - address::AztecAddress, - constants::RETURN_VALUES_LENGTH, -}; +use dep::protocol_types::{abis::function_selector::FunctionSelector, address::AztecAddress, constants::RETURN_VALUES_LENGTH}; #[oracle(callPublicFunction)] fn call_public_function_oracle( diff --git a/yarn-project/aztec-nr/aztec/src/state_vars/immutable_singleton.nr b/yarn-project/aztec-nr/aztec/src/state_vars/immutable_singleton.nr index ab676745d31..fed2d66a589 100644 --- a/yarn-project/aztec-nr/aztec/src/state_vars/immutable_singleton.nr +++ b/yarn-project/aztec-nr/aztec/src/state_vars/immutable_singleton.nr @@ -1,18 +1,10 @@ use dep::std::option::Option; -use dep::protocol_types::{ - address::AztecAddress, - constants::{ - GENERATOR_INDEX__INITIALIZATION_NULLIFIER, - }, - hash::pedersen_hash, -}; +use dep::protocol_types::{address::AztecAddress, constants::{GENERATOR_INDEX__INITIALIZATION_NULLIFIER}, hash::pedersen_hash}; use crate::context::{PrivateContext, Context}; use crate::note::{ - lifecycle::create_note, - note_getter::{get_note, view_notes}, - note_interface::NoteInterface, - note_viewer_options::NoteViewerOptions, + lifecycle::create_note, note_getter::{get_note, view_notes}, note_interface::NoteInterface, + note_viewer_options::NoteViewerOptions }; use crate::oracle::notes::check_nullifier_exists; use crate::state_vars::storage::Storage; @@ -28,15 +20,9 @@ impl Storage for ImmutableSingleton {} impl ImmutableSingleton { // docs:start:new - pub fn new( - context: Context, - storage_slot: Field, - ) -> Self { + pub fn new(context: Context, storage_slot: Field) -> Self { assert(storage_slot != 0, "Storage slot 0 not allowed. Storage slots must start from 1."); - Self { - context: context.private, - storage_slot, - } + Self { context: context.private, storage_slot } } // docs:end:new @@ -47,7 +33,10 @@ impl ImmutableSingleton { // This is especially dangerous for initial assignment to elements of a `Map` type (for example), because the storage slot often also identifies an actor. // e.g. the initial assignment to `my_map.at(msg.sender)` will leak: `msg.sender`, the fact that an element of `my_map` was assigned-to for the first time, and the contract_address. pub fn compute_initialization_nullifier(self) -> Field { - pedersen_hash([self.storage_slot], GENERATOR_INDEX__INITIALIZATION_NULLIFIER) + pedersen_hash( + [self.storage_slot], + GENERATOR_INDEX__INITIALIZATION_NULLIFIER + ) } // docs:start:is_initialized @@ -58,23 +47,14 @@ impl ImmutableSingleton { // docs:end:is_initialized // docs:start:initialize - pub fn initialize( - self, - note: &mut Note, - broadcast: bool, - ) where Note: NoteInterface { + pub fn initialize(self, note: &mut Note, broadcast: bool) where Note: NoteInterface { let context = self.context.unwrap(); // Nullify the storage slot. let nullifier = self.compute_initialization_nullifier(); context.push_new_nullifier(nullifier, 0); - create_note( - context, - self.storage_slot, - note, - broadcast, - ); + create_note(context, self.storage_slot, note, broadcast); } // docs:end:initialize diff --git a/yarn-project/aztec-nr/aztec/src/state_vars/map.nr b/yarn-project/aztec-nr/aztec/src/state_vars/map.nr index 7e38552e2ca..043c8a3f615 100644 --- a/yarn-project/aztec-nr/aztec/src/state_vars/map.nr +++ b/yarn-project/aztec-nr/aztec/src/state_vars/map.nr @@ -1,9 +1,6 @@ use crate::context::{PrivateContext, PublicContext, Context}; use dep::std::option::Option; -use dep::protocol_types::{ - hash::pedersen_hash, - traits::{ToField} -}; +use dep::protocol_types::{hash::pedersen_hash, traits::{ToField}}; use crate::state_vars::storage::Storage; // docs:start:map @@ -21,21 +18,17 @@ impl Map { pub fn new( context: Context, storage_slot: Field, - state_var_constructor: fn(Context, Field) -> V, + state_var_constructor: fn(Context, Field) -> V ) -> Self { assert(storage_slot != 0, "Storage slot 0 not allowed. Storage slots must start from 1."); - Map { - context, - storage_slot, - state_var_constructor, - } + Map { context, storage_slot, state_var_constructor } } // docs:end:new // docs:start:at pub fn at(self, key: K) -> V where K: ToField { // TODO(#1204): use a generator index for the storage slot - let derived_storage_slot = pedersen_hash([self.storage_slot, key.to_field()],0); + let derived_storage_slot = pedersen_hash([self.storage_slot, key.to_field()], 0); let state_var_constructor = self.state_var_constructor; state_var_constructor(self.context, derived_storage_slot) diff --git a/yarn-project/aztec-nr/aztec/src/state_vars/public_state.nr b/yarn-project/aztec-nr/aztec/src/state_vars/public_state.nr index 081b0d59653..883a2f7a3df 100644 --- a/yarn-project/aztec-nr/aztec/src/state_vars/public_state.nr +++ b/yarn-project/aztec-nr/aztec/src/state_vars/public_state.nr @@ -19,13 +19,10 @@ impl PublicState { pub fn new( // Note: Passing the contexts to new(...) just to have an interface compatible with a Map. context: Context, - storage_slot: Field, + storage_slot: Field ) -> Self { assert(storage_slot != 0, "Storage slot 0 not allowed. Storage slots must start from 1."); - PublicState { - context, - storage_slot, - } + PublicState { context, storage_slot } } // docs:end:public_state_struct_new diff --git a/yarn-project/aztec-nr/aztec/src/state_vars/set.nr b/yarn-project/aztec-nr/aztec/src/state_vars/set.nr index 7144bbe3013..2a56fb1f8da 100644 --- a/yarn-project/aztec-nr/aztec/src/state_vars/set.nr +++ b/yarn-project/aztec-nr/aztec/src/state_vars/set.nr @@ -1,17 +1,14 @@ use dep::std::option::Option; use dep::protocol_types::{ constants::{MAX_NOTES_PER_PAGE, MAX_READ_REQUESTS_PER_CALL}, - abis::side_effect::{SideEffect, SideEffectLinkedToNoteHash}, + abis::side_effect::{SideEffect, SideEffectLinkedToNoteHash} }; use crate::context::{PrivateContext, PublicContext, Context}; use crate::note::{ lifecycle::{create_note, create_note_hash_from_public, destroy_note}, - note_getter::{get_notes, view_notes}, - note_getter_options::NoteGetterOptions, - note_header::NoteHeader, - note_interface::NoteInterface, - note_viewer_options::NoteViewerOptions, - utils::compute_note_hash_for_consumption, + note_getter::{get_notes, view_notes}, note_getter_options::NoteGetterOptions, + note_header::NoteHeader, note_interface::NoteInterface, note_viewer_options::NoteViewerOptions, + utils::compute_note_hash_for_consumption }; use crate::state_vars::storage::Storage; @@ -26,49 +23,40 @@ impl Storage for Set {} impl Set { // docs:start:new - pub fn new( - context: Context, - storage_slot: Field, - ) -> Self { + pub fn new(context: Context, storage_slot: Field) -> Self { assert(storage_slot != 0, "Storage slot 0 not allowed. Storage slots must start from 1."); - Set { - context, - storage_slot, - } + Set { context, storage_slot } } // docs:end:new // docs:start:insert - pub fn insert(self, - note: &mut Note, - broadcast: bool, - ) where Note: NoteInterface { + pub fn insert(self, note: &mut Note, broadcast: bool) where Note: NoteInterface { create_note( self.context.private.unwrap(), self.storage_slot, note, - broadcast, + broadcast ); } // docs:end:insert // docs:start:insert_from_public pub fn insert_from_public(self, note: &mut Note) where Note: NoteInterface { - create_note_hash_from_public( - self.context.public.unwrap(), - self.storage_slot, - note, - ); + create_note_hash_from_public(self.context.public.unwrap(), self.storage_slot, note); } // docs:end:insert_from_public - + // DEPRECATED fn assert_contains_and_remove(_self: Self, _note: &mut Note, _nonce: Field) { - assert(false, "`assert_contains_and_remove` has been deprecated. Please call PXE.addNote() to add a note to the database. Then use Set.get_notes() and Set.remove() in your contract to verify and remove a note."); + assert( + false, "`assert_contains_and_remove` has been deprecated. Please call PXE.addNote() to add a note to the database. Then use Set.get_notes() and Set.remove() in your contract to verify and remove a note." + ); } // DEPRECATED fn assert_contains_and_remove_publicly_created(_self: Self, _note: &mut Note) { - assert(false, "`assert_contains_and_remove_publicly_created` has been deprecated. Please call PXE.addNote() to add a note to the database. Then use Set.get_notes() and Set.remove() in your contract to verify and remove a note."); + assert( + false, "`assert_contains_and_remove_publicly_created` has been deprecated. Please call PXE.addNote() to add a note to the database. Then use Set.get_notes() and Set.remove() in your contract to verify and remove a note." + ); } // docs:start:remove @@ -78,24 +66,17 @@ impl Set { let has_been_read = context.read_requests.any(|r: SideEffect| r.value == note_hash); assert(has_been_read, "Can only remove a note that has been read from the set."); - destroy_note( - context, - note, - ); + destroy_note(context, note); } // docs:end:remove // docs:start:get_notes pub fn get_notes( self, - options: NoteGetterOptions, + options: NoteGetterOptions ) -> [Option; MAX_READ_REQUESTS_PER_CALL] where Note: NoteInterface { let storage_slot = self.storage_slot; - let opt_notes = get_notes( - self.context.private.unwrap(), - storage_slot, - options, - ); + let opt_notes = get_notes(self.context.private.unwrap(), storage_slot, options); opt_notes } // docs:end:get_notes @@ -103,7 +84,7 @@ impl Set { // docs:start:view_notes unconstrained pub fn view_notes( self, - options: NoteViewerOptions, + options: NoteViewerOptions ) -> [Option; MAX_NOTES_PER_PAGE] where Note: NoteInterface { view_notes(self.storage_slot, options) } diff --git a/yarn-project/aztec-nr/aztec/src/state_vars/singleton.nr b/yarn-project/aztec-nr/aztec/src/state_vars/singleton.nr index 04f96e9fdea..49d34b0052b 100644 --- a/yarn-project/aztec-nr/aztec/src/state_vars/singleton.nr +++ b/yarn-project/aztec-nr/aztec/src/state_vars/singleton.nr @@ -1,24 +1,13 @@ use dep::std::option::Option; -use dep::protocol_types::{ - address::AztecAddress, - constants::{ - GENERATOR_INDEX__INITIALIZATION_NULLIFIER, - }, - hash::pedersen_hash, -}; +use dep::protocol_types::{address::AztecAddress, constants::{GENERATOR_INDEX__INITIALIZATION_NULLIFIER}, hash::pedersen_hash}; use crate::context::{PrivateContext, PublicContext, Context}; use crate::note::{ - lifecycle::{create_note, destroy_note}, - note_getter::{get_note, view_notes}, - note_interface::NoteInterface, - note_viewer_options::NoteViewerOptions, -}; -use crate::oracle::{ - nullifier_key::get_nullifier_secret_key, - notes::check_nullifier_exists, + lifecycle::{create_note, destroy_note}, note_getter::{get_note, view_notes}, + note_interface::NoteInterface, note_viewer_options::NoteViewerOptions }; +use crate::oracle::{nullifier_key::get_nullifier_secret_key, notes::check_nullifier_exists}; use crate::state_vars::storage::Storage; // docs:start:struct @@ -32,15 +21,9 @@ impl Storage for Singleton {} impl Singleton { // docs:start:new - pub fn new( - context: Context, - storage_slot: Field, - ) -> Self { + pub fn new(context: Context, storage_slot: Field) -> Self { assert(storage_slot != 0, "Storage slot 0 not allowed. Storage slots must start from 1."); - Self { - context: context.private, - storage_slot, - } + Self { context: context.private, storage_slot } } // docs:end:new @@ -53,7 +36,10 @@ impl Singleton { // Note: subsequent nullification of this state variable, via the `replace` method will not be leaky, if the `compute_nullifier()` method of the underlying note is designed to ensure privacy. // For example, if the `compute_nullifier()` method injects the secret key of a note owner into the computed nullifier's preimage. pub fn compute_initialization_nullifier(self) -> Field { - pedersen_hash([self.storage_slot], GENERATOR_INDEX__INITIALIZATION_NULLIFIER) + pedersen_hash( + [self.storage_slot], + GENERATOR_INDEX__INITIALIZATION_NULLIFIER + ) } // docs:start:is_initialized @@ -64,11 +50,7 @@ impl Singleton { // docs:end:is_initialized // docs:start:initialize - pub fn initialize( - self, - note: &mut Note, - broadcast: bool, - ) where Note: NoteInterface { + pub fn initialize(self, note: &mut Note, broadcast: bool) where Note: NoteInterface { let context = self.context.unwrap(); // Nullify the storage slot. @@ -80,11 +62,7 @@ impl Singleton { // docs:end:initialize // docs:start:replace - pub fn replace( - self, - new_note: &mut Note, - broadcast: bool, - ) where Note: NoteInterface { + pub fn replace(self, new_note: &mut Note, broadcast: bool) where Note: NoteInterface { let context = self.context.unwrap(); let prev_note = get_note(context, self.storage_slot); diff --git a/yarn-project/aztec-nr/aztec/src/state_vars/stable_public_state.nr b/yarn-project/aztec-nr/aztec/src/state_vars/stable_public_state.nr index e42b107bbd7..9612fb30a5d 100644 --- a/yarn-project/aztec-nr/aztec/src/state_vars/stable_public_state.nr +++ b/yarn-project/aztec-nr/aztec/src/state_vars/stable_public_state.nr @@ -1,7 +1,5 @@ use crate::context::{Context}; -use crate::oracle::{ - storage::{storage_read, storage_write}, -}; +use crate::oracle::{storage::{storage_read, storage_write}}; use crate::history::public_value_inclusion::prove_public_value_inclusion; use dep::std::option::Option; use dep::protocol_types::traits::{Deserialize, Serialize}; @@ -21,10 +19,7 @@ impl StablePublicState { storage_slot: Field ) -> Self { assert(storage_slot != 0, "Storage slot 0 not allowed. Storage slots must start from 1."); - Self { - context, - storage_slot, - } + Self { context, storage_slot } } // Intended to be only called once. @@ -59,10 +54,9 @@ impl StablePublicState { fields[i], self.storage_slot + i, (*private_context).this_address(), - (*private_context), + (*private_context) ) } T::deserialize(fields) } - } diff --git a/yarn-project/aztec-nr/compressed-string/src/compressed_string.nr b/yarn-project/aztec-nr/compressed-string/src/compressed_string.nr index 7f7945d1cfc..4900f10e18b 100644 --- a/yarn-project/aztec-nr/compressed-string/src/compressed_string.nr +++ b/yarn-project/aztec-nr/compressed-string/src/compressed_string.nr @@ -1,7 +1,4 @@ -use dep::aztec::protocol_types::{ - utils::field::field_from_bytes, - traits::{Serialize, Deserialize} -}; +use dep::aztec::protocol_types::{utils::field::field_from_bytes, traits::{Serialize, Deserialize}}; use dep::std; // A Fixedsize Compressed String. @@ -22,27 +19,27 @@ impl Deserialize<1> for FieldCompressedString { } } -impl FieldCompressedString{ - pub fn is_eq(self, other: FieldCompressedString) -> bool { - self.value == other.value - } +impl FieldCompressedString { + pub fn is_eq(self, other: FieldCompressedString) -> bool { + self.value == other.value + } - pub fn from_field(input_field: Field) -> Self { - Self {value: input_field} - } + pub fn from_field(input_field: Field) -> Self { + Self { value: input_field } + } - pub fn from_string(input_string: str<31>) -> Self { - Self {value: field_from_bytes(input_string.as_bytes(), true)} - } + pub fn from_string(input_string: str<31>) -> Self { + Self { value: field_from_bytes(input_string.as_bytes(), true) } + } - pub fn to_bytes(self) -> [u8; 31] { - let mut result = [0; 31]; - let bytes = self.value.to_be_bytes(31); - for i in 0..31 { - result[i] = bytes[i]; + pub fn to_bytes(self) -> [u8; 31] { + let mut result = [0; 31]; + let bytes = self.value.to_be_bytes(31); + for i in 0..31 { + result[i] = bytes[i]; + } + result } - result - } } // The general Compressed String. @@ -54,49 +51,49 @@ struct CompressedString { } impl CompressedString { - pub fn from_string(input_string: str) -> Self { - let mut fields = [0; N]; - let byts = input_string.as_bytes(); - - let mut r_index = 0 as u32; - - for i in 0..N { - let mut temp = [0 as u8; 31]; - for j in 0..31 { - if r_index < M { - temp[j] = byts[r_index]; - r_index += 1; + pub fn from_string(input_string: str) -> Self { + let mut fields = [0; N]; + let byts = input_string.as_bytes(); + + let mut r_index = 0 as u32; + + for i in 0..N { + let mut temp = [0 as u8; 31]; + for j in 0..31 { + if r_index < M { + temp[j] = byts[r_index]; + r_index += 1; + } + } + + fields[i] = field_from_bytes(temp, true); } - } - fields[i] = field_from_bytes(temp, true); + Self { value: fields } } - Self { value: fields } - } - - pub fn to_bytes(self) -> [u8; M] { - let mut result = [0; M]; - let mut w_index = 0 as u32; - for i in 0..N { - let bytes = self.value[i].to_be_bytes(31); - for j in 0..31 { - if w_index < M { - result[w_index] = bytes[j]; - w_index += 1; + pub fn to_bytes(self) -> [u8; M] { + let mut result = [0; M]; + let mut w_index = 0 as u32; + for i in 0..N { + let bytes = self.value[i].to_be_bytes(31); + for j in 0..31 { + if w_index < M { + result[w_index] = bytes[j]; + w_index += 1; + } + } } - } + result } - result - } - pub fn serialize(self) -> [Field; N] { - self.value - } + pub fn serialize(self) -> [Field; N] { + self.value + } - pub fn deserialize(input: [Field; N]) -> Self { - Self { value: input } - } + pub fn deserialize(input: [Field; N]) -> Self { + Self { value: input } + } } #[test] diff --git a/yarn-project/aztec-nr/field-note/src/field_note.nr b/yarn-project/aztec-nr/field-note/src/field_note.nr index cde638d15cb..439b4ad6378 100644 --- a/yarn-project/aztec-nr/field-note/src/field_note.nr +++ b/yarn-project/aztec-nr/field-note/src/field_note.nr @@ -1,10 +1,6 @@ use dep::aztec::{ - note::{ - note_header::NoteHeader, - note_interface::NoteInterface, - }, - hash::pedersen_hash, - context::PrivateContext, + note::{note_header::NoteHeader, note_interface::NoteInterface}, hash::pedersen_hash, + context::PrivateContext }; global FIELD_NOTE_LEN: Field = 1; @@ -61,10 +57,7 @@ impl NoteInterface for FieldNote { impl FieldNote { pub fn new(value: Field) -> Self { - FieldNote { - value, - header: NoteHeader::empty(), - } + FieldNote { value, header: NoteHeader::empty() } } } diff --git a/yarn-project/aztec-nr/safe-math/src/safe_u120.nr b/yarn-project/aztec-nr/safe-math/src/safe_u120.nr index 4ef341bf839..74acd0db57d 100644 --- a/yarn-project/aztec-nr/safe-math/src/safe_u120.nr +++ b/yarn-project/aztec-nr/safe-math/src/safe_u120.nr @@ -25,7 +25,8 @@ impl Serialize for SafeU120 { impl Deserialize for SafeU120 { // This is safe when reading from storage IF only correct safeu120 was written to storage fn deserialize(fields: [Field; SAFE_U120_SERIALIZED_LEN]) -> SafeU120 { - SafeU120 { value: fields[0] as u120 } + let value = fields[0] as u120; + SafeU120 { value } } } @@ -50,9 +51,9 @@ impl SafeU120 { for i in 0..17 { assert(bytes[i] == 0, "Value too large for SafeU120"); } - Self { - value: value as u120 - } + + let value = value as u120; + Self { value } } pub fn is_zero( diff --git a/yarn-project/aztec-nr/value-note/src/balance_utils.nr b/yarn-project/aztec-nr/value-note/src/balance_utils.nr index 74c6c79272e..570f0cca729 100644 --- a/yarn-project/aztec-nr/value-note/src/balance_utils.nr +++ b/yarn-project/aztec-nr/value-note/src/balance_utils.nr @@ -1,7 +1,4 @@ -use dep::aztec::note::{ - note_getter::view_notes, - note_viewer_options::NoteViewerOptions, -}; +use dep::aztec::note::{note_getter::view_notes, note_viewer_options::NoteViewerOptions}; use dep::aztec::state_vars::set::Set; use crate::value_note::{VALUE_NOTE_LEN, ValueNote}; diff --git a/yarn-project/aztec-nr/value-note/src/value_note.nr b/yarn-project/aztec-nr/value-note/src/value_note.nr index 6334a6f2af4..999197af9a6 100644 --- a/yarn-project/aztec-nr/value-note/src/value_note.nr +++ b/yarn-project/aztec-nr/value-note/src/value_note.nr @@ -1,21 +1,8 @@ use dep::aztec::{ - protocol_types::{ - address::AztecAddress, - traits::{Deserialize, Serialize} - }, - note::{ - note_header::NoteHeader, - note_interface::NoteInterface, - utils::compute_note_hash_for_consumption, - }, - oracle::{ - rand::rand, - nullifier_key::get_nullifier_secret_key, - get_public_key::get_public_key, - }, - log::emit_encrypted_log, - hash::pedersen_hash, - context::PrivateContext, + protocol_types::{address::AztecAddress, traits::{Deserialize, Serialize}}, + note::{note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_consumption}, + oracle::{rand::rand, nullifier_key::get_nullifier_secret_key, get_public_key::get_public_key}, + log::emit_encrypted_log, hash::pedersen_hash, context::PrivateContext }; global VALUE_NOTE_LEN: Field = 3; // 3 plus a header. @@ -99,11 +86,6 @@ impl ValueNote { pub fn new(value: Field, owner: AztecAddress) -> Self { let randomness = rand(); let header = NoteHeader::empty(); - ValueNote { - value, - owner, - randomness, - header, - } + ValueNote { value, owner, randomness, header } } } diff --git a/yarn-project/noir-contracts/contracts/avm_test_contract/src/main.nr b/yarn-project/noir-contracts/contracts/avm_test_contract/src/main.nr index 405432acb7c..c1f40dc56fd 100644 --- a/yarn-project/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -2,10 +2,7 @@ contract AvmTest { // Libs - use dep::aztec::protocol_types::address::{ - AztecAddress, - EthAddress, - }; + use dep::aztec::protocol_types::address::{AztecAddress, EthAddress}; // avm lib use dep::aztec::avm::context::AvmContext; diff --git a/yarn-project/noir-contracts/contracts/benchmarking_contract/src/main.nr b/yarn-project/noir-contracts/contracts/benchmarking_contract/src/main.nr index ce43fb06dee..dac5c5cd2a2 100644 --- a/yarn-project/noir-contracts/contracts/benchmarking_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/benchmarking_contract/src/main.nr @@ -5,20 +5,13 @@ // arise from code changes. contract Benchmarking { - use dep::value_note::{ - utils::{increment, decrement}, - value_note::{VALUE_NOTE_LEN, ValueNote}, - }; + use dep::value_note::{utils::{increment, decrement}, value_note::{VALUE_NOTE_LEN, ValueNote}}; use dep::aztec::{ - protocol_types::{ - abis::function_selector::FunctionSelector, - address::AztecAddress, - }, + protocol_types::{abis::function_selector::FunctionSelector, address::AztecAddress}, context::{Context}, note::{utils as note_utils, note_getter_options::NoteGetterOptions, note_header::NoteHeader}, - log::emit_unencrypted_log, - state_vars::{map::Map, public_state::PublicState, set::Set}, + log::emit_unencrypted_log, state_vars::{map::Map, public_state::PublicState, set::Set} }; struct Storage { diff --git a/yarn-project/noir-contracts/contracts/card_game_contract/src/game.nr b/yarn-project/noir-contracts/contracts/card_game_contract/src/game.nr index 4e9c75a77f7..f7b388c42b8 100644 --- a/yarn-project/noir-contracts/contracts/card_game_contract/src/game.nr +++ b/yarn-project/noir-contracts/contracts/card_game_contract/src/game.nr @@ -19,6 +19,22 @@ impl PlayerEntry { } } +global PLAYER_SERIALIZED_LEN: Field = 3; + +impl Deserialize for PlayerEntry { + fn deserialize(fields: [Field; PLAYER_SERIALIZED_LEN]) -> PlayerEntry { + let address = AztecAddress::from_field(fields[0]); + let deck_strength = fields[1] as u32; + let points = fields[2] as u120; + + PlayerEntry { + address, + deck_strength, + points + } + } +} + global PLAYABLE_CARDS = 4; struct Game { @@ -57,18 +73,10 @@ impl Serialize for Game { impl Deserialize for Game { fn deserialize(fields: [Field; GAME_SERIALIZED_LEN]) -> Game { - let players = [ - PlayerEntry { - address: AztecAddress::from_field(fields[0]), - deck_strength: fields[1] as u32, - points: fields[2] as u120 - }, - PlayerEntry { - address: AztecAddress::from_field(fields[3]), - deck_strength: fields[4] as u32, - points: fields[5] as u120 - } - ]; + let player1 = PlayerEntry::deserialize([fields[0], fields[1], fields[2]]); + let player2 = PlayerEntry::deserialize([fields[3], fields[4], fields[5]]); + + let players = [player1, player2]; let rounds_cards = [ Card::from_field(fields[6]), Card::from_field(fields[7]), Card::from_field(fields[8]), Card::from_field(fields[9]) diff --git a/yarn-project/noir-contracts/contracts/card_game_contract/src/main.nr b/yarn-project/noir-contracts/contracts/card_game_contract/src/main.nr index 0b4424ac9b5..9c26425af7a 100644 --- a/yarn-project/noir-contracts/contracts/card_game_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/card_game_contract/src/main.nr @@ -2,49 +2,16 @@ mod cards; mod game; contract CardGame { - use dep::aztec::protocol_types::{ - abis::function_selector::FunctionSelector, - address::AztecAddress, - constants::MAX_NOTES_PER_PAGE, - }; - use dep::aztec::{ - context::Context, - hash::pedersen_hash, - state_vars::{ - map::Map, - public_state::PublicState, - }, - }; + use dep::aztec::protocol_types::{abis::function_selector::FunctionSelector, address::AztecAddress, constants::MAX_NOTES_PER_PAGE}; + use dep::aztec::{context::Context, hash::pedersen_hash, state_vars::{map::Map, public_state::PublicState}}; use dep::std::option::Option; - use dep::value_note::{ - balance_utils, - value_note::{ - ValueNote, - VALUE_NOTE_LEN, - }, - }; - - use dep::aztec::note::{ - note_header::NoteHeader, - utils as note_utils, - }; - - use crate::cards::{ - PACK_CARDS, - Deck, - Card, - get_pack_cards, - compute_deck_strength, - }; - use crate::game::{ - NUMBER_OF_PLAYERS, - NUMBER_OF_CARDS_DECK, - PLAYABLE_CARDS, - PlayerEntry, - Game, - GAME_SERIALIZED_LEN - }; + use dep::value_note::{balance_utils, value_note::{ValueNote, VALUE_NOTE_LEN}}; + + use dep::aztec::note::{note_header::NoteHeader, utils as note_utils}; + + use crate::cards::{PACK_CARDS, Deck, Card, get_pack_cards, compute_deck_strength}; + use crate::game::{NUMBER_OF_PLAYERS, NUMBER_OF_CARDS_DECK, PLAYABLE_CARDS, PlayerEntry, Game, GAME_SERIALIZED_LEN}; struct Storage { collections: Map, diff --git a/yarn-project/noir-contracts/contracts/child_contract/src/main.nr b/yarn-project/noir-contracts/contracts/child_contract/src/main.nr index a830f36be2b..9e0e1d505bb 100644 --- a/yarn-project/noir-contracts/contracts/child_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/child_contract/src/main.nr @@ -3,17 +3,10 @@ contract Child { use dep::std::option::Option; use dep::aztec::{ - context::{PrivateContext, PublicContext, Context}, - log::emit_unencrypted_log, - state_vars::public_state::PublicState, - }; - use dep::aztec::protocol_types::{ - abis::{ - call_context::CallContext, - function_selector::FunctionSelector, - }, - address::AztecAddress, + context::{PrivateContext, PublicContext, Context}, log::emit_unencrypted_log, + state_vars::public_state::PublicState }; + use dep::aztec::protocol_types::{abis::{call_context::CallContext, function_selector::FunctionSelector}, address::AztecAddress}; struct Storage { current_value: PublicState, diff --git a/yarn-project/noir-contracts/contracts/contract_class_registerer_contract/src/events/private_function_broadcasted.nr b/yarn-project/noir-contracts/contracts/contract_class_registerer_contract/src/events/private_function_broadcasted.nr index 6f1b9c07117..b68f15408a3 100644 --- a/yarn-project/noir-contracts/contracts/contract_class_registerer_contract/src/events/private_function_broadcasted.nr +++ b/yarn-project/noir-contracts/contracts/contract_class_registerer_contract/src/events/private_function_broadcasted.nr @@ -1,8 +1,11 @@ use dep::aztec::protocol_types; use dep::aztec::protocol_types::{ - contract_class::ContractClassId, - abis::function_selector::FunctionSelector, - constants::{FUNCTION_TREE_HEIGHT, ARTIFACT_FUNCTION_TREE_MAX_HEIGHT, MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS, REGISTERER_PRIVATE_FUNCTION_BROADCASTED_MAGIC_VALUE}, + contract_class::ContractClassId, abis::function_selector::FunctionSelector, + constants::{ + FUNCTION_TREE_HEIGHT, ARTIFACT_FUNCTION_TREE_MAX_HEIGHT, + MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS, + REGISTERER_PRIVATE_FUNCTION_BROADCASTED_MAGIC_VALUE +}, traits::{Serialize} }; diff --git a/yarn-project/noir-contracts/contracts/contract_class_registerer_contract/src/events/unconstrained_function_broadcasted.nr b/yarn-project/noir-contracts/contracts/contract_class_registerer_contract/src/events/unconstrained_function_broadcasted.nr index 6ee5bb3bc26..39e2f79a5fb 100644 --- a/yarn-project/noir-contracts/contracts/contract_class_registerer_contract/src/events/unconstrained_function_broadcasted.nr +++ b/yarn-project/noir-contracts/contracts/contract_class_registerer_contract/src/events/unconstrained_function_broadcasted.nr @@ -1,8 +1,10 @@ use dep::aztec::protocol_types; use dep::aztec::protocol_types::{ - contract_class::ContractClassId, - abis::function_selector::FunctionSelector, - constants::{ARTIFACT_FUNCTION_TREE_MAX_HEIGHT, MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS, REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE}, + contract_class::ContractClassId, abis::function_selector::FunctionSelector, + constants::{ + ARTIFACT_FUNCTION_TREE_MAX_HEIGHT, MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS, + REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE +}, traits::{Serialize} }; diff --git a/yarn-project/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr b/yarn-project/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr index 050a5a5ccd9..1d0aed0116b 100644 --- a/yarn-project/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr @@ -3,13 +3,15 @@ mod events; contract ContractClassRegisterer { use dep::std::option::Option; use dep::aztec::protocol_types::{ - address::{ AztecAddress, EthAddress }, - contract_class::ContractClassId, - constants::{ARTIFACT_FUNCTION_TREE_MAX_HEIGHT, FUNCTION_TREE_HEIGHT, MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS, REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE}, + address::{AztecAddress, EthAddress}, contract_class::ContractClassId, + constants::{ + ARTIFACT_FUNCTION_TREE_MAX_HEIGHT, FUNCTION_TREE_HEIGHT, + MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS, REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE + }, traits::{Serialize} }; - use dep::aztec::log::{ emit_unencrypted_log, emit_unencrypted_log_from_private}; + use dep::aztec::log::{emit_unencrypted_log, emit_unencrypted_log_from_private}; use crate::events::{ class_registered::ContractClassRegistered, diff --git a/yarn-project/noir-contracts/contracts/contract_instance_deployer_contract/src/events/instance_deployed.nr b/yarn-project/noir-contracts/contracts/contract_instance_deployer_contract/src/events/instance_deployed.nr index 932973d45b1..b2f82d40d1e 100644 --- a/yarn-project/noir-contracts/contracts/contract_instance_deployer_contract/src/events/instance_deployed.nr +++ b/yarn-project/noir-contracts/contracts/contract_instance_deployer_contract/src/events/instance_deployed.nr @@ -1,8 +1,7 @@ use dep::aztec::protocol_types::{ contract_class::ContractClassId, - address::{ AztecAddress, EthAddress, PublicKeysHash, PartialAddress }, - constants::{DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE}, - traits::{Serialize} + address::{AztecAddress, EthAddress, PublicKeysHash, PartialAddress}, + constants::{DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE}, traits::{Serialize} }; // #[event] diff --git a/yarn-project/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr b/yarn-project/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr index 679085f994c..505de63b129 100644 --- a/yarn-project/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr @@ -3,17 +3,14 @@ mod events; contract ContractInstanceDeployer { use dep::std::option::Option; use dep::aztec::protocol_types::{ - address::{ AztecAddress, EthAddress, PublicKeysHash, PartialAddress }, - contract_class::ContractClassId, - constants::{DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE}, + address::{AztecAddress, EthAddress, PublicKeysHash, PartialAddress}, + contract_class::ContractClassId, constants::{DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE}, traits::{Serialize} }; - use dep::aztec::log::{ emit_unencrypted_log, emit_unencrypted_log_from_private}; + use dep::aztec::log::{emit_unencrypted_log, emit_unencrypted_log_from_private}; - use crate::events::{ - instance_deployed::ContractInstanceDeployed, - }; + use crate::events::{instance_deployed::ContractInstanceDeployed}; #[aztec(private)] fn constructor() {} diff --git a/yarn-project/noir-contracts/contracts/docs_example_contract/src/options.nr b/yarn-project/noir-contracts/contracts/docs_example_contract/src/options.nr index 9f1173f7588..d2f56953138 100644 --- a/yarn-project/noir-contracts/contracts/docs_example_contract/src/options.nr +++ b/yarn-project/noir-contracts/contracts/docs_example_contract/src/options.nr @@ -1,8 +1,5 @@ use crate::types::card_note::{CardNote, CARD_NOTE_LEN}; -use dep::aztec::protocol_types::{ - address::AztecAddress, - constants::MAX_READ_REQUESTS_PER_CALL, -}; +use dep::aztec::protocol_types::{address::AztecAddress, constants::MAX_READ_REQUESTS_PER_CALL}; use dep::aztec::note::note_getter_options::{NoteGetterOptions, Sort, SortOrder}; use dep::std::option::Option; diff --git a/yarn-project/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr b/yarn-project/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr index 8128f58e3ca..1e3d22782bf 100644 --- a/yarn-project/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr +++ b/yarn-project/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr @@ -1,20 +1,8 @@ use dep::aztec::{ - note::{ - note_header::NoteHeader, - note_interface::NoteInterface, - utils::compute_note_hash_for_consumption, - }, - oracle::{ - nullifier_key::get_nullifier_secret_key, - get_public_key::get_public_key, - }, - log::emit_encrypted_log, - hash::pedersen_hash, - context::PrivateContext, - protocol_types::{ - address::AztecAddress, - traits::Empty - } + note::{note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_consumption}, + oracle::{nullifier_key::get_nullifier_secret_key, get_public_key::get_public_key}, + log::emit_encrypted_log, hash::pedersen_hash, context::PrivateContext, + protocol_types::{address::AztecAddress, traits::Empty} }; // Shows how to create a custom note @@ -32,12 +20,7 @@ struct CardNote { impl CardNote { pub fn new(points: u8, randomness: Field, owner: AztecAddress) -> Self { - CardNote { - points, - randomness, - owner, - header: NoteHeader::empty(), - } + CardNote { points, randomness, owner, header: NoteHeader::empty() } } } diff --git a/yarn-project/noir-contracts/contracts/docs_example_contract/src/types/leader.nr b/yarn-project/noir-contracts/contracts/docs_example_contract/src/types/leader.nr index 7be0ef86dbf..85f1b08199d 100644 --- a/yarn-project/noir-contracts/contracts/docs_example_contract/src/types/leader.nr +++ b/yarn-project/noir-contracts/contracts/docs_example_contract/src/types/leader.nr @@ -1,7 +1,4 @@ -use dep::aztec::protocol_types::{ - address::AztecAddress, - traits::{Serialize, Deserialize} -}; +use dep::aztec::protocol_types::{address::AztecAddress, traits::{Serialize, Deserialize}}; // Shows how to create a custom struct in Public struct Leader { diff --git a/yarn-project/noir-contracts/contracts/easy_private_voting_contract/src/main.nr b/yarn-project/noir-contracts/contracts/easy_private_voting_contract/src/main.nr index 731976633cc..dec8f8d7ade 100644 --- a/yarn-project/noir-contracts/contracts/easy_private_voting_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/easy_private_voting_contract/src/main.nr @@ -1,12 +1,8 @@ contract EasyPrivateVoting { // docs:start:imports use dep::aztec::{ - protocol_types::{ - abis::function_selector::FunctionSelector, - address::AztecAddress - }, - context::{PrivateContext, Context}, - state_vars::{ map::Map, public_state::PublicState}, + protocol_types::{abis::function_selector::FunctionSelector, address::AztecAddress}, + context::{PrivateContext, Context}, state_vars::{map::Map, public_state::PublicState} }; // docs:end:imports // docs:start:storage_struct diff --git a/yarn-project/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr b/yarn-project/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr index 9778bab59d2..3d98773e00d 100644 --- a/yarn-project/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr +++ b/yarn-project/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr @@ -1,17 +1,8 @@ use dep::aztec::protocol_types::address::AztecAddress; use dep::aztec::{ - note::{ - note_header::NoteHeader, - note_interface::NoteInterface, - utils::compute_note_hash_for_consumption, - }, - oracle::{ - nullifier_key::get_nullifier_secret_key, - get_public_key::get_public_key, - }, - log::emit_encrypted_log, - hash::pedersen_hash, - context::PrivateContext, + note::{note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_consumption}, + oracle::{nullifier_key::get_nullifier_secret_key, get_public_key::get_public_key}, + log::emit_encrypted_log, hash::pedersen_hash, context::PrivateContext }; global ECDSA_PUBLIC_KEY_NOTE_LEN: Field = 5; @@ -120,13 +111,6 @@ impl NoteInterface for EcdsaPublicKeyNote { impl EcdsaPublicKeyNote { pub fn new(x: [u8; 32], y: [u8; 32], owner: AztecAddress) -> Self { - EcdsaPublicKeyNote { - x, - y, - owner, - header: NoteHeader::empty(), - } + EcdsaPublicKeyNote { x, y, owner, header: NoteHeader::empty() } } - - } diff --git a/yarn-project/noir-contracts/contracts/ecdsa_account_contract/src/main.nr b/yarn-project/noir-contracts/contracts/ecdsa_account_contract/src/main.nr index b94b576b364..bb250dc33b2 100644 --- a/yarn-project/noir-contracts/contracts/ecdsa_account_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/ecdsa_account_contract/src/main.nr @@ -3,30 +3,20 @@ mod ecdsa_public_key_note; // Account contract that uses ECDSA signatures for authentication on the same curve as Ethereum. // The signing key is stored in an immutable private note and should be different from the signing key. contract EcdsaAccount { - use dep::aztec::protocol_types::{ - abis::call_context::CallContext, - address::AztecAddress, - }; + use dep::aztec::protocol_types::{abis::call_context::CallContext, address::AztecAddress}; use dep::std; use dep::std::option::Option; use dep::aztec::{ context::{PrivateContext, PublicContext, Context}, - note::{ - note_header::NoteHeader, - utils as note_utils, - }, - oracle::get_public_key::get_public_key, - state_vars::immutable_singleton::ImmutableSingleton, + note::{note_header::NoteHeader, utils as note_utils}, oracle::get_public_key::get_public_key, + state_vars::immutable_singleton::ImmutableSingleton }; - use dep::authwit:: { - entrypoint::{ EntrypointPayload, ENTRYPOINT_PAYLOAD_SIZE }, - account::AccountActions, - auth_witness::get_auth_witness, + use dep::authwit::{ + entrypoint::{EntrypointPayload, ENTRYPOINT_PAYLOAD_SIZE}, account::AccountActions, + auth_witness::get_auth_witness }; - use crate::ecdsa_public_key_note::{ - EcdsaPublicKeyNote, ECDSA_PUBLIC_KEY_NOTE_LEN, - }; + use crate::ecdsa_public_key_note::{EcdsaPublicKeyNote, ECDSA_PUBLIC_KEY_NOTE_LEN}; struct Storage { public_key: ImmutableSingleton, diff --git a/yarn-project/noir-contracts/contracts/escrow_contract/src/main.nr b/yarn-project/noir-contracts/contracts/escrow_contract/src/main.nr index 125e5ea6815..094de197436 100644 --- a/yarn-project/noir-contracts/contracts/escrow_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/escrow_contract/src/main.nr @@ -2,26 +2,15 @@ contract Escrow { use dep::std::option::Option; - use dep::aztec::protocol_types::{ - abis::function_selector::FunctionSelector, - address::AztecAddress, - }; + use dep::aztec::protocol_types::{abis::function_selector::FunctionSelector, address::AztecAddress}; use dep::aztec::{ context::{PrivateContext, PublicContext, Context}, - note::{ - note_getter_options::NoteGetterOptions, - note_header::NoteHeader, - utils as note_utils, - }, - oracle::get_public_key::get_public_key, - state_vars::set::Set, + note::{note_getter_options::NoteGetterOptions, note_header::NoteHeader, utils as note_utils}, + oracle::get_public_key::get_public_key, state_vars::set::Set }; - use dep::address_note::address_note::{ - AddressNote, - ADDRESS_NOTE_LEN, - }; + use dep::address_note::address_note::{AddressNote, ADDRESS_NOTE_LEN}; struct Storage { owners: Set, diff --git a/yarn-project/noir-contracts/contracts/import_test_contract/src/main.nr b/yarn-project/noir-contracts/contracts/import_test_contract/src/main.nr index 613d3549b4c..c7ff4fa3a4a 100644 --- a/yarn-project/noir-contracts/contracts/import_test_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/import_test_contract/src/main.nr @@ -5,12 +5,9 @@ mod test_contract_interface; contract ImportTest { use dep::aztec::protocol_types::address::AztecAddress; use crate::test_contract_interface::{ - TestPrivateContextInterface, - TestPublicContextInterface, - AStructTestCodeGenStruct, - ADeepStructTestCodeGenStruct, - ANoteADeepStructTestCodeGenStruct, - ManyNotesADeepStructTestCodeGenStruct, + TestPrivateContextInterface, TestPublicContextInterface, AStructTestCodeGenStruct, + ADeepStructTestCodeGenStruct, ANoteADeepStructTestCodeGenStruct, + ManyNotesADeepStructTestCodeGenStruct }; #[aztec(private)] diff --git a/yarn-project/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr b/yarn-project/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr index 1e0a2917cb1..7d8a67d2df4 100644 --- a/yarn-project/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr @@ -1,60 +1,32 @@ // A demonstration of inclusion and non-inclusion proofs. contract InclusionProofs { use dep::aztec::protocol_types::{ - abis::function_selector::FunctionSelector, - address::{ - AztecAddress, - EthAddress, - }, - grumpkin_point::GrumpkinPoint, - contract_class::ContractClassId, + abis::function_selector::FunctionSelector, address::{AztecAddress, EthAddress}, + grumpkin_point::GrumpkinPoint, contract_class::ContractClassId }; use dep::aztec::{ - state_vars::{ - map::Map, - set::Set, - public_state::PublicState, - }, - context::Context, + state_vars::{map::Map, set::Set, public_state::PublicState}, context::Context, note::{ - note_getter_options::NoteGetterOptions, - note_getter_options::NoteStatus, - note_header::NoteHeader, - utils as note_utils, - }, - // docs:start:imports - history::{ - contract_inclusion::{ - prove_contract_inclusion, - prove_contract_inclusion_at, - }, - note_inclusion::{ - prove_note_inclusion, - prove_note_inclusion_at, - }, - note_validity::{ - prove_note_validity, - prove_note_validity_at, - }, - nullifier_inclusion::{ - prove_nullifier_inclusion, - prove_nullifier_inclusion_at, - prove_note_is_nullified, - prove_note_is_nullified_at, - }, - nullifier_non_inclusion::{ - prove_nullifier_not_included, - prove_nullifier_not_included_at, - prove_note_not_nullified, - prove_note_not_nullified_at, - }, - public_value_inclusion::{ - prove_public_value_inclusion, - prove_public_value_inclusion_at, - }, - }, - // docs:end:imports + note_getter_options::NoteGetterOptions, note_getter_options::NoteStatus, + note_header::NoteHeader, utils as note_utils + } + }; + // docs:start:imports + use dep::aztec::history::{ + contract_inclusion::{prove_contract_inclusion, prove_contract_inclusion_at}, + note_inclusion::{prove_note_inclusion, prove_note_inclusion_at}, + note_validity::{prove_note_validity, prove_note_validity_at}, + nullifier_inclusion::{ + prove_nullifier_inclusion, prove_nullifier_inclusion_at, prove_note_is_nullified, + prove_note_is_nullified_at + }, + nullifier_non_inclusion::{ + prove_nullifier_not_included, prove_nullifier_not_included_at, prove_note_not_nullified, + prove_note_not_nullified_at + }, + public_value_inclusion::{prove_public_value_inclusion, prove_public_value_inclusion_at} }; + // docs:end:imports // docs:start:value_note_imports use dep::value_note::value_note::{ValueNote, VALUE_NOTE_LEN}; // docs:end:value_note_imports diff --git a/yarn-project/noir-contracts/contracts/lending_contract/src/asset.nr b/yarn-project/noir-contracts/contracts/lending_contract/src/asset.nr index 5fbbb83a855..a3ef3db1695 100644 --- a/yarn-project/noir-contracts/contracts/lending_contract/src/asset.nr +++ b/yarn-project/noir-contracts/contracts/lending_contract/src/asset.nr @@ -32,11 +32,16 @@ impl Deserialize for Asset { // Right now we are wasting so many writes. If changing last_updated_ts // we will end up rewriting all of them, wasting writes. fn deserialize(fields: [Field; ASSET_SERIALIZED_LEN]) -> Asset { + let interest_accumulator = fields[0] as u120; + let last_updated_ts = fields[1] as u120; + let loan_to_value = fields[2] as u120; + let oracle = AztecAddress::from_field(fields[3]); + Asset { - interest_accumulator: fields[0] as u120, - last_updated_ts: fields[1] as u120, - loan_to_value: fields[2] as u120, - oracle: AztecAddress::from_field(fields[3]) + interest_accumulator, + last_updated_ts, + loan_to_value, + oracle, } } } diff --git a/yarn-project/noir-contracts/contracts/lending_contract/src/interfaces.nr b/yarn-project/noir-contracts/contracts/lending_contract/src/interfaces.nr index 22af86c6457..c65d8033a9d 100644 --- a/yarn-project/noir-contracts/contracts/lending_contract/src/interfaces.nr +++ b/yarn-project/noir-contracts/contracts/lending_contract/src/interfaces.nr @@ -96,11 +96,6 @@ impl Lending { FunctionSelector::from_signature("update_accumulator()"), ); - Asset { - interest_accumulator: return_values[0] as u120, - last_updated_ts: return_values[1] as u120, - loan_to_value: return_values[2] as u120, - oracle: AztecAddress::from_field(return_values[3]), - } + Asset::deserialize(return_values) } } diff --git a/yarn-project/noir-contracts/contracts/lending_contract/src/main.nr b/yarn-project/noir-contracts/contracts/lending_contract/src/main.nr index 2dd9bc1c16a..f8587fe21fc 100644 --- a/yarn-project/noir-contracts/contracts/lending_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/lending_contract/src/main.nr @@ -63,11 +63,14 @@ contract Lending { assert(asset.last_updated_ts == 0); assert(asset.interest_accumulator == 0); + let last_updated_ts = context.timestamp() as u120; + let loan_to_value = loan_to_value as u120; + asset_loc.write( Asset { interest_accumulator: 1000000000, - last_updated_ts: context.timestamp() as u120, - loan_to_value: loan_to_value as u120, + last_updated_ts, + loan_to_value, oracle } ); @@ -82,7 +85,8 @@ contract Lending { let asset_loc = storage.assets.at(0); let mut asset = asset_loc.read(); - let dt: SafeU120 = SafeU120 { value: context.timestamp() as u120 }.sub(SafeU120 { value: asset.last_updated_ts }); + let timestamp = context.timestamp() as u120; + let dt: SafeU120 = SafeU120 { value: timestamp }.sub(SafeU120 { value: asset.last_updated_ts }); // Only update if time has passed. if (!dt.is_zero()) { diff --git a/yarn-project/noir-contracts/contracts/parent_contract/src/main.nr b/yarn-project/noir-contracts/contracts/parent_contract/src/main.nr index 7992b1b83e8..62df3e83018 100644 --- a/yarn-project/noir-contracts/contracts/parent_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/parent_contract/src/main.nr @@ -1,9 +1,6 @@ // A contract used along with `Child` contract to test nested calls. contract Parent { - use dep::aztec::protocol_types::{ - address::AztecAddress, - abis::function_selector::FunctionSelector, - }; + use dep::aztec::protocol_types::{address::AztecAddress, abis::function_selector::FunctionSelector}; #[aztec(private)] fn constructor() {} diff --git a/yarn-project/noir-contracts/contracts/pending_commitments_contract/src/main.nr b/yarn-project/noir-contracts/contracts/pending_commitments_contract/src/main.nr index aa4035ffdbc..65a6a25316d 100644 --- a/yarn-project/noir-contracts/contracts/pending_commitments_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/pending_commitments_contract/src/main.nr @@ -5,25 +5,13 @@ contract PendingCommitments { // Libs use dep::std::option::Option; - use dep::value_note::{ - balance_utils, - filter::filter_notes_min_sum, - value_note::{VALUE_NOTE_LEN, ValueNote}, - }; + use dep::value_note::{balance_utils, filter::filter_notes_min_sum, value_note::{VALUE_NOTE_LEN, ValueNote}}; use dep::aztec::{ - context::{PrivateContext, PublicContext, Context}, - log::emit_encrypted_log, - note::{ - note_getter::NoteGetterOptions, - note_header::NoteHeader, - utils as note_utils, - }, - state_vars::{map::Map, set::Set}, - }; - use dep::aztec::protocol_types::{ - address::AztecAddress, - abis::function_selector::FunctionSelector, + context::{PrivateContext, PublicContext, Context}, log::emit_encrypted_log, + note::{note_getter::NoteGetterOptions, note_header::NoteHeader, utils as note_utils}, + state_vars::{map::Map, set::Set} }; + use dep::aztec::protocol_types::{address::AztecAddress, abis::function_selector::FunctionSelector}; struct Storage { balances: Map>, diff --git a/yarn-project/noir-contracts/contracts/price_feed_contract/src/asset.nr b/yarn-project/noir-contracts/contracts/price_feed_contract/src/asset.nr index 047705a1ace..b795fdf68a3 100644 --- a/yarn-project/noir-contracts/contracts/price_feed_contract/src/asset.nr +++ b/yarn-project/noir-contracts/contracts/price_feed_contract/src/asset.nr @@ -14,6 +14,7 @@ impl Serialize for Asset { impl Deserialize for Asset { fn deserialize(fields: [Field; ASSET_SERIALIZED_LEN]) -> Asset { - Asset { price: fields[0] as u120 } + let price = fields[0] as u120; + Asset { price } } } diff --git a/yarn-project/noir-contracts/contracts/reader_contract/src/main.nr b/yarn-project/noir-contracts/contracts/reader_contract/src/main.nr index 7139b9332dc..cfe709c3ee8 100644 --- a/yarn-project/noir-contracts/contracts/reader_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/reader_contract/src/main.nr @@ -1,8 +1,5 @@ contract Reader { - use dep::aztec::protocol_types::{ - address::AztecAddress, - abis::function_selector::FunctionSelector, - }; + use dep::aztec::protocol_types::{address::AztecAddress, abis::function_selector::FunctionSelector}; use dep::compressed_string::FieldCompressedString; diff --git a/yarn-project/noir-contracts/contracts/schnorr_account_contract/src/main.nr b/yarn-project/noir-contracts/contracts/schnorr_account_contract/src/main.nr index a784d7ce91c..b77d6e86fa3 100644 --- a/yarn-project/noir-contracts/contracts/schnorr_account_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/schnorr_account_contract/src/main.nr @@ -9,15 +9,12 @@ contract SchnorrAccount { use dep::aztec::protocol_types::address::AztecAddress; use dep::aztec::{ - context::{PrivateContext, Context}, - note::{ note_header::NoteHeader, utils as note_utils }, - oracle::get_public_key::get_public_key, - state_vars::immutable_singleton::ImmutableSingleton, + context::{PrivateContext, Context}, note::{note_header::NoteHeader, utils as note_utils}, + oracle::get_public_key::get_public_key, state_vars::immutable_singleton::ImmutableSingleton }; - use dep::authwit:: { - entrypoint::{ EntrypointPayload, ENTRYPOINT_PAYLOAD_SIZE }, - account::AccountActions, - auth_witness::get_auth_witness, + use dep::authwit::{ + entrypoint::{EntrypointPayload, ENTRYPOINT_PAYLOAD_SIZE}, account::AccountActions, + auth_witness::get_auth_witness }; use crate::public_key_note::{PublicKeyNote, PUBLIC_KEY_NOTE_LEN}; diff --git a/yarn-project/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr b/yarn-project/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr index 24a620e4ca6..f42930e2a90 100644 --- a/yarn-project/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr +++ b/yarn-project/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr @@ -1,19 +1,8 @@ use dep::aztec::{ - note::{ - note_header::NoteHeader, - note_interface::NoteInterface, - utils::compute_note_hash_for_consumption, - }, + note::{note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_consumption}, hash::pedersen_hash, - oracle::{ - nullifier_key::get_nullifier_secret_key, - get_public_key::get_public_key, - }, - log::emit_encrypted_log, - context::PrivateContext, - protocol_types::{ - address::AztecAddress, - } + oracle::{nullifier_key::get_nullifier_secret_key, get_public_key::get_public_key}, + log::emit_encrypted_log, context::PrivateContext, protocol_types::{address::AztecAddress} }; global PUBLIC_KEY_NOTE_LEN: Field = 3; @@ -91,11 +80,6 @@ impl NoteInterface for PublicKeyNote { impl PublicKeyNote { pub fn new(x: Field, y: Field, owner: AztecAddress) -> Self { - PublicKeyNote { - x, - y, - owner, - header: NoteHeader::empty(), - } + PublicKeyNote { x, y, owner, header: NoteHeader::empty() } } } diff --git a/yarn-project/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr b/yarn-project/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr index ce0c13a9844..955ab197d08 100644 --- a/yarn-project/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr @@ -4,10 +4,9 @@ contract SchnorrHardcodedAccount { use dep::std; use dep::aztec::context::PrivateContext; - use dep::authwit:: { - entrypoint::{ EntrypointPayload, ENTRYPOINT_PAYLOAD_SIZE }, - account::AccountActions, - auth_witness::get_auth_witness, + use dep::authwit::{ + entrypoint::{EntrypointPayload, ENTRYPOINT_PAYLOAD_SIZE}, account::AccountActions, + auth_witness::get_auth_witness }; global public_key_x: Field = 0x0ede3d33c920df8fdf43f3e39ed38b0882c25b056620ef52fd016fe811aa2443; diff --git a/yarn-project/noir-contracts/contracts/schnorr_single_key_account_contract/src/auth_oracle.nr b/yarn-project/noir-contracts/contracts/schnorr_single_key_account_contract/src/auth_oracle.nr index 1d43cb0816a..67791c75210 100644 --- a/yarn-project/noir-contracts/contracts/schnorr_single_key_account_contract/src/auth_oracle.nr +++ b/yarn-project/noir-contracts/contracts/schnorr_single_key_account_contract/src/auth_oracle.nr @@ -1,8 +1,5 @@ use dep::authwit::auth_witness; -use dep::aztec::protocol_types::{ - address::PartialAddress, - grumpkin_point::GrumpkinPoint, -}; +use dep::aztec::protocol_types::{address::PartialAddress, grumpkin_point::GrumpkinPoint}; struct AuthWitness { owner: GrumpkinPoint, @@ -19,7 +16,7 @@ impl AuthWitness { Self { owner: GrumpkinPoint::new(values[0], values[1]), signature, - partial_address: PartialAddress::from_field(values[66]), + partial_address: PartialAddress::from_field(values[66]) } } } diff --git a/yarn-project/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr b/yarn-project/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr index 0b20f873917..30aac8146ba 100644 --- a/yarn-project/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr @@ -2,17 +2,12 @@ mod util; mod auth_oracle; contract SchnorrSingleKeyAccount { - use dep::std::{ - option::Option, - }; - use dep::aztec::context::{ PrivateContext, PublicContext, Context }; + use dep::std::{option::Option}; + use dep::aztec::context::{PrivateContext, PublicContext, Context}; - use dep::authwit::{ - entrypoint::EntrypointPayload, - account::AccountActions, - }; + use dep::authwit::{entrypoint::EntrypointPayload, account::AccountActions}; - use crate::{ util::recover_address, auth_oracle::get_auth_witness }; + use crate::{util::recover_address, auth_oracle::get_auth_witness}; global ACCOUNT_ACTIONS_STORAGE_SLOT = 1; diff --git a/yarn-project/noir-contracts/contracts/slow_tree_contract/src/main.nr b/yarn-project/noir-contracts/contracts/slow_tree_contract/src/main.nr index ca25b3c193b..0a36cb11bfc 100644 --- a/yarn-project/noir-contracts/contracts/slow_tree_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/slow_tree_contract/src/main.nr @@ -6,28 +6,16 @@ mod types; // https://github.com/AztecProtocol/aztec-packages/issues/1291 // This is made as a separate contract for one thing mainly. Making it simpler to use. contract SlowTree { - use dep::aztec::protocol_types::{ - abis::function_selector::FunctionSelector, - address::AztecAddress, - }; + use dep::aztec::protocol_types::{abis::function_selector::FunctionSelector, address::AztecAddress}; use dep::std::option::Option; - use dep::value_note::{ - balance_utils, - utils::{increment, decrement}, - value_note::{VALUE_NOTE_LEN, ValueNote}, - }; + use dep::value_note::{balance_utils, utils::{increment, decrement}, value_note::{VALUE_NOTE_LEN, ValueNote}}; use dep::aztec::{ context::{PrivateContext, PublicContext, Context}, - note::{ - note_header::NoteHeader, - utils as note_utils, - }, + note::{note_header::NoteHeader, utils as note_utils}, state_vars::{map::Map, public_state::PublicState, set::Set}, - protocol_types::type_serialization::FIELD_SERIALIZED_LEN, - }; - use dep::slow_updates_tree::slow_map::{ - SlowMap, Leaf, SlowUpdateProof, compute_merkle_root, deserialize_slow_update_proof + protocol_types::type_serialization::FIELD_SERIALIZED_LEN }; + use dep::slow_updates_tree::slow_map::{SlowMap, Leaf, SlowUpdateProof, compute_merkle_root, deserialize_slow_update_proof}; // docs:start:import_pop_capsule use crate::capsule::pop_capsule; diff --git a/yarn-project/noir-contracts/contracts/slow_tree_contract/src/types.nr b/yarn-project/noir-contracts/contracts/slow_tree_contract/src/types.nr index 9245cb9aa13..58b934e7aa7 100644 --- a/yarn-project/noir-contracts/contracts/slow_tree_contract/src/types.nr +++ b/yarn-project/noir-contracts/contracts/slow_tree_contract/src/types.nr @@ -18,16 +18,16 @@ fn deserialize_membership_proof(serialized: [Field; M]) -> MembershipProof impl MembershipProof { fn serialize(self: Self) -> [Field; M] { - let mut serialized = [0; M]; - serialized[0] = self.index; - serialized[1] = self.value; - for i in 0..N { - serialized[2 + i] = self.sibling_path[i]; - } - serialized + let mut serialized = [0; M]; + serialized[0] = self.index; + serialized[1] = self.value; + for i in 0..N { + serialized[2 + i] = self.sibling_path[i]; + } + serialized } fn deserialize(serialized: [Field; M]) -> Self { - deserialize_membership_proof(serialized) + deserialize_membership_proof(serialized) } } diff --git a/yarn-project/noir-contracts/contracts/stateful_test_contract/src/main.nr b/yarn-project/noir-contracts/contracts/stateful_test_contract/src/main.nr index 0b40f7ad4b3..0aba89b09d5 100644 --- a/yarn-project/noir-contracts/contracts/stateful_test_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/stateful_test_contract/src/main.nr @@ -1,22 +1,12 @@ // A contract used for testing a random hodgepodge of small features from simulator and end-to-end tests. contract StatefulTest { - use dep::aztec::protocol_types::{ - address::AztecAddress, - abis::function_selector::FunctionSelector, - }; + use dep::aztec::protocol_types::{address::AztecAddress, abis::function_selector::FunctionSelector}; use dep::std::option::Option; - use dep::value_note::{ - balance_utils, - utils::{increment, decrement}, - value_note::{VALUE_NOTE_LEN, ValueNote}, - }; + use dep::value_note::{balance_utils, utils::{increment, decrement}, value_note::{VALUE_NOTE_LEN, ValueNote}}; use dep::aztec::{ context::{PrivateContext, PublicContext, Context}, - note::{ - note_header::NoteHeader, - utils as note_utils, - }, - state_vars::{map::Map, public_state::PublicState, set::Set}, + note::{note_header::NoteHeader, utils as note_utils}, + state_vars::{map::Map, public_state::PublicState, set::Set} }; struct Storage { diff --git a/yarn-project/noir-contracts/contracts/test_contract/src/interface.nr b/yarn-project/noir-contracts/contracts/test_contract/src/interface.nr index 0a42157be18..6af1d50e42e 100644 --- a/yarn-project/noir-contracts/contracts/test_contract/src/interface.nr +++ b/yarn-project/noir-contracts/contracts/test_contract/src/interface.nr @@ -1,12 +1,8 @@ /* Autogenerated file, do not edit! */ use dep::std; -use dep::aztec::context::{ PrivateContext, PublicContext }; -use dep::aztec::protocol_types::{ - address::AztecAddress, - abis::function_selector::FunctionSelector, - constants::RETURN_VALUES_LENGTH, -}; +use dep::aztec::context::{PrivateContext, PublicContext}; +use dep::aztec::protocol_types::{address::AztecAddress, abis::function_selector::FunctionSelector, constants::RETURN_VALUES_LENGTH}; struct AStructTestCodeGenStruct { amount: Field, @@ -56,214 +52,232 @@ struct TestPrivateContextInterface { } impl TestPrivateContextInterface { - pub fn at(address: AztecAddress) -> Self { - Self { - address, - } - } - - pub fn test_code_gen( - self, - context: &mut PrivateContext, - a_field: Field, - a_bool: bool, - a_number: u32, - an_array: [Field;2], - a_struct: AStructTestCodeGenStruct, - a_deep_struct: ADeepStructTestCodeGenStruct - ) -> [Field; RETURN_VALUES_LENGTH] { - let mut serialized_args = [0; 17]; - serialized_args[0] = a_field; - serialized_args[1] = a_bool as Field; - serialized_args[2] = a_number as Field; - serialized_args[3] = an_array[0]; - serialized_args[4] = an_array[1]; - serialized_args[5] = a_struct.amount; - serialized_args[6] = a_struct.secret_hash; - serialized_args[7] = a_deep_struct.a_field; - serialized_args[8] = a_deep_struct.a_bool as Field; - serialized_args[9] = a_deep_struct.a_note.amount; - serialized_args[10] = a_deep_struct.a_note.secret_hash; - serialized_args[11] = a_deep_struct.many_notes[0].amount; - serialized_args[12] = a_deep_struct.many_notes[0].secret_hash; - serialized_args[13] = a_deep_struct.many_notes[1].amount; - serialized_args[14] = a_deep_struct.many_notes[1].secret_hash; - serialized_args[15] = a_deep_struct.many_notes[2].amount; - serialized_args[16] = a_deep_struct.many_notes[2].secret_hash; - - context.call_private_function(self.address, FunctionSelector::from_field(0x0f054f9b), serialized_args) - } - - - pub fn get_public_key( - self, - context: &mut PrivateContext, - address: AddressGetPublicKeyStruct - ) -> [Field; RETURN_VALUES_LENGTH] { - let mut serialized_args = [0; 1]; - serialized_args[0] = address.inner; - - context.call_private_function(self.address, FunctionSelector::from_field(0x501e4f48), serialized_args) - } - - - pub fn create_nullifier_public( - self, - context: &mut PrivateContext, - amount: Field, - secret_hash: Field - ) { - let mut serialized_args = [0; 2]; - serialized_args[0] = amount; - serialized_args[1] = secret_hash; - - context.call_public_function(self.address, FunctionSelector::from_field(0xdf02db8d), serialized_args) - } - - - pub fn emit_msg_sender( - self, - context: &mut PrivateContext - ) -> [Field; RETURN_VALUES_LENGTH] { - let mut serialized_args = [0; 0]; - - context.call_private_function(self.address, FunctionSelector::from_field(0x11fb5d45), serialized_args) - } - - - pub fn get_portal_contract_address( - self, - context: &mut PrivateContext, - aztec_address: AztecAddressGetPortalContractAddressStruct - ) -> [Field; RETURN_VALUES_LENGTH] { - let mut serialized_args = [0; 1]; - serialized_args[0] = aztec_address.inner; - - context.call_private_function(self.address, FunctionSelector::from_field(0x30e5344b), serialized_args) - } - - - pub fn emit_unencrypted( - self, - context: &mut PrivateContext, - value: Field - ) { - let mut serialized_args = [0; 1]; - serialized_args[0] = value; - - context.call_public_function(self.address, FunctionSelector::from_field(0x817a64cb), serialized_args) - } - - - pub fn get_this_portal_address( - self, - context: &mut PrivateContext - ) -> [Field; RETURN_VALUES_LENGTH] { - let mut serialized_args = [0; 0]; - - context.call_private_function(self.address, FunctionSelector::from_field(0xc71384f5), serialized_args) - } - - - pub fn get_this_address( - self, - context: &mut PrivateContext - ) -> [Field; RETURN_VALUES_LENGTH] { - let mut serialized_args = [0; 0]; - - context.call_private_function(self.address, FunctionSelector::from_field(0x95a7b2ae), serialized_args) - } - - - pub fn is_time_equal( - self, - context: &mut PrivateContext, - time: Field - ) { - let mut serialized_args = [0; 1]; - serialized_args[0] = time; - - context.call_public_function(self.address, FunctionSelector::from_field(0x61fa2bda), serialized_args) - } - - - pub fn consume_mint_private_message( - self, - context: &mut PrivateContext, - secret_hash_for_redeeming_minted_notes: Field, - amount: Field, - canceller: CancellerConsumeMintPrivateMessageStruct, - msg_key: Field, - secret_for_L1_to_L2_message_consumption: Field - ) -> [Field; RETURN_VALUES_LENGTH] { - let mut serialized_args = [0; 5]; - serialized_args[0] = secret_hash_for_redeeming_minted_notes; - serialized_args[1] = amount; - serialized_args[2] = canceller.inner; - serialized_args[3] = msg_key; - serialized_args[4] = secret_for_L1_to_L2_message_consumption; - - context.call_private_function(self.address, FunctionSelector::from_field(0x260712c7), serialized_args) - } - - - pub fn emit_nullifier( - self, - context: &mut PrivateContext, - nullifier: Field - ) -> [Field; RETURN_VALUES_LENGTH] { - let mut serialized_args = [0; 1]; - serialized_args[0] = nullifier; - - context.call_private_function(self.address, FunctionSelector::from_field(0x82a8b183), serialized_args) - } - - - pub fn create_l2_to_l1_message_public( - self, - context: &mut PrivateContext, - amount: Field, - secret_hash: Field - ) { - let mut serialized_args = [0; 2]; - serialized_args[0] = amount; - serialized_args[1] = secret_hash; - - context.call_public_function(self.address, FunctionSelector::from_field(0x9749ca06), serialized_args) - } - - - pub fn consume_mint_public_message( - self, - context: &mut PrivateContext, - to: ToConsumeMintPublicMessageStruct, - amount: Field, - canceller: CancellerConsumeMintPublicMessageStruct, - msg_key: Field, - secret: Field - ) { - let mut serialized_args = [0; 5]; - serialized_args[0] = to.inner; - serialized_args[1] = amount; - serialized_args[2] = canceller.inner; - serialized_args[3] = msg_key; - serialized_args[4] = secret; - - context.call_public_function(self.address, FunctionSelector::from_field(0x04ee3bb0), serialized_args) - } - - - pub fn set_constant( - self, - context: &mut PrivateContext, - value: Field - ) -> [Field; RETURN_VALUES_LENGTH] { - let mut serialized_args = [0; 1]; - serialized_args[0] = value; - - context.call_private_function(self.address, FunctionSelector::from_field(0x1b3b9e18), serialized_args) - } - + pub fn at(address: AztecAddress) -> Self { + Self { address } + } + + pub fn test_code_gen( + self, + context: &mut PrivateContext, + a_field: Field, + a_bool: bool, + a_number: u32, + an_array: [Field; 2], + a_struct: AStructTestCodeGenStruct, + a_deep_struct: ADeepStructTestCodeGenStruct + ) -> [Field; RETURN_VALUES_LENGTH] { + let mut serialized_args = [0; 17]; + serialized_args[0] = a_field; + serialized_args[1] = a_bool as Field; + serialized_args[2] = a_number as Field; + serialized_args[3] = an_array[0]; + serialized_args[4] = an_array[1]; + serialized_args[5] = a_struct.amount; + serialized_args[6] = a_struct.secret_hash; + serialized_args[7] = a_deep_struct.a_field; + serialized_args[8] = a_deep_struct.a_bool as Field; + serialized_args[9] = a_deep_struct.a_note.amount; + serialized_args[10] = a_deep_struct.a_note.secret_hash; + serialized_args[11] = a_deep_struct.many_notes[0].amount; + serialized_args[12] = a_deep_struct.many_notes[0].secret_hash; + serialized_args[13] = a_deep_struct.many_notes[1].amount; + serialized_args[14] = a_deep_struct.many_notes[1].secret_hash; + serialized_args[15] = a_deep_struct.many_notes[2].amount; + serialized_args[16] = a_deep_struct.many_notes[2].secret_hash; + + context.call_private_function( + self.address, + FunctionSelector::from_field(0x0f054f9b), + serialized_args + ) + } + + pub fn get_public_key( + self, + context: &mut PrivateContext, + address: AddressGetPublicKeyStruct + ) -> [Field; RETURN_VALUES_LENGTH] { + let mut serialized_args = [0; 1]; + serialized_args[0] = address.inner; + + context.call_private_function( + self.address, + FunctionSelector::from_field(0x501e4f48), + serialized_args + ) + } + + pub fn create_nullifier_public(self, context: &mut PrivateContext, amount: Field, secret_hash: Field) { + let mut serialized_args = [0; 2]; + serialized_args[0] = amount; + serialized_args[1] = secret_hash; + + context.call_public_function( + self.address, + FunctionSelector::from_field(0xdf02db8d), + serialized_args + ) + } + + pub fn emit_msg_sender(self, context: &mut PrivateContext) -> [Field; RETURN_VALUES_LENGTH] { + let mut serialized_args = [0; 0]; + + context.call_private_function( + self.address, + FunctionSelector::from_field(0x11fb5d45), + serialized_args + ) + } + + pub fn get_portal_contract_address( + self, + context: &mut PrivateContext, + aztec_address: AztecAddressGetPortalContractAddressStruct + ) -> [Field; RETURN_VALUES_LENGTH] { + let mut serialized_args = [0; 1]; + serialized_args[0] = aztec_address.inner; + + context.call_private_function( + self.address, + FunctionSelector::from_field(0x30e5344b), + serialized_args + ) + } + + pub fn emit_unencrypted(self, context: &mut PrivateContext, value: Field) { + let mut serialized_args = [0; 1]; + serialized_args[0] = value; + + context.call_public_function( + self.address, + FunctionSelector::from_field(0x817a64cb), + serialized_args + ) + } + + pub fn get_this_portal_address(self, context: &mut PrivateContext) -> [Field; RETURN_VALUES_LENGTH] { + let mut serialized_args = [0; 0]; + + context.call_private_function( + self.address, + FunctionSelector::from_field(0xc71384f5), + serialized_args + ) + } + + pub fn get_this_address(self, context: &mut PrivateContext) -> [Field; RETURN_VALUES_LENGTH] { + let mut serialized_args = [0; 0]; + + context.call_private_function( + self.address, + FunctionSelector::from_field(0x95a7b2ae), + serialized_args + ) + } + + pub fn is_time_equal(self, context: &mut PrivateContext, time: Field) { + let mut serialized_args = [0; 1]; + serialized_args[0] = time; + + context.call_public_function( + self.address, + FunctionSelector::from_field(0x61fa2bda), + serialized_args + ) + } + + pub fn consume_mint_private_message( + self, + context: &mut PrivateContext, + secret_hash_for_redeeming_minted_notes: Field, + amount: Field, + canceller: CancellerConsumeMintPrivateMessageStruct, + msg_key: Field, + secret_for_L1_to_L2_message_consumption: Field + ) -> [Field; RETURN_VALUES_LENGTH] { + let mut serialized_args = [0; 5]; + serialized_args[0] = secret_hash_for_redeeming_minted_notes; + serialized_args[1] = amount; + serialized_args[2] = canceller.inner; + serialized_args[3] = msg_key; + serialized_args[4] = secret_for_L1_to_L2_message_consumption; + + context.call_private_function( + self.address, + FunctionSelector::from_field(0x260712c7), + serialized_args + ) + } + + pub fn emit_nullifier( + self, + context: &mut PrivateContext, + nullifier: Field + ) -> [Field; RETURN_VALUES_LENGTH] { + let mut serialized_args = [0; 1]; + serialized_args[0] = nullifier; + + context.call_private_function( + self.address, + FunctionSelector::from_field(0x82a8b183), + serialized_args + ) + } + + pub fn create_l2_to_l1_message_public( + self, + context: &mut PrivateContext, + amount: Field, + secret_hash: Field + ) { + let mut serialized_args = [0; 2]; + serialized_args[0] = amount; + serialized_args[1] = secret_hash; + + context.call_public_function( + self.address, + FunctionSelector::from_field(0x9749ca06), + serialized_args + ) + } + + pub fn consume_mint_public_message( + self, + context: &mut PrivateContext, + to: ToConsumeMintPublicMessageStruct, + amount: Field, + canceller: CancellerConsumeMintPublicMessageStruct, + msg_key: Field, + secret: Field + ) { + let mut serialized_args = [0; 5]; + serialized_args[0] = to.inner; + serialized_args[1] = amount; + serialized_args[2] = canceller.inner; + serialized_args[3] = msg_key; + serialized_args[4] = secret; + + context.call_public_function( + self.address, + FunctionSelector::from_field(0x04ee3bb0), + serialized_args + ) + } + + pub fn set_constant( + self, + context: &mut PrivateContext, + value: Field + ) -> [Field; RETURN_VALUES_LENGTH] { + let mut serialized_args = [0; 1]; + serialized_args[0] = value; + + context.call_private_function( + self.address, + FunctionSelector::from_field(0x1b3b9e18), + serialized_args + ) + } } // Interface for calling Test functions from a public context @@ -272,82 +286,87 @@ struct TestPublicContextInterface { } impl TestPublicContextInterface { - pub fn at(address: AztecAddress) -> Self { - Self { - address, - } - } - - pub fn create_nullifier_public( - self, - context: PublicContext, - amount: Field, - secret_hash: Field - ) -> [Field; RETURN_VALUES_LENGTH] { - let mut serialized_args = [0; 2]; - serialized_args[0] = amount; - serialized_args[1] = secret_hash; - - context.call_public_function(self.address, FunctionSelector::from_field(0xdf02db8d), serialized_args) - } - - - pub fn emit_unencrypted( - self, - context: PublicContext, - value: Field - ) -> [Field; RETURN_VALUES_LENGTH] { - let mut serialized_args = [0; 1]; - serialized_args[0] = value; - - context.call_public_function(self.address, FunctionSelector::from_field(0x817a64cb), serialized_args) - } - - - pub fn is_time_equal( - self, - context: PublicContext, - time: Field - ) -> [Field; RETURN_VALUES_LENGTH] { - let mut serialized_args = [0; 1]; - serialized_args[0] = time; - - context.call_public_function(self.address, FunctionSelector::from_field(0x61fa2bda), serialized_args) - } - - - pub fn create_l2_to_l1_message_public( - self, - context: PublicContext, - amount: Field, - secret_hash: Field - ) -> [Field; RETURN_VALUES_LENGTH] { - let mut serialized_args = [0; 2]; - serialized_args[0] = amount; - serialized_args[1] = secret_hash; - - context.call_public_function(self.address, FunctionSelector::from_field(0x9749ca06), serialized_args) - } - - - pub fn consume_mint_public_message( - self, - context: PublicContext, - to: ToConsumeMintPublicMessageStruct, - amount: Field, - canceller: CancellerConsumeMintPublicMessageStruct, - msg_key: Field, - secret: Field - ) -> [Field; RETURN_VALUES_LENGTH] { - let mut serialized_args = [0; 5]; - serialized_args[0] = to.inner; - serialized_args[1] = amount; - serialized_args[2] = canceller.inner; - serialized_args[3] = msg_key; - serialized_args[4] = secret; - - context.call_public_function(self.address, FunctionSelector::from_field(0x04ee3bb0), serialized_args) - } - + pub fn at(address: AztecAddress) -> Self { + Self { address } + } + + pub fn create_nullifier_public( + self, + context: PublicContext, + amount: Field, + secret_hash: Field + ) -> [Field; RETURN_VALUES_LENGTH] { + let mut serialized_args = [0; 2]; + serialized_args[0] = amount; + serialized_args[1] = secret_hash; + + context.call_public_function( + self.address, + FunctionSelector::from_field(0xdf02db8d), + serialized_args + ) + } + + pub fn emit_unencrypted(self, context: PublicContext, value: Field) -> [Field; RETURN_VALUES_LENGTH] { + let mut serialized_args = [0; 1]; + serialized_args[0] = value; + + context.call_public_function( + self.address, + FunctionSelector::from_field(0x817a64cb), + serialized_args + ) + } + + pub fn is_time_equal(self, context: PublicContext, time: Field) -> [Field; RETURN_VALUES_LENGTH] { + let mut serialized_args = [0; 1]; + serialized_args[0] = time; + + context.call_public_function( + self.address, + FunctionSelector::from_field(0x61fa2bda), + serialized_args + ) + } + + pub fn create_l2_to_l1_message_public( + self, + context: PublicContext, + amount: Field, + secret_hash: Field + ) -> [Field; RETURN_VALUES_LENGTH] { + let mut serialized_args = [0; 2]; + serialized_args[0] = amount; + serialized_args[1] = secret_hash; + + context.call_public_function( + self.address, + FunctionSelector::from_field(0x9749ca06), + serialized_args + ) + } + + pub fn consume_mint_public_message( + self, + context: PublicContext, + to: ToConsumeMintPublicMessageStruct, + amount: Field, + canceller: CancellerConsumeMintPublicMessageStruct, + msg_key: Field, + secret: Field + ) -> [Field; RETURN_VALUES_LENGTH] { + let mut serialized_args = [0; 5]; + serialized_args[0] = to.inner; + serialized_args[1] = amount; + serialized_args[2] = canceller.inner; + serialized_args[3] = msg_key; + serialized_args[4] = secret; + + context.call_public_function( + self.address, + FunctionSelector::from_field(0x04ee3bb0), + serialized_args + ) + } } diff --git a/yarn-project/noir-contracts/contracts/test_contract/src/main.nr b/yarn-project/noir-contracts/contracts/test_contract/src/main.nr index d381bcbcfb8..3a510118076 100644 --- a/yarn-project/noir-contracts/contracts/test_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/test_contract/src/main.nr @@ -3,46 +3,27 @@ contract Test { use dep::std::option::Option; use dep::aztec::protocol_types::{ abis::private_circuit_public_inputs::PrivateCircuitPublicInputs, - address::{ - AztecAddress, - EthAddress, - }, - constants::{ - MAX_READ_REQUESTS_PER_CALL, - MAX_NOTES_PER_PAGE - }, - hash::hash_args, + address::{AztecAddress, EthAddress}, + constants::{MAX_READ_REQUESTS_PER_CALL, MAX_NOTES_PER_PAGE}, hash::hash_args }; // docs:start:unencrypted_import use dep::aztec::log::emit_unencrypted_log; // docs:end:unencrypted_import use dep::aztec::{ - context::{ - Context, - inputs::private_context_inputs::PrivateContextInputs, - }, - hash::pedersen_hash, + context::{Context, inputs::private_context_inputs::PrivateContextInputs}, hash::pedersen_hash, context::PrivateContext, note::{ - note_header::NoteHeader, - utils as note_utils, - lifecycle::{create_note, destroy_note}, - note_getter::{get_notes, view_notes}, - note_getter_options::{NoteGetterOptions, NoteStatus}, - note_viewer_options::NoteViewerOptions, - }, - oracle::{ - get_public_key::get_public_key as get_public_key_oracle, - context::get_portal_address, - rand::rand - }, - state_vars::immutable_singleton::ImmutableSingleton, - log::emit_unencrypted_log_from_private, + note_header::NoteHeader, utils as note_utils, lifecycle::{create_note, destroy_note}, + note_getter::{get_notes, view_notes}, note_getter_options::{NoteGetterOptions, NoteStatus}, + note_viewer_options::NoteViewerOptions + }, + oracle::{get_public_key::get_public_key as get_public_key_oracle, context::get_portal_address, rand::rand}, + state_vars::immutable_singleton::ImmutableSingleton, log::emit_unencrypted_log_from_private }; use dep::token_portal_content_hash_lib::{get_mint_private_content_hash, get_mint_public_content_hash}; use dep::field_note::field_note::FieldNote; - use dep::value_note::value_note::{ValueNote,VALUE_NOTE_LEN}; + use dep::value_note::value_note::{ValueNote, VALUE_NOTE_LEN}; #[event] struct ExampleEvent { @@ -346,14 +327,11 @@ contract Test { impl DummyNote { fn new(amount: Field, secret_hash: Field) -> Self { - Self { - amount: amount, - secret_hash: secret_hash - } + Self { amount, secret_hash } } fn get_commitment(self) -> Field { - pedersen_hash([self.amount, self.secret_hash],0) + pedersen_hash([self.amount, self.secret_hash], 0) } } diff --git a/yarn-project/noir-contracts/contracts/token_blacklist_contract/src/interfaces.nr b/yarn-project/noir-contracts/contracts/token_blacklist_contract/src/interfaces.nr index 713bf20a4a5..3f4bf9983be 100644 --- a/yarn-project/noir-contracts/contracts/token_blacklist_contract/src/interfaces.nr +++ b/yarn-project/noir-contracts/contracts/token_blacklist_contract/src/interfaces.nr @@ -1,7 +1,4 @@ -use dep::aztec::protocol_types::{ - abis::function_selector::FunctionSelector, - address::AztecAddress, -}; +use dep::aztec::protocol_types::{abis::function_selector::FunctionSelector, address::AztecAddress}; use dep::aztec::context::{PrivateContext, PublicContext, Context}; @@ -10,40 +7,40 @@ struct SlowMap { } impl SlowMap { - pub fn at(address: AztecAddress) -> Self { - Self { address: address } - } + pub fn at(address: AztecAddress) -> Self { + Self { address } + } - pub fn initialize(self: Self, context: PublicContext) { - context.call_public_function_no_args( - self.address, - FunctionSelector::from_signature("initialize()") - ); - } + pub fn initialize(self: Self, context: PublicContext) { + context.call_public_function_no_args( + self.address, + FunctionSelector::from_signature("initialize()") + ); + } - pub fn read_at_pub(self: Self, context: PublicContext, index: Field) -> Field { - let _return_values = context.call_public_function( - self.address, - FunctionSelector::from_signature("read_at_pub(Field)"), - [index] - ); - _return_values[0] - } + pub fn read_at_pub(self: Self, context: PublicContext, index: Field) -> Field { + let _return_values = context.call_public_function( + self.address, + FunctionSelector::from_signature("read_at_pub(Field)"), + [index] + ); + _return_values[0] + } - pub fn read_at(self: Self, context: &mut PrivateContext, index: Field) -> Field { - let _return_values = context.call_private_function( - self.address, - FunctionSelector::from_signature("read_at(Field)"), - [index] - ); - _return_values[0] - } + pub fn read_at(self: Self, context: &mut PrivateContext, index: Field) -> Field { + let _return_values = context.call_private_function( + self.address, + FunctionSelector::from_signature("read_at(Field)"), + [index] + ); + _return_values[0] + } - pub fn update_at_private(self: Self, context: &mut PrivateContext, index: Field, new_value: Field) { - context.call_private_function( - self.address, - FunctionSelector::from_signature("update_at_private(Field,Field)"), - [index, new_value] - ); - } + pub fn update_at_private(self: Self, context: &mut PrivateContext, index: Field, new_value: Field) { + context.call_private_function( + self.address, + FunctionSelector::from_signature("update_at_private(Field,Field)"), + [index, new_value] + ); + } } diff --git a/yarn-project/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr b/yarn-project/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr index 3b4c0607528..a47fdce4f3f 100644 --- a/yarn-project/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr +++ b/yarn-project/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr @@ -1,23 +1,13 @@ use dep::std::option::Option; use dep::safe_math::SafeU120; use dep::aztec::{ - context::{PrivateContext, PublicContext, Context}, - hash::pedersen_hash, - protocol_types::{ - address::AztecAddress, - constants::MAX_READ_REQUESTS_PER_CALL, - }, - state_vars::{ - set::Set, - map::Map - }, + context::{PrivateContext, PublicContext, Context}, hash::pedersen_hash, + protocol_types::{address::AztecAddress, constants::MAX_READ_REQUESTS_PER_CALL}, + state_vars::{set::Set, map::Map}, note::{ - note_getter::view_notes, - note_getter_options::{NoteGetterOptions, SortOrder}, - note_viewer_options::NoteViewerOptions, - note_header::NoteHeader, - note_interface::NoteInterface, - } + note_getter::view_notes, note_getter_options::{NoteGetterOptions, SortOrder}, + note_viewer_options::NoteViewerOptions, note_header::NoteHeader, note_interface::NoteInterface +} }; use crate::types::token_note::{TokenNote, OwnedNote}; @@ -26,41 +16,47 @@ struct BalancesMap { } impl BalancesMap { - pub fn new( - context: Context, - storage_slot: Field, - ) -> Self { + pub fn new(context: Context, storage_slot: Field) -> Self { assert(storage_slot != 0, "Storage slot 0 not allowed. Storage slots must start from 1."); - Self { - map: Map::new(context, storage_slot, |context, slot| Set::new(context, slot)) - } + Self { map: Map::new(context, storage_slot, |context, slot| Set::new(context, slot)) } } - unconstrained pub fn balance_of(self: Self, owner: AztecAddress) -> SafeU120 where T: NoteInterface + OwnedNote { + unconstrained pub fn balance_of( + self: Self, + owner: AztecAddress + ) -> SafeU120 where T: NoteInterface + OwnedNote { self.balance_of_with_offset(owner, 0) } - unconstrained pub fn balance_of_with_offset(self: Self, owner: AztecAddress, offset: u32) -> SafeU120 where T: NoteInterface + OwnedNote { - // Same as SafeU120::new(0), but fewer constraints because no check. - let mut balance = SafeU120::min(); - // docs:start:view_notes - let options = NoteViewerOptions::new().set_offset(offset); - let opt_notes = self.map.at(owner).view_notes(options); - // docs:end:view_notes - let len = opt_notes.len(); - for i in 0..len { - if opt_notes[i].is_some() { - balance = balance.add(opt_notes[i].unwrap_unchecked().get_amount()); - } - } - if (opt_notes[len - 1].is_some()) { - balance = balance.add(self.balance_of_with_offset(owner, offset + opt_notes.len() as u32)); - } + unconstrained pub fn balance_of_with_offset( + self: Self, + owner: AztecAddress, + offset: u32 + ) -> SafeU120 where T: NoteInterface + OwnedNote { + // Same as SafeU120::new(0), but fewer constraints because no check. + let mut balance = SafeU120::min(); + // docs:start:view_notes + let options = NoteViewerOptions::new().set_offset(offset); + let opt_notes = self.map.at(owner).view_notes(options); + // docs:end:view_notes + let len = opt_notes.len(); + for i in 0..len { + if opt_notes[i].is_some() { + balance = balance.add(opt_notes[i].unwrap_unchecked().get_amount()); + } + } + if (opt_notes[len - 1].is_some()) { + balance = balance.add(self.balance_of_with_offset(owner, offset + opt_notes.len() as u32)); + } - balance - } + balance + } - pub fn add(self: Self, owner: AztecAddress, addend: SafeU120) where T: NoteInterface + OwnedNote { + pub fn add( + self: Self, + owner: AztecAddress, + addend: SafeU120 + ) where T: NoteInterface + OwnedNote { let mut addend_note = T::new(addend, owner); // docs:start:insert @@ -68,7 +64,11 @@ impl BalancesMap { // docs:end:insert } - pub fn sub(self: Self, owner: AztecAddress, subtrahend: SafeU120) where T: NoteInterface + OwnedNote{ + pub fn sub( + self: Self, + owner: AztecAddress, + subtrahend: SafeU120 + ) where T: NoteInterface + OwnedNote { // docs:start:get_notes let options = NoteGetterOptions::with_filter(filter_notes_min_sum, subtrahend); let maybe_notes = self.map.at(owner).get_notes(options); @@ -98,7 +98,6 @@ impl BalancesMap { self.add(owner, minuend.sub(subtrahend)); } - } pub fn filter_notes_min_sum( diff --git a/yarn-project/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr b/yarn-project/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr index 0988df4842e..a1a0f0810bd 100644 --- a/yarn-project/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr +++ b/yarn-project/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr @@ -1,25 +1,9 @@ use dep::aztec::{ - protocol_types::{ - address::AztecAddress, - constants::{ - MAX_READ_REQUESTS_PER_CALL - }, - }, - note::{ - note_header::NoteHeader, - note_interface::NoteInterface, - utils::compute_note_hash_for_consumption, - }, - context::PrivateContext, - state_vars::set::Set, - log::emit_encrypted_log, - hash::pedersen_hash, -}; -use dep::aztec::oracle::{ - rand::rand, - nullifier_key::get_nullifier_secret_key, - get_public_key::get_public_key, + protocol_types::{address::AztecAddress, constants::{MAX_READ_REQUESTS_PER_CALL}}, + note::{note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_consumption}, + context::PrivateContext, state_vars::set::Set, log::emit_encrypted_log, hash::pedersen_hash }; +use dep::aztec::oracle::{rand::rand, nullifier_key::get_nullifier_secret_key, get_public_key::get_public_key}; use dep::safe_math::SafeU120; use dep::std::option::Option; diff --git a/yarn-project/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr b/yarn-project/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr index 8754cf2f889..4117d289776 100644 --- a/yarn-project/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr +++ b/yarn-project/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr @@ -1,12 +1,7 @@ // docs:start:token_types_all use dep::aztec::{ - note::{ - note_header::NoteHeader, - note_interface::NoteInterface, - utils::compute_note_hash_for_consumption, - }, - hash::{compute_secret_hash, pedersen_hash}, - context::PrivateContext, + note::{note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_consumption}, + hash::{compute_secret_hash, pedersen_hash}, context::PrivateContext }; global TRANSPARENT_NOTE_LEN: Field = 2; @@ -69,23 +64,13 @@ impl TransparentNote { // CONSTRUCTORS pub fn new(amount: Field, secret_hash: Field) -> Self { - TransparentNote { - amount: amount, - secret_hash: secret_hash, - secret: 0, - header: NoteHeader::empty(), - } + TransparentNote { amount, secret_hash, secret: 0, header: NoteHeader::empty() } } // new oracle call primitive // get me the secret corresponding to this hash pub fn new_from_secret(amount: Field, secret: Field) -> Self { - TransparentNote { - amount: amount, - secret_hash: compute_secret_hash(secret), - secret: secret, - header: NoteHeader::empty(), - } + TransparentNote { amount, secret_hash: compute_secret_hash(secret), secret, header: NoteHeader::empty() } } // CUSTOM FUNCTIONS FOR THIS NOTE TYPE diff --git a/yarn-project/noir-contracts/contracts/token_bridge_contract/src/main.nr b/yarn-project/noir-contracts/contracts/token_bridge_contract/src/main.nr index 489c95cb26c..895beb1bc0c 100644 --- a/yarn-project/noir-contracts/contracts/token_bridge_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/token_bridge_contract/src/main.nr @@ -7,19 +7,9 @@ mod token_interface; // Bridge has to be set as a minter on the token before it can be used contract TokenBridge { - use dep::aztec::protocol_types::{ - abis::function_selector::FunctionSelector, - address::{ - AztecAddress, - EthAddress, - }, - }; - - use dep::aztec::{ - context::{Context}, - hash::{compute_secret_hash}, - state_vars::{public_state::PublicState}, - }; + use dep::aztec::protocol_types::{abis::function_selector::FunctionSelector, address::{AztecAddress, EthAddress}}; + + use dep::aztec::{context::{Context}, hash::{compute_secret_hash}, state_vars::{public_state::PublicState}}; use dep::token_portal_content_hash_lib::{get_mint_public_content_hash, get_mint_private_content_hash, get_withdraw_content_hash}; diff --git a/yarn-project/noir-contracts/contracts/token_bridge_contract/src/token_interface.nr b/yarn-project/noir-contracts/contracts/token_bridge_contract/src/token_interface.nr index 130083d4b1d..4f0ef61e978 100644 --- a/yarn-project/noir-contracts/contracts/token_bridge_contract/src/token_interface.nr +++ b/yarn-project/noir-contracts/contracts/token_bridge_contract/src/token_interface.nr @@ -1,59 +1,56 @@ // docs:start:token_bridge_token_interface -use dep::aztec::protocol_types::{ - abis::function_selector::FunctionSelector, - address::{ - AztecAddress, - EthAddress, - }, -}; -use dep::aztec::{ - context::{ PrivateContext, PublicContext, Context }, -}; +use dep::aztec::protocol_types::{abis::function_selector::FunctionSelector, address::{AztecAddress, EthAddress}}; +use dep::aztec::{context::{PrivateContext, PublicContext, Context}}; struct Token { address: AztecAddress, } impl Token { - pub fn at(address: AztecAddress) -> Self { - Self { address } - } + pub fn at(address: AztecAddress) -> Self { + Self { address } + } - pub fn mint_public(self: Self, context: PublicContext, to: AztecAddress, amount: Field) { - let _return_values = context.call_public_function( - self.address, - FunctionSelector::from_signature("mint_public((Field),Field)"), - [to.to_field(), amount] - ); - } + pub fn mint_public(self: Self, context: PublicContext, to: AztecAddress, amount: Field) { + let _return_values = context.call_public_function( + self.address, + FunctionSelector::from_signature("mint_public((Field),Field)"), + [to.to_field(), amount] + ); + } - // docs:start:public_burn_interface - pub fn burn_public(self: Self, context: PublicContext, from: AztecAddress, amount: Field, nonce: Field) { - let _return_values = context.call_public_function( - self.address, - FunctionSelector::from_signature("burn_public((Field),Field,Field)"), - [from.to_field(), amount, nonce] - ); - } - // docs:end:public_burn_interface + // docs:start:public_burn_interface + pub fn burn_public( + self: Self, + context: PublicContext, + from: AztecAddress, + amount: Field, + nonce: Field + ) { + let _return_values = context.call_public_function( + self.address, + FunctionSelector::from_signature("burn_public((Field),Field,Field)"), + [from.to_field(), amount, nonce] + ); + } + // docs:end:public_burn_interface - pub fn mint_private(self: Self, context: PublicContext, amount: Field, secret_hash: Field) { - let _return_values = context.call_public_function( - self.address, - FunctionSelector::from_signature("mint_private(Field,Field)"), - [amount, secret_hash] - ); - } + pub fn mint_private(self: Self, context: PublicContext, amount: Field, secret_hash: Field) { + let _return_values = context.call_public_function( + self.address, + FunctionSelector::from_signature("mint_private(Field,Field)"), + [amount, secret_hash] + ); + } - - // docs:start:private_burn_interface - pub fn burn(self: Self, context: &mut PrivateContext, from: AztecAddress, amount: Field, nonce: Field) { - let _return_values = context.call_private_function( - self.address, - FunctionSelector::from_signature("burn((Field),Field,Field)"), - [from.to_field(), amount, nonce] - ); - } - // docs:end:private_burn_interface + // docs:start:private_burn_interface + pub fn burn(self: Self, context: &mut PrivateContext, from: AztecAddress, amount: Field, nonce: Field) { + let _return_values = context.call_private_function( + self.address, + FunctionSelector::from_signature("burn((Field),Field,Field)"), + [from.to_field(), amount, nonce] + ); + } + // docs:end:private_burn_interface } // docs:end:token_bridge_token_interface diff --git a/yarn-project/noir-contracts/contracts/token_contract/src/types/balances_map.nr b/yarn-project/noir-contracts/contracts/token_contract/src/types/balances_map.nr index 8452ba327a7..cbc423cc4ff 100644 --- a/yarn-project/noir-contracts/contracts/token_contract/src/types/balances_map.nr +++ b/yarn-project/noir-contracts/contracts/token_contract/src/types/balances_map.nr @@ -1,22 +1,12 @@ use dep::std::option::Option; use dep::safe_math::SafeU120; use dep::aztec::{ - context::Context, - protocol_types::{ - address::AztecAddress, - constants::MAX_READ_REQUESTS_PER_CALL, - }, - state_vars::{ - set::Set, - map::Map - }, + context::Context, protocol_types::{address::AztecAddress, constants::MAX_READ_REQUESTS_PER_CALL}, + state_vars::{set::Set, map::Map}, note::{ - note_getter::view_notes, - note_getter_options::{NoteGetterOptions, SortOrder}, - note_viewer_options::NoteViewerOptions, - note_header::NoteHeader, - note_interface::NoteInterface, - } + note_getter::view_notes, note_getter_options::{NoteGetterOptions, SortOrder}, + note_viewer_options::NoteViewerOptions, note_header::NoteHeader, note_interface::NoteInterface +} }; use crate::types::token_note::{TokenNote, OwnedNote}; @@ -25,41 +15,47 @@ struct BalancesMap { } impl BalancesMap { - pub fn new( - context: Context, - storage_slot: Field, - ) -> Self { + pub fn new(context: Context, storage_slot: Field) -> Self { assert(storage_slot != 0, "Storage slot 0 not allowed. Storage slots must start from 1."); - Self { - map: Map::new(context, storage_slot, |context, slot| Set::new(context, slot)) - } + Self { map: Map::new(context, storage_slot, |context, slot| Set::new(context, slot)) } } - unconstrained pub fn balance_of(self: Self, owner: AztecAddress) -> SafeU120 where T: NoteInterface + OwnedNote { + unconstrained pub fn balance_of( + self: Self, + owner: AztecAddress + ) -> SafeU120 where T: NoteInterface + OwnedNote { self.balance_of_with_offset(owner, 0) } - unconstrained pub fn balance_of_with_offset(self: Self, owner: AztecAddress, offset: u32) -> SafeU120 where T: NoteInterface + OwnedNote { - // Same as SafeU120::new(0), but fewer constraints because no check. - let mut balance = SafeU120::min(); - // docs:start:view_notes - let options = NoteViewerOptions::new().set_offset(offset); - let opt_notes = self.map.at(owner).view_notes(options); - // docs:end:view_notes - let len = opt_notes.len(); - for i in 0..len { - if opt_notes[i].is_some() { - balance = balance.add(opt_notes[i].unwrap_unchecked().get_amount()); - } - } - if (opt_notes[len - 1].is_some()) { - balance = balance.add(self.balance_of_with_offset(owner, offset + opt_notes.len() as u32)); - } + unconstrained pub fn balance_of_with_offset( + self: Self, + owner: AztecAddress, + offset: u32 + ) -> SafeU120 where T: NoteInterface + OwnedNote { + // Same as SafeU120::new(0), but fewer constraints because no check. + let mut balance = SafeU120::min(); + // docs:start:view_notes + let options = NoteViewerOptions::new().set_offset(offset); + let opt_notes = self.map.at(owner).view_notes(options); + // docs:end:view_notes + let len = opt_notes.len(); + for i in 0..len { + if opt_notes[i].is_some() { + balance = balance.add(opt_notes[i].unwrap_unchecked().get_amount()); + } + } + if (opt_notes[len - 1].is_some()) { + balance = balance.add(self.balance_of_with_offset(owner, offset + opt_notes.len() as u32)); + } - balance - } + balance + } - pub fn add(self: Self, owner: AztecAddress, addend: SafeU120) where T: NoteInterface + OwnedNote { + pub fn add( + self: Self, + owner: AztecAddress, + addend: SafeU120 + ) where T: NoteInterface + OwnedNote { let mut addend_note = T::new(addend, owner); // docs:start:insert @@ -67,7 +63,11 @@ impl BalancesMap { // docs:end:insert } - pub fn sub(self: Self, owner: AztecAddress, subtrahend: SafeU120) where T: NoteInterface + OwnedNote{ + pub fn sub( + self: Self, + owner: AztecAddress, + subtrahend: SafeU120 + ) where T: NoteInterface + OwnedNote { // docs:start:get_notes let options = NoteGetterOptions::with_filter(filter_notes_min_sum, subtrahend); let maybe_notes = self.map.at(owner).get_notes(options); @@ -97,7 +97,6 @@ impl BalancesMap { self.add(owner, minuend.sub(subtrahend)); } - } pub fn filter_notes_min_sum( diff --git a/yarn-project/noir-contracts/contracts/token_contract/src/types/token_note.nr b/yarn-project/noir-contracts/contracts/token_contract/src/types/token_note.nr index 7c11144e1fb..f9e58497c86 100644 --- a/yarn-project/noir-contracts/contracts/token_contract/src/types/token_note.nr +++ b/yarn-project/noir-contracts/contracts/token_contract/src/types/token_note.nr @@ -1,23 +1,9 @@ use dep::aztec::{ - protocol_types::{ - address::AztecAddress, - constants::MAX_READ_REQUESTS_PER_CALL - }, - note::{ - note_header::NoteHeader, - note_interface::NoteInterface, - utils::compute_note_hash_for_consumption, - }, - context::PrivateContext, - state_vars::set::Set, - log::emit_encrypted_log, - hash::pedersen_hash, -}; -use dep::aztec::oracle::{ - rand::rand, - nullifier_key::get_nullifier_secret_key, - get_public_key::get_public_key, + protocol_types::{address::AztecAddress, constants::MAX_READ_REQUESTS_PER_CALL}, + note::{note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_consumption}, + context::PrivateContext, state_vars::set::Set, log::emit_encrypted_log, hash::pedersen_hash }; +use dep::aztec::oracle::{rand::rand, nullifier_key::get_nullifier_secret_key, get_public_key::get_public_key}; use dep::safe_math::SafeU120; use dep::std::option::Option; diff --git a/yarn-project/noir-contracts/contracts/token_contract/src/types/transparent_note.nr b/yarn-project/noir-contracts/contracts/token_contract/src/types/transparent_note.nr index 8754cf2f889..4117d289776 100644 --- a/yarn-project/noir-contracts/contracts/token_contract/src/types/transparent_note.nr +++ b/yarn-project/noir-contracts/contracts/token_contract/src/types/transparent_note.nr @@ -1,12 +1,7 @@ // docs:start:token_types_all use dep::aztec::{ - note::{ - note_header::NoteHeader, - note_interface::NoteInterface, - utils::compute_note_hash_for_consumption, - }, - hash::{compute_secret_hash, pedersen_hash}, - context::PrivateContext, + note::{note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_consumption}, + hash::{compute_secret_hash, pedersen_hash}, context::PrivateContext }; global TRANSPARENT_NOTE_LEN: Field = 2; @@ -69,23 +64,13 @@ impl TransparentNote { // CONSTRUCTORS pub fn new(amount: Field, secret_hash: Field) -> Self { - TransparentNote { - amount: amount, - secret_hash: secret_hash, - secret: 0, - header: NoteHeader::empty(), - } + TransparentNote { amount, secret_hash, secret: 0, header: NoteHeader::empty() } } // new oracle call primitive // get me the secret corresponding to this hash pub fn new_from_secret(amount: Field, secret: Field) -> Self { - TransparentNote { - amount: amount, - secret_hash: compute_secret_hash(secret), - secret: secret, - header: NoteHeader::empty(), - } + TransparentNote { amount, secret_hash: compute_secret_hash(secret), secret, header: NoteHeader::empty() } } // CUSTOM FUNCTIONS FOR THIS NOTE TYPE diff --git a/yarn-project/noir-contracts/contracts/uniswap_contract/src/interfaces.nr b/yarn-project/noir-contracts/contracts/uniswap_contract/src/interfaces.nr index 3db1354766b..f70a2f93c38 100644 --- a/yarn-project/noir-contracts/contracts/uniswap_contract/src/interfaces.nr +++ b/yarn-project/noir-contracts/contracts/uniswap_contract/src/interfaces.nr @@ -1,39 +1,45 @@ // docs:start:interfaces -use dep::aztec::protocol_types::{ - abis::function_selector::FunctionSelector, - address::{ - AztecAddress, - EthAddress, - }, - }; -use dep::aztec::{ - context::{ PrivateContext, PublicContext }, -}; +use dep::aztec::protocol_types::{abis::function_selector::FunctionSelector, address::{AztecAddress, EthAddress}}; +use dep::aztec::{context::{PrivateContext, PublicContext}}; struct Token { address: AztecAddress, } impl Token { - pub fn at(address: AztecAddress) -> Self { - Self { address } - } - - pub fn transfer_public(self: Self, context: PublicContext, from: AztecAddress, to: AztecAddress, amount: Field, nonce: Field) { - context.call_public_function( - self.address, - FunctionSelector::from_signature("transfer_public((Field),(Field),Field,Field)"), - [from.to_field(), to.to_field(), amount, nonce] - ); - } - - pub fn unshield(self: Self, context: &mut PrivateContext, from: AztecAddress, to: AztecAddress, amount: Field, nonce: Field) { - context.call_private_function( - self.address, - FunctionSelector::from_signature("unshield((Field),(Field),Field,Field)"), - [from.to_field(), to.to_field(), amount, nonce] - ); - } + pub fn at(address: AztecAddress) -> Self { + Self { address } + } + + pub fn transfer_public( + self: Self, + context: PublicContext, + from: AztecAddress, + to: AztecAddress, + amount: Field, + nonce: Field + ) { + context.call_public_function( + self.address, + FunctionSelector::from_signature("transfer_public((Field),(Field),Field,Field)"), + [from.to_field(), to.to_field(), amount, nonce] + ); + } + + pub fn unshield( + self: Self, + context: &mut PrivateContext, + from: AztecAddress, + to: AztecAddress, + amount: Field, + nonce: Field + ) { + context.call_private_function( + self.address, + FunctionSelector::from_signature("unshield((Field),(Field),Field,Field)"), + [from.to_field(), to.to_field(), amount, nonce] + ); + } } struct TokenBridge { @@ -41,21 +47,32 @@ struct TokenBridge { } impl TokenBridge { - pub fn at(address: AztecAddress) -> Self { - Self { address } - } - - pub fn token(self: Self, context: PublicContext) -> AztecAddress { - let return_values = context.call_public_function(self.address, FunctionSelector::from_signature("get_token()"), []); - AztecAddress::from_field(return_values[0]) - } - - pub fn exit_to_l1_public(self: Self, context: PublicContext, recipient: EthAddress, amount: Field, callerOnL1: EthAddress, nonce: Field) { - context.call_public_function( - self.address, - FunctionSelector::from_signature("exit_to_l1_public((Field),Field,(Field),Field)"), - [recipient.to_field(), amount, callerOnL1.to_field(), nonce] - ); - } + pub fn at(address: AztecAddress) -> Self { + Self { address } + } + + pub fn token(self: Self, context: PublicContext) -> AztecAddress { + let return_values = context.call_public_function( + self.address, + FunctionSelector::from_signature("get_token()"), + [] + ); + AztecAddress::from_field(return_values[0]) + } + + pub fn exit_to_l1_public( + self: Self, + context: PublicContext, + recipient: EthAddress, + amount: Field, + callerOnL1: EthAddress, + nonce: Field + ) { + context.call_public_function( + self.address, + FunctionSelector::from_signature("exit_to_l1_public((Field),Field,(Field),Field)"), + [recipient.to_field(), amount, callerOnL1.to_field(), nonce] + ); + } } // docs:end:interfaces diff --git a/yarn-project/noir-contracts/contracts/uniswap_contract/src/main.nr b/yarn-project/noir-contracts/contracts/uniswap_contract/src/main.nr index b389f1b3413..32a078a9090 100644 --- a/yarn-project/noir-contracts/contracts/uniswap_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/uniswap_contract/src/main.nr @@ -6,17 +6,8 @@ mod util; // Has two separate flows for private and public respectively // Uses the token bridge contract, which tells which input token we need to talk to and handles the exit funds to L1 contract Uniswap { - use dep::aztec::protocol_types::{ - abis::function_selector::FunctionSelector, - address::{ - AztecAddress, - EthAddress, - }, - }; - use dep::aztec::{ - oracle::{context::get_portal_address}, - state_vars::{map::Map, public_state::PublicState}, - }; + use dep::aztec::protocol_types::{abis::function_selector::FunctionSelector, address::{AztecAddress, EthAddress}}; + use dep::aztec::{oracle::{context::get_portal_address}, state_vars::{map::Map, public_state::PublicState}}; use dep::authwit::auth::{IS_VALID_SELECTOR, assert_current_call_valid_authwit_public, compute_authwit_message_hash}; diff --git a/yarn-project/noir-contracts/contracts/uniswap_contract/src/util.nr b/yarn-project/noir-contracts/contracts/uniswap_contract/src/util.nr index d4e7399fad7..6be6bab884e 100644 --- a/yarn-project/noir-contracts/contracts/uniswap_contract/src/util.nr +++ b/yarn-project/noir-contracts/contracts/uniswap_contract/src/util.nr @@ -1,11 +1,5 @@ // docs:start:uniswap_public_content_hash -use dep::aztec::protocol_types::{ - address::{ - AztecAddress, - EthAddress, - }, - hash::sha256_to_field, -}; +use dep::aztec::protocol_types::{address::{AztecAddress, EthAddress}, hash::sha256_to_field}; // This method computes the L2 to L1 message content hash for the public // refer `l1-contracts/test/portals/UniswapPortal.sol` on how L2 to L1 message is expected diff --git a/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/common.nr b/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/common.nr index 815dffe78a2..6295d147116 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/common.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/common.nr @@ -1,52 +1,32 @@ use dep::std; use dep::types::{ abis::{ - call_request::CallRequest, - combined_accumulated_data::CombinedAccumulatedData, - function_data::FunctionData, - kernel_circuit_public_inputs::PrivateKernelCircuitPublicInputsBuilder, - membership_witness::ReadRequestMembershipWitness, - new_contract_data::NewContractData, - nullifier_key_validation_request::NullifierKeyValidationRequestContext, - private_circuit_public_inputs::PrivateCircuitPublicInputs, - private_kernel::private_call_data::PrivateCallData, - kernel_data::{PrivateKernelInnerData, PrivateKernelTailData}, - side_effect::{SideEffect, SideEffectLinkedToNoteHash}, - }, + call_request::CallRequest, combined_accumulated_data::CombinedAccumulatedData, + function_data::FunctionData, kernel_circuit_public_inputs::PrivateKernelCircuitPublicInputsBuilder, + membership_witness::ReadRequestMembershipWitness, new_contract_data::NewContractData, + nullifier_key_validation_request::NullifierKeyValidationRequestContext, + private_circuit_public_inputs::PrivateCircuitPublicInputs, + private_kernel::private_call_data::PrivateCallData, + kernel_data::{PrivateKernelInnerData, PrivateKernelTailData}, + side_effect::{SideEffect, SideEffectLinkedToNoteHash} +}, address::{AztecAddress, EthAddress, PartialAddress, compute_initialization_hash}, - contract_class::ContractClassId, - contrakt::deployment_data::ContractDeploymentData, + contract_class::ContractClassId, contrakt::deployment_data::ContractDeploymentData, constants::{ - MAX_NEW_NULLIFIERS_PER_CALL, - MAX_NEW_L2_TO_L1_MSGS_PER_CALL, - MAX_NEW_COMMITMENTS_PER_CALL, - MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, - MAX_READ_REQUESTS_PER_CALL, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, - }, + MAX_NEW_NULLIFIERS_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_NEW_COMMITMENTS_PER_CALL, + MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_READ_REQUESTS_PER_CALL, + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL +}, grumpkin_private_key::GrumpkinPrivateKey, hash::{ - compute_constructor_hash, - compute_l2_to_l1_hash, - compute_logs_hash, - compute_new_contract_address_hash, - contract_tree_root_from_siblings, - function_tree_root_from_siblings, - pedersen_hash, - private_functions_root_from_siblings, - read_request_root_from_siblings, - silo_commitment, - silo_nullifier, - stdlib_recursion_verification_key_compress_native_vk, - }, - utils::{ - arrays::{ - array_length, - array_to_bounded_vec, - validate_array, - }, - }, - traits::{is_empty, is_empty_array}, + compute_constructor_hash, compute_l2_to_l1_hash, compute_logs_hash, + compute_new_contract_address_hash, contract_tree_root_from_siblings, + function_tree_root_from_siblings, pedersen_hash, private_functions_root_from_siblings, + read_request_root_from_siblings, silo_commitment, silo_nullifier, + stdlib_recursion_verification_key_compress_native_vk +}, + utils::{arrays::{array_length, array_to_bounded_vec, validate_array}}, + traits::{is_empty, is_empty_array} }; pub fn validate_arrays(app_public_inputs: PrivateCircuitPublicInputs) { diff --git a/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_init.nr b/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_init.nr index 390de60f612..d4a489228df 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_init.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_init.nr @@ -2,18 +2,16 @@ use crate::common; use dep::std::unsafe; use dep::types::{ abis::{ - combined_constant_data::CombinedConstantData, - private_kernel::private_call_data::PrivateCallData, - kernel_circuit_public_inputs::{ - PrivateKernelInnerCircuitPublicInputs, - PrivateKernelTailCircuitPublicInputs, - PrivateKernelCircuitPublicInputsBuilder}, - side_effect::{SideEffect, SideEffectLinkedToNoteHash}, - }, + combined_constant_data::CombinedConstantData, private_kernel::private_call_data::PrivateCallData, + kernel_circuit_public_inputs::{ + PrivateKernelInnerCircuitPublicInputs, PrivateKernelTailCircuitPublicInputs, + PrivateKernelCircuitPublicInputsBuilder +}, + side_effect::{SideEffect, SideEffectLinkedToNoteHash} +}, address::{AztecAddress, PublicKeysHash, compute_initialization_hash}, - mocked::{Proof, verify_previous_kernel_state}, - transaction::request::TxRequest, - traits::is_empty_array, + mocked::{Proof, verify_previous_kernel_state}, transaction::request::TxRequest, + traits::is_empty_array }; // Initialization struct for private inputs to the private kernel @@ -37,7 +35,7 @@ impl PrivateKernelInitCircuitPrivateInputs { let tx_request = self.tx_request; // Call stack item for the initial call let call_stack_item = self.private_call.call_stack_item; - + // Checks to ensure that the user's intent matches the initial private call // // We use the word correct to denote whether it matches the user intent. @@ -48,7 +46,9 @@ impl PrivateKernelInitCircuitPrivateInputs { // // Ensure we are calling the correct initial function in the contract let entry_point_function_matches = tx_request.function_data.hash() == call_stack_item.function_data.hash(); - assert(entry_point_function_matches, "tx_request function_data must match call_stack_item function_data"); + assert( + entry_point_function_matches, "tx_request function_data must match call_stack_item function_data" + ); // // Ensure we are passing the correct arguments to the function. let args_match = tx_request.args_hash == call_stack_item.public_inputs.args_hash; @@ -66,17 +66,14 @@ impl PrivateKernelInitCircuitPrivateInputs { assert(call_context.is_delegate_call == false, "Users cannot make a delegatecall"); assert(call_context.is_static_call == false, "Users cannot make a static call"); // The below also prevents delegatecall/staticcall in the base case - assert(call_context.storage_contract_address.eq(call_stack_item.contract_address), "Storage contract address must be that of the called contract"); + assert( + call_context.storage_contract_address.eq(call_stack_item.contract_address), "Storage contract address must be that of the called contract" + ); } fn update_end_values(self, public_inputs: &mut PrivateKernelCircuitPublicInputsBuilder) { // Since it's the first iteration, we need to push the the tx hash nullifier into the `new_nullifiers` array - public_inputs.end.new_nullifiers.push(SideEffectLinkedToNoteHash{ - value: self.tx_request.hash(), - note_hash: 0, - counter: 0, - }); - + public_inputs.end.new_nullifiers.push(SideEffectLinkedToNoteHash { value: self.tx_request.hash(), note_hash: 0, counter: 0 }); // Note that we do not need to nullify the transaction request nonce anymore. // Should an account want to additionally use nonces for replay protection or handling cancellations, // they will be able to do so in the account contract logic: @@ -86,7 +83,7 @@ impl PrivateKernelInitCircuitPrivateInputs { pub fn native_private_kernel_circuit_initial(self) -> PrivateKernelInnerCircuitPublicInputs { let mut public_inputs: PrivateKernelCircuitPublicInputsBuilder = unsafe::zeroed(); public_inputs.is_private = true; - + self.initialize_end_values(&mut public_inputs); self.validate_inputs(); @@ -105,13 +102,15 @@ impl PrivateKernelInitCircuitPrivateInputs { self.update_end_values(&mut public_inputs); common::update_end_values(self.private_call, &mut public_inputs); - common::contract_logic(self.private_call, - &mut public_inputs, - self.tx_request.tx_context.contract_deployment_data, - self.tx_request.function_data); + common::contract_logic( + self.private_call, + &mut public_inputs, + self.tx_request.tx_context.contract_deployment_data, + self.tx_request.function_data + ); // TODO(David): What previous kernel proof are we talking about, since this is private-kernel-init - let (is_previous_state_valid, updated_aggregation_object) = verify_previous_kernel_state(public_inputs.aggregation_object,self.private_call.proof); + let (is_previous_state_valid, updated_aggregation_object) = verify_previous_kernel_state(public_inputs.aggregation_object, self.private_call.proof); assert(is_previous_state_valid); public_inputs.aggregation_object = updated_aggregation_object; @@ -122,27 +121,19 @@ impl PrivateKernelInitCircuitPrivateInputs { mod tests { use crate::private_kernel_init::PrivateKernelInitCircuitPrivateInputs; - use dep::types::constants::{ - MAX_READ_REQUESTS_PER_CALL, - }; + use dep::types::constants::{MAX_READ_REQUESTS_PER_CALL}; use dep::types::{ abis::{ - kernel_circuit_public_inputs::PrivateKernelInnerCircuitPublicInputs, - nullifier_key_validation_request::NullifierKeyValidationRequest, - private_kernel::private_call_data::PrivateCallData, - side_effect::{SideEffect, SideEffectLinkedToNoteHash}, - }, - grumpkin_point::GrumpkinPoint, - grumpkin_private_key::GrumpkinPrivateKey, + kernel_circuit_public_inputs::PrivateKernelInnerCircuitPublicInputs, + nullifier_key_validation_request::NullifierKeyValidationRequest, + private_kernel::private_call_data::PrivateCallData, + side_effect::{SideEffect, SideEffectLinkedToNoteHash} + }, + grumpkin_point::GrumpkinPoint, grumpkin_private_key::GrumpkinPrivateKey, address::{AztecAddress, compute_initialization_hash}, - hash::{ - compute_constructor_hash, - compute_logs_hash, - stdlib_recursion_verification_key_compress_native_vk, - }, - tests::private_call_data_builder::PrivateCallDataBuilder, - transaction::request::TxRequest, - utils::arrays::array_length, + hash::{compute_constructor_hash, compute_logs_hash, stdlib_recursion_verification_key_compress_native_vk}, + tests::private_call_data_builder::PrivateCallDataBuilder, transaction::request::TxRequest, + utils::arrays::array_length }; struct PrivateKernelInitInputsBuilder { @@ -163,17 +154,11 @@ mod tests { let private_call = PrivateCallDataBuilder::new(is_constructor); let tx_request = private_call.build_tx_request(); - PrivateKernelInitInputsBuilder { - tx_request, - private_call, - } + PrivateKernelInitInputsBuilder { tx_request, private_call } } pub fn execute(self) -> PrivateKernelInnerCircuitPublicInputs { - let kernel = PrivateKernelInitCircuitPrivateInputs { - tx_request: self.tx_request, - private_call: self.private_call.finish(), - }; + let kernel = PrivateKernelInitCircuitPrivateInputs { tx_request: self.tx_request, private_call: self.private_call.finish() }; kernel.native_private_kernel_circuit_initial() } diff --git a/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_inner.nr b/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_inner.nr index 0f0abe3a330..65a93f4c77e 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_inner.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_inner.nr @@ -2,12 +2,11 @@ use crate::common; use dep::std::unsafe; use dep::types::{ abis::{ - kernel_data::PrivateKernelInnerData, - private_kernel::private_call_data::PrivateCallData, - kernel_circuit_public_inputs::{PrivateKernelInnerCircuitPublicInputs, PrivateKernelCircuitPublicInputsBuilder}, - side_effect::{SideEffect, SideEffectLinkedToNoteHash}, - }, - mocked::verify_previous_kernel_state, + kernel_data::PrivateKernelInnerData, private_kernel::private_call_data::PrivateCallData, + kernel_circuit_public_inputs::{PrivateKernelInnerCircuitPublicInputs, PrivateKernelCircuitPublicInputsBuilder}, + side_effect::{SideEffect, SideEffectLinkedToNoteHash} +}, + mocked::verify_previous_kernel_state }; struct PrivateKernelInnerCircuitPrivateInputs { @@ -16,7 +15,7 @@ struct PrivateKernelInnerCircuitPrivateInputs { } impl PrivateKernelInnerCircuitPrivateInputs { - fn pop_and_validate_this_private_call_hash(self, public_inputs: &mut PrivateKernelCircuitPublicInputsBuilder){ + fn pop_and_validate_this_private_call_hash(self, public_inputs: &mut PrivateKernelCircuitPublicInputsBuilder) { let call_request = public_inputs.end.private_call_stack.pop(); common::validate_call_against_request(self.private_call, call_request); } @@ -25,14 +24,18 @@ impl PrivateKernelInnerCircuitPrivateInputs { let purported_contract_tree_root = self.private_call.call_stack_item.public_inputs.historical_header.state.partial.contract_tree.root; let previous_kernel_contract_tree_root = self.previous_kernel.public_inputs.constants.historical_header.state.partial.contract_tree.root; - assert(purported_contract_tree_root == previous_kernel_contract_tree_root, "purported_contract_tree_root does not match previous_kernel_contract_tree_root"); + assert( + purported_contract_tree_root == previous_kernel_contract_tree_root, "purported_contract_tree_root does not match previous_kernel_contract_tree_root" + ); } fn validate_inputs(self) { let this_call_stack_item = self.private_call.call_stack_item; let function_data = this_call_stack_item.function_data; assert(function_data.is_private, "Private kernel circuit can only execute a private function"); - assert(self.previous_kernel.public_inputs.is_private, "Can only verify a private kernel snark in the private kernel circuit"); + assert( + self.previous_kernel.public_inputs.is_private, "Can only verify a private kernel snark in the private kernel circuit" + ); } pub fn native_private_kernel_circuit_inner(self) -> PrivateKernelInnerCircuitPublicInputs { @@ -52,8 +55,9 @@ impl PrivateKernelInnerCircuitPrivateInputs { common::validate_read_requests( public_inputs.constants.historical_header.state.partial.note_hash_tree.root, - self.private_call.call_stack_item.public_inputs.read_requests, // read requests from private call - self.private_call.read_request_membership_witnesses); + self.private_call.call_stack_item.public_inputs.read_requests, // read requests from private call + self.private_call.read_request_membership_witnesses + ); //TODO(David): feels like update_end_values should happen later common::update_end_values(self.private_call, &mut public_inputs); @@ -63,12 +67,14 @@ impl PrivateKernelInnerCircuitPrivateInputs { let this_call_stack_item = self.private_call.call_stack_item; - common::contract_logic(self.private_call, + common::contract_logic( + self.private_call, &mut public_inputs, this_call_stack_item.public_inputs.contract_deployment_data, - this_call_stack_item.function_data); + this_call_stack_item.function_data + ); - let (is_previous_state_valid, updated_aggregation_object) = verify_previous_kernel_state(public_inputs.aggregation_object,self.private_call.proof); + let (is_previous_state_valid, updated_aggregation_object) = verify_previous_kernel_state(public_inputs.aggregation_object, self.private_call.proof); assert(is_previous_state_valid); public_inputs.aggregation_object = updated_aggregation_object; @@ -79,24 +85,14 @@ impl PrivateKernelInnerCircuitPrivateInputs { mod tests { use crate::private_kernel_inner::PrivateKernelInnerCircuitPrivateInputs; - use dep::types::constants::{ - MAX_READ_REQUESTS_PER_CALL, - MAX_NEW_COMMITMENTS_PER_TX, - }; + use dep::types::constants::{MAX_READ_REQUESTS_PER_CALL, MAX_NEW_COMMITMENTS_PER_TX}; use dep::types::{ abis::{ - kernel_circuit_public_inputs::PrivateKernelInnerCircuitPublicInputs, - side_effect::{SideEffect, SideEffectLinkedToNoteHash}, - }, - tests::{ - kernel_data_builder::PreviousKernelDataBuilder, - private_call_data_builder::PrivateCallDataBuilder, - }, - address::AztecAddress, - hash::compute_logs_hash, - utils::{ - arrays::array_length, - }, + kernel_circuit_public_inputs::PrivateKernelInnerCircuitPublicInputs, + side_effect::{SideEffect, SideEffectLinkedToNoteHash} + }, + tests::{kernel_data_builder::PreviousKernelDataBuilder, private_call_data_builder::PrivateCallDataBuilder}, + address::AztecAddress, hash::compute_logs_hash, utils::{arrays::array_length} }; struct PrivateKernelInnerInputsBuilder { @@ -136,10 +132,7 @@ mod tests { self.previous_kernel.push_private_call_request(hash, is_delegate_call); let previous_kernel = self.previous_kernel.to_private_kernel_inner_data(); - let kernel = PrivateKernelInnerCircuitPrivateInputs { - previous_kernel, - private_call, - }; + let kernel = PrivateKernelInnerCircuitPrivateInputs { previous_kernel, private_call }; kernel.native_private_kernel_circuit_inner() } diff --git a/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_tail.nr b/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_tail.nr index 03e28b27fc2..250902c2819 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_tail.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_tail.nr @@ -1,38 +1,21 @@ use crate::common; -use dep::std::{ - cmp::Eq, - option::Option, - unsafe, -}; +use dep::std::{cmp::Eq, option::Option, unsafe}; use dep::types::{ abis::{ - call_request::CallRequest, - combined_accumulated_data::AccumulatedNonRevertibleData, - nullifier_key_validation_request::NullifierKeyValidationRequestContext, - kernel_data::{PrivateKernelInnerData, PrivateKernelTailData}, - kernel_circuit_public_inputs::{ - PrivateKernelCircuitPublicInputsBuilder, - PrivateKernelTailCircuitPublicInputs, - }, - side_effect::{SideEffect, SideEffectLinkedToNoteHash, Ordered}, - }, + call_request::CallRequest, combined_accumulated_data::AccumulatedNonRevertibleData, + nullifier_key_validation_request::NullifierKeyValidationRequestContext, + kernel_data::{PrivateKernelInnerData, PrivateKernelTailData}, + kernel_circuit_public_inputs::{PrivateKernelCircuitPublicInputsBuilder, PrivateKernelTailCircuitPublicInputs}, + side_effect::{SideEffect, SideEffectLinkedToNoteHash, Ordered} +}, constants::{ - MAX_NEW_COMMITMENTS_PER_TX, - MAX_NEW_NULLIFIERS_PER_TX, - MAX_READ_REQUESTS_PER_TX, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, - MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, - MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX - }, + MAX_NEW_COMMITMENTS_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_READ_REQUESTS_PER_TX, + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, + MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX +}, grumpkin_private_key::GrumpkinPrivateKey, - hash::{ - compute_commitment_nonce, - compute_unique_siloed_commitment, - }, - utils::{ - arrays::{array_length, array_eq}, - }, - traits::{Empty, is_empty} + hash::{compute_commitment_nonce, compute_unique_siloed_commitment}, + utils::{arrays::{array_length, array_eq}}, traits::{Empty, is_empty} }; struct PrivateKernelTailCircuitPrivateInputs { @@ -48,8 +31,9 @@ struct PrivateKernelTailCircuitPrivateInputs { impl PrivateKernelTailCircuitPrivateInputs { fn validate_inputs(self) { - assert_eq(array_length(self.previous_kernel.public_inputs.end.private_call_stack), 0, - "Private call stack must be empty when executing the ordering circuit"); + assert_eq( + array_length(self.previous_kernel.public_inputs.end.private_call_stack), 0, "Private call stack must be empty when executing the ordering circuit" + ); } fn validate_nullifier_keys(self, public_inputs: &mut PrivateKernelCircuitPublicInputsBuilder) { @@ -59,10 +43,14 @@ impl PrivateKernelTailCircuitPrivateInputs { if !is_empty(request) { let master_secret_key = self.master_nullifier_secret_keys[i]; let computed_public_key = master_secret_key.derive_public_key(); - assert(computed_public_key.eq(request.public_key), "Cannot derive nullifier public key from the master key."); + assert( + computed_public_key.eq(request.public_key), "Cannot derive nullifier public key from the master key." + ); let computed_secret_key = common::compute_siloed_nullifier_secret_key(master_secret_key, request.contract_address); - assert(computed_secret_key.eq(request.secret_key), "Cannot derive siloed secret key from the master key."); + assert( + computed_secret_key.eq(request.secret_key), "Cannot derive siloed secret key from the master key." + ); } } @@ -81,8 +69,12 @@ impl PrivateKernelTailCircuitPrivateInputs { if (read_request.value != 0) { let commitment = new_commitments.get_unchecked(read_commitment_hint as Field); - assert_eq(read_request.value, commitment.value, "Hinted commitment does not match read request"); - assert(read_request.counter > commitment.counter, "Read request counter must be greater than commitment counter"); + assert_eq( + read_request.value, commitment.value, "Hinted commitment does not match read request" + ); + assert( + read_request.counter > commitment.counter, "Read request counter must be greater than commitment counter" + ); } } @@ -113,8 +105,16 @@ impl PrivateKernelTailCircuitPrivateInputs { } fn sort_arrays(self, public_inputs: &mut PrivateKernelCircuitPublicInputsBuilder) { - PrivateKernelTailCircuitPrivateInputs::assert_sorted_counters(public_inputs.end.new_commitments.storage, self.sorted_new_commitments, self.sorted_new_commitments_indexes); - PrivateKernelTailCircuitPrivateInputs::assert_sorted_counters(public_inputs.end.new_nullifiers.storage, self.sorted_new_nullifiers, self.sorted_new_nullifiers_indexes); + PrivateKernelTailCircuitPrivateInputs::assert_sorted_counters( + public_inputs.end.new_commitments.storage, + self.sorted_new_commitments, + self.sorted_new_commitments_indexes + ); + PrivateKernelTailCircuitPrivateInputs::assert_sorted_counters( + public_inputs.end.new_nullifiers.storage, + self.sorted_new_nullifiers, + self.sorted_new_nullifiers_indexes + ); public_inputs.end.new_commitments.storage = self.sorted_new_commitments; public_inputs.end.new_nullifiers.storage = self.sorted_new_nullifiers; } @@ -136,10 +136,14 @@ impl PrivateKernelTailCircuitPrivateInputs { // Non-empty nullified_commitment implies transient nullifier which MUST be matched to a commitment below! // 0-valued nullified_commitment is empty and will be ignored if nullified_commitment != 0 { - assert(hint_pos < MAX_NEW_COMMITMENTS_PER_TX as u64, "New nullifier is transient but hint is invalid"); + assert( + hint_pos < MAX_NEW_COMMITMENTS_PER_TX as u64, "New nullifier is transient but hint is invalid" + ); let commitment = new_commitments[hint_pos]; assert_eq(nullified_commitment, commitment.value, "Hinted commitment does not match"); - assert(nullifier.counter > commitment.counter, "Nullifier counter must be greater than commitment counter"); + assert( + nullifier.counter > commitment.counter, "Nullifier counter must be greater than commitment counter" + ); // match found! // squash both the nullifier and the commitment // (set to 0 here and then rearrange array after loop) @@ -218,8 +222,7 @@ impl PrivateKernelTailCircuitPrivateInputs { PrivateKernelTailCircuitPrivateInputs::apply_commitment_nonces(&mut public_inputs); // TODO(fees) populate this - let end_non_revertible : AccumulatedNonRevertibleData = unsafe::zeroed(); - + let end_non_revertible : AccumulatedNonRevertibleData = unsafe::zeroed(); public_inputs.to_tail(end_non_revertible) } @@ -228,22 +231,14 @@ impl PrivateKernelTailCircuitPrivateInputs { mod tests { use dep::std::cmp::Eq; use crate::private_kernel_tail::PrivateKernelTailCircuitPrivateInputs; - use dep::types::constants::{ - MAX_READ_REQUESTS_PER_TX, - MAX_NEW_COMMITMENTS_PER_TX, - MAX_NEW_NULLIFIERS_PER_TX, - }; + use dep::types::constants::{MAX_READ_REQUESTS_PER_TX, MAX_NEW_COMMITMENTS_PER_TX, MAX_NEW_NULLIFIERS_PER_TX}; use dep::types::{ abis::{ - kernel_circuit_public_inputs::PrivateKernelTailCircuitPublicInputs, - side_effect::{SideEffect, SideEffectLinkedToNoteHash, Ordered}, - }, - hash::compute_unique_siloed_commitments, - tests::kernel_data_builder::PreviousKernelDataBuilder, - utils::{ - arrays::{array_eq, array_length}, - }, - traits::{Empty, is_empty, is_empty_array} + kernel_circuit_public_inputs::PrivateKernelTailCircuitPublicInputs, + side_effect::{SideEffect, SideEffectLinkedToNoteHash, Ordered} + }, + hash::compute_unique_siloed_commitments, tests::kernel_data_builder::PreviousKernelDataBuilder, + utils::{arrays::{array_eq, array_length}}, traits::{Empty, is_empty, is_empty_array} }; struct PrivateKernelOrderingInputsBuilder { @@ -257,7 +252,7 @@ mod tests { PrivateKernelOrderingInputsBuilder { previous_kernel: PreviousKernelDataBuilder::new(), read_commitment_hints: [0; MAX_READ_REQUESTS_PER_TX], - nullifier_commitment_hints: [0; MAX_NEW_NULLIFIERS_PER_TX], + nullifier_commitment_hints: [0; MAX_NEW_NULLIFIERS_PER_TX] } } @@ -299,12 +294,13 @@ mod tests { self.nullifier_commitment_hints[nullifier_index] = commitment_index; } - fn sort_sideffects(original: [T; N]) -> ([T; N],[u32; N]) where T: Ordered + Eq + Empty { + fn sort_sideffects(original: [T; N]) -> ([T; N], [u32; N]) where T: Ordered + Eq + Empty { let mut indexes = [0; N]; for i in 0..N { indexes[i] = i as u32; } - let sorted_indexes = indexes.sort_via(|a_index: u32, b_index: u32| { + let sorted_indexes = indexes.sort_via( + |a_index: u32, b_index: u32| { let a = original[a_index]; let b = original[b_index]; if is_empty(b) { @@ -314,7 +310,8 @@ mod tests { } else { a.counter() < b.counter() } - }); + } + ); let sorted_sideffects = sorted_indexes.map(|i: u32| original[i]); let mut reverse_map = [0; N]; for i in 0..N { @@ -343,7 +340,7 @@ mod tests { sorted_new_nullifiers, sorted_new_nullifiers_indexes, nullifier_commitment_hints: sorted_nullifier_commitment_hints, - master_nullifier_secret_keys: dep::std::unsafe::zeroed(), + master_nullifier_secret_keys: dep::std::unsafe::zeroed() }; kernel.native_private_kernel_circuit_ordering() } diff --git a/yarn-project/noir-protocol-circuits/src/crates/public-kernel-lib/src/common.nr b/yarn-project/noir-protocol-circuits/src/crates/public-kernel-lib/src/common.nr index 8841ecd5bee..9a79c8060cf 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/public-kernel-lib/src/common.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/public-kernel-lib/src/common.nr @@ -1,36 +1,22 @@ use dep::types::{ abis::{ - call_request::CallRequest, - public_call_stack_item::PublicCallStackItem, - combined_accumulated_data::{CombinedAccumulatedData, CombinedAccumulatedDataBuilder}, - kernel_circuit_public_inputs::PublicKernelCircuitPublicInputsBuilder, - new_contract_data::NewContractData, - kernel_data::{PrivateKernelTailData, PublicKernelData}, - public_call_data::PublicCallData, - public_circuit_public_inputs::PublicCircuitPublicInputs, - public_data_read::PublicDataRead, - public_data_update_request::PublicDataUpdateRequest, - side_effect::{SideEffect, SideEffectLinkedToNoteHash}, - }, + call_request::CallRequest, public_call_stack_item::PublicCallStackItem, + combined_accumulated_data::{CombinedAccumulatedData, CombinedAccumulatedDataBuilder}, + kernel_circuit_public_inputs::PublicKernelCircuitPublicInputsBuilder, + new_contract_data::NewContractData, kernel_data::{PrivateKernelTailData, PublicKernelData}, + public_call_data::PublicCallData, public_circuit_public_inputs::PublicCircuitPublicInputs, + public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, + side_effect::{SideEffect, SideEffectLinkedToNoteHash} +}, address::AztecAddress, - contrakt::{ - storage_read::StorageRead, - storage_update_request::StorageUpdateRequest, - }, + contrakt::{storage_read::StorageRead, storage_update_request::StorageUpdateRequest}, constants::{ - MAX_NEW_L2_TO_L1_MSGS_PER_CALL, - MAX_NEW_COMMITMENTS_PER_CALL, - MAX_NEW_NULLIFIERS_PER_CALL, - MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - MAX_PUBLIC_DATA_READS_PER_CALL, - NUM_FIELDS_PER_SHA256 - }, + MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_NEW_COMMITMENTS_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, + MAX_PUBLIC_DATA_READS_PER_CALL, NUM_FIELDS_PER_SHA256 +}, hash::{silo_commitment, silo_nullifier, compute_l2_to_l1_hash, accumulate_sha256}, - utils::{ - arrays::{array_length, array_to_bounded_vec}, - }, - traits::is_empty_array + utils::{arrays::{array_length, array_to_bounded_vec}}, traits::is_empty_array }; use crate::hash::{compute_public_data_tree_index, compute_public_data_tree_value}; diff --git a/yarn-project/noir-protocol-circuits/src/crates/public-kernel-lib/src/hash.nr b/yarn-project/noir-protocol-circuits/src/crates/public-kernel-lib/src/hash.nr index 531fc8f8077..3af3adb0bfe 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/public-kernel-lib/src/hash.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/public-kernel-lib/src/hash.nr @@ -1,7 +1,4 @@ -use dep::types::{ - address::AztecAddress, - constants::GENERATOR_INDEX__PUBLIC_LEAF_INDEX, -}; +use dep::types::{address::AztecAddress, constants::GENERATOR_INDEX__PUBLIC_LEAF_INDEX}; pub fn compute_public_data_tree_index(contract_address: AztecAddress, storage_slot: Field) -> Field { dep::std::hash::pedersen_hash_with_separator( diff --git a/yarn-project/noir-protocol-circuits/src/crates/public-kernel-lib/src/public_kernel_app_logic.nr b/yarn-project/noir-protocol-circuits/src/crates/public-kernel-lib/src/public_kernel_app_logic.nr index b5b7089aaff..2df4f9f803e 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/public-kernel-lib/src/public_kernel_app_logic.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/public-kernel-lib/src/public_kernel_app_logic.nr @@ -1,5 +1,5 @@ use dep::types::abis::public_call_data::PublicCallData; -use dep::types::abis::kernel_data::{ PublicKernelData }; +use dep::types::abis::kernel_data::{PublicKernelData}; use dep::types::PublicKernelCircuitPublicInputs; use dep::types::abis::kernel_circuit_public_inputs::PublicKernelCircuitPublicInputsBuilder; use crate::common; @@ -12,14 +12,14 @@ struct PublicKernelAppLogicCircuitPrivateInputs { impl PublicKernelAppLogicCircuitPrivateInputs { -// this is the only difference between the two PublicKernels' logic: + // this is the only difference between the two PublicKernels' logic: fn validate_inputs(self) { let previous_call_is_private = self.previous_kernel.public_inputs.is_private; - assert(previous_call_is_private == false, - "Previous kernel must be public when in this public kernel version"); + assert( + previous_call_is_private == false, "Previous kernel must be public when in this public kernel version" + ); } - fn public_kernel_app_logic(self) -> PublicKernelCircuitPublicInputs { // construct the circuit outputs let mut public_inputs: PublicKernelCircuitPublicInputsBuilder = unsafe::zeroed(); @@ -37,7 +37,7 @@ impl PublicKernelAppLogicCircuitPrivateInputs { let call_request = public_inputs.end.public_call_stack.pop(); common::validate_call_against_request(self.public_call, call_request); - common::update_public_end_values(self.public_call,&mut public_inputs); + common::update_public_end_values(self.public_call, &mut public_inputs); common::accumulate_unencrypted_logs( self.public_call, @@ -54,37 +54,21 @@ mod tests { use crate::{ public_kernel_app_logic::PublicKernelAppLogicCircuitPrivateInputs, utils::{ - assert_eq_public_data_reads, - assert_eq_public_data_update_requests, - compute_public_data_reads, - compute_public_data_update_requests, - }, + assert_eq_public_data_reads, assert_eq_public_data_update_requests, compute_public_data_reads, + compute_public_data_update_requests + } }; use dep::types::{ abis::{ - kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs, - public_data_read::PublicDataRead, - public_data_update_request::PublicDataUpdateRequest, - side_effect::{SideEffect, SideEffectLinkedToNoteHash}, - }, - hash::{ - compute_l2_to_l1_hash, - compute_logs_hash, - silo_commitment, - silo_nullifier, - }, - tests::{ - kernel_data_builder::PreviousKernelDataBuilder, - public_call_data_builder::PublicCallDataBuilder, - }, - utils::{ - arrays::array_eq, - }, - }; - use dep::types::constants::{ - MAX_PUBLIC_DATA_READS_PER_CALL, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, + kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs, public_data_read::PublicDataRead, + public_data_update_request::PublicDataUpdateRequest, + side_effect::{SideEffect, SideEffectLinkedToNoteHash} + }, + hash::{compute_l2_to_l1_hash, compute_logs_hash, silo_commitment, silo_nullifier}, + tests::{kernel_data_builder::PreviousKernelDataBuilder, public_call_data_builder::PublicCallDataBuilder}, + utils::{arrays::array_eq} }; + use dep::types::constants::{MAX_PUBLIC_DATA_READS_PER_CALL, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL}; struct PublicKernelAppLogicCircuitPrivateInputsBuilder { previous_kernel: PreviousKernelDataBuilder, @@ -95,11 +79,8 @@ mod tests { pub fn new() -> Self { let previous_kernel = PreviousKernelDataBuilder::new().is_public(); let public_call = PublicCallDataBuilder::new(); - - PublicKernelAppLogicCircuitPrivateInputsBuilder { - previous_kernel, - public_call, - } + + PublicKernelAppLogicCircuitPrivateInputsBuilder { previous_kernel, public_call } } pub fn is_delegate_call(&mut self) -> Self { @@ -115,7 +96,7 @@ mod tests { pub fn get_current_public_data_update_requests(self) -> [PublicDataUpdateRequest; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL] { compute_public_data_update_requests( self.public_call.contract_address, - self.public_call.public_inputs.contract_storage_update_requests.storage, + self.public_call.public_inputs.contract_storage_update_requests.storage ) } @@ -127,10 +108,7 @@ mod tests { self.previous_kernel.push_public_call_request(hash, is_delegate_call); let previous_kernel = self.previous_kernel.to_public_kernel_data(); - let kernel = PublicKernelAppLogicCircuitPrivateInputs { - previous_kernel, - public_call, - }; + let kernel = PublicKernelAppLogicCircuitPrivateInputs { previous_kernel, public_call }; kernel.public_kernel_app_logic() } diff --git a/yarn-project/noir-protocol-circuits/src/crates/public-kernel-lib/src/public_kernel_setup.nr b/yarn-project/noir-protocol-circuits/src/crates/public-kernel-lib/src/public_kernel_setup.nr index 05594ed0f2a..50e991a414b 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/public-kernel-lib/src/public_kernel_setup.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/public-kernel-lib/src/public_kernel_setup.nr @@ -1,13 +1,10 @@ use crate::common; use dep::types::abis::{ kernel_circuit_public_inputs::{ - PrivateKernelTailCircuitPublicInputs, - PublicKernelCircuitPublicInputs, - PublicKernelCircuitPublicInputsBuilder, - - }, - kernel_data::PublicKernelData, - public_call_data::PublicCallData, + PrivateKernelTailCircuitPublicInputs, PublicKernelCircuitPublicInputs, + PublicKernelCircuitPublicInputsBuilder +}, + kernel_data::PublicKernelData, public_call_data::PublicCallData }; use dep::std::unsafe; @@ -29,13 +26,15 @@ impl PublicKernelSetupCircuitPrivateInputs { let private_call_stack = self.previous_kernel.public_inputs.end.private_call_stack; for i in 0..private_call_stack.len() { let private_call = private_call_stack[i]; - assert(private_call.is_empty(), - "Private call stack must be empty when executing in the public kernel"); + assert( + private_call.is_empty(), "Private call stack must be empty when executing in the public kernel" + ); } let previous_call_is_private = self.previous_kernel.public_inputs.is_private; - assert(previous_call_is_private == true, - "Previous kernel must be private when in this public kernel version"); + assert( + previous_call_is_private == true, "Previous kernel must be private when in this public kernel version" + ); } fn public_kernel_setup(self) -> PublicKernelCircuitPublicInputs { @@ -55,7 +54,7 @@ impl PublicKernelSetupCircuitPrivateInputs { let call_request = public_inputs.end.public_call_stack.pop(); common::validate_call_against_request(self.public_call, call_request); - common::update_public_end_values(self.public_call,&mut public_inputs); + common::update_public_end_values(self.public_call, &mut public_inputs); common::accumulate_unencrypted_logs( self.public_call, @@ -72,42 +71,26 @@ mod tests { use crate::{ public_kernel_setup::PublicKernelSetupCircuitPrivateInputs, utils::{ - assert_eq_call_requests, - assert_eq_new_contracts, - assert_eq_public_data_reads, - assert_eq_public_data_update_requests, - compute_public_data_reads, - compute_public_data_update_requests, - }, + assert_eq_call_requests, assert_eq_new_contracts, assert_eq_public_data_reads, + assert_eq_public_data_update_requests, compute_public_data_reads, + compute_public_data_update_requests + } }; use dep::types::{ abis::{ - call_request::CallRequest, - function_selector::FunctionSelector, - kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs, - new_contract_data::NewContractData, - public_data_read::PublicDataRead, - public_data_update_request::PublicDataUpdateRequest, - }, - address::{AztecAddress, EthAddress}, - contract_class::ContractClassId, - contrakt::storage_read::StorageRead, - hash::compute_logs_hash, - tests::{ - kernel_data_builder::PreviousKernelDataBuilder, - public_call_data_builder::PublicCallDataBuilder, - }, - utils::{ - arrays::{ - array_eq, - array_length, - }, - }, + call_request::CallRequest, function_selector::FunctionSelector, + kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs, + new_contract_data::NewContractData, public_data_read::PublicDataRead, + public_data_update_request::PublicDataUpdateRequest + }, + address::{AztecAddress, EthAddress}, contract_class::ContractClassId, + contrakt::storage_read::StorageRead, hash::compute_logs_hash, + tests::{kernel_data_builder::PreviousKernelDataBuilder, public_call_data_builder::PublicCallDataBuilder}, + utils::{arrays::{array_eq, array_length}} }; use dep::types::constants::{ - MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, - MAX_PUBLIC_DATA_READS_PER_CALL, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_DATA_READS_PER_CALL, + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL }; struct PublicKernelSetupCircuitPrivateInputsBuilder { @@ -119,11 +102,8 @@ mod tests { pub fn new() -> Self { let previous_kernel = PreviousKernelDataBuilder::new(); let public_call = PublicCallDataBuilder::new(); - - PublicKernelSetupCircuitPrivateInputsBuilder { - previous_kernel, - public_call, - } + + PublicKernelSetupCircuitPrivateInputsBuilder { previous_kernel, public_call } } pub fn is_delegate_call(&mut self) -> Self { @@ -145,7 +125,7 @@ mod tests { pub fn get_current_public_data_update_requests(self) -> [PublicDataUpdateRequest; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL] { compute_public_data_update_requests( self.public_call.contract_address, - self.public_call.public_inputs.contract_storage_update_requests.storage, + self.public_call.public_inputs.contract_storage_update_requests.storage ) } @@ -157,10 +137,7 @@ mod tests { self.previous_kernel.push_public_call_request(hash, is_delegate_call); let previous_kernel = self.previous_kernel.to_public_kernel_data(); - let kernel = PublicKernelSetupCircuitPrivateInputs { - previous_kernel, - public_call, - }; + let kernel = PublicKernelSetupCircuitPrivateInputs { previous_kernel, public_call }; kernel.public_kernel_setup() } diff --git a/yarn-project/noir-protocol-circuits/src/crates/public-kernel-lib/src/utils.nr b/yarn-project/noir-protocol-circuits/src/crates/public-kernel-lib/src/utils.nr index 7c4483d46ca..9bcb92fb179 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/public-kernel-lib/src/utils.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/public-kernel-lib/src/utils.nr @@ -1,19 +1,12 @@ use crate::hash::{compute_public_data_tree_index, compute_public_data_tree_value}; use dep::types::{ abis::{ - call_request::CallRequest, - new_contract_data::NewContractData, - public_data_read::PublicDataRead, - public_data_update_request::PublicDataUpdateRequest, - }, + call_request::CallRequest, new_contract_data::NewContractData, public_data_read::PublicDataRead, + public_data_update_request::PublicDataUpdateRequest +}, address::AztecAddress, - contrakt::{ - storage_read::StorageRead, - storage_update_request::StorageUpdateRequest, - }, - utils::{ - arrays::array_eq, - }, + contrakt::{storage_read::StorageRead, storage_update_request::StorageUpdateRequest}, + utils::{arrays::array_eq} }; pub fn compute_public_data_reads( diff --git a/yarn-project/noir-protocol-circuits/src/crates/rollup-base-simulated/src/main.nr b/yarn-project/noir-protocol-circuits/src/crates/rollup-base-simulated/src/main.nr index 67faaa8ec99..970496511a1 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/rollup-base-simulated/src/main.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/rollup-base-simulated/src/main.nr @@ -1,4 +1,4 @@ -use dep::rollup_lib::base::{BaseRollupInputs,BaseOrMergeRollupPublicInputs}; +use dep::rollup_lib::base::{BaseRollupInputs, BaseOrMergeRollupPublicInputs}; unconstrained fn main(inputs: BaseRollupInputs) -> pub BaseOrMergeRollupPublicInputs { inputs.base_rollup_circuit() diff --git a/yarn-project/noir-protocol-circuits/src/crates/rollup-base/src/main.nr b/yarn-project/noir-protocol-circuits/src/crates/rollup-base/src/main.nr index a7b7b5cdd10..04ceaafcbba 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/rollup-base/src/main.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/rollup-base/src/main.nr @@ -1,4 +1,4 @@ -use dep::rollup_lib::base::{BaseRollupInputs,BaseOrMergeRollupPublicInputs}; +use dep::rollup_lib::base::{BaseRollupInputs, BaseOrMergeRollupPublicInputs}; fn main(inputs: BaseRollupInputs) -> pub BaseOrMergeRollupPublicInputs { inputs.base_rollup_circuit() diff --git a/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr b/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr index 9fd46ecdf0d..2bbaeda1a3a 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr @@ -1,7 +1,6 @@ use dep::types::{ - abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot, - constants::NUM_FIELDS_PER_SHA256, - partial_state_reference::PartialStateReference, + abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot, constants::NUM_FIELDS_PER_SHA256, + partial_state_reference::PartialStateReference }; use crate::abis::constant_rollup_data::ConstantRollupData; use dep::types::mocked::AggregationObject; diff --git a/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/abis/constant_rollup_data.nr b/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/abis/constant_rollup_data.nr index 074c5a76566..66de37d34b4 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/abis/constant_rollup_data.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/abis/constant_rollup_data.nr @@ -1,8 +1,5 @@ use dep::std::cmp::Eq; -use dep::types::abis::{ - global_variables::GlobalVariables, - append_only_tree_snapshot::AppendOnlyTreeSnapshot, -}; +use dep::types::abis::{global_variables::GlobalVariables, append_only_tree_snapshot::AppendOnlyTreeSnapshot}; struct ConstantRollupData { // Archive tree snapshot at the very beginning of the entire rollup. diff --git a/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/base/base_rollup_inputs.nr b/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/base/base_rollup_inputs.nr index 0ecf13d2661..5218f9c9b9b 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/base/base_rollup_inputs.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/base/base_rollup_inputs.nr @@ -1,71 +1,35 @@ use crate::{ abis::{ - constant_rollup_data::ConstantRollupData, - base_or_merge_rollup_public_inputs::{ - BaseOrMergeRollupPublicInputs, - BASE_ROLLUP_TYPE, - }, - }, - base::state_diff_hints::StateDiffHints, - components, - merkle_tree::{ - calculate_empty_tree_root, - calculate_subtree, - }, + constant_rollup_data::ConstantRollupData, + base_or_merge_rollup_public_inputs::{BaseOrMergeRollupPublicInputs, BASE_ROLLUP_TYPE} +}, + base::state_diff_hints::StateDiffHints, components, + merkle_tree::{calculate_empty_tree_root, calculate_subtree} }; use dep::types::{ abis::{ - append_only_tree_snapshot::AppendOnlyTreeSnapshot, - membership_witness::{ - ArchiveRootMembershipWitness, - MembershipWitness, - NullifierMembershipWitness, - PublicDataMembershipWitness, - }, - nullifier_leaf_preimage::NullifierLeafPreimage, - public_data_update_request::PublicDataUpdateRequest, - public_data_read::PublicDataRead, - kernel_data::PublicKernelData, - side_effect::{ - SideEffect, - SideEffectLinkedToNoteHash, - }, - }, + append_only_tree_snapshot::AppendOnlyTreeSnapshot, + membership_witness::{ + ArchiveRootMembershipWitness, MembershipWitness, NullifierMembershipWitness, + PublicDataMembershipWitness +}, + nullifier_leaf_preimage::NullifierLeafPreimage, public_data_update_request::PublicDataUpdateRequest, + public_data_read::PublicDataRead, kernel_data::PublicKernelData, + side_effect::{SideEffect, SideEffectLinkedToNoteHash} +}, constants::{ - NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH, - NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH, - CONTRACT_SUBTREE_SIBLING_PATH_LENGTH, - PUBLIC_DATA_TREE_HEIGHT, - MAX_NEW_CONTRACTS_PER_TX, - NOTE_HASH_SUBTREE_HEIGHT, - CONTRACT_SUBTREE_HEIGHT, - NUM_FIELDS_PER_SHA256, - MAX_NEW_COMMITMENTS_PER_TX, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - MAX_PUBLIC_DATA_READS_PER_TX, - MAX_NEW_NULLIFIERS_PER_TX, - NUM_ENCRYPTED_LOGS_HASHES_PER_TX, - MAX_NEW_L2_TO_L1_MSGS_PER_TX, - NUM_UNENCRYPTED_LOGS_HASHES_PER_TX, - NULLIFIER_SUBTREE_HEIGHT, - NULLIFIER_TREE_HEIGHT, - PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH, - PUBLIC_DATA_SUBTREE_HEIGHT, - }, - mocked::{ - AggregationObject, - Proof - }, - partial_state_reference::PartialStateReference, + NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH, NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH, + CONTRACT_SUBTREE_SIBLING_PATH_LENGTH, PUBLIC_DATA_TREE_HEIGHT, MAX_NEW_CONTRACTS_PER_TX, + NOTE_HASH_SUBTREE_HEIGHT, CONTRACT_SUBTREE_HEIGHT, NUM_FIELDS_PER_SHA256, + MAX_NEW_COMMITMENTS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_PUBLIC_DATA_READS_PER_TX, + MAX_NEW_NULLIFIERS_PER_TX, NUM_ENCRYPTED_LOGS_HASHES_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, + NUM_UNENCRYPTED_LOGS_HASHES_PER_TX, NULLIFIER_SUBTREE_HEIGHT, NULLIFIER_TREE_HEIGHT, + PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH, PUBLIC_DATA_SUBTREE_HEIGHT +}, + mocked::{AggregationObject, Proof}, partial_state_reference::PartialStateReference, public_data_tree_leaf::PublicDataTreeLeaf, public_data_tree_leaf_preimage::PublicDataTreeLeafPreimage, - utils::{ - field::{ - full_field_less_than, - full_field_greater_than, - }, - uint256::U256, - }, + utils::{field::{full_field_less_than, full_field_greater_than}, uint256::U256} }; struct BaseRollupInputs { @@ -89,15 +53,19 @@ struct BaseRollupInputs { } impl BaseRollupInputs { - pub fn base_rollup_circuit(self) -> BaseOrMergeRollupPublicInputs { + pub fn base_rollup_circuit(self) -> BaseOrMergeRollupPublicInputs { // Verify the previous kernel proof assert(verify_kernel_proof(self.kernel_data.proof), "kernel proof verification failed"); // Verify the kernel chain_id and versions - assert(self.kernel_data.public_inputs.constants.tx_context.chain_id == - self.constants.global_variables.chain_id, "kernel chain_id does not match the rollup chain_id"); - assert(self.kernel_data.public_inputs.constants.tx_context.version == - self.constants.global_variables.version, "kernel version does not match the rollup version"); + assert( + self.kernel_data.public_inputs.constants.tx_context.chain_id + == self.constants.global_variables.chain_id, "kernel chain_id does not match the rollup chain_id" + ); + assert( + self.kernel_data.public_inputs.constants.tx_context.version + == self.constants.global_variables.version, "kernel version does not match the rollup version" + ); // First we compute the contract tree leaves let contract_leaves = self.calculate_contract_leaves(); @@ -112,7 +80,7 @@ impl BaseRollupInputs { self.state_diff_hints.note_hash_subtree_sibling_path, empty_commitments_subtree_root, commitments_tree_subroot, - NOTE_HASH_SUBTREE_HEIGHT as u8, + NOTE_HASH_SUBTREE_HEIGHT as u8 ); // Insert contract subtrees: @@ -122,7 +90,7 @@ impl BaseRollupInputs { self.state_diff_hints.contract_subtree_sibling_path, empty_contracts_subtree_root, contracts_tree_subroot, - CONTRACT_SUBTREE_HEIGHT as u8, + CONTRACT_SUBTREE_HEIGHT as u8 ); // Insert nullifiers: @@ -133,26 +101,25 @@ impl BaseRollupInputs { // Calculate the overall calldata hash let calldata_hash = BaseRollupInputs::components_compute_kernel_calldata_hash(self.kernel_data); - + // Perform membership checks that the notes provided exist within the historical trees data self.perform_archive_membership_checks(); let aggregation_object = self.aggregate_proofs(); BaseOrMergeRollupPublicInputs { - rollup_type : BASE_ROLLUP_TYPE, - height_in_block_tree : 0, - aggregation_object : aggregation_object, - constants : self.constants, + rollup_type: BASE_ROLLUP_TYPE, + height_in_block_tree: 0, + aggregation_object, + constants: self.constants, start: self.start, end: PartialStateReference { - note_hash_tree : end_note_hash_tree_snapshot, - nullifier_tree : end_nullifier_tree_snapshot, - contract_tree : end_contract_tree_snapshot, - public_data_tree : end_public_data_tree_snapshot, + note_hash_tree: end_note_hash_tree_snapshot, + nullifier_tree: end_nullifier_tree_snapshot, + contract_tree: end_contract_tree_snapshot, + public_data_tree: end_public_data_tree_snapshot }, - - calldata_hash : calldata_hash, + calldata_hash } } @@ -166,20 +133,19 @@ impl BaseRollupInputs { // When there is no contract deployment, we should insert a zero leaf into the tree and ignore the // member-ship check. This is to ensure that we don't hit "already deployed" errors when we are not // deploying contracts. e.g., when we are only calling functions on existing contracts. - let to_push = if leaf_preimage.contract_address.to_field() == 0 { + let to_push = if leaf_preimage.contract_address.to_field() == 0 { 0 - } else { + } else { leaf_preimage.hash() }; contract_leaves[i] = to_push; } - contract_leaves } // Cpp code says calculate_contract_subtree, so I'm leaving it as is for now - fn calculate_contract_subtree_root(self, leaves : [Field; MAX_NEW_CONTRACTS_PER_TX]) -> Field { + fn calculate_contract_subtree_root(self, leaves: [Field; MAX_NEW_CONTRACTS_PER_TX]) -> Field { assert_eq(leaves.len(), 1); leaves[0] } @@ -198,12 +164,14 @@ impl BaseRollupInputs { self.state_diff_hints.sorted_nullifier_indexes, self.state_diff_hints.nullifier_subtree_sibling_path, self.state_diff_hints.nullifier_predecessor_preimages, - self.state_diff_hints.nullifier_predecessor_membership_witnesses.map(|witness: NullifierMembershipWitness| { + self.state_diff_hints.nullifier_predecessor_membership_witnesses.map( + |witness: NullifierMembershipWitness| { MembershipWitness { leaf_index: witness.leaf_index, sibling_path: witness.sibling_path, } - }), + } + ), |a: Field, b: Field| {a == b}, // Nullifier equals |nullifier: Field| {nullifier == 0}, // Nullifier is zero |leaf: NullifierLeafPreimage| {leaf.hash()}, // Hash leaf @@ -231,7 +199,7 @@ impl BaseRollupInputs { } }, [0; NULLIFIER_SUBTREE_HEIGHT], - [0; NULLIFIER_TREE_HEIGHT], + [0; NULLIFIER_TREE_HEIGHT] ) } @@ -244,7 +212,6 @@ impl BaseRollupInputs { // Blocks all interesting usecases that read and write to the same public state in the same tx. // https://aztecprotocol.slack.com/archives/C02M7VC7TN0/p1695809629015719?thread_ts=1695653252.007339&cid=C02M7VC7TN0 - // Process public data reads and public data update requests for left input // validate_public_data_reads( // self.start_public_data_tree_root, @@ -254,17 +221,19 @@ impl BaseRollupInputs { let end_public_data_tree_snapshot = insert_public_data_update_requests( self.start.public_data_tree, - self.kernel_data.public_inputs.end.public_data_update_requests.map(|request: PublicDataUpdateRequest| { + self.kernel_data.public_inputs.end.public_data_update_requests.map( + |request: PublicDataUpdateRequest| { PublicDataTreeLeaf { slot: request.leaf_slot, value: request.new_value, } - }), + } + ), self.sorted_public_data_writes, self.sorted_public_data_writes_indexes, self.low_public_data_writes_preimages, self.low_public_data_writes_witnesses, - self.state_diff_hints.public_data_sibling_path, + self.state_diff_hints.public_data_sibling_path ); end_public_data_tree_snapshot @@ -273,7 +242,7 @@ impl BaseRollupInputs { // Computes the calldata hash for a base rollup // TODO(Kev): move this into components module // TODO(Alvaro): This is too slow for brillig without the array optimization - fn components_compute_kernel_calldata_hash(kernel_data : PublicKernelData) -> [Field; NUM_FIELDS_PER_SHA256]{ + fn components_compute_kernel_calldata_hash(kernel_data: PublicKernelData) -> [Field; NUM_FIELDS_PER_SHA256] { // Compute calldata hashes // Consist of // MAX_NEW_COMMITMENTS_PER_TX fields for commitments @@ -338,11 +307,10 @@ impl BaseRollupInputs { for j in 0..NUM_FIELDS_PER_SHA256 { calldata_hash_inputs[offset + j] = unencryptedLogsHash[j]; } - + offset += NUM_UNENCRYPTED_LOGS_HASHES_PER_TX * NUM_FIELDS_PER_SHA256; assert_eq(offset, CALLDATA_HASH_INPUT_SIZE); // Sanity check - let mut hash_input_flattened = [0; CALL_DATA_HASH_FULL_FIELDS * 32 + CALL_DATA_HASH_LOG_FIELDS * 16]; for offset in 0..CALL_DATA_HASH_FULL_FIELDS { let input_as_bytes = calldata_hash_inputs[offset].to_be_bytes(32); @@ -572,76 +540,39 @@ fn test_u256_greater_than() { mod tests { use crate::{ abis::{ - constant_rollup_data::ConstantRollupData, - base_or_merge_rollup_public_inputs::BaseOrMergeRollupPublicInputs, - }, + constant_rollup_data::ConstantRollupData, + base_or_merge_rollup_public_inputs::BaseOrMergeRollupPublicInputs + }, base::{ - state_diff_hints::StateDiffHints, - base_rollup_inputs::{ - CALL_DATA_HASH_FULL_FIELDS, - CALL_DATA_HASH_LOG_FIELDS, - BaseRollupInputs, - }, - }, - merkle_tree::{ - calculate_empty_tree_root, - calculate_subtree, - }, - components, - tests::merkle_tree_utils::{ - NonEmptyMerkleTree, - compute_zero_hashes, - }, + state_diff_hints::StateDiffHints, + base_rollup_inputs::{CALL_DATA_HASH_FULL_FIELDS, CALL_DATA_HASH_LOG_FIELDS, BaseRollupInputs} + }, + merkle_tree::{calculate_empty_tree_root, calculate_subtree}, components, + tests::merkle_tree_utils::{NonEmptyMerkleTree, compute_zero_hashes} }; use dep::types::{ abis::{ - append_only_tree_snapshot::AppendOnlyTreeSnapshot, - membership_witness::{ - ArchiveRootMembershipWitness, - NullifierMembershipWitness, - PublicDataMembershipWitness, - }, - new_contract_data::NewContractData, - nullifier_leaf_preimage::NullifierLeafPreimage, - public_data_read::PublicDataRead, - public_data_update_request::PublicDataUpdateRequest, - kernel_data::PublicKernelData, - side_effect::SideEffect, - }, - address::{ - AztecAddress, - EthAddress, - }, + append_only_tree_snapshot::AppendOnlyTreeSnapshot, + membership_witness::{ArchiveRootMembershipWitness, NullifierMembershipWitness, PublicDataMembershipWitness}, + new_contract_data::NewContractData, nullifier_leaf_preimage::NullifierLeafPreimage, + public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, + kernel_data::PublicKernelData, side_effect::SideEffect + }, + address::{AztecAddress, EthAddress}, constants::{ - CONTRACT_SUBTREE_SIBLING_PATH_LENGTH, - CONTRACT_TREE_HEIGHT, - CONTRACT_SUBTREE_HEIGHT, - ARCHIVE_HEIGHT, - MAX_PUBLIC_DATA_READS_PER_TX, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - MAX_NEW_COMMITMENTS_PER_TX, - MAX_NEW_NULLIFIERS_PER_TX, - MAX_NEW_CONTRACTS_PER_TX, - NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH, - NOTE_HASH_TREE_HEIGHT, - NOTE_HASH_SUBTREE_HEIGHT, - NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH, - NULLIFIER_TREE_HEIGHT, - NULLIFIER_SUBTREE_HEIGHT, - PUBLIC_DATA_TREE_HEIGHT, - PUBLIC_DATA_SUBTREE_HEIGHT, - PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH, - NUM_FIELDS_PER_SHA256, - }, - contract_class::ContractClassId, - partial_state_reference::PartialStateReference, + CONTRACT_SUBTREE_SIBLING_PATH_LENGTH, CONTRACT_TREE_HEIGHT, CONTRACT_SUBTREE_HEIGHT, + ARCHIVE_HEIGHT, MAX_PUBLIC_DATA_READS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, + MAX_NEW_COMMITMENTS_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_NEW_CONTRACTS_PER_TX, + NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH, NOTE_HASH_TREE_HEIGHT, NOTE_HASH_SUBTREE_HEIGHT, + NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH, NULLIFIER_TREE_HEIGHT, NULLIFIER_SUBTREE_HEIGHT, + PUBLIC_DATA_TREE_HEIGHT, PUBLIC_DATA_SUBTREE_HEIGHT, PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH, + NUM_FIELDS_PER_SHA256 + }, + contract_class::ContractClassId, partial_state_reference::PartialStateReference, public_data_tree_leaf::PublicDataTreeLeaf, public_data_tree_leaf_preimage::PublicDataTreeLeafPreimage, tests::kernel_data_builder::PreviousKernelDataBuilder, - utils::{ - field::full_field_less_than, - uint256::U256, - } + utils::{field::full_field_less_than, uint256::U256} }; use dep::std::option::Option; @@ -659,7 +590,7 @@ mod tests { global MAX_PUBLIC_DATA_WRITES_PER_TEST = 2; global MAX_PUBLIC_DATA_READS_PER_TEST = 2; - fn sort_high_to_low(values: [T; N], is_less_than: fn(T, T) -> bool) -> [SortedTuple; N] { + fn sort_high_to_low(values: [T; N], is_less_than: fn(T, T) -> bool) -> [SortedTuple; N] where T: Eq { let mut sorted_tuples = [SortedTuple { value: values[0], original_index: 0 }; N]; for i in 0..N { @@ -669,7 +600,7 @@ mod tests { }; } - sorted_tuples.sort_via(|a: SortedTuple, b: SortedTuple| is_less_than(b.value, a.value)) + sorted_tuples.sort_via(|a: SortedTuple, b: SortedTuple| (b.value == a.value) | is_less_than(b.value, a.value)) } fn update_public_data_tree( @@ -779,13 +710,16 @@ mod tests { let mut builder = PreviousKernelDataBuilder::new(); let _nullifier = builder.end.new_nullifiers.pop(); inputs.kernel_data = builder.is_public(); - + inputs.pre_existing_blocks[0] = inputs.kernel_data.historical_header.hash(); inputs } - fn extract_subtree_sibling_path(path: [Field; FULL_HEIGHT], mut sibling_path: [Field; SIBLING_PATH_LENGTH]) -> [Field; SIBLING_PATH_LENGTH] { + fn extract_subtree_sibling_path( + path: [Field; FULL_HEIGHT], + mut sibling_path: [Field; SIBLING_PATH_LENGTH] + ) -> [Field; SIBLING_PATH_LENGTH] { let subtree_height = FULL_HEIGHT - SIBLING_PATH_LENGTH; for i in subtree_height..FULL_HEIGHT { sibling_path[i - subtree_height] = path[i]; @@ -794,20 +728,18 @@ mod tests { } fn update_nullifier_tree_with_new_leaves( - mut self, - nullifier_tree: &mut NonEmptyMerkleTree, - kernel_data: &mut PublicKernelData, + mut self, + nullifier_tree: &mut NonEmptyMerkleTree, + kernel_data: &mut PublicKernelData, start_nullifier_tree_snapshot: AppendOnlyTreeSnapshot - ) -> ( - [NullifierLeafPreimage; MAX_NEW_NULLIFIERS_PER_TX], - [NullifierMembershipWitness; MAX_NEW_NULLIFIERS_PER_TX], - [Field; MAX_NEW_NULLIFIERS_PER_TX], - [u32; MAX_NEW_NULLIFIERS_PER_TX], - ) { + ) -> ([NullifierLeafPreimage; MAX_NEW_NULLIFIERS_PER_TX], [NullifierMembershipWitness; MAX_NEW_NULLIFIERS_PER_TX], [Field; MAX_NEW_NULLIFIERS_PER_TX], [u32; MAX_NEW_NULLIFIERS_PER_TX]) { let mut nullifier_predecessor_preimages: [NullifierLeafPreimage; MAX_NEW_NULLIFIERS_PER_TX] = dep::std::unsafe::zeroed(); let mut low_nullifier_membership_witness: [NullifierMembershipWitness; MAX_NEW_NULLIFIERS_PER_TX] = dep::std::unsafe::zeroed(); - let sorted_new_nullifier_tuples = sort_high_to_low(self.new_nullifiers.storage.map(|insertion: NullifierInsertion| insertion.value), full_field_less_than); + let sorted_new_nullifier_tuples = sort_high_to_low( + self.new_nullifiers.storage.map(|insertion: NullifierInsertion| insertion.value), + full_field_less_than + ); let mut sorted_nullifiers = [0; MAX_NEW_NULLIFIERS_PER_TX]; let mut sorted_nullifiers_indexes = [0; MAX_NEW_NULLIFIERS_PER_TX]; @@ -849,50 +781,73 @@ mod tests { } } - (nullifier_predecessor_preimages, low_nullifier_membership_witness, sorted_nullifiers, sorted_nullifiers_indexes) + ( + nullifier_predecessor_preimages, low_nullifier_membership_witness, sorted_nullifiers, sorted_nullifiers_indexes + ) } fn build_inputs(mut self) -> BaseRollupInputs { let mut kernel_data = self.kernel_data.to_public_kernel_data(); - let start_note_hash_tree = NonEmptyMerkleTree::new(self.pre_existing_notes, [0; NOTE_HASH_TREE_HEIGHT], [0; NOTE_HASH_TREE_HEIGHT - NOTE_HASH_SUBTREE_HEIGHT], [0; NOTE_HASH_SUBTREE_HEIGHT]); + let start_note_hash_tree = NonEmptyMerkleTree::new( + self.pre_existing_notes, + [0; NOTE_HASH_TREE_HEIGHT], + [0; NOTE_HASH_TREE_HEIGHT - NOTE_HASH_SUBTREE_HEIGHT], + [0; NOTE_HASH_SUBTREE_HEIGHT] + ); let start_note_hash_tree_snapshot = AppendOnlyTreeSnapshot { root: start_note_hash_tree.get_root(), - next_available_leaf_index: start_note_hash_tree.get_next_available_index() as u32, + next_available_leaf_index: start_note_hash_tree.get_next_available_index() as u32 }; - let note_hash_subtree_sibling_path = BaseRollupInputsBuilder::extract_subtree_sibling_path(start_note_hash_tree.get_sibling_path(self.pre_existing_notes.len()), [0; NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH]); + let note_hash_subtree_sibling_path = BaseRollupInputsBuilder::extract_subtree_sibling_path( + start_note_hash_tree.get_sibling_path(self.pre_existing_notes.len()), + [0; NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH] + ); let mut start_nullifier_tree = NonEmptyMerkleTree::new( - self.pre_existing_nullifiers.map(|preimage: NullifierLeafPreimage| preimage.hash()), - [0; NULLIFIER_TREE_HEIGHT], - [0; NULLIFIER_TREE_HEIGHT - NULLIFIER_SUBTREE_HEIGHT], + self.pre_existing_nullifiers.map(|preimage: NullifierLeafPreimage| preimage.hash()), + [0; NULLIFIER_TREE_HEIGHT], + [0; NULLIFIER_TREE_HEIGHT - NULLIFIER_SUBTREE_HEIGHT], [0; NULLIFIER_SUBTREE_HEIGHT] ); let start_nullifier_tree_snapshot = AppendOnlyTreeSnapshot { root: start_nullifier_tree.get_root(), - next_available_leaf_index: start_nullifier_tree.get_next_available_index() as u32, + next_available_leaf_index: start_nullifier_tree.get_next_available_index() as u32 }; - let start_contract_tree = NonEmptyMerkleTree::new(self.pre_existing_contracts, [0; CONTRACT_TREE_HEIGHT], [0; CONTRACT_TREE_HEIGHT - 1], [0; 1]); + let start_contract_tree = NonEmptyMerkleTree::new( + self.pre_existing_contracts, + [0; CONTRACT_TREE_HEIGHT], + [0; CONTRACT_TREE_HEIGHT - 1], + [0; 1] + ); let start_contract_tree_snapshot = AppendOnlyTreeSnapshot { root: start_contract_tree.get_root(), - next_available_leaf_index: start_contract_tree.get_next_available_index() as u32, + next_available_leaf_index: start_contract_tree.get_next_available_index() as u32 }; - let contract_subtree_sibling_path = BaseRollupInputsBuilder::extract_subtree_sibling_path(start_contract_tree.get_sibling_path(self.pre_existing_contracts.len()), [0; CONTRACT_SUBTREE_SIBLING_PATH_LENGTH]); + let contract_subtree_sibling_path = BaseRollupInputsBuilder::extract_subtree_sibling_path( + start_contract_tree.get_sibling_path(self.pre_existing_contracts.len()), + [0; CONTRACT_SUBTREE_SIBLING_PATH_LENGTH] + ); let mut start_public_data_tree = NonEmptyMerkleTree::new( self.pre_existing_public_data.map(|preimage: PublicDataTreeLeafPreimage| preimage.hash()), - [0; PUBLIC_DATA_TREE_HEIGHT], - [0; PUBLIC_DATA_TREE_HEIGHT - PUBLIC_DATA_SUBTREE_HEIGHT], + [0; PUBLIC_DATA_TREE_HEIGHT], + [0; PUBLIC_DATA_TREE_HEIGHT - PUBLIC_DATA_SUBTREE_HEIGHT], [0; PUBLIC_DATA_SUBTREE_HEIGHT] ); let start_public_data_tree_snapshot = AppendOnlyTreeSnapshot { root: start_public_data_tree.get_root(), - next_available_leaf_index: start_public_data_tree.get_next_available_index() as u32, + next_available_leaf_index: start_public_data_tree.get_next_available_index() as u32 }; - let start_archive = NonEmptyMerkleTree::new(self.pre_existing_blocks, [0; ARCHIVE_HEIGHT], [0; ARCHIVE_HEIGHT - 1], [0; 1]); + let start_archive = NonEmptyMerkleTree::new( + self.pre_existing_blocks, + [0; ARCHIVE_HEIGHT], + [0; ARCHIVE_HEIGHT - 1], + [0; 1] + ); self.constants.last_archive = AppendOnlyTreeSnapshot { root: start_archive.get_root(), next_available_leaf_index: start_archive.get_next_available_index() as u32, @@ -903,9 +858,16 @@ mod tests { nullifier_predecessor_membership_witnesses, sorted_nullifiers, sorted_nullifier_indexes - ) = self.update_nullifier_tree_with_new_leaves(&mut start_nullifier_tree, &mut kernel_data, start_nullifier_tree_snapshot); + ) = self.update_nullifier_tree_with_new_leaves( + &mut start_nullifier_tree, + &mut kernel_data, + start_nullifier_tree_snapshot + ); - let nullifier_subtree_sibling_path = BaseRollupInputsBuilder::extract_subtree_sibling_path(start_nullifier_tree.get_sibling_path(self.pre_existing_nullifiers.len()), [0; NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH]); + let nullifier_subtree_sibling_path = BaseRollupInputsBuilder::extract_subtree_sibling_path( + start_nullifier_tree.get_sibling_path(self.pre_existing_nullifiers.len()), + [0; NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH] + ); let ( public_data_sibling_path, @@ -917,8 +879,8 @@ mod tests { public_data_reads_witnesses, _new_subtree ) = update_public_data_tree( - &mut start_public_data_tree, - &mut kernel_data, + &mut start_public_data_tree, + &mut kernel_data, start_public_data_tree_snapshot, self.public_data_writes, self.pre_existing_public_data @@ -939,28 +901,21 @@ mod tests { note_hash_subtree_sibling_path, nullifier_subtree_sibling_path, contract_subtree_sibling_path, - public_data_sibling_path, + public_data_sibling_path }; BaseRollupInputs { kernel_data, start, state_diff_hints, - sorted_public_data_writes, sorted_public_data_writes_indexes, low_public_data_writes_preimages, low_public_data_writes_witnesses, - public_data_reads_preimages, public_data_reads_witnesses, - - archive_root_membership_witness: ArchiveRootMembershipWitness { - leaf_index: 0, - sibling_path: start_archive.get_sibling_path(0) - }, - - constants: self.constants, + archive_root_membership_witness: ArchiveRootMembershipWitness { leaf_index: 0, sibling_path: start_archive.get_sibling_path(0) }, + constants: self.constants } } diff --git a/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/base/state_diff_hints.nr b/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/base/state_diff_hints.nr index 9aeb4bdfceb..bfdae2ecf5d 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/base/state_diff_hints.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/base/state_diff_hints.nr @@ -1,15 +1,10 @@ use dep::types::{ - abis::{ - membership_witness::NullifierMembershipWitness, - nullifier_leaf_preimage::NullifierLeafPreimage, - }, + abis::{membership_witness::NullifierMembershipWitness, nullifier_leaf_preimage::NullifierLeafPreimage}, constants::{ - MAX_NEW_NULLIFIERS_PER_TX, - NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH, - NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH, - CONTRACT_SUBTREE_SIBLING_PATH_LENGTH, - PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH, - }, + MAX_NEW_NULLIFIERS_PER_TX, NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH, + NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH, CONTRACT_SUBTREE_SIBLING_PATH_LENGTH, + PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH +} }; struct StateDiffHints { diff --git a/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/indexed_tree.nr b/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/indexed_tree.nr index a25c070a625..47713a81496 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/indexed_tree.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/indexed_tree.nr @@ -1,9 +1,6 @@ use crate::merkle_tree::{calculate_subtree, calculate_empty_tree_root}; -use dep::types::abis::{ - append_only_tree_snapshot::AppendOnlyTreeSnapshot, - membership_witness::MembershipWitness, -}; +use dep::types::abis::{append_only_tree_snapshot::AppendOnlyTreeSnapshot, membership_witness::MembershipWitness}; fn check_permutation( original_array: [T; N], diff --git a/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/merge/merge_rollup_inputs.nr b/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/merge/merge_rollup_inputs.nr index e3766db20cd..d386f19bc6d 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/merge/merge_rollup_inputs.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/merge/merge_rollup_inputs.nr @@ -9,7 +9,6 @@ struct MergeRollupInputs{ impl MergeRollupInputs { pub fn merge_rollup_circuit(self) -> BaseOrMergeRollupPublicInputs { - // TODO(Lasse): Verify the previous rollup proofs // TODO(Lasse): Check both previous rollup vks (in previous_rollup_data) against the permitted set of kernel vks. // we don't have a set of permitted kernel vks yet. @@ -29,13 +28,13 @@ impl MergeRollupInputs { let new_calldata_hash = components::compute_calldata_hash(self.previous_rollup_data); let public_inputs = BaseOrMergeRollupPublicInputs { - rollup_type : MERGE_ROLLUP_TYPE, - height_in_block_tree : current_height + 1, - aggregation_object : aggregation_object, - constants : left.constants, - start : left.start, - end : right.end, - calldata_hash : new_calldata_hash, + rollup_type: MERGE_ROLLUP_TYPE, + height_in_block_tree: current_height + 1, + aggregation_object, + constants: left.constants, + start: left.start, + end: right.end, + calldata_hash: new_calldata_hash }; public_inputs @@ -45,7 +44,7 @@ impl MergeRollupInputs { mod tests { use crate::{ merge::merge_rollup_inputs::MergeRollupInputs, - tests::merge_rollup_inputs::default_merge_rollup_inputs, + tests::merge_rollup_inputs::default_merge_rollup_inputs }; use dep::types::hash::accumulate_sha256; diff --git a/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/merkle_tree.nr b/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/merkle_tree.nr index 406a11059c8..70f4eec2d04 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/merkle_tree.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/merkle_tree.nr @@ -6,11 +6,11 @@ struct MerkleTree { impl MerkleTree { pub fn new(leaves: [Field; N]) -> Self { let mut nodes = [0; N]; - + // We need one less node than leaves, but we cannot have computed array lengths let total_nodes = N - 1; - let half_size = N/2; - + let half_size = N / 2; + // hash base layer for i in 0..half_size { nodes[i] = dep::std::hash::pedersen_hash([leaves[2*i], leaves[2*i+1]]); @@ -21,14 +21,11 @@ impl MerkleTree { nodes[half_size+i] = dep::std::hash::pedersen_hash([nodes[2*i], nodes[2*i+1]]); } - MerkleTree { - leaves, - nodes, - } + MerkleTree { leaves, nodes } } fn get_root(self) -> Field { - self.nodes[N-2] + self.nodes[N - 2] } } diff --git a/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/root.nr b/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/root.nr index cfd8ad62d4e..86f2d224a88 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/root.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/root.nr @@ -4,21 +4,14 @@ mod root_rollup_public_inputs; use root_rollup_public_inputs::RootRollupPublicInputs; use dep::types::{ abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot, - constants::{ - NUM_FIELDS_PER_SHA256, - NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, - L1_TO_L2_MSG_SUBTREE_HEIGHT, - }, - header::Header, - state_reference::StateReference, - utils::uint256::U256, + constants::{NUM_FIELDS_PER_SHA256, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, L1_TO_L2_MSG_SUBTREE_HEIGHT}, + header::Header, state_reference::StateReference, utils::uint256::U256 }; use crate::components; use crate::merkle_tree::{calculate_subtree, calculate_empty_tree_root}; impl RootRollupInputs { pub fn root_rollup_circuit(self) -> RootRollupPublicInputs { - let left = self.previous_rollup_data[0].base_or_merge_rollup_public_inputs; let right = self.previous_rollup_data[1].base_or_merge_rollup_public_inputs; @@ -41,19 +34,16 @@ impl RootRollupInputs { l1_to_l2_subtree_root, // TODO(Kev): For now we can add a test that this fits inside of // a u8. - L1_TO_L2_MSG_SUBTREE_HEIGHT as u8 + L1_TO_L2_MSG_SUBTREE_HEIGHT as u8 ); - let state = StateReference { - l1_to_l2_message_tree : new_l1_to_l2_message_tree_snapshot, - partial: right.end, - }; + let state = StateReference { l1_to_l2_message_tree: new_l1_to_l2_message_tree_snapshot, partial: right.end }; let header = Header { last_archive: left.constants.last_archive, body_hash: components::compute_calldata_hash(self.previous_rollup_data), state, - global_variables : left.constants.global_variables + global_variables: left.constants.global_variables }; // Build the block hash for this by hashing the header and then insert the new leaf to archive tree. @@ -68,12 +58,12 @@ impl RootRollupInputs { 0 ); - RootRollupPublicInputs{ + RootRollupPublicInputs { aggregation_object, archive, header, // TODO(#3938): Nuke this once body hash/calldata hash is updated - l1_to_l2_messages_hash : compute_messages_hash(self.new_l1_to_l2_messages), + l1_to_l2_messages_hash: compute_messages_hash(self.new_l1_to_l2_messages) } } } @@ -126,11 +116,8 @@ fn test_message_input_flattened_length() { mod tests { use crate::{ - root::{ - root_rollup_inputs::RootRollupInputs, - NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP_NUM_BYTES, - }, - tests::root_rollup_inputs::default_root_rollup_inputs, + root::{root_rollup_inputs::RootRollupInputs, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP_NUM_BYTES}, + tests::root_rollup_inputs::default_root_rollup_inputs }; use dep::types::utils::uint256::U256; use dep::types::hash::accumulate_sha256; diff --git a/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/root/root_rollup_inputs.nr b/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/root/root_rollup_inputs.nr index 37244315b76..bb569c35e1b 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/root/root_rollup_inputs.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/root/root_rollup_inputs.nr @@ -1,15 +1,8 @@ use crate::abis::previous_rollup_data::PreviousRollupData; use crate::abis::constant_rollup_data::ConstantRollupData; use dep::types::{ - abis::{ - append_only_tree_snapshot::AppendOnlyTreeSnapshot, - nullifier_leaf_preimage::NullifierLeafPreimage, - }, - constants::{ - NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, - L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH, - ARCHIVE_HEIGHT - }, + abis::{append_only_tree_snapshot::AppendOnlyTreeSnapshot, nullifier_leaf_preimage::NullifierLeafPreimage}, + constants::{NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH, ARCHIVE_HEIGHT} }; struct RootRollupInputs { diff --git a/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/root/root_rollup_public_inputs.nr b/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/root/root_rollup_public_inputs.nr index a159a8e530f..34a8763e739 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/root/root_rollup_public_inputs.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/root/root_rollup_public_inputs.nr @@ -1,12 +1,6 @@ use dep::types::{ - abis::{ - append_only_tree_snapshot::AppendOnlyTreeSnapshot, - global_variables::GlobalVariables, - }, - constants::{ - NUM_FIELDS_PER_SHA256 - }, - header::Header, + abis::{append_only_tree_snapshot::AppendOnlyTreeSnapshot, global_variables::GlobalVariables}, + constants::{NUM_FIELDS_PER_SHA256}, header::Header }; use dep::types::mocked::AggregationObject; diff --git a/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/tests/root_rollup_inputs.nr b/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/tests/root_rollup_inputs.nr index b74a3635e23..933e35f118e 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/tests/root_rollup_inputs.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/tests/root_rollup_inputs.nr @@ -1,16 +1,10 @@ -use crate::{ - root::{ - root_rollup_inputs::RootRollupInputs, - }, -}; +use crate::{root::{root_rollup_inputs::RootRollupInputs}}; use dep::types::{ abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot, constants::{ - L1_TO_L2_MSG_TREE_HEIGHT, - L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH, - L1_TO_L2_MSG_SUBTREE_HEIGHT, - ARCHIVE_HEIGHT, - }, + L1_TO_L2_MSG_TREE_HEIGHT, L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH, L1_TO_L2_MSG_SUBTREE_HEIGHT, + ARCHIVE_HEIGHT +} }; use crate::tests::previous_rollup_data::default_previous_rollup_data; use crate::tests::merkle_tree_utils::compute_zero_hashes; diff --git a/yarn-project/noir-protocol-circuits/src/crates/rollup-merge/src/main.nr b/yarn-project/noir-protocol-circuits/src/crates/rollup-merge/src/main.nr index fafe08c9296..fb38eb0da23 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/rollup-merge/src/main.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/rollup-merge/src/main.nr @@ -1,4 +1,4 @@ -use dep::rollup_lib::merge::{MergeRollupInputs,BaseOrMergeRollupPublicInputs}; +use dep::rollup_lib::merge::{MergeRollupInputs, BaseOrMergeRollupPublicInputs}; fn main(inputs: MergeRollupInputs) -> pub BaseOrMergeRollupPublicInputs { inputs.merge_rollup_circuit() diff --git a/yarn-project/noir-protocol-circuits/src/crates/rollup-root/src/main.nr b/yarn-project/noir-protocol-circuits/src/crates/rollup-root/src/main.nr index 757a2885a93..23170287af8 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/rollup-root/src/main.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/rollup-root/src/main.nr @@ -1,4 +1,4 @@ -use dep::rollup_lib::root::{RootRollupInputs,RootRollupPublicInputs}; +use dep::rollup_lib::root::{RootRollupInputs, RootRollupPublicInputs}; fn main(inputs: RootRollupInputs) -> pub RootRollupPublicInputs { inputs.root_rollup_circuit() diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/append_only_tree_snapshot.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/append_only_tree_snapshot.nr index 7ff7b69503e..138760030c7 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/append_only_tree_snapshot.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/append_only_tree_snapshot.nr @@ -13,17 +13,11 @@ impl AppendOnlyTreeSnapshot { } pub fn deserialize(serialized: [Field; APPEND_ONLY_TREE_SNAPSHOT_LENGTH]) -> AppendOnlyTreeSnapshot { - AppendOnlyTreeSnapshot { - root : serialized[0], - next_available_leaf_index : serialized[1] as u32 - } + AppendOnlyTreeSnapshot { root: serialized[0], next_available_leaf_index: serialized[1] as u32 } } pub fn zero() -> Self { - Self { - root: 0, - next_available_leaf_index: 0, - } + Self { root: 0, next_available_leaf_index: 0 } } } diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/call_context.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/call_context.nr index e6c3189b487..9f1cd659fef 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/call_context.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/call_context.nr @@ -1,16 +1,7 @@ use crate::{ - abis::function_selector::FunctionSelector, - address::{EthAddress,AztecAddress}, - constants::{ - CALL_CONTEXT_LENGTH, - GENERATOR_INDEX__CALL_CONTEXT, - }, - hash::pedersen_hash, - traits::{ - Deserialize, - Hash, - Serialize, - }, + abis::function_selector::FunctionSelector, address::{EthAddress, AztecAddress}, + constants::{CALL_CONTEXT_LENGTH, GENERATOR_INDEX__CALL_CONTEXT}, hash::pedersen_hash, + traits::{Deserialize, Hash, Serialize} }; // docs:start:call-context diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/combined_accumulated_data.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/combined_accumulated_data.nr index b2bede3ca32..e60d27afdc8 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/combined_accumulated_data.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/combined_accumulated_data.nr @@ -1,29 +1,18 @@ use crate::{ abis::{ - call_request::CallRequest, - new_contract_data::NewContractData, - nullifier_key_validation_request::NullifierKeyValidationRequestContext, - public_data_read::PublicDataRead, - public_data_update_request::PublicDataUpdateRequest, - side_effect::{SideEffect, SideEffectLinkedToNoteHash}, - } + call_request::CallRequest, new_contract_data::NewContractData, + nullifier_key_validation_request::NullifierKeyValidationRequestContext, + public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, + side_effect::{SideEffect, SideEffectLinkedToNoteHash} +} }; use crate::constants::{ - MAX_READ_REQUESTS_PER_TX, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, - MAX_NEW_COMMITMENTS_PER_TX, - MAX_NEW_NULLIFIERS_PER_TX, - MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, - MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, - MAX_NEW_L2_TO_L1_MSGS_PER_TX, - MAX_NEW_CONTRACTS_PER_TX, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - MAX_PUBLIC_DATA_READS_PER_TX, - NUM_FIELDS_PER_SHA256, - - MAX_NEW_COMMITMENTS_PER_TX_META, - MAX_NEW_NULLIFIERS_PER_TX_META, - MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX_META, + MAX_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_NEW_COMMITMENTS_PER_TX, + MAX_NEW_NULLIFIERS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, + MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, MAX_NEW_CONTRACTS_PER_TX, + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_PUBLIC_DATA_READS_PER_TX, NUM_FIELDS_PER_SHA256, + MAX_NEW_COMMITMENTS_PER_TX_META, MAX_NEW_NULLIFIERS_PER_TX_META, + MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX_META }; struct CombinedAccumulatedData { @@ -106,53 +95,44 @@ struct CombinedAccumulatedDataBuilder { impl CombinedAccumulatedDataBuilder { pub fn finish(self) -> CombinedAccumulatedData { CombinedAccumulatedData { - read_requests: self.read_requests.storage, nullifier_key_validation_requests: self.nullifier_key_validation_requests.storage, - new_commitments: self.new_commitments.storage, new_nullifiers: self.new_nullifiers.storage, - private_call_stack: self.private_call_stack.storage, public_call_stack: self.public_call_stack.storage, new_l2_to_l1_msgs: self.new_l2_to_l1_msgs.storage, - encrypted_logs_hash: self.encrypted_logs_hash, unencrypted_logs_hash: self.unencrypted_logs_hash, - encrypted_log_preimages_length: self.encrypted_log_preimages_length, unencrypted_log_preimages_length: self.unencrypted_log_preimages_length, - new_contracts: self.new_contracts.storage, - public_data_update_requests: self.public_data_update_requests.storage, - - public_data_reads: self.public_data_reads.storage, + public_data_reads: self.public_data_reads.storage } } pub fn to_final(self) -> FinalAccumulatedData { assert_eq(self.read_requests.len, 0, "Final accumulated data: read requests not empty"); - assert_eq(self.nullifier_key_validation_requests.len, 0, "Final accumulated data: nullifier key validation requests not empty"); - assert_eq(self.public_data_update_requests.len, 0, "Final accumulated data: public data update requests not empty"); + assert_eq( + self.nullifier_key_validation_requests.len, 0, "Final accumulated data: nullifier key validation requests not empty" + ); + assert_eq( + self.public_data_update_requests.len, 0, "Final accumulated data: public data update requests not empty" + ); assert_eq(self.public_data_reads.len, 0, "Final accumulated data: public data reads not empty"); FinalAccumulatedData { - new_commitments: self.new_commitments.storage, new_nullifiers: self.new_nullifiers.storage, - private_call_stack: self.private_call_stack.storage, public_call_stack: self.public_call_stack.storage, new_l2_to_l1_msgs: self.new_l2_to_l1_msgs.storage, - encrypted_logs_hash: self.encrypted_logs_hash, unencrypted_logs_hash: self.unencrypted_logs_hash, - encrypted_log_preimages_length: self.encrypted_log_preimages_length, unencrypted_log_preimages_length: self.unencrypted_log_preimages_length, - - new_contracts: self.new_contracts.storage, + new_contracts: self.new_contracts.storage } } } diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/function_data.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/function_data.nr index 29c193a47dc..ac042d74b31 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/function_data.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/function_data.nr @@ -1,15 +1,7 @@ use crate::{ abis::function_selector::FunctionSelector, - constants::{ - GENERATOR_INDEX__FUNCTION_DATA, - FUNCTION_DATA_LENGTH, - }, - hash::pedersen_hash, - traits::{ - Serialize, - Hash, - Deserialize, - }, + constants::{GENERATOR_INDEX__FUNCTION_DATA, FUNCTION_DATA_LENGTH}, hash::pedersen_hash, + traits::{Serialize, Hash, Deserialize} }; struct FunctionData { diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/function_selector.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/function_selector.nr index 93538f5248e..82ab480da19 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/function_selector.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/function_selector.nr @@ -35,15 +35,11 @@ impl FunctionSelector { } pub fn from_u32(value: u32) -> Self { - Self { - inner : value, - } + Self { inner: value } } - pub fn from_field(value : Field) -> Self { - Self { - inner : value as u32, - } + pub fn from_field(value: Field) -> Self { + Self { inner: value as u32 } } pub fn from_signature(signature: str) -> Self { diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/global_variables.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/global_variables.nr index 81c040a246b..68097f779ee 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/global_variables.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/global_variables.nr @@ -1,19 +1,8 @@ use dep::std::cmp::Eq; use crate::{ - address::{ - AztecAddress, - EthAddress, - }, - constants::{ - GENERATOR_INDEX__GLOBAL_VARIABLES, - GLOBAL_VARIABLES_LENGTH, - }, - traits::{ - Deserialize, - Empty, - Hash, - Serialize, - }, + address::{AztecAddress, EthAddress}, + constants::{GENERATOR_INDEX__GLOBAL_VARIABLES, GLOBAL_VARIABLES_LENGTH}, + traits::{Deserialize, Empty, Hash, Serialize} }; // docs:start:global-variables diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/kernel_circuit_public_inputs.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/kernel_circuit_public_inputs.nr index d79a57b590c..9996c28a33b 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/kernel_circuit_public_inputs.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/kernel_circuit_public_inputs.nr @@ -1,10 +1,8 @@ use crate::abis::{ combined_accumulated_data::{ - CombinedAccumulatedData, - FinalAccumulatedData, - AccumulatedNonRevertibleData, - CombinedAccumulatedDataBuilder, - }, + CombinedAccumulatedData, FinalAccumulatedData, AccumulatedNonRevertibleData, + CombinedAccumulatedDataBuilder +}, combined_constant_data::CombinedConstantData }; use crate::mocked::AggregationObject; @@ -48,17 +46,20 @@ impl PrivateKernelCircuitPublicInputsBuilder { max_non_revertible_side_effect_counter: self.max_non_revertible_side_effect_counter, end: self.end.finish(), constants: self.constants, - is_private: self.is_private, + is_private: self.is_private } } - pub fn to_tail(self, end_non_revertible: AccumulatedNonRevertibleData) -> PrivateKernelTailCircuitPublicInputs { + pub fn to_tail( + self, + end_non_revertible: AccumulatedNonRevertibleData + ) -> PrivateKernelTailCircuitPublicInputs { PrivateKernelTailCircuitPublicInputs { aggregation_object: self.aggregation_object, - end_non_revertible: end_non_revertible, + end_non_revertible, end: self.end.to_final(), constants: self.constants, - is_private: self.is_private, + is_private: self.is_private } } } @@ -78,7 +79,7 @@ impl PublicKernelCircuitPublicInputsBuilder { end_non_revertible: self.end_non_revertible, end: self.end.finish(), constants: self.constants, - is_private: self.is_private, + is_private: self.is_private } } } diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/kernel_data.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/kernel_data.nr index e20977aa331..216f7f141c1 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/kernel_data.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/kernel_data.nr @@ -1,10 +1,8 @@ use crate::mocked::{Proof, VerificationKey}; use crate::constants::VK_TREE_HEIGHT; use crate::abis::kernel_circuit_public_inputs::{ - PrivateKernelInnerCircuitPublicInputs, - PrivateKernelTailCircuitPublicInputs, + PrivateKernelInnerCircuitPublicInputs, PrivateKernelTailCircuitPublicInputs, PublicKernelCircuitPublicInputs - }; struct PrivateKernelInnerData { diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/membership_witness.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/membership_witness.nr index 1cfe9e6ca69..38d6777a31b 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/membership_witness.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/membership_witness.nr @@ -1,11 +1,6 @@ use crate::constants::{ - CONTRACT_TREE_HEIGHT, - FUNCTION_TREE_HEIGHT, - NULLIFIER_TREE_HEIGHT, - NOTE_HASH_TREE_HEIGHT, - ROLLUP_VK_TREE_HEIGHT, - ARCHIVE_HEIGHT, - PUBLIC_DATA_TREE_HEIGHT, + CONTRACT_TREE_HEIGHT, FUNCTION_TREE_HEIGHT, NULLIFIER_TREE_HEIGHT, NOTE_HASH_TREE_HEIGHT, + ROLLUP_VK_TREE_HEIGHT, ARCHIVE_HEIGHT, PUBLIC_DATA_TREE_HEIGHT }; struct MembershipWitness { diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/new_contract_data.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/new_contract_data.nr index e5eea1680c1..598c00e103a 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/new_contract_data.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/new_contract_data.nr @@ -44,9 +44,8 @@ impl Hash for NewContractData { impl NewContractData { pub fn is_empty(self) -> bool { - (self.contract_address.to_field() == 0) & - (self.portal_contract_address.to_field() == 0) & - (self.contract_class_id.to_field() == 0) + (self.contract_address.to_field() == 0) + & (self.portal_contract_address.to_field() == 0) + & (self.contract_class_id.to_field() == 0) } - } diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/nullifier_key_validation_request.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/nullifier_key_validation_request.nr index b43754493d1..e1e7769bb10 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/nullifier_key_validation_request.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/nullifier_key_validation_request.nr @@ -1,9 +1,7 @@ use dep::std::cmp::Eq; use crate::{ - address::AztecAddress, - traits::{Empty, Serialize, Deserialize}, - grumpkin_point::GrumpkinPoint, - grumpkin_private_key::GrumpkinPrivateKey, + address::AztecAddress, traits::{Empty, Serialize, Deserialize}, grumpkin_point::GrumpkinPoint, + grumpkin_private_key::GrumpkinPrivateKey }; global NULLIFIER_KEY_VALIDATION_REQUEST_SERIALIZED_LEN = 4; @@ -52,11 +50,7 @@ impl Deserialize for NullifierK impl NullifierKeyValidationRequest { pub fn to_context(self, contract_address: AztecAddress) -> NullifierKeyValidationRequestContext { - NullifierKeyValidationRequestContext { - public_key: self.public_key, - secret_key: self.secret_key, - contract_address, - } + NullifierKeyValidationRequestContext { public_key: self.public_key, secret_key: self.secret_key, contract_address } } } diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/nullifier_leaf_preimage.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/nullifier_leaf_preimage.nr index 76ac2834bb3..605740777fe 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/nullifier_leaf_preimage.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/nullifier_leaf_preimage.nr @@ -38,10 +38,6 @@ impl NullifierLeafPreimage { } pub fn deserialize(fields: [Field; NULLIFIER_LEAF_PREIMAGE_LENGTH]) -> Self { - Self { - nullifier: fields[0], - next_nullifier: fields[1], - next_index: fields[2] as u32, - } + Self { nullifier: fields[0], next_nullifier: fields[1], next_index: fields[2] as u32 } } } diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/private_call_stack_item.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/private_call_stack_item.nr index 3ecdebed3b4..b5856915bd7 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/private_call_stack_item.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/private_call_stack_item.nr @@ -1,20 +1,8 @@ use crate::{ - abis::{ - function_data::FunctionData, - private_circuit_public_inputs::PrivateCircuitPublicInputs, - }, + abis::{function_data::FunctionData, private_circuit_public_inputs::PrivateCircuitPublicInputs}, address::AztecAddress, - constants::{ - GENERATOR_INDEX__CALL_STACK_ITEM, - PRIVATE_CALL_STACK_ITEM_LENGTH, - }, - hash::pedersen_hash, - traits::{ - Deserialize, - Hash, - Serialize, - }, - utils::reader::Reader, + constants::{GENERATOR_INDEX__CALL_STACK_ITEM, PRIVATE_CALL_STACK_ITEM_LENGTH}, hash::pedersen_hash, + traits::{Deserialize, Hash, Serialize}, utils::reader::Reader }; struct PrivateCallStackItem { diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/private_circuit_public_inputs.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/private_circuit_public_inputs.nr index 6580653f446..5e0b9921d64 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/private_circuit_public_inputs.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/private_circuit_public_inputs.nr @@ -1,34 +1,17 @@ use crate::{ abis::{ - call_context::CallContext, - nullifier_key_validation_request::NullifierKeyValidationRequest, - side_effect::{ - SideEffect, - SideEffectLinkedToNoteHash, - }, - }, + call_context::CallContext, nullifier_key_validation_request::NullifierKeyValidationRequest, + side_effect::{SideEffect, SideEffectLinkedToNoteHash} +}, constants::{ - MAX_READ_REQUESTS_PER_CALL, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, - MAX_NEW_COMMITMENTS_PER_CALL, - MAX_NEW_NULLIFIERS_PER_CALL, - MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, - MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, - MAX_NEW_L2_TO_L1_MSGS_PER_CALL, - NUM_FIELDS_PER_SHA256, - RETURN_VALUES_LENGTH, - PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH, - GENERATOR_INDEX__PRIVATE_CIRCUIT_PUBLIC_INPUTS, - }, - contrakt::deployment_data::ContractDeploymentData, - header::Header, - hash::pedersen_hash, - traits::{ - Deserialize, - Hash, - Serialize, - }, - utils::reader::Reader, + MAX_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, + MAX_NEW_COMMITMENTS_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, NUM_FIELDS_PER_SHA256, + RETURN_VALUES_LENGTH, PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH, + GENERATOR_INDEX__PRIVATE_CIRCUIT_PUBLIC_INPUTS +}, + contrakt::deployment_data::ContractDeploymentData, header::Header, hash::pedersen_hash, + traits::{Deserialize, Hash, Serialize}, utils::reader::Reader }; struct PrivateCircuitPublicInputs { diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/private_kernel/private_call_data.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/private_kernel/private_call_data.nr index b0365bbdb40..10647b0d3f3 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/private_kernel/private_call_data.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/private_kernel/private_call_data.nr @@ -1,19 +1,13 @@ use crate::abis::{ - call_request::CallRequest, - private_call_stack_item::PrivateCallStackItem, - membership_witness::{ - ContractLeafMembershipWitness, - FunctionLeafMembershipWitness, - ReadRequestMembershipWitness, - } + call_request::CallRequest, private_call_stack_item::PrivateCallStackItem, + membership_witness::{ContractLeafMembershipWitness, FunctionLeafMembershipWitness, ReadRequestMembershipWitness} }; -use crate::address::{ SaltedInitializationHash, PublicKeysHash, EthAddress }; -use crate::contract_class::{ ContractClassId }; +use crate::address::{SaltedInitializationHash, PublicKeysHash, EthAddress}; +use crate::contract_class::{ContractClassId}; use crate::mocked::{Proof, VerificationKey}; use crate::constants::{ - MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, - MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, - MAX_READ_REQUESTS_PER_CALL, + MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, + MAX_READ_REQUESTS_PER_CALL }; struct PrivateCallData { diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/public_call_data.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/public_call_data.nr index fc57026db5b..8d762839c99 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/public_call_data.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/public_call_data.nr @@ -1,10 +1,6 @@ use crate::{ - abis::{ - call_request::CallRequest, - public_call_stack_item::PublicCallStackItem, - }, - address::EthAddress, - mocked::Proof, + abis::{call_request::CallRequest, public_call_stack_item::PublicCallStackItem}, address::EthAddress, + mocked::Proof }; use crate::constants::MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL; diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/public_call_stack_item.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/public_call_stack_item.nr index 879b5e7d768..d113c95b0ab 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/public_call_stack_item.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/public_call_stack_item.nr @@ -1,7 +1,4 @@ -use crate::abis::{ - function_data::FunctionData, - public_circuit_public_inputs::PublicCircuitPublicInputs, -}; +use crate::abis::{function_data::FunctionData, public_circuit_public_inputs::PublicCircuitPublicInputs}; use crate::address::AztecAddress; use crate::constants::GENERATOR_INDEX__CALL_STACK_ITEM; use crate::traits::Hash; @@ -42,7 +39,7 @@ impl PublicCallStackItem { contract_address: self.contract_address, function_data: self.function_data, is_execution_request: true, - public_inputs: request_public_inputs, + public_inputs: request_public_inputs }; call_stack_item } diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/public_circuit_public_inputs.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/public_circuit_public_inputs.nr index 372aefde016..8167f7d32f4 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/public_circuit_public_inputs.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/public_circuit_public_inputs.nr @@ -1,33 +1,14 @@ use crate::{ - abis::{ - call_context::CallContext, - side_effect::{SideEffect, SideEffectLinkedToNoteHash}, - }, + abis::{call_context::CallContext, side_effect::{SideEffect, SideEffectLinkedToNoteHash}}, address::AztecAddress, constants::{ - MAX_NEW_L2_TO_L1_MSGS_PER_CALL, - MAX_NEW_NULLIFIERS_PER_CALL, - MAX_NEW_COMMITMENTS_PER_CALL, - MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, - MAX_PUBLIC_DATA_READS_PER_CALL, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, - NUM_FIELDS_PER_SHA256, - RETURN_VALUES_LENGTH, - GENERATOR_INDEX__PUBLIC_CIRCUIT_PUBLIC_INPUTS, - PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH, - }, - contrakt::{ - storage_read::StorageRead, - storage_update_request::StorageUpdateRequest, - }, - hash::pedersen_hash, - header::Header, - traits::{ - Hash, - Serialize, - Deserialize, - }, - utils::reader::Reader, + MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, MAX_NEW_COMMITMENTS_PER_CALL, + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_DATA_READS_PER_CALL, + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, NUM_FIELDS_PER_SHA256, RETURN_VALUES_LENGTH, + GENERATOR_INDEX__PUBLIC_CIRCUIT_PUBLIC_INPUTS, PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH +}, + contrakt::{storage_read::StorageRead, storage_update_request::StorageUpdateRequest}, + hash::pedersen_hash, header::Header, traits::{Hash, Serialize, Deserialize}, utils::reader::Reader }; struct PublicCircuitPublicInputs{ diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/public_data_read.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/public_data_read.nr index 096cc439c33..f790fe142c8 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/public_data_read.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/public_data_read.nr @@ -1,6 +1,6 @@ use crate::constants::GENERATOR_INDEX__PUBLIC_DATA_READ; use dep::std::cmp::Eq; -use crate::traits::{Empty,Hash}; +use crate::traits::{Empty, Hash}; struct PublicDataRead { leaf_slot : Field, diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/address.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/address.nr index d4dc79fd9bf..ab4b31e0ce2 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/address.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/address.nr @@ -1,13 +1,6 @@ use crate::{ - constants::{ - GENERATOR_INDEX__CONTRACT_ADDRESS, - GENERATOR_INDEX__PARTIAL_ADDRESS, - GENERATOR_INDEX__CONSTRUCTOR - }, - hash::pedersen_hash, - contract_class::ContractClassId, - utils, - grumpkin_point::GrumpkinPoint, + constants::{GENERATOR_INDEX__CONTRACT_ADDRESS, GENERATOR_INDEX__PARTIAL_ADDRESS, GENERATOR_INDEX__CONSTRUCTOR}, + hash::pedersen_hash, contract_class::ContractClassId, utils, grumpkin_point::GrumpkinPoint }; use dep::std::cmp::Eq; use crate::traits::{Empty, ToField, Serialize, Deserialize}; @@ -52,19 +45,29 @@ impl Deserialize for AztecAddress { impl AztecAddress { pub fn zero() -> Self { - Self { - inner: 0 - } + Self { inner: 0 } } - pub fn from_field(field : Field) -> Self { - Self { - inner : field - } + pub fn from_field(field: Field) -> Self { + Self { inner: field } } - pub fn compute_from_public_key(pub_key: GrumpkinPoint, contract_class_id: ContractClassId, salt: Field, initialization_hash: Field, portal_contract_address: EthAddress) -> AztecAddress { - AztecAddress::compute(PublicKeysHash::compute(pub_key), PartialAddress::compute(contract_class_id, salt, initialization_hash, portal_contract_address)) + pub fn compute_from_public_key( + pub_key: GrumpkinPoint, + contract_class_id: ContractClassId, + salt: Field, + initialization_hash: Field, + portal_contract_address: EthAddress + ) -> AztecAddress { + AztecAddress::compute( + PublicKeysHash::compute(pub_key), + PartialAddress::compute( + contract_class_id, + salt, + initialization_hash, + portal_contract_address + ) + ) } pub fn compute(pub_keys_hash: PublicKeysHash, partial_address: PartialAddress) -> AztecAddress { @@ -79,16 +82,14 @@ impl AztecAddress { pub fn is_zero(self) -> bool { self.inner == 0 } - + pub fn assert_is_zero(self) { assert(self.to_field() == 0); } - pub fn conditional_assign(predicate: bool, lhs : Self, rhs : Self) -> Self{ + pub fn conditional_assign(predicate: bool, lhs: Self, rhs: Self) -> Self { let result = utils::conditional_assign(predicate, rhs.to_field(), lhs.to_field()); - Self { - inner : result - } + Self { inner: result } } } @@ -130,17 +131,13 @@ impl Deserialize for EthAddress { } } -impl EthAddress{ +impl EthAddress { pub fn zero() -> Self { - Self { - inner: 0 - } + Self { inner: 0 } } - pub fn from_field(field : Field) -> Self { - Self { - inner : field - } + pub fn from_field(field: Field) -> Self { + Self { inner: field } } pub fn is_zero(self) -> bool { @@ -151,11 +148,9 @@ impl EthAddress{ assert(self.to_field() == 0); } - pub fn conditional_assign(predicate: bool, lhs : Self, rhs : Self) -> Self{ + pub fn conditional_assign(predicate: bool, lhs: Self, rhs: Self) -> Self { let result = utils::conditional_assign(predicate, rhs.to_field(), lhs.to_field()); - Self { - inner : result - } + Self { inner: result } } } @@ -171,26 +166,37 @@ impl ToField for PartialAddress { } impl PartialAddress { - pub fn from_field(field : Field) -> Self { - Self { - inner : field - } - } - - pub fn compute(contract_class_id: ContractClassId, salt: Field, initialization_hash: Field, portal_contract_address: EthAddress) -> Self { - PartialAddress::compute_from_salted_initialization_hash(contract_class_id, SaltedInitializationHash::compute(salt, initialization_hash, portal_contract_address)) + pub fn from_field(field: Field) -> Self { + Self { inner: field } + } + + pub fn compute( + contract_class_id: ContractClassId, + salt: Field, + initialization_hash: Field, + portal_contract_address: EthAddress + ) -> Self { + PartialAddress::compute_from_salted_initialization_hash( + contract_class_id, + SaltedInitializationHash::compute(salt, initialization_hash, portal_contract_address) + ) } - pub fn compute_from_salted_initialization_hash(contract_class_id: ContractClassId, salted_initialization_hash: SaltedInitializationHash) -> Self { + pub fn compute_from_salted_initialization_hash( + contract_class_id: ContractClassId, + salted_initialization_hash: SaltedInitializationHash + ) -> Self { PartialAddress::from_field( - pedersen_hash([ - contract_class_id.to_field(), - salted_initialization_hash.to_field() - ], GENERATOR_INDEX__PARTIAL_ADDRESS) + pedersen_hash( + [ + contract_class_id.to_field(), + salted_initialization_hash.to_field() + ], + GENERATOR_INDEX__PARTIAL_ADDRESS + ) ) } - pub fn to_field(self) -> Field { self.inner } @@ -212,19 +218,20 @@ impl ToField for SaltedInitializationHash { } impl SaltedInitializationHash { - pub fn from_field(field : Field) -> Self { - Self { - inner : field - } + pub fn from_field(field: Field) -> Self { + Self { inner: field } } - pub fn compute(salt : Field, initialization_hash: Field, portal_contract_address: EthAddress) -> Self { + pub fn compute(salt: Field, initialization_hash: Field, portal_contract_address: EthAddress) -> Self { SaltedInitializationHash::from_field( - pedersen_hash([ - salt, - initialization_hash, - portal_contract_address.to_field(), - ], GENERATOR_INDEX__PARTIAL_ADDRESS) + pedersen_hash( + [ + salt, + initialization_hash, + portal_contract_address.to_field() + ], + GENERATOR_INDEX__PARTIAL_ADDRESS + ) ) } @@ -261,18 +268,19 @@ impl Deserialize<1> for PublicKeysHash { } impl PublicKeysHash { - pub fn from_field(field : Field) -> Self { - Self { - inner : field - } + pub fn from_field(field: Field) -> Self { + Self { inner: field } } pub fn compute(public_key: GrumpkinPoint) -> Self { PublicKeysHash::from_field( - pedersen_hash([ - public_key.x, - public_key.y, - ], GENERATOR_INDEX__PARTIAL_ADDRESS) + pedersen_hash( + [ + public_key.x, + public_key.y + ], + GENERATOR_INDEX__PARTIAL_ADDRESS + ) ) } diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/contract_class.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/contract_class.nr index 96bbfe89e65..69ffb16ecdf 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/contract_class.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/contract_class.nr @@ -1,12 +1,9 @@ use crate::abis::{ - function_data::FunctionData, - private_circuit_public_inputs::PrivateCircuitPublicInputs, - public_circuit_public_inputs::PublicCircuitPublicInputs, + function_data::FunctionData, private_circuit_public_inputs::PrivateCircuitPublicInputs, + public_circuit_public_inputs::PublicCircuitPublicInputs }; use crate::address::AztecAddress; -use crate::constants::{ - GENERATOR_INDEX__CONTRACT_LEAF, -}; +use crate::constants::{GENERATOR_INDEX__CONTRACT_LEAF}; use crate::traits::Hash; struct ContractClassId { @@ -20,13 +17,20 @@ impl Eq for ContractClassId { } impl ContractClassId { - pub fn compute(artifact_hash: Field, private_functions_root: Field, public_bytecode_commitment: Field) -> Self { - let hash = dep::std::hash::pedersen_hash_with_separator([ + pub fn compute( + artifact_hash: Field, + private_functions_root: Field, + public_bytecode_commitment: Field + ) -> Self { + let hash = dep::std::hash::pedersen_hash_with_separator( + [ artifact_hash, private_functions_root, - public_bytecode_commitment, - ], GENERATOR_INDEX__CONTRACT_LEAF); // TODO(@spalladino): Update generator index - + public_bytecode_commitment + ], + GENERATOR_INDEX__CONTRACT_LEAF + ); // TODO(@spalladino): Update generator index + ContractClassId::from_field(hash) } @@ -34,7 +38,7 @@ impl ContractClassId { self.inner as Field } - pub fn from_field(value : Field) -> Self { + pub fn from_field(value: Field) -> Self { Self { inner: value } } diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/contrakt/deployment_data.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/contrakt/deployment_data.nr index 668234a8832..e1f13954e36 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/contrakt/deployment_data.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/contrakt/deployment_data.nr @@ -1,17 +1,7 @@ use crate::{ - address::EthAddress, - contract_class::ContractClassId, - constants::{ - CONTRACT_DEPLOYMENT_DATA_LENGTH, - GENERATOR_INDEX__CONTRACT_DEPLOYMENT_DATA, - }, - grumpkin_point::GrumpkinPoint, - hash::pedersen_hash, - traits::{ - Deserialize, - Hash, - Serialize, - }, + address::EthAddress, contract_class::ContractClassId, + constants::{CONTRACT_DEPLOYMENT_DATA_LENGTH, GENERATOR_INDEX__CONTRACT_DEPLOYMENT_DATA}, + grumpkin_point::GrumpkinPoint, hash::pedersen_hash, traits::{Deserialize, Hash, Serialize} }; // docs:start:contract-deployment-data diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/contrakt/storage_read.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/contrakt/storage_read.nr index 2921e23ab94..04ee782bd3d 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/contrakt/storage_read.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/contrakt/storage_read.nr @@ -1,15 +1,6 @@ use crate::{ - constants::{ - CONTRACT_STORAGE_READ_LENGTH, - GENERATOR_INDEX__PUBLIC_DATA_READ, - }, - hash::pedersen_hash, - traits::{ - Deserialize, - Hash, - Empty, - Serialize, - }, + constants::{CONTRACT_STORAGE_READ_LENGTH, GENERATOR_INDEX__PUBLIC_DATA_READ}, hash::pedersen_hash, + traits::{Deserialize, Hash, Empty, Serialize} }; struct StorageRead { diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/contrakt/storage_update_request.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/contrakt/storage_update_request.nr index 7c837dec53f..cdea292a2c5 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/contrakt/storage_update_request.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/contrakt/storage_update_request.nr @@ -1,15 +1,6 @@ use crate::{ - constants::{ - CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH, - GENERATOR_INDEX__PUBLIC_DATA_UPDATE_REQUEST, - }, - hash::pedersen_hash, - traits::{ - Deserialize, - Hash, - Empty, - Serialize, - }, + constants::{CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH, GENERATOR_INDEX__PUBLIC_DATA_UPDATE_REQUEST}, + hash::pedersen_hash, traits::{Deserialize, Hash, Empty, Serialize} }; use dep::std::cmp::Eq; diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/grumpkin_point.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/grumpkin_point.nr index 59b3db2ec5f..965654ac144 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/grumpkin_point.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/grumpkin_point.nr @@ -35,10 +35,7 @@ impl GrumpkinPoint { } pub fn zero() -> Self { - Self { - x: 0, - y: 0, - } + Self { x: 0, y: 0 } } pub fn is_zero(self) -> bool { diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/grumpkin_private_key.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/grumpkin_private_key.nr index b88381ee118..4694322da8a 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/grumpkin_private_key.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/grumpkin_private_key.nr @@ -1,8 +1,4 @@ -use dep::std::{ - cmp::Eq, - grumpkin_scalar::GrumpkinScalar, - grumpkin_scalar_mul::grumpkin_fixed_base, -}; +use dep::std::{cmp::Eq, grumpkin_scalar::GrumpkinScalar, grumpkin_scalar_mul::grumpkin_fixed_base}; use crate::grumpkin_point::GrumpkinPoint; global GRUMPKIN_PRIVATE_KEY_SERIALIZED_LEN: Field = 2; @@ -24,10 +20,7 @@ impl GrumpkinPrivateKey { } pub fn zero() -> Self { - Self { - high: 0, - low: 0, - } + Self { high: 0, low: 0 } } pub fn is_zero(self) -> bool { diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/hash.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/hash.nr index efcb331b954..dd00a8874ee 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/hash.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/hash.nr @@ -8,21 +8,12 @@ use crate::abis::function_data::FunctionData; use crate::abis::side_effect::{SideEffect}; use crate::utils::uint256::U256; use crate::constants::{ - ARGS_HASH_CHUNK_COUNT, - ARGS_HASH_CHUNK_LENGTH, - CONTRACT_TREE_HEIGHT, - FUNCTION_TREE_HEIGHT, - NOTE_HASH_TREE_HEIGHT, - NUM_FIELDS_PER_SHA256, - GENERATOR_INDEX__SILOED_COMMITMENT, - GENERATOR_INDEX__OUTER_NULLIFIER, - GENERATOR_INDEX__VK, - GENERATOR_INDEX__CONSTRUCTOR, - GENERATOR_INDEX__PARTIAL_ADDRESS, - GENERATOR_INDEX__CONTRACT_ADDRESS, - GENERATOR_INDEX__COMMITMENT_NONCE, - GENERATOR_INDEX__UNIQUE_COMMITMENT, - GENERATOR_INDEX__FUNCTION_ARGS, + ARGS_HASH_CHUNK_COUNT, ARGS_HASH_CHUNK_LENGTH, CONTRACT_TREE_HEIGHT, FUNCTION_TREE_HEIGHT, + NOTE_HASH_TREE_HEIGHT, NUM_FIELDS_PER_SHA256, GENERATOR_INDEX__SILOED_COMMITMENT, + GENERATOR_INDEX__OUTER_NULLIFIER, GENERATOR_INDEX__VK, GENERATOR_INDEX__CONSTRUCTOR, + GENERATOR_INDEX__PARTIAL_ADDRESS, GENERATOR_INDEX__CONTRACT_ADDRESS, + GENERATOR_INDEX__COMMITMENT_NONCE, GENERATOR_INDEX__UNIQUE_COMMITMENT, + GENERATOR_INDEX__FUNCTION_ARGS }; use dep::std::hash::{pedersen_hash_with_separator, sha256}; diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/header.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/header.nr index f5f38bceb4c..a8e8713e760 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/header.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/header.nr @@ -1,31 +1,11 @@ use crate::{ abis::{ - append_only_tree_snapshot::{ - AppendOnlyTreeSnapshot, - APPEND_ONLY_TREE_SNAPSHOT_LENGTH, - }, - global_variables::{ - GlobalVariables, - GLOBAL_VARIABLES_LENGTH, - }, - }, - constants::{ - GENERATOR_INDEX__BLOCK_HASH, - HEADER_LENGTH, - NUM_FIELDS_PER_SHA256, - STATE_REFERENCE_LENGTH, - }, - hash::pedersen_hash, - state_reference::StateReference, - traits::{ - Deserialize, - Empty, - Hash, - Serialize, - }, - utils::{ - arr_copy_slice, - }, + append_only_tree_snapshot::{AppendOnlyTreeSnapshot, APPEND_ONLY_TREE_SNAPSHOT_LENGTH}, + global_variables::{GlobalVariables, GLOBAL_VARIABLES_LENGTH} +}, + constants::{GENERATOR_INDEX__BLOCK_HASH, HEADER_LENGTH, NUM_FIELDS_PER_SHA256, STATE_REFERENCE_LENGTH}, + hash::pedersen_hash, state_reference::StateReference, traits::{Deserialize, Empty, Hash, Serialize}, + utils::{arr_copy_slice} }; // docs:start:header diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/lib.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/lib.nr index 437cb6146c1..352d5f2feef 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/lib.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/lib.nr @@ -27,8 +27,7 @@ mod partial_state_reference; mod public_data_tree_leaf; mod public_data_tree_leaf_preimage; -use abis::kernel_circuit_public_inputs::{ - PrivateKernelInnerCircuitPublicInputs, - PrivateKernelTailCircuitPublicInputs, - PublicKernelCircuitPublicInputs, +use abis::kernel_circuit_public_inputs::{ + PrivateKernelInnerCircuitPublicInputs, PrivateKernelTailCircuitPublicInputs, + PublicKernelCircuitPublicInputs }; diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/partial_state_reference.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/partial_state_reference.nr index 7e22fd8bee0..245294969c0 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/partial_state_reference.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/partial_state_reference.nr @@ -1,12 +1,6 @@ use crate::{ - abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot, - constants::PARTIAL_STATE_REFERENCE_LENGTH, - traits::{ - Deserialize, - Empty, - Hash, - Serialize, - }, + abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot, constants::PARTIAL_STATE_REFERENCE_LENGTH, + traits::{Deserialize, Empty, Hash, Serialize} }; struct PartialStateReference { diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/state_reference.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/state_reference.nr index 99aa8a52d74..1fdaba370f7 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/state_reference.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/state_reference.nr @@ -1,22 +1,8 @@ use crate::{ - abis::append_only_tree_snapshot::{ - AppendOnlyTreeSnapshot, - APPEND_ONLY_TREE_SNAPSHOT_LENGTH, - }, - constants::{ - PARTIAL_STATE_REFERENCE_LENGTH, - STATE_REFERENCE_LENGTH, - }, - partial_state_reference::PartialStateReference, - traits::{ - Deserialize, - Empty, - Hash, - Serialize, - }, - utils::{ - arr_copy_slice, - }, + abis::append_only_tree_snapshot::{AppendOnlyTreeSnapshot, APPEND_ONLY_TREE_SNAPSHOT_LENGTH}, + constants::{PARTIAL_STATE_REFERENCE_LENGTH, STATE_REFERENCE_LENGTH}, + partial_state_reference::PartialStateReference, traits::{Deserialize, Empty, Hash, Serialize}, + utils::{arr_copy_slice} }; struct StateReference { diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/fixtures.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/fixtures.nr index 32b29b89d48..d5c7e80f258 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/fixtures.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/fixtures.nr @@ -5,20 +5,10 @@ mod note_hash_tree; mod read_requests; use crate::{ - abis::{ - append_only_tree_snapshot::AppendOnlyTreeSnapshot, - global_variables::GlobalVariables, - }, - address::{ - AztecAddress, - EthAddress, - }, - constants::NUM_FIELDS_PER_SHA256, - grumpkin_point::GrumpkinPoint, - header::Header, - partial_state_reference::PartialStateReference, - state_reference::StateReference, - tests::fixtures + abis::{append_only_tree_snapshot::AppendOnlyTreeSnapshot, global_variables::GlobalVariables}, + address::{AztecAddress, EthAddress}, constants::NUM_FIELDS_PER_SHA256, + grumpkin_point::GrumpkinPoint, header::Header, partial_state_reference::PartialStateReference, + state_reference::StateReference, tests::fixtures }; global MSG_SENDER = AztecAddress { inner: 27 }; diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/fixtures/contract_functions.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/fixtures/contract_functions.nr index ae6533e70de..ecee58edac1 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/fixtures/contract_functions.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/fixtures/contract_functions.nr @@ -1,7 +1,6 @@ use crate::abis::{ - function_data::FunctionData, - function_selector::FunctionSelector, - membership_witness::FunctionLeafMembershipWitness, + function_data::FunctionData, function_selector::FunctionSelector, + membership_witness::FunctionLeafMembershipWitness }; struct ContractFunction { diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/fixtures/contracts.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/fixtures/contracts.nr index 51e91ef7527..9da6995f294 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/fixtures/contracts.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/fixtures/contracts.nr @@ -1,5 +1,5 @@ use crate::abis::membership_witness::ContractLeafMembershipWitness; -use crate::address::{AztecAddress, EthAddress, PublicKeysHash, SaltedInitializationHash, PartialAddress }; +use crate::address::{AztecAddress, EthAddress, PublicKeysHash, SaltedInitializationHash, PartialAddress}; use crate::tests::fixtures; use crate::contract_class::ContractClassId; diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/fixtures/read_requests.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/fixtures/read_requests.nr index a77ddd9b45f..3b655178474 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/fixtures/read_requests.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/fixtures/read_requests.nr @@ -1,11 +1,6 @@ -use crate::abis::{ - membership_witness::ReadRequestMembershipWitness, - side_effect::SideEffect, -}; +use crate::abis::{membership_witness::ReadRequestMembershipWitness, side_effect::SideEffect}; use crate::tests::fixtures; -use crate::constants::{ - MAX_READ_REQUESTS_PER_CALL, -}; +use crate::constants::{MAX_READ_REQUESTS_PER_CALL}; pub fn generate_read_requests(how_many: Field) -> (BoundedVec, BoundedVec) { generate_read_requests_with_config(how_many, false, [0; MAX_READ_REQUESTS_PER_CALL]) diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/kernel_data_builder.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/kernel_data_builder.nr index 211d5a39abe..b8849b6b19a 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/kernel_data_builder.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/kernel_data_builder.nr @@ -1,31 +1,23 @@ use crate::{ abis::{ - call_context::CallContext, - call_request::{CallerContext, CallRequest}, - combined_constant_data::CombinedConstantData, - combined_accumulated_data::{CombinedAccumulatedDataBuilder, AccumulatedNonRevertibleData}, - kernel_circuit_public_inputs::{PrivateKernelInnerCircuitPublicInputs, PrivateKernelTailCircuitPublicInputs, PublicKernelCircuitPublicInputs}, - kernel_data::{PrivateKernelInnerData, PrivateKernelTailData, PublicKernelData}, - public_data_read::PublicDataRead, - public_data_update_request::PublicDataUpdateRequest, - side_effect::{SideEffect, SideEffectLinkedToNoteHash}, - }, - address::{AztecAddress, EthAddress}, - header::Header, + call_context::CallContext, call_request::{CallerContext, CallRequest}, + combined_constant_data::CombinedConstantData, + combined_accumulated_data::{CombinedAccumulatedDataBuilder, AccumulatedNonRevertibleData}, + kernel_circuit_public_inputs::{ + PrivateKernelInnerCircuitPublicInputs, PrivateKernelTailCircuitPublicInputs, + PublicKernelCircuitPublicInputs +}, + kernel_data::{PrivateKernelInnerData, PrivateKernelTailData, PublicKernelData}, + public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, + side_effect::{SideEffect, SideEffectLinkedToNoteHash} +}, + address::{AztecAddress, EthAddress}, header::Header, mocked::{AggregationObject, Proof, VerificationKey}, - tests::{ - fixtures, - testing_harness::build_tx_context, - }, - transaction::context::TxContext, + tests::{fixtures, testing_harness::build_tx_context}, transaction::context::TxContext }; use crate::constants::{ - MAX_NEW_COMMITMENTS_PER_TX, - MAX_NEW_NULLIFIERS_PER_TX, - MAX_PUBLIC_DATA_READS_PER_TX, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - NUM_FIELDS_PER_SHA256, - VK_TREE_HEIGHT, + MAX_NEW_COMMITMENTS_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_PUBLIC_DATA_READS_PER_TX, + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, NUM_FIELDS_PER_SHA256, VK_TREE_HEIGHT }; struct PreviousKernelDataBuilder { @@ -45,11 +37,7 @@ struct PreviousKernelDataBuilder { impl PreviousKernelDataBuilder { pub fn new() -> Self { let mut end: CombinedAccumulatedDataBuilder = dep::std::unsafe::zeroed(); - end.new_nullifiers.push(SideEffectLinkedToNoteHash{ - value: 321, - note_hash: 0, - counter: 0 - }); // 0th nullifier must be non-zero. + end.new_nullifiers.push(SideEffectLinkedToNoteHash { value: 321, note_hash: 0, counter: 0 }); // 0th nullifier must be non-zero. let tx_context = build_tx_context(false, 0); @@ -64,7 +52,7 @@ impl PreviousKernelDataBuilder { vk: VerificationKey {}, vk_index: 0, vk_path: [0; VK_TREE_HEIGHT], - sideffect_counter: 2, + sideffect_counter: 2 } } @@ -83,7 +71,7 @@ impl PreviousKernelDataBuilder { // The default value is its index + 45. old_value: value_offset + i + 45, // The default value is its index + 678. - new_value: value_offset + i + 678, + new_value: value_offset + i + 678 }; self.end.public_data_update_requests.push(update_request); } @@ -98,7 +86,7 @@ impl PreviousKernelDataBuilder { // The default leaf index is its index + 34. leaf_slot: value_offset + i + 34, // The default value is its index + 5566. - value: value_offset + i + 5566, + value: value_offset + i + 5566 }; self.end.public_data_reads.push(read_request); } @@ -114,10 +102,7 @@ impl PreviousKernelDataBuilder { pub fn add_read_request_for_transient_commitment(&mut self, commitment_index: Field) -> Field { let new_read_request_index = self.end.read_requests.len(); let commitment = self.end.new_commitments.get(commitment_index); - let read_request = SideEffect { - value: commitment.value, - counter: self.next_sideffect_counter(), - }; + let read_request = SideEffect { value: commitment.value, counter: self.next_sideffect_counter() }; self.end.read_requests.push(read_request); new_read_request_index } @@ -127,10 +112,9 @@ impl PreviousKernelDataBuilder { for i in 0..MAX_NEW_COMMITMENTS_PER_TX { if i as u64 < num_new_commitments as u64 { // The default value is its index + 1. - self.end.new_commitments.push(SideEffect{ - value: i + mocked_value_offset, - counter: self.next_sideffect_counter() - }); + self.end.new_commitments.push( + SideEffect { value: i + mocked_value_offset, counter: self.next_sideffect_counter() } + ); } } } @@ -141,11 +125,13 @@ impl PreviousKernelDataBuilder { for i in 1..MAX_NEW_NULLIFIERS_PER_TX { if i as u64 <= num_extra_nullifier as u64 { // The default value is its index + the value of the first nullifier. - self.end.new_nullifiers.push(SideEffectLinkedToNoteHash{ + self.end.new_nullifiers.push( + SideEffectLinkedToNoteHash { value: i + mocked_value_offset, note_hash: first_nullifier.note_hash, counter: self.next_sideffect_counter() - }); + } + ); } } } @@ -184,7 +170,7 @@ impl PreviousKernelDataBuilder { caller_contract_address: self.contract_address, caller_context, start_side_effect_counter: counter, - end_side_effect_counter: end_counter, + end_side_effect_counter: end_counter } } @@ -193,64 +179,37 @@ impl PreviousKernelDataBuilder { aggregation_object: AggregationObject {}, max_non_revertible_side_effect_counter: 0, end: self.end.finish(), - constants: CombinedConstantData { - historical_header: self.historical_header, - tx_context: self.tx_context, - }, - is_private: self.is_private, + constants: CombinedConstantData { historical_header: self.historical_header, tx_context: self.tx_context }, + is_private: self.is_private }; - PrivateKernelInnerData { - public_inputs, - proof: self.proof, - vk: self.vk, - vk_index: self.vk_index, - vk_path: self.vk_path, - } + PrivateKernelInnerData { public_inputs, proof: self.proof, vk: self.vk, vk_index: self.vk_index, vk_path: self.vk_path } } pub fn to_private_kernel_tail_data(self) -> PrivateKernelTailData { // TODO(fees) probably need to add this to the builder once it is implemented. - let end_non_revertible: AccumulatedNonRevertibleData = dep::std::unsafe::zeroed(); + let end_non_revertible: AccumulatedNonRevertibleData = dep::std::unsafe::zeroed(); let public_inputs = PrivateKernelTailCircuitPublicInputs { aggregation_object: AggregationObject {}, - end_non_revertible: end_non_revertible, + end_non_revertible, end: self.end.to_final(), - constants: CombinedConstantData { - historical_header: self.historical_header, - tx_context: self.tx_context, - }, - is_private: self.is_private, + constants: CombinedConstantData { historical_header: self.historical_header, tx_context: self.tx_context }, + is_private: self.is_private }; - PrivateKernelTailData { - public_inputs, - proof: self.proof, - vk: self.vk, - vk_index: self.vk_index, - vk_path: self.vk_path, - } + PrivateKernelTailData { public_inputs, proof: self.proof, vk: self.vk, vk_index: self.vk_index, vk_path: self.vk_path } } pub fn to_public_kernel_data(self) -> PublicKernelData { // TODO(fees) probably need to add this to the builder once it is implemented. - let end_non_revertible: AccumulatedNonRevertibleData = dep::std::unsafe::zeroed(); + let end_non_revertible: AccumulatedNonRevertibleData = dep::std::unsafe::zeroed(); let public_inputs = PublicKernelCircuitPublicInputs { aggregation_object: AggregationObject {}, - end_non_revertible: end_non_revertible, + end_non_revertible, end: self.end.finish(), - constants: CombinedConstantData { - historical_header: self.historical_header, - tx_context: self.tx_context, - }, - is_private: self.is_private, + constants: CombinedConstantData { historical_header: self.historical_header, tx_context: self.tx_context }, + is_private: self.is_private }; - PublicKernelData { - public_inputs, - proof: self.proof, - vk: self.vk, - vk_index: self.vk_index, - vk_path: self.vk_path, - } + PublicKernelData { public_inputs, proof: self.proof, vk: self.vk, vk_index: self.vk_index, vk_path: self.vk_path } } } diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/private_call_data_builder.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/private_call_data_builder.nr index 64f17d36727..6af5745507a 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/private_call_data_builder.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/private_call_data_builder.nr @@ -1,32 +1,22 @@ use crate::{ abis::{ - call_request::{CallerContext, CallRequest}, - private_call_stack_item::PrivateCallStackItem, - function_data::FunctionData, - membership_witness::{ - ContractLeafMembershipWitness, - FunctionLeafMembershipWitness, - ReadRequestMembershipWitness, - }, - private_circuit_public_inputs::{PrivateCircuitPublicInputs}, - private_kernel::private_call_data::PrivateCallData, - }, + call_request::{CallerContext, CallRequest}, private_call_stack_item::PrivateCallStackItem, + function_data::FunctionData, + membership_witness::{ContractLeafMembershipWitness, FunctionLeafMembershipWitness, ReadRequestMembershipWitness}, + private_circuit_public_inputs::{PrivateCircuitPublicInputs}, + private_kernel::private_call_data::PrivateCallData +}, address::{AztecAddress, EthAddress, SaltedInitializationHash, PublicKeysHash}, mocked::{Proof, VerificationKey}, tests::{ - fixtures, - private_circuit_public_inputs_builder::PrivateCircuitPublicInputsBuilder, - testing_harness::build_tx_context, - }, - transaction::{ - request::TxRequest, - }, + fixtures, private_circuit_public_inputs_builder::PrivateCircuitPublicInputsBuilder, + testing_harness::build_tx_context +}, + transaction::{request::TxRequest} }; use crate::constants::{ - MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, - MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, - MAX_READ_REQUESTS_PER_CALL, - NUM_FIELDS_PER_SHA256, + MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, + MAX_READ_REQUESTS_PER_CALL, NUM_FIELDS_PER_SHA256 }; struct PrivateCallDataBuilder { @@ -61,7 +51,7 @@ impl PrivateCallDataBuilder { fixtures::contract_functions::default_private_function }; let function_data = contract_function.data; - + PrivateCallDataBuilder { contract_address: public_inputs.call_context.storage_contract_address, public_inputs, @@ -78,7 +68,7 @@ impl PrivateCallDataBuilder { contract_class_public_bytecode_commitment: contract_data.public_bytecode_commitment, read_request_membership_witnesses: dep::std::unsafe::zeroed(), portal_contract_address: public_inputs.call_context.portal_contract_address, - acir_hash: contract_function.acir_hash, + acir_hash: contract_function.acir_hash } } @@ -106,12 +96,15 @@ impl PrivateCallDataBuilder { } pub fn build_tx_request(self) -> TxRequest { - let tx_context = build_tx_context(self.public_inputs.call_context.is_contract_deployment, self.public_inputs.args_hash); + let tx_context = build_tx_context( + self.public_inputs.call_context.is_contract_deployment, + self.public_inputs.args_hash + ); TxRequest { origin: self.contract_address, args_hash: self.public_inputs.args_hash, tx_context, - function_data: self.function_data, + function_data: self.function_data } } @@ -131,7 +124,7 @@ impl PrivateCallDataBuilder { self, requests: BoundedVec, num_requests: Field, - is_delegate_call: bool, + is_delegate_call: bool ) -> (BoundedVec, BoundedVec) { let value_offset = requests.len(); let mut caller_context = CallerContext::empty(); @@ -154,7 +147,7 @@ impl PrivateCallDataBuilder { caller_context, // TODO: populate these start_side_effect_counter: 0, - end_side_effect_counter:0, + end_side_effect_counter: 0 }; hashes.push(hash); call_requests.push(request); @@ -189,7 +182,7 @@ impl PrivateCallDataBuilder { let call_stack_item = PrivateCallStackItem { contract_address: self.contract_address, function_data: self.function_data, - public_inputs: self.public_inputs.finish(), + public_inputs: self.public_inputs.finish() }; call_stack_item.hash() } @@ -198,7 +191,7 @@ impl PrivateCallDataBuilder { let call_stack_item = PrivateCallStackItem { contract_address: self.contract_address, function_data: self.function_data, - public_inputs: self.public_inputs.finish(), + public_inputs: self.public_inputs.finish() }; PrivateCallData { @@ -214,7 +207,7 @@ impl PrivateCallDataBuilder { contract_class_public_bytecode_commitment: self.contract_class_public_bytecode_commitment, read_request_membership_witnesses: self.read_request_membership_witnesses.storage, portal_contract_address: self.portal_contract_address, - acir_hash: self.acir_hash, + acir_hash: self.acir_hash } } } diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/private_circuit_public_inputs_builder.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/private_circuit_public_inputs_builder.nr index d2af5585e03..82ed9326491 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/private_circuit_public_inputs_builder.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/private_circuit_public_inputs_builder.nr @@ -1,29 +1,18 @@ use crate::{ abis::{ - call_context::CallContext, - nullifier_key_validation_request::NullifierKeyValidationRequest, - private_circuit_public_inputs::PrivateCircuitPublicInputs, - side_effect::{SideEffect, SideEffectLinkedToNoteHash}, - }, + call_context::CallContext, nullifier_key_validation_request::NullifierKeyValidationRequest, + private_circuit_public_inputs::PrivateCircuitPublicInputs, + side_effect::{SideEffect, SideEffectLinkedToNoteHash} +}, address::{AztecAddress, compute_initialization_hash}, - contrakt::deployment_data::ContractDeploymentData, - hash::{compute_constructor_hash, hash_args}, - header::Header, - tests::{ - fixtures, - testing_harness::build_contract_deployment_data, - }, + contrakt::deployment_data::ContractDeploymentData, hash::{compute_constructor_hash, hash_args}, + header::Header, tests::{fixtures, testing_harness::build_contract_deployment_data} }; use crate::constants::{ - MAX_READ_REQUESTS_PER_CALL, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, - MAX_NEW_COMMITMENTS_PER_CALL, - MAX_NEW_NULLIFIERS_PER_CALL, - MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, - MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, - MAX_NEW_L2_TO_L1_MSGS_PER_CALL, - NUM_FIELDS_PER_SHA256, - RETURN_VALUES_LENGTH, + MAX_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, + MAX_NEW_COMMITMENTS_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, NUM_FIELDS_PER_SHA256, + RETURN_VALUES_LENGTH }; struct PrivateCircuitPublicInputsBuilder { @@ -84,7 +73,7 @@ impl PrivateCircuitPublicInputsBuilder { contract_deployment_data.contract_class_id, contract_deployment_data.contract_address_salt, initialization_hash, - portal_contract_address, + portal_contract_address ) } else { contract_data.address @@ -98,7 +87,7 @@ impl PrivateCircuitPublicInputsBuilder { is_delegate_call: false, is_static_call: false, is_contract_deployment: is_constructor, - start_side_effect_counter: 0, + start_side_effect_counter: 0 }; public_inputs.call_context = call_context; public_inputs.args_hash = args_hash; @@ -110,36 +99,28 @@ impl PrivateCircuitPublicInputsBuilder { public_inputs } - pub fn finish(self) -> PrivateCircuitPublicInputs { + pub fn finish(self) -> PrivateCircuitPublicInputs { PrivateCircuitPublicInputs { call_context: self.call_context, args_hash: self.args_hash, return_values: self.return_values.storage, max_non_revertible_side_effect_counter: self.max_non_revertible_side_effect_counter, - read_requests: self.read_requests.storage, nullifier_key_validation_requests: self.nullifier_key_validation_requests.storage, - new_commitments: self.new_commitments.storage, new_nullifiers: self.new_nullifiers.storage, - private_call_stack_hashes: self.private_call_stack_hashes.storage, public_call_stack_hashes: self.public_call_stack_hashes.storage, new_l2_to_l1_msgs: self.new_l2_to_l1_msgs.storage, end_side_effect_counter: 10, - encrypted_logs_hash: self.encrypted_logs_hash, unencrypted_logs_hash: self.unencrypted_logs_hash, - encrypted_log_preimages_length: self.encrypted_log_preimages_length, unencrypted_log_preimages_length: self.unencrypted_log_preimages_length, - historical_header: self.historical_header, - contract_deployment_data: self.contract_deployment_data, - chain_id: self.chain_id, - version: self.version, + version: self.version } } } diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/public_call_data_builder.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/public_call_data_builder.nr index 77f9c6164cb..513226e26c1 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/public_call_data_builder.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/public_call_data_builder.nr @@ -1,28 +1,16 @@ use crate::{ abis::{ - call_context::CallContext, - call_request::{CallerContext, CallRequest}, - function_data::FunctionData, - public_call_data::PublicCallData, - public_call_stack_item::PublicCallStackItem, - public_circuit_public_inputs::PublicCircuitPublicInputs, - }, + call_context::CallContext, call_request::{CallerContext, CallRequest}, function_data::FunctionData, + public_call_data::PublicCallData, public_call_stack_item::PublicCallStackItem, + public_circuit_public_inputs::PublicCircuitPublicInputs +}, address::{AztecAddress, EthAddress}, - contrakt::{ - storage_read::StorageRead, - storage_update_request::StorageUpdateRequest, - }, - mocked::Proof, - tests::{ - fixtures, - public_circuit_public_inputs_builder::PublicCircuitPublicInputsBuilder, - }, + contrakt::{storage_read::StorageRead, storage_update_request::StorageUpdateRequest}, mocked::Proof, + tests::{fixtures, public_circuit_public_inputs_builder::PublicCircuitPublicInputsBuilder} }; use crate::constants::{ - MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, - MAX_PUBLIC_DATA_READS_PER_CALL, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, - NUM_FIELDS_PER_SHA256, + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_DATA_READS_PER_CALL, + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, NUM_FIELDS_PER_SHA256 }; struct PublicCallDataBuilder { @@ -57,7 +45,7 @@ impl PublicCallDataBuilder { is_contract_deployment: false, start_side_effect_counter: 0, // needed? }; - + PublicCallDataBuilder { contract_address, public_inputs, @@ -66,7 +54,7 @@ impl PublicCallDataBuilder { public_call_stack: dep::std::unsafe::zeroed(), proof: Proof {}, portal_contract_address, - bytecode_hash: contract_function.acir_hash, + bytecode_hash: contract_function.acir_hash } } @@ -115,8 +103,7 @@ impl PublicCallDataBuilder { caller_context, // todo: real values? start_side_effect_counter: i as u32, - end_side_effect_counter: (i + 1) as u32, - + end_side_effect_counter: (i + 1) as u32 }; self.public_inputs.public_call_stack_hashes.push(hash); self.public_call_stack.push(call_request); @@ -132,7 +119,7 @@ impl PublicCallDataBuilder { // The default storage slot is its index + 1. storage_slot: value_offset + i + 1, // The default value is its index + 999. - current_value: value_offset + i + 999, + current_value: value_offset + i + 999 }; self.public_inputs.contract_storage_reads.push(read_request); } @@ -157,7 +144,7 @@ impl PublicCallDataBuilder { // The default value is its index + 567. old_value: value_offset + i + 567, // The default value is its index + 890. - new_value: value_offset + i + 890, + new_value: value_offset + i + 890 }; self.public_inputs.contract_storage_update_requests.push(update_request); } @@ -183,12 +170,12 @@ impl PublicCallDataBuilder { contract_address: self.contract_address, function_data: self.function_data, is_execution_request: self.is_execution_request, - public_inputs: self.public_inputs.finish(), + public_inputs: self.public_inputs.finish() }, public_call_stack: self.public_call_stack.storage, proof: self.proof, portal_contract_address: self.portal_contract_address, - bytecode_hash: self.bytecode_hash, + bytecode_hash: self.bytecode_hash } } } diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/public_circuit_public_inputs_builder.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/public_circuit_public_inputs_builder.nr index 41f2102a051..c6487b1264e 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/public_circuit_public_inputs_builder.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/public_circuit_public_inputs_builder.nr @@ -1,26 +1,16 @@ use crate::{ abis::{ - call_context::CallContext, - public_circuit_public_inputs::PublicCircuitPublicInputs, - side_effect::{SideEffect, SideEffectLinkedToNoteHash}, - }, + call_context::CallContext, public_circuit_public_inputs::PublicCircuitPublicInputs, + side_effect::{SideEffect, SideEffectLinkedToNoteHash} +}, address::AztecAddress, - contrakt::{ - storage_read::StorageRead, - storage_update_request::StorageUpdateRequest, - }, - header::Header, - tests::fixtures, + contrakt::{storage_read::StorageRead, storage_update_request::StorageUpdateRequest}, header::Header, + tests::fixtures }; use crate::constants::{ - MAX_NEW_COMMITMENTS_PER_CALL, - MAX_NEW_L2_TO_L1_MSGS_PER_CALL, - MAX_NEW_NULLIFIERS_PER_CALL, - MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, - MAX_PUBLIC_DATA_READS_PER_CALL, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, - NUM_FIELDS_PER_SHA256, - RETURN_VALUES_LENGTH, + MAX_NEW_COMMITMENTS_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_DATA_READS_PER_CALL, + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, NUM_FIELDS_PER_SHA256, RETURN_VALUES_LENGTH }; struct PublicCircuitPublicInputsBuilder { @@ -61,7 +51,7 @@ impl PublicCircuitPublicInputsBuilder { unencrypted_logs_hash: self.unencrypted_logs_hash, unencrypted_log_preimages_length: self.unencrypted_log_preimages_length, historical_header: self.historical_header, - prover_address: self.prover_address, + prover_address: self.prover_address } } } diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/testing_harness.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/testing_harness.nr index 0c1eaeeea42..84d6e5b8c43 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/testing_harness.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/testing_harness.nr @@ -1,8 +1,6 @@ use crate::{ - contrakt::deployment_data::ContractDeploymentData, - tests::fixtures, - transaction::context::TxContext, - address::compute_initialization_hash, + contrakt::deployment_data::ContractDeploymentData, tests::fixtures, transaction::context::TxContext, + address::compute_initialization_hash }; pub fn build_contract_deployment_data(is_constructor: bool, args_hash: Field) -> ContractDeploymentData { diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/utils/reader.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/utils/reader.nr index 10bfc050fb8..6546b4aced6 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/utils/reader.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/utils/reader.nr @@ -37,5 +37,5 @@ impl Reader { pub fn finish(self) { assert(self.offset == self.data.len(), "Reader did not read all data"); - } + } } diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/utils/uint256.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/utils/uint256.nr index 7731218c9eb..54ac75ed94a 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/utils/uint256.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/utils/uint256.nr @@ -13,45 +13,45 @@ struct U256 { } impl U256 { - pub fn from_bytes32(bytes : [u8;32]) -> U256 { + pub fn from_bytes32(bytes: [u8; 32]) -> U256 { // We use addition rather than a bitwise OR as the bitshifts ensure that none of the bytes overlap each other. let high_0 = ((bytes[0] as u64) << 56) - + ((bytes[1] as u64) << 48) - + ((bytes[2] as u64) << 40) - + ((bytes[3] as u64) << 32) - + ((bytes[4] as u64) << 24) - + ((bytes[5] as u64) << 16) - + ((bytes[6] as u64) << 8) - + (bytes[7] as u64); - + + ((bytes[1] as u64) << 48) + + ((bytes[2] as u64) << 40) + + ((bytes[3] as u64) << 32) + + ((bytes[4] as u64) << 24) + + ((bytes[5] as u64) << 16) + + ((bytes[6] as u64) << 8) + + (bytes[7] as u64); + let high_1 = ((bytes[8] as u64) << 56) - + ((bytes[9] as u64) << 48) - + ((bytes[10] as u64) << 40) - + ((bytes[11] as u64) << 32) - + ((bytes[12] as u64) << 24) - + ((bytes[13] as u64) << 16) - + ((bytes[14] as u64) << 8) - + (bytes[15] as u64); - + + ((bytes[9] as u64) << 48) + + ((bytes[10] as u64) << 40) + + ((bytes[11] as u64) << 32) + + ((bytes[12] as u64) << 24) + + ((bytes[13] as u64) << 16) + + ((bytes[14] as u64) << 8) + + (bytes[15] as u64); + let low_0 = ((bytes[16] as u64) << 56) - + ((bytes[17] as u64) << 48) - + ((bytes[18] as u64) << 40) - + ((bytes[19] as u64) << 32) - + ((bytes[20] as u64) << 24) - + ((bytes[21] as u64) << 16) - + ((bytes[22] as u64) << 8) - + (bytes[23] as u64); - + + ((bytes[17] as u64) << 48) + + ((bytes[18] as u64) << 40) + + ((bytes[19] as u64) << 32) + + ((bytes[20] as u64) << 24) + + ((bytes[21] as u64) << 16) + + ((bytes[22] as u64) << 8) + + (bytes[23] as u64); + let low_1 = ((bytes[24] as u64) << 56) - + ((bytes[25] as u64) << 48) - + ((bytes[26] as u64) << 40) - + ((bytes[27] as u64) << 32) - + ((bytes[28] as u64) << 24) - + ((bytes[29] as u64) << 16) - + ((bytes[30] as u64) << 8) - + (bytes[31] as u64); + + ((bytes[25] as u64) << 48) + + ((bytes[26] as u64) << 40) + + ((bytes[27] as u64) << 32) + + ((bytes[28] as u64) << 24) + + ((bytes[29] as u64) << 16) + + ((bytes[30] as u64) << 8) + + (bytes[31] as u64); - U256{inner : [high_0, high_1, low_0, low_1]} + U256 { inner: [high_0, high_1, low_0, low_1] } } // We cannot represent u128 in the type system @@ -61,13 +61,13 @@ impl U256 { // or else the conversion is lossy. // // TODO: Add a test for this. - pub fn to_u128_limbs(self) -> [Field;2] { + pub fn to_u128_limbs(self) -> [Field; 2] { let two_pow_64 = 2.pow_32(64); let high = (self.inner[0] as Field) * two_pow_64 + self.inner[1] as Field; let low = (self.inner[2] as Field) * two_pow_64 + self.inner[3] as Field; - - [high,low] + + [high, low] } } diff --git a/yarn-project/pxe/tsconfig.json b/yarn-project/pxe/tsconfig.json index 91273923e82..0a0b5ee4533 100644 --- a/yarn-project/pxe/tsconfig.json +++ b/yarn-project/pxe/tsconfig.json @@ -6,9 +6,6 @@ "tsBuildInfoFile": ".tsbuildinfo" }, "references": [ - { - "path": "../simulator" - }, { "path": "../circuit-types" }, @@ -36,6 +33,9 @@ { "path": "../protocol-contracts" }, + { + "path": "../simulator" + }, { "path": "../types" }, diff --git a/yarn-project/sequencer-client/jest.config.ts b/yarn-project/sequencer-client/jest.config.ts deleted file mode 100644 index 9644a193478..00000000000 --- a/yarn-project/sequencer-client/jest.config.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { Config } from 'jest'; - -const config: Config = { - preset: 'ts-jest/presets/default-esm', - moduleNameMapper: { - '^(\\.{1,2}/.*)\\.[cm]?js$': '$1', - }, - testRegex: './src/.*\\.test\\.(js|mjs|ts)$', - rootDir: './src', - // extensionsToTreatAsEsm: ['.ts'], - // moduleFileExtensions: ['js', 'ts', 'cts'], - // transform: { - // '^.+\\.tsx?$': [ - // 'ts-jest', - // { - // useESM: true, - // }, - // ], - // }, -}; - -export default config; diff --git a/yarn-project/sequencer-client/package.json b/yarn-project/sequencer-client/package.json index 1db7f69a61b..5a1c48d0fa6 100644 --- a/yarn-project/sequencer-client/package.json +++ b/yarn-project/sequencer-client/package.json @@ -68,5 +68,13 @@ "types": "./dest/index.d.ts", "engines": { "node": ">=18" + }, + "jest": { + "preset": "ts-jest/presets/default-esm", + "moduleNameMapper": { + "^(\\.{1,2}/.*)\\.[cm]?js$": "$1" + }, + "testRegex": "./src/.*\\.test\\.(js|mjs|ts)$", + "rootDir": "./src" } } diff --git a/yarn-project/sequencer-client/tsconfig.json b/yarn-project/sequencer-client/tsconfig.json index d17fa6334ab..02b1b57f0dc 100644 --- a/yarn-project/sequencer-client/tsconfig.json +++ b/yarn-project/sequencer-client/tsconfig.json @@ -6,9 +6,6 @@ "tsBuildInfoFile": ".tsbuildinfo" }, "references": [ - { - "path": "../simulator" - }, { "path": "../circuit-types" }, @@ -33,6 +30,9 @@ { "path": "../p2p" }, + { + "path": "../simulator" + }, { "path": "../types" }, diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index 5d903bf814d..0b8a772cf03 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -2790,7 +2790,7 @@ __metadata: version: 0.0.0-use.local resolution: "@noir-lang/backend_barretenberg@portal:../noir/packages/backend_barretenberg::locator=%40aztec%2Faztec3-packages%40workspace%3A." dependencies: - "@aztec/bb.js": 0.21.0 + "@aztec/bb.js": 0.23.0 "@noir-lang/types": 0.23.0 fflate: ^0.8.0 languageName: node @@ -2809,14 +2809,14 @@ __metadata: "@noir-lang/noirc_abi@portal:../noir/packages/noirc_abi::locator=%40aztec%2Faztec3-packages%40workspace%3A.": version: 0.0.0-use.local resolution: "@noir-lang/noirc_abi@portal:../noir/packages/noirc_abi::locator=%40aztec%2Faztec3-packages%40workspace%3A." + dependencies: + "@noir-lang/types": 0.23.0 languageName: node linkType: soft "@noir-lang/types@portal:../noir/packages/types::locator=%40aztec%2Faztec3-packages%40workspace%3A.": version: 0.0.0-use.local resolution: "@noir-lang/types@portal:../noir/packages/types::locator=%40aztec%2Faztec3-packages%40workspace%3A." - dependencies: - "@noir-lang/noirc_abi": 0.23.0 languageName: node linkType: soft