diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6d6db808cf3..e92f513a023 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,11 +52,14 @@ jobs: run: earthly-ci ./yarn-project+export-e2e-test-images # We base our e2e list used in e2e-x86 off the targets in ./yarn-project/end-to-end # (Note ARM uses just 2 tests as a smoketest) - - name: Create list of end-to-end jobs + - name: Create list of non-bench end-to-end jobs id: e2e_list - run: echo "list=$(earthly ls ./yarn-project/end-to-end | grep -v '+base' | sed 's/+//' | jq -R . | jq -cs .)" >> $GITHUB_OUTPUT + run: echo "list=$(earthly ls ./yarn-project/end-to-end | grep -v '+base' | grep -v '+bench' | sed 's/+//' | jq -R . | jq -cs .)" >> $GITHUB_OUTPUT + - name: Create list of bench end-to-end jobs + id: bench_list + run: echo "list=$(earthly ls ./yarn-project/end-to-end | grep '+bench' | sed 's/+//' | jq -R . | jq -cs .)" >> $GITHUB_OUTPUT - # all the end-to-end integration tests for aztec + # all the non-bench end-to-end integration tests for aztec e2e: needs: build runs-on: ${{ inputs.username || github.actor }}-x86 @@ -81,6 +84,31 @@ jobs: --no-output \ +${{ matrix.test }} --skip_build=true + # all the benchmarking end-to-end integration tests for aztec (not required to merge) + bench-e2e: + needs: build + runs-on: ${{ inputs.username || github.actor }}-x86 + strategy: + fail-fast: false + matrix: + test: ${{ fromJson( needs.build.outputs.bench_list )}} + steps: + - uses: actions/checkout@v4 + with: { ref: "${{ github.event.pull_request.head.sha }}" } + - uses: ./.github/ci-setup-action + with: + dockerhub_password: "${{ secrets.DOCKERHUB_PASSWORD }}" + # must be globally unique for build x runner + concurrency_key: e2e-${{ inputs.username || github.actor }}-x86-${{ matrix.test }} + - name: Test + working-directory: ./yarn-project/end-to-end/ + timeout-minutes: 25 + run: earthly-ci -P \ + --secret AWS_ACCESS_KEY_ID=${{ secrets.AWS_ACCESS_KEY_ID }} \ + --secret AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }} \ + --no-output \ + +${{ matrix.test }} --skip_build=true + # bench-summary: # needs: e2e # runs-on: ${{ inputs.username || github.actor }}-x86 @@ -112,7 +140,7 @@ jobs: # barretenberg (prover) native and AVM (public VM) tests # only ran on x86 for resource reasons (memory intensive) bb-native-tests: - needs: build + needs: setup runs-on: ${{ inputs.username || github.actor }}-x86 steps: - { @@ -244,6 +272,22 @@ jobs: timeout-minutes: 25 run: earthly-ci --no-output ./yarn-project/+prover-client-test + client-proof-tests: + needs: build + runs-on: ${{ github.actor }}-x86 + steps: + - { + uses: actions/checkout@v4, + with: { ref: "${{ github.event.pull_request.head.sha }}" }, + } + - uses: ./.github/ci-setup-action + with: + dockerhub_password: "${{ secrets.DOCKERHUB_PASSWORD }}" + concurrency_key: client-proof-tests-${{ github.actor }}-x86 + - name: "Client Proof Tests" + timeout-minutes: 25 + run: earthly-ci --no-output ./yarn-project/+run-e2e --test=client_prover_integration/client_prover_integration.test.ts + build-acir-tests: needs: build runs-on: ${{ github.actor }}-x86 @@ -419,30 +463,6 @@ jobs: merge-check: runs-on: ubuntu-latest - needs: - - e2e - - bb-native-tests - - bb-bench - - yarn-project-formatting - - yarn-project-test - - prover-client-test - - noir-packages-test - - noir-test - if: always() - steps: - - run: | - echo "e2e status: ${{ needs.e2e.result }}" - echo "bb-native-tests status: ${{ needs.bb-native-tests.result }}" - echo "bb-bench status: ${{ needs.bb-bench.result }}" - echo "yarn-project-formatting status: ${{ needs.yarn-project-formatting.result }}" - echo "yarn-project-test status: ${{ needs.yarn-project-test.result }}" - if [[ "${{ needs.e2e.result }}" != 'success' || "${{ needs.bb-native-tests.result }}" != 'success' || "${{ needs.bb-bench.result }}" != 'success' || "${{ needs.yarn-project-formatting.result }}" != 'success' || "${{ needs.yarn-project-test.result }}" != 'success' ]]; then - echo "Pull request merging not allowed due to failures." - exit 1 - fi - echo "Pull request merging now allowed." - - notify: needs: [ e2e, @@ -451,7 +471,28 @@ jobs: yarn-project-formatting, yarn-project-test, prover-client-test, + bb-js-test, + barretenberg-acir-tests-bb-js, + barretenberg-acir-tests-bb, + barretenberg-acir-tests-sol, + noir-test, + noir-packages-test, + client-proof-tests, ] + if: always() + steps: + - run: | + failed=${{ contains(needs.*.result, 'failure') }} + if $failed + then + echo "At least one job failed, merging not allowed." + exit 1 + fi + echo "All jobs succeeded, merge allowed." + + notify: + needs: + - merge-check runs-on: ubuntu-latest if: ${{ github.ref == 'refs/heads/master' && failure() }} steps: diff --git a/.github/workflows/setup-runner.yml b/.github/workflows/setup-runner.yml index dff8f10cff3..658e5b581ba 100644 --- a/.github/workflows/setup-runner.yml +++ b/.github/workflows/setup-runner.yml @@ -147,4 +147,6 @@ jobs: fi - name: Run Earthly Bootstrap - run: earthly bootstrap + run: | + earthly bootstrap + touch /run/.earthly-bootstrap # Used in `earthly-ci` wrapper to check that earthly has been bootstrapped ok diff --git a/.github/workflows/start-spot.yml b/.github/workflows/start-spot.yml index b4ed1f3ca1b..eb13f205cb4 100644 --- a/.github/workflows/start-spot.yml +++ b/.github/workflows/start-spot.yml @@ -16,7 +16,7 @@ jobs: with: runner_label: ${{ inputs.username || github.actor }}-x86 ebs_cache_size_gb: 256 - runner_concurrency: 20 + runner_concurrency: 50 subaction: ${{ inputs.action }} # Use instance types with low interruption rate in us-east-2 https://aws.amazon.com/ec2/spot/instance-advisor/ ec2_instance_type: r6in.32xlarge r6a.32xlarge i4i.32xlarge r7iz.32xlarge diff --git a/.release-please-manifest.json b/.release-please-manifest.json index bcd45cb551a..1bd543620ee 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,7 +1,7 @@ { - ".": "0.37.0", + ".": "0.38.0", "yarn-project/cli": "0.35.1", - "yarn-project/aztec": "0.37.0", - "barretenberg": "0.37.0", - "barretenberg/ts": "0.37.0" + "yarn-project/aztec": "0.38.0", + "barretenberg": "0.38.0", + "barretenberg/ts": "0.38.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index ff67eb0ae7f..f4848f7f584 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,112 @@ # Changelog +## [0.38.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.37.0...aztec-packages-v0.38.0) (2024-05-07) + + +### ⚠ BREAKING CHANGES + +* AES blackbox ([#6016](https://github.com/AztecProtocol/aztec-packages/issues/6016)) + +### Features + +* `multi_scalar_mul` blackbox func ([#6097](https://github.com/AztecProtocol/aztec-packages/issues/6097)) ([f6b1ba6](https://github.com/AztecProtocol/aztec-packages/commit/f6b1ba60daf37a5a6466ca1e5ee7be70354af485)) +* Add `Neg` trait to stdlib (https://github.com/noir-lang/noir/pull/4983) ([02d3d17](https://github.com/AztecProtocol/aztec-packages/commit/02d3d177e86683aa77680127c3e6738bc22fdc02)) +* Add ciphertext computation for log header ([#6175](https://github.com/AztecProtocol/aztec-packages/issues/6175)) ([3e05534](https://github.com/AztecProtocol/aztec-packages/commit/3e0553456535cd32743f7cf33e51ffd8a36ff75d)) +* Add proving retries ([#6145](https://github.com/AztecProtocol/aztec-packages/issues/6145)) ([39ab99c](https://github.com/AztecProtocol/aztec-packages/commit/39ab99c3d0c819094b7eb39edd22c81322ca4627)) +* Add public teardown to circuit structs ([#6191](https://github.com/AztecProtocol/aztec-packages/issues/6191)) ([03e1b93](https://github.com/AztecProtocol/aztec-packages/commit/03e1b937db09dc64ac73960285849c4dd88e1f01)) +* AES blackbox ([#6016](https://github.com/AztecProtocol/aztec-packages/issues/6016)) ([e4b97a8](https://github.com/AztecProtocol/aztec-packages/commit/e4b97a8cd7574a828c2a54b4a93b5ced79df6abf)) +* Always including debug data in a function artifact ([#6223](https://github.com/AztecProtocol/aztec-packages/issues/6223)) ([5d6d22c](https://github.com/AztecProtocol/aztec-packages/commit/5d6d22ca416c6471428b56a55968e859334caa6a)) +* **avm-simulator:** Consider previous pending nullifiers across enqueued calls ([#6188](https://github.com/AztecProtocol/aztec-packages/issues/6188)) ([4676431](https://github.com/AztecProtocol/aztec-packages/commit/4676431ecf18003c6648e914effb1c3087108f0f)) +* **avm-simulator:** Make storage work across enqueued calls ([#6181](https://github.com/AztecProtocol/aztec-packages/issues/6181)) ([8e218a2](https://github.com/AztecProtocol/aztec-packages/commit/8e218a22c1f85e7b0de4afc4219a860e6bbab7fb)) +* **avm:** Add TransactionFee opcode to simulator ([#6210](https://github.com/AztecProtocol/aztec-packages/issues/6210)) ([fcac844](https://github.com/AztecProtocol/aztec-packages/commit/fcac84451f657bb4a70c496538b443dda5bc961e)) +* Complex outputs from acir call (https://github.com/noir-lang/noir/pull/4952) ([3ed41a0](https://github.com/AztecProtocol/aztec-packages/commit/3ed41a08c1fef80a6b8eecf4618dcc9be891e4c0)) +* Expose set_public_teardown_function in private context ([#6199](https://github.com/AztecProtocol/aztec-packages/issues/6199)) ([4d8b51c](https://github.com/AztecProtocol/aztec-packages/commit/4d8b51caf477ff83390ec6b40f11b0768e57903f)) +* Handle empty response foreign calls without an external resolver (https://github.com/noir-lang/noir/pull/4959) ([3ed41a0](https://github.com/AztecProtocol/aztec-packages/commit/3ed41a08c1fef80a6b8eecf4618dcc9be891e4c0)) +* Hash logs inside circuit ([#5934](https://github.com/AztecProtocol/aztec-packages/issues/5934)) ([6b99527](https://github.com/AztecProtocol/aztec-packages/commit/6b99527881345d7aa0dc90cfc61832432d817587)) +* Honk flows exposed through wasm ([#6096](https://github.com/AztecProtocol/aztec-packages/issues/6096)) ([c9b3206](https://github.com/AztecProtocol/aztec-packages/commit/c9b32061b2849442516ff0395b69d9a230191234)) +* Implement `From` array trait for `BoundedVec` (https://github.com/noir-lang/noir/pull/4927) ([02d3d17](https://github.com/AztecProtocol/aztec-packages/commit/02d3d177e86683aa77680127c3e6738bc22fdc02)) +* Include transaction fee in txreceipt ([#6139](https://github.com/AztecProtocol/aztec-packages/issues/6139)) ([6785512](https://github.com/AztecProtocol/aztec-packages/commit/6785512fff9dfec77bec5ce1580880c7ae21dce8)) +* Making keys getters complete ([#6171](https://github.com/AztecProtocol/aztec-packages/issues/6171)) ([e85dde9](https://github.com/AztecProtocol/aztec-packages/commit/e85dde9743c4e2e6c2f0dfd7bf487a2b4234d2b5)) +* Move noir-tests to earthly ([#6185](https://github.com/AztecProtocol/aztec-packages/issues/6185)) ([4daea40](https://github.com/AztecProtocol/aztec-packages/commit/4daea40fc8d994f25321ee6359ad37321ccd99dd)) +* Note hash read requests fixes and refactoring ([#6125](https://github.com/AztecProtocol/aztec-packages/issues/6125)) ([9d03f34](https://github.com/AztecProtocol/aztec-packages/commit/9d03f34ca023c954832889ee8eef65aca60f1b1b)) +* Optimize array sets in if conditions (alternate version) (https://github.com/noir-lang/noir/pull/4716) ([3ed41a0](https://github.com/AztecProtocol/aztec-packages/commit/3ed41a08c1fef80a6b8eecf4618dcc9be891e4c0)) +* Osxcross ([#6099](https://github.com/AztecProtocol/aztec-packages/issues/6099)) ([6cc924d](https://github.com/AztecProtocol/aztec-packages/commit/6cc924dc44a36d9ef2aeda05ea69a120898fc272)) +* Parsing non-string assertion payloads in noir js ([#6079](https://github.com/AztecProtocol/aztec-packages/issues/6079)) ([fbd78fd](https://github.com/AztecProtocol/aztec-packages/commit/fbd78fdc53071f3548971dfb4832a440512f4687)) +* Proving benchmark ([#6051](https://github.com/AztecProtocol/aztec-packages/issues/6051)) ([644bd85](https://github.com/AztecProtocol/aztec-packages/commit/644bd8525f6de8b71d6cc299baf3fda94b68abbb)) +* Proving the private kernels and app circuits ([#6112](https://github.com/AztecProtocol/aztec-packages/issues/6112)) ([4a43fab](https://github.com/AztecProtocol/aztec-packages/commit/4a43fab043d9974a80c259703ebe2e0027e8ae57)) +* Publish transaction_fee ([#6126](https://github.com/AztecProtocol/aztec-packages/issues/6126)) ([6f3a036](https://github.com/AztecProtocol/aztec-packages/commit/6f3a036585da589e04eb35b823ed2aaa7135bae5)) +* Recursive folding verifier and decider as ultra circuits and circuit simulator ([#6150](https://github.com/AztecProtocol/aztec-packages/issues/6150)) ([acc8641](https://github.com/AztecProtocol/aztec-packages/commit/acc86416668ccfd6425ee3af4a898f2e8513168b)) +* Reproducible ClientIVC proofs ([#6227](https://github.com/AztecProtocol/aztec-packages/issues/6227)) ([c145757](https://github.com/AztecProtocol/aztec-packages/commit/c145757a13ba4ff881c4bb05c4caaee7351053b3)) +* Run noir-packages-test in Earthly ([#6174](https://github.com/AztecProtocol/aztec-packages/issues/6174)) ([58e40c9](https://github.com/AztecProtocol/aztec-packages/commit/58e40c9125e6d7b30abf7a4cbb170bbfc15e2037)) +* Set aztec private functions to be recursive ([#6192](https://github.com/AztecProtocol/aztec-packages/issues/6192)) ([22625f8](https://github.com/AztecProtocol/aztec-packages/commit/22625f845f22703dc0d6e661fa36a0f67e6c719e)) +* Use actual tx fee in gas token when charging fee ([#6166](https://github.com/AztecProtocol/aztec-packages/issues/6166)) ([8418eac](https://github.com/AztecProtocol/aztec-packages/commit/8418eac301fc9761cc29efd901ca5f719c3dfa09)) + + +### Bug Fixes + +* **abstract-phase-manager:** Get available gas from latest kernel output ([#6102](https://github.com/AztecProtocol/aztec-packages/issues/6102)) ([0fa509b](https://github.com/AztecProtocol/aztec-packages/commit/0fa509b68da7a8ab1b5865d17a7cf4cb197eb8b3)) +* Aztec-run not exposing port for builder ([#6241](https://github.com/AztecProtocol/aztec-packages/issues/6241)) ([a80c091](https://github.com/AztecProtocol/aztec-packages/commit/a80c0911c629852d72bbff48b22af3b178b191b2)) +* Boxes use base image ([#6120](https://github.com/AztecProtocol/aztec-packages/issues/6120)) ([ef2589a](https://github.com/AztecProtocol/aztec-packages/commit/ef2589a41f72981e5245f294695c5da8d4f04d0e)) +* Compute the correct slice length when coercing from a literal array of complex types (https://github.com/noir-lang/noir/pull/4986) ([02d3d17](https://github.com/AztecProtocol/aztec-packages/commit/02d3d177e86683aa77680127c3e6738bc22fdc02)) +* Correct circuit size estimation for UltraHonk ([#6164](https://github.com/AztecProtocol/aztec-packages/issues/6164)) ([ed84fe3](https://github.com/AztecProtocol/aztec-packages/commit/ed84fe3bcc29c69b1e9d9caafd2c2c2134a67dce)) +* Docs release ci setup ([#6159](https://github.com/AztecProtocol/aztec-packages/issues/6159)) ([6d5cfe6](https://github.com/AztecProtocol/aztec-packages/commit/6d5cfe65dadf56b3f9094a2662b32792dd1a9520)) +* **docs:** Fix broken link in tree implementations page ([#6143](https://github.com/AztecProtocol/aztec-packages/issues/6143)) ([b39f1db](https://github.com/AztecProtocol/aztec-packages/commit/b39f1db91942096eb1768a37ba9ecfb94d4e1313)) +* **docs:** Update sandbox reference ([#6094](https://github.com/AztecProtocol/aztec-packages/issues/6094)) ([0641085](https://github.com/AztecProtocol/aztec-packages/commit/06410858fd1b6d0d8a1c225a08b8c6628ad9ddcc)) +* Increase default number of proving agents ([#6146](https://github.com/AztecProtocol/aztec-packages/issues/6146)) ([5ade36e](https://github.com/AztecProtocol/aztec-packages/commit/5ade36e63ad9d521efe62e889836de5e891e6d0b)) +* Install aztec-builder ([#6149](https://github.com/AztecProtocol/aztec-packages/issues/6149)) ([0497dcf](https://github.com/AztecProtocol/aztec-packages/commit/0497dcf4876b9e7bd7e7459f8d49a6167fd57323)) +* Move remove_if_else pass after second inlining (https://github.com/noir-lang/noir/pull/4976) ([02d3d17](https://github.com/AztecProtocol/aztec-packages/commit/02d3d177e86683aa77680127c3e6738bc22fdc02)) +* **public-kernel:** Only validate start-gas for execution requests ([#6100](https://github.com/AztecProtocol/aztec-packages/issues/6100)) ([3ec9303](https://github.com/AztecProtocol/aztec-packages/commit/3ec9303c4fe25eb8bf5b81e58dcf989acc8ac7e6)) +* Registering PublicDataWitness in JsonRpcServer ([#6243](https://github.com/AztecProtocol/aztec-packages/issues/6243)) ([e8c4455](https://github.com/AztecProtocol/aztec-packages/commit/e8c4455339ac0b4c7444aba7ff1308c10af4d139)) +* Scope netlify to yarn bin ([#6162](https://github.com/AztecProtocol/aztec-packages/issues/6162)) ([be8e3c0](https://github.com/AztecProtocol/aztec-packages/commit/be8e3c00837f7b823b74dfad7ef0875265ae35fe)) +* Set index and value to 0 for array_get with predicate (https://github.com/noir-lang/noir/pull/4971) ([02d3d17](https://github.com/AztecProtocol/aztec-packages/commit/02d3d177e86683aa77680127c3e6738bc22fdc02)) +* Set up the ci runner for doc deployment ([#6160](https://github.com/AztecProtocol/aztec-packages/issues/6160)) ([e295900](https://github.com/AztecProtocol/aztec-packages/commit/e2959004c132f87b876e7b08ed3b2c3eb99622bf)) +* Sporadic failure of GoblinRecursionTests.Vanilla ([#6218](https://github.com/AztecProtocol/aztec-packages/issues/6218)) ([f4ecea5](https://github.com/AztecProtocol/aztec-packages/commit/f4ecea5a83bcc88fd11698ac5c8e174c2461a74b)) +* Use annotated type when checking declaration (https://github.com/noir-lang/noir/pull/4966) ([3ed41a0](https://github.com/AztecProtocol/aztec-packages/commit/3ed41a08c1fef80a6b8eecf4618dcc9be891e4c0)) +* Use pushed build images. ([#6154](https://github.com/AztecProtocol/aztec-packages/issues/6154)) ([426f7a7](https://github.com/AztecProtocol/aztec-packages/commit/426f7a7c0911512058d5d5d49a3ed9f2ab5ed4e0)) +* Use random id for proving jobs ([#6084](https://github.com/AztecProtocol/aztec-packages/issues/6084)) ([0e0fc58](https://github.com/AztecProtocol/aztec-packages/commit/0e0fc585b9329371e5f89accf10ff1b7a08749c0)) +* Various aztec-builder issues ([#6233](https://github.com/AztecProtocol/aztec-packages/issues/6233)) ([9a644ba](https://github.com/AztecProtocol/aztec-packages/commit/9a644baeae7c46250ced9942ce30f3f8694efe7f)) + + +### Miscellaneous + +* Add avm team as codeowners for public context ([#6247](https://github.com/AztecProtocol/aztec-packages/issues/6247)) ([c571ff0](https://github.com/AztecProtocol/aztec-packages/commit/c571ff0545d54819dd5b386e1bbd932dbe603819)) +* **avm-simulator:** Avm's nested calls now stay internal and properly track PublicExecutionResult ([#6165](https://github.com/AztecProtocol/aztec-packages/issues/6165)) ([9fd4f39](https://github.com/AztecProtocol/aztec-packages/commit/9fd4f39e48793262d8d84e4ac0990c80072dcca3)) +* **avm-simulator:** Make shifts take u8 ([#5905](https://github.com/AztecProtocol/aztec-packages/issues/5905)) ([4719ff1](https://github.com/AztecProtocol/aztec-packages/commit/4719ff19e71e27965a3ccf75b7356a27389ee766)) +* **avm-simulator:** Track recursive public execution result in avm-simulator for integration with old kernel ([#6106](https://github.com/AztecProtocol/aztec-packages/issues/6106)) ([df3bcc6](https://github.com/AztecProtocol/aztec-packages/commit/df3bcc6315ba6ded3a352f7374888504ecc48eb9)) +* **aztec-macros:** Avm function return types are auto tagged as `pub` ([#6250](https://github.com/AztecProtocol/aztec-packages/issues/6250)) ([0e828f3](https://github.com/AztecProtocol/aztec-packages/commit/0e828f3914078850b9a8e1e928c886c59cfab64e)) +* **aztec-nr:** Create a 'with_selector' version of `emit_unencrypted_log` in avm context ([#6248](https://github.com/AztecProtocol/aztec-packages/issues/6248)) ([fda6442](https://github.com/AztecProtocol/aztec-packages/commit/fda64425ed673e2f4f4f7edc231b7a563ec5b0cc)) +* Bump bb.js timeouts ([#6196](https://github.com/AztecProtocol/aztec-packages/issues/6196)) ([acab3de](https://github.com/AztecProtocol/aztec-packages/commit/acab3de86aae9ce5078795ba1ed0626d0c018565)) +* Check root parity is only enqueued once its deps are ready ([#6015](https://github.com/AztecProtocol/aztec-packages/issues/6015)) ([c1120d1](https://github.com/AztecProtocol/aztec-packages/commit/c1120d16a68550934ab6744f8759b41f3dcdf4eb)) +* **ci:** Fix restarts with fresh spot, acir test fixes, non-mandatory benches ([#6226](https://github.com/AztecProtocol/aztec-packages/issues/6226)) ([adb7f37](https://github.com/AztecProtocol/aztec-packages/commit/adb7f37a4ad01acf1ef197189a1e78323cae8f0b)) +* **ci:** Force earthly prune if corrupted cache ([#6152](https://github.com/AztecProtocol/aztec-packages/issues/6152)) ([3910314](https://github.com/AztecProtocol/aztec-packages/commit/39103141a56f7f71fffb2d4164f0c4f432704a81)) +* **ci:** Improve dependency structure ([#6200](https://github.com/AztecProtocol/aztec-packages/issues/6200)) ([3abc862](https://github.com/AztecProtocol/aztec-packages/commit/3abc862f77b883382e6f03ec66c5fd93efef9989)) +* **ci:** Migrate `protocol-circuits-gate-diff` to earthly ([#6204](https://github.com/AztecProtocol/aztec-packages/issues/6204)) ([4b43295](https://github.com/AztecProtocol/aztec-packages/commit/4b432951a9fe46ca1b0e0d38ebafe523bebf04eb)) +* **ci:** More stable spot request ([#6212](https://github.com/AztecProtocol/aztec-packages/issues/6212)) ([00156b5](https://github.com/AztecProtocol/aztec-packages/commit/00156b566dbc2973ddc8a61550000e980f9c3454)) +* **ci:** Optimize e2e build ([#6202](https://github.com/AztecProtocol/aztec-packages/issues/6202)) ([4614059](https://github.com/AztecProtocol/aztec-packages/commit/4614059c9667d4b42063d47a2b4cc5b24d54db9b)) +* **ci:** Rollback earthly prune ([#6208](https://github.com/AztecProtocol/aztec-packages/issues/6208)) ([3ccc6ac](https://github.com/AztecProtocol/aztec-packages/commit/3ccc6acae834f9add0548c0ca044e65a2e13b08b)) +* **ci:** Try to make base image more stable ([#6144](https://github.com/AztecProtocol/aztec-packages/issues/6144)) ([979a22d](https://github.com/AztecProtocol/aztec-packages/commit/979a22d5668f5b46c350f2355b60da8bd59e2cda)) +* Debug log oracle calls return nothing ([#6209](https://github.com/AztecProtocol/aztec-packages/issues/6209)) ([151d3a3](https://github.com/AztecProtocol/aztec-packages/commit/151d3a3feaad5cf59041eac1b47f2bc31d1dbcf2)) +* **docs:** Fix some typos in specs of private kernel initial ([#6224](https://github.com/AztecProtocol/aztec-packages/issues/6224)) ([ead54c4](https://github.com/AztecProtocol/aztec-packages/commit/ead54c479ce221f6eed2b31fe37db82e615897ea)) +* E2e workaround ([#6158](https://github.com/AztecProtocol/aztec-packages/issues/6158)) ([7794d78](https://github.com/AztecProtocol/aztec-packages/commit/7794d788cb9675dbb4714f850e3a39d6dd3ce990)) +* Migrate acir tests to earthly ([#6142](https://github.com/AztecProtocol/aztec-packages/issues/6142)) ([18c8ea8](https://github.com/AztecProtocol/aztec-packages/commit/18c8ea8eb5f9fd1cb51c116d6d1976c774d51bc1)) +* Misc AVM migration prep changes ([#6253](https://github.com/AztecProtocol/aztec-packages/issues/6253)) ([fe19404](https://github.com/AztecProtocol/aztec-packages/commit/fe194043b6a7b7256b39b1db786b4df754b14890)) +* Nuking `GrumpkinScalar` ([#6240](https://github.com/AztecProtocol/aztec-packages/issues/6240)) ([d2df10d](https://github.com/AztecProtocol/aztec-packages/commit/d2df10d78036f6fb4e0dae5c7287e4523bd8b47d)) +* Release Noir(0.29.0) (https://github.com/noir-lang/noir/pull/4905) ([02d3d17](https://github.com/AztecProtocol/aztec-packages/commit/02d3d177e86683aa77680127c3e6738bc22fdc02)) +* Rename instruction checks for side effects (https://github.com/noir-lang/noir/pull/4945) ([3ed41a0](https://github.com/AztecProtocol/aztec-packages/commit/3ed41a08c1fef80a6b8eecf4618dcc9be891e4c0)) +* Replace relative paths to noir-protocol-circuits ([cf543a6](https://github.com/AztecProtocol/aztec-packages/commit/cf543a6ea944e49e9fff71e52620718385456428)) +* Replace relative paths to noir-protocol-circuits ([53cf7bb](https://github.com/AztecProtocol/aztec-packages/commit/53cf7bbc008fc1dae4c295901153d6751bf9eacd)) +* Replace relative paths to noir-protocol-circuits ([ca29cea](https://github.com/AztecProtocol/aztec-packages/commit/ca29cea33adda120adc90b3a32163625271af319)) +* Replace relative paths to noir-protocol-circuits ([08e538b](https://github.com/AztecProtocol/aztec-packages/commit/08e538b3ef0805270c498b3d65443378cf720985)) +* Speedup static_call test ([#6157](https://github.com/AztecProtocol/aztec-packages/issues/6157)) ([abe8875](https://github.com/AztecProtocol/aztec-packages/commit/abe8875fe40703419fcf12653a21d734e8028b4d)) +* Switch Noir JS to use execute program instead of circuit (https://github.com/noir-lang/noir/pull/4965) ([3ed41a0](https://github.com/AztecProtocol/aztec-packages/commit/3ed41a08c1fef80a6b8eecf4618dcc9be891e4c0)) +* Use correct call type ([#6064](https://github.com/AztecProtocol/aztec-packages/issues/6064)) ([b3ae289](https://github.com/AztecProtocol/aztec-packages/commit/b3ae289748954229aac7ae2e1fe72483ede79a52)) + + +### Documentation + +* Add GlobalVariables to CombinedConstantData ([#6071](https://github.com/AztecProtocol/aztec-packages/issues/6071)) ([cf026d2](https://github.com/AztecProtocol/aztec-packages/commit/cf026d2c5928ce081bfac1e0d85260075b06f418)) +* Update fees kernel tracking docs ([#6151](https://github.com/AztecProtocol/aztec-packages/issues/6151)) ([7d80428](https://github.com/AztecProtocol/aztec-packages/commit/7d804287889164873c5fdec452a9af0144bbe183)) + ## [0.37.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.36.0...aztec-packages-v0.37.0) (2024-05-02) diff --git a/CODEOWNERS b/CODEOWNERS index efa2632379c..cdd57834a49 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -2,7 +2,15 @@ /build_manifest.yml @charlielye # Notify the AVM team of any changes to public oracle. -/yarn-project/simulator/src/public/public_execution_context.ts @Maddiaa0 @fcarreiro +/yarn-project/simulator/src/public/public_execution_context.ts @Maddiaa0 @fcarreiro @dbanks12 # Notify the AVM team of changes to generated PIL code barretenberg/cpp/src/barretenberg/**/generated/* @Maddiaa0 @jeanmon @IlyasRidhuan + +# Notify the AVM team of any changes to public context or avm context. +/noir-projects/aztec-nr/aztec/src/context/inputs/public_context_inputs.nr @fcarreiro @dbanks12 +/noir-projects/aztec-nr/aztec/src/context/inputs/avm_context_inputs.nr @fcarreiro @dbanks12 +/noir-projects/aztec-nr/aztec/src/context/public_context.nr @fcarreiro @dbanks12 +/noir-projects/aztec-nr/aztec/src/context/avm_context.nr @fcarreiro @dbanks12 +/noir-projects/aztec-nr/aztec/src/context/interface.nr @fcarreiro @dbanks12 + diff --git a/avm-transpiler/Cargo.lock b/avm-transpiler/Cargo.lock index 89301797fbe..e0b11bd742a 100644 --- a/avm-transpiler/Cargo.lock +++ b/avm-transpiler/Cargo.lock @@ -51,6 +51,7 @@ dependencies = [ "blake3", "k256", "keccak", + "libaes", "num-bigint", "p256", "sha2", @@ -1127,6 +1128,12 @@ dependencies = [ "regex-automata", ] +[[package]] +name = "libaes" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82903360c009b816f5ab72a9b68158c27c301ee2c3f20655b55c5e589e7d3bb7" + [[package]] name = "libc" version = "0.2.153" diff --git a/avm-transpiler/src/transpile.rs b/avm-transpiler/src/transpile.rs index ecbc8f16f0c..314dc77414b 100644 --- a/avm-transpiler/src/transpile.rs +++ b/avm-transpiler/src/transpile.rs @@ -507,28 +507,42 @@ fn handle_emit_unencrypted_log( inputs.len() ); } - let (event_offset, message_array) = match &inputs[..] { - [ValueOrArray::MemoryAddress(offset), ValueOrArray::HeapArray(array)] => { - (offset.to_usize() as u32, array) + let event_offset = match &inputs[0] { + ValueOrArray::MemoryAddress(offset) => offset.to_usize() as u32, + _ => panic!( + "Unexpected inputs[0] (event) for ForeignCall::EMITUNENCRYPTEDLOG: {:?}", + inputs[0] + ), + }; + let (message_offset, message_size, message_offset_indirect) = match &inputs[1] { + ValueOrArray::HeapArray(array) => { + // Heap array, so offset to array is an indirect memory offset + (array.pointer.to_usize() as u32, array.size as u32, true) } + ValueOrArray::MemoryAddress(single_val) => (single_val.to_usize() as u32, 1 as u32, false), _ => panic!( "Unexpected inputs for ForeignCall::EMITUNENCRYPTEDLOG: {:?}", inputs ), }; + let indirect_flag = if message_offset_indirect { + FIRST_OPERAND_INDIRECT + } else { + 0 + }; avm_instrs.push(AvmInstruction { opcode: AvmOpcode::EMITUNENCRYPTEDLOG, // The message array from Brillig is indirect. - indirect: Some(FIRST_OPERAND_INDIRECT), + indirect: Some(indirect_flag), operands: vec![ AvmOperand::U32 { value: event_offset, }, AvmOperand::U32 { - value: message_array.pointer.to_usize() as u32, + value: message_offset, }, AvmOperand::U32 { - value: message_array.size as u32, + value: message_size, }, ], ..Default::default() diff --git a/barretenberg/.gitrepo b/barretenberg/.gitrepo index 9f9083e954d..02e8f6da718 100644 --- a/barretenberg/.gitrepo +++ b/barretenberg/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/AztecProtocol/barretenberg branch = master - commit = 59bbde3c076ba7cd7786e552d99bd3d6e175e78d - parent = f4ecea5a83bcc88fd11698ac5c8e174c2461a74b + commit = 7ffbebd1eb8f60fb77145842a31358522ad161b9 + parent = 856657fbd1f82b7526b3ff0214e3e6758db214e3 method = merge cmdver = 0.4.6 diff --git a/barretenberg/CHANGELOG.md b/barretenberg/CHANGELOG.md index fa599e687dc..08ba7134b53 100644 --- a/barretenberg/CHANGELOG.md +++ b/barretenberg/CHANGELOG.md @@ -1,5 +1,34 @@ # Changelog +## [0.38.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.37.0...barretenberg-v0.38.0) (2024-05-07) + + +### ⚠ BREAKING CHANGES + +* AES blackbox ([#6016](https://github.com/AztecProtocol/aztec-packages/issues/6016)) + +### Features + +* `multi_scalar_mul` blackbox func ([#6097](https://github.com/AztecProtocol/aztec-packages/issues/6097)) ([f6b1ba6](https://github.com/AztecProtocol/aztec-packages/commit/f6b1ba60daf37a5a6466ca1e5ee7be70354af485)) +* AES blackbox ([#6016](https://github.com/AztecProtocol/aztec-packages/issues/6016)) ([e4b97a8](https://github.com/AztecProtocol/aztec-packages/commit/e4b97a8cd7574a828c2a54b4a93b5ced79df6abf)) +* **avm:** Add TransactionFee opcode to simulator ([#6210](https://github.com/AztecProtocol/aztec-packages/issues/6210)) ([fcac844](https://github.com/AztecProtocol/aztec-packages/commit/fcac84451f657bb4a70c496538b443dda5bc961e)) +* Honk flows exposed through wasm ([#6096](https://github.com/AztecProtocol/aztec-packages/issues/6096)) ([c9b3206](https://github.com/AztecProtocol/aztec-packages/commit/c9b32061b2849442516ff0395b69d9a230191234)) +* Osxcross ([#6099](https://github.com/AztecProtocol/aztec-packages/issues/6099)) ([6cc924d](https://github.com/AztecProtocol/aztec-packages/commit/6cc924dc44a36d9ef2aeda05ea69a120898fc272)) +* Recursive folding verifier and decider as ultra circuits and circuit simulator ([#6150](https://github.com/AztecProtocol/aztec-packages/issues/6150)) ([acc8641](https://github.com/AztecProtocol/aztec-packages/commit/acc86416668ccfd6425ee3af4a898f2e8513168b)) +* Reproducible ClientIVC proofs ([#6227](https://github.com/AztecProtocol/aztec-packages/issues/6227)) ([c145757](https://github.com/AztecProtocol/aztec-packages/commit/c145757a13ba4ff881c4bb05c4caaee7351053b3)) + + +### Bug Fixes + +* Correct circuit size estimation for UltraHonk ([#6164](https://github.com/AztecProtocol/aztec-packages/issues/6164)) ([ed84fe3](https://github.com/AztecProtocol/aztec-packages/commit/ed84fe3bcc29c69b1e9d9caafd2c2c2134a67dce)) +* Sporadic failure of GoblinRecursionTests.Vanilla ([#6218](https://github.com/AztecProtocol/aztec-packages/issues/6218)) ([f4ecea5](https://github.com/AztecProtocol/aztec-packages/commit/f4ecea5a83bcc88fd11698ac5c8e174c2461a74b)) + + +### Miscellaneous + +* **ci:** Fix restarts with fresh spot, acir test fixes, non-mandatory benches ([#6226](https://github.com/AztecProtocol/aztec-packages/issues/6226)) ([adb7f37](https://github.com/AztecProtocol/aztec-packages/commit/adb7f37a4ad01acf1ef197189a1e78323cae8f0b)) +* Migrate acir tests to earthly ([#6142](https://github.com/AztecProtocol/aztec-packages/issues/6142)) ([18c8ea8](https://github.com/AztecProtocol/aztec-packages/commit/18c8ea8eb5f9fd1cb51c116d6d1976c774d51bc1)) + ## [0.37.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.36.0...barretenberg-v0.37.0) (2024-05-02) diff --git a/barretenberg/acir_tests/Dockerfile.bb b/barretenberg/acir_tests/Dockerfile.bb deleted file mode 100644 index 20cc12846df..00000000000 --- a/barretenberg/acir_tests/Dockerfile.bb +++ /dev/null @@ -1,26 +0,0 @@ -FROM aztecprotocol/barretenberg-x86_64-linux-clang-assert -FROM aztecprotocol/noir-compile-acir-tests as noir-acir-tests - -FROM node:18.19.0 -RUN apt update && apt install git bash curl jq coreutils -y -COPY --from=0 /usr/src/barretenberg/cpp/build /usr/src/barretenberg/cpp/build -COPY --from=noir-acir-tests /usr/src/noir/noir-repo/test_programs /usr/src/noir/noir-repo/test_programs -WORKDIR /usr/src/barretenberg/acir_tests -COPY . . -# Run every acir test through native bb build prove_then_verify flow for UltraPlonk. -# This ensures we test independent pk construction through real/garbage witness data paths. -RUN FLOW=prove_then_verify ./run_acir_tests.sh -# Construct and separately verify a UltraHonk proof for a single program -RUN FLOW=prove_then_verify_ultra_honk ./run_acir_tests.sh double_verify_nested_proof -# Construct and separately verify a GoblinUltraHonk proof for all acir programs -RUN FLOW=prove_then_verify_goblin_ultra_honk ./run_acir_tests.sh -# Construct and verify a UltraHonk proof for a single program -RUN FLOW=prove_and_verify_ultra_honk ./run_acir_tests.sh double_verify_nested_proof -# Construct and verify a Goblin UltraHonk (GUH) proof for a single arbitrary program -RUN FLOW=prove_and_verify_goblin_ultra_honk ./run_acir_tests.sh 6_array -# Construct and verify a UltraHonk proof for all ACIR programs using the new witness stack workflow -RUN FLOW=prove_and_verify_ultra_honk_program ./run_acir_tests.sh -# This is a "full" Goblin flow. It constructs and verifies four proofs: GoblinUltraHonk, ECCVM, Translator, and merge -RUN FLOW=prove_and_verify_goblin ./run_acir_tests.sh 6_array -# Run 1_mul through native bb build, all_cmds flow, to test all cli args. -RUN VERBOSE=1 FLOW=all_cmds ./run_acir_tests.sh 1_mul diff --git a/barretenberg/cpp/CMakeLists.txt b/barretenberg/cpp/CMakeLists.txt index 24b3836c41e..5a63e8b373f 100644 --- a/barretenberg/cpp/CMakeLists.txt +++ b/barretenberg/cpp/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.24 FATAL_ERROR) project( Barretenberg DESCRIPTION "BN254 elliptic curve library, and PLONK SNARK prover" - VERSION 0.37.0 # x-release-please-version + VERSION 0.38.0 # x-release-please-version LANGUAGES CXX C ) # Insert version into `bb` config file diff --git a/barretenberg/cpp/Earthfile b/barretenberg/cpp/Earthfile index 7d3c42a6e64..7d97dbfd191 100644 --- a/barretenberg/cpp/Earthfile +++ b/barretenberg/cpp/Earthfile @@ -180,6 +180,9 @@ test-clang-format: test: ARG hardware_concurrency="" + # prefetch + BUILD +test-binaries + BUILD +preset-release-assert-test BUILD +test-clang-format BUILD ./srs_db/+build # prefetch FROM +source diff --git a/barretenberg/cpp/src/CMakeLists.txt b/barretenberg/cpp/src/CMakeLists.txt index 7f7b588c58d..a9809f12c61 100644 --- a/barretenberg/cpp/src/CMakeLists.txt +++ b/barretenberg/cpp/src/CMakeLists.txt @@ -179,6 +179,7 @@ if(WASM) $ $ $ + $ $ $ $ diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp index eef0001e0c2..da85699eb47 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp @@ -53,7 +53,7 @@ bool ClientIVC::verify(Proof& proof, const std::vector& ver // Decider verification ClientIVC::FoldingVerifier folding_verifier({ verifier_instances[0], verifier_instances[1] }); - auto verifier_accumulator = folding_verifier.verify_folding_proof(proof.fold_proof); + auto verifier_accumulator = folding_verifier.verify_folding_proof(proof.folding_proof); ClientIVC::DeciderVerifier decider_verifier(verifier_accumulator); bool decision = decider_verifier.verify_proof(proof.decider_proof); diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp index f2e0ee309c3..6ef9a8676b6 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp @@ -37,9 +37,24 @@ class ClientIVC { // A full proof for the IVC scheme struct Proof { - FoldProof fold_proof; // final fold proof + FoldProof folding_proof; // final fold proof HonkProof decider_proof; Goblin::Proof goblin_proof; + + std::vector to_buffer() const + { + size_t proof_size = folding_proof.size() + decider_proof.size() + goblin_proof.size(); + + std::vector result; + result.reserve(proof_size); + const auto insert = [&result](const std::vector& buf) { + result.insert(result.end(), buf.begin(), buf.end()); + }; + insert(folding_proof); + insert(decider_proof); + insert(goblin_proof.to_buffer()); + return result; + } }; struct PrecomputedVerificationKeys { diff --git a/barretenberg/cpp/src/barretenberg/dsl/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/dsl/CMakeLists.txt index 9a62acd6356..158c5752774 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/dsl/CMakeLists.txt @@ -2,6 +2,7 @@ barretenberg_module( dsl plonk stdlib_sha256 + stdlib_aes128 stdlib_keccak stdlib_poseidon2 crypto_merkle_tree diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp index 6629707e6bf..f74228a115f 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp @@ -31,6 +31,11 @@ void build_constraints(Builder& builder, AcirFormat const& constraint_system, bo builder.create_range_constraint(constraint.witness, constraint.num_bits, ""); } + // Add aes128 constraints + for (const auto& constraint : constraint_system.aes128_constraints) { + create_aes128_constraints(builder, constraint); + } + // Add sha256 constraints for (const auto& constraint : constraint_system.sha256_constraints) { create_sha256_constraints(builder, constraint); diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp index bde98babdaa..8b7823260d0 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp @@ -1,4 +1,5 @@ #pragma once +#include "aes128_constraint.hpp" #include "barretenberg/common/slab_allocator.hpp" #include "barretenberg/serialize/msgpack.hpp" #include "bigint_constraint.hpp" @@ -35,6 +36,7 @@ struct AcirFormat { std::vector logic_constraints; std::vector range_constraints; + std::vector aes128_constraints; std::vector sha256_constraints; std::vector sha256_compression; std::vector schnorr_constraints; @@ -69,6 +71,7 @@ struct AcirFormat { public_inputs, logic_constraints, range_constraints, + aes128_constraints, sha256_constraints, sha256_compression, schnorr_constraints, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp index fa24b515465..2d23b057c64 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp @@ -35,6 +35,7 @@ TEST_F(AcirFormatTests, TestASingleConstraintNoPubInputs) .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, + .aes128_constraints = {}, .sha256_constraints = {}, .sha256_compression = {}, .schnorr_constraints = {}, @@ -151,6 +152,7 @@ TEST_F(AcirFormatTests, TestLogicGateFromNoirCircuit) .public_inputs = { 1 }, .logic_constraints = { logic_constraint }, .range_constraints = { range_a, range_b }, + .aes128_constraints = {}, .sha256_constraints = {}, .sha256_compression = {}, .schnorr_constraints = {}, @@ -219,6 +221,7 @@ TEST_F(AcirFormatTests, TestSchnorrVerifyPass) .public_inputs = {}, .logic_constraints = {}, .range_constraints = range_constraints, + .aes128_constraints = {}, .sha256_constraints = {}, .sha256_compression = {}, .schnorr_constraints = { schnorr_constraint }, @@ -314,6 +317,7 @@ TEST_F(AcirFormatTests, TestSchnorrVerifySmallRange) .public_inputs = {}, .logic_constraints = {}, .range_constraints = range_constraints, + .aes128_constraints = {}, .sha256_constraints = {}, .sha256_compression = {}, .schnorr_constraints = { schnorr_constraint }, @@ -428,6 +432,7 @@ TEST_F(AcirFormatTests, TestVarKeccak) .public_inputs = {}, .logic_constraints = {}, .range_constraints = { range_a, range_b, range_c, range_d }, + .aes128_constraints = {}, .sha256_constraints = {}, .sha256_compression = {}, .schnorr_constraints = {}, @@ -475,6 +480,7 @@ TEST_F(AcirFormatTests, TestKeccakPermutation) .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, + .aes128_constraints = {}, .sha256_constraints = {}, .sha256_compression = {}, .schnorr_constraints = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp index faaa3d4bb24..110087d40af 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp @@ -2,6 +2,7 @@ #include "acir_format.hpp" #include "barretenberg/common/container.hpp" #include "barretenberg/common/throw_or_abort.hpp" +#include "barretenberg/dsl/acir_format/aes128_constraint.hpp" #include "barretenberg/dsl/acir_format/bigint_constraint.hpp" #include "barretenberg/dsl/acir_format/blake2s_constraint.hpp" #include "barretenberg/dsl/acir_format/blake3_constraint.hpp" @@ -222,6 +223,31 @@ void handle_blackbox_func_call(Program::Opcode::BlackBoxFuncCall const& arg, Aci .witness = arg.input.witness.value, .num_bits = arg.input.num_bits, }); + } else if constexpr (std::is_same_v) { + af.aes128_constraints.push_back(AES128Constraint{ + .inputs = map(arg.inputs, + [](auto& e) { + return AES128Input{ + .witness = e.witness.value, + .num_bits = e.num_bits, + }; + }), + .iv = map(arg.iv, + [](auto& e) { + return AES128Input{ + .witness = e.witness.value, + .num_bits = e.num_bits, + }; + }), + .key = map(arg.key, + [](auto& e) { + return AES128Input{ + .witness = e.witness.value, + .num_bits = e.num_bits, + }; + }), + .outputs = map(arg.outputs, [](auto& e) { return e.value; }), + }); } else if constexpr (std::is_same_v) { af.sha256_constraints.push_back(Sha256Constraint{ .inputs = map(arg.inputs, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/aes128_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/aes128_constraint.cpp new file mode 100644 index 00000000000..48777aa8136 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/aes128_constraint.cpp @@ -0,0 +1,77 @@ +#include "aes128_constraint.hpp" +#include "barretenberg/stdlib/encryption/aes128/aes128.hpp" +#include +#include +#include + +namespace acir_format { + +template void create_aes128_constraints(Builder& builder, const AES128Constraint& constraint) +{ + + using field_ct = bb::stdlib::field_t; + + // Packs 16 bytes from the inputs (plaintext, iv, key) into a field element + const auto convert_input = [&](std::span inputs, size_t padding) { + field_ct converted = 0; + for (size_t i = 0; i < 16 - padding; ++i) { + converted *= 256; + field_ct byte = field_ct::from_witness_index(&builder, inputs[i].witness); + converted += byte; + } + for (size_t i = 0; i < padding; ++i) { + converted *= 256; + field_ct byte = padding; + converted += byte; + } + return converted; + }; + + // Packs 16 bytes from the outputs (witness indexes) into a field element for comparison + const auto convert_output = [&](std::span outputs) { + field_ct converted = 0; + for (const auto& output : outputs) { + converted *= 256; + field_ct byte = field_ct::from_witness_index(&builder, output); + converted += byte; + } + return converted; + }; + + const size_t padding_size = 16 - constraint.inputs.size() % 16; + + // Perform the conversions from array of bytes to field elements + std::vector converted_inputs; + for (size_t i = 0; i < constraint.inputs.size(); i += 16) { + field_ct to_add; + if (i + 16 > constraint.inputs.size()) { + to_add = convert_input( + std::span{ &constraint.inputs[i], 16 - padding_size }, + padding_size); + } else { + to_add = convert_input(std::span{ &constraint.inputs[i], 16 }, 0); + } + converted_inputs.emplace_back(to_add); + } + + std::vector converted_outputs; + for (size_t i = 0; i < constraint.outputs.size(); i += 16) { + std::span outputs{ &constraint.outputs[i], 16 }; + converted_outputs.emplace_back(convert_output(outputs)); + } + + const std::vector output_bytes = bb::stdlib::aes128::encrypt_buffer_cbc( + converted_inputs, convert_input(constraint.iv, 0), convert_input(constraint.key, 0)); + + for (size_t i = 0; i < output_bytes.size(); ++i) { + builder.assert_equal(output_bytes[i].normalize().witness_index, converted_outputs[i].normalize().witness_index); + } +} + +template void create_aes128_constraints(UltraCircuitBuilder& builder, + const AES128Constraint& constraint); + +template void create_aes128_constraints(GoblinUltraCircuitBuilder& builder, + const AES128Constraint& constraint); + +} // namespace acir_format diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/aes128_constraint.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/aes128_constraint.hpp new file mode 100644 index 00000000000..b0833c1e447 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/aes128_constraint.hpp @@ -0,0 +1,31 @@ +#pragma once +#include "barretenberg/dsl/types.hpp" +#include "barretenberg/serialize/msgpack.hpp" +#include +#include + +namespace acir_format { + +struct AES128Input { + uint32_t witness; + uint32_t num_bits; + + // For serialization, update with any new fields + MSGPACK_FIELDS(witness, num_bits); + friend bool operator==(AES128Input const& lhs, AES128Input const& rhs) = default; +}; + +struct AES128Constraint { + std::vector inputs; + std::array iv; + std::array key; + std::vector outputs; + + // For serialization, update with any new fields + MSGPACK_FIELDS(inputs, iv, key, outputs); + friend bool operator==(AES128Constraint const& lhs, AES128Constraint const& rhs) = default; +}; + +template void create_aes128_constraints(Builder& builder, const AES128Constraint& constraint); + +} // namespace acir_format diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.test.cpp index 47e3e64b435..863737703ef 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.test.cpp @@ -172,6 +172,7 @@ TEST_F(BigIntTests, TestBigIntConstraintMultiple) .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, + .aes128_constraints = {}, .sha256_constraints = {}, .sha256_compression = {}, .schnorr_constraints = {}, @@ -240,6 +241,7 @@ TEST_F(BigIntTests, TestBigIntConstraintSimple) .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, + .aes128_constraints = {}, .sha256_constraints = {}, .sha256_compression = {}, .schnorr_constraints = {}, @@ -293,6 +295,7 @@ TEST_F(BigIntTests, TestBigIntConstraintReuse) .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, + .aes128_constraints = {}, .sha256_constraints = {}, .sha256_compression = {}, .schnorr_constraints = {}, @@ -350,6 +353,7 @@ TEST_F(BigIntTests, TestBigIntConstraintReuse2) .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, + .aes128_constraints = {}, .sha256_constraints = {}, .sha256_compression = {}, .schnorr_constraints = {}, @@ -428,6 +432,7 @@ TEST_F(BigIntTests, TestBigIntDIV) .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, + .aes128_constraints = {}, .sha256_constraints = {}, .sha256_compression = {}, .schnorr_constraints = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp index 39424f4c3a1..7cb3e5955bd 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp @@ -114,6 +114,7 @@ TEST_F(UltraPlonkRAM, TestBlockConstraint) .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, + .aes128_constraints = {}, .sha256_constraints = {}, .sha256_compression = {}, .schnorr_constraints = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp index 0fb59c5b03a..fb676af0a8b 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp @@ -54,6 +54,7 @@ TEST_F(EcOperations, TestECOperations) .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, + .aes128_constraints = {}, .sha256_constraints = {}, .sha256_compression = {}, .schnorr_constraints = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp index 2dd20037387..20dddfe4abe 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp @@ -94,6 +94,7 @@ TEST_F(ECDSASecp256k1, TestECDSAConstraintSucceed) .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, + .aes128_constraints = {}, .sha256_constraints = {}, .sha256_compression = {}, .schnorr_constraints = {}, @@ -143,6 +144,7 @@ TEST_F(ECDSASecp256k1, TestECDSACompilesForVerifier) .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, + .aes128_constraints = {}, .sha256_constraints = {}, .sha256_compression = {}, .schnorr_constraints = {}, @@ -187,6 +189,7 @@ TEST_F(ECDSASecp256k1, TestECDSAConstraintFail) .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, + .aes128_constraints = {}, .sha256_constraints = {}, .sha256_compression = {}, .schnorr_constraints = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp index 19b87a26ddd..6217149fdf0 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp @@ -128,6 +128,7 @@ TEST(ECDSASecp256r1, test_hardcoded) .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, + .aes128_constraints = {}, .sha256_constraints = {}, .sha256_compression = {}, .schnorr_constraints = {}, @@ -179,6 +180,7 @@ TEST(ECDSASecp256r1, TestECDSAConstraintSucceed) .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, + .aes128_constraints = {}, .sha256_constraints = {}, .sha256_compression = {}, .schnorr_constraints = {}, @@ -228,6 +230,7 @@ TEST(ECDSASecp256r1, TestECDSACompilesForVerifier) .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, + .aes128_constraints = {}, .sha256_constraints = {}, .sha256_compression = {}, .schnorr_constraints = {}, @@ -272,6 +275,7 @@ TEST(ECDSASecp256r1, TestECDSAConstraintFail) .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, + .aes128_constraints = {}, .sha256_constraints = {}, .sha256_compression = {}, .schnorr_constraints = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/poseidon2_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/poseidon2_constraint.test.cpp index ee230848b55..d35a9d36974 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/poseidon2_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/poseidon2_constraint.test.cpp @@ -34,6 +34,7 @@ TEST_F(Poseidon2Tests, TestPoseidon2Permutation) .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, + .aes128_constraints = {}, .sha256_constraints = {}, .sha256_compression = {}, .schnorr_constraints = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp index 031095f95be..0b12a411951 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp @@ -86,6 +86,7 @@ Builder create_inner_circuit() .public_inputs = { 1, 2 }, .logic_constraints = { logic_constraint }, .range_constraints = { range_a, range_b }, + .aes128_constraints = {}, .sha256_constraints = {}, .sha256_compression = {}, .schnorr_constraints = {}, @@ -243,6 +244,7 @@ Builder create_outer_circuit(std::vector& inner_circuits) .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, + .aes128_constraints = {}, .sha256_constraints = {}, .sha256_compression = {}, .schnorr_constraints = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp index 561e7021683..171bcfa280e 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp @@ -24,6 +24,17 @@ struct FunctionInput { struct BlackBoxFuncCall { + struct AES128Encrypt { + std::vector inputs; + std::array iv; + std::array key; + std::vector outputs; + + friend bool operator==(const AES128Encrypt&, const AES128Encrypt&); + std::vector bincodeSerialize() const; + static AES128Encrypt bincodeDeserialize(std::vector); + }; + struct AND { Program::FunctionInput lhs; Program::FunctionInput rhs; @@ -266,7 +277,8 @@ struct BlackBoxFuncCall { static Sha256Compression bincodeDeserialize(std::vector); }; - std::variant bincodeSerialize() const; + static AES128Encrypt bincodeDeserialize(std::vector); + }; + struct Sha256 { Program::HeapVector message; Program::HeapArray output; @@ -844,7 +868,8 @@ struct BlackBoxOp { static Sha256Compression bincodeDeserialize(std::vector); }; - std::variant::dese namespace Program { +inline bool operator==(const BlackBoxFuncCall::AES128Encrypt& lhs, const BlackBoxFuncCall::AES128Encrypt& rhs) +{ + if (!(lhs.inputs == rhs.inputs)) { + return false; + } + if (!(lhs.iv == rhs.iv)) { + return false; + } + if (!(lhs.key == rhs.key)) { + return false; + } + if (!(lhs.outputs == rhs.outputs)) { + return false; + } + return true; +} + +inline std::vector BlackBoxFuncCall::AES128Encrypt::bincodeSerialize() const +{ + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); +} + +inline BlackBoxFuncCall::AES128Encrypt BlackBoxFuncCall::AES128Encrypt::bincodeDeserialize(std::vector input) +{ + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw_or_abort("Some input bytes were not read"); + } + return value; +} + +} // end of namespace Program + +template <> +template +void serde::Serializable::serialize( + const Program::BlackBoxFuncCall::AES128Encrypt& obj, Serializer& serializer) +{ + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.iv, serializer); + serde::Serializable::serialize(obj.key, serializer); + serde::Serializable::serialize(obj.outputs, serializer); +} + +template <> +template +Program::BlackBoxFuncCall::AES128Encrypt serde::Deserializable::deserialize( + Deserializer& deserializer) +{ + Program::BlackBoxFuncCall::AES128Encrypt obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.iv = serde::Deserializable::deserialize(deserializer); + obj.key = serde::Deserializable::deserialize(deserializer); + obj.outputs = serde::Deserializable::deserialize(deserializer); + return obj; +} + +namespace Program { + inline bool operator==(const BlackBoxFuncCall::AND& lhs, const BlackBoxFuncCall::AND& rhs) { if (!(lhs.lhs == rhs.lhs)) { @@ -3813,6 +3900,71 @@ Program::BlackBoxOp serde::Deserializable::deserialize(Dese namespace Program { +inline bool operator==(const BlackBoxOp::AES128Encrypt& lhs, const BlackBoxOp::AES128Encrypt& rhs) +{ + if (!(lhs.inputs == rhs.inputs)) { + return false; + } + if (!(lhs.iv == rhs.iv)) { + return false; + } + if (!(lhs.key == rhs.key)) { + return false; + } + if (!(lhs.length == rhs.length)) { + return false; + } + if (!(lhs.outputs == rhs.outputs)) { + return false; + } + return true; +} + +inline std::vector BlackBoxOp::AES128Encrypt::bincodeSerialize() const +{ + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); +} + +inline BlackBoxOp::AES128Encrypt BlackBoxOp::AES128Encrypt::bincodeDeserialize(std::vector input) +{ + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw_or_abort("Some input bytes were not read"); + } + return value; +} + +} // end of namespace Program + +template <> +template +void serde::Serializable::serialize(const Program::BlackBoxOp::AES128Encrypt& obj, + Serializer& serializer) +{ + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.iv, serializer); + serde::Serializable::serialize(obj.key, serializer); + serde::Serializable::serialize(obj.outputs, serializer); +} + +template <> +template +Program::BlackBoxOp::AES128Encrypt serde::Deserializable::deserialize( + Deserializer& deserializer) +{ + Program::BlackBoxOp::AES128Encrypt obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.iv = serde::Deserializable::deserialize(deserializer); + obj.key = serde::Deserializable::deserialize(deserializer); + obj.outputs = serde::Deserializable::deserialize(deserializer); + return obj; +} + +namespace Program { + inline bool operator==(const BlackBoxOp::Sha256& lhs, const BlackBoxOp::Sha256& rhs) { if (!(lhs.message == rhs.message)) { diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/sha256_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/sha256_constraint.test.cpp index 54457630b67..4b78a9550e7 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/sha256_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/sha256_constraint.test.cpp @@ -36,6 +36,7 @@ TEST_F(Sha256Tests, TestSha256Compression) .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, + .aes128_constraints = {}, .sha256_constraints = {}, .sha256_compression = { sha256_compression }, .schnorr_constraints = {}, diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_circuit_builder.test.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_circuit_builder.test.cpp index 253c1af019c..b5cb7698360 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_circuit_builder.test.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_circuit_builder.test.cpp @@ -39,7 +39,7 @@ TEST(ECCVMCircuitBuilderTests, BaseCase) op_queue->mul_accumulate(c, x); ECCVMCircuitBuilder circuit{ op_queue }; - bool result = ECCVMTraceChecker::check(circuit); + bool result = ECCVMTraceChecker::check(circuit, &engine); EXPECT_EQ(result, true); } @@ -53,7 +53,7 @@ TEST(ECCVMCircuitBuilderTests, Add) op_queue->add_accumulate(a); ECCVMCircuitBuilder circuit{ op_queue }; - bool result = ECCVMTraceChecker::check(circuit); + bool result = ECCVMTraceChecker::check(circuit, &engine); EXPECT_EQ(result, true); } @@ -68,7 +68,7 @@ TEST(ECCVMCircuitBuilderTests, Mul) op_queue->mul_accumulate(a, x); ECCVMCircuitBuilder circuit{ op_queue }; - bool result = ECCVMTraceChecker::check(circuit); + bool result = ECCVMTraceChecker::check(circuit, &engine); EXPECT_EQ(result, true); } @@ -89,7 +89,7 @@ TEST(ECCVMCircuitBuilderTests, ShortMul) op_queue->eq_and_reset(); ECCVMCircuitBuilder circuit{ op_queue }; - bool result = ECCVMTraceChecker::check(circuit); + bool result = ECCVMTraceChecker::check(circuit, &engine); EXPECT_EQ(result, true); } @@ -106,7 +106,7 @@ TEST(ECCVMCircuitBuilderTests, EqFails) op_queue->add_erroneous_equality_op_for_testing(); ECCVMCircuitBuilder circuit{ op_queue }; - bool result = ECCVMTraceChecker::check(circuit); + bool result = ECCVMTraceChecker::check(circuit, &engine); EXPECT_EQ(result, false); } @@ -117,7 +117,7 @@ TEST(ECCVMCircuitBuilderTests, EmptyRow) op_queue->empty_row_for_testing(); ECCVMCircuitBuilder circuit{ op_queue }; - bool result = ECCVMTraceChecker::check(circuit); + bool result = ECCVMTraceChecker::check(circuit, &engine); EXPECT_EQ(result, true); } @@ -134,7 +134,7 @@ TEST(ECCVMCircuitBuilderTests, EmptyRowBetweenOps) op_queue->eq_and_reset(); ECCVMCircuitBuilder circuit{ op_queue }; - bool result = ECCVMTraceChecker::check(circuit); + bool result = ECCVMTraceChecker::check(circuit, &engine); EXPECT_EQ(result, true); } @@ -150,7 +150,7 @@ TEST(ECCVMCircuitBuilderTests, EndWithEq) op_queue->eq_and_reset(); ECCVMCircuitBuilder circuit{ op_queue }; - bool result = ECCVMTraceChecker::check(circuit); + bool result = ECCVMTraceChecker::check(circuit, &engine); EXPECT_EQ(result, true); } @@ -167,7 +167,7 @@ TEST(ECCVMCircuitBuilderTests, EndWithAdd) op_queue->add_accumulate(a); ECCVMCircuitBuilder circuit{ op_queue }; - bool result = ECCVMTraceChecker::check(circuit); + bool result = ECCVMTraceChecker::check(circuit, &engine); EXPECT_EQ(result, true); } @@ -184,7 +184,7 @@ TEST(ECCVMCircuitBuilderTests, EndWithMul) op_queue->mul_accumulate(a, x); ECCVMCircuitBuilder circuit{ op_queue }; - bool result = ECCVMTraceChecker::check(circuit); + bool result = ECCVMTraceChecker::check(circuit, &engine); EXPECT_EQ(result, true); } @@ -202,7 +202,7 @@ TEST(ECCVMCircuitBuilderTests, EndWithNoop) op_queue->empty_row_for_testing(); ECCVMCircuitBuilder circuit{ op_queue }; - bool result = ECCVMTraceChecker::check(circuit); + bool result = ECCVMTraceChecker::check(circuit, &engine); EXPECT_EQ(result, true); } @@ -240,6 +240,6 @@ TEST(ECCVMCircuitBuilderTests, MSM) compute_msms(j, op_queue); } ECCVMCircuitBuilder circuit{ op_queue }; - bool result = ECCVMTraceChecker::check(circuit); + bool result = ECCVMTraceChecker::check(circuit, &engine); EXPECT_EQ(result, true); } diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_trace_checker.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_trace_checker.cpp index c8acc2400be..24c440f3303 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_trace_checker.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_trace_checker.cpp @@ -9,10 +9,10 @@ using Builder = typename ECCVMFlavor::CircuitBuilder; using FF = typename ECCVMFlavor::FF; using ProverPolynomials = typename ECCVMFlavor::ProverPolynomials; -bool ECCVMTraceChecker::check(Builder& builder) +bool ECCVMTraceChecker::check(Builder& builder, numeric::RNG* engine_ptr) { - const FF gamma = FF::random_element(); - const FF beta = FF::random_element(); + const FF gamma = FF::random_element(engine_ptr); + const FF beta = FF::random_element(engine_ptr); const FF beta_sqr = beta.sqr(); const FF beta_cube = beta_sqr * beta; auto eccvm_set_permutation_delta = diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_trace_checker.hpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_trace_checker.hpp index 1dc84fb33e8..fdb918dee41 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_trace_checker.hpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_trace_checker.hpp @@ -4,6 +4,6 @@ namespace bb { class ECCVMTraceChecker { public: - static bool check(ECCVMCircuitBuilder&); + static bool check(ECCVMCircuitBuilder&, numeric::RNG* engine_ptr = nullptr); }; } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp index f8b6adc61dd..3823a510059 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp @@ -52,21 +52,24 @@ class Goblin { HonkProof eccvm_proof; HonkProof translator_proof; TranslationEvaluations translation_evaluations; - std::vector to_buffer() + + size_t size() const { - // ACIRHACK: so much copying and duplication added here and elsewhere - std::vector translation_evaluations_buf; // = translation_evaluations.to_buffer(); - size_t proof_size = - merge_proof.size() + eccvm_proof.size() + translator_proof.size() + translation_evaluations_buf.size(); + return merge_proof.size() + eccvm_proof.size() + translator_proof.size() + TranslationEvaluations::size(); + }; - std::vector result(proof_size); + std::vector to_buffer() const + { + // ACIRHACK: so much copying and duplication added here and elsewhere + std::vector result; + result.reserve(size()); const auto insert = [&result](const std::vector& buf) { result.insert(result.end(), buf.begin(), buf.end()); }; insert(merge_proof); insert(eccvm_proof); insert(translator_proof); - insert(translation_evaluations_buf); + insert(translation_evaluations.to_buffer()); return result; } }; diff --git a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp index e6457060f6f..46586ff58da 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp @@ -17,6 +17,7 @@ #include "barretenberg/stdlib_circuit_builders/mock_circuits.hpp" namespace bb { + class GoblinMockCircuits { public: using Curve = curve::BN254; @@ -120,8 +121,8 @@ class GoblinMockCircuits { { // Add some arbitrary ecc op gates for (size_t i = 0; i < 3; ++i) { - auto point = Point::random_element(); - auto scalar = FF::random_element(); + auto point = Point::random_element(&engine); + auto scalar = FF::random_element(&engine); builder.queue_ecc_add_accum(point); builder.queue_ecc_mul_accum(point, scalar); } diff --git a/barretenberg/cpp/src/barretenberg/goblin/translation_evaluations.hpp b/barretenberg/cpp/src/barretenberg/goblin/translation_evaluations.hpp index 6dcee0e24fd..5495504296d 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/translation_evaluations.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/translation_evaluations.hpp @@ -1,14 +1,18 @@ #pragma once #include "barretenberg/ecc/curves/bn254/fq.hpp" +#include "barretenberg/ecc/fields/field_conversion.hpp" namespace bb { struct TranslationEvaluations { fq op, Px, Py, z1, z2; - std::vector to_buffer() + static constexpr uint32_t NUM_EVALUATIONS = 5; + static size_t size() { return field_conversion::calc_num_bn254_frs() * NUM_EVALUATIONS; } + std::vector to_buffer() const { - std::vector result(5 * sizeof(fq)); + std::vector result; + result.reserve(size()); const auto insert = [&result](const fq& elt) { - std::vector buf = elt.to_buffer(); + std::vector buf = field_conversion::convert_to_bn254_frs(elt); result.insert(result.end(), buf.begin(), buf.end()); }; insert(op); diff --git a/barretenberg/cpp/src/barretenberg/numeric/random/engine.cpp b/barretenberg/cpp/src/barretenberg/numeric/random/engine.cpp index e8b5c4a940a..0c3604cb92a 100644 --- a/barretenberg/cpp/src/barretenberg/numeric/random/engine.cpp +++ b/barretenberg/cpp/src/barretenberg/numeric/random/engine.cpp @@ -79,7 +79,7 @@ class DebugEngine : public RNG { : engine(std::mt19937_64(12345)) {} - DebugEngine(std::seed_seq& seed) + DebugEngine(std::uint_fast64_t seed) : engine(std::mt19937_64(seed)) {} @@ -116,12 +116,12 @@ class DebugEngine : public RNG { /** * Used by tests to ensure consistent behavior. */ -RNG& get_debug_randomness(bool reset) +RNG& get_debug_randomness(bool reset, std::uint_fast64_t seed) { // static std::seed_seq seed({ 1, 2, 3, 4, 5 }); - static DebugEngine debug_engine; + static DebugEngine debug_engine = DebugEngine(); if (reset) { - debug_engine = DebugEngine(); + debug_engine = DebugEngine(seed); } return debug_engine; } diff --git a/barretenberg/cpp/src/barretenberg/numeric/random/engine.hpp b/barretenberg/cpp/src/barretenberg/numeric/random/engine.hpp index aad7932bbbf..0e54341ea91 100644 --- a/barretenberg/cpp/src/barretenberg/numeric/random/engine.hpp +++ b/barretenberg/cpp/src/barretenberg/numeric/random/engine.hpp @@ -4,6 +4,7 @@ #include "../uintx/uintx.hpp" #include "unistd.h" #include +#include namespace bb::numeric { @@ -45,7 +46,7 @@ class RNG { } }; -RNG& get_debug_randomness(bool reset = false); +RNG& get_debug_randomness(bool reset = false, std::uint_fast64_t seed = 12345); RNG& get_randomness(); } // namespace bb::numeric diff --git a/barretenberg/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa_impl.hpp b/barretenberg/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa_impl.hpp index ae6731c06a7..a40ba91f45d 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa_impl.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa_impl.hpp @@ -7,6 +7,10 @@ namespace bb::stdlib { +namespace { +auto& engine = numeric::get_debug_randomness(); +} + /** * @brief Verify ECDSA signature. Produces unsatisfiable constraints if signature fails * @@ -241,7 +245,7 @@ template void generate_ecdsa_verification_test_circuit(Builde crypto::ecdsa_key_pair account; for (size_t i = 0; i < num_iterations; i++) { // Generate unique signature for each iteration - account.private_key = curve::fr::random_element(); + account.private_key = curve::fr::random_element(&engine); account.public_key = curve::g1::one * account.private_key; crypto::ecdsa_signature signature = diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/goblin_ultra_circuit_builder.cpp b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/goblin_ultra_circuit_builder.cpp index 58542f3e151..dd12ae51109 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/goblin_ultra_circuit_builder.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/goblin_ultra_circuit_builder.cpp @@ -92,7 +92,7 @@ template void GoblinUltraCircuitBuilder_::add_goblin_gates_to_ this->blocks.poseidon_internal, this->zero_idx, this->zero_idx, this->zero_idx, this->zero_idx); // add dummy mul accum op and an equality op - this->queue_ecc_mul_accum(bb::g1::affine_element::one() * FF::random_element(), FF::random_element()); + this->queue_ecc_mul_accum(bb::g1::affine_element::one(), 2); this->queue_ecc_eq(); } diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/mock_circuits.hpp b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/mock_circuits.hpp index 36937d8c347..a7d72d7e53e 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/mock_circuits.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/mock_circuits.hpp @@ -3,6 +3,9 @@ namespace bb { +namespace { +auto& engine = numeric::get_debug_randomness(); +} class MockCircuits { public: using Curve = curve::BN254; @@ -20,9 +23,9 @@ class MockCircuits { { // For good measure, include a gate with some public inputs for (size_t i = 0; i < num_gates; ++i) { - FF a = FF::random_element(); - FF b = FF::random_element(); - FF c = FF::random_element(); + FF a = FF::random_element(&engine); + FF b = FF::random_element(&engine); + FF c = FF::random_element(&engine); FF d = a + b + c; uint32_t a_idx = builder.add_public_variable(a); uint32_t b_idx = builder.add_variable(b); @@ -43,9 +46,9 @@ class MockCircuits { { // For good measure, include a gate with some public inputs for (size_t i = 0; i < num_gates; ++i) { - FF a = FF::random_element(); - FF b = FF::random_element(); - FF c = FF::random_element(); + FF a = FF::random_element(&engine); + FF b = FF::random_element(&engine); + FF c = FF::random_element(&engine); FF d = a + b + c; uint32_t a_idx = builder.add_variable(a); uint32_t b_idx = builder.add_variable(b); @@ -98,8 +101,8 @@ class MockCircuits { static void construct_goblin_ecc_op_circuit(GoblinUltraCircuitBuilder& builder) { // Add a mul accum op, an add accum op and an equality op - builder.queue_ecc_add_accum(Point::one() * FF::random_element()); - builder.queue_ecc_mul_accum(Point::one() * FF::random_element(), FF::random_element()); + builder.queue_ecc_add_accum(Point::one() * FF::random_element(&engine)); + builder.queue_ecc_mul_accum(Point::one() * FF::random_element(&engine), FF::random_element(&engine)); builder.queue_ecc_eq(); } }; diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.test.cpp index 564afd23c4a..330a2ab8c14 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.test.cpp @@ -16,10 +16,6 @@ using namespace bb; -namespace { -auto& engine = numeric::get_debug_randomness(); -} - using ProverInstance = ProverInstance_; using VerificationKey = UltraFlavor::VerificationKey; diff --git a/barretenberg/ts/CHANGELOG.md b/barretenberg/ts/CHANGELOG.md index 6da5a887ff7..ef2feb322d5 100644 --- a/barretenberg/ts/CHANGELOG.md +++ b/barretenberg/ts/CHANGELOG.md @@ -1,5 +1,25 @@ # Changelog +## [0.38.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.37.0...barretenberg.js-v0.38.0) (2024-05-07) + + +### ⚠ BREAKING CHANGES + +* AES blackbox ([#6016](https://github.com/AztecProtocol/aztec-packages/issues/6016)) + +### Features + +* `multi_scalar_mul` blackbox func ([#6097](https://github.com/AztecProtocol/aztec-packages/issues/6097)) ([f6b1ba6](https://github.com/AztecProtocol/aztec-packages/commit/f6b1ba60daf37a5a6466ca1e5ee7be70354af485)) +* AES blackbox ([#6016](https://github.com/AztecProtocol/aztec-packages/issues/6016)) ([e4b97a8](https://github.com/AztecProtocol/aztec-packages/commit/e4b97a8cd7574a828c2a54b4a93b5ced79df6abf)) +* Honk flows exposed through wasm ([#6096](https://github.com/AztecProtocol/aztec-packages/issues/6096)) ([c9b3206](https://github.com/AztecProtocol/aztec-packages/commit/c9b32061b2849442516ff0395b69d9a230191234)) +* Run noir-packages-test in Earthly ([#6174](https://github.com/AztecProtocol/aztec-packages/issues/6174)) ([58e40c9](https://github.com/AztecProtocol/aztec-packages/commit/58e40c9125e6d7b30abf7a4cbb170bbfc15e2037)) + + +### Miscellaneous + +* Bump bb.js timeouts ([#6196](https://github.com/AztecProtocol/aztec-packages/issues/6196)) ([acab3de](https://github.com/AztecProtocol/aztec-packages/commit/acab3de86aae9ce5078795ba1ed0626d0c018565)) +* Migrate acir tests to earthly ([#6142](https://github.com/AztecProtocol/aztec-packages/issues/6142)) ([18c8ea8](https://github.com/AztecProtocol/aztec-packages/commit/18c8ea8eb5f9fd1cb51c116d6d1976c774d51bc1)) + ## [0.37.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.36.0...barretenberg.js-v0.37.0) (2024-05-02) diff --git a/barretenberg/ts/package.json b/barretenberg/ts/package.json index e5a546e963c..ad49f2f53a4 100644 --- a/barretenberg/ts/package.json +++ b/barretenberg/ts/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/bb.js", - "version": "0.37.0", + "version": "0.38.0", "homepage": "https://github.com/AztecProtocol/aztec-packages/tree/master/barretenberg/ts", "license": "MIT", "type": "module", diff --git a/barretenberg/ts/src/info.ts b/barretenberg/ts/src/info.ts index 04e33525400..f5ad9980591 100644 --- a/barretenberg/ts/src/info.ts +++ b/barretenberg/ts/src/info.ts @@ -9,6 +9,7 @@ export const acvmInfoJson = { 'and', 'xor', 'range', + 'aes128_encrypt', 'sha256', 'blake2s', 'keccak256', diff --git a/cspell.json b/cspell.json index 6c2ce17a407..6e0ff296264 100644 --- a/cspell.json +++ b/cspell.json @@ -66,6 +66,12 @@ "defi", "delegatecall", "delegatecalls", + "demonomorphization", + "demonomorphize", + "demonomorphized", + "demonomorphizer", + "demonomorphizes", + "demonomorphizing", "deregistration", "devex", "devnet", diff --git a/docs/docs/protocol-specs/circuits/private-kernel-initial.mdx b/docs/docs/protocol-specs/circuits/private-kernel-initial.mdx index 13d188829c6..843f516772e 100644 --- a/docs/docs/protocol-specs/circuits/private-kernel-initial.mdx +++ b/docs/docs/protocol-specs/circuits/private-kernel-initial.mdx @@ -168,8 +168,8 @@ The circuit undergoes the following validations for data within [`private_inputs For each `note_hash` at index `i` in `note_hashes`: - Find the `request_index` at [`hints`](#hints).`note_hash_range_hints[i]`, which is the index of the `private_call_requests` with the smallest `counter_start` that was emitted after the `note_hash`. - - If `request_index` equals `NM`, indicating no request was emitted after the `note_hash`, its counter must be greater the `counter_end` of the last request. - - If `request_index` equals `0`, indicating no request was emitted before the `note_hash`. Its counter must be less the `counter_start` of the first request. + - If `request_index` equals `NE`, indicating no request was emitted after the `note_hash`, its counter must be greater than the `counter_end` of the last request. + - If `request_index` equals `0`, indicating no request was emitted before the `note_hash`. Its counter must be less than the `counter_start` of the first request. - Otherwise, the request was emitted after the `note_hash`, and its immediate previous request was emitted before the `note_hash`. Its counter must fall between those two requests. The code simplifies as: diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index 8a9200aaee6..29a43807bb1 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -89,7 +89,7 @@ library Constants { uint256 internal constant DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE = 0x85864497636cf755ae7bde03f267ce01a520981c21c3682aaf82a631; uint256 internal constant DEPLOYER_CONTRACT_ADDRESS = - 0x0097949bb96834550868230a1b6cc242d1f662f7c52946245e4e73da1b8b2165; + 0x2e9c386f07e22a1d24e677ab70407b2dd0adbc7cafb9c822bf249685d6a2e4cc; uint256 internal constant DEFAULT_GAS_LIMIT = 1_000_000_000; uint256 internal constant DEFAULT_TEARDOWN_GAS_LIMIT = 100_000_000; uint256 internal constant DEFAULT_MAX_FEE_PER_GAS = 10; diff --git a/noir-projects/aztec-nr/.gitrepo b/noir-projects/aztec-nr/.gitrepo index 5e88701643c..ef0a30f2bb4 100644 --- a/noir-projects/aztec-nr/.gitrepo +++ b/noir-projects/aztec-nr/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/AztecProtocol/aztec-nr branch = master - commit = f313dc19adbf18ac7e733948787e026c623594f9 + commit = 425256e90b778e29913427d71bf0038187ca6bc7 method = merge cmdver = 0.4.6 - parent = cf1748cc954ec5d1345deb095d632ee63d059c28 + parent = 4b4187f4bd004a11710b1fdd0119e9c098ae969c diff --git a/noir-projects/aztec-nr/aztec/src/context/avm_context.nr b/noir-projects/aztec-nr/aztec/src/context/avm_context.nr index 30097e522f1..d7180bd8338 100644 --- a/noir-projects/aztec-nr/aztec/src/context/avm_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/avm_context.nr @@ -38,7 +38,7 @@ impl AvmContext { * Should be automatically convertible to [Field; N]. For example str works with * one char per field. Otherwise you can use CompressedString. */ - pub fn emit_unencrypted_log(&mut self, event_selector: Field, log: T) { + pub fn emit_unencrypted_log_with_selector(&mut self, event_selector: Field, log: T) { emit_unencrypted_log(event_selector, log); } pub fn note_hash_exists(self, note_hash: Field, leaf_index: Field) -> bool { @@ -88,7 +88,7 @@ impl PublicContextInterface for AvmContext { fn emit_unencrypted_log(&mut self, log: T) { let event_selector = 5; // Matches current PublicContext. - self.emit_unencrypted_log(event_selector, log); + self.emit_unencrypted_log_with_selector(event_selector, log); } fn consume_l1_to_l2_message(&mut self, content: Field, secret: Field, sender: EthAddress, leaf_index: Field) { diff --git a/noir-projects/aztec-nr/aztec/src/context/interface.nr b/noir-projects/aztec-nr/aztec/src/context/interface.nr index b0fa94a211e..cac03e3702d 100644 --- a/noir-projects/aztec-nr/aztec/src/context/interface.nr +++ b/noir-projects/aztec-nr/aztec/src/context/interface.nr @@ -1,7 +1,4 @@ -use dep::protocol_types::{ - abis::function_selector::FunctionSelector, address::{AztecAddress, EthAddress}, header::Header, - traits::Deserialize -}; +use dep::protocol_types::{abis::function_selector::FunctionSelector, address::{AztecAddress, EthAddress}, traits::Deserialize}; use crate::context::private_context::PrivateContext; use crate::context::public_context::PublicContext; @@ -209,20 +206,22 @@ struct AvmCallInterface { target_contract: AztecAddress, selector: FunctionSelector, args: [Field], + gas_opts: GasOpts, } impl AvmCallInterface { - pub fn call(self, context: &mut AvmContext, gas_opts: GasOpts) -> T where T: Deserialize { - let returns = context.call_public_function(self.target_contract, self.selector, self.args, gas_opts); + pub fn with_gas(self: &mut Self, gas_opts: GasOpts) -> &mut Self { + self.gas_opts = gas_opts; + self + } + + pub fn call(self, context: &mut AvmContext) -> T where T: Deserialize { + let returns = context.call_public_function(self.target_contract, self.selector, self.args, self.gas_opts); returns.deserialize_into() } - pub fn static_call( - self, - context: &mut AvmContext, - gas_opts: GasOpts - ) -> T where T: Deserialize { - let returns = context.static_call_public_function(self.target_contract, self.selector, self.args, gas_opts); + pub fn static_call(self, context: &mut AvmContext) -> T where T: Deserialize { + let returns = context.static_call_public_function(self.target_contract, self.selector, self.args, self.gas_opts); returns.deserialize_into() } @@ -236,16 +235,22 @@ struct AvmVoidCallInterface { target_contract: AztecAddress, selector: FunctionSelector, args: [Field], + gas_opts: GasOpts, } impl AvmVoidCallInterface { - pub fn call(self, context: &mut AvmContext, gas_opts: GasOpts) { - let returns = context.call_public_function(self.target_contract, self.selector, self.args, gas_opts); + pub fn with_gas(self: &mut Self, gas_opts: GasOpts) -> &mut Self { + self.gas_opts = gas_opts; + self + } + + pub fn call(self, context: &mut AvmContext) { + let returns = context.call_public_function(self.target_contract, self.selector, self.args, self.gas_opts); returns.assert_empty() } - pub fn static_call(self, context: &mut AvmContext, gas_opts: GasOpts) { - let returns = context.static_call_public_function(self.target_contract, self.selector, self.args, gas_opts); + pub fn static_call(self, context: &mut AvmContext) { + let returns = context.static_call_public_function(self.target_contract, self.selector, self.args, self.gas_opts); returns.assert_empty() } diff --git a/noir-projects/aztec-nr/aztec/src/keys/point_to_symmetric_key.nr b/noir-projects/aztec-nr/aztec/src/keys/point_to_symmetric_key.nr index 905a049f9d5..1c80662dcb3 100644 --- a/noir-projects/aztec-nr/aztec/src/keys/point_to_symmetric_key.nr +++ b/noir-projects/aztec-nr/aztec/src/keys/point_to_symmetric_key.nr @@ -1,5 +1,5 @@ use dep::protocol_types::{constants::GENERATOR_INDEX__SYMMETRIC_KEY, grumpkin_private_key::GrumpkinPrivateKey, grumpkin_point::GrumpkinPoint, utils::arr_copy_slice}; -use dep::std::{hash::sha256, grumpkin_scalar::GrumpkinScalar, embedded_curve_ops::multi_scalar_mul}; +use dep::std::{hash::sha256, embedded_curve_ops::multi_scalar_mul}; // TODO(#5726): This function is called deriveAESSecret in TS. I don't like point_to_symmetric_key name much since // point is not the only input of the function. Unify naming with TS once we have a better name. diff --git a/noir-projects/noir-contracts/contracts/avm_nested_calls_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_nested_calls_test_contract/src/main.nr index 4a0611968ed..1ebc736cc8d 100644 --- a/noir-projects/noir-contracts/contracts/avm_nested_calls_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_nested_calls_test_contract/src/main.nr @@ -40,36 +40,36 @@ contract AvmNestedCallsTest { l2_gas: Field, da_gas: Field ) -> pub Field { - AvmNestedCallsTest::at(context.this_address()).add_args_return(arg_a, arg_b).call(&mut context, GasOpts::new(l2_gas, da_gas)) + AvmNestedCallsTest::at(context.this_address()).add_args_return(arg_a, arg_b).with_gas(GasOpts::new(l2_gas, da_gas)).call(&mut context) } // Use the `call_public_function` wrapper to initiate a nested call to the add function #[aztec(public-vm)] fn nested_call_to_add(arg_a: Field, arg_b: Field) -> pub Field { - AvmNestedCallsTest::at(context.this_address()).add_args_return(arg_a, arg_b).call(&mut context, GasOpts::default()) + AvmNestedCallsTest::at(context.this_address()).add_args_return(arg_a, arg_b).call(&mut context) } // Indirectly call_static the external call opcode to initiate a nested call to the add function #[aztec(public-vm)] fn nested_static_call_to_add(arg_a: Field, arg_b: Field) -> pub Field { - AvmNestedCallsTest::at(context.this_address()).add_args_return(arg_a, arg_b).static_call(&mut context, GasOpts::default()) + AvmNestedCallsTest::at(context.this_address()).add_args_return(arg_a, arg_b).static_call(&mut context) } // Indirectly call_static `set_storage_single`. Should revert since it's accessing storage. #[aztec(public-vm)] fn nested_static_call_to_set_storage() { - AvmNestedCallsTest::at(context.this_address()).set_storage_single(20).static_call(&mut context, GasOpts::default()); + AvmNestedCallsTest::at(context.this_address()).set_storage_single(20).static_call(&mut context); } #[aztec(public-vm)] fn create_same_nullifier_in_nested_call(nestedAddress: AztecAddress, nullifier: Field) { context.push_new_nullifier(nullifier, 0); - AvmNestedCallsTest::at(nestedAddress).new_nullifier(nullifier).call(&mut context, GasOpts::default()); + AvmNestedCallsTest::at(nestedAddress).new_nullifier(nullifier).call(&mut context); } #[aztec(public-vm)] fn create_different_nullifier_in_nested_call(nestedAddress: AztecAddress, nullifier: Field) { context.push_new_nullifier(nullifier, 0); - AvmNestedCallsTest::at(nestedAddress).new_nullifier(nullifier + 1).call(&mut context, GasOpts::default()); + AvmNestedCallsTest::at(nestedAddress).new_nullifier(nullifier + 1).call(&mut context); } } diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr index 03b9f8912da..c26c4f2551a 100644 --- a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -60,10 +60,11 @@ contract AvmTest { } #[aztec(public-vm)] - fn read_storage_single() -> pub Field { + fn read_storage_single() -> Field { storage.single.read() } + // should still be able to use ` -> pub *` for return type even though macro forces `pub` #[aztec(public-vm)] fn set_read_storage_single(a: Field) -> pub Field { storage.single.write(a); @@ -76,20 +77,20 @@ contract AvmTest { } #[aztec(public-vm)] - fn read_storage_list() -> pub [Field; 2] { + fn read_storage_list() -> [Field; 2] { let note: Note = storage.list.read(); note.serialize() } #[aztec(public-vm)] - fn set_storage_map(to: AztecAddress, amount: u32) -> pub Field { + fn set_storage_map(to: AztecAddress, amount: u32) -> Field { storage.map.at(to).write(amount); // returns storage slot for key dep::std::hash::pedersen_hash([storage.map.storage_slot, to.to_field()]) } #[aztec(public-vm)] - fn add_storage_map(to: AztecAddress, amount: u32) -> pub Field { + fn add_storage_map(to: AztecAddress, amount: u32) -> Field { let new_balance = storage.map.at(to).read().add(amount); storage.map.at(to).write(new_balance); // returns storage slot for key @@ -97,12 +98,12 @@ contract AvmTest { } #[aztec(public-vm)] - fn read_storage_map(address: AztecAddress) -> pub u32 { + fn read_storage_map(address: AztecAddress) -> u32 { storage.map.at(address).read() } #[aztec(public-vm)] - fn add_args_return(arg_a: Field, arg_b: Field) -> pub Field { + fn add_args_return(arg_a: Field, arg_b: Field) -> Field { arg_a + arg_b } @@ -110,32 +111,32 @@ contract AvmTest { * General Opcodes ************************************************************************/ #[aztec(public-vm)] - fn set_opcode_u8() -> pub u8 { + fn set_opcode_u8() -> u8 { 8 as u8 } #[aztec(public-vm)] - fn set_opcode_u32() -> pub u32 { + fn set_opcode_u32() -> u32 { 1 << 30 as u8 } #[aztec(public-vm)] - fn set_opcode_u64() -> pub u64 { + fn set_opcode_u64() -> u64 { 1 << 60 as u8 } #[aztec(public-vm)] - fn set_opcode_small_field() -> pub Field { + fn set_opcode_small_field() -> Field { big_field_128_bits } #[aztec(public-vm)] - fn set_opcode_big_field() -> pub Field { + fn set_opcode_big_field() -> Field { big_field_136_bits } #[aztec(public-vm)] - fn add_u128(a: U128, b: U128) -> pub U128 { + fn add_u128(a: U128, b: U128) -> U128 { a + b } @@ -143,27 +144,27 @@ contract AvmTest { * Hashing functions ************************************************************************/ #[aztec(public-vm)] - fn keccak_hash(data: [u8; 10]) -> pub [u8; 32] { + fn keccak_hash(data: [u8; 10]) -> [u8; 32] { dep::std::hash::keccak256(data, data.len() as u32) } #[aztec(public-vm)] - fn poseidon2_hash(data: [Field; 10]) -> pub Field { + fn poseidon2_hash(data: [Field; 10]) -> Field { dep::std::hash::poseidon2::Poseidon2::hash(data, data.len()) } #[aztec(public-vm)] - fn sha256_hash(data: [u8; 10]) -> pub [u8; 32] { + fn sha256_hash(data: [u8; 10]) -> [u8; 32] { dep::std::hash::sha256(data) } #[aztec(public-vm)] - fn pedersen_hash(data: [Field; 10]) -> pub Field { + fn pedersen_hash(data: [Field; 10]) -> Field { dep::std::hash::pedersen_hash(data) } #[aztec(public-vm)] - fn pedersen_hash_with_index(data: [Field; 10]) -> pub Field { + fn pedersen_hash_with_index(data: [Field; 10]) -> Field { dep::std::hash::pedersen_hash_with_separator(data, /*index=*/ 20) } @@ -193,57 +194,57 @@ contract AvmTest { * AvmContext functions ************************************************************************/ #[aztec(public-vm)] - fn get_address() -> pub AztecAddress { + fn get_address() -> AztecAddress { context.this_address() } #[aztec(public-vm)] - fn get_storage_address() -> pub AztecAddress { + fn get_storage_address() -> AztecAddress { context.storage_address() } #[aztec(public-vm)] - fn get_sender() -> pub AztecAddress { + fn get_sender() -> AztecAddress { context.msg_sender() } #[aztec(public-vm)] - fn get_fee_per_l2_gas() -> pub Field { + fn get_fee_per_l2_gas() -> Field { context.fee_per_l2_gas() } #[aztec(public-vm)] - fn get_fee_per_da_gas() -> pub Field { + fn get_fee_per_da_gas() -> Field { context.fee_per_da_gas() } #[aztec(public-vm)] - fn get_transaction_fee() -> pub Field { + fn get_transaction_fee() -> Field { context.transaction_fee() } #[aztec(public-vm)] - fn get_chain_id() -> pub Field { + fn get_chain_id() -> Field { context.chain_id() } #[aztec(public-vm)] - fn get_version() -> pub Field { + fn get_version() -> Field { context.version() } #[aztec(public-vm)] - fn get_block_number() -> pub Field { + fn get_block_number() -> Field { context.block_number() } #[aztec(public-vm)] - fn get_timestamp() -> pub u64 { + fn get_timestamp() -> u64 { context.timestamp() } // #[aztec(public-vm)] - // fn get_contract_call_depth() -> pub Field { + // fn get_contract_call_depth() -> Field { // context.contract_call_depth() // } @@ -255,20 +256,20 @@ contract AvmTest { } #[aztec(public-vm)] - fn get_args_hash(_a: u8, _fields: [Field; 3]) -> pub Field { + fn get_args_hash(_a: u8, _fields: [Field; 3]) -> Field { context.get_args_hash() } #[aztec(public-vm)] fn emit_unencrypted_log() { - context.emit_unencrypted_log(/*event_selector=*/ 5, /*message=*/ [10, 20, 30]); - context.emit_unencrypted_log(/*event_selector=*/ 8, /*message=*/ "Hello, world!"); + context.emit_unencrypted_log_with_selector(/*event_selector=*/ 5, /*message=*/ [10, 20, 30]); + context.emit_unencrypted_log_with_selector(/*event_selector=*/ 8, /*message=*/ "Hello, world!"); let s: CompressedString<2,44> = CompressedString::from_string("A long time ago, in a galaxy far far away..."); - context.emit_unencrypted_log(/*event_selector=*/ 10, /*message=*/ s); + context.emit_unencrypted_log_with_selector(/*event_selector=*/ 10, /*message=*/ s); } #[aztec(public-vm)] - fn note_hash_exists(note_hash: Field, leaf_index: Field) -> pub bool { + fn note_hash_exists(note_hash: Field, leaf_index: Field) -> bool { context.note_hash_exists(note_hash, leaf_index) } @@ -286,7 +287,7 @@ contract AvmTest { // Use the standard context interface to check for a nullifier #[aztec(public-vm)] - fn nullifier_exists(nullifier: Field) -> pub bool { + fn nullifier_exists(nullifier: Field) -> bool { context.nullifier_exists(nullifier, context.this_address()) } @@ -312,7 +313,7 @@ contract AvmTest { } #[aztec(public-vm)] - fn l1_to_l2_msg_exists(msg_hash: Field, msg_leaf_index: Field) -> pub bool { + fn l1_to_l2_msg_exists(msg_hash: Field, msg_leaf_index: Field) -> bool { context.l1_to_l2_msg_exists(msg_hash, msg_leaf_index) } diff --git a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr index c2b88b4726b..d863ecaaaeb 100644 --- a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr @@ -26,6 +26,7 @@ contract Counter { // docs:start:increment #[aztec(private)] fn increment(owner: AztecAddress) { + dep::aztec::oracle::debug_log::debug_log_format("Incrementing counter for owner {0}", [owner.to_field()]); let counters = storage.counters; counters.at(owner).add(1, owner); } diff --git a/noir-projects/noir-contracts/contracts/gas_token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/gas_token_contract/src/main.nr index 3b46f9b53fa..7ba446c54ed 100644 --- a/noir-projects/noir-contracts/contracts/gas_token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/gas_token_contract/src/main.nr @@ -55,10 +55,11 @@ contract GasToken { fn pay_fee(fee_limit: Field) -> Field { let fee_limit_u128 = U128::from_integer(fee_limit); let fee = U128::from_integer(calculate_fee(context)); - dep::aztec::oracle::debug_log::debug_log_format( - "Gas token: paying fee {0} (limit {1})", - [fee.to_field(), fee_limit] - ); + // TODO(6252): implement debug logging in AVM + //dep::aztec::oracle::debug_log::debug_log_format( + // "Gas token: paying fee {0} (limit {1})", + // [fee.to_field(), fee_limit] + //); assert(fee <= fee_limit_u128, "Fee too high"); let sender_new_balance = storage.balances.at(context.msg_sender()).read() - fee; diff --git a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr index 430e0e21347..1d181a97486 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -11,7 +11,8 @@ contract Test { use dep::aztec::protocol_types::{ abis::private_circuit_public_inputs::PrivateCircuitPublicInputs, constants::{MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, CANONICAL_KEY_REGISTRY_ADDRESS}, - traits::{Serialize, ToField, FromField}, grumpkin_point::GrumpkinPoint, grumpkin_private_key::GrumpkinPrivateKey + traits::{Serialize, ToField, FromField}, grumpkin_point::GrumpkinPoint, + grumpkin_private_key::GrumpkinPrivateKey }; use dep::aztec::encrypted_logs::header::EncryptedLogHeader; @@ -375,10 +376,11 @@ contract Test { assert(context.historical_header.hash() == header_hash, "Invalid header hash"); } - #[aztec(public)] - fn assert_header_public(header_hash: Field) { - assert(context.historical_header.hash() == header_hash, "Invalid header hash"); - } + // TODO(4840): add AVM opcodes for getting header (members) + //#[aztec(public)] + //fn assert_header_public(header_hash: Field) { + // assert(context.historical_header.hash() == header_hash, "Invalid header hash"); + //} #[aztec(private)] fn deploy_contract(target: AztecAddress) { @@ -431,15 +433,16 @@ contract Test { let derived_slot = derive_storage_slot_in_map(storage_slot_of_shared_mutable, address_to_get_in_registry); // It's a bit wonky because we need to know the delay for get_current_value_in_private to work correctly - let registry_private_getter: SharedMutablePrivateGetter = SharedMutablePrivateGetter::new(context, AztecAddress::from_field(CANONICAL_KEY_REGISTRY_ADDRESS), derived_slot); + let registry_private_getter: SharedMutablePrivateGetter = SharedMutablePrivateGetter::new( + context, + AztecAddress::from_field(CANONICAL_KEY_REGISTRY_ADDRESS), + derived_slot + ); registry_private_getter.get_current_value_in_private() } #[aztec(private)] - fn test_nullifier_key_freshness( - address: AztecAddress, - public_nullifying_key: GrumpkinPoint, - ) { + fn test_nullifier_key_freshness(address: AztecAddress, public_nullifying_key: GrumpkinPoint) { assert_eq(get_npk_m(&mut context, address), public_nullifying_key); } diff --git a/noir-projects/noir-contracts/scripts/transpile.sh b/noir-projects/noir-contracts/scripts/transpile.sh index 9bea61f5ffa..934f8982d55 100755 --- a/noir-projects/noir-contracts/scripts/transpile.sh +++ b/noir-projects/noir-contracts/scripts/transpile.sh @@ -2,4 +2,5 @@ set -eu TRANSPILER=${TRANSPILER:-../../avm-transpiler/target/release/avm-transpiler} -ls target/avm_*.json | parallel "$TRANSPILER {} {}" \ No newline at end of file +ls target/*.json | parallel "$TRANSPILER {} {}" + diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr index ffe93c8dfd0..bbc11756c56 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr @@ -57,7 +57,7 @@ impl PublicKernelTailCircuitPrivateInputs { hint.leaf_slot, exists_in_tree, hint.leaf_preimage, - MembershipWitness { leaf_index: hint.membership_witness.leaf_index, sibling_path: hint.membership_witness.sibling_path }, + hint.membership_witness, public_data_tree_root ); } @@ -115,19 +115,20 @@ mod tests { use dep::types::{ abis::{ kernel_circuit_public_inputs::KernelCircuitPublicInputs, kernel_data::PublicKernelData, - nullifier_leaf_preimage::NullifierLeafPreimage, membership_witness::PublicDataMembershipWitness + nullifier_leaf_preimage::NullifierLeafPreimage }, constants::{ MAX_NEW_NULLIFIERS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_PUBLIC_DATA_HINTS, MAX_PUBLIC_DATA_READS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, NULLIFIER_TREE_HEIGHT, NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH, NULLIFIER_SUBTREE_HEIGHT, PUBLIC_DATA_SUBTREE_HEIGHT, PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH, PUBLIC_DATA_TREE_HEIGHT, MAX_ENCRYPTED_LOGS_PER_TX, - MAX_UNENCRYPTED_LOGS_PER_TX, + MAX_UNENCRYPTED_LOGS_PER_TX }, hash::{silo_nullifier, sha256_to_field}, public_data_tree_leaf_preimage::PublicDataTreeLeafPreimage, tests::{fixture_builder::FixtureBuilder, merkle_tree_utils::NonEmptyMerkleTree}, - partial_state_reference::PartialStateReference, utils::arrays::array_merge + partial_state_reference::PartialStateReference, utils::arrays::array_merge, + merkle_tree::MembershipWitness }; fn build_nullifier_tree() -> NonEmptyMerkleTree { @@ -264,7 +265,7 @@ mod tests { pub fn add_public_data_hint_for_settled_public_data(&mut self, leaf_index: u64) { let leaf_preimage = get_settled_public_data_leaves()[leaf_index]; - let membership_witness = PublicDataMembershipWitness { leaf_index: leaf_index as Field, sibling_path: self.public_data_tree.get_sibling_path(leaf_index) }; + let membership_witness = MembershipWitness { leaf_index: leaf_index as Field, sibling_path: self.public_data_tree.get_sibling_path(leaf_index) }; let hint = PublicDataHint { leaf_slot: leaf_preimage.slot, value: leaf_preimage.value, @@ -277,7 +278,7 @@ mod tests { pub fn add_public_data_hint_for_non_existent_public_data(&mut self, leaf_slot: Field, low_leaf_index: u64) { let leaf_preimage = get_settled_public_data_leaves()[low_leaf_index]; - let membership_witness = PublicDataMembershipWitness { + let membership_witness = MembershipWitness { leaf_index: low_leaf_index as Field, sibling_path: self.public_data_tree.get_sibling_path(low_leaf_index) }; @@ -360,18 +361,11 @@ mod tests { public_inputs.end.unencrypted_log_preimages_length, unencrypted_log_preimages_length + prev_unencrypted_log_preimages_length ); - let hash_bytes: [u8; MAX_ENCRYPTED_LOGS_PER_TX * 32] = prev_encrypted_logs_hash - .to_be_bytes(32) - .append(&[0; MAX_ENCRYPTED_LOGS_PER_TX * 32 - 32]) - .as_array(); + let hash_bytes: [u8; MAX_ENCRYPTED_LOGS_PER_TX * 32] = prev_encrypted_logs_hash.to_be_bytes(32).append(&[0; MAX_ENCRYPTED_LOGS_PER_TX * 32 - 32]).as_array(); let expected_encrypted_logs_hash = sha256_to_field(hash_bytes); assert_eq(public_inputs.end.encrypted_logs_hash, expected_encrypted_logs_hash); - let hash_bytes: [u8; MAX_UNENCRYPTED_LOGS_PER_TX * 32] = prev_unencrypted_logs_hash - .to_be_bytes(32) - .append(unencrypted_logs_hash.to_be_bytes(32)) - .append(&[0; MAX_UNENCRYPTED_LOGS_PER_TX * 32 - 64]) - .as_array(); + let hash_bytes: [u8; MAX_UNENCRYPTED_LOGS_PER_TX * 32] = prev_unencrypted_logs_hash.to_be_bytes(32).append(unencrypted_logs_hash.to_be_bytes(32)).append(&[0; MAX_UNENCRYPTED_LOGS_PER_TX * 32 - 64]).as_array(); let expected_unencrypted_logs_hash = sha256_to_field(hash_bytes); assert_eq(public_inputs.end.unencrypted_logs_hash, expected_unencrypted_logs_hash); } diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/note_hash_read_request_reset.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/note_hash_read_request_reset.nr index 8c40d7c2cf3..8bb008c5421 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/note_hash_read_request_reset.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/note_hash_read_request_reset.nr @@ -1,14 +1,14 @@ // This will be moved to a separate Read Request Reset Circuit. use crate::reset::read_request::{PendingReadHint, ReadRequestStatus, ReadValueHint, SettledReadHint}; use dep::types::{ - abis::{membership_witness::NoteHashMembershipWitness, note_hash_leaf_preimage::NoteHashLeafPreimage}, + abis::{note_hash_leaf_preimage::NoteHashLeafPreimage}, constants::{MAX_NOTE_HASH_READ_REQUESTS_PER_TX, NOTE_HASH_TREE_HEIGHT}, merkle_tree::MembershipWitness }; struct NoteHashSettledReadHint { read_request_index: u64, - membership_witness: NoteHashMembershipWitness, // Should be MembershipWitness when we can handle generics when converting to ts types. + membership_witness: MembershipWitness, leaf_preimage: NoteHashLeafPreimage, } @@ -20,7 +20,7 @@ impl ReadValueHint for NoteHashSettledReadHint { impl SettledReadHint for NoteHashSettledReadHint { fn membership_witness(self) -> MembershipWitness { - MembershipWitness { leaf_index: self.membership_witness.leaf_index, sibling_path: self.membership_witness.sibling_path } + self.membership_witness } fn leaf_preimage(self) -> NoteHashLeafPreimage { @@ -30,7 +30,7 @@ impl SettledReadHint for NoteHashSe fn nada(read_request_len: u64) -> Self { NoteHashSettledReadHint { read_request_index: read_request_len, - membership_witness: NoteHashMembershipWitness::empty(), + membership_witness: MembershipWitness::empty(), leaf_preimage: NoteHashLeafPreimage::empty() } } @@ -46,10 +46,10 @@ mod tests { use crate::note_hash_read_request_reset::NoteHashSettledReadHint; use crate::reset::read_request::{PendingReadHint, ReadRequestState, ReadRequestStatus, reset_read_requests}; use dep::types::{ - address::AztecAddress, + address::AztecAddress, merkle_tree::MembershipWitness, abis::{ - membership_witness::NoteHashMembershipWitness, note_hash::NoteHashContext, - note_hash_leaf_preimage::NoteHashLeafPreimage, read_request::ReadRequestContext + note_hash::NoteHashContext, note_hash_leaf_preimage::NoteHashLeafPreimage, + read_request::ReadRequestContext }, constants::NOTE_HASH_TREE_HEIGHT, hash::silo_note_hash, tests::merkle_tree_utils::NonEmptyMerkleTree @@ -108,12 +108,12 @@ mod tests { let hints = [ NoteHashSettledReadHint { read_request_index: 0, - membership_witness: NoteHashMembershipWitness { leaf_index: 1, sibling_path: tree.get_sibling_path(1) }, + membership_witness: MembershipWitness { leaf_index: 1, sibling_path: tree.get_sibling_path(1) }, leaf_preimage: leaf_preimages[1] }, NoteHashSettledReadHint { read_request_index: 3, - membership_witness: NoteHashMembershipWitness { leaf_index: 0, sibling_path: tree.get_sibling_path(0) }, + membership_witness: MembershipWitness { leaf_index: 0, sibling_path: tree.get_sibling_path(0) }, leaf_preimage: leaf_preimages[0] } ]; diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/types/public_data_hint.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/types/public_data_hint.nr index 28a3eb74cb0..2bd7316a9a9 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/types/public_data_hint.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/types/public_data_hint.nr @@ -1,14 +1,14 @@ use crate::reset::{mutable_data_read_request::LeafDataHint}; use dep::types::{ - abis::membership_witness::PublicDataMembershipWitness, - public_data_tree_leaf_preimage::PublicDataTreeLeafPreimage + public_data_tree_leaf_preimage::PublicDataTreeLeafPreimage, merkle_tree::MembershipWitness, + constants::PUBLIC_DATA_TREE_HEIGHT }; struct PublicDataHint { leaf_slot: Field, value: Field, override_counter: u32, - membership_witness: PublicDataMembershipWitness, // Should be MembershipWitness when we can handle generics when converting to ts types. + membership_witness: MembershipWitness, // Should be MembershipWitness when we can handle generics when converting to ts types. leaf_preimage: PublicDataTreeLeafPreimage, } diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/previous_rollup_data.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/previous_rollup_data.nr index aecee269f9e..07abf8e362c 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/previous_rollup_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/previous_rollup_data.nr @@ -1,9 +1,7 @@ use crate::abis::base_or_merge_rollup_public_inputs::BaseOrMergeRollupPublicInputs; use dep::types::{ - abis::membership_witness::VKMembershipWitness, - constants::ROLLUP_VK_TREE_HEIGHT, - mocked::{Proof, VerificationKey}, - traits::Empty + constants::ROLLUP_VK_TREE_HEIGHT, mocked::{Proof, VerificationKey}, traits::Empty, + merkle_tree::MembershipWitness }; struct PreviousRollupData{ @@ -11,7 +9,7 @@ struct PreviousRollupData{ proof : Proof, vk : VerificationKey, vk_index : u32, - vk_sibling_path : VKMembershipWitness, + vk_sibling_path : MembershipWitness, } impl Empty for PreviousRollupData { @@ -21,7 +19,7 @@ impl Empty for PreviousRollupData { proof : Proof::empty(), vk : VerificationKey::empty(), vk_index : 0 as u32, - vk_sibling_path : VKMembershipWitness::empty(), + vk_sibling_path : MembershipWitness::empty(), } } -} \ No newline at end of file +} diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr index 3df978857ad..238cc1dbd13 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr @@ -9,10 +9,9 @@ use crate::{ use dep::types::{ hash::sha256_to_field, abis::{ - append_only_tree_snapshot::AppendOnlyTreeSnapshot, - membership_witness::{ArchiveRootMembershipWitness, NullifierMembershipWitness, PublicDataMembershipWitness}, - nullifier_leaf_preimage::NullifierLeafPreimage, public_data_update_request::PublicDataUpdateRequest, - public_data_read::PublicDataRead, kernel_data::KernelData + append_only_tree_snapshot::AppendOnlyTreeSnapshot, nullifier_leaf_preimage::NullifierLeafPreimage, + public_data_update_request::PublicDataUpdateRequest, public_data_read::PublicDataRead, + kernel_data::KernelData }, constants::{ NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH, NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH, @@ -20,7 +19,7 @@ use dep::types::{ 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 + PUBLIC_DATA_SUBTREE_HEIGHT, ARCHIVE_HEIGHT }, merkle_tree::{ append_only_tree, assert_check_membership, calculate_empty_tree_root, calculate_subtree_root, @@ -43,9 +42,9 @@ struct BaseRollupInputs { sorted_public_data_writes: [PublicDataTreeLeaf; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], sorted_public_data_writes_indexes: [u64; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], low_public_data_writes_preimages: [PublicDataTreeLeafPreimage; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], - low_public_data_writes_witnesses: [PublicDataMembershipWitness; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], + low_public_data_writes_witnesses: [MembershipWitness; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], - archive_root_membership_witness: ArchiveRootMembershipWitness, + archive_root_membership_witness: MembershipWitness, constants: ConstantRollupData, } @@ -148,7 +147,7 @@ impl BaseRollupInputs { 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| { + |witness: MembershipWitness| { MembershipWitness { leaf_index: witness.leaf_index, sibling_path: witness.sibling_path, @@ -266,7 +265,7 @@ fn insert_public_data_update_requests( sorted_public_data_writes: [PublicDataTreeLeaf; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], sorted_public_data_writes_indexes: [u64; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], low_public_data_writes_preimages: [PublicDataTreeLeafPreimage; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], - low_public_data_writes_witnesses: [PublicDataMembershipWitness; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], + low_public_data_writes_witnesses: [MembershipWitness; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], public_data_writes_subtree_sibling_path: [Field; PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH] ) -> AppendOnlyTreeSnapshot { indexed_tree::batch_insert( @@ -277,7 +276,7 @@ fn insert_public_data_update_requests( public_data_writes_subtree_sibling_path, low_public_data_writes_preimages, low_public_data_writes_witnesses.map( - |witness: PublicDataMembershipWitness| { + |witness: MembershipWitness| { MembershipWitness { leaf_index: witness.leaf_index, sibling_path: witness.sibling_path, @@ -369,12 +368,11 @@ mod tests { use dep::types::{ abis::{ append_only_tree_snapshot::AppendOnlyTreeSnapshot, - membership_witness::{ArchiveRootMembershipWitness, NullifierMembershipWitness, PublicDataMembershipWitness}, nullifier_leaf_preimage::NullifierLeafPreimage, public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, kernel_data::KernelData, side_effect::SideEffect, accumulated_data::CombinedAccumulatedData }, - address::{AztecAddress, EthAddress}, + merkle_tree::MembershipWitness, address::{AztecAddress, EthAddress}, constants::{ ARCHIVE_HEIGHT, MAX_PUBLIC_DATA_READS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH, @@ -409,12 +407,12 @@ mod tests { snapshot: AppendOnlyTreeSnapshot, public_data_writes: BoundedVec<(u64, PublicDataTreeLeaf), 2>, mut pre_existing_public_data: [PublicDataTreeLeafPreimage; EXISTING_LEAVES] - ) -> ([Field; 35], [PublicDataTreeLeaf; 32], [u64; 32], [PublicDataTreeLeafPreimage; 32], [PublicDataMembershipWitness; 32], [PublicDataTreeLeafPreimage; EXISTING_LEAVES]) { + ) -> ([Field; 35], [PublicDataTreeLeaf; 32], [u64; 32], [PublicDataTreeLeafPreimage; 32], [MembershipWitness; 32], [PublicDataTreeLeafPreimage; EXISTING_LEAVES]) { let mut subtree_path = [0; PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH]; let mut sorted_public_data_writes = [PublicDataTreeLeaf::empty(); MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX]; let mut sorted_public_data_writes_indexes = [0 as u64; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX]; let mut low_public_data_writes_preimages = [PublicDataTreeLeafPreimage::empty(); MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX]; - let mut low_public_data_writes_witnesses = [PublicDataMembershipWitness::empty(); MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX]; + let mut low_public_data_writes_witnesses = [MembershipWitness::empty(); MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX]; let mut new_subtree = [PublicDataTreeLeafPreimage::empty(); MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX]; for i in 0..MAX_PUBLIC_DATA_WRITES_PER_TEST { @@ -458,7 +456,7 @@ mod tests { }; } low_public_data_writes_preimages[i] = low_leaf; - low_public_data_writes_witnesses[i] = PublicDataMembershipWitness { + low_public_data_writes_witnesses[i] = MembershipWitness { leaf_index: low_leaf_index as Field, sibling_path: public_data_tree.get_sibling_path(low_leaf_index) }; @@ -526,9 +524,9 @@ mod tests { nullifier_tree: &mut NonEmptyMerkleTree, kernel_data: &mut KernelData, start_nullifier_tree_snapshot: AppendOnlyTreeSnapshot - ) -> ([NullifierLeafPreimage; MAX_NEW_NULLIFIERS_PER_TX], [NullifierMembershipWitness; MAX_NEW_NULLIFIERS_PER_TX], [Field; MAX_NEW_NULLIFIERS_PER_TX], [u64; MAX_NEW_NULLIFIERS_PER_TX]) { + ) -> ([NullifierLeafPreimage; MAX_NEW_NULLIFIERS_PER_TX], [MembershipWitness; MAX_NEW_NULLIFIERS_PER_TX], [Field; MAX_NEW_NULLIFIERS_PER_TX], [u64; MAX_NEW_NULLIFIERS_PER_TX]) { let mut nullifier_predecessor_preimages = [NullifierLeafPreimage::empty(); MAX_NEW_NULLIFIERS_PER_TX]; - let mut low_nullifier_membership_witness = [NullifierMembershipWitness::empty(); MAX_NEW_NULLIFIERS_PER_TX]; + let mut low_nullifier_membership_witness = [MembershipWitness::empty(); MAX_NEW_NULLIFIERS_PER_TX]; let sorted_new_nullifier_tuples = sort_high_to_low( self.new_nullifiers.storage.map(|insertion: NullifierInsertion| insertion.value), @@ -562,7 +560,7 @@ mod tests { let mut low_preimage = pre_existing_nullifiers[low_index]; nullifier_predecessor_preimages[i] = low_preimage; - low_nullifier_membership_witness[i] = NullifierMembershipWitness { + low_nullifier_membership_witness[i] = MembershipWitness { leaf_index: low_index as Field, sibling_path: nullifier_tree.get_sibling_path(low_index) }; @@ -687,7 +685,7 @@ mod tests { sorted_public_data_writes_indexes, low_public_data_writes_preimages, low_public_data_writes_witnesses, - archive_root_membership_witness: ArchiveRootMembershipWitness { leaf_index: 0, sibling_path: start_archive.get_sibling_path(0) }, + archive_root_membership_witness: MembershipWitness { leaf_index: 0, sibling_path: start_archive.get_sibling_path(0) }, constants: self.constants } } diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/state_diff_hints.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/state_diff_hints.nr index 9c7dd03d70d..6af5eb698af 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/state_diff_hints.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/state_diff_hints.nr @@ -1,14 +1,16 @@ use dep::types::{ - abis::{membership_witness::NullifierMembershipWitness, nullifier_leaf_preimage::NullifierLeafPreimage}, + abis::{nullifier_leaf_preimage::NullifierLeafPreimage}, constants::{ MAX_NEW_NULLIFIERS_PER_TX, NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH, - NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH, PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH -} + NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH, PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH, + NULLIFIER_TREE_HEIGHT +}, + merkle_tree::MembershipWitness }; struct StateDiffHints { nullifier_predecessor_preimages: [NullifierLeafPreimage; MAX_NEW_NULLIFIERS_PER_TX], - nullifier_predecessor_membership_witnesses: [NullifierMembershipWitness; MAX_NEW_NULLIFIERS_PER_TX], + nullifier_predecessor_membership_witnesses: [MembershipWitness; MAX_NEW_NULLIFIERS_PER_TX], sorted_nullifiers: [Field; MAX_NEW_NULLIFIERS_PER_TX], sorted_nullifier_indexes: [u64; MAX_NEW_NULLIFIERS_PER_TX], diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis.nr index 2d0566b9c0d..2c2a9325bcb 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis.nr @@ -6,9 +6,6 @@ mod function_selector; mod function_data; mod global_variables; - -mod membership_witness; - mod note_hash_leaf_preimage; mod nullifier_leaf_preimage; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/membership_witness.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/membership_witness.nr deleted file mode 100644 index e0dfc960f08..00000000000 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/membership_witness.nr +++ /dev/null @@ -1,77 +0,0 @@ -use crate::{ - constants::{ - FUNCTION_TREE_HEIGHT, NULLIFIER_TREE_HEIGHT, NOTE_HASH_TREE_HEIGHT, ROLLUP_VK_TREE_HEIGHT, - ARCHIVE_HEIGHT, PUBLIC_DATA_TREE_HEIGHT -}, - traits::Empty -}; - -// TODO(Kev): Instead of doing `MembershipWitness` we are forced -// to do this new struct because the typescript bindings generator -// does not have logic to monomorphize these properly. See the file named -// `typechain-type-alias` in the folder `bug-collecting-crate` -struct FunctionLeafMembershipWitness{ - leaf_index: Field, - sibling_path: [Field; FUNCTION_TREE_HEIGHT] -} - -struct VKMembershipWitness{ - leaf_index: Field, - sibling_path: [Field; ROLLUP_VK_TREE_HEIGHT] -} - -struct NullifierMembershipWitness{ - leaf_index: Field, - sibling_path: [Field; NULLIFIER_TREE_HEIGHT] -} - -struct PublicDataMembershipWitness{ - leaf_index: Field, - sibling_path: [Field; PUBLIC_DATA_TREE_HEIGHT] -} - -struct ArchiveRootMembershipWitness{ - leaf_index: Field, - sibling_path: [Field; ARCHIVE_HEIGHT] -} - -struct NoteHashMembershipWitness { - leaf_index: Field, - sibling_path: [Field; NOTE_HASH_TREE_HEIGHT], -} - -impl Empty for VKMembershipWitness { - fn empty() -> Self { - VKMembershipWitness { - leaf_index: 0, - sibling_path: [0; ROLLUP_VK_TREE_HEIGHT] - } - } -} - -impl Empty for NullifierMembershipWitness { - fn empty() -> Self { - NullifierMembershipWitness { - leaf_index: 0, - sibling_path: [0; NULLIFIER_TREE_HEIGHT] - } - } -} - -impl Empty for PublicDataMembershipWitness { - fn empty() -> Self { - PublicDataMembershipWitness { - leaf_index: 0, - sibling_path: [0; PUBLIC_DATA_TREE_HEIGHT] - } - } -} - -impl Empty for NoteHashMembershipWitness { - fn empty() -> Self { - NoteHashMembershipWitness { - leaf_index: 0, - sibling_path: [0; NOTE_HASH_TREE_HEIGHT] - } - } -} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/nullifier_key_validation_request.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/nullifier_key_validation_request.nr index 1a08e9f7a2f..bab8b642f09 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/nullifier_key_validation_request.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/nullifier_key_validation_request.nr @@ -3,12 +3,11 @@ use crate::{ address::AztecAddress, constants::{NULLIFIER_KEY_VALIDATION_REQUEST_CONTEXT_LENGTH, NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH}, traits::{Empty, Serialize, Deserialize}, grumpkin_point::GrumpkinPoint, - grumpkin_private_key::GrumpkinPrivateKey }; struct NullifierKeyValidationRequest { master_nullifier_public_key: GrumpkinPoint, - app_nullifier_secret_key: Field, // not a GrumpkinScalar because it's output of poseidon2 + app_nullifier_secret_key: Field, // not a grumpkin scalar because it's output of poseidon2 } impl Eq for NullifierKeyValidationRequest { diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel/private_call_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel/private_call_data.nr index e00c6c79a47..760189375dd 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel/private_call_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel/private_call_data.nr @@ -1,11 +1,9 @@ -use crate::abis::{ - call_request::CallRequest, private_call_stack_item::PrivateCallStackItem, - membership_witness::FunctionLeafMembershipWitness -}; +use crate::abis::{call_request::CallRequest, private_call_stack_item::PrivateCallStackItem}; use crate::address::{SaltedInitializationHash, PublicKeysHash, EthAddress}; use crate::contract_class_id::ContractClassId; use crate::mocked::{Proof, VerificationKey}; -use crate::constants::{MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL}; +use crate::constants::{MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, FUNCTION_TREE_HEIGHT}; +use crate::merkle_tree::membership::MembershipWitness; struct PrivateCallData { call_stack_item: PrivateCallStackItem, @@ -20,7 +18,7 @@ struct PrivateCallData { public_keys_hash: PublicKeysHash, contract_class_artifact_hash: Field, contract_class_public_bytecode_commitment: Field, - function_leaf_membership_witness: FunctionLeafMembershipWitness, + function_leaf_membership_witness: MembershipWitness, acir_hash: Field, } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr index ad82df9c822..254d07a3e0b 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -126,7 +126,7 @@ global REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE = 0xe7af8166354 // CONTRACT INSTANCE CONSTANTS // sha224sum 'struct ContractInstanceDeployed' global DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE = 0x85864497636cf755ae7bde03f267ce01a520981c21c3682aaf82a631; -global DEPLOYER_CONTRACT_ADDRESS = 0x0097949bb96834550868230a1b6cc242d1f662f7c52946245e4e73da1b8b2165; +global DEPLOYER_CONTRACT_ADDRESS = 0x2e9c386f07e22a1d24e677ab70407b2dd0adbc7cafb9c822bf249685d6a2e4cc; // GAS DEFAULTS global DEFAULT_GAS_LIMIT: u32 = 1_000_000_000; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/debug_log.nr b/noir-projects/noir-protocol-circuits/crates/types/src/debug_log.nr index a701336d926..d9892f1617e 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/debug_log.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/debug_log.nr @@ -2,21 +2,21 @@ // WARNING: sometimes when using debug logs the ACVM errors with: `thrown: "solver opcode resolution error: cannot solve opcode: expression has too many unknowns x155"` #[oracle(debugLog)] -fn debug_log_oracle(_msg: T, _num_args: Field) -> Field {} +fn debug_log_oracle(_msg: T, _num_args: Field) {} #[oracle(debugLog)] -fn debug_log_format_oracle(_msg: T, _args: [Field; N], _num_args: Field) -> Field {} +fn debug_log_format_oracle(_msg: T, _args: [Field; N], _num_args: Field) {} #[oracle(debugLog)] -fn debug_log_field_oracle(_field: Field) -> Field {} +fn debug_log_field_oracle(_field: Field) {} #[oracle(debugLog)] -fn debug_log_array_oracle(_arbitrary_array: [T; N]) -> Field {} +fn debug_log_array_oracle(_arbitrary_array: [T; N]) {} #[oracle(debugLogWithPrefix)] -fn debug_log_array_with_prefix_oracle(_prefix: S, _arbitrary_array: [T; N]) -> Field {} +fn debug_log_array_with_prefix_oracle(_prefix: S, _arbitrary_array: [T; N]) {} /// NOTE: call this with a str msg of length > 1 /// Example: /// `debug_log("blah blah this is a debug string");` unconstrained pub fn debug_log(msg: T) { - assert(debug_log_oracle(msg, 0) == 0); + debug_log_oracle(msg, 0); } /// NOTE: call this with a str msg of form @@ -26,23 +26,23 @@ unconstrained pub fn debug_log(msg: T) { /// Example: /// debug_log_format("get_2(slot:{0}) =>\n\t0:{1}\n\t1:{2}", [storage_slot, note0_hash, note1_hash]); unconstrained pub fn debug_log_format(msg: T, args: [Field; N]) { - assert(debug_log_format_oracle(msg, args, args.len() as Field) == 0); + debug_log_format_oracle(msg, args, args.len() as Field); } /// Example: /// `debug_log_field(my_field);` unconstrained pub fn debug_log_field(field: Field) { - assert(debug_log_field_oracle(field) == 0); + debug_log_field_oracle(field); } /// Example: /// `debug_log_array(my_array);` unconstrained fn debug_log_array(arbitrary_array: [T; N]) { - assert(debug_log_array_oracle(arbitrary_array) == 0); + debug_log_array_oracle(arbitrary_array); } /// Example: /// `debug_log_array_with_prefix("Prefix", my_array);` unconstrained pub fn debug_log_array_with_prefix(prefix: S, arbitrary_array: [T; N]) { - assert(debug_log_array_with_prefix_oracle(prefix, arbitrary_array) == 0); + debug_log_array_with_prefix_oracle(prefix, arbitrary_array); } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/grumpkin_private_key.nr b/noir-projects/noir-protocol-circuits/crates/types/src/grumpkin_private_key.nr index 20b43f7aebc..79261ec4f20 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/grumpkin_private_key.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/grumpkin_private_key.nr @@ -1,4 +1,4 @@ -use dep::std::{cmp::Eq, grumpkin_scalar::GrumpkinScalar, embedded_curve_ops::fixed_base_scalar_mul}; +use dep::std::{cmp::Eq, embedded_curve_ops::fixed_base_scalar_mul}; use crate::{ grumpkin_point::GrumpkinPoint, traits::Empty diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/contract_functions.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/contract_functions.nr index a5f7642811a..836e673b5e1 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/contract_functions.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/contract_functions.nr @@ -1,13 +1,12 @@ -use crate::abis::{ - function_data::FunctionData, function_selector::FunctionSelector, - membership_witness::FunctionLeafMembershipWitness -}; +use crate::abis::{function_data::FunctionData, function_selector::FunctionSelector}; +use crate::merkle_tree::membership::MembershipWitness; +use crate::constants::FUNCTION_TREE_HEIGHT; struct ContractFunction { data: FunctionData, vk_hash: Field, acir_hash: Field, - membership_witness: FunctionLeafMembershipWitness, + membership_witness: MembershipWitness, } // sibling_path taken from __snapshots__/noir_test_gen.test.ts.snap @@ -18,7 +17,7 @@ global default_private_function = ContractFunction { }, vk_hash: 0, acir_hash: 1111, - membership_witness: FunctionLeafMembershipWitness { + membership_witness: MembershipWitness { leaf_index: 0, sibling_path: [ 0x1e5cebe7a50c5c8fd1ebe19ed6bbf80f77819b12a2a28f334e895501e1cda574, @@ -37,7 +36,7 @@ global default_public_function = ContractFunction { }, vk_hash: 0, acir_hash: 3333, - membership_witness: FunctionLeafMembershipWitness { + membership_witness: MembershipWitness { leaf_index: 2, sibling_path: [ 0x2d72ef5ebb7c974e1f5a8bed092f1cf1bf0a0cb1eda28516221ca7e5811ecf15, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr index c1b266fd6a0..a4c6a52930e 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr @@ -2,16 +2,16 @@ use crate::{ abis::{ gas_settings::GasSettings, call_request::{CallerContext, CallRequest}, private_call_stack_item::PrivateCallStackItem, function_data::FunctionData, - max_block_number::MaxBlockNumber, membership_witness::FunctionLeafMembershipWitness, - private_circuit_public_inputs::PrivateCircuitPublicInputs, + max_block_number::MaxBlockNumber, private_circuit_public_inputs::PrivateCircuitPublicInputs, private_kernel::private_call_data::PrivateCallData, side_effect::SideEffect }, + merkle_tree::membership::MembershipWitness, address::{AztecAddress, EthAddress, SaltedInitializationHash, PublicKeysHash}, mocked::{Proof, VerificationKey}, tests::{fixtures, private_circuit_public_inputs_builder::PrivateCircuitPublicInputsBuilder}, transaction::{tx_request::TxRequest, tx_context::TxContext} }; -use crate::constants::{MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL}; +use crate::constants::{MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, FUNCTION_TREE_HEIGHT}; struct PrivateCallDataBuilder { // Values of PrivateCallStackItem. @@ -28,7 +28,7 @@ struct PrivateCallDataBuilder { public_keys_hash: PublicKeysHash, contract_class_artifact_hash: Field, contract_class_public_bytecode_commitment: Field, - function_leaf_membership_witness: FunctionLeafMembershipWitness, + function_leaf_membership_witness: MembershipWitness, acir_hash: Field, gas_settings: GasSettings, } diff --git a/noir/.gitignore b/noir/.gitignore index 781ea857ba6..b211695f37c 100644 --- a/noir/.gitignore +++ b/noir/.gitignore @@ -1,2 +1,3 @@ **/package.tgz -packages \ No newline at end of file +packages +.earthly-staging \ No newline at end of file diff --git a/noir/Earthfile b/noir/Earthfile index 3fb400700b5..5f0f0c928f4 100644 --- a/noir/Earthfile +++ b/noir/Earthfile @@ -106,64 +106,64 @@ packages: SAVE IMAGE --cache-hint packages-test-build: - FROM +packages-deps + FROM +packages-deps - COPY +nargo/nargo /usr/src/noir/noir-repo/target/release/nargo - COPY +nargo/acvm /usr/src/noir/noir-repo/target/release/acvm + COPY +nargo/nargo /usr/src/noir/noir-repo/target/release/nargo + COPY +nargo/acvm /usr/src/noir/noir-repo/target/release/acvm - ENV NARGO_BACKEND_PATH=/usr/src/barretenberg/ts/dest/node/main.js - ENV PATH=$PATH:/usr/src/noir/noir-repo/target/release + ENV NARGO_BACKEND_PATH=/usr/src/barretenberg/ts/dest/node/main.js + ENV PATH=$PATH:/usr/src/noir/noir-repo/target/release - WORKDIR /usr/src/barretenberg/ts - RUN yarn --immutable + WORKDIR /usr/src/barretenberg/ts + RUN yarn --immutable - WORKDIR /usr/src/noir/noir-repo - COPY --dir noir-repo/.github/scripts/wasm-bindgen-install.sh ./.github/scripts/wasm-bindgen-install.sh - RUN ./.github/scripts/wasm-bindgen-install.sh + WORKDIR /usr/src/noir/noir-repo + COPY --dir noir-repo/.github/scripts/wasm-bindgen-install.sh ./.github/scripts/wasm-bindgen-install.sh + RUN ./.github/scripts/wasm-bindgen-install.sh - ENV SOURCE_DATE_EPOCH=$(date +%s) - ENV GIT_DIRTY=false - ENV GIT_COMMIT=$COMMIT_HASH - RUN yarn build - # this builds text fixtures to be used in tests - RUN yarn workspace @noir-lang/noir_wasm run test:build_fixtures + ENV SOURCE_DATE_EPOCH=$(date +%s) + ENV GIT_DIRTY=false + ENV GIT_COMMIT=$COMMIT_HASH + RUN yarn build + # this builds text fixtures to be used in tests + RUN yarn workspace @noir-lang/noir_wasm run test:build_fixtures - SAVE ARTIFACT /usr/src /usr/src + SAVE ARTIFACT /usr/src /usr/src packages-test-node: - FROM +packages-test-build - ENV NODE_OPTIONS=--max_old_space_size=8192 - WORKDIR /usr/src/noir/noir-repo - RUN yarn workspaces foreach \ - --parallel \ - --verbose \ - --exclude @noir-lang/root \ # foreach includes the root workspace, ignore it - --exclude @noir-lang/noir_js \ # noir_js OOMs - --exclude integration-tests \ # separate node and browser tests - --exclude @noir-lang/noir_wasm \ - run test - RUN yarn workspaces foreach \ - --parallel \ - --verbose \ - --include integration-tests \ - --include @noir-lang/noir_wasm \ - run test:node + FROM +packages-test-build + ENV NODE_OPTIONS=--max_old_space_size=8192 + WORKDIR /usr/src/noir/noir-repo + RUN yarn workspaces foreach \ + --parallel \ + --verbose \ + --exclude @noir-lang/root \ # foreach includes the root workspace, ignore it + --exclude @noir-lang/noir_js \ # noir_js OOMs + --exclude integration-tests \ # separate node and browser tests + --exclude @noir-lang/noir_wasm \ + run test + RUN yarn workspaces foreach \ + --parallel \ + --verbose \ + --include integration-tests \ + --include @noir-lang/noir_wasm \ + run test:node packages-test-browser: - FROM node:18 - COPY --dir +packages-test-build/usr/src /usr - WORKDIR /usr/src/noir/noir-repo - RUN ./.github/scripts/playwright-install.sh - RUN yarn workspaces foreach \ - --parallel \ - --verbose \ - --include integration-tests \ - --include @noir-lang/noir_wasm \ - run test:browser + FROM node:18 + COPY --dir +packages-test-build/usr/src /usr + WORKDIR /usr/src/noir/noir-repo + RUN ./.github/scripts/playwright-install.sh + RUN yarn workspaces foreach \ + --parallel \ + --verbose \ + --include integration-tests \ + --include @noir-lang/noir_wasm \ + run test:browser packages-test: - BUILD +packages-test-node - BUILD +packages-test-browser + BUILD +packages-test-node + BUILD +packages-test-browser run: # When running the container, mount the users home directory to same location. @@ -174,141 +174,101 @@ run: COPY +build/. /usr/src ENTRYPOINT ["/usr/bin/tini", "--", "/usr/src/nargo"] -build: - BUILD +nargo - BUILD +packages - build-acir-tests: - FROM ../build-images/+build - COPY +nargo/ /usr/src/noir-repo/target/release - ENV PATH="/usr/src/noir-repo/target/release:${PATH}" - WORKDIR /usr/src/noir-repo/test_programs - COPY ./noir-repo/test_programs/ /usr/src/noir-repo/test_programs/ - RUN /usr/src/noir-repo/target/release/nargo --version - # We run this with parallel compilation switched off, which isn't ideal. - # There seems to be problems with this when running under Earthly, see bottom of this file* - RUN ./rebuild.sh true - SAVE ARTIFACT /usr/src/noir-repo/test_programs/acir_artifacts/* + LOCALLY + # Prepare our exact dependency formula, this avoids problems with copied empty folders or build artifacts + RUN rm -rf .earthly-staging && mkdir -p .earthly-staging + RUN cp --parents $(git ls-files "noir-repo/test_programs/*.toml" "noir-repo/test_programs/*.nr" "noir-repo/test_programs/rebuild.sh") .earthly-staging + FROM ../build-images/+build + COPY +nargo/ /usr/src/noir-repo/target/release + ENV PATH="/usr/src/noir-repo/target/release:${PATH}" + WORKDIR /usr/src/noir-repo/test_programs + COPY .earthly-staging/noir-repo/test_programs /usr/src/noir-repo/test_programs/ + RUN /usr/src/noir-repo/target/release/nargo --version + # TODO(#6225): We have trouble with concurrency and pass 'true' to build in serial, see #6225 for details + RUN ./rebuild.sh true + SAVE ARTIFACT /usr/src/noir-repo/test_programs/acir_artifacts/* barretenberg-acir-tests-bb: - FROM ../build-images/+build - - COPY ../barretenberg/cpp/+preset-clang-assert/bin/bb /usr/src/barretenberg/cpp/build/bin/bb - COPY ../barretenberg/+acir-tests/ /usr/src/barretenberg/acir_tests - COPY +build-acir-tests/ /usr/src/acir_artifacts - - WORKDIR /usr/src/barretenberg/acir_tests - RUN rm -rf ./acir_tests - - ENV TEST_SRC /usr/src/acir_artifacts - ENV VERBOSE=1 - # Run every acir test through native bb build prove_then_verify flow for UltraPlonk. - # This ensures we test independent pk construction through real/garbage witness data paths. - RUN FLOW=prove_then_verify ./run_acir_tests.sh - # Construct and separately verify a UltraHonk proof for a single program - RUN FLOW=prove_then_verify_ultra_honk ./run_acir_tests.sh double_verify_nested_proof - # Construct and separately verify a GoblinUltraHonk proof for all acir programs - RUN FLOW=prove_then_verify_goblin_ultra_honk ./run_acir_tests.sh - # Construct and verify a UltraHonk proof for a single program - RUN FLOW=prove_and_verify_ultra_honk ./run_acir_tests.sh double_verify_nested_proof - # Construct and verify a Goblin UltraHonk (GUH) proof for a single arbitrary program - RUN FLOW=prove_and_verify_goblin_ultra_honk ./run_acir_tests.sh 6_array - # Construct and verify a UltraHonk proof for all ACIR programs using the new witness stack workflow - RUN FLOW=prove_and_verify_ultra_honk_program ./run_acir_tests.sh - # This is a "full" Goblin flow. It constructs and verifies four proofs: GoblinUltraHonk, ECCVM, Translator, and merge - RUN FLOW=prove_and_verify_goblin ./run_acir_tests.sh 6_array - # Run 1_mul through native bb build, all_cmds flow, to test all cli args. - RUN FLOW=all_cmds ./run_acir_tests.sh 1_mul + FROM ../build-images/+build + COPY ../barretenberg/cpp/+preset-clang-assert/bin/bb /usr/src/barretenberg/cpp/build/bin/bb + COPY ../barretenberg/+acir-tests/ /usr/src/barretenberg/acir_tests + COPY +build-acir-tests/ /usr/src/acir_artifacts + + WORKDIR /usr/src/barretenberg/acir_tests + RUN rm -rf ./acir_tests + + ENV TEST_SRC /usr/src/acir_artifacts + ENV VERBOSE=1 + # Run every acir test through native bb build prove_then_verify flow for UltraPlonk. + # This ensures we test independent pk construction through real/garbage witness data paths. + RUN FLOW=prove_then_verify ./run_acir_tests.sh + # Construct and separately verify a UltraHonk proof for a single program + RUN FLOW=prove_then_verify_ultra_honk ./run_acir_tests.sh double_verify_nested_proof + # Construct and separately verify a GoblinUltraHonk proof for all acir programs + RUN FLOW=prove_then_verify_goblin_ultra_honk ./run_acir_tests.sh + # Construct and verify a UltraHonk proof for a single program + RUN FLOW=prove_and_verify_ultra_honk ./run_acir_tests.sh double_verify_nested_proof + # Construct and verify a Goblin UltraHonk (GUH) proof for a single arbitrary program + RUN FLOW=prove_and_verify_goblin_ultra_honk ./run_acir_tests.sh 6_array + # Construct and verify a UltraHonk proof for all ACIR programs using the new witness stack workflow + RUN FLOW=prove_and_verify_ultra_honk_program ./run_acir_tests.sh + # This is a "full" Goblin flow. It constructs and verifies four proofs: GoblinUltraHonk, ECCVM, Translator, and merge + RUN FLOW=prove_and_verify_goblin ./run_acir_tests.sh 6_array + # Run 1_mul through native bb build, all_cmds flow, to test all cli args. + RUN FLOW=all_cmds ./run_acir_tests.sh 1_mul barretenberg-acir-tests-sol: - FROM ../build-images/+build + FROM ../build-images/+build - COPY ../barretenberg/cpp/+preset-sol/ /usr/src/barretenberg/cpp/build - COPY ../barretenberg/cpp/+preset-clang-assert/bin/bb /usr/src/barretenberg/cpp/build/bin/bb - COPY ../barretenberg/+acir-tests/ /usr/src/barretenberg/acir_tests - COPY ../barretenberg/+sol/ /usr/src/barretenberg/sol - COPY +build-acir-tests/ /usr/src/acir_artifacts + COPY ../barretenberg/cpp/+preset-sol/ /usr/src/barretenberg/cpp/build + COPY ../barretenberg/cpp/+preset-clang-assert/bin/bb /usr/src/barretenberg/cpp/build/bin/bb + COPY ../barretenberg/+acir-tests/ /usr/src/barretenberg/acir_tests + COPY ../barretenberg/+sol/ /usr/src/barretenberg/sol + COPY +build-acir-tests/ /usr/src/acir_artifacts - WORKDIR /usr/src/barretenberg/acir_tests + WORKDIR /usr/src/barretenberg/acir_tests - ENV TEST_SRC /usr/src/acir_artifacts - ENV VERBOSE=1 + ENV TEST_SRC /usr/src/acir_artifacts + ENV VERBOSE=1 - RUN (cd sol-test && yarn) - RUN PARALLEL=1 FLOW=sol ./run_acir_tests.sh assert_statement double_verify_proof double_verify_nested_proof + RUN (cd sol-test && yarn) + RUN PARALLEL=1 FLOW=sol ./run_acir_tests.sh assert_statement double_verify_proof double_verify_nested_proof barretenberg-acir-tests-bb.js: - # Playwright not supported on base image ubuntu:noble, results in unmet dependencies - FROM node:18.19.0 - RUN apt update && apt install -y curl jq lsof - - COPY ../barretenberg/ts/+build/build/ /usr/src/barretenberg/ts - COPY ../barretenberg/+acir-tests/ /usr/src/barretenberg/acir_tests - COPY +build-acir-tests/ /usr/src/acir_artifacts - - WORKDIR /usr/src/barretenberg/acir_tests - - # Build/install ts apps. - RUN cd browser-test-app && yarn && yarn build - RUN cd headless-test && yarn && npx playwright install && npx playwright install-deps - RUN cd ../ts && yarn - ENV VERBOSE=1 - ENV TEST_SRC /usr/src/acir_artifacts - - # Run double_verify_proof through bb.js on node to check 512k support. - RUN BIN=../ts/dest/node/main.js FLOW=prove_then_verify ./run_acir_tests.sh double_verify_proof - # Run a single arbitrary test not involving recursion through bb.js for UltraHonk - RUN BIN=../ts/dest/node/main.js FLOW=prove_and_verify_ultra_honk ./run_acir_tests.sh 6_array - # Run a single arbitrary test not involving recursion through bb.js for GoblinUltraHonk - RUN BIN=../ts/dest/node/main.js FLOW=prove_and_verify_goblin_ultra_honk ./run_acir_tests.sh 6_array - # Run a single arbitrary test not involving recursion through bb.js for full Goblin - RUN BIN=../ts/dest/node/main.js FLOW=prove_and_verify_goblin ./run_acir_tests.sh 6_array - # Run 1_mul through bb.js build, all_cmds flow, to test all cli args. - RUN BIN=../ts/dest/node/main.js FLOW=all_cmds ./run_acir_tests.sh 1_mul - # Run double_verify_proof through bb.js on chrome testing multi-threaded browser support. - # TODO: Currently headless webkit doesn't seem to have shared memory so skipping multi-threaded test. - RUN BROWSER=chrome THREAD_MODEL=mt ./run_acir_tests_browser.sh double_verify_proof - # Run 1_mul through bb.js on chrome/webkit testing single threaded browser support. - RUN BROWSER=chrome THREAD_MODEL=st ./run_acir_tests_browser.sh 1_mul - # Commenting for now as fails intermittently. Unreproducable on mainframe. - # See https://github.com/AztecProtocol/aztec-packages/issues/2104 - #RUN BROWSER=webkit THREAD_MODEL=st ./run_acir_tests_browser.sh 1_mul - -#* Analysis of compiling Acir tests inside/outside Earthly -# Each test run compiles the full suite, either in series or in parallel, either inside or outside Earthly. -# Each test prints the contents of the target directory of the eddsa circuit after compilation -# You can see that the 'Inside Earthly Parallel' run has an acir.gz file of a different size -# This results in a proof that fails verification -# -# Outside Earthly Parallel - -# [eddsa] Circuit witness successfully solved -# [eddsa] Witness saved to /mnt/user-data/phil/aztec3-packages/noir/noir-repo/test_programs/execution_success/eddsa/target/witness.gz -# total 2544 -# -rw-rw-r-- 1 phil phil 904034 May 3 10:40 acir.gz -# -rw-rw-r-- 1 phil phil 1696442 May 3 10:40 witness.gz - -# Outside Earthly Series - -# [eddsa] Circuit witness successfully solved -# [eddsa] Witness saved to /mnt/user-data/phil/aztec3-packages/noir/noir-repo/test_programs/execution_success/eddsa/target/witness.gz -# total 2544 -# -rw-rw-r-- 1 phil phil 904034 May 3 10:43 acir.gz -# -rw-rw-r-- 1 phil phil 1696442 May 3 10:43 witness.gz - -# Inside Earthly Parallel - -# +build-acir-tests | [eddsa] Circuit witness successfully solved -# +build-acir-tests | [eddsa] Witness saved to /usr/src/noir-repo/test_programs/execution_success/eddsa/target/witness.gz -# +build-acir-tests | total 2472 -# +build-acir-tests | -rw-r--r-- 1 root root 830340 May 3 10:47 acir.gz -# +build-acir-tests | -rw-r--r-- 1 root root 1696442 May 3 10:47 witness.gz - -# Inside Earthly Series - -# +build-acir-tests | [eddsa] Circuit witness successfully solved -# +build-acir-tests | [eddsa] Witness saved to /usr/src/noir-repo/test_programs/execution_success/eddsa/target/witness.gz -# +build-acir-tests | total 2544 -# +build-acir-tests | -rw-r--r-- 1 root root 904034 May 3 10:50 acir.gz -# +build-acir-tests | -rw-r--r-- 1 root root 1696442 May 3 10:51 witness.gz + # Playwright not supported on base image ubuntu:noble, results in unmet dependencies + FROM node:18.19.0 + RUN apt update && apt install -y curl jq lsof + + COPY ../barretenberg/ts/+build/build/ /usr/src/barretenberg/ts + COPY ../barretenberg/+acir-tests/ /usr/src/barretenberg/acir_tests + COPY +build-acir-tests/ /usr/src/acir_artifacts + + WORKDIR /usr/src/barretenberg/acir_tests + + # Build/install ts apps. + RUN cd browser-test-app && yarn && yarn build + RUN cd headless-test && yarn && npx playwright install && npx playwright install-deps + RUN cd ../ts && yarn + ENV VERBOSE=1 + ENV TEST_SRC /usr/src/acir_artifacts + + # Run double_verify_proof through bb.js on node to check 512k support. + RUN BIN=../ts/dest/node/main.js FLOW=prove_then_verify ./run_acir_tests.sh double_verify_proof + # Run a single arbitrary test not involving recursion through bb.js for UltraHonk + RUN BIN=../ts/dest/node/main.js FLOW=prove_and_verify_ultra_honk ./run_acir_tests.sh 6_array + # Run a single arbitrary test not involving recursion through bb.js for GoblinUltraHonk + RUN BIN=../ts/dest/node/main.js FLOW=prove_and_verify_goblin_ultra_honk ./run_acir_tests.sh 6_array + # Run a single arbitrary test not involving recursion through bb.js for full Goblin + RUN BIN=../ts/dest/node/main.js FLOW=prove_and_verify_goblin ./run_acir_tests.sh 6_array + # Run 1_mul through bb.js build, all_cmds flow, to test all cli args. + RUN BIN=../ts/dest/node/main.js FLOW=all_cmds ./run_acir_tests.sh 1_mul + # Run double_verify_proof through bb.js on chrome testing multi-threaded browser support. + # TODO: Currently headless webkit doesn't seem to have shared memory so skipping multi-threaded test. + RUN BROWSER=chrome THREAD_MODEL=mt ./run_acir_tests_browser.sh double_verify_proof + # Run 1_mul through bb.js on chrome/webkit testing single threaded browser support. + RUN BROWSER=chrome THREAD_MODEL=st ./run_acir_tests_browser.sh 1_mul + # Commenting for now as fails intermittently. Unreproducable on mainframe. + # See https://github.com/AztecProtocol/aztec-packages/issues/2104 + #RUN BROWSER=webkit THREAD_MODEL=st ./run_acir_tests_browser.sh 1_mul diff --git a/noir/noir-repo/Cargo.lock b/noir/noir-repo/Cargo.lock index 2c365b7775e..a8c63c032aa 100644 --- a/noir/noir-repo/Cargo.lock +++ b/noir/noir-repo/Cargo.lock @@ -63,6 +63,7 @@ dependencies = [ "blake3", "k256", "keccak", + "libaes", "num-bigint", "p256", "sha2", @@ -2615,6 +2616,12 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" +[[package]] +name = "libaes" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82903360c009b816f5ab72a9b68158c27c301ee2c3f20655b55c5e589e7d3bb7" + [[package]] name = "libc" version = "0.2.151" diff --git a/noir/noir-repo/acvm-repo/acir/README.md b/noir/noir-repo/acvm-repo/acir/README.md index 838c0b9dc36..f7fccad0799 100644 --- a/noir/noir-repo/acvm-repo/acir/README.md +++ b/noir/noir-repo/acvm-repo/acir/README.md @@ -76,6 +76,12 @@ Some more advanced computations assume that the proving system has an 'embedded The black box functions supported by ACIR are: +**AES128Encrypt**: ciphers the provided plaintext using AES128 in CBC mode, padding the input using PKCS#7. +- inputs: byte array [u8; N] +- iv: initialization vector [u8; 16] +- key: user key [u8; 16] +- outputs: byte vector [u8] of length `input.len() + (16 - input.len() % 16)`` + **AND**: performs the bitwise AND of lhs and rhs. bit_size must be the same for both inputs. - lhs: (witness, bit_size) - rhs: (witness, bit_size) diff --git a/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp b/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp index 10015ce18bb..b7e75c4320d 100644 --- a/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp +++ b/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp @@ -24,6 +24,17 @@ namespace Program { struct BlackBoxFuncCall { + struct AES128Encrypt { + std::vector inputs; + std::array iv; + std::array key; + std::vector outputs; + + friend bool operator==(const AES128Encrypt&, const AES128Encrypt&); + std::vector bincodeSerialize() const; + static AES128Encrypt bincodeDeserialize(std::vector); + }; + struct AND { Program::FunctionInput lhs; Program::FunctionInput rhs; @@ -266,7 +277,7 @@ namespace Program { static Sha256Compression bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; friend bool operator==(const BlackBoxFuncCall&, const BlackBoxFuncCall&); std::vector bincodeSerialize() const; @@ -618,6 +629,17 @@ namespace Program { struct BlackBoxOp { + struct AES128Encrypt { + Program::HeapVector inputs; + Program::HeapArray iv; + Program::HeapArray key; + Program::HeapVector outputs; + + friend bool operator==(const AES128Encrypt&, const AES128Encrypt&); + std::vector bincodeSerialize() const; + static AES128Encrypt bincodeDeserialize(std::vector); + }; + struct Sha256 { Program::HeapVector message; Program::HeapArray output; @@ -820,7 +842,7 @@ namespace Program { static Sha256Compression bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; friend bool operator==(const BlackBoxOp&, const BlackBoxOp&); std::vector bincodeSerialize() const; @@ -2159,6 +2181,53 @@ Program::BlackBoxFuncCall serde::Deserializable::dese return obj; } +namespace Program { + + inline bool operator==(const BlackBoxFuncCall::AES128Encrypt &lhs, const BlackBoxFuncCall::AES128Encrypt &rhs) { + if (!(lhs.inputs == rhs.inputs)) { return false; } + if (!(lhs.iv == rhs.iv)) { return false; } + if (!(lhs.key == rhs.key)) { return false; } + if (!(lhs.outputs == rhs.outputs)) { return false; } + return true; + } + + inline std::vector BlackBoxFuncCall::AES128Encrypt::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline BlackBoxFuncCall::AES128Encrypt BlackBoxFuncCall::AES128Encrypt::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 Program + +template <> +template +void serde::Serializable::serialize(const Program::BlackBoxFuncCall::AES128Encrypt &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.iv, serializer); + serde::Serializable::serialize(obj.key, serializer); + serde::Serializable::serialize(obj.outputs, serializer); +} + +template <> +template +Program::BlackBoxFuncCall::AES128Encrypt serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxFuncCall::AES128Encrypt obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.iv = serde::Deserializable::deserialize(deserializer); + obj.key = serde::Deserializable::deserialize(deserializer); + obj.outputs = serde::Deserializable::deserialize(deserializer); + return obj; +} + namespace Program { inline bool operator==(const BlackBoxFuncCall::AND &lhs, const BlackBoxFuncCall::AND &rhs) { @@ -3263,6 +3332,53 @@ Program::BlackBoxOp serde::Deserializable::deserialize(Dese return obj; } +namespace Program { + + inline bool operator==(const BlackBoxOp::AES128Encrypt &lhs, const BlackBoxOp::AES128Encrypt &rhs) { + if (!(lhs.inputs == rhs.inputs)) { return false; } + if (!(lhs.iv == rhs.iv)) { return false; } + if (!(lhs.key == rhs.key)) { return false; } + if (!(lhs.outputs == rhs.outputs)) { return false; } + return true; + } + + inline std::vector BlackBoxOp::AES128Encrypt::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline BlackBoxOp::AES128Encrypt BlackBoxOp::AES128Encrypt::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 Program + +template <> +template +void serde::Serializable::serialize(const Program::BlackBoxOp::AES128Encrypt &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.iv, serializer); + serde::Serializable::serialize(obj.key, serializer); + serde::Serializable::serialize(obj.outputs, serializer); +} + +template <> +template +Program::BlackBoxOp::AES128Encrypt serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxOp::AES128Encrypt obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.iv = serde::Deserializable::deserialize(deserializer); + obj.key = serde::Deserializable::deserialize(deserializer); + obj.outputs = serde::Deserializable::deserialize(deserializer); + return obj; +} + namespace Program { inline bool operator==(const BlackBoxOp::Sha256 &lhs, const BlackBoxOp::Sha256 &rhs) { diff --git a/noir/noir-repo/acvm-repo/acir/src/circuit/black_box_functions.rs b/noir/noir-repo/acvm-repo/acir/src/circuit/black_box_functions.rs index 53c68debce1..33c14436c85 100644 --- a/noir/noir-repo/acvm-repo/acir/src/circuit/black_box_functions.rs +++ b/noir/noir-repo/acvm-repo/acir/src/circuit/black_box_functions.rs @@ -9,6 +9,8 @@ use strum_macros::EnumIter; #[derive(Clone, Debug, Hash, Copy, PartialEq, Eq, Serialize, Deserialize)] #[cfg_attr(test, derive(EnumIter))] pub enum BlackBoxFunc { + /// Encrypts the input using AES128. + AES128Encrypt, /// Bitwise AND. AND, /// Bitwise XOR. @@ -74,6 +76,7 @@ impl std::fmt::Display for BlackBoxFunc { impl BlackBoxFunc { pub fn name(&self) -> &'static str { match self { + BlackBoxFunc::AES128Encrypt => "aes128_encrypt", BlackBoxFunc::SHA256 => "sha256", BlackBoxFunc::SchnorrVerify => "schnorr_verify", BlackBoxFunc::Blake2s => "blake2s", @@ -103,6 +106,7 @@ impl BlackBoxFunc { pub fn lookup(op_name: &str) -> Option { match op_name { + "aes128_encrypt" => Some(BlackBoxFunc::AES128Encrypt), "sha256" => Some(BlackBoxFunc::SHA256), "schnorr_verify" => Some(BlackBoxFunc::SchnorrVerify), "blake2s" => Some(BlackBoxFunc::Blake2s), diff --git a/noir/noir-repo/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs b/noir/noir-repo/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs index 51b2ca9d51f..115a33c1c9d 100644 --- a/noir/noir-repo/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs +++ b/noir/noir-repo/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs @@ -12,6 +12,12 @@ pub struct FunctionInput { #[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum BlackBoxFuncCall { + AES128Encrypt { + inputs: Vec, + iv: Box<[FunctionInput; 16]>, + key: Box<[FunctionInput; 16]>, + outputs: Vec, + }, AND { lhs: FunctionInput, rhs: FunctionInput, @@ -177,6 +183,7 @@ pub enum BlackBoxFuncCall { impl BlackBoxFuncCall { pub fn get_black_box_func(&self) -> BlackBoxFunc { match self { + BlackBoxFuncCall::AES128Encrypt { .. } => BlackBoxFunc::AES128Encrypt, BlackBoxFuncCall::AND { .. } => BlackBoxFunc::AND, BlackBoxFuncCall::XOR { .. } => BlackBoxFunc::XOR, BlackBoxFuncCall::RANGE { .. } => BlackBoxFunc::RANGE, @@ -210,7 +217,8 @@ impl BlackBoxFuncCall { pub fn get_inputs_vec(&self) -> Vec { match self { - BlackBoxFuncCall::SHA256 { inputs, .. } + BlackBoxFuncCall::AES128Encrypt { inputs, .. } + | BlackBoxFuncCall::SHA256 { inputs, .. } | BlackBoxFuncCall::Blake2s { inputs, .. } | BlackBoxFuncCall::Blake3 { inputs, .. } | BlackBoxFuncCall::PedersenCommitment { inputs, .. } @@ -326,7 +334,8 @@ impl BlackBoxFuncCall { BlackBoxFuncCall::Sha256Compression { outputs, .. } => outputs.to_vec(), - BlackBoxFuncCall::Poseidon2Permutation { outputs, .. } => outputs.to_vec(), + BlackBoxFuncCall::AES128Encrypt { outputs, .. } + | BlackBoxFuncCall::Poseidon2Permutation { outputs, .. } => outputs.to_vec(), BlackBoxFuncCall::AND { output, .. } | BlackBoxFuncCall::XOR { output, .. } diff --git a/noir/noir-repo/acvm-repo/acir/tests/test_program_serialization.rs b/noir/noir-repo/acvm-repo/acir/tests/test_program_serialization.rs index 63cba788c02..d9327f784e6 100644 --- a/noir/noir-repo/acvm-repo/acir/tests/test_program_serialization.rs +++ b/noir/noir-repo/acvm-repo/acir/tests/test_program_serialization.rs @@ -83,10 +83,10 @@ fn multi_scalar_mul_circuit() { let bytes = Program::serialize_program(&program); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 85, 76, 65, 14, 0, 32, 8, 82, 179, 58, 244, 105, 159, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 85, 76, 65, 14, 0, 32, 8, 82, 179, 186, 244, 104, 159, 30, 45, 218, 136, 141, 33, 40, 186, 93, 76, 208, 57, 31, 93, 96, 136, 47, 250, 146, 188, - 209, 39, 181, 131, 131, 187, 148, 110, 240, 246, 101, 38, 63, 180, 243, 97, 3, 86, 121, 62, - 10, 153, 0, 0, 0, + 209, 39, 181, 131, 131, 187, 148, 110, 240, 246, 101, 38, 63, 180, 243, 97, 3, 125, 173, + 118, 131, 153, 0, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -112,11 +112,10 @@ fn pedersen_circuit() { let bytes = Program::serialize_program(&program); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 74, 9, 10, 0, 0, 4, 115, 149, 255, 127, 88, 8, 133, - 213, 218, 137, 80, 144, 32, 182, 79, 213, 151, 173, 61, 5, 121, 245, 91, 103, 255, 191, 3, - 7, 16, 26, 112, 158, 113, 0, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 74, 73, 10, 0, 0, 4, 180, 29, 252, 255, 193, 66, 40, + 76, 77, 179, 34, 20, 36, 136, 237, 83, 245, 101, 107, 79, 65, 94, 253, 214, 217, 255, 239, + 192, 1, 43, 124, 181, 238, 113, 0, 0, 0, ]; - assert_eq!(bytes, expected_serialization) } @@ -159,7 +158,7 @@ fn schnorr_verify_circuit() { let expected_serialization: Vec = vec![ 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 85, 210, 85, 78, 67, 81, 24, 133, 209, 226, 238, 238, 238, 238, 238, 165, 148, 82, 102, 193, 252, 135, 64, 232, 78, 87, 147, 114, 147, 147, 5, - 47, 132, 252, 251, 107, 41, 212, 191, 159, 218, 107, 241, 115, 236, 228, 111, 237, 181, + 47, 132, 252, 251, 107, 41, 212, 191, 159, 218, 107, 241, 115, 236, 226, 111, 237, 181, 178, 173, 246, 186, 107, 175, 157, 29, 236, 100, 23, 27, 175, 135, 189, 236, 99, 63, 7, 56, 200, 33, 14, 115, 132, 163, 28, 227, 56, 39, 56, 201, 41, 78, 115, 134, 179, 156, 227, 60, 23, 184, 200, 37, 46, 115, 133, 171, 92, 227, 58, 55, 184, 201, 45, 110, 115, 135, 187, @@ -171,8 +170,8 @@ fn schnorr_verify_circuit() { 180, 144, 14, 210, 64, 246, 95, 46, 212, 119, 207, 230, 217, 59, 91, 103, 231, 108, 156, 125, 183, 237, 186, 107, 207, 125, 59, 30, 218, 239, 216, 110, 167, 246, 58, 183, 211, 165, 125, 174, 237, 114, 107, 143, 123, 59, 60, 186, 255, 179, 187, 191, 186, 115, 209, 125, 75, - 238, 90, 118, 207, 138, 59, 54, 110, 214, 184, 91, 161, 233, 158, 255, 190, 63, 165, 188, - 93, 151, 233, 3, 0, 0, + 238, 90, 118, 207, 138, 59, 54, 110, 214, 184, 91, 161, 233, 158, 255, 190, 63, 71, 59, 68, + 130, 233, 3, 0, 0, ]; assert_eq!(bytes, expected_serialization) diff --git a/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/aes128.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/aes128.rs new file mode 100644 index 00000000000..c02c59a174f --- /dev/null +++ b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/aes128.rs @@ -0,0 +1,32 @@ +use acir::{ + circuit::opcodes::FunctionInput, + native_types::{Witness, WitnessMap}, + FieldElement, +}; +use acvm_blackbox_solver::aes128_encrypt; + +use crate::{pwg::insert_value, OpcodeResolutionError}; + +use super::utils::{to_u8_array, to_u8_vec}; + +pub(super) fn solve_aes128_encryption_opcode( + initial_witness: &mut WitnessMap, + inputs: &[FunctionInput], + iv: &[FunctionInput; 16], + key: &[FunctionInput; 16], + outputs: &[Witness], +) -> Result<(), OpcodeResolutionError> { + let scalars = to_u8_vec(initial_witness, inputs)?; + + let iv = to_u8_array(initial_witness, iv)?; + let key = to_u8_array(initial_witness, key)?; + + let ciphertext = aes128_encrypt(&scalars, iv, key)?; + + // Write witness assignments + for (output_witness, value) in outputs.iter().zip(ciphertext.into_iter()) { + insert_value(output_witness, FieldElement::from(value as u128), initial_witness)?; + } + + Ok(()) +} diff --git a/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/mod.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/mod.rs index 8ed7d2a2711..a74f44b79dc 100644 --- a/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/mod.rs +++ b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/mod.rs @@ -6,12 +6,14 @@ use acir::{ use acvm_blackbox_solver::{blake2s, blake3, keccak256, keccakf1600, sha256}; use self::{ - bigint::AcvmBigIntSolver, hash::solve_poseidon2_permutation_opcode, pedersen::pedersen_hash, + aes128::solve_aes128_encryption_opcode, bigint::AcvmBigIntSolver, + hash::solve_poseidon2_permutation_opcode, pedersen::pedersen_hash, }; use super::{insert_value, OpcodeNotSolvable, OpcodeResolutionError}; use crate::{pwg::witness_to_value, BlackBoxFunctionSolver}; +mod aes128; pub(crate) mod bigint; mod embedded_curve_ops; mod hash; @@ -19,6 +21,7 @@ mod logic; mod pedersen; mod range; mod signature; +pub(crate) mod utils; use embedded_curve_ops::{embedded_curve_add, multi_scalar_mul}; // Hash functions should eventually be exposed for external consumers. @@ -68,6 +71,9 @@ pub(crate) fn solve( } match bb_func { + BlackBoxFuncCall::AES128Encrypt { inputs, iv, key, outputs } => { + solve_aes128_encryption_opcode(initial_witness, inputs, iv, key, outputs) + } BlackBoxFuncCall::AND { lhs, rhs, output } => and(initial_witness, lhs, rhs, output), BlackBoxFuncCall::XOR { lhs, rhs, output } => xor(initial_witness, lhs, rhs, output), BlackBoxFuncCall::RANGE { input } => solve_range_opcode(initial_witness, input), diff --git a/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/signature/ecdsa.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/signature/ecdsa.rs index b113c801251..ce2e57e0bd7 100644 --- a/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/signature/ecdsa.rs +++ b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/signature/ecdsa.rs @@ -5,9 +5,13 @@ use acir::{ }; use acvm_blackbox_solver::{ecdsa_secp256k1_verify, ecdsa_secp256r1_verify}; -use crate::{pwg::insert_value, OpcodeResolutionError}; - -use super::{to_u8_array, to_u8_vec}; +use crate::{ + pwg::{ + blackbox::utils::{to_u8_array, to_u8_vec}, + insert_value, + }, + OpcodeResolutionError, +}; pub(crate) fn secp256k1_prehashed( initial_witness: &mut WitnessMap, diff --git a/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/signature/mod.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/signature/mod.rs index bd223ecd0c9..0cfb96740b8 100644 --- a/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/signature/mod.rs +++ b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/signature/mod.rs @@ -1,36 +1,2 @@ -use acir::{circuit::opcodes::FunctionInput, native_types::WitnessMap}; - -use crate::pwg::{witness_to_value, OpcodeResolutionError}; - -fn to_u8_array( - initial_witness: &WitnessMap, - inputs: &[FunctionInput; N], -) -> Result<[u8; N], OpcodeResolutionError> { - let mut result = [0; N]; - for (it, input) in result.iter_mut().zip(inputs) { - let witness_value_bytes = witness_to_value(initial_witness, input.witness)?.to_be_bytes(); - let byte = witness_value_bytes - .last() - .expect("Field element must be represented by non-zero amount of bytes"); - *it = *byte; - } - Ok(result) -} - -fn to_u8_vec( - initial_witness: &WitnessMap, - inputs: &[FunctionInput], -) -> Result, OpcodeResolutionError> { - let mut result = Vec::with_capacity(inputs.len()); - for input in inputs { - let witness_value_bytes = witness_to_value(initial_witness, input.witness)?.to_be_bytes(); - let byte = witness_value_bytes - .last() - .expect("Field element must be represented by non-zero amount of bytes"); - result.push(*byte); - } - Ok(result) -} - pub(super) mod ecdsa; pub(super) mod schnorr; diff --git a/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/signature/schnorr.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/signature/schnorr.rs index 3d0216fa217..7b085d9ff47 100644 --- a/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/signature/schnorr.rs +++ b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/signature/schnorr.rs @@ -1,6 +1,8 @@ -use super::{to_u8_array, to_u8_vec}; use crate::{ - pwg::{insert_value, witness_to_value, OpcodeResolutionError}, + pwg::{ + blackbox::utils::{to_u8_array, to_u8_vec}, + insert_value, witness_to_value, OpcodeResolutionError, + }, BlackBoxFunctionSolver, }; use acir::{ diff --git a/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/utils.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/utils.rs new file mode 100644 index 00000000000..700f30890ae --- /dev/null +++ b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/utils.rs @@ -0,0 +1,33 @@ +use acir::{circuit::opcodes::FunctionInput, native_types::WitnessMap}; + +use crate::pwg::{witness_to_value, OpcodeResolutionError}; + +pub(crate) fn to_u8_array( + initial_witness: &WitnessMap, + inputs: &[FunctionInput; N], +) -> Result<[u8; N], OpcodeResolutionError> { + let mut result = [0; N]; + for (it, input) in result.iter_mut().zip(inputs) { + let witness_value_bytes = witness_to_value(initial_witness, input.witness)?.to_be_bytes(); + let byte = witness_value_bytes + .last() + .expect("Field element must be represented by non-zero amount of bytes"); + *it = *byte; + } + Ok(result) +} + +pub(crate) fn to_u8_vec( + initial_witness: &WitnessMap, + inputs: &[FunctionInput], +) -> Result, OpcodeResolutionError> { + let mut result = Vec::with_capacity(inputs.len()); + for input in inputs { + let witness_value_bytes = witness_to_value(initial_witness, input.witness)?.to_be_bytes(); + let byte = witness_value_bytes + .last() + .expect("Field element must be represented by non-zero amount of bytes"); + result.push(*byte); + } + Ok(result) +} diff --git a/noir/noir-repo/acvm-repo/acvm_js/test/shared/multi_scalar_mul.ts b/noir/noir-repo/acvm-repo/acvm_js/test/shared/multi_scalar_mul.ts index c76fe264e12..8ee0a067a3a 100644 --- a/noir/noir-repo/acvm-repo/acvm_js/test/shared/multi_scalar_mul.ts +++ b/noir/noir-repo/acvm-repo/acvm_js/test/shared/multi_scalar_mul.ts @@ -1,8 +1,8 @@ // See `multi_scalar_mul_circuit` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 85, 76, 65, 14, 0, 32, 8, 82, 179, 58, 244, 105, 159, 30, 45, 218, 136, 141, 33, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 85, 76, 65, 14, 0, 32, 8, 82, 179, 186, 244, 104, 159, 30, 45, 218, 136, 141, 33, 40, 186, 93, 76, 208, 57, 31, 93, 96, 136, 47, 250, 146, 188, 209, 39, 181, 131, 131, 187, 148, 110, 240, 246, 101, - 38, 63, 180, 243, 97, 3, 86, 121, 62, 10, 153, 0, 0, 0, + 38, 63, 180, 243, 97, 3, 125, 173, 118, 131, 153, 0, 0, 0, ]); export const initialWitnessMap = new Map([ [1, '0x0000000000000000000000000000000000000000000000000000000000000001'], diff --git a/noir/noir-repo/acvm-repo/acvm_js/test/shared/pedersen.ts b/noir/noir-repo/acvm-repo/acvm_js/test/shared/pedersen.ts index e8ddc893d87..6e3ec403d65 100644 --- a/noir/noir-repo/acvm-repo/acvm_js/test/shared/pedersen.ts +++ b/noir/noir-repo/acvm-repo/acvm_js/test/shared/pedersen.ts @@ -1,7 +1,7 @@ // See `pedersen_circuit` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 74, 9, 10, 0, 0, 4, 115, 149, 255, 127, 88, 8, 133, 213, 218, 137, 80, 144, 32, - 182, 79, 213, 151, 173, 61, 5, 121, 245, 91, 103, 255, 191, 3, 7, 16, 26, 112, 158, 113, 0, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 74, 73, 10, 0, 0, 4, 180, 29, 252, 255, 193, 66, 40, 76, 77, 179, 34, 20, 36, + 136, 237, 83, 245, 101, 107, 79, 65, 94, 253, 214, 217, 255, 239, 192, 1, 43, 124, 181, 238, 113, 0, 0, 0, ]); export const initialWitnessMap = new Map([[1, '0x0000000000000000000000000000000000000000000000000000000000000001']]); diff --git a/noir/noir-repo/acvm-repo/acvm_js/test/shared/schnorr_verify.ts b/noir/noir-repo/acvm-repo/acvm_js/test/shared/schnorr_verify.ts index a207aa12b2c..05fcc47e3aa 100644 --- a/noir/noir-repo/acvm-repo/acvm_js/test/shared/schnorr_verify.ts +++ b/noir/noir-repo/acvm-repo/acvm_js/test/shared/schnorr_verify.ts @@ -2,7 +2,7 @@ export const bytecode = Uint8Array.from([ 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 85, 210, 85, 78, 67, 81, 24, 133, 209, 226, 238, 238, 238, 238, 238, 165, 148, 82, 102, 193, 252, 135, 64, 232, 78, 87, 147, 114, 147, 147, 5, 47, 132, 252, 251, 107, 41, 212, 191, 159, 218, 107, 241, - 115, 236, 228, 111, 237, 181, 178, 173, 246, 186, 107, 175, 157, 29, 236, 100, 23, 27, 175, 135, 189, 236, 99, 63, 7, + 115, 236, 226, 111, 237, 181, 178, 173, 246, 186, 107, 175, 157, 29, 236, 100, 23, 27, 175, 135, 189, 236, 99, 63, 7, 56, 200, 33, 14, 115, 132, 163, 28, 227, 56, 39, 56, 201, 41, 78, 115, 134, 179, 156, 227, 60, 23, 184, 200, 37, 46, 115, 133, 171, 92, 227, 58, 55, 184, 201, 45, 110, 115, 135, 187, 220, 227, 62, 15, 120, 200, 35, 30, 243, 132, 167, 60, 227, 57, 47, 120, 201, 43, 94, 243, 134, 183, 188, 227, 61, 31, 248, 200, 39, 62, 243, 133, 175, 77, 59, 230, 123, @@ -11,7 +11,7 @@ export const bytecode = Uint8Array.from([ 210, 72, 250, 72, 27, 233, 34, 77, 164, 135, 180, 144, 14, 210, 64, 246, 95, 46, 212, 119, 207, 230, 217, 59, 91, 103, 231, 108, 156, 125, 183, 237, 186, 107, 207, 125, 59, 30, 218, 239, 216, 110, 167, 246, 58, 183, 211, 165, 125, 174, 237, 114, 107, 143, 123, 59, 60, 186, 255, 179, 187, 191, 186, 115, 209, 125, 75, 238, 90, 118, 207, 138, 59, 54, 110, - 214, 184, 91, 161, 233, 158, 255, 190, 63, 165, 188, 93, 151, 233, 3, 0, 0, + 214, 184, 91, 161, 233, 158, 255, 190, 63, 71, 59, 68, 130, 233, 3, 0, 0, ]); export const initialWitnessMap = new Map([ diff --git a/noir/noir-repo/acvm-repo/blackbox_solver/Cargo.toml b/noir/noir-repo/acvm-repo/blackbox_solver/Cargo.toml index 4dc7df03599..f40046acad6 100644 --- a/noir/noir-repo/acvm-repo/blackbox_solver/Cargo.toml +++ b/noir/noir-repo/acvm-repo/blackbox_solver/Cargo.toml @@ -37,6 +37,7 @@ p256 = { version = "0.11.0", features = [ "arithmetic", ] } +libaes = "0.7.0" [features] default = ["bn254"] diff --git a/noir/noir-repo/acvm-repo/blackbox_solver/src/aes128.rs b/noir/noir-repo/acvm-repo/blackbox_solver/src/aes128.rs new file mode 100644 index 00000000000..a4c6a228744 --- /dev/null +++ b/noir/noir-repo/acvm-repo/blackbox_solver/src/aes128.rs @@ -0,0 +1,12 @@ +use crate::BlackBoxResolutionError; +use libaes::Cipher; + +pub fn aes128_encrypt( + inputs: &[u8], + iv: [u8; 16], + key: [u8; 16], +) -> Result, BlackBoxResolutionError> { + let cipher = Cipher::new_128(&key); + let encrypted = cipher.cbc_encrypt(&iv, inputs); + Ok(encrypted) +} diff --git a/noir/noir-repo/acvm-repo/blackbox_solver/src/lib.rs b/noir/noir-repo/acvm-repo/blackbox_solver/src/lib.rs index 0f57f2ce7da..a68b52a2a62 100644 --- a/noir/noir-repo/acvm-repo/blackbox_solver/src/lib.rs +++ b/noir/noir-repo/acvm-repo/blackbox_solver/src/lib.rs @@ -10,11 +10,13 @@ use acir::BlackBoxFunc; use thiserror::Error; +mod aes128; mod bigint; mod curve_specific_solver; mod ecdsa; mod hash; +pub use aes128::aes128_encrypt; pub use bigint::BigIntSolver; pub use curve_specific_solver::{BlackBoxFunctionSolver, StubbedBlackBoxSolver}; pub use ecdsa::{ecdsa_secp256k1_verify, ecdsa_secp256r1_verify}; diff --git a/noir/noir-repo/acvm-repo/brillig/src/black_box.rs b/noir/noir-repo/acvm-repo/brillig/src/black_box.rs index 2a61bb2b96d..15abc19ed90 100644 --- a/noir/noir-repo/acvm-repo/brillig/src/black_box.rs +++ b/noir/noir-repo/acvm-repo/brillig/src/black_box.rs @@ -5,6 +5,13 @@ use serde::{Deserialize, Serialize}; /// They are implemented as native functions in the VM. #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub enum BlackBoxOp { + /// Encrypts a message using AES128. + AES128Encrypt { + inputs: HeapVector, + iv: HeapArray, + key: HeapArray, + outputs: HeapVector, + }, /// Calculates the SHA256 hash of the inputs. Sha256 { message: HeapVector, diff --git a/noir/noir-repo/acvm-repo/brillig_vm/src/black_box.rs b/noir/noir-repo/acvm-repo/brillig_vm/src/black_box.rs index 1cd08563677..c999b5bf330 100644 --- a/noir/noir-repo/acvm-repo/brillig_vm/src/black_box.rs +++ b/noir/noir-repo/acvm-repo/brillig_vm/src/black_box.rs @@ -2,8 +2,8 @@ use acir::brillig::{BlackBoxOp, HeapArray, HeapVector}; use acir::{BlackBoxFunc, FieldElement}; use acvm_blackbox_solver::BigIntSolver; use acvm_blackbox_solver::{ - blake2s, blake3, ecdsa_secp256k1_verify, ecdsa_secp256r1_verify, keccak256, keccakf1600, - sha256, sha256compression, BlackBoxFunctionSolver, BlackBoxResolutionError, + aes128_encrypt, blake2s, blake3, ecdsa_secp256k1_verify, ecdsa_secp256r1_verify, keccak256, + keccakf1600, sha256, sha256compression, BlackBoxFunctionSolver, BlackBoxResolutionError, }; use crate::memory::MemoryValue; @@ -38,6 +38,25 @@ pub(crate) fn evaluate_black_box( bigint_solver: &mut BigIntSolver, ) -> Result<(), BlackBoxResolutionError> { match op { + BlackBoxOp::AES128Encrypt { inputs, iv, key, outputs } => { + let bb_func = black_box_function_from_op(op); + + let inputs = to_u8_vec(read_heap_vector(memory, inputs)); + + let iv: [u8; 16] = to_u8_vec(read_heap_array(memory, iv)).try_into().map_err(|_| { + BlackBoxResolutionError::Failed(bb_func, "Invalid iv length".to_string()) + })?; + let key: [u8; 16] = + to_u8_vec(read_heap_array(memory, key)).try_into().map_err(|_| { + BlackBoxResolutionError::Failed(bb_func, "Invalid ley length".to_string()) + })?; + let ciphertext = aes128_encrypt(&inputs, iv, key)?; + + memory.write(outputs.size, ciphertext.len().into()); + memory.write_slice(memory.read_ref(outputs.pointer), &to_value_vec(&ciphertext)); + + Ok(()) + } BlackBoxOp::Sha256 { message, output } => { let message = to_u8_vec(read_heap_vector(memory, message)); let bytes = sha256(message.as_slice())?; @@ -281,6 +300,7 @@ pub(crate) fn evaluate_black_box( fn black_box_function_from_op(op: &BlackBoxOp) -> BlackBoxFunc { match op { + BlackBoxOp::AES128Encrypt { .. } => BlackBoxFunc::AES128Encrypt, BlackBoxOp::Sha256 { .. } => BlackBoxFunc::SHA256, BlackBoxOp::Blake2s { .. } => BlackBoxFunc::Blake2s, BlackBoxOp::Blake3 { .. } => BlackBoxFunc::Blake3, diff --git a/noir/noir-repo/aztec_macros/src/transforms/contract_interface.rs b/noir/noir-repo/aztec_macros/src/transforms/contract_interface.rs index 5f68ce98c8a..1afe0a30068 100644 --- a/noir/noir-repo/aztec_macros/src/transforms/contract_interface.rs +++ b/noir/noir-repo/aztec_macros/src/transforms/contract_interface.rs @@ -126,6 +126,7 @@ pub fn stub_function(aztec_visibility: &str, func: &NoirFunction) -> String { target_contract: self.target_contract, selector: {}, args: args_acc, + gas_opts: dep::aztec::context::gas::GasOpts::default(), }}", args, is_void, fn_selector, ); diff --git a/noir/noir-repo/aztec_macros/src/transforms/functions.rs b/noir/noir-repo/aztec_macros/src/transforms/functions.rs index 0a628f473ef..90563c6085c 100644 --- a/noir/noir-repo/aztec_macros/src/transforms/functions.rs +++ b/noir/noir-repo/aztec_macros/src/transforms/functions.rs @@ -1,10 +1,10 @@ use convert_case::{Case, Casing}; use noirc_errors::Span; -use noirc_frontend::ast; +use noirc_frontend::ast::{self, FunctionKind}; use noirc_frontend::ast::{ BlockExpression, ConstrainKind, ConstrainStatement, Expression, ExpressionKind, - ForLoopStatement, ForRange, FunctionKind, FunctionReturnType, Ident, Literal, NoirFunction, - NoirStruct, Param, PathKind, Pattern, Signedness, Statement, StatementKind, UnresolvedType, + ForLoopStatement, ForRange, FunctionReturnType, Ident, Literal, NoirFunction, NoirStruct, + Param, PathKind, Pattern, Signedness, Statement, StatementKind, UnresolvedType, UnresolvedTypeData, Visibility, }; @@ -103,6 +103,8 @@ pub fn transform_function( let return_type = create_return_type(&return_type_name); func.def.return_type = return_type; func.def.return_visibility = Visibility::Public; + } else { + func.def.return_visibility = Visibility::Public; } // Public functions should have unconstrained auto-inferred diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs index 9262047fb60..d982d864d06 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs @@ -401,6 +401,28 @@ pub(crate) fn convert_black_box_call( unreachable!("ICE: Sha256Compression expects two array argument, one array result") } } + BlackBoxFunc::AES128Encrypt => { + if let ( + [inputs, BrilligVariable::BrilligArray(iv), BrilligVariable::BrilligArray(key)], + [BrilligVariable::SingleAddr(out_len), outputs], + ) = (function_arguments, function_results) + { + let inputs = convert_array_or_vector(brillig_context, inputs, bb_func); + let outputs = convert_array_or_vector(brillig_context, outputs, bb_func); + let output_vec = outputs.to_heap_vector(); + brillig_context.black_box_op_instruction(BlackBoxOp::AES128Encrypt { + inputs: inputs.to_heap_vector(), + iv: iv.to_heap_array(), + key: key.to_heap_array(), + outputs: output_vec, + }); + brillig_context.mov_instruction(out_len.address, output_vec.size); + // Returns slice, so we need to allocate memory for it after the fact + brillig_context.increase_free_memory_pointer_instruction(output_vec.size); + } else { + unreachable!("ICE: AES128Encrypt expects three array arguments, one array result") + } + } } } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs index 4843026293b..667ccf6ddbe 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs @@ -266,6 +266,16 @@ impl DebugShow { /// Debug function for black_box_op pub(crate) fn black_box_op_instruction(&self, op: &BlackBoxOp) { match op { + BlackBoxOp::AES128Encrypt { inputs, iv, key, outputs } => { + debug_println!( + self.enable_debug_trace, + " AES128 ENCRYPT {} {} {} -> {}", + inputs, + iv, + key, + outputs + ); + } BlackBoxOp::Sha256 { message, output } => { debug_println!(self.enable_debug_trace, " SHA256 {} -> {}", message, output); } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs index 2d546bc7d86..407cdf0a17f 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs @@ -1324,6 +1324,21 @@ impl AcirContext { self.big_int_ctx.new_big_int(FieldElement::from(modulus_id as u128)); (modulus, vec![result_id.bigint_id(), result_id.modulus_id()]) } + BlackBoxFunc::AES128Encrypt => { + let invalid_input = "aes128_encrypt - operation requires a plaintext to encrypt"; + let input_size = match inputs.first().expect(invalid_input) { + AcirValue::Array(values) => Ok::(values.len()), + AcirValue::DynamicArray(dyn_array) => Ok::(dyn_array.len), + _ => { + return Err(RuntimeError::InternalError(InternalError::General { + message: "aes128_encrypt requires an array of inputs".to_string(), + call_stack: self.get_call_stack(), + })); + } + }?; + output_count = input_size + (16 - input_size % 16); + (vec![], vec![FieldElement::from(output_count as u128)]) + } _ => (vec![], vec![]), }; diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs index c0b427046ad..c1249ae41c8 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs @@ -188,6 +188,18 @@ impl GeneratedAcir { let outputs_clone = outputs.clone(); let black_box_func_call = match func_name { + BlackBoxFunc::AES128Encrypt => BlackBoxFuncCall::AES128Encrypt { + inputs: inputs[0].clone(), + iv: inputs[1] + .clone() + .try_into() + .expect("Compiler should generate correct size inputs"), + key: inputs[2] + .clone() + .try_into() + .expect("Compiler should generate correct size inputs"), + outputs, + }, BlackBoxFunc::AND => { BlackBoxFuncCall::AND { lhs: inputs[0][0], rhs: inputs[1][0], output: outputs[0] } } @@ -642,7 +654,8 @@ fn black_box_func_expected_input_size(name: BlackBoxFunc) -> Option { // All of the hash/cipher methods will take in a // variable number of inputs. - BlackBoxFunc::Keccak256 + BlackBoxFunc::AES128Encrypt + | BlackBoxFunc::Keccak256 | BlackBoxFunc::SHA256 | BlackBoxFunc::Blake2s | BlackBoxFunc::Blake3 @@ -736,6 +749,9 @@ fn black_box_expected_output_size(name: BlackBoxFunc) -> Option { // Recursive aggregation has a variable number of outputs BlackBoxFunc::RecursiveAggregation => None, + + // AES encryption returns a variable number of outputs + BlackBoxFunc::AES128Encrypt => None, } } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs index 98794f3dbf8..7ad6a625f9c 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs @@ -492,6 +492,7 @@ fn simplify_black_box_func( ) } BlackBoxFunc::Sha256Compression => SimplifyResult::None, //TODO(Guillaume) + BlackBoxFunc::AES128Encrypt => SimplifyResult::None, } } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/ast.rs b/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/ast.rs index 4bd501c07ba..15c27ee344c 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/ast.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/ast.rs @@ -5,13 +5,14 @@ use noirc_errors::{ Location, }; -use super::HirType; use crate::hir_def::function::FunctionSignature; use crate::{ ast::{BinaryOpKind, IntegerBitSize, Signedness, Visibility}, token::{Attributes, FunctionAttribute}, }; +use super::HirType; + /// The monomorphized AST is expression-based, all statements are also /// folded into this expression enum. Compared to the HIR, the monomorphized /// AST has several differences: diff --git a/noir/noir-repo/docs/docs/noir/standard_library/black_box_fns.md b/noir/noir-repo/docs/docs/noir/standard_library/black_box_fns.md index ceb37774785..eeead580969 100644 --- a/noir/noir-repo/docs/docs/noir/standard_library/black_box_fns.md +++ b/noir/noir-repo/docs/docs/noir/standard_library/black_box_fns.md @@ -12,6 +12,7 @@ The ACVM spec defines a set of blackbox functions which backends will be expecte Here is a list of the current black box functions: +- [AES128](./cryptographic_primitives/ciphers.mdx#aes128) - [SHA256](./cryptographic_primitives/hashes.mdx#sha256) - [Schnorr signature verification](./cryptographic_primitives/schnorr.mdx) - [Blake2s](./cryptographic_primitives/hashes.mdx#blake2s) diff --git a/noir/noir-repo/docs/docs/noir/standard_library/cryptographic_primitives/ciphers.mdx b/noir/noir-repo/docs/docs/noir/standard_library/cryptographic_primitives/ciphers.mdx new file mode 100644 index 00000000000..0103791d2e4 --- /dev/null +++ b/noir/noir-repo/docs/docs/noir/standard_library/cryptographic_primitives/ciphers.mdx @@ -0,0 +1,28 @@ +--- +title: Ciphers +description: + Learn about the implemented ciphers ready to use for any Noir project +keywords: + [ciphers, Noir project, aes128, encrypt] +sidebar_position: 0 +--- + +import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; + +## aes128 + +Given a plaintext as an array of bytes, returns the corresponding aes128 ciphertext (CBC mode). Input padding is automatically performed using PKCS#7, so that the output length is `input.len() + (16 - input.len() % 16)`. + +#include_code aes128 noir_stdlib/src/aes128.nr rust + +```rust +fn main() { + let input: [u8; 4] = [0, 12, 3, 15] // Random bytes, will be padded to 16 bytes. + let iv: [u8; 16] = [0; 16]; // Initialisation vector + let key: [u8; 16] = [0; 16] // AES key + let ciphertext = std::aes128::aes128_encrypt(inputs.as_bytes(), iv.as_bytes(), key.as_bytes()); // In this case, the output length will be 16 bytes. +} +``` + + + \ No newline at end of file diff --git a/noir/noir-repo/noir_stdlib/src/aes128.nr b/noir/noir-repo/noir_stdlib/src/aes128.nr new file mode 100644 index 00000000000..ac5c2b48ad8 --- /dev/null +++ b/noir/noir-repo/noir_stdlib/src/aes128.nr @@ -0,0 +1,5 @@ + +#[foreign(aes128_encrypt)] +// docs:start:aes128 +pub fn aes128_encrypt(input: [u8; N], iv: [u8; 16], key: [u8; 16]) -> [u8] {} +// docs:end:aes128 diff --git a/noir/noir-repo/noir_stdlib/src/grumpkin_scalar.nr b/noir/noir-repo/noir_stdlib/src/grumpkin_scalar.nr deleted file mode 100644 index dd4b029d0a7..00000000000 --- a/noir/noir-repo/noir_stdlib/src/grumpkin_scalar.nr +++ /dev/null @@ -1,22 +0,0 @@ -// TODO(https://github.com/noir-lang/noir/issues/4968): move to aztec noir-protocol-circuits -struct GrumpkinScalar { - low: Field, - high: Field, -} - -impl GrumpkinScalar { - pub fn new(low: Field, high: Field) -> Self { - // TODO: check that the low and high value fit within the grumpkin modulus - GrumpkinScalar { low, high } - } -} - -global GRUMPKIN_SCALAR_SERIALIZED_LEN: Field = 2; - -pub fn deserialize_grumpkin_scalar(fields: [Field; GRUMPKIN_SCALAR_SERIALIZED_LEN]) -> GrumpkinScalar { - GrumpkinScalar { low: fields[0], high: fields[1] } -} - -pub fn serialize_grumpkin_scalar(scalar: GrumpkinScalar) -> [Field; GRUMPKIN_SCALAR_SERIALIZED_LEN] { - [scalar.low, scalar.high] -} diff --git a/noir/noir-repo/noir_stdlib/src/lib.nr b/noir/noir-repo/noir_stdlib/src/lib.nr index 73fc7a28417..33504be0b9a 100644 --- a/noir/noir-repo/noir_stdlib/src/lib.nr +++ b/noir/noir-repo/noir_stdlib/src/lib.nr @@ -1,4 +1,5 @@ mod hash; +mod aes128; mod array; mod slice; mod merkle; @@ -6,7 +7,6 @@ mod schnorr; mod ecdsa_secp256k1; mod ecdsa_secp256r1; mod eddsa; -mod grumpkin_scalar; mod embedded_curve_ops; mod sha256; mod sha512; diff --git a/noir/noir-repo/test_programs/execution_success/aes128_encrypt/Nargo.toml b/noir/noir-repo/test_programs/execution_success/aes128_encrypt/Nargo.toml new file mode 100644 index 00000000000..29425131cff --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/aes128_encrypt/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "aes128_encrypt" +type = "bin" +authors = [""] +compiler_version = ">=0.27.0" + +[dependencies] \ No newline at end of file diff --git a/noir/noir-repo/test_programs/execution_success/aes128_encrypt/Prover.toml b/noir/noir-repo/test_programs/execution_success/aes128_encrypt/Prover.toml new file mode 100644 index 00000000000..b6b684790e1 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/aes128_encrypt/Prover.toml @@ -0,0 +1,4 @@ +inputs = "kevlovesrust" +iv = "0000000000000000" +key = "0000000000000000" +output = "F40E7EACAB28D0BAADB8E269EE7ACDBF" \ No newline at end of file diff --git a/noir/noir-repo/test_programs/execution_success/aes128_encrypt/src/main.nr b/noir/noir-repo/test_programs/execution_success/aes128_encrypt/src/main.nr new file mode 100644 index 00000000000..f6ed0f309c3 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/aes128_encrypt/src/main.nr @@ -0,0 +1,44 @@ +use dep::std; + +unconstrained fn decode_ascii(ascii: u8) -> u8 { + if ascii < 58 { + ascii - 48 + } else if ascii < 71 { + ascii - 55 + } else { + ascii - 87 + } +} + +unconstrained fn decode_hex(s: str) -> [u8; M] { + let mut result: [u8; M] = [0; M]; + let as_bytes = s.as_bytes(); + for i in 0..N { + if i % 2 != 0 { + continue; + } + result[i/2] = decode_ascii(as_bytes[i]) * 16 + decode_ascii(as_bytes[i + 1]); + } + result +} + +unconstrained fn cipher(plaintext: [u8; 12], iv: [u8; 16], key: [u8; 16]) -> [u8; 16] { + let slice_res = std::aes128::aes128_encrypt(plaintext, iv, key); + let mut result = [0; 16]; + for i in 0..16 { + result[i] = slice_res[i]; + } + result +} + +fn main(inputs: str<12>, iv: str<16>, key: str<16>, output: str<32>) { + let result = std::aes128::aes128_encrypt(inputs.as_bytes(), iv.as_bytes(), key.as_bytes()); + let output_bytes: [u8; 16] = decode_hex(output); + for i in 0..16 { + assert(result[i] == output_bytes[i]); + } + let unconstrained_result = cipher(inputs.as_bytes(), iv.as_bytes(), key.as_bytes()); + for i in 0..16 { + assert(unconstrained_result[i] == output_bytes[i]); + } +} diff --git a/noir/noir-repo/tooling/debugger/ignored-tests.txt b/noir/noir-repo/tooling/debugger/ignored-tests.txt index d08f5609645..cda26169421 100644 --- a/noir/noir-repo/tooling/debugger/ignored-tests.txt +++ b/noir/noir-repo/tooling/debugger/ignored-tests.txt @@ -24,3 +24,4 @@ fold_distinct_return fold_fibonacci fold_complex_outputs slice_init_with_complex_type +hashmap diff --git a/noir/noir-repo/tooling/noirc_abi/src/lib.rs b/noir/noir-repo/tooling/noirc_abi/src/lib.rs index 35f85b5f59c..7e89a102a98 100644 --- a/noir/noir-repo/tooling/noirc_abi/src/lib.rs +++ b/noir/noir-repo/tooling/noirc_abi/src/lib.rs @@ -221,7 +221,7 @@ impl From<&AbiType> for PrintableType { } AbiType::Array { length, typ } => { let borrowed: &AbiType = typ.borrow(); - PrintableType::Array { length: Some(*length), typ: Box::new(borrowed.into()) } + PrintableType::Array { length: *length, typ: Box::new(borrowed.into()) } } AbiType::Boolean => PrintableType::Boolean, AbiType::Struct { path, fields } => { diff --git a/scripts/earthly-ci b/scripts/earthly-ci index 84ffc925c7b..e424c0a4201 100755 --- a/scripts/earthly-ci +++ b/scripts/earthly-ci @@ -3,6 +3,21 @@ # The silver lining is if Earthly does crash, the cache can pick up the build. set -eu -o pipefail +MAX_WAIT_TIME=300 # Maximum wait time in seconds +WAIT_INTERVAL=10 # Interval between checks in seconds +elapsed_time=0 + +while ! [ -f /run/.earthly-bootstrap ] ; do + echo "Did not detect .earthly-bootstrap. Waiting for runner to fully initialize..." + if [ $elapsed_time -ge $MAX_WAIT_TIME ]; then + echo "Earthly bootstrap did not become available within $MAX_WAIT_TIME seconds... did the runner start correctly?" + exit 1 + fi + + sleep $WAIT_INTERVAL + elapsed_time=$((elapsed_time + WAIT_INTERVAL)) +done + OUTPUT_FILE=$(mktemp) INCONSISTENT_GRAPH_STATE_COUNT=0 # Counter for 'inconsistent graph state' errors @@ -22,12 +37,12 @@ while [ $ATTEMPT_COUNT -lt $MAX_ATTEMPTS ]; do # Check the output for specific errors if grep 'failed to get edge: inconsistent graph state' $OUTPUT_FILE >/dev/null || grep 'failed to get state for index' $OUTPUT_FILE >/dev/null ; then INCONSISTENT_GRAPH_STATE_COUNT=$((INCONSISTENT_GRAPH_STATE_COUNT + 1)) - if [ "$INCONSISTENT_GRAPH_STATE_COUNT" -eq 2 ]; then + if [ "$INCONSISTENT_GRAPH_STATE_COUNT" -eq 3 ]; then echo "Unable to recover from 'inconsistent graph state' or 'failed to get state for index'. Connect to spot runner and run 'earthly prune'." exit 1 fi - echo "Got 'inconsistent graph state' or 'failed to get state for index'. Sleeping for 20 seconds and retrying." - sleep 20 + echo "Got 'inconsistent graph state' or 'failed to get state for index'. Sleeping for 30 seconds and retrying." + sleep 30 elif grep 'Error: pull ping error: pull ping response' $OUTPUT_FILE >/dev/null; then echo "Got 'Error: pull ping error: pull ping response', intermittent failure when writing out images to docker" elif grep '================================= System Info ==================================' $OUTPUT_FILE >/dev/null; then diff --git a/yarn-project/aztec-node/src/aztec-node/http_rpc_server.ts b/yarn-project/aztec-node/src/aztec-node/http_rpc_server.ts index dd283644826..8270b171ffe 100644 --- a/yarn-project/aztec-node/src/aztec-node/http_rpc_server.ts +++ b/yarn-project/aztec-node/src/aztec-node/http_rpc_server.ts @@ -5,6 +5,7 @@ import { L2Block, LogId, NullifierMembershipWitness, + PublicDataWitness, SiblingPath, Tx, TxEffect, @@ -37,6 +38,7 @@ export function createAztecNodeRpcServer(node: AztecNode) { TxEffect, LogId, TxHash, + PublicDataWitness, SiblingPath, }, { Tx, TxReceipt, EncryptedL2BlockL2Logs, UnencryptedL2BlockL2Logs, NullifierMembershipWitness }, diff --git a/yarn-project/aztec/CHANGELOG.md b/yarn-project/aztec/CHANGELOG.md index 3f0d5f16310..1f3185ae61c 100644 --- a/yarn-project/aztec/CHANGELOG.md +++ b/yarn-project/aztec/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.38.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.37.0...aztec-package-v0.38.0) (2024-05-07) + + +### Features + +* Proving benchmark ([#6051](https://github.com/AztecProtocol/aztec-packages/issues/6051)) ([644bd85](https://github.com/AztecProtocol/aztec-packages/commit/644bd8525f6de8b71d6cc299baf3fda94b68abbb)) + ## [0.37.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.36.0...aztec-package-v0.37.0) (2024-05-02) diff --git a/yarn-project/aztec/package.json b/yarn-project/aztec/package.json index f8c277e0494..f01354896f8 100644 --- a/yarn-project/aztec/package.json +++ b/yarn-project/aztec/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/aztec", - "version": "0.37.0", + "version": "0.38.0", "type": "module", "exports": { ".": "./dest/index.js" diff --git a/yarn-project/circuit-types/src/index.ts b/yarn-project/circuit-types/src/index.ts index fb71e18a5dc..67763d4d6d3 100644 --- a/yarn-project/circuit-types/src/index.ts +++ b/yarn-project/circuit-types/src/index.ts @@ -6,6 +6,7 @@ export * from './l2_block.js'; export * from './body.js'; export * from './l2_block_downloader/index.js'; export * from './l2_block_source.js'; +export * from './public_data_witness.js'; export * from './tx_effect.js'; export * from './logs/index.js'; export * from './merkle_tree_id.js'; diff --git a/yarn-project/circuit-types/src/interfaces/aztec-node.ts b/yarn-project/circuit-types/src/interfaces/aztec-node.ts index fd8b71c1126..d59543943e8 100644 --- a/yarn-project/circuit-types/src/interfaces/aztec-node.ts +++ b/yarn-project/circuit-types/src/interfaces/aztec-node.ts @@ -20,6 +20,7 @@ import { type LogType, } from '../logs/index.js'; import { type MerkleTreeId } from '../merkle_tree_id.js'; +import { type PublicDataWitness } from '../public_data_witness.js'; import { type SiblingPath } from '../sibling_path/index.js'; import { type ProcessOutput, type Tx, type TxHash, type TxReceipt } from '../tx/index.js'; import { type TxEffect } from '../tx_effect.js'; @@ -27,7 +28,6 @@ import { type SequencerConfig } from './configs.js'; import { type L2BlockNumber } from './l2_block_number.js'; import { type NullifierMembershipWitness } from './nullifier_tree.js'; import { type ProverConfig } from './prover-client.js'; -import { type PublicDataWitness } from './public_data_tree.js'; /** * The aztec node. diff --git a/yarn-project/circuit-types/src/interfaces/index.ts b/yarn-project/circuit-types/src/interfaces/index.ts index 71bfeeda4a2..5b13506853c 100644 --- a/yarn-project/circuit-types/src/interfaces/index.ts +++ b/yarn-project/circuit-types/src/interfaces/index.ts @@ -4,7 +4,6 @@ export * from './pxe.js'; export * from './sync-status.js'; export * from './configs.js'; export * from './nullifier_tree.js'; -export * from './public_data_tree.js'; export * from './prover-client.js'; export * from './proving-job.js'; export * from './block-prover.js'; diff --git a/yarn-project/circuit-types/src/interfaces/public_data_tree.ts b/yarn-project/circuit-types/src/interfaces/public_data_tree.ts deleted file mode 100644 index 1ae620154ee..00000000000 --- a/yarn-project/circuit-types/src/interfaces/public_data_tree.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { Fr, type PUBLIC_DATA_TREE_HEIGHT, type PublicDataTreeLeafPreimage } from '@aztec/circuits.js'; - -import { type SiblingPath } from '../sibling_path/index.js'; - -/** - * Public data witness. - * @remarks This allows to prove either: - * - That a slot in the public data tree is empty (0 value) if it falls within the range of the leaf. - * - The current value of a slot in the public data tree if it matches exactly the slot of the leaf. - */ -export class PublicDataWitness { - constructor( - /** - * The index of the leaf in the public data tree. - */ - public readonly index: bigint, - /** - * Preimage of a low leaf. All the slots in the range of the leaf are empty, and the current value of the - * leaf slot is stored in the leaf. - */ - public readonly leafPreimage: PublicDataTreeLeafPreimage, - /** - * Sibling path to prove membership of the leaf. - */ - public readonly siblingPath: SiblingPath, - ) {} - - /** - * Returns a field array representation of a public data witness. - * @returns A field array representation of a public data witness. - */ - public toFields(): Fr[] { - return [ - new Fr(this.index), - new Fr(this.leafPreimage.slot), - new Fr(this.leafPreimage.value), - new Fr(this.leafPreimage.nextIndex), - new Fr(this.leafPreimage.nextSlot), - ...this.siblingPath.toFields(), - ]; - } -} diff --git a/yarn-project/circuit-types/src/public_data_witness.test.ts b/yarn-project/circuit-types/src/public_data_witness.test.ts new file mode 100644 index 00000000000..c2b031217d9 --- /dev/null +++ b/yarn-project/circuit-types/src/public_data_witness.test.ts @@ -0,0 +1,31 @@ +import { PUBLIC_DATA_TREE_HEIGHT, PublicDataTreeLeafPreimage } from '@aztec/circuits.js'; +import { fr } from '@aztec/circuits.js/testing'; +import { toBufferBE } from '@aztec/foundation/bigint-buffer'; +import { randomInt } from '@aztec/foundation/crypto'; + +import { PublicDataWitness } from './public_data_witness.js'; +import { SiblingPath } from './sibling_path/sibling_path.js'; + +describe('contract_artifact', () => { + it('serializes and deserializes an instance', () => { + const witness = makePublicDataWitness(randomInt(1000000)); + + const deserialized = PublicDataWitness.fromBuffer(witness.toBuffer()); + expect(deserialized).toEqual(witness); + }); +}); + +/** + * Factory function to create a PublicDataWitness based on given seed. + * @param seed - A seed used to derive all parameters. + * @returns A new instance of PublicDataWitness. + */ +function makePublicDataWitness(seed: number): PublicDataWitness { + const leafPreimage = new PublicDataTreeLeafPreimage(fr(seed + 1), fr(seed + 2), fr(seed + 3), BigInt(seed + 4)); + const siblingPath = new SiblingPath( + PUBLIC_DATA_TREE_HEIGHT, + Array.from({ length: PUBLIC_DATA_TREE_HEIGHT }, (_, i) => toBufferBE(BigInt(seed + i + 6), 32)), + ); + + return new PublicDataWitness(BigInt(seed + 5), leafPreimage, siblingPath); +} diff --git a/yarn-project/circuit-types/src/public_data_witness.ts b/yarn-project/circuit-types/src/public_data_witness.ts new file mode 100644 index 00000000000..a8a80a76e0c --- /dev/null +++ b/yarn-project/circuit-types/src/public_data_witness.ts @@ -0,0 +1,79 @@ +import { Fr, PUBLIC_DATA_TREE_HEIGHT, PublicDataTreeLeafPreimage } from '@aztec/circuits.js'; +import { toBigIntBE } from '@aztec/foundation/bigint-buffer'; +import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; + +import { SiblingPath } from './sibling_path/sibling_path.js'; + +/** + * Public data witness. + * @remarks This allows to prove either: + * - That a slot in the public data tree is empty (0 value) if it falls within the range of the leaf. + * - The current value of a slot in the public data tree if it matches exactly the slot of the leaf. + */ +export class PublicDataWitness { + constructor( + /** + * The index of the leaf in the public data tree. + */ + public readonly index: bigint, + /** + * Preimage of a low leaf. All the slots in the range of the leaf are empty, and the current value of the + * leaf slot is stored in the leaf. + */ + public readonly leafPreimage: PublicDataTreeLeafPreimage, + /** + * Sibling path to prove membership of the leaf. + */ + public readonly siblingPath: SiblingPath, + ) {} + + /** + * Returns a field array representation of a public data witness. + * @returns A field array representation of a public data witness. + */ + public toFields(): Fr[] { + return [ + new Fr(this.index), + new Fr(this.leafPreimage.slot), + new Fr(this.leafPreimage.value), + new Fr(this.leafPreimage.nextIndex), + new Fr(this.leafPreimage.nextSlot), + ...this.siblingPath.toFields(), + ]; + } + + toBuffer(): Buffer { + return serializeToBuffer([this.index, this.leafPreimage, this.siblingPath]); + } + + /** + * Returns a string representation of the TxEffect object. + */ + toString(): string { + return this.toBuffer().toString('hex'); + } + + /** + * Deserializes an PublicDataWitness object from a buffer. + * @param buf - Buffer or BufferReader to deserialize. + * @returns An instance of PublicDataWitness. + */ + static fromBuffer(buffer: Buffer | BufferReader): PublicDataWitness { + const reader = BufferReader.asReader(buffer); + + return new PublicDataWitness( + toBigIntBE(reader.readBytes(32)), + reader.readObject(PublicDataTreeLeafPreimage), + SiblingPath.fromBuffer(reader.readBytes(4 + 32 * PUBLIC_DATA_TREE_HEIGHT)), + ); + } + + /** + * Deserializes an PublicDataWitness object from a string. + * @param str - String to deserialize. + * @returns An instance of PublicDataWitness. + */ + static fromString(str: string) { + return PublicDataWitness.fromBuffer(Buffer.from(str, 'hex')); + } +} diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index 70d3975bfea..b7eef53b018 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -74,7 +74,7 @@ export const REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE = 0xe7af816635466f128568edb04c9fa024f6c87fb9010fdbffa68b3d99n; export const DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE = 0x85864497636cf755ae7bde03f267ce01a520981c21c3682aaf82a631n; -export const DEPLOYER_CONTRACT_ADDRESS = 0x0097949bb96834550868230a1b6cc242d1f662f7c52946245e4e73da1b8b2165n; +export const DEPLOYER_CONTRACT_ADDRESS = 0x2e9c386f07e22a1d24e677ab70407b2dd0adbc7cafb9c822bf249685d6a2e4ccn; export const DEFAULT_GAS_LIMIT = 1_000_000_000; export const DEFAULT_TEARDOWN_GAS_LIMIT = 100_000_000; export const DEFAULT_MAX_FEE_PER_GAS = 10; diff --git a/yarn-project/end-to-end/Earthfile b/yarn-project/end-to-end/Earthfile index c7b91115513..e6b2b72fd26 100644 --- a/yarn-project/end-to-end/Earthfile +++ b/yarn-project/end-to-end/Earthfile @@ -15,16 +15,15 @@ E2E_COMPOSE_TEST: ELSE LET CMD="docker-compose" END - # In CI, we do an optimization to push these images to docker once - # We still want the default code path to work with no faff locally - # To not rebuild unnecessarily, we pass --skip_build=true in CI - IF [ $skip_build != "true" ] + # Let docker compose know about the pushed tags above + ENV AZTEC_DOCKER_TAG=$(git rev-parse HEAD) + # Optimize to not cause serial behavior if image already exists + IF ! docker image ls --format '{{.Repository}}:{{.Tag}}' | grep "aztecprotocol/aztec:$AZTEC_DOCKER_TAG" && \ + docker image ls --format '{{.Repository}}:{{.Tag}}' | grep "aztecprotocol/end-to-end:$AZTEC_DOCKER_TAG" WAIT BUILD ../+export-e2e-test-images END END - # Let docker compose know about the pushed tags above - ENV AZTEC_DOCKER_TAG=$(git rev-parse HEAD) # Run our docker compose, ending whenever sandbox ends, filtering out noisy eth_getLogs RUN $CMD -p $project_name -f $compose_file up --exit-code-from=end-to-end --force-recreate @@ -42,10 +41,133 @@ UPLOAD_LOGS: ENV COMMIT_HASH=$COMMIT_HASH RUN --secret AWS_ACCESS_KEY_ID --secret AWS_SECRET_ACCESS_KEY /usr/src/scripts/logs/upload_logs_to_s3.sh /usr/var/log -# Define e2e tests -e2e-tests: +e2e-2-pxes: + FROM ../+end-to-end + RUN yarn test ./src/e2e_2_pxes.test.ts + +e2e-account-contracts: + FROM ../+end-to-end + RUN yarn test ./src/e2e_account_contracts.test.ts + +e2e-auth-contract: + FROM ../+end-to-end + RUN yarn test ./src/e2e_auth_contract.test.ts + +e2e-authwit: + FROM ../+end-to-end + RUN yarn test ./src/e2e_authwit.test.ts + +e2e-avm-simulator: + FROM ../+end-to-end + RUN yarn test ./src/e2e_avm_simulator.test.ts + +e2e-blacklist-token-contract: + FROM ../+end-to-end + RUN yarn test ./src/e2e_blacklist_token_contract + +e2e-block-building: + FROM ../+end-to-end + RUN yarn test ./src/e2e_block_building.test.ts + +e2e-card-game: + FROM ../+end-to-end + RUN yarn test ./src/e2e_card_game.test.ts + +e2e-cheat-codes: + FROM ../+end-to-end + RUN yarn test ./src/e2e_cheat_codes.test.ts + +e2e-counter-contract: + FROM ../+end-to-end + RUN yarn test ./src/e2e_counter_contract.test.ts + +e2e-cross-chain-messaging: + FROM ../+end-to-end + RUN yarn test ./src/e2e_cross_chain_messaging.test.ts + +e2e-crowdfunding-and-claim: + FROM ../+end-to-end + RUN yarn test ./src/e2e_crowdfunding_and_claim.test.ts + +e2e-delegate-calls: + FROM ../+end-to-end + RUN yarn test ./src/e2e_delegate_calls + +e2e-deploy-contract: + FROM ../+end-to-end + RUN yarn test ./src/e2e_deploy_contract + +e2e-encryption: + FROM ../+end-to-end + RUN yarn test ./src/e2e_encryption.test.ts + +e2e-escrow-contract: + FROM ../+end-to-end + RUN yarn test ./src/e2e_escrow_contract.test.ts + +e2e-key-registry: + FROM ../+end-to-end + RUN yarn test ./src/e2e_key_registry.test.ts + +e2e-lending-contract: + FROM ../+end-to-end + RUN yarn test ./src/e2e_lending_contract.test.ts + +e2e-max-block-number: + FROM ../+end-to-end + RUN yarn test ./src/e2e_max_block_number.test.ts + +e2e-multiple-accounts-1-enc-key: + FROM ../+end-to-end + RUN yarn test ./src/e2e_multiple_accounts_1_enc_key.test.ts + +e2e-nested-contract: + FROM ../+end-to-end + RUN yarn test ./src/e2e_nested_contract + +e2e-non-contract-account: + FROM ../+end-to-end + RUN yarn test ./src/e2e_non_contract_account.test.ts + +e2e-note-getter: + FROM ../+end-to-end + RUN yarn test ./src/e2e_note_getter.test.ts + +e2e-ordering: + FROM ../+end-to-end + RUN yarn test ./src/e2e_ordering.test.ts + +e2e-outbox: + FROM ../+end-to-end + RUN yarn test ./src/e2e_outbox.test.ts + +e2e-pending-note-hashes-contract: + FROM ../+end-to-end + RUN yarn test ./src/e2e_pending_note_hashes_contract.test.ts + +e2e-private-voting-contract: + FROM ../+end-to-end + RUN yarn test ./src/e2e_private_voting_contract.test.ts + +e2e-public-cross-chain-messaging: + FROM ../+end-to-end + RUN yarn test ./src/e2e_public_cross_chain_messaging + +e2e-public-to-private-messaging: + FROM ../+end-to-end + RUN yarn test ./src/e2e_public_to_private_messaging.test.ts + +e2e-state-vars: + FROM ../+end-to-end + RUN yarn test ./src/e2e_state_vars.test.ts + +e2e-static-calls: + FROM ../+end-to-end + RUN yarn test ./src/e2e_static_calls.test.ts + +e2e-token-contract: FROM ../+end-to-end - RUN yarn test ./src/e2e + RUN yarn test ./src/e2e_token_contract flakey-e2e-tests: FROM ../+end-to-end diff --git a/yarn-project/end-to-end/package.json b/yarn-project/end-to-end/package.json index fcc621d59ad..ea3a6893cfd 100644 --- a/yarn-project/end-to-end/package.json +++ b/yarn-project/end-to-end/package.json @@ -15,7 +15,7 @@ "clean": "rm -rf ./dest .tsbuildinfo", "formatting": "run -T prettier --check ./src \"!src/web/main.js\" && run -T eslint ./src", "formatting:fix": "run -T eslint --fix ./src && run -T prettier -w ./src", - "test": "LOG_LEVEL=${LOG_LEVEL:-silent} DEBUG_COLORS=1 NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --testTimeout=300000 --forceExit", + "test": "LOG_LEVEL=${LOG_LEVEL:-verbose} DEBUG_COLORS=1 NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --testTimeout=300000 --forceExit", "test:integration": "concurrently -k -s first -c reset,dim -n test,anvil \"yarn test:integration:run\" \"anvil\"", "test:integration:run": "NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --no-cache --runInBand --config jest.integration.config.json" }, diff --git a/yarn-project/end-to-end/package.local.json b/yarn-project/end-to-end/package.local.json index 6e3666e9fa6..a998d042e73 100644 --- a/yarn-project/end-to-end/package.local.json +++ b/yarn-project/end-to-end/package.local.json @@ -2,6 +2,6 @@ "scripts": { "build": "yarn clean && tsc -b && webpack", "formatting": "run -T prettier --check ./src \"!src/web/main.js\" && run -T eslint ./src", - "test": "LOG_LEVEL=${LOG_LEVEL:-silent} DEBUG_COLORS=1 NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --testTimeout=300000 --forceExit" + "test": "LOG_LEVEL=${LOG_LEVEL:-verbose} DEBUG_COLORS=1 NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --testTimeout=300000 --forceExit" } } diff --git a/yarn-project/end-to-end/src/client_prover_integration/client_prover_integration.test.ts b/yarn-project/end-to-end/src/client_prover_integration/client_prover_integration.test.ts index ec6c32d11a6..ed244b2da64 100644 --- a/yarn-project/end-to-end/src/client_prover_integration/client_prover_integration.test.ts +++ b/yarn-project/end-to-end/src/client_prover_integration/client_prover_integration.test.ts @@ -4,13 +4,8 @@ import { type BBNativeProofCreator } from '@aztec/pxe'; import { ClientProverTest } from './client_prover_test.js'; -const TIMEOUT = 300_000; - -async function verifyProof(_1: ClientProtocolArtifact, _2: Tx, _3: BBNativeProofCreator) { - // TODO(@PhilWindle): Will verify proof once the circuits are fixed - await Promise.resolve(); - //const result = await proofCreator.verifyProof(circuitType, tx.proof); - expect(true).toBeTruthy(); +async function verifyProof(circuitType: ClientProtocolArtifact, tx: Tx, proofCreator: BBNativeProofCreator) { + await expect(proofCreator.verifyProof(circuitType, tx.proof)).resolves.not.toThrow(); } describe('client_prover_integration', () => { @@ -32,47 +27,39 @@ describe('client_prover_integration', () => { await t.tokenSim.check(); }); - it( - 'private transfer less than balance', - async () => { - logger.info( - `Starting test using function: ${provenAsset.address}:${provenAsset.methods.balance_of_private.selector}`, - ); - const balance0 = await provenAsset.methods.balance_of_private(accounts[0].address).simulate(); - const amount = balance0 / 2n; - expect(amount).toBeGreaterThan(0n); - const interaction = provenAsset.methods.transfer(accounts[0].address, accounts[1].address, amount, 0); - const provenTx = await interaction.prove(); + it('private transfer less than balance', async () => { + logger.info( + `Starting test using function: ${provenAsset.address}:${provenAsset.methods.balance_of_private.selector}`, + ); + const balance0 = await provenAsset.methods.balance_of_private(accounts[0].address).simulate(); + const amount = balance0 / 2n; + expect(amount).toBeGreaterThan(0n); + const interaction = provenAsset.methods.transfer(accounts[0].address, accounts[1].address, amount, 0); + const provenTx = await interaction.prove(); - // This will recursively verify all app and kernel circuits involved in the private stage of this transaction! - logger.info(`Verifying kernel tail proof`); - await verifyProof('PrivateKernelTailArtifact', provenTx, proofCreator!); + // This will recursively verify all app and kernel circuits involved in the private stage of this transaction! + logger.info(`Verifying kernel tail proof`); + await verifyProof('PrivateKernelTailArtifact', provenTx, proofCreator!); - await interaction.send().wait(); - tokenSim.transferPrivate(accounts[0].address, accounts[1].address, amount); - }, - TIMEOUT, - ); + await interaction.send().wait(); + tokenSim.transferPrivate(accounts[0].address, accounts[1].address, amount); + }); - it( - 'public transfer less than balance', - async () => { - logger.info( - `Starting test using function: ${provenAsset.address}:${provenAsset.methods.balance_of_public.selector}`, - ); - const balance0 = await provenAsset.methods.balance_of_public(accounts[0].address).simulate(); - const amount = balance0 / 2n; - expect(amount).toBeGreaterThan(0n); - const interaction = provenAsset.methods.transfer(accounts[0].address, accounts[1].address, amount, 0); - const provenTx = await interaction.prove(); + it('public transfer less than balance', async () => { + logger.info( + `Starting test using function: ${provenAsset.address}:${provenAsset.methods.balance_of_public.selector}`, + ); + const balance0 = await provenAsset.methods.balance_of_public(accounts[0].address).simulate(); + const amount = balance0 / 2n; + expect(amount).toBeGreaterThan(0n); + const interaction = provenAsset.methods.transfer_public(accounts[0].address, accounts[1].address, amount, 0); + const provenTx = await interaction.prove(); - // This will recursively verify all app and kernel circuits involved in the private stage of this transaction! - logger.info(`Verifying kernel tail to public proof`); - await verifyProof('PrivateKernelTailToPublicArtifact', provenTx, proofCreator!); + // This will recursively verify all app and kernel circuits involved in the private stage of this transaction! + logger.info(`Verifying kernel tail to public proof`); + await verifyProof('PrivateKernelTailToPublicArtifact', provenTx, proofCreator!); - await interaction.send().wait(); - tokenSim.transferPublic(accounts[0].address, accounts[1].address, amount); - }, - TIMEOUT, - ); + await interaction.send().wait(); + tokenSim.transferPublic(accounts[0].address, accounts[1].address, amount); + }); }); diff --git a/yarn-project/end-to-end/src/e2e_avm_simulator.test.ts b/yarn-project/end-to-end/src/e2e_avm_simulator.test.ts index 435bc3e8be0..6691ad45c34 100644 --- a/yarn-project/end-to-end/src/e2e_avm_simulator.test.ts +++ b/yarn-project/end-to-end/src/e2e_avm_simulator.test.ts @@ -1,4 +1,4 @@ -import { type AccountWallet, AztecAddress, Fr, FunctionSelector, TxStatus } from '@aztec/aztec.js'; +import { type AccountWallet, AztecAddress, BatchCall, Fr, FunctionSelector, TxStatus } from '@aztec/aztec.js'; import { GasSettings } from '@aztec/circuits.js'; import { AvmAcvmInteropTestContract, @@ -60,6 +60,19 @@ describe('e2e_avm_simulator', () => { await avmContract.methods.add_storage_map(address, 100).send().wait(); expect(await avmContract.methods.view_storage_map(address).simulate()).toEqual(200n); }); + + it('Preserves storage across enqueued public calls', async () => { + const address = AztecAddress.fromBigInt(9090n); + // This will create 1 tx with 2 public calls in it. + await new BatchCall(wallet, [ + avmContract.methods.set_storage_map(address, 100).request(), + avmContract.methods.add_storage_map(address, 100).request(), + ]) + .send() + .wait(); + // On a separate tx, we check the result. + expect(await avmContract.methods.view_storage_map(address).simulate()).toEqual(200n); + }); }); describe('Contract instance', () => { @@ -85,6 +98,18 @@ describe('e2e_avm_simulator', () => { tx = await avmContract.methods.assert_nullifier_exists(nullifier).send().wait(); expect(tx.status).toEqual(TxStatus.MINED); }); + + it('Emit and check in separate enqueued calls but same tx', async () => { + const nullifier = new Fr(123456); + + // This will create 1 tx with 2 public calls in it. + await new BatchCall(wallet, [ + avmContract.methods.new_nullifier(nullifier).request(), + avmContract.methods.assert_nullifier_exists(nullifier).request(), + ]) + .send() + .wait(); + }); }); }); diff --git a/yarn-project/noir-protocol-circuits-types/package.json b/yarn-project/noir-protocol-circuits-types/package.json index c8bcbff9171..83f918856b4 100644 --- a/yarn-project/noir-protocol-circuits-types/package.json +++ b/yarn-project/noir-protocol-circuits-types/package.json @@ -52,6 +52,7 @@ "@noir-lang/acvm_js": "portal:../../noir/packages/acvm_js", "@noir-lang/noirc_abi": "portal:../../noir/packages/noirc_abi", "@noir-lang/types": "portal:../../noir/packages/types", + "change-case": "^5.4.4", "tslib": "^2.4.0" }, "devDependencies": { diff --git a/yarn-project/noir-protocol-circuits-types/src/index.ts b/yarn-project/noir-protocol-circuits-types/src/index.ts index 6e48dddc7a3..20cff6648be 100644 --- a/yarn-project/noir-protocol-circuits-types/src/index.ts +++ b/yarn-project/noir-protocol-circuits-types/src/index.ts @@ -2,7 +2,6 @@ import { type BaseOrMergeRollupPublicInputs, type BaseParityInputs, type BaseRollupInputs, - Fr, type KernelCircuitPublicInputs, type MergeRollupInputs, type ParityPublicInputs, @@ -25,6 +24,7 @@ import { type NoirCompiledCircuit } from '@aztec/types/noir'; import { type ForeignCallInput, + type ForeignCallOutput, type WasmBlackBoxFunctionSolver, createBlackBoxSolver, executeCircuitWithBlackBoxSolver, @@ -71,26 +71,22 @@ import { mapRootRollupInputsToNoir, mapRootRollupPublicInputsFromNoir, } from './type_conversion.js'; -import { type ReturnType as BaseParityReturnType } from './types/parity_base_types.js'; -import { type ReturnType as RootParityReturnType } from './types/parity_root_types.js'; import { - type InputType as InitInputType, - type ReturnType as InitReturnType, -} from './types/private_kernel_init_types.js'; -import { - type InputType as InnerInputType, - type ReturnType as InnerReturnType, -} from './types/private_kernel_inner_types.js'; -import { type InputType as TailToPublicInputType } from './types/private_kernel_tail_to_public_types.js'; -import { - type InputType as TailInputType, - type ReturnType as TailReturnType, -} from './types/private_kernel_tail_types.js'; -import { type ReturnType as PublicPublicPreviousReturnType } from './types/public_kernel_app_logic_types.js'; -import { type ReturnType as PublicSetupReturnType } from './types/public_kernel_setup_types.js'; -import { type ReturnType as BaseRollupReturnType } from './types/rollup_base_types.js'; -import { type ReturnType as MergeRollupReturnType } from './types/rollup_merge_types.js'; -import { type ReturnType as RootRollupReturnType } from './types/rollup_root_types.js'; + type ParityBaseReturnType as BaseParityReturnType, + type RollupBaseReturnType as BaseRollupReturnType, + type PrivateKernelInitInputType as InitInputType, + type PrivateKernelInitReturnType as InitReturnType, + type PrivateKernelInnerInputType as InnerInputType, + type PrivateKernelInnerReturnType as InnerReturnType, + type RollupMergeReturnType as MergeRollupReturnType, + type PublicKernelAppLogicReturnType as PublicPublicPreviousReturnType, + type PublicKernelSetupReturnType as PublicSetupReturnType, + type ParityRootReturnType as RootParityReturnType, + type RollupRootReturnType as RootRollupReturnType, + type PrivateKernelTailInputType as TailInputType, + type PrivateKernelTailReturnType as TailReturnType, + type PrivateKernelTailToPublicInputType as TailToPublicInputType, +} from './types/index.js'; // TODO(Tom): This should be exported from noirc_abi /** @@ -755,7 +751,7 @@ async function executePrivateKernelTailToPublicWithACVM( return decodedInputs.return_value as PublicPublicPreviousReturnType; } -export const foreignCallHandler = (name: string, args: ForeignCallInput[]) => { +export function foreignCallHandler(name: string, args: ForeignCallInput[]): Promise { const log = createDebugLogger('aztec:noir-protocol-circuits:oracle'); if (name === 'debugLog') { @@ -766,5 +762,5 @@ export const foreignCallHandler = (name: string, args: ForeignCallInput[]) => { throw Error(`unexpected oracle during execution: ${name}`); } - return Promise.resolve([`0x${Buffer.alloc(Fr.SIZE_IN_BYTES).toString('hex')}`]); -}; + return Promise.resolve([]); +} diff --git a/yarn-project/noir-protocol-circuits-types/src/scripts/abi_type_with_generics.ts b/yarn-project/noir-protocol-circuits-types/src/scripts/abi_type_with_generics.ts new file mode 100644 index 00000000000..c03dbb62a65 --- /dev/null +++ b/yarn-project/noir-protocol-circuits-types/src/scripts/abi_type_with_generics.ts @@ -0,0 +1,127 @@ +import { type AbiType } from '@aztec/foundation/abi'; + +/** + * Represents a binding to a generic. + */ +export class BindingId { + constructor(public id: number, public isNumeric: boolean) {} +} + +export type StructType = { + path: string; + fields: { name: string; type: AbiTypeWithGenerics }[]; + /** The generics of the struct, bound to the fields */ + generics: BindingId[]; +}; + +export type StringType = { + kind: 'string'; + length: number | BindingId; +}; + +export type Constant = { + kind: 'constant'; + value: number; +}; + +export type ArrayType = { + kind: 'array'; + length: number | BindingId; + type: AbiTypeWithGenerics; +}; + +export type Tuple = { + kind: 'tuple'; + fields: AbiTypeWithGenerics[]; +}; + +export type Struct = { + kind: 'struct'; + structType: StructType; + /** The arguments are the concrete instantiation of the generics in the struct type. */ + args: AbiTypeWithGenerics[]; +}; + +export type AbiTypeWithGenerics = + | { kind: 'field' } + | { kind: 'boolean' } + | { kind: 'integer'; sign: string; width: number } + | { kind: 'binding'; id: BindingId } + | { kind: 'constant'; value: number } + | StringType + | ArrayType + | Tuple + | Struct; + +/** + * Maps an ABI type to an ABI type with generics. + * This performs pure type conversion, and does not generate any bindings. + */ +export function mapAbiTypeToAbiTypeWithGenerics(abiType: AbiType): AbiTypeWithGenerics { + switch (abiType.kind) { + case 'field': + case 'boolean': + case 'string': + case 'integer': + return abiType; + case 'array': + return { + kind: 'array', + length: abiType.length, + type: mapAbiTypeToAbiTypeWithGenerics(abiType.type), + }; + case 'struct': { + const structType = { + path: abiType.path, + fields: abiType.fields.map(field => ({ + name: field.name, + type: mapAbiTypeToAbiTypeWithGenerics(field.type), + })), + generics: [], + }; + return { + kind: 'struct', + structType, + args: [], + }; + } + } +} + +/** + * Finds the structs in an ABI type. + * This won't explore nested structs. + */ +export function findStructsInType(abiType: AbiTypeWithGenerics): Struct[] { + switch (abiType.kind) { + case 'field': + case 'boolean': + case 'string': + case 'integer': + return []; + case 'array': + return findStructsInType(abiType.type); + case 'tuple': + return abiType.fields.flatMap(findStructsInType); + case 'struct': + return [abiType]; + default: { + return []; + } + } +} + +/** + * Finds all the structs in an ABI type, including nested structs. + */ +export function findAllStructsInType(abiType: AbiTypeWithGenerics): Struct[] { + let allStructs: Struct[] = []; + let lastStructs = findStructsInType(abiType); + while (lastStructs.length > 0) { + allStructs = allStructs.concat(lastStructs); + lastStructs = lastStructs.flatMap(struct => + struct.structType.fields.flatMap(field => findStructsInType(field.type)), + ); + } + return allStructs; +} diff --git a/yarn-project/noir-protocol-circuits-types/src/scripts/demonomorphizer.ts b/yarn-project/noir-protocol-circuits-types/src/scripts/demonomorphizer.ts new file mode 100644 index 00000000000..bd654ca5a18 --- /dev/null +++ b/yarn-project/noir-protocol-circuits-types/src/scripts/demonomorphizer.ts @@ -0,0 +1,274 @@ +import { + type AbiTypeWithGenerics, + type ArrayType, + BindingId, + type Constant, + type StringType, + type Struct, + type StructType, + type Tuple, + findAllStructsInType, + findStructsInType, +} from './abi_type_with_generics.js'; + +/** + * Demonomorphizes a list of ABI types adding generics to structs. + * Since monomorphization of the generics destroys information, this process is not guaranteed to return the original structure. + * However, it should succesfully unify all struct types that share the same name and field names. + */ +export class Demonomorphizer { + private variantsMap: Map; + private visitedStructs: Map; + private lastBindingId = 0; + + /** + * Demonomorphizes the passed in ABI types, mutating them. + */ + public static demonomorphize(abiTypes: AbiTypeWithGenerics[]) { + new Demonomorphizer(abiTypes); + } + + private constructor(private types: AbiTypeWithGenerics[]) { + this.variantsMap = new Map(); + this.fillVariantsMap(); + + this.visitedStructs = new Map(); + this.demonomorphizeStructs(); + } + + /** + * Finds all the variants of the structs in the types. + * A variant is every use of a struct with the same name and fields. + */ + private fillVariantsMap() { + const allStructs = this.types.flatMap(findAllStructsInType); + for (const struct of allStructs) { + const id = Demonomorphizer.buildIdForStruct(struct.structType); + const variants = this.variantsMap.get(id) ?? []; + variants.push(struct); + this.variantsMap.set(id, variants); + } + } + + private demonomorphizeStructs() { + for (const type of this.types) { + const topLevelStructs = findStructsInType(type); + for (const struct of topLevelStructs) { + this.demonomorphizeStruct(struct); + } + } + } + + /** + * Demonomorphizes a struct, by demonomorphizing its dependencies first. + * Then it'll unify the types of the variants generating a unique generic type. + * It'll also generate args that instantiate the generic type with the concrete arguments for each variant. + */ + private demonomorphizeStruct(struct: Struct) { + const id = Demonomorphizer.buildIdForStruct(struct.structType); + if (this.visitedStructs.has(id)) { + return; + } + const dependencies = struct.structType.fields.flatMap(field => findStructsInType(field.type)); + for (const dependency of dependencies) { + this.demonomorphizeStruct(dependency); + } + if (this.visitedStructs.has(id)) { + throw new Error('Circular dependency detected'); + } + + const variants = this.variantsMap.get(id)!; + const mappedStructType = struct.structType; + + for (let i = 0; i < struct.structType.fields.length; i++) { + const variantTypes = variants.map(variant => variant.structType.fields[i].type); + const mappedType = this.unifyTypes(variantTypes, mappedStructType.generics, variants); + mappedStructType.fields[i].type = mappedType; + } + + // Mutate variants setting the new struct type + variants.forEach(variant => (variant.structType = mappedStructType)); + + this.visitedStructs.set(id, mappedStructType); + } + + /** + * Tries to unify the types of a set of variants recursively. + * Unification will imply replacing some properties with bindings and pushing bindings to the generics of the struct. + */ + private unifyTypes( + types: AbiTypeWithGenerics[], + generics: BindingId[], // Mutates generics adding new bindings + variants: Struct[], // mutates variants adding different args to the variants + ): AbiTypeWithGenerics { + const kinds = new Set(types.map(type => type.kind)); + if (kinds.size > 1) { + return this.buildBindingAndPushToVariants(types, generics, variants); + } + switch (types[0].kind) { + case 'field': + case 'boolean': + case 'binding': + return types[0]; + case 'integer': { + if (allDeepEqual(types)) { + return types[0]; + } else { + return this.buildBindingAndPushToVariants(types, generics, variants); + } + } + case 'string': { + const strings = types as StringType[]; + const unifiedString = strings[0]; + if (strings.every(string => string.length === unifiedString.length)) { + return unifiedString; + } else { + const unifiedStringType: StringType = unifiedString; + unifiedStringType.length = this.buildNumericBindingAndPushToVariants( + strings.map(string => { + if (typeof string.length !== 'number') { + throw new Error('Trying to unify strings with bindings'); + } + return string.length; + }), + generics, + variants, + ); + return unifiedStringType; + } + } + case 'array': { + const arrays = types as ArrayType[]; + const unifiedArrayType: ArrayType = arrays[0]; + if ( + !arrays.every(array => { + return array.length === unifiedArrayType.length; + }) + ) { + unifiedArrayType.length = this.buildNumericBindingAndPushToVariants( + arrays.map(array => { + if (typeof array.length !== 'number') { + throw new Error('Trying to unify arrays with bindings'); + } + return array.length; + }), + generics, + variants, + ); + } + + unifiedArrayType.type = this.unifyTypes( + arrays.map(array => array.type), + generics, + variants, + ); + return unifiedArrayType; + } + case 'tuple': { + const tuples = types as Tuple[]; + const unifiedTupleType: Tuple = tuples[0]; + for (let i = 0; i < unifiedTupleType.fields.length; i++) { + unifiedTupleType.fields[i] = this.unifyTypes( + tuples.map(tuple => tuple.fields[i]), + generics, + variants, + ); + } + return unifiedTupleType; + } + case 'struct': { + const structs = types as Struct[]; + const ids = new Set(structs.map(struct => Demonomorphizer.buildIdForStruct(struct.structType))); + if (ids.size > 1) { + // If the types are different structs, we can only unify them by creating a new binding. + // For example, if we have a struct A { x: u32 } and a struct A { x: Field }, the only possible unification is A { x: T } + return this.buildBindingAndPushToVariants(types, generics, variants); + } else { + // If the types are the same struct, we must unify the arguments to the struct. + // For example, if we have A and A, we need to unify to A and push T to the generics of the struct type. + const unifiedStruct = structs[0]; + + if (!structs.every(struct => struct.args.length === unifiedStruct.args.length)) { + throw new Error('Same struct with different number of args encountered'); + } + for (let i = 0; i < unifiedStruct.args.length; i++) { + const argTypes = structs.map(struct => struct.args[i]); + unifiedStruct.args[i] = this.unifyTypes(argTypes, generics, variants); + } + return unifiedStruct; + } + } + + case 'constant': { + const constants = types as Constant[]; + if (constants.every(constant => constant.value === constants[0].value)) { + return constants[0]; + } else { + return this.buildBindingAndPushToVariants(types, generics, variants, true); + } + } + + default: { + const exhaustiveCheck: never = types[0]; + throw new Error(`Unhandled abi type: ${exhaustiveCheck}`); + } + } + } + + /** + * We consider a struct to be the same if it has the same name and field names. + * Structs with the same id will be unified into a single type by the demonomorphizer. + */ + public static buildIdForStruct(struct: StructType): string { + const name = struct.path.split('::').pop()!; + const fields = struct.fields.map(field => field.name).join(','); + return `${name}(${fields})`; + } + + private buildBindingAndPushToVariants( + concreteTypes: AbiTypeWithGenerics[], + generics: BindingId[], + variants: Struct[], + isNumeric = false, + ): AbiTypeWithGenerics { + const bindingId = new BindingId(this.lastBindingId++, isNumeric); + + for (let i = 0; i < variants.length; i++) { + const variant = variants[i]; + const concreteType = concreteTypes[i]; + variant.args.push(concreteType); + } + + generics.push(bindingId); + return { kind: 'binding', id: bindingId }; + } + + private buildNumericBindingAndPushToVariants( + concreteNumbers: number[], + generics: BindingId[], + variants: Struct[], + ): BindingId { + const bindingId = new BindingId(this.lastBindingId++, true); + + for (let i = 0; i < variants.length; i++) { + const variant = variants[i]; + variant.args.push({ kind: 'constant', value: concreteNumbers[i] }); + } + + generics.push(bindingId); + return bindingId; + } +} + +function allDeepEqual(arr: T[]): boolean { + if (arr.length === 0) { + return true; + } + const first = JSON.stringify(arr[0]); + for (let i = 0; i < arr.length; i++) { + if (JSON.stringify(arr[i]) !== first) { + return false; + } + } + return true; +} diff --git a/yarn-project/noir-protocol-circuits-types/src/scripts/generate_ts_from_abi.ts b/yarn-project/noir-protocol-circuits-types/src/scripts/generate_ts_from_abi.ts index 8b8f29d890f..7222143d6b0 100644 --- a/yarn-project/noir-protocol-circuits-types/src/scripts/generate_ts_from_abi.ts +++ b/yarn-project/noir-protocol-circuits-types/src/scripts/generate_ts_from_abi.ts @@ -1,9 +1,18 @@ -import { type AbiType } from '@aztec/foundation/abi'; import { createConsoleLogger } from '@aztec/foundation/log'; import { type NoirCompiledCircuit, type NoirFunctionAbi } from '@aztec/types/noir'; +import { pascalCase } from 'change-case'; import fs from 'fs/promises'; +import { + type AbiTypeWithGenerics, + type BindingId, + type StructType, + findAllStructsInType, + mapAbiTypeToAbiTypeWithGenerics, +} from './abi_type_with_generics.js'; +import { Demonomorphizer } from './demonomorphizer.js'; + const log = createConsoleLogger('aztec:noir-contracts'); /** @@ -30,52 +39,6 @@ type PrimitiveTypesUsed = { tsType: string; }; -const noirPrimitiveTypesToTsTypes = new Map(); - -/** - * Typescript does not allow us to check for equality of non-primitive types - * easily, so we create a addIfUnique function that will only add an item - * to the map if it is not already there by using JSON.stringify. - * @param item - The item to add to the map. - */ -function addIfUnique(item: PrimitiveTypesUsed) { - const key = JSON.stringify(item); - if (!noirPrimitiveTypesToTsTypes.has(key)) { - noirPrimitiveTypesToTsTypes.set(key, item); - } -} - -/** - * Converts an ABI type to a TypeScript type. - * @param type - The ABI type to convert. - * @returns The typescript code to define the type. - */ -function abiTypeToTs(type: AbiType): string { - switch (type.kind) { - case 'integer': { - let tsIntType = ''; - if (type.sign === 'signed') { - tsIntType = `i${type.width}`; - } else { - tsIntType = `u${type.width}`; - } - addIfUnique({ aliasName: tsIntType, tsType: 'string' }); - return tsIntType; - } - case 'boolean': - return `boolean`; - case 'array': - return `FixedLengthArray<${abiTypeToTs(type.type)}, ${type.length}>`; - case 'struct': - return getLastComponentOfPath(type.path); - case 'field': - addIfUnique({ aliasName: 'Field', tsType: 'string' }); - return 'Field'; - default: - throw new Error(`Unknown ABI type ${type}`); - } -} - /** * Returns the last component of a path, e.g. "foo::bar::baz" -\> "baz" * Note: that if we have a path such as "Baz", we will return "Baz". @@ -102,99 +65,217 @@ function getLastComponentOfPath(str: string): string { } /** - * Generates TypeScript interfaces for the structs used in the ABI. - * @param type - The ABI type to generate the interface for. - * @param output - The set of structs that we have already generated bindings for. - * @returns The TypeScript code to define the struct. + * Replaces a numeric binding with the corresponding generics name or the actual value. */ -function generateStructInterfaces(type: AbiType, output: Set): string { - let result = ''; - - // Edge case to handle the array of structs case. - if ( - type.kind === 'array' && - ((type.type.kind === 'struct' && !output.has(getLastComponentOfPath(type.type.path))) || type.type.kind === 'array') - ) { - result += generateStructInterfaces(type.type, output); +function replaceNumericBinding(id: number | BindingId, genericsNameMap: Map): string { + if (typeof id === 'number') { + return id.toString(); + } else { + return genericsNameMap.get(id.id) ?? 'unknown'; } +} - if (type.kind !== 'struct') { - return result; +class TypingsGenerator { + /** All the types in the ABIs */ + private allTypes: AbiTypeWithGenerics[] = []; + /** The demonomorphized ABIs of the circuits */ + private demonomorphizedAbis: { + circuitName: string; + params: { name: string; type: AbiTypeWithGenerics }[]; + returnType?: AbiTypeWithGenerics; + }[] = []; + /** Maps struct id to name for structs with the same name and different field sets */ + private structIdToTsName = new Map(); + /** Collect all the primitives used in the types to add them to the codegen */ + private primitiveTypesUsed = new Map(); + + constructor(circuits: { abi: NoirFunctionAbi; circuitName: string }[]) { + // Map all the types used in the ABIs to the demonomorphized types + for (const { abi, circuitName } of circuits) { + const params = abi.parameters.map(param => { + const type = mapAbiTypeToAbiTypeWithGenerics(param.type); + this.allTypes.push(type); + return { name: param.name, type }; + }); + if (abi.return_type) { + const returnType = mapAbiTypeToAbiTypeWithGenerics(abi.return_type.abi_type); + this.allTypes.push(returnType); + this.demonomorphizedAbis.push({ circuitName, params, returnType }); + } else { + this.demonomorphizedAbis.push({ circuitName, params }); + } + } + // Demonomorphize the types + Demonomorphizer.demonomorphize(this.allTypes); } - // List of structs encountered while viewing this type that we need to generate - // bindings for. - const typesEncountered = new Set(); - - // Codegen the struct and then its fields, so that the structs fields - // are defined before the struct itself. - let codeGeneratedStruct = ''; - let codeGeneratedStructFields = ''; - - const structName = getLastComponentOfPath(type.path); - if (!output.has(structName)) { - codeGeneratedStruct += `export interface ${structName} {\n`; - for (const field of type.fields) { - codeGeneratedStruct += ` ${field.name}: ${abiTypeToTs(field.type)};\n`; - typesEncountered.add(field.type); + public codegen(): string { + this.primitiveTypesUsed = new Map(); + const structsCode = this.codegenAllStructs(); + const interfacesCode = this.codegenAllInterfaces(); + const primitivesCode = this.codegenAllPrimitives(); + + return ` + /* Autogenerated file, do not edit! */ + /* eslint-disable */ + ${primitivesCode} + ${structsCode} + ${interfacesCode}`; + } + + private codegenAllStructs(): string { + const allStructs = this.allTypes.flatMap(findAllStructsInType); + // First, deduplicate the structs used + const structTypesToExport = new Map(); + for (const struct of allStructs) { + const id = Demonomorphizer.buildIdForStruct(struct.structType); + if (structTypesToExport.has(id)) { + continue; + } + structTypesToExport.set(id, struct.structType); } - codeGeneratedStruct += `}\n\n`; - output.add(structName); - // Generate code for the encountered structs in the field above - for (const type of typesEncountered) { - codeGeneratedStructFields += generateStructInterfaces(type, output); + // Then, we have to consider the case where we have struct with the same name but different fields. + // For those, we'll naively append a number to the name. + const idsPerName = new Map(); + for (const [id, structType] of structTypesToExport.entries()) { + const name = getLastComponentOfPath(structType.path); + const ids = idsPerName.get(name) ?? []; + ids.push(id); + idsPerName.set(name, ids); + } + + this.structIdToTsName = new Map(); + for (const [name, ids] of idsPerName.entries()) { + if (ids.length !== 1) { + ids.forEach((id, index) => { + this.structIdToTsName.set(id, `${name}${index + 1}`); + }); + } } + // Now we can just generate the code for the structs + let resultCode = ''; + + for (const structType of structTypesToExport.values()) { + resultCode += this.codegenStructType(structType); + } + + return resultCode; } - return codeGeneratedStructFields + '\n' + codeGeneratedStruct; -} + private getStructName(structType: StructType): string { + return ( + this.structIdToTsName.get(Demonomorphizer.buildIdForStruct(structType)) || getLastComponentOfPath(structType.path) + ); + } -/** - * Generates a TypeScript interface for the ABI. - * @param abiObj - The ABI to generate the interface for. - * @returns The TypeScript code to define the interface. - */ -function generateTsInterface(abiObj: NoirFunctionAbi): string { - let result = ``; - const outputStructs = new Set(); + private codegenStructType(structType: StructType): string { + // Generate names for the generic bindings. + const genericsNameMap = new Map(); + structType.generics.forEach((generic, index) => { + genericsNameMap.set(generic.id, String.fromCharCode('A'.charCodeAt(0) + index)); + }); - // Define structs for composite types - for (const param of abiObj.parameters) { - result += generateStructInterfaces(param.type, outputStructs); + const name = this.getStructName(structType); + const generics = structType.generics.length + ? `<${structType.generics + .map(generic => `${genericsNameMap.get(generic.id)}${generic.isNumeric ? ' extends number' : ''}`) + .join(', ')}>` + : ''; + + let resultCode = `export interface ${name}${generics} {\n`; + + for (const field of structType.fields) { + resultCode += ` ${field.name}: ${this.codegenType(field.type, genericsNameMap)};\n`; + } + + resultCode += '}\n\n'; + + return resultCode; } - // Generating Return type, if it exists - // - if (abiObj.return_type != null) { - result += generateStructInterfaces(abiObj.return_type.abi_type, outputStructs); - result += `export type ReturnType = ${abiTypeToTs(abiObj.return_type.abi_type)};\n`; + private codegenType(type: AbiTypeWithGenerics, genericsNameMap: Map): string { + switch (type.kind) { + case 'field': + this.addIfUnique({ aliasName: 'Field', tsType: 'string' }); + return 'Field'; + case 'boolean': + return 'boolean'; + case 'integer': { + let tsIntType = ''; + if (type.sign === 'signed') { + tsIntType = `i${type.width}`; + } else { + tsIntType = `u${type.width}`; + } + this.addIfUnique({ aliasName: tsIntType, tsType: 'string' }); + return tsIntType; + } + case 'binding': + return genericsNameMap.get(type.id.id) ?? 'unknown'; + case 'constant': + return type.value.toString(); + case 'string': + return `string`; + case 'array': + return `FixedLengthArray<${this.codegenType(type.type, genericsNameMap)}, ${replaceNumericBinding( + type.length, + genericsNameMap, + )}>`; + case 'tuple': + throw new Error('Unimplemented'); + case 'struct': { + const name = this.getStructName(type.structType); + if (type.args.length) { + const args = type.args.map(arg => this.codegenType(arg, genericsNameMap)).join(', '); + return `${name}<${args}>`; + } else { + return name; + } + } + } } - // Generating Input type - result += '\nexport interface InputType {\n'; - for (const param of abiObj.parameters) { - result += ` ${param.name}: ${abiTypeToTs(param.type)};\n`; + /** + * Typescript does not allow us to check for equality of non-primitive types + * easily, so we create a addIfUnique function that will only add an item + * to the map if it is not already there by using JSON.stringify. + * @param item - The item to add to the map. + */ + private addIfUnique(item: PrimitiveTypesUsed) { + const key = JSON.stringify(item); + if (!this.primitiveTypesUsed.has(key)) { + this.primitiveTypesUsed.set(key, item); + } } - result += '}'; - // Add the primitive Noir types that do not have a 1-1 mapping to TypeScript. - let primitiveTypeAliases = ''; - for (const [, value] of noirPrimitiveTypesToTsTypes) { - primitiveTypeAliases += `\nexport type ${value.aliasName} = ${value.tsType};`; + /** + * Codegen all the interfaces for the circuits. + * For a circuit named Foo, we'll codegen FooInputType and FooReturnType. + */ + private codegenAllInterfaces(): string { + let resultCode = ''; + for (const { circuitName, params, returnType } of this.demonomorphizedAbis) { + resultCode += this.codegenStructType({ + path: `${circuitName}InputType`, + fields: params, + generics: [], + }); + if (returnType) { + resultCode += `export type ${circuitName}ReturnType = ${this.codegenType(returnType, new Map())};\n`; + } + } + return resultCode; } - const fixedLengthArray = - '\nexport type FixedLengthArray = L extends 0 ? never[]: T[] & { length: L }'; - - return ( - `/* Autogenerated file, do not edit! */\n\n/* eslint-disable */\n` + - fixedLengthArray + - '\n' + - primitiveTypeAliases + - '\n' + - result - ); + private codegenAllPrimitives(): string { + let primitiveTypeAliases = + 'export type FixedLengthArray = L extends 0 ? never[]: T[] & { length: L }\n'; + for (const [, value] of this.primitiveTypesUsed) { + primitiveTypeAliases += `export type ${value.aliasName} = ${value.tsType};\n`; + } + return primitiveTypeAliases; + } } const circuits = [ @@ -220,14 +301,19 @@ const main = async () => { await fs.mkdir('./src/types', { recursive: true }); } + const allAbis = []; + + // Collect all abis for (const circuit of circuits) { const rawData = await fs.readFile(`./src/target/${circuit}.json`, 'utf-8'); const abiObj: NoirCompiledCircuit = JSON.parse(rawData); - const generatedInterface = generateTsInterface(abiObj.abi); - - const outputFile = `./src/types/${circuit}_types.ts`; - await fs.writeFile(outputFile, generatedInterface); + allAbis.push({ + abi: abiObj.abi, + circuitName: pascalCase(circuit), + }); } + const interfaces = new TypingsGenerator(allAbis).codegen(); + await fs.writeFile('./src/types/index.ts', interfaces); }; try { diff --git a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts index a891b6c775c..ed2295e907c 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -1,5 +1,4 @@ import { - type ARCHIVE_HEIGHT, AggregationObject, AppendOnlyTreeSnapshot, AztecAddress, @@ -16,7 +15,6 @@ import { type ContractStorageRead, type ContractStorageUpdateRequest, EthAddress, - type FUNCTION_TREE_HEIGHT, Fr, FunctionData, FunctionSelector, @@ -119,120 +117,101 @@ import { import { toBufferBE } from '@aztec/foundation/bigint-buffer'; import { type Tuple, mapTuple, toTruncField } from '@aztec/foundation/serialize'; -import { type BaseParityInputs as BaseParityInputsNoir } from './types/parity_base_types.js'; -import { - type RootParityInput as ParityRootParityInputNoir, - type RootParityInputs as RootParityInputsNoir, -} from './types/parity_root_types.js'; -import { - type CallContext as CallContextNoir, - type CallRequest as CallRequestNoir, - type CallerContext as CallerContextNoir, - type CombinedConstantData as CombinedConstantDataNoir, - type FunctionData as FunctionDataNoir, - type FunctionLeafMembershipWitness as FunctionLeafMembershipWitnessNoir, - type FunctionSelector as FunctionSelectorNoir, - type GasFees as GasFeesNoir, - type GasSettings as GasSettingsNoir, - type L2ToL1Message as L2ToL1MessageNoir, - type MaxBlockNumber as MaxBlockNumberNoir, - type AztecAddress as NoirAztecAddress, - type EthAddress as NoirEthAddress, - type Field as NoirField, - type GrumpkinPoint as NoirPoint, - type NoteHashContext as NoteHashContextNoir, - type NoteHash as NoteHashNoir, - type NullifierKeyValidationRequestContext as NullifierKeyValidationRequestContextNoir, - type NullifierKeyValidationRequest as NullifierKeyValidationRequestNoir, - type Nullifier as NullifierNoir, - type PrivateAccumulatedData as PrivateAccumulatedDataNoir, - type PrivateCallData as PrivateCallDataNoir, - type PrivateCallStackItem as PrivateCallStackItemNoir, - type PrivateCircuitPublicInputs as PrivateCircuitPublicInputsNoir, - type PrivateKernelCircuitPublicInputs as PrivateKernelCircuitPublicInputsNoir, - type PrivateKernelInitCircuitPrivateInputs as PrivateKernelInitCircuitPrivateInputsNoir, - type PublicDataRead as PublicDataReadNoir, - type ReadRequestContext as ReadRequestContextNoir, - type ReadRequest as ReadRequestNoir, - type RollupValidationRequests as RollupValidationRequestsNoir, - type SideEffect as SideEffectNoir, - type TxContext as TxContextNoir, - type TxRequest as TxRequestNoir, - type ValidationRequests as ValidationRequestsNoir, -} from './types/private_kernel_init_types.js'; -import { - type PrivateKernelInnerCircuitPrivateInputs as PrivateKernelInnerCircuitPrivateInputsNoir, - type PrivateKernelInnerHints as PrivateKernelInnerHintsNoir, -} from './types/private_kernel_inner_types.js'; -import { type PrivateKernelTailToPublicCircuitPrivateInputs as PrivateKernelTailToPublicCircuitPrivateInputsNoir } from './types/private_kernel_tail_to_public_types.js'; -import { - type CombinedAccumulatedData as CombinedAccumulatedDataNoir, - type Gas as GasNoir, - type GrumpkinPrivateKey as GrumpkinPrivateKeyNoir, - type NoteHashLeafPreimage as NoteHashLeafPreimageNoir, - type NoteHashMembershipWitness as NoteHashMembershipWitnessNoir, - type NoteHashReadRequestHints as NoteHashReadRequestHintsNoir, - type NoteHashSettledReadHint as NoteHashSettledReadHintNoir, - type NullifierReadRequestHints as NullifierReadRequestHintsNoir, - type NullifierSettledReadHint as NullifierSettledReadHintNoir, - type PendingReadHint as PendingReadHintNoir, - type PrivateKernelData as PrivateKernelDataNoir, - type PrivateKernelTailCircuitPrivateInputs as PrivateKernelTailCircuitPrivateInputsNoir, - type PrivateKernelTailHints as PrivateKernelTailHintsNoir, - type PrivateKernelTailOutputs as PrivateKernelTailOutputsNoir, - type ReadRequestStatus as ReadRequestStatusNoir, -} from './types/private_kernel_tail_types.js'; -import { - type PublicAccumulatedData as PublicAccumulatedDataNoir, - type PublicKernelData as PublicKernelDataNoir, -} from './types/public_kernel_app_logic_types.js'; -import { - type PublicCallData as PublicCallDataNoir, - type PublicCallStackItem as PublicCallStackItemNoir, - type PublicCircuitPublicInputs as PublicCircuitPublicInputsNoir, - type PublicKernelCircuitPublicInputs as PublicKernelCircuitPublicInputsNoir, - type PublicKernelSetupCircuitPrivateInputs as PublicKernelSetupCircuitPrivateInputsNoir, - type StorageRead as StorageReadNoir, - type StorageUpdateRequest as StorageUpdateRequestNoir, -} from './types/public_kernel_setup_types.js'; -import { - type LeafDataReadHint as LeafDataReadHintNoir, - type NullifierNonExistentReadRequestHints as NullifierNonExistentReadRequestHintsNoir, - type NullifierNonMembershipHint as NullifierNonMembershipHintNoir, - type PublicDataHint as PublicDataHintNoir, - type PublicDataReadRequestHints as PublicDataReadRequestHintsNoir, - type PublicDataUpdateRequest as PublicDataUpdateRequestNoir, - type PublicKernelTailCircuitPrivateInputs as PublicKernelTailCircuitPrivateInputsNoir, -} from './types/public_kernel_tail_types.js'; -import { - type ArchiveRootMembershipWitness as ArchiveRootMembershipWitnessNoir, - type BaseRollupInputs as BaseRollupInputsNoir, - type KernelCircuitPublicInputs as KernelCircuitPublicInputsNoir, - type KernelData as KernelDataNoir, - type NullifierLeafPreimage as NullifierLeafPreimageNoir, - type NullifierMembershipWitness as NullifierMembershipWitnessNoir, - type PublicDataMembershipWitness as PublicDataMembershipWitnessNoir, - type PublicDataTreeLeaf as PublicDataTreeLeafNoir, - type PublicDataTreeLeafPreimage as PublicDataTreeLeafPreimageNoir, - type StateDiffHints as StateDiffHintsNoir, -} from './types/rollup_base_types.js'; -import { type MergeRollupInputs as MergeRollupInputsNoir } from './types/rollup_merge_types.js'; -import { - type AppendOnlyTreeSnapshot as AppendOnlyTreeSnapshotNoir, - type BaseOrMergeRollupPublicInputs as BaseOrMergeRollupPublicInputsNoir, - type ConstantRollupData as ConstantRollupDataNoir, - type ContentCommitment as ContentCommitmentNoir, - type Field, - type GlobalVariables as GlobalVariablesNoir, - type Header as HeaderNoir, - type ParityPublicInputs as ParityPublicInputsNoir, - type PartialStateReference as PartialStateReferenceNoir, - type PreviousRollupData as PreviousRollupDataNoir, - type RootRollupInputs as RootRollupInputsNoir, - type RootRollupParityInput as RootRollupParityInputNoir, - type RootRollupPublicInputs as RootRollupPublicInputsNoir, - type StateReference as StateReferenceNoir, -} from './types/rollup_root_types.js'; +import type { + AppendOnlyTreeSnapshot as AppendOnlyTreeSnapshotNoir, + BaseOrMergeRollupPublicInputs as BaseOrMergeRollupPublicInputsNoir, + BaseParityInputs as BaseParityInputsNoir, + BaseRollupInputs as BaseRollupInputsNoir, + CallContext as CallContextNoir, + CallRequest as CallRequestNoir, + CallerContext as CallerContextNoir, + CombinedAccumulatedData as CombinedAccumulatedDataNoir, + CombinedConstantData as CombinedConstantDataNoir, + ConstantRollupData as ConstantRollupDataNoir, + ContentCommitment as ContentCommitmentNoir, + Field, + FixedLengthArray, + FunctionData as FunctionDataNoir, + FunctionSelector as FunctionSelectorNoir, + GasFees as GasFeesNoir, + Gas as GasNoir, + GasSettings as GasSettingsNoir, + GlobalVariables as GlobalVariablesNoir, + GrumpkinPrivateKey as GrumpkinPrivateKeyNoir, + Header as HeaderNoir, + KernelCircuitPublicInputs as KernelCircuitPublicInputsNoir, + KernelData as KernelDataNoir, + L2ToL1Message as L2ToL1MessageNoir, + LeafDataReadHint as LeafDataReadHintNoir, + MaxBlockNumber as MaxBlockNumberNoir, + MembershipWitness as MembershipWitnessNoir, + MergeRollupInputs as MergeRollupInputsNoir, + AztecAddress as NoirAztecAddress, + EthAddress as NoirEthAddress, + Field as NoirField, + GrumpkinPoint as NoirPoint, + NoteHashContext as NoteHashContextNoir, + NoteHashLeafPreimage as NoteHashLeafPreimageNoir, + NoteHash as NoteHashNoir, + NoteHashReadRequestHints as NoteHashReadRequestHintsNoir, + NoteHashSettledReadHint as NoteHashSettledReadHintNoir, + NullifierKeyValidationRequestContext as NullifierKeyValidationRequestContextNoir, + NullifierKeyValidationRequest as NullifierKeyValidationRequestNoir, + NullifierLeafPreimage as NullifierLeafPreimageNoir, + Nullifier as NullifierNoir, + NullifierNonExistentReadRequestHints as NullifierNonExistentReadRequestHintsNoir, + NullifierNonMembershipHint as NullifierNonMembershipHintNoir, + NullifierReadRequestHints as NullifierReadRequestHintsNoir, + NullifierSettledReadHint as NullifierSettledReadHintNoir, + ParityPublicInputs as ParityPublicInputsNoir, + RootParityInput as ParityRootParityInputNoir, + PartialStateReference as PartialStateReferenceNoir, + PendingReadHint as PendingReadHintNoir, + PreviousRollupData as PreviousRollupDataNoir, + PrivateAccumulatedData as PrivateAccumulatedDataNoir, + PrivateCallData as PrivateCallDataNoir, + PrivateCallStackItem as PrivateCallStackItemNoir, + PrivateCircuitPublicInputs as PrivateCircuitPublicInputsNoir, + PrivateKernelCircuitPublicInputs as PrivateKernelCircuitPublicInputsNoir, + PrivateKernelData as PrivateKernelDataNoir, + PrivateKernelInitCircuitPrivateInputs as PrivateKernelInitCircuitPrivateInputsNoir, + PrivateKernelInnerCircuitPrivateInputs as PrivateKernelInnerCircuitPrivateInputsNoir, + PrivateKernelInnerHints as PrivateKernelInnerHintsNoir, + PrivateKernelTailCircuitPrivateInputs as PrivateKernelTailCircuitPrivateInputsNoir, + PrivateKernelTailHints as PrivateKernelTailHintsNoir, + PrivateKernelTailOutputs as PrivateKernelTailOutputsNoir, + PrivateKernelTailToPublicCircuitPrivateInputs as PrivateKernelTailToPublicCircuitPrivateInputsNoir, + PublicAccumulatedData as PublicAccumulatedDataNoir, + PublicCallData as PublicCallDataNoir, + PublicCallStackItem as PublicCallStackItemNoir, + PublicCircuitPublicInputs as PublicCircuitPublicInputsNoir, + PublicDataHint as PublicDataHintNoir, + PublicDataRead as PublicDataReadNoir, + PublicDataReadRequestHints as PublicDataReadRequestHintsNoir, + PublicDataTreeLeaf as PublicDataTreeLeafNoir, + PublicDataTreeLeafPreimage as PublicDataTreeLeafPreimageNoir, + PublicDataUpdateRequest as PublicDataUpdateRequestNoir, + PublicKernelCircuitPublicInputs as PublicKernelCircuitPublicInputsNoir, + PublicKernelData as PublicKernelDataNoir, + PublicKernelSetupCircuitPrivateInputs as PublicKernelSetupCircuitPrivateInputsNoir, + PublicKernelTailCircuitPrivateInputs as PublicKernelTailCircuitPrivateInputsNoir, + ReadRequestContext as ReadRequestContextNoir, + ReadRequest as ReadRequestNoir, + ReadRequestStatus as ReadRequestStatusNoir, + RollupValidationRequests as RollupValidationRequestsNoir, + RootParityInputs as RootParityInputsNoir, + RootRollupInputs as RootRollupInputsNoir, + RootRollupParityInput as RootRollupParityInputNoir, + RootRollupPublicInputs as RootRollupPublicInputsNoir, + SideEffect as SideEffectNoir, + StateDiffHints as StateDiffHintsNoir, + StateReference as StateReferenceNoir, + StorageRead as StorageReadNoir, + StorageUpdateRequest as StorageUpdateRequestNoir, + TxContext as TxContextNoir, + TxRequest as TxRequestNoir, + ValidationRequests as ValidationRequestsNoir, +} from './types/index.js'; /* eslint-disable camelcase */ @@ -775,20 +754,6 @@ export function mapPrivateCallStackItemToNoir(privateCallStackItem: PrivateCallS }; } -/** - * Maps a function leaf membership witness to a noir function leaf membership witness. - * @param membershipWitness - The membership witness. - * @returns The noir function leaf membership witness. - */ -function mapFunctionLeafMembershipWitnessToNoir( - membershipWitness: MembershipWitness, -): FunctionLeafMembershipWitnessNoir { - return { - leaf_index: membershipWitness.leafIndex.toString(), - sibling_path: mapTuple(membershipWitness.siblingPath, mapFieldToNoir), - }; -} - /** * Maps a private call data to a noir private call data. * @param privateCallData - The private call data. @@ -801,9 +766,7 @@ export function mapPrivateCallDataToNoir(privateCallData: PrivateCallData): Priv public_call_stack: mapTuple(privateCallData.publicCallStack, mapCallRequestToNoir), proof: {}, vk: {}, - function_leaf_membership_witness: mapFunctionLeafMembershipWitnessToNoir( - privateCallData.functionLeafMembershipWitness, - ), + function_leaf_membership_witness: mapMembershipWitnessToNoir(privateCallData.functionLeafMembershipWitness), contract_class_artifact_hash: mapFieldToNoir(privateCallData.contractClassArtifactHash), contract_class_public_bytecode_commitment: mapFieldToNoir(privateCallData.contractClassPublicBytecodeCommitment), public_keys_hash: mapWrappedFieldToNoir(privateCallData.publicKeysHash), @@ -931,7 +894,7 @@ function mapNoteHashSettledReadHintToNoir( ): NoteHashSettledReadHintNoir { return { read_request_index: mapNumberToNoir(hint.readRequestIndex), - membership_witness: mapNoteHashMembershipWitnessToNoir(hint.membershipWitness), + membership_witness: mapMembershipWitnessToNoir(hint.membershipWitness), leaf_preimage: mapNoteHashLeafPreimageToNoir(hint.leafPreimage), }; } @@ -941,7 +904,7 @@ function mapNullifierSettledReadHintToNoir( ): NullifierSettledReadHintNoir { return { read_request_index: mapNumberToNoir(hint.readRequestIndex), - membership_witness: mapNullifierMembershipWitnessToNoir(hint.membershipWitness), + membership_witness: mapMembershipWitnessToNoir(hint.membershipWitness), leaf_preimage: mapNullifierLeafPreimageToNoir(hint.leafPreimage), }; } @@ -967,7 +930,7 @@ function mapNullifierNonMembershipHintToNoir( ): NullifierNonMembershipHintNoir { return { low_leaf_preimage: mapNullifierLeafPreimageToNoir(hint.leafPreimage), - membership_witness: mapNullifierMembershipWitnessToNoir(hint.membershipWitness), + membership_witness: mapMembershipWitnessToNoir(hint.membershipWitness), }; } @@ -987,7 +950,7 @@ function mapPublicDataHintToNoir(hint: PublicDataHint): PublicDataHintNoir { leaf_slot: mapFieldToNoir(hint.leafSlot), value: mapFieldToNoir(hint.value), override_counter: mapNumberToNoir(hint.overrideCounter), - membership_witness: mapPublicDataMembershipWitnessToNoir(hint.membershipWitness), + membership_witness: mapMembershipWitnessToNoir(hint.membershipWitness), leaf_preimage: mapPublicDataTreePreimageToNoir(hint.leafPreimage), }; } @@ -1957,52 +1920,11 @@ export function mapNullifierLeafPreimageToNoir( }; } -function mapNoteHashMembershipWitnessToNoir( - membershipWitness: MembershipWitness, -): NoteHashMembershipWitnessNoir { - return { - leaf_index: membershipWitness.leafIndex.toString(), - sibling_path: mapTuple(membershipWitness.siblingPath, mapFieldToNoir), - }; -} - -/** - * Maps a nullifier membership witness to noir. - * @param membershipWitness - The nullifier membership witness. - * @returns The noir nullifier membership witness. - */ -export function mapNullifierMembershipWitnessToNoir( - membershipWitness: MembershipWitness, -): NullifierMembershipWitnessNoir { - return { - leaf_index: membershipWitness.leafIndex.toString(), - sibling_path: mapTuple(membershipWitness.siblingPath, mapFieldToNoir), - }; -} - -/** - * Maps a membership witness of the public data tree to noir. - */ -export function mapPublicDataMembershipWitnessToNoir( - membershipWitness: MembershipWitness, -): PublicDataMembershipWitnessNoir { - return { - leaf_index: membershipWitness.leafIndex.toString(), - sibling_path: mapTuple(membershipWitness.siblingPath, mapFieldToNoir), - }; -} - -/** - * Maps a membership witness of the blocks tree to noir. - * @param membershipWitness - The membership witness. - * @returns The noir membership witness. - */ -export function mapArchiveRootMembershipWitnessToNoir( - membershipWitness: MembershipWitness, -): ArchiveRootMembershipWitnessNoir { +function mapMembershipWitnessToNoir(witness: MembershipWitness): MembershipWitnessNoir { + const siblingPath = mapTuple(witness.siblingPath, mapFieldToNoir) as FixedLengthArray; return { - leaf_index: membershipWitness.leafIndex.toString(), - sibling_path: mapTuple(membershipWitness.siblingPath, mapFieldToNoir), + leaf_index: witness.leafIndex.toString(), + sibling_path: siblingPath, }; } @@ -2053,7 +1975,7 @@ export function mapStateDiffHintsToNoir(hints: StateDiffHints): StateDiffHintsNo nullifier_predecessor_preimages: mapTuple(hints.nullifierPredecessorPreimages, mapNullifierLeafPreimageToNoir), nullifier_predecessor_membership_witnesses: mapTuple( hints.nullifierPredecessorMembershipWitnesses, - mapNullifierMembershipWitnessToNoir, + (witness: MembershipWitness) => mapMembershipWitnessToNoir(witness), ), sorted_nullifiers: mapTuple(hints.sortedNullifiers, mapFieldToNoir), sorted_nullifier_indexes: mapTuple(hints.sortedNullifierIndexes, (index: number) => mapNumberToNoir(index)), @@ -2104,10 +2026,10 @@ export function mapBaseRollupInputsToNoir(inputs: BaseRollupInputs): BaseRollupI low_public_data_writes_witnesses: mapTuple( inputs.lowPublicDataWritesMembershipWitnesses, - mapPublicDataMembershipWitnessToNoir, + (witness: MembershipWitness) => mapMembershipWitnessToNoir(witness), ), - archive_root_membership_witness: mapArchiveRootMembershipWitnessToNoir(inputs.archiveRootMembershipWitness), + archive_root_membership_witness: mapMembershipWitnessToNoir(inputs.archiveRootMembershipWitness), constants: mapConstantRollupDataToNoir(inputs.constants), }; } diff --git a/yarn-project/prover-client/src/mocks/test_context.ts b/yarn-project/prover-client/src/mocks/test_context.ts index 75abb24ada6..7dcdcf6ea93 100644 --- a/yarn-project/prover-client/src/mocks/test_context.ts +++ b/yarn-project/prover-client/src/mocks/test_context.ts @@ -1,5 +1,5 @@ import { type BlockProver, type ProcessedTx, type Tx, type TxValidator } from '@aztec/circuit-types'; -import { type Gas, GlobalVariables, Header, type TxContext } from '@aztec/circuits.js'; +import { type Gas, GlobalVariables, Header, type Nullifier, type TxContext } from '@aztec/circuits.js'; import { type Fr } from '@aztec/foundation/fields'; import { type DebugLogger } from '@aztec/foundation/log'; import { openTmpStore } from '@aztec/kv-store/utils'; @@ -129,6 +129,7 @@ export class TestContext { _globalVariables: GlobalVariables, availableGas: Gas, _txContext: TxContext, + _pendingNullifiers: Nullifier[], transactionFee?: Fr, _sideEffectCounter?: number, ) => { @@ -166,6 +167,7 @@ export class TestContext { globalVariables: GlobalVariables, availableGas: Gas, txContext: TxContext, + pendingNullifiers: Nullifier[], transactionFee?: Fr, sideEffectCounter?: number, ) => Promise, diff --git a/yarn-project/pxe/src/kernel_prover/bb_prover/bb_native_proof_creator.ts b/yarn-project/pxe/src/kernel_prover/bb_prover/bb_native_proof_creator.ts index 7f4fba37064..15eed0996a9 100644 --- a/yarn-project/pxe/src/kernel_prover/bb_prover/bb_native_proof_creator.ts +++ b/yarn-project/pxe/src/kernel_prover/bb_prover/bb_native_proof_creator.ts @@ -8,7 +8,6 @@ import { type PrivateKernelTailCircuitPublicInputs, Proof, type VERIFICATION_KEY_LENGTH_IN_FIELDS, - makeEmptyProof, } from '@aztec/circuits.js'; import { siloNoteHash } from '@aztec/circuits.js/hash'; import { randomBytes, sha256 } from '@aztec/foundation/crypto'; @@ -23,9 +22,9 @@ import { convertPrivateKernelInnerInputsToWitnessMap, convertPrivateKernelInnerOutputsFromWitnessMap, convertPrivateKernelTailForPublicOutputsFromWitnessMap, + convertPrivateKernelTailInputsToWitnessMap, convertPrivateKernelTailOutputsFromWitnessMap, - executeTail, - executeTailForPublic, + convertPrivateKernelTailToPublicInputsToWitnessMap, } from '@aztec/noir-protocol-circuits-types'; import { type ACVMField, WASMSimulator } from '@aztec/simulator'; import { type NoirCompiledCircuit } from '@aztec/types/noir'; @@ -294,7 +293,7 @@ export async function generateKeyForNoirCircuit( await fs.writeFile(bytecodePath, bytecode); // args are the output path and the input bytecode path - const args = ['-o', outputPath, '-b', bytecodePath]; + const args = ['-o', `${outputPath}/${VK_FILENAME}`, '-b', bytecodePath]; const timer = new Timer(); let result = await executeBB(pathToBB, `write_${key}`, args, log); // If we succeeded and the type of key if verification, have bb write the 'fields' version too @@ -468,25 +467,12 @@ export class BBNativeProofCreator implements ProofCreator { public async createProofTail( inputs: PrivateKernelTailCircuitPrivateInputs, ): Promise> { - // if (!inputs.isForPublic()) { - // const witnessMap = convertPrivateKernelTailInputsToWitnessMap(inputs); - // return await this.createSafeProof(witnessMap, 'PrivateKernelTailArtifact'); - // } - if (!inputs.isForPublic()) { - const result = await executeTail(inputs); - return { - publicInputs: result, - proof: makeEmptyProof(), - }; + const witnessMap = convertPrivateKernelTailInputsToWitnessMap(inputs); + return await this.createSafeProof(witnessMap, 'PrivateKernelTailArtifact'); } - // const witnessMap = convertPrivateKernelTailToPublicInputsToWitnessMap(inputs); - // return await this.createSafeProof(witnessMap, 'PrivateKernelTailToPublicArtifact'); - const result = await executeTailForPublic(inputs); - return { - publicInputs: result, - proof: makeEmptyProof(), - }; + const witnessMap = convertPrivateKernelTailToPublicInputsToWitnessMap(inputs); + return await this.createSafeProof(witnessMap, 'PrivateKernelTailToPublicArtifact'); } public async createAppCircuitProof(partialWitness: Map, bytecode: Buffer): Promise { diff --git a/yarn-project/simulator/src/acvm/acvm.ts b/yarn-project/simulator/src/acvm/acvm.ts index d166b5d16c3..9f9edb98bd7 100644 --- a/yarn-project/simulator/src/acvm/acvm.ts +++ b/yarn-project/simulator/src/acvm/acvm.ts @@ -19,7 +19,7 @@ import { type ORACLE_NAMES } from './oracle/index.js'; */ type ACIRCallback = Record< ORACLE_NAMES, - (...args: ForeignCallInput[]) => ForeignCallOutput | Promise + (...args: ForeignCallInput[]) => void | ForeignCallOutput | Promise >; /** @@ -105,7 +105,7 @@ export async function acvm( } const result = await oracleFunction.call(callback, ...args); - return [result]; + return typeof result === 'undefined' ? [] : [result]; } catch (err) { let typedError: Error; if (err instanceof Error) { diff --git a/yarn-project/simulator/src/acvm/oracle/oracle.ts b/yarn-project/simulator/src/acvm/oracle/oracle.ts index b599e32aead..41c027ba411 100644 --- a/yarn-project/simulator/src/acvm/oracle/oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/oracle.ts @@ -373,14 +373,12 @@ export class Oracle { return toACVMField(logHash); } - debugLog(...args: ACVMField[][]): ACVMField { + debugLog(...args: ACVMField[][]): void { this.log.verbose(oracleDebugCallToFormattedStr(args)); - return toACVMField(0); } - debugLogWithPrefix(arg0: ACVMField[], ...args: ACVMField[][]): ACVMField { + debugLogWithPrefix(arg0: ACVMField[], ...args: ACVMField[][]): void { this.log.verbose(`${acvmFieldMessageToString(arg0)}: ${oracleDebugCallToFormattedStr(args)}`); - return toACVMField(0); } async callPrivateFunction( diff --git a/yarn-project/simulator/src/avm/journal/journal.ts b/yarn-project/simulator/src/avm/journal/journal.ts index 175ed4db2d1..3a47c4adebb 100644 --- a/yarn-project/simulator/src/avm/journal/journal.ts +++ b/yarn-project/simulator/src/avm/journal/journal.ts @@ -50,6 +50,8 @@ export type JournalData = { newLogsHashes: TracedUnencryptedL2Log[]; /** contract address -\> key -\> value */ currentStorageValue: Map>; + + sideEffectCounter: number; }; // TRANSITIONAL: This should be removed once the kernel handles and entire enqueued call per circuit @@ -143,6 +145,15 @@ export class AvmPersistableStateManager { this.publicStorage.write(storageAddress, slot, value); // TRANSITIONAL: This should be removed once the kernel handles and entire enqueued call per circuit + // The current info to the kernel clears any previous read or write request. + this.transitionalExecutionResult.contractStorageReads = + this.transitionalExecutionResult.contractStorageReads.filter( + read => !read.storageSlot.equals(slot) || !read.contractAddress!.equals(storageAddress), + ); + this.transitionalExecutionResult.contractStorageUpdateRequests = + this.transitionalExecutionResult.contractStorageUpdateRequests.filter( + update => !update.storageSlot.equals(slot) || !update.contractAddress!.equals(storageAddress), + ); this.transitionalExecutionResult.contractStorageUpdateRequests.push( new ContractStorageUpdateRequest(slot, value, this.trace.accessCounter, storageAddress), ); @@ -159,16 +170,24 @@ export class AvmPersistableStateManager { * @returns the latest value written to slot, or 0 if never written to before */ public async readStorage(storageAddress: Fr, slot: Fr): Promise { - const [exists, value] = await this.publicStorage.read(storageAddress, slot); - this.log.debug(`storage(${storageAddress})@${slot} ?? value: ${value}, exists: ${exists}.`); + const { value, exists, cached } = await this.publicStorage.read(storageAddress, slot); + this.log.debug(`storage(${storageAddress})@${slot} ?? value: ${value}, exists: ${exists}, cached: ${cached}.`); // TRANSITIONAL: This should be removed once the kernel handles and entire enqueued call per circuit - this.transitionalExecutionResult.contractStorageReads.push( - new ContractStorageRead(slot, value, this.trace.accessCounter, storageAddress), - ); + // The current info to the kernel kernel does not consider cached reads. + if (!cached) { + // The current info to the kernel removes any previous reads to the same slot. + this.transitionalExecutionResult.contractStorageReads = + this.transitionalExecutionResult.contractStorageReads.filter( + read => !read.storageSlot.equals(slot) || !read.contractAddress!.equals(storageAddress), + ); + this.transitionalExecutionResult.contractStorageReads.push( + new ContractStorageRead(slot, value, this.trace.accessCounter, storageAddress), + ); + } // We want to keep track of all performed reads (even reverted ones) - this.trace.tracePublicStorageRead(storageAddress, slot, value, exists); + this.trace.tracePublicStorageRead(storageAddress, slot, value, exists, cached); return Promise.resolve(value); } @@ -348,6 +367,7 @@ export class AvmPersistableStateManager { currentStorageValue: this.publicStorage.getCache().cachePerContract, storageReads: this.trace.publicStorageReads, storageWrites: this.trace.publicStorageWrites, + sideEffectCounter: this.trace.accessCounter, }; } } diff --git a/yarn-project/simulator/src/avm/journal/nullifiers.ts b/yarn-project/simulator/src/avm/journal/nullifiers.ts index f8374f6f8a7..99d12757e60 100644 --- a/yarn-project/simulator/src/avm/journal/nullifiers.ts +++ b/yarn-project/simulator/src/avm/journal/nullifiers.ts @@ -1,3 +1,4 @@ +import { AztecAddress } from '@aztec/circuits.js'; import { siloNullifier } from '@aztec/circuits.js/hash'; import { Fr } from '@aztec/foundation/fields'; @@ -10,7 +11,7 @@ import type { CommitmentsDB } from '../../index.js'; */ export class Nullifiers { /** Cached nullifiers. */ - private cache: NullifierCache; + public cache: NullifierCache; /** Parent's nullifier cache. Checked on cache-miss. */ private readonly parentCache: NullifierCache | undefined; /** Reference to node storage. Checked on parent cache-miss. */ @@ -95,6 +96,7 @@ export class NullifierCache { * each entry being a nullifier. */ private cachePerContract: Map> = new Map(); + private siloedNullifiers: Set = new Set(); /** * Check whether a nullifier exists in the cache. @@ -104,8 +106,10 @@ export class NullifierCache { * @returns whether the nullifier is found in the cache */ public exists(storageAddress: Fr, nullifier: Fr): boolean { - const exists = this.cachePerContract.get(storageAddress.toBigInt())?.has(nullifier.toBigInt()); - return exists ? true : false; + const exists = + this.cachePerContract.get(storageAddress.toBigInt())?.has(nullifier.toBigInt()) || + this.siloedNullifiers.has(siloNullifier(AztecAddress.fromField(storageAddress), nullifier).toBigInt()); + return !!exists; } /** @@ -115,20 +119,25 @@ export class NullifierCache { * @param nullifier - the nullifier to stage */ public append(storageAddress: Fr, nullifier: Fr) { + if (this.exists(storageAddress, nullifier)) { + throw new NullifierCollisionError( + `Nullifier ${nullifier} at contract ${storageAddress} already exists in cache.`, + ); + } + let nullifiersForContract = this.cachePerContract.get(storageAddress.toBigInt()); // If this contract's nullifier set has no cached nullifiers, create a new Set to store them if (!nullifiersForContract) { nullifiersForContract = new Set(); this.cachePerContract.set(storageAddress.toBigInt(), nullifiersForContract); } - if (nullifiersForContract.has(nullifier.toBigInt())) { - throw new NullifierCollisionError( - `Nullifier ${nullifier} at contract ${storageAddress} already exists in cache.`, - ); - } nullifiersForContract.add(nullifier.toBigInt()); } + public appendSiloed(siloedNullifier: Fr) { + this.siloedNullifiers.add(siloedNullifier.toBigInt()); + } + /** * Merge another cache's nullifiers into this instance's. * @@ -139,6 +148,8 @@ export class NullifierCache { * @param incomingNullifiers - the incoming cached nullifiers to merge into this instance's */ public acceptAndMerge(incomingNullifiers: NullifierCache) { + // Merge siloed nullifiers. + this.siloedNullifiers = new Set([...this.siloedNullifiers, ...incomingNullifiers.siloedNullifiers]); // Iterate over all contracts with staged writes in the child. for (const [incomingAddress, incomingCacheAtContract] of incomingNullifiers.cachePerContract) { const thisCacheAtContract = this.cachePerContract.get(incomingAddress); diff --git a/yarn-project/simulator/src/avm/journal/public_storage.test.ts b/yarn-project/simulator/src/avm/journal/public_storage.test.ts index 33c747977d7..54633e40f96 100644 --- a/yarn-project/simulator/src/avm/journal/public_storage.test.ts +++ b/yarn-project/simulator/src/avm/journal/public_storage.test.ts @@ -19,22 +19,26 @@ describe('avm public storage', () => { const contractAddress = new Fr(1); const slot = new Fr(2); // never written! - const [exists, gotValue] = await publicStorage.read(contractAddress, slot); + const { exists, value: gotValue, cached } = await publicStorage.read(contractAddress, slot); // doesn't exist, value is zero expect(exists).toEqual(false); expect(gotValue).toEqual(Fr.ZERO); + expect(cached).toEqual(false); }); + it('Should cache storage write, reading works after write', async () => { const contractAddress = new Fr(1); const slot = new Fr(2); const value = new Fr(3); // Write to cache publicStorage.write(contractAddress, slot, value); - const [exists, gotValue] = await publicStorage.read(contractAddress, slot); + const { exists, value: gotValue, cached } = await publicStorage.read(contractAddress, slot); // exists because it was previously written expect(exists).toEqual(true); expect(gotValue).toEqual(value); + expect(cached).toEqual(true); }); + it('Reading works on fallback to host (gets value & exists)', async () => { const contractAddress = new Fr(1); const slot = new Fr(2); @@ -42,11 +46,13 @@ describe('avm public storage', () => { // ensure that fallback to host gets a value publicDb.storageRead.mockResolvedValue(Promise.resolve(storedValue)); - const [exists, gotValue] = await publicStorage.read(contractAddress, slot); + const { exists, value: gotValue, cached } = await publicStorage.read(contractAddress, slot); // it exists in the host, so it must've been written before expect(exists).toEqual(true); expect(gotValue).toEqual(storedValue); + expect(cached).toEqual(false); }); + it('Reading works on fallback to parent (gets value & exists)', async () => { const contractAddress = new Fr(1); const slot = new Fr(2); @@ -54,11 +60,13 @@ describe('avm public storage', () => { const childStorage = new PublicStorage(publicDb, publicStorage); publicStorage.write(contractAddress, slot, value); - const [exists, gotValue] = await childStorage.read(contractAddress, slot); + const { exists, value: gotValue, cached } = await childStorage.read(contractAddress, slot); // exists because it was previously written! expect(exists).toEqual(true); expect(gotValue).toEqual(value); + expect(cached).toEqual(true); }); + it('When reading from storage, should check cache, then parent, then host', async () => { // Store a different value in storage vs the cache, and make sure the cache is returned const contractAddress = new Fr(1); @@ -71,21 +79,24 @@ describe('avm public storage', () => { const childStorage = new PublicStorage(publicDb, publicStorage); // Cache miss falls back to host - const [, cacheMissResult] = await childStorage.read(contractAddress, slot); - expect(cacheMissResult).toEqual(storedValue); + const { cached: cachedCacheMiss, value: valueCacheMiss } = await childStorage.read(contractAddress, slot); + expect(valueCacheMiss).toEqual(storedValue); + expect(cachedCacheMiss).toEqual(false); // Write to storage publicStorage.write(contractAddress, slot, parentValue); // Reading from child should give value written in parent - const [, valueFromParent] = await childStorage.read(contractAddress, slot); + const { cached: cachedValueFromParent, value: valueFromParent } = await childStorage.read(contractAddress, slot); expect(valueFromParent).toEqual(parentValue); + expect(cachedValueFromParent).toEqual(true); // Now write a value directly in child childStorage.write(contractAddress, slot, cachedValue); // Reading should now give the value written in child - const [, cachedResult] = await childStorage.read(contractAddress, slot); + const { cached: cachedChild, value: cachedResult } = await childStorage.read(contractAddress, slot); expect(cachedResult).toEqual(cachedValue); + expect(cachedChild).toEqual(true); }); }); @@ -109,7 +120,7 @@ describe('avm public storage', () => { publicStorage.acceptAndMerge(childStorage); // Read from parent gives latest value written in child before merge (valueT1) - const [exists, result] = await publicStorage.read(contractAddress, slot); + const { exists, value: result } = await publicStorage.read(contractAddress, slot); expect(exists).toEqual(true); expect(result).toEqual(valueT1); }); diff --git a/yarn-project/simulator/src/avm/journal/public_storage.ts b/yarn-project/simulator/src/avm/journal/public_storage.ts index f6b3b7a35d8..30c59e421b3 100644 --- a/yarn-project/simulator/src/avm/journal/public_storage.ts +++ b/yarn-project/simulator/src/avm/journal/public_storage.ts @@ -1,7 +1,14 @@ +import { AztecAddress } from '@aztec/circuits.js'; import { Fr } from '@aztec/foundation/fields'; import type { PublicStateDB } from '../../index.js'; +type PublicStorageReadResult = { + value: Fr; + exists: boolean; + cached: boolean; +}; + /** * A class to manage public storage reads and writes during a contract call's AVM simulation. * Maintains a storage write cache, and ensures that reads fall back to the correct source. @@ -39,7 +46,8 @@ export class PublicStorage { * @param slot - the slot in the contract's storage being read from * @returns exists: whether the slot has EVER been written to before, value: the latest value written to slot, or 0 if never written to before */ - public async read(storageAddress: Fr, slot: Fr): Promise<[/*exists=*/ boolean, /*value=*/ Fr]> { + public async read(storageAddress: Fr, slot: Fr): Promise { + let cached = false; // First try check this storage cache let value = this.cache.read(storageAddress, slot); // Then try parent's storage cache (if it exists / written to earlier in this TX) @@ -49,11 +57,13 @@ export class PublicStorage { // Finally try the host's Aztec state (a trip to the database) if (!value) { value = await this.hostPublicStorage.storageRead(storageAddress, slot); + } else { + cached = true; } // if value is undefined, that means this slot has never been written to! const exists = value !== undefined; const valueOrZero = exists ? value : Fr.ZERO; - return Promise.resolve([exists, valueOrZero]); + return Promise.resolve({ value: valueOrZero, exists, cached }); } /** @@ -75,6 +85,17 @@ export class PublicStorage { public acceptAndMerge(incomingPublicStorage: PublicStorage) { this.cache.acceptAndMerge(incomingPublicStorage.cache); } + + /** + * Commits ALL staged writes to the host's state. + */ + public async commitToDB() { + for (const [storageAddress, cacheAtContract] of this.cache.cachePerContract) { + for (const [slot, value] of cacheAtContract) { + await this.hostPublicStorage.storageWrite(AztecAddress.fromBigInt(storageAddress), new Fr(slot), value); + } + } + } } /** diff --git a/yarn-project/simulator/src/avm/journal/trace.test.ts b/yarn-project/simulator/src/avm/journal/trace.test.ts index e19c14dc706..f8692e01c84 100644 --- a/yarn-project/simulator/src/avm/journal/trace.test.ts +++ b/yarn-project/simulator/src/avm/journal/trace.test.ts @@ -110,7 +110,7 @@ describe('world state access trace', () => { let counter = 0; trace.tracePublicStorageWrite(contractAddress, slot, value); counter++; - trace.tracePublicStorageRead(contractAddress, slot, value, /*exists=*/ true); + trace.tracePublicStorageRead(contractAddress, slot, value, /*exists=*/ true, /*cached=*/ true); counter++; trace.traceNoteHashCheck(contractAddress, noteHash, noteHashExists, noteHashLeafIndex); counter++; @@ -124,7 +124,7 @@ describe('world state access trace', () => { counter++; trace.tracePublicStorageWrite(contractAddress, slot, value); counter++; - trace.tracePublicStorageRead(contractAddress, slot, value, /*exists=*/ true); + trace.tracePublicStorageRead(contractAddress, slot, value, /*exists=*/ true, /*cached=*/ true); counter++; trace.traceNewNoteHash(contractAddress, noteHash); counter++; @@ -178,7 +178,7 @@ describe('world state access trace', () => { }; trace.tracePublicStorageWrite(contractAddress, slot, value); - trace.tracePublicStorageRead(contractAddress, slot, value, /*exists=*/ true); + trace.tracePublicStorageRead(contractAddress, slot, value, /*exists=*/ true, /*cached=*/ true); trace.traceNoteHashCheck(contractAddress, noteHash, noteHashExists, noteHashLeafIndex); trace.traceNewNoteHash(contractAddress, noteHash); trace.traceNullifierCheck(contractAddress, nullifier, nullifierExists, nullifierIsPending, nullifierLeafIndex); @@ -187,7 +187,7 @@ describe('world state access trace', () => { const childTrace = new WorldStateAccessTrace(trace); childTrace.tracePublicStorageWrite(contractAddress, slot, valueT1); - childTrace.tracePublicStorageRead(contractAddress, slot, valueT1, /*exists=*/ true); + childTrace.tracePublicStorageRead(contractAddress, slot, valueT1, /*exists=*/ true, /*cached=*/ true); childTrace.traceNoteHashCheck(contractAddress, noteHashT1, noteHashExistsT1, noteHashLeafIndexT1); childTrace.traceNewNoteHash(contractAddress, nullifierT1); childTrace.traceNullifierCheck( @@ -205,8 +205,20 @@ describe('world state access trace', () => { expect(trace.getAccessCounter()).toEqual(childCounterBeforeMerge); expect(trace.publicStorageReads).toEqual([ - expect.objectContaining({ storageAddress: contractAddress, slot: slot, value: value, exists: true }), - expect.objectContaining({ storageAddress: contractAddress, slot: slot, value: valueT1, exists: true }), + expect.objectContaining({ + storageAddress: contractAddress, + slot: slot, + value: value, + exists: true, + cached: true, + }), + expect.objectContaining({ + storageAddress: contractAddress, + slot: slot, + value: valueT1, + exists: true, + cached: true, + }), ]); expect(trace.publicStorageWrites).toEqual([ expect.objectContaining({ storageAddress: contractAddress, slot: slot, value: value }), diff --git a/yarn-project/simulator/src/avm/journal/trace.ts b/yarn-project/simulator/src/avm/journal/trace.ts index 5ca5be9dbc1..da857f984fc 100644 --- a/yarn-project/simulator/src/avm/journal/trace.ts +++ b/yarn-project/simulator/src/avm/journal/trace.ts @@ -36,7 +36,7 @@ export class WorldStateAccessTrace { return this.accessCounter; } - public tracePublicStorageRead(storageAddress: Fr, slot: Fr, value: Fr, exists: boolean) { + public tracePublicStorageRead(storageAddress: Fr, slot: Fr, value: Fr, exists: boolean, cached: boolean) { // TODO(4805): check if some threshold is reached for max storage reads // (need access to parent length, or trace needs to be initialized with parent's contents) const traced: TracedPublicStorageRead = { @@ -45,6 +45,7 @@ export class WorldStateAccessTrace { slot, value, exists, + cached, counter: new Fr(this.accessCounter), // endLifetime: Fr.ZERO, }; diff --git a/yarn-project/simulator/src/avm/journal/trace_types.ts b/yarn-project/simulator/src/avm/journal/trace_types.ts index 3c93649cefd..4c292146a7b 100644 --- a/yarn-project/simulator/src/avm/journal/trace_types.ts +++ b/yarn-project/simulator/src/avm/journal/trace_types.ts @@ -11,6 +11,7 @@ export type TracedPublicStorageRead = { // callPointer: Fr; storageAddress: Fr; exists: boolean; + cached: boolean; slot: Fr; value: Fr; counter: Fr; diff --git a/yarn-project/simulator/src/public/abstract_phase_manager.ts b/yarn-project/simulator/src/public/abstract_phase_manager.ts index e3084193263..f6a7d1848ad 100644 --- a/yarn-project/simulator/src/public/abstract_phase_manager.ts +++ b/yarn-project/simulator/src/public/abstract_phase_manager.ts @@ -249,6 +249,7 @@ export abstract class AbstractPhaseManager { // TODO(6052): Extract correct new counter from nested calls const sideEffectCounter = lastSideEffectCounter(tx) + 1; const availableGas = this.getAvailableGas(tx, kernelOutput); + const pendingNullifiers = this.getSiloedPendingNullifiers(kernelOutput); const result = isExecutionRequest ? await this.publicExecutor.simulate( @@ -256,6 +257,7 @@ export abstract class AbstractPhaseManager { this.globalVariables, availableGas, tx.data.constants.txContext, + pendingNullifiers, transactionFee, sideEffectCounter, ) @@ -323,6 +325,11 @@ export abstract class AbstractPhaseManager { return [publicKernelInputs, kernelOutput, kernelProof, newUnencryptedFunctionLogs, undefined, returns]; } + /** Returns all pending private and public nullifiers. */ + private getSiloedPendingNullifiers(ko: PublicKernelCircuitPublicInputs) { + return [...ko.end.newNullifiers, ...ko.endNonRevertibleData.newNullifiers].filter(n => !n.isEmpty()); + } + protected getAvailableGas(tx: Tx, previousPublicKernelOutput: PublicKernelCircuitPublicInputs) { return tx.data.constants.txContext.gasSettings .getLimits() // No need to subtract teardown limits since they are already included in end.gasUsed diff --git a/yarn-project/simulator/src/public/executor.ts b/yarn-project/simulator/src/public/executor.ts index d00ea70af12..89951608404 100644 --- a/yarn-project/simulator/src/public/executor.ts +++ b/yarn-project/simulator/src/public/executor.ts @@ -4,6 +4,7 @@ import { Gas, type GlobalVariables, type Header, + type Nullifier, PublicCircuitPublicInputs, type TxContext, } from '@aztec/circuits.js'; @@ -46,7 +47,7 @@ export async function executePublicFunction( } if (isAvmBytecode(bytecode)) { - return await executeTopLevelPublicFunctionAvm(context); + return await executeTopLevelPublicFunctionAvm(context, bytecode); } else { return await executePublicFunctionAcvm(context, bytecode, nested); } @@ -58,6 +59,7 @@ export async function executePublicFunction( */ async function executeTopLevelPublicFunctionAvm( executionContext: PublicExecutionContext, + bytecode: Buffer, ): Promise { const address = executionContext.execution.contractAddress; const selector = executionContext.execution.functionData.selector; @@ -77,6 +79,9 @@ async function executeTopLevelPublicFunctionAvm( // or modify the PersistableStateManager to manage rollbacks across enqueued-calls and transactions. const worldStateJournal = new AvmPersistableStateManager(hostStorage); const startSideEffectCounter = executionContext.execution.callContext.sideEffectCounter; + for (const nullifier of executionContext.pendingNullifiers) { + worldStateJournal.nullifiers.cache.appendSiloed(nullifier.value); + } worldStateJournal.trace.accessCounter = startSideEffectCounter; const executionEnv = createAvmExecutionEnvironment( @@ -91,7 +96,12 @@ async function executeTopLevelPublicFunctionAvm( const avmContext = new AvmContext(worldStateJournal, executionEnv, machineState); const simulator = new AvmSimulator(avmContext); - const avmResult = await simulator.execute(); + const avmResult = await simulator.executeBytecode(bytecode); + + // Commit the journals state to the DBs since this is a top-level execution. + // Observe that this will write all the state changes to the DBs, not only the latest for each slot. + // However, the underlying DB keep a cache and will only write the latest state to disk. + await avmContext.persistableState.publicStorage.commitToDB(); log.verbose( `[AVM] ${address.toString()}:${selector} returned, reverted: ${avmResult.reverted}, reason: ${ @@ -99,8 +109,12 @@ async function executeTopLevelPublicFunctionAvm( }.`, ); - return Promise.resolve( - convertAvmResultsToPxResult(avmResult, startSideEffectCounter, executionContext.execution, startGas, avmContext), + return convertAvmResultsToPxResult( + avmResult, + startSideEffectCounter, + executionContext.execution, + startGas, + avmContext, ); } @@ -279,6 +293,7 @@ export class PublicExecutor { globalVariables: GlobalVariables, availableGas: Gas, txContext: TxContext, + pendingNullifiers: Nullifier[], transactionFee: Fr = Fr.ZERO, sideEffectCounter: number = 0, ): Promise { @@ -298,6 +313,7 @@ export class PublicExecutor { availableGas, transactionFee, txContext.gasSettings, + pendingNullifiers, ); const executionResult = await executePublicFunction(context, /*nested=*/ false); diff --git a/yarn-project/simulator/src/public/index.test.ts b/yarn-project/simulator/src/public/index.test.ts index 14995aa727a..0a00456b62e 100644 --- a/yarn-project/simulator/src/public/index.test.ts +++ b/yarn-project/simulator/src/public/index.test.ts @@ -99,7 +99,7 @@ describe('ACIR public execution simulator', () => { }); const simulate = (execution: PublicExecution, globalVariables: GlobalVariables) => - executor.simulate(execution, globalVariables, Gas.test(), makeTxContext(), Fr.ZERO); + executor.simulate(execution, globalVariables, Gas.test(), makeTxContext(), /*pendingNullifiers=*/ [], Fr.ZERO); describe('Token contract', () => { let recipient: AztecAddress; @@ -731,7 +731,8 @@ describe('ACIR public execution simulator', () => { }); }); - describe('Historical header in public context', () => { + // TODO(4840): add AVM opcodes for getting header (members) + describe.skip('Historical header in public context', () => { let contractAddress: AztecAddress; let callContext: CallContext; let assertHeaderPublicArtifact: FunctionArtifact; diff --git a/yarn-project/simulator/src/public/public_execution_context.ts b/yarn-project/simulator/src/public/public_execution_context.ts index bcd468aa568..c6279209ecf 100644 --- a/yarn-project/simulator/src/public/public_execution_context.ts +++ b/yarn-project/simulator/src/public/public_execution_context.ts @@ -7,6 +7,7 @@ import { type GasSettings, type GlobalVariables, type Header, + type Nullifier, PublicContextInputs, } from '@aztec/circuits.js'; import { type AztecAddress } from '@aztec/foundation/aztec-address'; @@ -45,6 +46,7 @@ export class PublicExecutionContext extends TypedOracle { public readonly availableGas: Gas, public readonly transactionFee: Fr, public readonly gasSettings: GasSettings, + public readonly pendingNullifiers: Nullifier[], // Unencrypted logs emitted during this call AND any nested calls // Useful for maintaining correct ordering in ts private allUnencryptedLogs: UnencryptedL2Log[] = [], @@ -239,6 +241,7 @@ export class PublicExecutionContext extends TypedOracle { this.availableGas, this.transactionFee, this.gasSettings, + /*pendingNullifiers=*/ [], this.allUnencryptedLogs, this.log, ); diff --git a/yarn-project/simulator/src/public/public_processor.test.ts b/yarn-project/simulator/src/public/public_processor.test.ts index 94e666fd524..33c25cab600 100644 --- a/yarn-project/simulator/src/public/public_processor.test.ts +++ b/yarn-project/simulator/src/public/public_processor.test.ts @@ -764,6 +764,7 @@ describe('public_processor', () => { expect.anything(), // GlobalVariables Gas.from(availableGas), expect.anything(), // TxContext + expect.anything(), // pendingNullifiers new Fr(txFee), expect.anything(), // SideEffectCounter ]; diff --git a/yarn-project/simulator/src/public/transitional_adaptors.ts b/yarn-project/simulator/src/public/transitional_adaptors.ts index 09b2e2d99fc..5e241a6a315 100644 --- a/yarn-project/simulator/src/public/transitional_adaptors.ts +++ b/yarn-project/simulator/src/public/transitional_adaptors.ts @@ -1,31 +1,21 @@ // All code in this file needs to die once the public executor is phased out in favor of the AVM. -import { UnencryptedFunctionL2Logs, UnencryptedL2Log } from '@aztec/circuit-types'; +import { UnencryptedFunctionL2Logs } from '@aztec/circuit-types'; import { CallContext, - ContractStorageRead, - ContractStorageUpdateRequest, FunctionData, type Gas, type GasSettings, type GlobalVariables, type Header, - L2ToL1Message, - NoteHash, - Nullifier, - ReadRequest, - SideEffect, } from '@aztec/circuits.js'; import { Fr } from '@aztec/foundation/fields'; import { type AvmContext } from '../avm/avm_context.js'; import { AvmExecutionEnvironment } from '../avm/avm_execution_environment.js'; -import { type AvmMachineState } from '../avm/avm_machine_state.js'; -import { AvmContractCallResults } from '../avm/avm_message_call_result.js'; -import { type JournalData } from '../avm/journal/journal.js'; +import { type AvmContractCallResults } from '../avm/avm_message_call_result.js'; import { Mov } from '../avm/opcodes/memory.js'; import { createSimulationError } from '../common/errors.js'; import { type PublicExecution, type PublicExecutionResult } from './execution.js'; -import { type PublicExecutionContext } from './public_execution_context.js'; /** * Convert a PublicExecution(Environment) object to an AvmExecutionEnvironment @@ -109,97 +99,6 @@ export function convertAvmResultsToPxResult( }; } -/** - * Convert the result of an AVM contract call to a PublicExecutionResult for the public kernel - * - * @param execution - * @param newWorldState - * @param result - * @returns - */ -export async function convertAvmResults( - executionContext: PublicExecutionContext, - newWorldState: JournalData, - result: AvmContractCallResults, - endMachineState: AvmMachineState, -): Promise { - const execution = executionContext.execution; - - const contractStorageReads: ContractStorageRead[] = newWorldState.storageReads.map( - read => new ContractStorageRead(read.slot, read.value, read.counter.toNumber(), read.storageAddress), - ); - const contractStorageUpdateRequests: ContractStorageUpdateRequest[] = newWorldState.storageWrites.map( - write => new ContractStorageUpdateRequest(write.slot, write.value, write.counter.toNumber(), write.storageAddress), - ); - // We need to write the storage updates to the DB, because that's what the ACVM expects. - // Assumes the updates are in the right order. - for (const write of newWorldState.storageWrites) { - await executionContext.stateDb.storageWrite(write.storageAddress, write.slot, write.value); - } - - const newNoteHashes = newWorldState.newNoteHashes.map( - noteHash => new NoteHash(noteHash.noteHash, noteHash.counter.toNumber()), - ); - const nullifierReadRequests: ReadRequest[] = newWorldState.nullifierChecks - .filter(nullifierCheck => nullifierCheck.exists) - .map(nullifierCheck => new ReadRequest(nullifierCheck.nullifier, nullifierCheck.counter.toNumber())); - const nullifierNonExistentReadRequests: ReadRequest[] = newWorldState.nullifierChecks - .filter(nullifierCheck => !nullifierCheck.exists) - .map(nullifierCheck => new ReadRequest(nullifierCheck.nullifier, nullifierCheck.counter.toNumber())); - const newNullifiers: Nullifier[] = newWorldState.newNullifiers.map( - tracedNullifier => - new Nullifier( - /*value=*/ tracedNullifier.nullifier, - tracedNullifier.counter.toNumber(), - /*noteHash=*/ Fr.ZERO, // NEEDED? - ), - ); - const unencryptedLogs: UnencryptedFunctionL2Logs = new UnencryptedFunctionL2Logs( - newWorldState.newLogs.map(log => new UnencryptedL2Log(log.contractAddress, log.selector, log.data)), - ); - const unencryptedLogsHashes = newWorldState.newLogsHashes.map( - logHash => new SideEffect(logHash.logHash, logHash.counter), - ); - const newL2ToL1Messages = newWorldState.newL1Messages.map(m => new L2ToL1Message(m.recipient, m.content)); - - const returnValues = result.output; - - // TODO: Support nested executions. - const nestedExecutions: PublicExecutionResult[] = []; - const allUnencryptedLogs = unencryptedLogs; - // TODO keep track of side effect counters - const startSideEffectCounter = Fr.ZERO; - const endSideEffectCounter = Fr.ZERO; - - return { - execution, - nullifierReadRequests, - nullifierNonExistentReadRequests, - newNoteHashes, - newL2ToL1Messages, - startSideEffectCounter, - endSideEffectCounter, - newNullifiers, - contractStorageReads, - contractStorageUpdateRequests, - returnValues, - nestedExecutions, - unencryptedLogsHashes, - unencryptedLogs, - unencryptedLogPreimagesLength: new Fr(unencryptedLogs.getSerializedLength()), - allUnencryptedLogs, - reverted: result.reverted, - revertReason: result.revertReason ? createSimulationError(result.revertReason) : undefined, - startGasLeft: executionContext.availableGas, - endGasLeft: endMachineState.gasLeft, - transactionFee: executionContext.transactionFee, - }; -} - -export function convertPublicExecutionResult(res: PublicExecutionResult): AvmContractCallResults { - return new AvmContractCallResults(res.reverted, res.returnValues, res.revertReason); -} - const AVM_MAGIC_SUFFIX = Buffer.from([ Mov.opcode, // opcode 0x00, // indirect diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index f2539b2eb46..1be75065b37 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -592,6 +592,7 @@ __metadata: "@noir-lang/types": "portal:../../noir/packages/types" "@types/jest": ^29.5.0 "@types/node": ^18.7.23 + change-case: ^5.4.4 jest: ^29.5.0 levelup: ^5.1.1 memdown: ^6.1.1 @@ -2860,7 +2861,7 @@ __metadata: 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.28.0 + "@noir-lang/types": 0.29.0 languageName: node linkType: soft @@ -5255,6 +5256,13 @@ __metadata: languageName: node linkType: hard +"change-case@npm:^5.4.4": + version: 5.4.4 + resolution: "change-case@npm:5.4.4" + checksum: a22a25a763719658424ffbcd41e931d2d19cc22399cc765dca447fbe1eaf13e179d5e8ab1677af75f2e814dbddf74e42ffdecb526cd5bc906cc859f62aa154b2 + languageName: node + linkType: hard + "char-regex@npm:^1.0.2": version: 1.0.2 resolution: "char-regex@npm:1.0.2"